Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch branch-3.28 Excluding Merge-Ins
This is equivalent to a diff from e6c8e19ab0 to 357d9513d2
2024-04-02
| ||
18:48 | Fix typos in comments. Provided ".wheretrace" debugging output for the interstage heuristic module. Do omit automatic index loops in the interstage heuristic. (Leaf check-in: 357d9513d2 user: drh tags: branch-3.28) | |
18:31 | Fix table-valued functions so that they will work as the right table in a LEFT JOIN. Ticket [2ae0c599b735d59e] (check-in: 1f97086d62 user: drh tags: branch-3.28) | |
14:12 | Fix typos in comments. Provided ".wheretrace" debugging output for the interstage heuristic module. Do omit automatic index loops in the interstage heuristic. (Closed-Leaf check-in: 186dcae19e user: drh tags: interstage-heuristic) | |
2023-02-17
| ||
18:27 | Do not allow the COUNTOFVIEW optimization to run if the count() contains a FILTER clause. dbsqlfuzz 4f8e0de6e272bbbb3e1b41cb5aea31e0b47297e3 (check-in: 29fc06465e user: drh tags: trunk) | |
2023-02-15
| ||
17:53 | Do not compute result columns of subqueries that are never used. Make those columns NULL instead. This optimization potentially resolves the enhancement request described by [baa5bb76c35a124c|ticket baa5bb76c35a124c]. (check-in: 5dec3cc022 user: drh tags: omit-unused-subquery-columns) | |
2023-02-14
| ||
18:09 | Update testrunner.tcl to run zipvfs test scripts on unix. (check-in: e6c8e19ab0 user: dan tags: trunk) | |
2023-02-13
| ||
19:32 | Ignore extra parentheses around a subquery on the RHS of an IN operator, because that is what PostgreSQL does. (check-in: ecdeef43b2 user: drh tags: trunk) | |
Changes to Makefile.in.
︙ | ︙ | |||
31 32 33 34 35 36 37 | CC = @CC@ CFLAGS = @CPPFLAGS@ @CFLAGS@ TCC = ${CC} ${CFLAGS} -I. -I${TOP}/src -I${TOP}/ext/rtree -I${TOP}/ext/icu TCC += -I${TOP}/ext/fts3 -I${TOP}/ext/async -I${TOP}/ext/session TCC += -I${TOP}/ext/userauth # Define this for the autoconf-based build, so that the code knows it can | | | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | CC = @CC@ CFLAGS = @CPPFLAGS@ @CFLAGS@ TCC = ${CC} ${CFLAGS} -I. -I${TOP}/src -I${TOP}/ext/rtree -I${TOP}/ext/icu TCC += -I${TOP}/ext/fts3 -I${TOP}/ext/async -I${TOP}/ext/session TCC += -I${TOP}/ext/userauth # Define this for the autoconf-based build, so that the code knows it can # include the generated config.h # TCC += -D_HAVE_SQLITE_CONFIG_H -DBUILD_sqlite # Define -DNDEBUG to compile without debugging (i.e., for production usage) # Omitting the define will cause extra debugging code to be inserted and # includes extra comments when "EXPLAIN stmt" is used. # |
︙ | ︙ | |||
161 162 163 164 165 166 167 | 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@ | < | | < | | 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 | 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 \ expr.lo fault.lo fkey.lo \ fts3.lo fts3_aux.lo fts3_expr.lo fts3_hash.lo fts3_icu.lo \ fts3_porter.lo fts3_snippet.lo fts3_tokenizer.lo fts3_tokenizer1.lo \ fts3_tokenize_vtab.lo \ fts3_unicode.lo fts3_unicode2.lo fts3_write.lo \ fts5.lo \ func.lo global.lo hash.lo \ icu.lo insert.lo json1.lo legacy.lo loadext.lo \ main.lo malloc.lo mem0.lo mem1.lo mem2.lo mem3.lo mem5.lo \ memdb.lo memjournal.lo \ mutex.lo mutex_noop.lo mutex_unix.lo mutex_w32.lo \ notify.lo opcodes.lo os.lo os_unix.lo os_win.lo \ pager.lo parse.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \ random.lo resolve.lo rowset.lo rtree.lo \ 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 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 |
︙ | ︙ | |||
230 231 232 233 234 235 236 | $(TOP)/src/fkey.c \ $(TOP)/src/func.c \ $(TOP)/src/global.c \ $(TOP)/src/hash.c \ $(TOP)/src/hash.h \ $(TOP)/src/hwtime.h \ $(TOP)/src/insert.c \ | < | 228 229 230 231 232 233 234 235 236 237 238 239 240 241 | $(TOP)/src/fkey.c \ $(TOP)/src/func.c \ $(TOP)/src/global.c \ $(TOP)/src/hash.c \ $(TOP)/src/hash.h \ $(TOP)/src/hwtime.h \ $(TOP)/src/insert.c \ $(TOP)/src/legacy.c \ $(TOP)/src/loadext.c \ $(TOP)/src/main.c \ $(TOP)/src/malloc.c \ $(TOP)/src/mem0.c \ $(TOP)/src/mem1.c \ $(TOP)/src/mem2.c \ |
︙ | ︙ | |||
253 254 255 256 257 258 259 | $(TOP)/src/mutex_unix.c \ $(TOP)/src/mutex_w32.c \ $(TOP)/src/notify.c \ $(TOP)/src/os.c \ $(TOP)/src/os.h \ $(TOP)/src/os_common.h \ $(TOP)/src/os_setup.h \ | < | 250 251 252 253 254 255 256 257 258 259 260 261 262 263 | $(TOP)/src/mutex_unix.c \ $(TOP)/src/mutex_w32.c \ $(TOP)/src/notify.c \ $(TOP)/src/os.c \ $(TOP)/src/os.h \ $(TOP)/src/os_common.h \ $(TOP)/src/os_setup.h \ $(TOP)/src/os_unix.c \ $(TOP)/src/os_win.c \ $(TOP)/src/os_win.h \ $(TOP)/src/pager.c \ $(TOP)/src/pager.h \ $(TOP)/src/parse.y \ $(TOP)/src/pcache.c \ |
︙ | ︙ | |||
296 297 298 299 300 301 302 | $(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 \ | < > > > > > > > > > > > > > > > > > > | 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 | $(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 \ $(TOP)/src/wherecode.c \ $(TOP)/src/whereexpr.c \ $(TOP)/src/whereInt.h \ $(TOP)/src/window.c # Source code for extensions # SRC += \ $(TOP)/ext/fts1/fts1.c \ $(TOP)/ext/fts1/fts1.h \ $(TOP)/ext/fts1/fts1_hash.c \ $(TOP)/ext/fts1/fts1_hash.h \ $(TOP)/ext/fts1/fts1_porter.c \ $(TOP)/ext/fts1/fts1_tokenizer.h \ $(TOP)/ext/fts1/fts1_tokenizer1.c SRC += \ $(TOP)/ext/fts2/fts2.c \ $(TOP)/ext/fts2/fts2.h \ $(TOP)/ext/fts2/fts2_hash.c \ $(TOP)/ext/fts2/fts2_hash.h \ $(TOP)/ext/fts2/fts2_icu.c \ $(TOP)/ext/fts2/fts2_porter.c \ $(TOP)/ext/fts2/fts2_tokenizer.h \ $(TOP)/ext/fts2/fts2_tokenizer.c \ $(TOP)/ext/fts2/fts2_tokenizer1.c SRC += \ $(TOP)/ext/fts3/fts3.c \ $(TOP)/ext/fts3/fts3.h \ $(TOP)/ext/fts3/fts3Int.h \ $(TOP)/ext/fts3/fts3_aux.c \ $(TOP)/ext/fts3/fts3_expr.c \ $(TOP)/ext/fts3/fts3_hash.c \ $(TOP)/ext/fts3/fts3_hash.h \ |
︙ | ︙ | |||
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 | SRC += \ $(TOP)/ext/userauth/userauth.c \ $(TOP)/ext/userauth/sqlite3userauth.h SRC += \ $(TOP)/ext/rbu/sqlite3rbu.h \ $(TOP)/ext/rbu/sqlite3rbu.c SRC += \ $(TOP)/ext/misc/stmt.c # Generated source code files # SRC += \ keywordhash.h \ opcodes.c \ opcodes.h \ parse.c \ parse.h \ | > | > | 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 | SRC += \ $(TOP)/ext/userauth/userauth.c \ $(TOP)/ext/userauth/sqlite3userauth.h SRC += \ $(TOP)/ext/rbu/sqlite3rbu.h \ $(TOP)/ext/rbu/sqlite3rbu.c SRC += \ $(TOP)/ext/misc/json1.c \ $(TOP)/ext/misc/stmt.c # Generated source code files # SRC += \ keywordhash.h \ opcodes.c \ opcodes.h \ parse.c \ parse.h \ config.h \ shell.c \ sqlite3.h # Source code to the test files. # TESTSRC = \ $(TOP)/src/test1.c \ $(TOP)/src/test2.c \ $(TOP)/src/test3.c \ $(TOP)/src/test4.c \ $(TOP)/src/test5.c \ $(TOP)/src/test6.c \ $(TOP)/src/test7.c \ $(TOP)/src/test8.c \ $(TOP)/src/test9.c \ $(TOP)/src/test_autoext.c \ $(TOP)/src/test_async.c \ $(TOP)/src/test_backup.c \ $(TOP)/src/test_bestindex.c \ $(TOP)/src/test_blob.c \ |
︙ | ︙ | |||
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 | $(TOP)/src/test_mutex.c \ $(TOP)/src/test_onefile.c \ $(TOP)/src/test_osinst.c \ $(TOP)/src/test_pcache.c \ $(TOP)/src/test_quota.c \ $(TOP)/src/test_rtree.c \ $(TOP)/src/test_schema.c \ $(TOP)/src/test_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 \ | > < < < < < < < < | < | 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 | $(TOP)/src/test_mutex.c \ $(TOP)/src/test_onefile.c \ $(TOP)/src/test_osinst.c \ $(TOP)/src/test_pcache.c \ $(TOP)/src/test_quota.c \ $(TOP)/src/test_rtree.c \ $(TOP)/src/test_schema.c \ $(TOP)/src/test_server.c \ $(TOP)/src/test_superlock.c \ $(TOP)/src/test_syscall.c \ $(TOP)/src/test_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/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/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/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 # Source code to the library files needed by the test fixture # TESTSRC2 = \ $(TOP)/src/attach.c \ $(TOP)/src/backup.c \ $(TOP)/src/bitvec.c \ |
︙ | ︙ | |||
473 474 475 476 477 478 479 | $(TOP)/src/func.c \ $(TOP)/src/global.c \ $(TOP)/src/insert.c \ $(TOP)/src/wal.c \ $(TOP)/src/main.c \ $(TOP)/src/mem5.c \ $(TOP)/src/os.c \ | < < < | < | 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 | $(TOP)/src/func.c \ $(TOP)/src/global.c \ $(TOP)/src/insert.c \ $(TOP)/src/wal.c \ $(TOP)/src/main.c \ $(TOP)/src/mem5.c \ $(TOP)/src/os.c \ $(TOP)/src/os_unix.c \ $(TOP)/src/os_win.c \ $(TOP)/src/pager.c \ $(TOP)/src/pragma.c \ $(TOP)/src/prepare.c \ $(TOP)/src/printf.c \ $(TOP)/src/random.c \ $(TOP)/src/pcache.c \ $(TOP)/src/pcache1.c \ $(TOP)/src/select.c \ $(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/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 \ $(TOP)/ext/misc/stmt.c # Header files used by all library source files. # HDR = \ $(TOP)/src/btree.h \ $(TOP)/src/btreeInt.h \ $(TOP)/src/hash.h \ |
︙ | ︙ | |||
537 538 539 540 541 542 543 | $(TOP)/src/sqlite3ext.h \ $(TOP)/src/sqliteInt.h \ $(TOP)/src/sqliteLimit.h \ $(TOP)/src/vdbe.h \ $(TOP)/src/vdbeInt.h \ $(TOP)/src/vxworks.h \ $(TOP)/src/whereInt.h \ | | > > > > > > > > | 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 | $(TOP)/src/sqlite3ext.h \ $(TOP)/src/sqliteInt.h \ $(TOP)/src/sqliteLimit.h \ $(TOP)/src/vdbe.h \ $(TOP)/src/vdbeInt.h \ $(TOP)/src/vxworks.h \ $(TOP)/src/whereInt.h \ config.h # Header files used by extensions # EXTHDR += \ $(TOP)/ext/fts1/fts1.h \ $(TOP)/ext/fts1/fts1_hash.h \ $(TOP)/ext/fts1/fts1_tokenizer.h EXTHDR += \ $(TOP)/ext/fts2/fts2.h \ $(TOP)/ext/fts2/fts2_hash.h \ $(TOP)/ext/fts2/fts2_tokenizer.h EXTHDR += \ $(TOP)/ext/fts3/fts3.h \ $(TOP)/ext/fts3/fts3Int.h \ $(TOP)/ext/fts3/fts3_hash.h \ $(TOP)/ext/fts3/fts3_tokenizer.h EXTHDR += \ $(TOP)/ext/rtree/rtree.h \ $(TOP)/ext/rtree/geopoly.c |
︙ | ︙ | |||
584 585 586 587 588 589 590 | # Standard options to testfixture # TESTOPTS = --verbose=file --output=test-out.txt # Extra compiler options for various shell tools # | < | | | > | < < < | | | | < | < < < < < < < < < < < < | < | 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 | # Standard options to testfixture # TESTOPTS = --verbose=file --output=test-out.txt # Extra compiler options for various shell tools # SHELL_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 #SHELL_OPT += -DSQLITE_ENABLE_FTS5 SHELL_OPT += -DSQLITE_ENABLE_RTREE SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC SHELL_OPT += -DSQLITE_ENABLE_DESERIALIZE SHELL_OPT += -DSQLITE_INTROSPECTION_PRAGMAS 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_DESERIALIZE FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS4 #FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS5 FUZZCHECK_OPT += -DSQLITE_ENABLE_RTREE FUZZCHECK_OPT += -DSQLITE_ENABLE_GEOPOLY FUZZCHECK_OPT += -DSQLITE_ENABLE_DBSTAT_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) Makefile: $(TOP)/Makefile.in ./config.status sqlite3.pc: $(TOP)/sqlite3.pc.in ./config.status |
︙ | ︙ | |||
672 673 674 675 676 677 678 | sourcetest: srcck1$(BEXE) sqlite3.c ./srcck1 sqlite3.c fuzzershell$(TEXE): $(TOP)/tool/fuzzershell.c sqlite3.c sqlite3.h $(LTLINK) -o $@ $(FUZZERSHELL_OPT) \ $(TOP)/tool/fuzzershell.c sqlite3.c $(TLIBS) | | > < | 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 | sourcetest: srcck1$(BEXE) sqlite3.c ./srcck1 sqlite3.c fuzzershell$(TEXE): $(TOP)/tool/fuzzershell.c sqlite3.c sqlite3.h $(LTLINK) -o $@ $(FUZZERSHELL_OPT) \ $(TOP)/tool/fuzzershell.c sqlite3.c $(TLIBS) fuzzcheck$(TEXE): $(FUZZCHECK_SRC) sqlite3.c sqlite3.h $(LTLINK) -o $@ $(FUZZCHECK_OPT) $(FUZZCHECK_SRC) sqlite3.c $(TLIBS) ossshell$(TEXE): $(TOP)/test/ossfuzz.c $(TOP)/test/ossshell.c sqlite3.c sqlite3.h $(LTLINK) -o $@ $(FUZZCHECK_OPT) $(TOP)/test/ossshell.c \ $(TOP)/test/ossfuzz.c sqlite3.c $(TLIBS) sessionfuzz$(TEXE): $(TOP)/test/sessionfuzz.c sqlite3.c sqlite3.h $(LTLINK) -o $@ $(TOP)/test/sessionfuzz.c $(TLIBS) 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_ENABLE_DESERIALIZE \ -DSQLITE_DEBUG \ -DSQLITE_ENABLE_DBSTAT_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 \ |
︙ | ︙ | |||
751 752 753 754 755 756 757 | 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 | | < < < < < < < < < | 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 | rm tsrc/sqlite.h.in tsrc/parse.y $(TCLSH_CMD) $(TOP)/tool/vdbe-compress.tcl $(OPTS) <tsrc/vdbe.c >vdbe.new mv vdbe.new tsrc/vdbe.c cp fts5.c fts5.h tsrc touch .target_source sqlite3.c: .target_source $(TOP)/tool/mksqlite3c.tcl $(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl cp tsrc/sqlite3ext.h . cp $(TOP)/ext/session/sqlite3session.h . sqlite3ext.h: .target_source cp tsrc/sqlite3ext.h . tclsqlite3.c: sqlite3.c echo '#ifndef USE_SYSTEM_SQLITE' >tclsqlite3.c cat sqlite3.c >>tclsqlite3.c echo '#endif /* USE_SYSTEM_SQLITE */' >>tclsqlite3.c |
︙ | ︙ | |||
875 876 877 878 879 880 881 | hash.lo: $(TOP)/src/hash.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/hash.c insert.lo: $(TOP)/src/insert.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/insert.c | < < < | 860 861 862 863 864 865 866 867 868 869 870 871 872 873 | hash.lo: $(TOP)/src/hash.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/hash.c insert.lo: $(TOP)/src/insert.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/insert.c legacy.lo: $(TOP)/src/legacy.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/legacy.c loadext.lo: $(TOP)/src/loadext.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/loadext.c main.lo: $(TOP)/src/main.c $(HDR) |
︙ | ︙ | |||
938 939 940 941 942 943 944 | pcache1.lo: $(TOP)/src/pcache1.c $(HDR) $(TOP)/src/pcache.h $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/pcache1.c os.lo: $(TOP)/src/os.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/os.c | < < < | 920 921 922 923 924 925 926 927 928 929 930 931 932 933 | pcache1.lo: $(TOP)/src/pcache1.c $(HDR) $(TOP)/src/pcache.h $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/pcache1.c os.lo: $(TOP)/src/os.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/os.c os_unix.lo: $(TOP)/src/os_unix.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/os_unix.c os_win.lo: $(TOP)/src/os_win.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/os_win.c pragma.lo: $(TOP)/src/pragma.c $(HDR) |
︙ | ︙ | |||
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 | < < < | 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 | 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) |
︙ | ︙ | |||
1073 1074 1075 1076 1077 1078 1079 | # 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 . | | < < < < < < < | < < < | < < < < < < < > > > > > > > > > > > > > > > > > > | 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 | # 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) parse.y sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest mksourceid$(BEXE) $(TOP)/VERSION $(TCLSH_CMD) $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.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/shathree.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/completion.c \ $(TOP)/ext/misc/sqlar.c \ $(TOP)/ext/expert/sqlite3expert.c \ $(TOP)/ext/expert/sqlite3expert.h \ $(TOP)/ext/misc/zipfile.c \ $(TOP)/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 # Rules to build the extension objects. # icu.lo: $(TOP)/ext/icu/icu.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/icu/icu.c fts2.lo: $(TOP)/ext/fts2/fts2.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2.c fts2_hash.lo: $(TOP)/ext/fts2/fts2_hash.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2_hash.c fts2_icu.lo: $(TOP)/ext/fts2/fts2_icu.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2_icu.c fts2_porter.lo: $(TOP)/ext/fts2/fts2_porter.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2_porter.c fts2_tokenizer.lo: $(TOP)/ext/fts2/fts2_tokenizer.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2_tokenizer.c fts2_tokenizer1.lo: $(TOP)/ext/fts2/fts2_tokenizer1.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2_tokenizer1.c fts3.lo: $(TOP)/ext/fts3/fts3.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3.c fts3_aux.lo: $(TOP)/ext/fts3/fts3_aux.c $(HDR) $(EXTHDR) $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_aux.c fts3_expr.lo: $(TOP)/ext/fts3/fts3_expr.c $(HDR) $(EXTHDR) |
︙ | ︙ | |||
1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 | 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 stmt.lo: $(TOP)/ext/misc/stmt.c $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/misc/stmt.c # FTS5 things # FTS5_SRC = \ $(TOP)/ext/fts5/fts5.h \ | > > > | 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 | 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 # FTS5 things # FTS5_SRC = \ $(TOP)/ext/fts5/fts5.h \ |
︙ | ︙ | |||
1194 1195 1196 1197 1198 1199 1200 | 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 \ | | | | 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 | 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 cp $(TOP)/ext/fts5/fts5parse.y . rm -f fts5parse.h ./lemon$(BEXE) $(OPTS) fts5parse.y fts5parse.h: fts5parse.c fts5.c: $(FTS5_SRC) $(TCLSH_CMD) $(TOP)/ext/fts5/tool/mkfts5c.tcl cp $(TOP)/ext/fts5/fts5.h . |
︙ | ︙ | |||
1227 1228 1229 1230 1231 1232 1233 | 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 | | < < < < | > > > > | < < < < < < < < < < < < < < < | < < < | 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 | 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_DESERIALIZE 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: $(TESTPROGS) fuzztest ./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 fastfuzztest: fuzzcheck$(TEXE) $(FUZZDATA) sessionfuzz$(TEXE) $(TOP)/test/sessionfuzz-data1.db ./fuzzcheck$(TEXE) --limit-mem 100M $(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 --timeout 600 $(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: fastfuzztest 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) 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 |
︙ | ︙ | |||
1387 1388 1389 1390 1391 1392 1393 | LogEst$(TEXE): $(TOP)/tool/logest.c sqlite3.h $(LTLINK) -I. -o $@ $(TOP)/tool/logest.c wordcount$(TEXE): $(TOP)/test/wordcount.c sqlite3.lo $(LTLINK) -o $@ $(TOP)/test/wordcount.c sqlite3.lo $(TLIBS) | | < < < | 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 | LogEst$(TEXE): $(TOP)/tool/logest.c sqlite3.h $(LTLINK) -I. -o $@ $(TOP)/tool/logest.c 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) |
︙ | ︙ | |||
1418 1419 1420 1421 1422 1423 1424 | 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 # | | | | | | 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 | 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 TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --normal snapshot-tarball: sqlite3.c 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) 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) |
︙ | ︙ | |||
1473 1474 1475 1476 1477 1478 1479 | clean: rm -f *.lo *.la *.o sqlite3$(TEXE) libsqlite3.la rm -f sqlite3.h opcodes.* rm -rf .libs .deps rm -f lemon$(BEXE) lempar.c parse.* sqlite*.tar.gz rm -f mkkeywordhash$(BEXE) keywordhash.h | < | 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 | clean: rm -f *.lo *.la *.o sqlite3$(TEXE) libsqlite3.la rm -f sqlite3.h opcodes.* rm -rf .libs .deps rm -f lemon$(BEXE) lempar.c parse.* sqlite*.tar.gz rm -f mkkeywordhash$(BEXE) keywordhash.h rm -f *.da *.bb *.bbg gmon.out rm -rf tsrc .target_source rm -f tclsqlite3$(TEXE) rm -f testfixture$(TEXE) test.db rm -f LogEst$(TEXE) fts3view$(TEXE) rollback-test$(TEXE) showdb$(TEXE) rm -f showjournal$(TEXE) showstat4$(TEXE) showwal$(TEXE) speedtest1$(TEXE) rm -f wordcount$(TEXE) changeset$(TEXE) |
︙ | ︙ | |||
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.* | < | < < < < < < < | 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 | 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 # dll: sqlite3.dll REAL_LIBOBJ = $(LIBOBJ:%.lo=.libs/%.o) $(REAL_LIBOBJ): $(LIBOBJ) sqlite3.def: $(REAL_LIBOBJ) echo 'EXPORTS' >sqlite3.def nm $(REAL_LIBOBJ) | grep ' T ' | grep ' _sqlite3_' \ | sed 's/^.* _//' >>sqlite3.def sqlite3.dll: $(REAL_LIBOBJ) sqlite3.def $(TCC) -shared -o $@ sqlite3.def \ -Wl,"--strip-all" $(REAL_LIBOBJ) |
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 105 106 107 108 109 110 111 112 | # 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 -O2 #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 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=2 #OPTS = -DSQLITE_DEBUG=1 #OPTS = OPTS = -DNDEBUG=1 OPTS += -DHAVE_FDATASYNC=1 #### 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 -O6 #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 = #TCL_FLAGS = -DSTATIC_BUILD=1 TCL_FLAGS = -I/home/drh/tcltk/8.5linux #TCL_FLAGS = -I/home/drh/tcltk/8.5win -DSTATIC_BUILD=1 #TCL_FLAGS = -I/home/drh/tcltk/8.3hpux #### Linker options needed to link against the TCL library. # #LIBTCL = -ltcl -lm -ldl LIBTCL = /home/drh/tcltk/8.5linux/libtcl8.5g.a -lm -ldl #LIBTCL = /home/drh/tcltk/8.5win/libtcl85s.a -lmsvcrt #LIBTCL = /home/drh/tcltk/8.3hpux/libtcl8.3.a -ldld -lm -lc #### 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 -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 | # 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 | < < < < < < < < < < < < < < < < | 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 | # 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 !ELSE |
︙ | ︙ | |||
359 360 361 362 363 364 365 366 367 368 | # the Windows platform. # !IFNDEF OPT_FEATURE_FLAGS !IF $(MINIMAL_AMALGAMATION)==0 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_STMTVTAB=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBSTAT_VTAB=1 | > | > < < < < < < < < < < | 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 | # the Windows platform. # !IFNDEF OPT_FEATURE_FLAGS !IF $(MINIMAL_AMALGAMATION)==0 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_INTROSPECTION_PRAGMAS=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DESERIALIZE=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 # 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 EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_SYSTEM_MALLOC=1 |
︙ | ︙ | |||
575 576 577 578 579 580 581 | # also be noted here that building any target with these "stdcall" options # will most likely fail if the Tcl library is also required. This is due # to how the Tcl library functions are declared and exported (i.e. without # an explicit calling convention, which results in "cdecl"). # !IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0 !IF "$(PLATFORM)"=="x86" | | | | | | | | 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 | # also be noted here that building any target with these "stdcall" options # will most likely fail if the Tcl library is also required. This is due # to how the Tcl library functions are declared and exported (i.e. without # an explicit calling convention, which results in "cdecl"). # !IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0 !IF "$(PLATFORM)"=="x86" CORE_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall SHELL_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall # <<mark>> TEST_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall -DINCLUDE_SQLITE_TCL_H=1 -DSQLITE_TCLAPI=__cdecl # <</mark>> !ELSE !IFNDEF PLATFORM CORE_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall SHELL_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall # <<mark>> TEST_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall -DINCLUDE_SQLITE_TCL_H=1 -DSQLITE_TCLAPI=__cdecl # <</mark>> !ELSE CORE_CCONV_OPTS = SHELL_CCONV_OPTS = # <<mark>> TEST_CCONV_OPTS = # <</mark>> |
︙ | ︙ | |||
783 784 785 786 787 788 789 | MKSQLITE3C_TOOL = $(TOP)\tool\mksqlite3c-noext.tcl !ELSE MKSQLITE3C_TOOL = $(TOP)\tool\mksqlite3c.tcl !ENDIF !ENDIF !IFNDEF MKSQLITE3C_ARGS | | | | | 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 | MKSQLITE3C_TOOL = $(TOP)\tool\mksqlite3c-noext.tcl !ELSE MKSQLITE3C_TOOL = $(TOP)\tool\mksqlite3c.tcl !ENDIF !ENDIF !IFNDEF MKSQLITE3C_ARGS !IF $(DEBUG)>1 MKSQLITE3C_ARGS = --linemacros !ELSE MKSQLITE3C_ARGS = !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. |
︙ | ︙ | |||
1243 1244 1245 1246 1247 1248 1249 | date.lo dbpage.lo dbstat.lo delete.lo \ expr.lo fault.lo fkey.lo \ fts3.lo fts3_aux.lo fts3_expr.lo fts3_hash.lo fts3_icu.lo \ fts3_porter.lo fts3_snippet.lo fts3_tokenizer.lo fts3_tokenizer1.lo \ fts3_tokenize_vtab.lo fts3_unicode.lo fts3_unicode2.lo fts3_write.lo \ fts5.lo \ func.lo global.lo hash.lo \ | | | | < | 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 | date.lo dbpage.lo dbstat.lo delete.lo \ expr.lo fault.lo fkey.lo \ fts3.lo fts3_aux.lo fts3_expr.lo fts3_hash.lo fts3_icu.lo \ fts3_porter.lo fts3_snippet.lo fts3_tokenizer.lo fts3_tokenizer1.lo \ fts3_tokenize_vtab.lo fts3_unicode.lo fts3_unicode2.lo fts3_write.lo \ fts5.lo \ func.lo global.lo hash.lo \ icu.lo insert.lo json1.lo legacy.lo loadext.lo \ main.lo malloc.lo mem0.lo mem1.lo mem2.lo mem3.lo mem5.lo \ memdb.lo memjournal.lo \ mutex.lo mutex_noop.lo mutex_unix.lo mutex_w32.lo \ notify.lo opcodes.lo os.lo os_unix.lo os_win.lo \ pager.lo 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 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 |
︙ | ︙ | |||
1310 1311 1312 1313 1314 1315 1316 | $(TOP)\src\expr.c \ $(TOP)\src\fault.c \ $(TOP)\src\fkey.c \ $(TOP)\src\func.c \ $(TOP)\src\global.c \ $(TOP)\src\hash.c \ $(TOP)\src\insert.c \ | < < | 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 | $(TOP)\src\expr.c \ $(TOP)\src\fault.c \ $(TOP)\src\fkey.c \ $(TOP)\src\func.c \ $(TOP)\src\global.c \ $(TOP)\src\hash.c \ $(TOP)\src\insert.c \ $(TOP)\src\legacy.c \ $(TOP)\src\loadext.c \ $(TOP)\src\main.c \ $(TOP)\src\malloc.c \ $(TOP)\src\mem0.c \ $(TOP)\src\mem1.c \ $(TOP)\src\mem2.c \ $(TOP)\src\mem3.c \ $(TOP)\src\mem5.c \ $(TOP)\src\memdb.c \ $(TOP)\src\memjournal.c \ $(TOP)\src\mutex.c \ $(TOP)\src\mutex_noop.c \ $(TOP)\src\mutex_unix.c \ $(TOP)\src\mutex_w32.c \ $(TOP)\src\notify.c \ $(TOP)\src\os.c \ $(TOP)\src\os_unix.c \ $(TOP)\src\os_win.c # Core source code files, part 2. # SRC01 = \ $(TOP)\src\pager.c \ |
︙ | ︙ | |||
1364 1365 1366 1367 1368 1369 1370 | $(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 \ | < | 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 | $(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 |
︙ | ︙ | |||
1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 | $(TOP)\src\sqliteInt.h \ $(TOP)\src\sqliteLimit.h \ $(TOP)\src\vdbe.h \ $(TOP)\src\vdbeInt.h \ $(TOP)\src\vxworks.h \ $(TOP)\src\wal.h \ $(TOP)\src\whereInt.h # Extension source code files, part 2. # SRC07 = \ $(TOP)\ext\fts3\fts3.c \ $(TOP)\ext\fts3\fts3_aux.c \ $(TOP)\ext\fts3\fts3_expr.c \ | > > > > > > > > > > > > > > | 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 | $(TOP)\src\sqliteInt.h \ $(TOP)\src\sqliteLimit.h \ $(TOP)\src\vdbe.h \ $(TOP)\src\vdbeInt.h \ $(TOP)\src\vxworks.h \ $(TOP)\src\wal.h \ $(TOP)\src\whereInt.h # Extension source code files, part 1. # SRC06 = \ $(TOP)\ext\fts1\fts1.c \ $(TOP)\ext\fts1\fts1_hash.c \ $(TOP)\ext\fts1\fts1_porter.c \ $(TOP)\ext\fts1\fts1_tokenizer1.c \ $(TOP)\ext\fts2\fts2.c \ $(TOP)\ext\fts2\fts2_hash.c \ $(TOP)\ext\fts2\fts2_icu.c \ $(TOP)\ext\fts2\fts2_porter.c \ $(TOP)\ext\fts2\fts2_tokenizer.c \ $(TOP)\ext\fts2\fts2_tokenizer1.c # Extension source code files, part 2. # SRC07 = \ $(TOP)\ext\fts3\fts3.c \ $(TOP)\ext\fts3\fts3_aux.c \ $(TOP)\ext\fts3\fts3_expr.c \ |
︙ | ︙ | |||
1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 | $(TOP)\ext\fts3\fts3_unicode.c \ $(TOP)\ext\fts3\fts3_unicode2.c \ $(TOP)\ext\fts3\fts3_write.c \ $(TOP)\ext\icu\icu.c \ $(TOP)\ext\rtree\rtree.c \ $(TOP)\ext\session\sqlite3session.c \ $(TOP)\ext\rbu\sqlite3rbu.c \ $(TOP)\ext\misc\stmt.c # Extension header files, part 2. # SRC09 = \ $(TOP)\ext\fts3\fts3.h \ $(TOP)\ext\fts3\fts3Int.h \ $(TOP)\ext\fts3\fts3_hash.h \ $(TOP)\ext\fts3\fts3_tokenizer.h \ | > > > > > > > > > > > | 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 | $(TOP)\ext\fts3\fts3_unicode.c \ $(TOP)\ext\fts3\fts3_unicode2.c \ $(TOP)\ext\fts3\fts3_write.c \ $(TOP)\ext\icu\icu.c \ $(TOP)\ext\rtree\rtree.c \ $(TOP)\ext\session\sqlite3session.c \ $(TOP)\ext\rbu\sqlite3rbu.c \ $(TOP)\ext\misc\json1.c \ $(TOP)\ext\misc\stmt.c # Extension header files, part 1. # SRC08 = \ $(TOP)\ext\fts1\fts1.h \ $(TOP)\ext\fts1\fts1_hash.h \ $(TOP)\ext\fts1\fts1_tokenizer.h \ $(TOP)\ext\fts2\fts2.h \ $(TOP)\ext\fts2\fts2_hash.h \ $(TOP)\ext\fts2\fts2_tokenizer.h # Extension header files, part 2. # SRC09 = \ $(TOP)\ext\fts3\fts3.h \ $(TOP)\ext\fts3\fts3Int.h \ $(TOP)\ext\fts3\fts3_hash.h \ $(TOP)\ext\fts3\fts3_tokenizer.h \ |
︙ | ︙ | |||
1470 1471 1472 1473 1474 1475 1476 | $(SQLITETCLDECLSH) !ELSE SRC12 = !ENDIF # All source code files. # | | > | 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 | $(SQLITETCLDECLSH) !ELSE SRC12 = !ENDIF # All source code files. # SRC = $(SRC00) $(SRC01) $(SRC03) $(SRC04) $(SRC05) $(SRC06) $(SRC07) $(SRC08) $(SRC09) $(SRC10) $(SRC11) # Source code to the test files. # TESTSRC = \ $(TOP)\src\test1.c \ $(TOP)\src\test2.c \ $(TOP)\src\test3.c \ $(TOP)\src\test4.c \ $(TOP)\src\test5.c \ $(TOP)\src\test6.c \ $(TOP)\src\test7.c \ $(TOP)\src\test8.c \ $(TOP)\src\test9.c \ $(TOP)\src\test_autoext.c \ $(TOP)\src\test_async.c \ $(TOP)\src\test_backup.c \ $(TOP)\src\test_bestindex.c \ $(TOP)\src\test_blob.c \ |
︙ | ︙ | |||
1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 | $(TOP)\src\test_mutex.c \ $(TOP)\src\test_onefile.c \ $(TOP)\src\test_osinst.c \ $(TOP)\src\test_pcache.c \ $(TOP)\src\test_quota.c \ $(TOP)\src\test_rtree.c \ $(TOP)\src\test_schema.c \ $(TOP)\src\test_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 \ | > | < < < < < | < < < < < > | 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 | $(TOP)\src\test_mutex.c \ $(TOP)\src\test_onefile.c \ $(TOP)\src\test_osinst.c \ $(TOP)\src\test_pcache.c \ $(TOP)\src\test_quota.c \ $(TOP)\src\test_rtree.c \ $(TOP)\src\test_schema.c \ $(TOP)\src\test_server.c \ $(TOP)\src\test_superlock.c \ $(TOP)\src\test_syscall.c \ $(TOP)\src\test_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\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\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 # If use of zlib is enabled, add the "zipfile.c" source file. # !IF $(USE_ZLIB)!=0 TESTEXT = $(TESTEXT) $(TOP)\ext\misc\zipfile.c !ENDIF # Source code to the library files needed by the test fixture # (non-amalgamation) # TESTSRC2 = \ $(SRC00) \ $(SRC01) \ $(SRC06) \ $(SRC07) \ $(SRC10) \ $(TOP)\ext\async\sqlite3async.c # Header files used by all library source files. # HDR = \ |
︙ | ︙ | |||
1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 | $(TOP)\src\vdbeInt.h \ $(TOP)\src\vxworks.h \ $(TOP)\src\whereInt.h # Header files used by extensions # EXTHDR = $(EXTHDR) \ $(TOP)\ext\fts3\fts3.h \ $(TOP)\ext\fts3\fts3Int.h \ $(TOP)\ext\fts3\fts3_hash.h \ $(TOP)\ext\fts3\fts3_tokenizer.h EXTHDR = $(EXTHDR) \ $(TOP)\ext\rtree\rtree.h \ $(TOP)\ext\rtree\geopoly.c | > > > > > > > > | 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 | $(TOP)\src\vdbeInt.h \ $(TOP)\src\vxworks.h \ $(TOP)\src\whereInt.h # Header files used by extensions # EXTHDR = $(EXTHDR) \ $(TOP)\ext\fts1\fts1.h \ $(TOP)\ext\fts1\fts1_hash.h \ $(TOP)\ext\fts1\fts1_tokenizer.h EXTHDR = $(EXTHDR) \ $(TOP)\ext\fts2\fts2.h \ $(TOP)\ext\fts2\fts2_hash.h \ $(TOP)\ext\fts2\fts2_tokenizer.h EXTHDR = $(EXTHDR) \ $(TOP)\ext\fts3\fts3.h \ $(TOP)\ext\fts3\fts3Int.h \ $(TOP)\ext\fts3\fts3_hash.h \ $(TOP)\ext\fts3\fts3_tokenizer.h EXTHDR = $(EXTHDR) \ $(TOP)\ext\rtree\rtree.h \ $(TOP)\ext\rtree\geopoly.c |
︙ | ︙ | |||
1653 1654 1655 1656 1657 1658 1659 | $(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 | < > | | < < | < | < < < < < < < < < > | 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 | $(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 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_DESERIALIZE=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_DESERIALIZE FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_FTS4 FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_RTREE FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_GEOPOLY FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_DBSTAT_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. # |
︙ | ︙ | |||
1752 1753 1754 1755 1756 1757 1758 | $(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 \ | | | 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 | $(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)?_[^@]*)(?:@\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) |
︙ | ︙ | |||
1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 | -rmdir /Q/S tsrc 2>NUL -mkdir tsrc for %i in ($(SRC00)) do copy /Y %i tsrc for %i in ($(SRC01)) do copy /Y %i tsrc for %i in ($(SRC03)) do copy /Y %i tsrc for %i in ($(SRC04)) do copy /Y %i tsrc for %i in ($(SRC05)) do copy /Y %i tsrc for %i in ($(SRC07)) 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 | > > < < | > | < | 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 | -rmdir /Q/S tsrc 2>NUL -mkdir tsrc for %i in ($(SRC00)) do copy /Y %i tsrc for %i in ($(SRC01)) do copy /Y %i tsrc for %i in ($(SRC03)) do copy /Y %i tsrc for %i in ($(SRC04)) do copy /Y %i tsrc for %i in ($(SRC05)) do copy /Y %i tsrc for %i in ($(SRC06)) do copy /Y %i tsrc 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 sqlite3.c: .target_source sqlite3ext.h $(MKSQLITE3C_TOOL) $(TCLSH_CMD) $(MKSQLITE3C_TOOL) $(MKSQLITE3C_ARGS) copy $(TOP)\ext\session\sqlite3session.h . 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 $(TOP)\tool\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 |
︙ | ︙ | |||
1965 1966 1967 1968 1969 1970 1971 | hash.lo: $(TOP)\src\hash.c $(HDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\hash.c insert.lo: $(TOP)\src\insert.c $(HDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\insert.c | < < < | 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 | hash.lo: $(TOP)\src\hash.c $(HDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\hash.c insert.lo: $(TOP)\src\insert.c $(HDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\insert.c legacy.lo: $(TOP)\src\legacy.c $(HDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\legacy.c loadext.lo: $(TOP)\src\loadext.c $(HDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\loadext.c main.lo: $(TOP)\src\main.c $(HDR) |
︙ | ︙ | |||
2028 2029 2030 2031 2032 2033 2034 | pcache1.lo: $(TOP)\src\pcache1.c $(HDR) $(TOP)\src\pcache.h $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\pcache1.c os.lo: $(TOP)\src\os.c $(HDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\os.c | < < < | 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 | pcache1.lo: $(TOP)\src\pcache1.c $(HDR) $(TOP)\src\pcache.h $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\pcache1.c os.lo: $(TOP)\src\os.c $(HDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\os.c os_unix.lo: $(TOP)\src\os_unix.c $(HDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\os_unix.c os_win.lo: $(TOP)\src\os_win.c $(HDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\os_win.c pragma.lo: $(TOP)\src\pragma.c $(HDR) |
︙ | ︙ | |||
2112 2113 2114 2115 2116 2117 2118 | 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 | < < < | 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 | 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) |
︙ | ︙ | |||
2159 2160 2161 2162 2163 2164 2165 | # 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 | | < | < < < < < < | < < < < < < | < < < > > > > > > > > > > > > > > > > > > | 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 | # 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 $(TOP)\src\parse.y . .\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) 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 !ENDIF 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\shathree.c \ $(TOP)\ext\misc\fileio.c \ $(TOP)\ext\misc\completion.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 !ENDIF shell.c: $(SHELL_SRC) $(TOP)\tool\mkshellc.tcl $(TCLSH_CMD) $(TOP)\tool\mkshellc.tcl > shell.c zlib: pushd $(ZLIBDIR) && $(MAKE) /f win32\Makefile.msc clean $(ZLIBLIB) && popd # Rules to build the extension objects. # icu.lo: $(TOP)\ext\icu\icu.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\icu\icu.c fts2.lo: $(TOP)\ext\fts2\fts2.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts2\fts2.c fts2_hash.lo: $(TOP)\ext\fts2\fts2_hash.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts2\fts2_hash.c fts2_icu.lo: $(TOP)\ext\fts2\fts2_icu.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts2\fts2_icu.c fts2_porter.lo: $(TOP)\ext\fts2\fts2_porter.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts2\fts2_porter.c fts2_tokenizer.lo: $(TOP)\ext\fts2\fts2_tokenizer.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts2\fts2_tokenizer.c fts2_tokenizer1.lo: $(TOP)\ext\fts2\fts2_tokenizer1.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts2\fts2_tokenizer1.c fts3.lo: $(TOP)\ext\fts3\fts3.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3.c fts3_aux.lo: $(TOP)\ext\fts3\fts3_aux.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_aux.c fts3_expr.lo: $(TOP)\ext\fts3\fts3_expr.c $(HDR) $(EXTHDR) |
︙ | ︙ | |||
2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 | fts3_unicode2.lo: $(TOP)\ext\fts3\fts3_unicode2.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_unicode2.c fts3_write.lo: $(TOP)\ext\fts3\fts3_write.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_write.c stmt.lo: $(TOP)\ext\misc\stmt.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\misc\stmt.c rtree.lo: $(TOP)\ext\rtree\rtree.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\rtree\rtree.c sqlite3session.lo: $(TOP)\ext\session\sqlite3session.c $(HDR) $(EXTHDR) | > > > | 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 | fts3_unicode2.lo: $(TOP)\ext\fts3\fts3_unicode2.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_unicode2.c fts3_write.lo: $(TOP)\ext\fts3\fts3_write.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\fts3\fts3_write.c json1.lo: $(TOP)\ext\misc\json1.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\misc\json1.c stmt.lo: $(TOP)\ext\misc\stmt.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\misc\stmt.c rtree.lo: $(TOP)\ext\rtree\rtree.c $(HDR) $(EXTHDR) $(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c $(TOP)\ext\rtree\rtree.c sqlite3session.lo: $(TOP)\ext\session\sqlite3session.c $(HDR) $(EXTHDR) |
︙ | ︙ | |||
2313 2314 2315 2316 2317 2318 2319 | $(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 | | < | | < | < | 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 | $(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 $(TOP)\ext\fts5\fts5parse.y . del /Q fts5parse.h 2>NUL .\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) fts5parse.y fts5parse.h: fts5parse.c fts5.c: $(FTS5_SRC) $(TCLSH_CMD) $(TOP)\ext\fts5\tool\mkfts5c.tcl copy $(TOP)\ext\fts5\fts5.h . lsm1.c: $(LSM1_SRC) $(TCLSH_CMD) $(TOP)\ext\lsm1\tool\mklsm1c.tcl copy $(TOP)\ext\lsm1\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 |
︙ | ︙ | |||
2356 2357 2358 2359 2360 2361 2362 | 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 | | | | 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 | 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 TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_DESERIALIZE=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 |
︙ | ︙ | |||
2402 2403 2404 2405 2406 2407 2408 | @set PATH=$(LIBTCLPATH);$(PATH) .\testfixture.exe $(TOP)\test\loadext.test $(TESTOPTS) coretestprogs: $(TESTPROGS) testprogs: coretestprogs srcck1.exe fuzzcheck.exe sessionfuzz.exe | < < | > > > | < < < < < < < < < < < < < < < < < < < < < < < | 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 | @set PATH=$(LIBTCLPATH);$(PATH) .\testfixture.exe $(TOP)\test\loadext.test $(TESTOPTS) coretestprogs: $(TESTPROGS) testprogs: coretestprogs srcck1.exe fuzzcheck.exe sessionfuzz.exe fulltest: $(TESTPROGS) fuzztest @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) fastfuzztest: fuzzcheck.exe .\fuzzcheck.exe --limit-mem 100M $(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 fastfuzztest @set PATH=$(LIBTCLPATH);$(PATH) .\testfixture.exe $(TOP)\test\veryquick.test $(TESTOPTS) smoketest: $(TESTPROGS) @set PATH=$(LIBTCLPATH);$(PATH) .\testfixture.exe $(TOP)\test\main.test $(TESTOPTS) sqlite3_analyzer.c: $(SQLITE3C) $(SQLITE3H) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in $(SQLITE_TCL_DEP) $(TCLSH_CMD) $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in > $@ sqlite3_analyzer.exe: sqlite3_analyzer.c $(LIBRESOBJS) $(LTLINK) $(NO_WARN) -DBUILD_sqlite -I$(TCLINCDIR) sqlite3_analyzer.c \ /link $(LDFLAGS) $(LTLINKOPTS) $(TCLLIBPATHS) $(LTLIBPATHS) $(LIBRESOBJS) $(TCLLIBS) $(LTLIBS) $(TLIBS) |
︙ | ︙ | |||
2574 2575 2576 2577 2578 2579 2580 | $(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) | < < < < < < < < < < < | 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 | $(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>> |
︙ | ︙ | |||
2622 2623 2624 2625 2626 2627 2628 | 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 | | | 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 | 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 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 | <h1 align="center">SQLite Source Repository</h1> | | | | | | | | | | | | | | 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 ~/sqlite cd ~/sqlite fossil clone https://www.sqlite.org/src sqlite.fossil fossil open 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 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". |
︙ | ︙ | |||
90 91 92 93 94 95 96 | 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 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: mkdir bld cd bld nmake /f Makefile.msc TOP=..\sqlite nmake /f Makefile.msc sqlite3.c TOP=..\sqlite nmake /f Makefile.msc sqlite3.dll TOP=..\sqlite nmake /f Makefile.msc sqlite3.exe TOP=..\sqlite nmake /f 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. |
︙ | ︙ | |||
132 133 134 135 136 137 138 | [command-line shell](https://sqlite.org/cli.html) and the "tclsqlite.c" file which implements the [Tcl bindings](https://sqlite.org/tclsqlite.html) for SQLite. (Historical note: SQLite began as a Tcl extension and only later escaped to the wild as an independent library.) Test scripts and programs are found in the **test/** subdirectory. | | | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | [command-line shell](https://sqlite.org/cli.html) and the "tclsqlite.c" file which implements the [Tcl bindings](https://sqlite.org/tclsqlite.html) for SQLite. (Historical note: SQLite began as a Tcl extension and only later escaped to the wild as an independent library.) Test scripts and programs are found in the **test/** subdirectory. Addtional test code is found in other source repositories. See [How SQLite Is Tested](http://www.sqlite.org/testing.html) for additional information. The **ext/** subdirectory contains code for extensions. The Full-text search engine is in **ext/fts3**. The R-Tree engine is in **ext/rtree**. The **ext/misc** subdirectory contains a number of smaller, single-file extensions, such as a REGEXP operator. |
︙ | ︙ | |||
166 167 168 169 170 171 172 | and is used to generate the SQLITE\_SOURCE\_ID macro. The VERSION file contains the current SQLite version number. The sqlite3.h header is really just a copy of src/sqlite.h.in with the source-id and version number inserted at just the right spots. Note that comment text in the sqlite3.h file is used to generate much of the SQLite API documentation. The Tcl scripts used to generate that documentation are in a separate source repository. | | | | 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 | and is used to generate the SQLITE\_SOURCE\_ID macro. The VERSION file contains the current SQLite version number. The sqlite3.h header is really just a copy of src/sqlite.h.in with the source-id and version number inserted at just the right spots. Note that comment text in the sqlite3.h file is used to generate much of the SQLite API documentation. The Tcl scripts 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 opcode-number to opcode-name that is used for EXPLAIN output. The **keywordhash.h** header file contains the definition of a hash table that maps SQL language keywords (ex: "CREATE", "SELECT", "INDEX", etc.) into |
︙ | ︙ | |||
233 234 235 236 237 238 239 | (helping to understand how SQLite works include the [file format](http://www.sqlite.org/fileformat2.html) description, the [virtual machine](http://www.sqlite.org/opcode.html) that runs prepared statements, the description of [how transactions work](http://www.sqlite.org/atomiccommit.html), and the [overview of the query planner](http://www.sqlite.org/optoverview.html). | | | 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | (helping to understand how SQLite works include the [file format](http://www.sqlite.org/fileformat2.html) description, the [virtual machine](http://www.sqlite.org/opcode.html) that runs prepared statements, the description of [how transactions work](http://www.sqlite.org/atomiccommit.html), and the [overview of the query planner](http://www.sqlite.org/optoverview.html). Years of effort have gone into optimizating SQLite, both for small size and high performance. And optimizations tend to result in complex code. So there is a lot of complexity in the current SQLite implementation. It will not be the easiest library in the world to hack. Key files: * **sqlite.h.in** - This file defines the public interface to the SQLite |
︙ | ︙ | |||
290 291 292 293 294 295 296 | is not part of the core SQLite library. But as most of the tests in this repository are written in Tcl, the Tcl language bindings are important. * **test*.c** - Files in the src/ folder that begin with "test" go into building the "testfixture.exe" program. The testfixture.exe program is an enhanced Tcl shell. The testfixture.exe program runs scripts in the test/ folder to validate the core SQLite code. The testfixture program | | | > > > > > > > > > > > > > > > | > | | < > | < < > | | | 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 | is not part of the core SQLite library. But as most of the tests in this repository are written in Tcl, the Tcl language bindings are important. * **test*.c** - Files in the src/ folder that begin with "test" go into building the "testfixture.exe" program. The testfixture.exe program is an enhanced Tcl shell. The testfixture.exe program runs scripts in the test/ folder to validate the core SQLite code. The testfixture program (and some other test programs too) is build and run when you type "make test". * **ext/misc/json1.c** - This file implements the various JSON functions that are build into SQLite. 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 If you obtained an SQLite source tree from a secondary source, such as a GitHub mirror, and you want to verify that it has not been altered, there are a couple of ways to do that. If you have a release version of SQLite, and you are using the `sqlite3.c` amalgamation, then SHA3-256 hashes for the amalgamation are available in the [change log](https://www.sqlite.org/changes.html) on the official website. After building the `sqlite3.c` file, you can check that it is authentic by comparing the hash. This does not ensure that the test scripts are unaltered, but it does validate the deliverable part of the code and the verification process only involves computing and comparing a single hash. For versions other than an official release, or if you are building the `sqlite3.c` amalgamation using non-standard build options, the verification process is a little more involved. 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. You can write a script to extracts hashes from `manifest` and verifies the hashes against the corresponding files in the source tree. 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.28.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 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 -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 |
︙ | ︙ | |||
192 193 194 195 196 197 198 | # 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 | < < < < < < < | 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 | # 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 !ELSE |
︙ | ︙ | |||
281 282 283 284 285 286 287 288 289 290 | # the Windows platform. # !IFNDEF OPT_FEATURE_FLAGS !IF $(MINIMAL_AMALGAMATION)==0 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_STMTVTAB=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBSTAT_VTAB=1 | > | > < < < < < < < < < < | 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 | # the Windows platform. # !IFNDEF OPT_FEATURE_FLAGS !IF $(MINIMAL_AMALGAMATION)==0 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_INTROSPECTION_PRAGMAS=1 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DESERIALIZE=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 # 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 EXT_FEATURE_FLAGS = $(EXT_FEATURE_FLAGS) -DSQLITE_SYSTEM_MALLOC=1 |
︙ | ︙ | |||
497 498 499 500 501 502 503 | # also be noted here that building any target with these "stdcall" options # will most likely fail if the Tcl library is also required. This is due # to how the Tcl library functions are declared and exported (i.e. without # an explicit calling convention, which results in "cdecl"). # !IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0 !IF "$(PLATFORM)"=="x86" | | | | | | 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 | # also be noted here that building any target with these "stdcall" options # will most likely fail if the Tcl library is also required. This is due # to how the Tcl library functions are declared and exported (i.e. without # an explicit calling convention, which results in "cdecl"). # !IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0 !IF "$(PLATFORM)"=="x86" CORE_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall SHELL_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall !ELSE !IFNDEF PLATFORM CORE_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall SHELL_CCONV_OPTS = -Gz -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall !ELSE CORE_CCONV_OPTS = SHELL_CCONV_OPTS = !ENDIF !ENDIF !ELSE CORE_CCONV_OPTS = |
︙ | ︙ | |||
954 955 956 957 958 959 960 961 962 963 964 965 966 967 | # 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 | > | 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 | # 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 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_DESERIALIZE=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 |
︙ | ︙ | |||
988 989 990 991 992 993 994 | Replace.exe: $(CSC) /target:exe $(TOP)\Replace.cs sqlite3.def: Replace.exe $(LIBOBJ) echo EXPORTS > sqlite3.def dumpbin /all $(LIBOBJ) \ | | | 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 | 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)?_[^@,]*)(?:@\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/README.txt.
︙ | ︙ | |||
101 102 103 104 105 106 107 | Additionally, preprocessor defines may be specified by using the OPTS macro on the NMAKE command line. However, not all possible preprocessor defines may be specified in this manner as some require the amalgamation to be built with them enabled (see http://www.sqlite.org/compile.html). For example, the following will work: | | | 101 102 103 104 105 106 107 108 109 110 111 112 113 | Additionally, preprocessor defines may be specified by using the OPTS macro on the NMAKE command line. However, not all possible preprocessor defines may be specified in this manner as some require the amalgamation to be built with them enabled (see http://www.sqlite.org/compile.html). For example, the following will work: "OPTS=-DSQLITE_ENABLE_STAT4=1 -DSQLITE_ENABLE_JSON1=1" However, the following will not compile unless the amalgamation was built with it enabled: "OPTS=-DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1" |
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 | #----------------------------------------------------------------------- # --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 -D_REENTRANT=1 -DSQLITE_THREADSAFE=1" AC_SEARCH_LIBS(pthread_create, pthread) AC_SEARCH_LIBS(pthread_mutexattr_init, pthread) fi #----------------------------------------------------------------------- #----------------------------------------------------------------------- |
︙ | ︙ | |||
107 108 109 110 111 112 113 | 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) #----------------------------------------------------------------------- | < < < < < < < < < < < < < < < < < < < < < < < < < < > > | > | > > > > > > < | < < < < < < < < < < < | 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 | 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 BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_RTREE" fi #----------------------------------------------------------------------- #----------------------------------------------------------------------- # --enable-session # AC_ARG_ENABLE(session, [AS_HELP_STRING( [--enable-session], [enable the session extension [default=no]])], [], []) if test x"$enable_session" = "xyes"; then BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_SESSION -DSQLITE_ENABLE_PREUPDATE_HOOK" fi #----------------------------------------------------------------------- #----------------------------------------------------------------------- # --enable-debug # AC_ARG_ENABLE(debug, [AS_HELP_STRING( [--enable-debug], [build with debugging features enabled [default=no]])], [], []) if test x"$enable_debug" = "xyes"; then BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_DEBUG -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE" CFLAGS="-g -O0" fi #----------------------------------------------------------------------- #----------------------------------------------------------------------- # --enable-static-shell # AC_ARG_ENABLE(static-shell, [AS_HELP_STRING( |
︙ | ︙ |
Changes to autoconf/tea/Makefile.in.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # Makefile.in -- # # This file is a Makefile for Sample TEA Extension. If it has the name # "Makefile.in" then it is a template for a Makefile; to generate the # actual Makefile, run "./configure", which is a configuration script # generated by the "autoconf" program (constructs like "@foo@" will get # replaced in the actual Makefile. # # Copyright (c) 1999 Scriptics Corporation. # Copyright (c) 2002-2005 ActiveState Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. #======================================================================== # Add additional lines to handle any additional AC_SUBST cases that # have been added in a customized configure script. #======================================================================== #SAMPLE_NEW_VAR = @SAMPLE_NEW_VAR@ | > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # Makefile.in -- # # This file is a Makefile for Sample TEA Extension. If it has the name # "Makefile.in" then it is a template for a Makefile; to generate the # actual Makefile, run "./configure", which is a configuration script # generated by the "autoconf" program (constructs like "@foo@" will get # replaced in the actual Makefile. # # Copyright (c) 1999 Scriptics Corporation. # Copyright (c) 2002-2005 ActiveState Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # RCS: @(#) $Id: Makefile.in,v 1.59 2005/07/26 19:17:02 mdejong Exp $ #======================================================================== # Add additional lines to handle any additional AC_SUBST cases that # have been added in a customized configure script. #======================================================================== #SAMPLE_NEW_VAR = @SAMPLE_NEW_VAR@ |
︙ | ︙ | |||
54 55 56 57 58 59 60 | #======================================================================== # "PKG_LIB_FILE" refers to the library (dynamic or static as per # configuration options) composed of the named objects. #======================================================================== PKG_LIB_FILE = @PKG_LIB_FILE@ | < < < < > | < | | < < < > > > > > | | > | < | > | | < < < < | < < < < < < < < | > | 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 | #======================================================================== # "PKG_LIB_FILE" refers to the library (dynamic or static as per # configuration options) composed of the named objects. #======================================================================== PKG_LIB_FILE = @PKG_LIB_FILE@ PKG_STUB_LIB_FILE = @PKG_STUB_LIB_FILE@ lib_BINARIES = $(PKG_LIB_FILE) BINARIES = $(lib_BINARIES) SHELL = @SHELL@ srcdir = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ libdir = @libdir@ datarootdir = @datarootdir@ datadir = @datadir@ mandir = @mandir@ includedir = @includedir@ DESTDIR = PKG_DIR = $(PACKAGE_NAME)$(PACKAGE_VERSION) pkgdatadir = $(datadir)/$(PKG_DIR) pkglibdir = $(libdir)/$(PKG_DIR) pkgincludedir = $(includedir)/$(PKG_DIR) top_builddir = . INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ CC = @CC@ CFLAGS_DEFAULT = @CFLAGS_DEFAULT@ CFLAGS_WARNING = @CFLAGS_WARNING@ CLEANFILES = @CLEANFILES@ EXEEXT = @EXEEXT@ LDFLAGS_DEFAULT = @LDFLAGS_DEFAULT@ MAKE_LIB = @MAKE_LIB@ MAKE_SHARED_LIB = @MAKE_SHARED_LIB@ MAKE_STATIC_LIB = @MAKE_STATIC_LIB@ MAKE_STUB_LIB = @MAKE_STUB_LIB@ OBJEXT = @OBJEXT@ RANLIB = @RANLIB@ RANLIB_STUB = @RANLIB_STUB@ SHLIB_CFLAGS = @SHLIB_CFLAGS@ SHLIB_LD = @SHLIB_LD@ SHLIB_LD_LIBS = @SHLIB_LD_LIBS@ STLIB_LD = @STLIB_LD@ #TCL_DEFS = @TCL_DEFS@ TCL_BIN_DIR = @TCL_BIN_DIR@ TCL_SRC_DIR = @TCL_SRC_DIR@ #TK_BIN_DIR = @TK_BIN_DIR@ #TK_SRC_DIR = @TK_SRC_DIR@ # This is no longer necessary even for packages that use private Tcl headers #TCL_TOP_DIR_NATIVE = @TCL_TOP_DIR_NATIVE@ # Not used, but retained for reference of what libs Tcl required #TCL_LIBS = @TCL_LIBS@ #======================================================================== # TCLLIBPATH seeds the auto_path in Tcl's init.tcl so we can test our # package without installing. The other environment variables allow us # to test against an uninstalled Tcl. Add special env vars that you # require for testing here (like TCLX_LIBRARY). #======================================================================== EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR) #EXTRA_PATH = $(top_builddir):$(TCL_BIN_DIR):$(TK_BIN_DIR) TCLLIBPATH = $(top_builddir) TCLSH_ENV = TCL_LIBRARY=`@CYGPATH@ $(TCL_SRC_DIR)/library` \ @LD_LIBRARY_PATH_VAR@="$(EXTRA_PATH):$(@LD_LIBRARY_PATH_VAR@)" \ PATH="$(EXTRA_PATH):$(PATH)" \ TCLLIBPATH="$(TCLLIBPATH)" # TK_LIBRARY=`@CYGPATH@ $(TK_SRC_DIR)/library` TCLSH_PROG = @TCLSH_PROG@ TCLSH = $(TCLSH_ENV) $(TCLSH_PROG) #WISH_PROG = @WISH_PROG@ #WISH = $(TCLSH_ENV) $(WISH_PROG) SHARED_BUILD = @SHARED_BUILD@ INCLUDES = @PKG_INCLUDES@ @TCL_INCLUDES@ -I$(srcdir)/.. #INCLUDES = @PKG_INCLUDES@ @TCL_INCLUDES@ @TK_INCLUDES@ @TK_XINCLUDES@ PKG_CFLAGS = @PKG_CFLAGS@ # TCL_DEFS is not strictly need here, but if you remove it, then you # must make sure that configure.in checks for the necessary components # that your library may use. TCL_DEFS can actually be a problem if # you do not compile with a similar machine setup as the Tcl core was # compiled with. #DEFS = $(TCL_DEFS) @DEFS@ $(PKG_CFLAGS) DEFS = @DEFS@ $(PKG_CFLAGS) CONFIG_CLEAN_FILES = Makefile pkgIndex.tcl CPPFLAGS = @CPPFLAGS@ LIBS = @PKG_LIBS@ @LIBS@ AR = @AR@ CFLAGS = @CFLAGS@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) #======================================================================== # Start of user-definable TARGETS section #======================================================================== #======================================================================== # TEA TARGETS. Please note that the "libraries:" target refers to platform # independent files, and the "binaries:" target inclues executable programs and # platform-dependent libraries. Modify these targets so that they install # the various pieces of your package. The make and install rules # for the BINARIES that you specified above have already been done. #======================================================================== all: binaries libraries doc #======================================================================== # The binaries target builds executable programs, Windows .dll's, unix # shared/static libraries, and any other platform-dependent files. # The list of targets to build for "binaries:" is specified at the top # of the Makefile, in the "BINARIES" variable. #======================================================================== binaries: $(BINARIES) libraries: #======================================================================== # Your doc target should differentiate from doc builds (by the developer) # and doc installs (see install-doc), which just install the docs on the # end user machine when building from source. #======================================================================== |
︙ | ︙ | |||
222 223 224 225 226 227 228 | #======================================================================== # This rule installs platform-independent files, such as header files. # The list=...; for p in $$list handles the empty list case x-platform. #======================================================================== install-libraries: libraries | | | | | > < < < | < < < < < < < < < < < | 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 | #======================================================================== # This rule installs platform-independent files, such as header files. # The list=...; for p in $$list handles the empty list case x-platform. #======================================================================== install-libraries: libraries @mkdir -p $(DESTDIR)$(includedir) @echo "Installing header files in $(DESTDIR)$(includedir)" @list='$(PKG_HEADERS)'; for i in $$list; do \ echo "Installing $(srcdir)/$$i" ; \ $(INSTALL_DATA) $(srcdir)/$$i $(DESTDIR)$(includedir) ; \ done; #======================================================================== # Install documentation. Unix manpages should go in the $(mandir) # directory. #======================================================================== install-doc: doc @mkdir -p $(DESTDIR)$(mandir)/mann @echo "Installing documentation in $(DESTDIR)$(mandir)" @list='$(srcdir)/doc/*.n'; for i in $$list; do \ echo "Installing $$i"; \ rm -f $(DESTDIR)$(mandir)/mann/`basename $$i`; \ $(INSTALL_DATA) $$i $(DESTDIR)$(mandir)/mann ; \ done test: binaries libraries @echo "SQLite TEA distribution does not include tests" shell: binaries libraries @$(TCLSH) $(SCRIPT) gdb: $(TCLSH_ENV) gdb $(TCLSH_PROG) $(SCRIPT) depend: #======================================================================== # $(PKG_LIB_FILE) should be listed as part of the BINARIES variable # mentioned above. That will ensure that this target is built when you # run "make binaries". |
︙ | ︙ | |||
302 303 304 305 306 307 308 | # $(COMPILE) -c `@CYGPATH@ $(srcdir)/generic/sample.c` -o $@ # # Setting the VPATH variable to a list of paths will cause the makefile # to look into these paths when resolving .c to .obj dependencies. # As necessary, add $(srcdir):$(srcdir)/compat:.... #======================================================================== | | < < < < < < < < < < < < < < | < < < | | | < < | | > | < < | < > | > > < | | < < < < | > > | | | | | | | | > > > > > > | > > | | | | | > > | | | < | 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 | # $(COMPILE) -c `@CYGPATH@ $(srcdir)/generic/sample.c` -o $@ # # Setting the VPATH variable to a list of paths will cause the makefile # to look into these paths when resolving .c to .obj dependencies. # As necessary, add $(srcdir):$(srcdir)/compat:.... #======================================================================== VPATH = $(srcdir):$(srcdir)/generic:$(srcdir)/unix:$(srcdir)/win .c.@OBJEXT@: $(COMPILE) -c `@CYGPATH@ $<` -o $@ #======================================================================== # Distribution creation # You may need to tweak this target to make it work correctly. #======================================================================== #COMPRESS = tar cvf $(PKG_DIR).tar $(PKG_DIR); compress $(PKG_DIR).tar COMPRESS = gtar zcvf $(PKG_DIR).tar.gz $(PKG_DIR) DIST_ROOT = /tmp/dist DIST_DIR = $(DIST_ROOT)/$(PKG_DIR) dist-clean: rm -rf $(DIST_DIR) $(DIST_ROOT)/$(PKG_DIR).tar.* dist: dist-clean mkdir -p $(DIST_DIR) cp -p $(srcdir)/README* $(srcdir)/license* \ $(srcdir)/aclocal.m4 $(srcdir)/configure $(srcdir)/*.in \ $(DIST_DIR)/ chmod 664 $(DIST_DIR)/Makefile.in $(DIST_DIR)/aclocal.m4 chmod 775 $(DIST_DIR)/configure $(DIST_DIR)/configure.in for i in $(srcdir)/*.[ch]; do \ if [ -f $$i ]; then \ cp -p $$i $(DIST_DIR)/ ; \ fi; \ done; mkdir $(DIST_DIR)/tclconfig cp $(srcdir)/tclconfig/install-sh $(srcdir)/tclconfig/tcl.m4 \ $(DIST_DIR)/tclconfig/ chmod 664 $(DIST_DIR)/tclconfig/tcl.m4 chmod +x $(DIST_DIR)/tclconfig/install-sh list='demos doc generic library mac tests unix win'; \ for p in $$list; do \ if test -d $(srcdir)/$$p ; then \ mkdir $(DIST_DIR)/$$p; \ cp -p $(srcdir)/$$p/*.* $(DIST_DIR)/$$p/; \ fi; \ done (cd $(DIST_ROOT); $(COMPRESS);) #======================================================================== # End of user-definable section #======================================================================== #======================================================================== # Don't modify the file to clean here. Instead, set the "CLEANFILES" # variable in configure.in #======================================================================== clean: -test -z "$(BINARIES)" || rm -f $(BINARIES) -rm -f *.$(OBJEXT) core *.core -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean: clean -rm -f *.tab.c -rm -f $(CONFIG_CLEAN_FILES) -rm -f config.h config.cache config.log config.status #======================================================================== # Install binary object libraries. On Windows this includes both .dll and # .lib files. Because the .lib files are not explicitly listed anywhere, # we need to deduce their existence from the .dll file of the same name. # Library files go into the lib directory. # In addition, this will generate the pkgIndex.tcl # file in the install location (assuming it can find a usable tclsh shell) # # You should not have to modify this target. #======================================================================== install-lib-binaries: binaries @mkdir -p $(DESTDIR)$(pkglibdir) @list='$(lib_BINARIES)'; for p in $$list; do \ if test -f $$p; then \ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p"; \ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkglibdir)/$$p; \ stub=`echo $$p|sed -e "s/.*\(stub\).*/\1/"`; \ if test "x$$stub" = "xstub"; then \ echo " $(RANLIB_STUB) $(DESTDIR)$(pkglibdir)/$$p"; \ $(RANLIB_STUB) $(DESTDIR)$(pkglibdir)/$$p; \ else \ echo " $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p"; \ $(RANLIB) $(DESTDIR)$(pkglibdir)/$$p; \ fi; \ ext=`echo $$p|sed -e "s/.*\.//"`; \ if test "x$$ext" = "xdll"; then \ lib=`basename $$p|sed -e 's/.[^.]*$$//'`.lib; \ if test -f $$lib; then \ echo " $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib"; \ $(INSTALL_DATA) $$lib $(DESTDIR)$(pkglibdir)/$$lib; \ fi; \ fi; \ fi; \ done @list='$(PKG_TCL_SOURCES)'; for p in $$list; do \ if test -f $(srcdir)/$$p; then \ destp=`basename $$p`; \ echo " Install $$destp $(DESTDIR)$(pkglibdir)/$$destp"; \ $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(pkglibdir)/$$destp; \ fi; \ done @if test "x$(SHARED_BUILD)" = "x1"; then \ echo " Install pkgIndex.tcl $(DESTDIR)$(pkglibdir)"; \ $(INSTALL_DATA) pkgIndex.tcl $(DESTDIR)$(pkglibdir); \ fi #======================================================================== # Install binary executables (e.g. .exe files and dependent .dll files) # This is for files that must go in the bin directory (located next to # wish and tclsh), like dependent .dll files on Windows. # # You should not have to modify this target, except to define bin_BINARIES # above if necessary. #======================================================================== install-bin-binaries: binaries @mkdir -p $(DESTDIR)$(bindir) @list='$(bin_BINARIES)'; for p in $$list; do \ if test -f $$p; then \ echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p"; \ $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p; \ fi; \ done .SUFFIXES: .c .$(OBJEXT) Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status cd $(top_builddir) \ && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status uninstall-binaries: list='$(lib_BINARIES)'; for p in $$list; do \ rm -f $(DESTDIR)$(pkglibdir)/$$p; \ done list='$(PKG_TCL_SOURCES)'; for p in $$list; do \ p=`basename $$p`; \ rm -f $(DESTDIR)$(pkglibdir)/$$p; \ done list='$(bin_BINARIES)'; for p in $$list; do \ rm -f $(DESTDIR)$(bindir)/$$p; \ done .PHONY: all binaries clean depend distclean doc install libraries test # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: |
Changes to autoconf/tea/configure.ac.
1 2 3 4 | #!/bin/bash -norc dnl This file is an input file used by the GNU "autoconf" program to dnl generate the file "configure", which is run during Tcl installation dnl to configure the system for the local environment. | | > > | < < | | | 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 | #!/bin/bash -norc dnl This file is an input file used by the GNU "autoconf" program to dnl generate the file "configure", which is run during Tcl installation dnl to configure the system for the local environment. # # RCS: @(#) $Id: configure.in,v 1.43 2005/07/26 19:17:05 mdejong Exp $ #----------------------------------------------------------------------- # Sample configure.in for Tcl Extensions. The only places you should # need to modify this file are marked by the string __CHANGE__ #----------------------------------------------------------------------- #----------------------------------------------------------------------- # __CHANGE__ # 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.7.4]) #-------------------------------------------------------------------- # 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. #-------------------------------------------------------------------- TEA_INIT([3.9]) AC_CONFIG_AUX_DIR(tclconfig) #-------------------------------------------------------------------- # Load the tclConfig.sh file #-------------------------------------------------------------------- |
︙ | ︙ | |||
51 52 53 54 55 56 57 | #----------------------------------------------------------------------- TEA_PREFIX #----------------------------------------------------------------------- # Standard compiler checks. # This sets up CC by using the CC env var, or looks for gcc otherwise. | | | | < < < < < < < < | 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 | #----------------------------------------------------------------------- TEA_PREFIX #----------------------------------------------------------------------- # Standard compiler checks. # This sets up CC by using the CC env var, or looks for gcc otherwise. # This also calls AC_PROG_CC, AC_PROG_INSTALL and a few others to create # the basic setup necessary to compile executables. #----------------------------------------------------------------------- TEA_SETUP_COMPILER #----------------------------------------------------------------------- # __CHANGE__ # Specify the C source files to compile in TEA_ADD_SOURCES, # public headers that need to be installed in TEA_ADD_HEADERS, # stub library C source files to compile in TEA_ADD_STUB_SOURCES, # and runtime Tcl library files in TEA_ADD_TCL_SOURCES. # This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS # and PKG_TCL_SOURCES. #----------------------------------------------------------------------- TEA_ADD_SOURCES([tclsqlite3.c]) TEA_ADD_HEADERS([]) TEA_ADD_INCLUDES([-I\"`\${CYGPATH} \${srcdir}/generic`\"]) TEA_ADD_LIBS([]) TEA_ADD_CFLAGS([-DSQLITE_ENABLE_FTS3=1]) TEA_ADD_CFLAGS([-DSQLITE_3_SUFFIX_ONLY=1]) TEA_ADD_CFLAGS([-DSQLITE_ENABLE_RTREE=1]) TEA_ADD_STUB_SOURCES([]) TEA_ADD_TCL_SOURCES([]) #-------------------------------------------------------------------- # The --with-system-sqlite causes the TCL bindings to SQLite to use # the system shared library for SQLite rather than statically linking # against its own private copy. This is dangerous and leads to |
︙ | ︙ | |||
103 104 105 106 107 108 109 | if test x$with_system_sqlite != xno; then AC_CHECK_HEADER([sqlite3.h], [AC_CHECK_LIB([sqlite3],[sqlite3_initialize], [AC_DEFINE(USE_SYSTEM_SQLITE) LIBS="$LIBS -lsqlite3"])]) fi | < < < < < < < < < < < < < < < < < < < < < < < < < | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | if test x$with_system_sqlite != xno; then AC_CHECK_HEADER([sqlite3.h], [AC_CHECK_LIB([sqlite3],[sqlite3_initialize], [AC_DEFINE(USE_SYSTEM_SQLITE) LIBS="$LIBS -lsqlite3"])]) fi #-------------------------------------------------------------------- # __CHANGE__ # Choose which headers you need. Extension authors should try very # hard to only rely on the Tcl public header files. Internal headers # contain private data structures and are subject to change without # notice. # This MUST be called after TEA_LOAD_TCLCONFIG / TEA_LOAD_TKCONFIG |
︙ | ︙ | |||
179 180 181 182 183 184 185 186 187 188 189 190 191 192 | TEA_CONFIG_CFLAGS #-------------------------------------------------------------------- # Set the default compiler switches based on the --enable-symbols option. #-------------------------------------------------------------------- TEA_ENABLE_SYMBOLS #-------------------------------------------------------------------- # This macro generates a line to use when building a library. It # depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS, # and TEA_LOAD_TCLCONFIG macros above. #-------------------------------------------------------------------- | > > > > > > > > > > > > > > > > > > > > > > | 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 | TEA_CONFIG_CFLAGS #-------------------------------------------------------------------- # Set the default compiler switches based on the --enable-symbols option. #-------------------------------------------------------------------- TEA_ENABLE_SYMBOLS #-------------------------------------------------------------------- # Everyone should be linking against the Tcl stub library. If you # can't for some reason, remove this definition. If you aren't using # stubs, you also need to modify the SHLIB_LD_LIBS setting below to # link against the non-stubbed Tcl library. Add Tk too if necessary. #-------------------------------------------------------------------- AC_DEFINE(USE_TCL_STUBS, 1, [Use Tcl stubs]) #AC_DEFINE(USE_TK_STUBS, 1, [Use Tk stubs]) #-------------------------------------------------------------------- # Redefine fdatasync as fsync on systems that lack fdatasync #-------------------------------------------------------------------- # #AC_CHECK_FUNC(fdatasync, , AC_DEFINE(fdatasync, fsync)) # Check for library functions that SQLite can optionally use. AC_CHECK_FUNCS([fdatasync usleep fullfsync localtime_r gmtime_r]) AC_FUNC_STRERROR_R #-------------------------------------------------------------------- # This macro generates a line to use when building a library. It # depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS, # and TEA_LOAD_TCLCONFIG macros above. #-------------------------------------------------------------------- |
︙ | ︙ | |||
200 201 202 203 204 205 206 | # a pkgIndex.tcl file or anything else at extension build time. #-------------------------------------------------------------------- TEA_PROG_TCLSH #TEA_PROG_WISH #-------------------------------------------------------------------- | < < | < < < < < | | | < < < < < < < < | 189 190 191 192 193 194 195 196 197 198 199 200 201 | # a pkgIndex.tcl file or anything else at extension build time. #-------------------------------------------------------------------- TEA_PROG_TCLSH #TEA_PROG_WISH #-------------------------------------------------------------------- # Finally, substitute all of the various values into the Makefile. # You may alternatively have a special pkgIndex.tcl.in or other files # which require substituting th AC variables in. Include these here. #-------------------------------------------------------------------- AC_OUTPUT([Makefile pkgIndex.tcl]) |
Changes to autoconf/tea/pkgIndex.tcl.in.
|
| < > | < | < < > | | < | 1 2 3 4 5 6 7 | # # Tcl package index file # # Note sqlite*3* init specifically # package ifneeded sqlite3 @PACKAGE_VERSION@ \ [list load [file join $dir @PKG_LIB_FILE@] Sqlite3] |
Changes to autoconf/tea/tclconfig/tcl.m4.
1 2 3 4 5 6 7 8 9 10 11 | # tcl.m4 -- # # This file provides a set of autoconf macros to help TEA-enable # a Tcl extension. # # Copyright (c) 1999-2000 Ajuba Solutions. # Copyright (c) 2002-2005 ActiveState Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. | | > > > > < | 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 | # tcl.m4 -- # # This file provides a set of autoconf macros to help TEA-enable # a Tcl extension. # # Copyright (c) 1999-2000 Ajuba Solutions. # Copyright (c) 2002-2005 ActiveState Corporation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. AC_PREREQ(2.57) dnl TEA extensions pass us the version of TEA they think they dnl are compatible with (must be set in TEA_INIT below) dnl TEA_VERSION="3.9" # Possible values for key variables defined: # # TEA_WINDOWINGSYSTEM - win32 aqua x11 (mirrors 'tk windowingsystem') # TEA_PLATFORM - windows unix # #------------------------------------------------------------------------ # TEA_PATH_TCLCONFIG -- # # Locate the tclConfig.sh file and perform a sanity check on # the Tcl compile flags |
︙ | ︙ | |||
46 47 48 49 50 51 52 | # the alternative search directory is invoked by --with-tcl # if test x"${no_tcl}" = x ; then # we reset no_tcl in case something fails here no_tcl=true AC_ARG_WITH(tcl, | | | | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | # the alternative search directory is invoked by --with-tcl # if test x"${no_tcl}" = x ; then # we reset no_tcl in case something fails here no_tcl=true AC_ARG_WITH(tcl, AC_HELP_STRING([--with-tcl], [directory containing tcl configuration (tclConfig.sh)]), with_tclconfig="${withval}") AC_MSG_CHECKING([for Tcl configuration]) AC_CACHE_VAL(ac_cv_c_tclconfig,[ # First check to see if --with-tcl was specified. if test x"${with_tclconfig}" != x ; then case "${with_tclconfig}" in */tclConfig.sh ) |
︙ | ︙ | |||
100 101 102 103 104 105 106 | fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ | < < | | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tcl.framework/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i/Tcl.framework; pwd)`" break fi done fi |
︙ | ︙ | |||
131 132 133 134 135 136 137 | # check in a few common install locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ | < < < < < | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | # check in a few common install locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ `ls -d /usr/lib/tcl8.6 2>/dev/null` \ `ls -d /usr/lib/tcl8.5 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i; pwd)`" break fi done fi |
︙ | ︙ | |||
208 209 210 211 212 213 214 | # the alternative search directory is invoked by --with-tk # if test x"${no_tk}" = x ; then # we reset no_tk in case something fails here no_tk=true AC_ARG_WITH(tk, | | | | 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | # the alternative search directory is invoked by --with-tk # if test x"${no_tk}" = x ; then # we reset no_tk in case something fails here no_tk=true AC_ARG_WITH(tk, AC_HELP_STRING([--with-tk], [directory containing tk configuration (tkConfig.sh)]), with_tkconfig="${withval}") AC_MSG_CHECKING([for Tk configuration]) AC_CACHE_VAL(ac_cv_c_tkconfig,[ # First check to see if --with-tkconfig was specified. if test x"${with_tkconfig}" != x ; then case "${with_tkconfig}" in */tkConfig.sh ) |
︙ | ︙ | |||
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 | fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tk.framework/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/Tk.framework; pwd)`" break fi done fi # check in a few common install locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ | > < < < < < < < | 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 | fi # on Darwin, check in Framework installation locations if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ `ls -d /Library/Frameworks 2>/dev/null` \ `ls -d /Network/Library/Frameworks 2>/dev/null` \ `ls -d /System/Library/Frameworks 2>/dev/null` \ ; do if test -f "$i/Tk.framework/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i/Tk.framework; pwd)`" break fi done fi # check in a few common install locations if test x"${ac_cv_c_tkconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ ; do if test -f "$i/tkConfig.sh" ; then ac_cv_c_tkconfig="`(cd $i; pwd)`" break fi done fi |
︙ | ︙ | |||
354 355 356 357 358 359 360 | # # Results: # # Substitutes the following vars: # TCL_BIN_DIR # TCL_SRC_DIR # TCL_LIB_FILE | < < > > > > | 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 | # # Results: # # Substitutes the following vars: # TCL_BIN_DIR # TCL_SRC_DIR # TCL_LIB_FILE #------------------------------------------------------------------------ AC_DEFUN([TEA_LOAD_TCLCONFIG], [ AC_MSG_CHECKING([for existence of ${TCL_BIN_DIR}/tclConfig.sh]) if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then AC_MSG_RESULT([loading]) . "${TCL_BIN_DIR}/tclConfig.sh" else AC_MSG_RESULT([could not find ${TCL_BIN_DIR}/tclConfig.sh]) fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" # If the TCL_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TCL_LIB_SPEC will be set to the value # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC # instead of TCL_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. |
︙ | ︙ | |||
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 | TCL_STUB_LIB_SPEC="-L`echo "${TCL_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TCL_STUB_LIB_FLAG}" TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}" fi ;; esac fi AC_SUBST(TCL_VERSION) AC_SUBST(TCL_PATCH_LEVEL) AC_SUBST(TCL_BIN_DIR) AC_SUBST(TCL_SRC_DIR) AC_SUBST(TCL_LIB_FILE) AC_SUBST(TCL_LIB_FLAG) AC_SUBST(TCL_LIB_SPEC) AC_SUBST(TCL_STUB_LIB_FILE) AC_SUBST(TCL_STUB_LIB_FLAG) AC_SUBST(TCL_STUB_LIB_SPEC) AC_MSG_CHECKING([platform]) hold_cc=$CC; CC="$TCL_CC" | > > > > > > | < < | < < < < > | 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 | TCL_STUB_LIB_SPEC="-L`echo "${TCL_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TCL_STUB_LIB_FLAG}" TCL_STUB_LIB_PATH="${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TCL_DBGX substitution eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" AC_SUBST(TCL_VERSION) AC_SUBST(TCL_PATCH_LEVEL) AC_SUBST(TCL_BIN_DIR) AC_SUBST(TCL_SRC_DIR) AC_SUBST(TCL_LIB_FILE) AC_SUBST(TCL_LIB_FLAG) AC_SUBST(TCL_LIB_SPEC) AC_SUBST(TCL_STUB_LIB_FILE) AC_SUBST(TCL_STUB_LIB_FLAG) AC_SUBST(TCL_STUB_LIB_SPEC) AC_MSG_CHECKING([platform]) hold_cc=$CC; CC="$TCL_CC" AC_TRY_COMPILE(,[ #ifdef _WIN32 #error win32 #endif ], TEA_PLATFORM="unix", TEA_PLATFORM="windows" ) CC=$hold_cc AC_MSG_RESULT($TEA_PLATFORM) # The BUILD_$pkg is to define the correct extern storage class # handling when making this package AC_DEFINE_UNQUOTED(BUILD_${PACKAGE_NAME}, [], [Building extension source?]) |
︙ | ︙ | |||
475 476 477 478 479 480 481 482 483 484 485 486 487 488 | if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then AC_MSG_RESULT([loading]) . "${TK_BIN_DIR}/tkConfig.sh" else AC_MSG_RESULT([could not find ${TK_BIN_DIR}/tkConfig.sh]) fi # If the TK_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TK_LIB_SPEC will be set to the value # of TK_BUILD_LIB_SPEC. An extension should make use of TK_LIB_SPEC # instead of TK_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. | > > > > | 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 | if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then AC_MSG_RESULT([loading]) . "${TK_BIN_DIR}/tkConfig.sh" else AC_MSG_RESULT([could not find ${TK_BIN_DIR}/tkConfig.sh]) fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FILE=\"${TK_LIB_FILE}\"" eval "TK_STUB_LIB_FILE=\"${TK_STUB_LIB_FILE}\"" # If the TK_BIN_DIR is the build directory (not the install directory), # then set the common variable name to the value of the build variables. # For example, the variable TK_LIB_SPEC will be set to the value # of TK_BUILD_LIB_SPEC. An extension should make use of TK_LIB_SPEC # instead of TK_BUILD_LIB_SPEC since it will work with both an # installed and uninstalled version of Tcl. |
︙ | ︙ | |||
508 509 510 511 512 513 514 515 516 517 518 519 520 521 | if test -f "${TK_BIN_DIR}/${TK_STUB_LIB_FILE}"; then TK_STUB_LIB_SPEC="-L` echo "${TK_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TK_STUB_LIB_FLAG}" TK_STUB_LIB_PATH="${TK_BIN_DIR}/${TK_STUB_LIB_FILE}" fi ;; esac fi # TEA specific: Ensure windowingsystem is defined if test "${TEA_PLATFORM}" = "unix" ; then case ${TK_DEFS} in *MAC_OSX_TK*) AC_DEFINE(MAC_OSX_TK, 1, [Are we building against Mac OS X TkAqua?]) TEA_WINDOWINGSYSTEM="aqua" | > > > > > > | 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 | if test -f "${TK_BIN_DIR}/${TK_STUB_LIB_FILE}"; then TK_STUB_LIB_SPEC="-L` echo "${TK_BIN_DIR}" | sed -e 's/ /\\\\ /g'` ${TK_STUB_LIB_FLAG}" TK_STUB_LIB_PATH="${TK_BIN_DIR}/${TK_STUB_LIB_FILE}" fi ;; esac fi # eval is required to do the TK_DBGX substitution eval "TK_LIB_FLAG=\"${TK_LIB_FLAG}\"" eval "TK_LIB_SPEC=\"${TK_LIB_SPEC}\"" eval "TK_STUB_LIB_FLAG=\"${TK_STUB_LIB_FLAG}\"" eval "TK_STUB_LIB_SPEC=\"${TK_STUB_LIB_SPEC}\"" # TEA specific: Ensure windowingsystem is defined if test "${TEA_PLATFORM}" = "unix" ; then case ${TK_DEFS} in *MAC_OSX_TK*) AC_DEFINE(MAC_OSX_TK, 1, [Are we building against Mac OS X TkAqua?]) TEA_WINDOWINGSYSTEM="aqua" |
︙ | ︙ | |||
565 566 567 568 569 570 571 | #------------------------------------------------------------------------ AC_DEFUN([TEA_PROG_TCLSH], [ AC_MSG_CHECKING([for tclsh]) if test -f "${TCL_BIN_DIR}/Makefile" ; then # tclConfig.sh is in Tcl build directory if test "${TEA_PLATFORM}" = "windows"; then | < | < < < < < < < | | | 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 | #------------------------------------------------------------------------ AC_DEFUN([TEA_PROG_TCLSH], [ AC_MSG_CHECKING([for tclsh]) if test -f "${TCL_BIN_DIR}/Makefile" ; then # tclConfig.sh is in Tcl build directory if test "${TEA_PLATFORM}" = "windows"; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" else TCLSH_PROG="${TCL_BIN_DIR}/tclsh" fi else # tclConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" else TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}${TCL_DBGX}" fi list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TCL_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${TCLSH_PROG}" ; then REAL_TCL_BIN_DIR="`cd "$i"; pwd`/" |
︙ | ︙ | |||
623 624 625 626 627 628 629 | #------------------------------------------------------------------------ AC_DEFUN([TEA_PROG_WISH], [ AC_MSG_CHECKING([for wish]) if test -f "${TK_BIN_DIR}/Makefile" ; then # tkConfig.sh is in Tk build directory if test "${TEA_PLATFORM}" = "windows"; then | < | < < < < < < < | | | 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 | #------------------------------------------------------------------------ AC_DEFUN([TEA_PROG_WISH], [ AC_MSG_CHECKING([for wish]) if test -f "${TK_BIN_DIR}/Makefile" ; then # tkConfig.sh is in Tk build directory if test "${TEA_PLATFORM}" = "windows"; then WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" else WISH_PROG="${TK_BIN_DIR}/wish" fi else # tkConfig.sh is in install location if test "${TEA_PLATFORM}" = "windows"; then WISH_PROG="wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" else WISH_PROG="wish${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}${TK_DBGX}" fi list="`ls -d ${TK_BIN_DIR}/../bin 2>/dev/null` \ `ls -d ${TK_BIN_DIR}/.. 2>/dev/null` \ `ls -d ${TK_PREFIX}/bin 2>/dev/null`" for i in $list ; do if test -f "$i/${WISH_PROG}" ; then REAL_TK_BIN_DIR="`cd "$i"; pwd`/" |
︙ | ︙ | |||
669 670 671 672 673 674 675 | # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-shared=yes|no | < < < < < < > | | | | < < < < < < < < < < < < < | < | < < < < | < < < < < < < < < < | 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 | # Arguments: # none # # Results: # # Adds the following arguments to configure: # --enable-shared=yes|no # # Defines the following vars: # STATIC_BUILD Used for building import/export libraries # on Windows. # # Sets the following vars: # SHARED_BUILD Value of 1 or 0 #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_SHARED], [ AC_MSG_CHECKING([how to build libraries]) AC_ARG_ENABLE(shared, AC_HELP_STRING([--enable-shared], [build and link with shared libraries (default: on)]), [tcl_ok=$enableval], [tcl_ok=yes]) if test "${enable_shared+set}" = set; then enableval="$enable_shared" tcl_ok=$enableval else tcl_ok=yes fi if test "$tcl_ok" = "yes" ; then AC_MSG_RESULT([shared]) SHARED_BUILD=1 else AC_MSG_RESULT([static]) SHARED_BUILD=0 AC_DEFINE(STATIC_BUILD, 1, [Is this a static build?]) fi AC_SUBST(SHARED_BUILD) ]) #------------------------------------------------------------------------ # TEA_ENABLE_THREADS -- # # Specify if thread support should be enabled. If "yes" is specified # as an arg (optional), threads are enabled by default, "no" means |
︙ | ︙ | |||
770 771 772 773 774 775 776 | # TCL_THREADS # _REENTRANT # _THREAD_SAFE #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_THREADS], [ AC_ARG_ENABLE(threads, | | | | 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 | # TCL_THREADS # _REENTRANT # _THREAD_SAFE #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_THREADS], [ AC_ARG_ENABLE(threads, AC_HELP_STRING([--enable-threads], [build with threads]), [tcl_ok=$enableval], [tcl_ok=yes]) if test "${enable_threads+set}" = set; then enableval="$enable_threads" tcl_ok=$enableval else tcl_ok=yes |
︙ | ︙ | |||
855 856 857 858 859 860 861 862 863 864 865 866 867 868 | *THREADS=1*) if test "${TCL_THREADS}" = "0"; then AC_MSG_WARN([ Building ${PACKAGE_NAME} without threads enabled, but building against Tcl that IS thread-enabled. It is recommended to use --enable-threads.]) fi ;; esac AC_SUBST(TCL_THREADS) ]) #------------------------------------------------------------------------ # TEA_ENABLE_SYMBOLS -- # | > > > > > > > > | 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 | *THREADS=1*) if test "${TCL_THREADS}" = "0"; then AC_MSG_WARN([ Building ${PACKAGE_NAME} without threads enabled, but building against Tcl that IS thread-enabled. It is recommended to use --enable-threads.]) fi ;; *) if test "${TCL_THREADS}" = "1"; then AC_MSG_WARN([ --enable-threads requested, but building against a Tcl that is NOT thread-enabled. This is an OK configuration that will also run in a thread-enabled core.]) fi ;; esac AC_SUBST(TCL_THREADS) ]) #------------------------------------------------------------------------ # TEA_ENABLE_SYMBOLS -- # |
︙ | ︙ | |||
884 885 886 887 888 889 890 891 892 893 894 895 896 897 | # --enable-symbols # # Defines the following vars: # CFLAGS_DEFAULT Sets to $(CFLAGS_DEBUG) if true # Sets to "$(CFLAGS_OPTIMIZE) -DNDEBUG" if false # LDFLAGS_DEFAULT Sets to $(LDFLAGS_DEBUG) if true # Sets to $(LDFLAGS_OPTIMIZE) if false #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_SYMBOLS], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_CONFIG_CFLAGS]) AC_MSG_CHECKING([for build with symbols]) AC_ARG_ENABLE(symbols, | > > | > < > > > > > | 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 | # --enable-symbols # # Defines the following vars: # CFLAGS_DEFAULT Sets to $(CFLAGS_DEBUG) if true # Sets to "$(CFLAGS_OPTIMIZE) -DNDEBUG" if false # LDFLAGS_DEFAULT Sets to $(LDFLAGS_DEBUG) if true # Sets to $(LDFLAGS_OPTIMIZE) if false # DBGX Formerly used as debug library extension; # always blank now. #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_SYMBOLS], [ dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_CONFIG_CFLAGS]) AC_MSG_CHECKING([for build with symbols]) AC_ARG_ENABLE(symbols, AC_HELP_STRING([--enable-symbols], [build with debugging symbols (default: off)]), [tcl_ok=$enableval], [tcl_ok=no]) DBGX="" if test "$tcl_ok" = "no"; then CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE} -DNDEBUG" LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}" AC_MSG_RESULT([no]) else CFLAGS_DEFAULT="${CFLAGS_DEBUG}" LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}" if test "$tcl_ok" = "yes"; then AC_MSG_RESULT([yes (standard debugging)]) fi fi # TEA specific: if test "${TEA_PLATFORM}" != "windows" ; then LDFLAGS_DEFAULT="${LDFLAGS}" fi AC_SUBST(CFLAGS_DEFAULT) AC_SUBST(LDFLAGS_DEFAULT) AC_SUBST(TCL_DBGX) if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then AC_DEFINE(TCL_MEM_DEBUG, 1, [Is memory debugging enabled?]) fi if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then if test "$tcl_ok" = "all"; then |
︙ | ︙ | |||
942 943 944 945 946 947 948 | # # Defines the following vars: # HAVE_LANGINFO Triggers use of nl_langinfo if defined. #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_LANGINFO], [ AC_ARG_ENABLE(langinfo, | | | | 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 | # # Defines the following vars: # HAVE_LANGINFO Triggers use of nl_langinfo if defined. #------------------------------------------------------------------------ AC_DEFUN([TEA_ENABLE_LANGINFO], [ AC_ARG_ENABLE(langinfo, AC_HELP_STRING([--enable-langinfo], [use nl_langinfo if possible to determine encoding at startup, otherwise use old heuristic (default: on)]), [langinfo_ok=$enableval], [langinfo_ok=yes]) HAVE_LANGINFO=0 if test "$langinfo_ok" = "yes"; then AC_CHECK_HEADER(langinfo.h,[langinfo_ok=yes],[langinfo_ok=no]) fi AC_MSG_CHECKING([whether to use nl_langinfo]) if test "$langinfo_ok" = "yes"; then AC_CACHE_VAL(tcl_cv_langinfo_h, [ AC_TRY_COMPILE([#include <langinfo.h>], [nl_langinfo(CODESET);], [tcl_cv_langinfo_h=yes],[tcl_cv_langinfo_h=no])]) AC_MSG_RESULT([$tcl_cv_langinfo_h]) if test $tcl_cv_langinfo_h = yes; then AC_DEFINE(HAVE_LANGINFO, 1, [Do we have nl_langinfo()?]) fi else AC_MSG_RESULT([$langinfo_ok]) |
︙ | ︙ | |||
978 979 980 981 982 983 984 | # Arguments: # none # # Results: # Defines the following var: # # system - System/platform/version identification code. | < < < < | 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 | # Arguments: # none # # Results: # Defines the following var: # # system - System/platform/version identification code. #-------------------------------------------------------------------- AC_DEFUN([TEA_CONFIG_SYSTEM], [ AC_CACHE_CHECK([system version], tcl_cv_sys_version, [ # TEA specific: if test "${TEA_PLATFORM}" = "windows" ; then tcl_cv_sys_version=windows else tcl_cv_sys_version=`uname -s`-`uname -r` if test "$?" -ne 0 ; then AC_MSG_WARN([can't find uname command]) tcl_cv_sys_version=unknown else if test "`uname -s`" = "AIX" ; then tcl_cv_sys_version=AIX-`uname -v`.`uname -r` fi fi fi ]) system=$tcl_cv_sys_version ]) #-------------------------------------------------------------------- |
︙ | ︙ | |||
1074 1075 1076 1077 1078 1079 1080 | dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_INIT]) # Step 0.a: Enable 64 bit support? AC_MSG_CHECKING([if 64bit support is requested]) AC_ARG_ENABLE(64bit, | | | | | | | > > > > > > > > > > > | 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 | dnl TEA specific: Make sure we are initialized AC_REQUIRE([TEA_INIT]) # Step 0.a: Enable 64 bit support? AC_MSG_CHECKING([if 64bit support is requested]) AC_ARG_ENABLE(64bit, AC_HELP_STRING([--enable-64bit], [enable 64bit support (default: off)]), [do64bit=$enableval], [do64bit=no]) AC_MSG_RESULT([$do64bit]) # Step 0.b: Enable Solaris 64 bit VIS support? AC_MSG_CHECKING([if 64bit Sparc VIS support is requested]) AC_ARG_ENABLE(64bit-vis, AC_HELP_STRING([--enable-64bit-vis], [enable 64bit Sparc VIS support (default: off)]), [do64bitVIS=$enableval], [do64bitVIS=no]) AC_MSG_RESULT([$do64bitVIS]) # Force 64bit on with VIS AS_IF([test "$do64bitVIS" = "yes"], [do64bit=yes]) # Step 0.c: Check if visibility support is available. Do this here so # that platform specific alternatives can be used below if this fails. AC_CACHE_CHECK([if compiler supports visibility "hidden"], tcl_cv_cc_visibility_hidden, [ hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -Werror" AC_TRY_LINK([ extern __attribute__((__visibility__("hidden"))) void f(void); void f(void) {}], [f();], tcl_cv_cc_visibility_hidden=yes, tcl_cv_cc_visibility_hidden=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_visibility_hidden = yes], [ AC_DEFINE(MODULE_SCOPE, [extern __attribute__((__visibility__("hidden")))], [Compiler support for module scope symbols]) AC_DEFINE(HAVE_HIDDEN, [1], [Compiler support for module scope symbols]) ]) # Step 0.d: Disable -rpath support? AC_MSG_CHECKING([if rpath support is requested]) AC_ARG_ENABLE(rpath, AC_HELP_STRING([--disable-rpath], [disable rpath support (default: on)]), [doRpath=$enableval], [doRpath=yes]) AC_MSG_RESULT([$doRpath]) # TEA specific: Cross-compiling options for Windows/CE builds? AS_IF([test "${TEA_PLATFORM}" = windows], [ AC_MSG_CHECKING([if Windows/CE build is requested]) AC_ARG_ENABLE(wince, AC_HELP_STRING([--enable-wince], [enable Win/CE support (where applicable)]), [doWince=$enableval], [doWince=no]) AC_MSG_RESULT([$doWince]) ]) # Set the variable "system" to hold the name and version number # for the system. TEA_CONFIG_SYSTEM # Require ranlib early so we can override it in special cases below. |
︙ | ︙ | |||
1153 1154 1155 1156 1157 1158 1159 | ], [ CFLAGS_OPTIMIZE=-O CFLAGS_WARNING="" ]) AC_CHECK_TOOL(AR, ar) STLIB_LD='${AR} cr' LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" | | > > > > > > > > > > < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < < < < < < > | > | | | > > > > | > > > > > > > > > > > > > > > > > > > > > > | | | | | | < < < < < < < | | 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 | ], [ CFLAGS_OPTIMIZE=-O CFLAGS_WARNING="" ]) AC_CHECK_TOOL(AR, ar) STLIB_LD='${AR} cr' LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" AS_IF([test "x$SHLIB_VERSION" = x],[SHLIB_VERSION="1.0"]) case $system in # TEA specific: windows) # This is a 2-stage check to make sure we have the 64-bit SDK # We have to know where the SDK is installed. # This magic is based on MS Platform SDK for Win2003 SP1 - hobbs # MACHINE is IX86 for LINK, but this is used by the manifest, # which requires x86|amd64|ia64. MACHINE="X86" if test "$do64bit" != "no" ; then if test "x${MSSDK}x" = "xx" ; then MSSDK="C:/Progra~1/Microsoft Platform SDK" fi MSSDK=`echo "$MSSDK" | sed -e 's!\\\!/!g'` PATH64="" case "$do64bit" in amd64|x64|yes) MACHINE="AMD64" ; # default to AMD64 64-bit build PATH64="${MSSDK}/Bin/Win64/x86/AMD64" ;; ia64) MACHINE="IA64" PATH64="${MSSDK}/Bin/Win64" ;; esac if test "$GCC" != "yes" -a ! -d "${PATH64}" ; then AC_MSG_WARN([Could not find 64-bit $MACHINE SDK to enable 64bit mode]) AC_MSG_WARN([Ensure latest Platform SDK is installed]) do64bit="no" else AC_MSG_RESULT([ Using 64-bit $MACHINE mode]) do64bit_ok="yes" fi fi if test "$doWince" != "no" ; then if test "$do64bit" != "no" ; then AC_MSG_ERROR([Windows/CE and 64-bit builds incompatible]) fi if test "$GCC" = "yes" ; then AC_MSG_ERROR([Windows/CE and GCC builds incompatible]) fi TEA_PATH_CELIB # Set defaults for common evc4/PPC2003 setup # Currently Tcl requires 300+, possibly 420+ for sockets CEVERSION=420; # could be 211 300 301 400 420 ... TARGETCPU=ARMV4; # could be ARMV4 ARM MIPS SH3 X86 ... ARCH=ARM; # could be ARM MIPS X86EM ... PLATFORM="Pocket PC 2003"; # or "Pocket PC 2002" if test "$doWince" != "yes"; then # If !yes then the user specified something # Reset ARCH to allow user to skip specifying it ARCH= eval `echo $doWince | awk -F, '{ \ if (length([$]1)) { printf "CEVERSION=\"%s\"\n", [$]1; \ if ([$]1 < 400) { printf "PLATFORM=\"Pocket PC 2002\"\n" } }; \ if (length([$]2)) { printf "TARGETCPU=\"%s\"\n", toupper([$]2) }; \ if (length([$]3)) { printf "ARCH=\"%s\"\n", toupper([$]3) }; \ if (length([$]4)) { printf "PLATFORM=\"%s\"\n", [$]4 }; \ }'` if test "x${ARCH}" = "x" ; then ARCH=$TARGETCPU; fi fi OSVERSION=WCE$CEVERSION; if test "x${WCEROOT}" = "x" ; then WCEROOT="C:/Program Files/Microsoft eMbedded C++ 4.0" if test ! -d "${WCEROOT}" ; then WCEROOT="C:/Program Files/Microsoft eMbedded Tools" fi fi if test "x${SDKROOT}" = "x" ; then SDKROOT="C:/Program Files/Windows CE Tools" if test ! -d "${SDKROOT}" ; then SDKROOT="C:/Windows CE Tools" fi fi WCEROOT=`echo "$WCEROOT" | sed -e 's!\\\!/!g'` SDKROOT=`echo "$SDKROOT" | sed -e 's!\\\!/!g'` if test ! -d "${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" \ -o ! -d "${WCEROOT}/EVC/${OSVERSION}/bin"; then AC_MSG_ERROR([could not find PocketPC SDK or target compiler to enable WinCE mode [$CEVERSION,$TARGETCPU,$ARCH,$PLATFORM]]) doWince="no" else # We could PATH_NOSPACE these, but that's not important, # as long as we quote them when used. CEINCLUDE="${SDKROOT}/${OSVERSION}/${PLATFORM}/include" if test -d "${CEINCLUDE}/${TARGETCPU}" ; then CEINCLUDE="${CEINCLUDE}/${TARGETCPU}" fi CELIBPATH="${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" fi fi if test "$GCC" != "yes" ; then if test "${SHARED_BUILD}" = "0" ; then runtime=-MT else runtime=-MD fi if test "$do64bit" != "no" ; then # All this magic is necessary for the Win64 SDK RC1 - hobbs CC="\"${PATH64}/cl.exe\"" CFLAGS="${CFLAGS} -I\"${MSSDK}/Include\" -I\"${MSSDK}/Include/crt\" -I\"${MSSDK}/Include/crt/sys\"" RC="\"${MSSDK}/bin/rc.exe\"" lflags="-nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\"" LINKBIN="\"${PATH64}/link.exe\"" CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" # Avoid 'unresolved external symbol __security_cookie' # errors, c.f. http://support.microsoft.com/?id=894573 TEA_ADD_LIBS([bufferoverflowU.lib]) elif test "$doWince" != "no" ; then CEBINROOT="${WCEROOT}/EVC/${OSVERSION}/bin" if test "${TARGETCPU}" = "X86"; then CC="\"${CEBINROOT}/cl.exe\"" else CC="\"${CEBINROOT}/cl${ARCH}.exe\"" fi CFLAGS="$CFLAGS -I\"${CELIB_DIR}/inc\" -I\"${CEINCLUDE}\"" RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\"" arch=`echo ${ARCH} | awk '{print tolower([$]0)}'` defs="${ARCH} _${ARCH}_ ${arch} PALM_SIZE _MT _WINDOWS" if test "${SHARED_BUILD}" = "1" ; then # Static CE builds require static celib as well defs="${defs} _DLL" fi for i in $defs ; do AC_DEFINE_UNQUOTED($i, 1, [WinCE def ]$i) done AC_DEFINE_UNQUOTED(_WIN32_WCE, $CEVERSION, [_WIN32_WCE version]) AC_DEFINE_UNQUOTED(UNDER_CE, $CEVERSION, [UNDER_CE version]) CFLAGS_DEBUG="-nologo -Zi -Od" CFLAGS_OPTIMIZE="-nologo -Ox" lversion=`echo ${CEVERSION} | sed -e 's/\(.\)\(..\)/\1\.\2/'` lflags="-MACHINE:${ARCH} -LIBPATH:\"${CELIBPATH}\" -subsystem:windowsce,${lversion} -nologo" LINKBIN="\"${CEBINROOT}/link.exe\"" AC_SUBST(CELIB_DIR) else RC="rc" lflags="-nologo" LINKBIN="link" CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d" CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" fi fi if test "$GCC" = "yes"; then # mingw gcc mode AC_CHECK_TOOL(RC, windres) CFLAGS_DEBUG="-g" CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" SHLIB_LD='${CC} -shared' UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}" LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}" AC_CACHE_CHECK(for cross-compile version of gcc, ac_cv_cross, AC_TRY_COMPILE([ #ifdef _WIN32 #error cross-compiler #endif ], [], ac_cv_cross=yes, ac_cv_cross=no) ) if test "$ac_cv_cross" = "yes"; then case "$do64bit" in amd64|x64|yes) CC="x86_64-w64-mingw32-gcc" LD="x86_64-w64-mingw32-ld" AR="x86_64-w64-mingw32-ar" RANLIB="x86_64-w64-mingw32-ranlib" RC="x86_64-w64-mingw32-windres" ;; *) CC="i686-w64-mingw32-gcc" LD="i686-w64-mingw32-ld" AR="i686-w64-mingw32-ar" RANLIB="i686-w64-mingw32-ranlib" RC="i686-w64-mingw32-windres" ;; esac fi |
︙ | ︙ | |||
1265 1266 1267 1268 1269 1270 1271 | # For information on what debugtype is most useful, see: # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp # and also # http://msdn2.microsoft.com/en-us/library/y0zzbyt4%28VS.80%29.aspx # This essentially turns it all on. LDFLAGS_DEBUG="-debug -debugtype:cv" LDFLAGS_OPTIMIZE="-release" | > > > > | | > | | 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 | # For information on what debugtype is most useful, see: # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp # and also # http://msdn2.microsoft.com/en-us/library/y0zzbyt4%28VS.80%29.aspx # This essentially turns it all on. LDFLAGS_DEBUG="-debug -debugtype:cv" LDFLAGS_OPTIMIZE="-release" if test "$doWince" != "no" ; then LDFLAGS_CONSOLE="-link ${lflags}" LDFLAGS_WINDOW=${LDFLAGS_CONSOLE} else LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}" LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}" fi fi SHLIB_SUFFIX=".dll" SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.dll' TCL_LIB_VERSIONS_OK=nodots ;; AIX-*) AS_IF([test "${TCL_THREADS}" = "1" -a "$GCC" != "yes"], [ # AIX requires the _r compiler when gcc isn't being used case "${CC}" in *_r|*_r\ *) # ok ... ;; *) # Make sure only first arg gets _r |
︙ | ︙ | |||
1312 1313 1314 1315 1316 1317 1318 | ]) ]) AS_IF([test "`uname -m`" = ia64], [ # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC SHLIB_LD="/usr/ccs/bin/ld -G -z text" AS_IF([test "$GCC" = yes], [ | | | | | < < < < < < < < < < < < < < < < | > > > > < < | | > > > > | < < < < < < < < < < < < < < < < < < < < < | | | 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 | ]) ]) AS_IF([test "`uname -m`" = ia64], [ # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC SHLIB_LD="/usr/ccs/bin/ld -G -z text" AS_IF([test "$GCC" = yes], [ CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' ], [ CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}' ]) LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' ], [ AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared -Wl,-bexpall' ], [ SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bexpall -H512 -T512 -bnoentry" LDFLAGS="$LDFLAGS -brtl" ]) SHLIB_LD="${SHLIB_LD} ${SHLIB_LD_FLAGS}" CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ]) ;; BeOS*) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -nostart' SHLIB_SUFFIX=".so" #----------------------------------------------------------- # Check for inet_ntoa in -lbind, for BeOS (which also needs # -lsocket, even if the network functions are in -lnet which # is always linked to, for compatibility. #----------------------------------------------------------- AC_CHECK_LIB(bind, inet_ntoa, [LIBS="$LIBS -lbind -lsocket"]) ;; BSD/OS-4.*) SHLIB_CFLAGS="-export-dynamic -fPIC" SHLIB_LD='${CC} -shared' SHLIB_SUFFIX=".so" LDFLAGS="$LDFLAGS -export-dynamic" CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; CYGWIN_*) SHLIB_CFLAGS="" SHLIB_LD='${CC} -shared' SHLIB_SUFFIX=".dll" EXEEXT=".exe" do64bit_ok=yes CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; Haiku*) LDFLAGS="$LDFLAGS -Wl,--export-dynamic" SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS}' AC_CHECK_LIB(network, inet_ntoa, [LIBS="$LIBS -lnetwork"]) ;; HP-UX-*.11.*) # Use updated header definitions where possible AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, [Do we want to use the XOPEN network library?]) # TEA specific: Needed by Tcl, but not most extensions #AC_DEFINE(_XOPEN_SOURCE, 1, [Do we want to use the XOPEN network library?]) #LIBS="$LIBS -lxnet" # Use the XOPEN network library AS_IF([test "`uname -m`" = ia64], [ SHLIB_SUFFIX=".so" # Use newer C++ library for C++ extensions #if test "$GCC" != "yes" ; then # CPPFLAGS="-AA" #fi ], [ SHLIB_SUFFIX=".sl" ]) AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) AS_IF([test "$tcl_ok" = yes], [ LDFLAGS="$LDFLAGS -Wl,-E" CC_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' LD_LIBRARY_PATH_VAR="SHLIB_PATH" ]) AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ], [ CFLAGS="$CFLAGS -z" # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc #CFLAGS="$CFLAGS +DAportable" SHLIB_CFLAGS="+z" SHLIB_LD="ld -b" ]) # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = "yes"], [ AS_IF([test "$GCC" = yes], [ case `${CC} -dumpmachine` in hppa64*) # 64-bit gcc in use. Fix flags for GNU ld. do64bit_ok=yes SHLIB_LD='${CC} -shared' AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ;; *) AC_MSG_WARN([64bit mode not supported with GCC on $system]) ;; esac ], [ do64bit_ok=yes CFLAGS="$CFLAGS +DD64" LDFLAGS_ARCH="+DD64" ]) ]) ;; IRIX-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) AS_IF([test "$GCC" = yes], [ CFLAGS="$CFLAGS -mabi=n32" LDFLAGS="$LDFLAGS -mabi=n32" ], [ case $system in IRIX-6.3) # Use to build 6.2 compatible binaries on 6.3. |
︙ | ︙ | |||
1480 1481 1482 1483 1484 1485 1486 | ]) ;; IRIX64-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ | | | | | < < < < < < < < < < < | < | | 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 | ]) ;; IRIX64-6.*) SHLIB_CFLAGS="" SHLIB_LD="ld -n32 -shared -rdata_shared" SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) # Check to enable 64-bit flags for compiler/linker AS_IF([test "$do64bit" = yes], [ AS_IF([test "$GCC" = yes], [ AC_MSG_WARN([64bit mode not supported by gcc]) ], [ do64bit_ok=yes SHLIB_LD="ld -64 -shared -rdata_shared" CFLAGS="$CFLAGS -64" LDFLAGS_ARCH="-64" ]) ]) ;; Linux*|GNU*|NetBSD-Debian) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" # TEA specific: CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -shared ${CFLAGS} ${LDFLAGS_DEFAULT}' LDFLAGS="$LDFLAGS -Wl,--export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "`uname -m`" = "alpha"], [CFLAGS="$CFLAGS -mieee"]) AS_IF([test $do64bit = yes], [ AC_CACHE_CHECK([if compiler accepts -m64 flag], tcl_cv_cc_m64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -m64" AC_TRY_LINK(,, tcl_cv_cc_m64=yes, tcl_cv_cc_m64=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_m64 = yes], [ CFLAGS="$CFLAGS -m64" do64bit_ok=yes ]) ]) |
︙ | ︙ | |||
1549 1550 1551 1552 1553 1554 1555 | Lynx*) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE=-02 SHLIB_LD='${CC} -shared' LD_FLAGS="-Wl,--export-dynamic" AS_IF([test $doRpath = yes], [ | | | | > > | | < < | | | | | | | > > > > > > > | > > > | | | | > | | > | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | < | > > > > | | | 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 | Lynx*) SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" CFLAGS_OPTIMIZE=-02 SHLIB_LD='${CC} -shared' LD_FLAGS="-Wl,--export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) ;; OpenBSD-*) arch=`arch -s` case "$arch" in vax) SHLIB_SUFFIX="" SHARED_LIB_SUFFIX="" LDFLAGS="" ;; *) SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.${SHLIB_VERSION}' LDFLAGS="-Wl,-export-dynamic" ;; esac case "$arch" in vax) CFLAGS_OPTIMIZE="-O1" ;; *) CFLAGS_OPTIMIZE="-O2" ;; esac AS_IF([test "${TCL_THREADS}" = "1"], [ # On OpenBSD: Compile with -pthread # Don't link with -lpthread LIBS=`echo $LIBS | sed s/-lpthread//` CFLAGS="$CFLAGS -pthread" ]) # OpenBSD doesn't do version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; NetBSD-*) # NetBSD has ELF and can use 'cc -shared' to build shared libs SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} -shared ${SHLIB_CFLAGS}' SHLIB_SUFFIX=".so" LDFLAGS="$LDFLAGS -export-dynamic" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "${TCL_THREADS}" = "1"], [ # The -pthread needs to go in the CFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" ]) ;; FreeBSD-*) # This configuration from FreeBSD Ports. SHLIB_CFLAGS="-fPIC" SHLIB_LD="${CC} -shared" TCL_SHLIB_LD_EXTRAS="-Wl,-soname=\$[@]" TK_SHLIB_LD_EXTRAS="-Wl,-soname,\$[@]" SHLIB_SUFFIX=".so" LDFLAGS="" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}']) AS_IF([test "${TCL_THREADS}" = "1"], [ # The -pthread needs to go in the LDFLAGS, not LIBS LIBS=`echo $LIBS | sed s/-pthread//` CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LDFLAGS="$LDFLAGS $PTHREAD_LIBS"]) case $system in FreeBSD-3.*) # Version numbers are dot-stripped by system policy. TCL_TRIM_DOTS=`echo ${VERSION} | tr -d .` UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so' TCL_LIB_VERSIONS_OK=nodots ;; esac ;; Darwin-*) CFLAGS_OPTIMIZE="-Os" SHLIB_CFLAGS="-fno-common" # To avoid discrepancies between what headers configure sees during # preprocessing tests and compiling tests, move any -isysroot and # -mmacosx-version-min flags from CFLAGS to CPPFLAGS: CPPFLAGS="${CPPFLAGS} `echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if ([$]i~/^(isysroot|mmacosx-version-min)/) print "-"[$]i}'`" CFLAGS="`echo " ${CFLAGS}" | \ awk 'BEGIN {FS=" +-";ORS=" "}; {for (i=2;i<=NF;i++) \ if (!([$]i~/^(isysroot|mmacosx-version-min)/)) print "-"[$]i}'`" AS_IF([test $do64bit = yes], [ case `arch` in ppc) AC_CACHE_CHECK([if compiler accepts -arch ppc64 flag], tcl_cv_cc_arch_ppc64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" AC_TRY_LINK(,, tcl_cv_cc_arch_ppc64=yes, tcl_cv_cc_arch_ppc64=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_arch_ppc64 = yes], [ CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" do64bit_ok=yes ]);; i386) AC_CACHE_CHECK([if compiler accepts -arch x86_64 flag], tcl_cv_cc_arch_x86_64, [ hold_cflags=$CFLAGS CFLAGS="$CFLAGS -arch x86_64" AC_TRY_LINK(,, tcl_cv_cc_arch_x86_64=yes, tcl_cv_cc_arch_x86_64=no) CFLAGS=$hold_cflags]) AS_IF([test $tcl_cv_cc_arch_x86_64 = yes], [ CFLAGS="$CFLAGS -arch x86_64" do64bit_ok=yes ]);; *) AC_MSG_WARN([Don't know how enable 64-bit on architecture `arch`]);; esac ], [ # Check for combined 32-bit and 64-bit fat build AS_IF([echo "$CFLAGS " |grep -E -q -- '-arch (ppc64|x86_64) ' \ && echo "$CFLAGS " |grep -E -q -- '-arch (ppc|i386) '], [ fat_32_64=yes]) ]) # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS_DEFAULT}' AC_CACHE_CHECK([if ld accepts -single_module flag], tcl_cv_ld_single_module, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" AC_TRY_LINK(, [int i;], tcl_cv_ld_single_module=yes, tcl_cv_ld_single_module=no) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_single_module = yes], [ SHLIB_LD="${SHLIB_LD} -Wl,-single_module" ]) # TEA specific: link shlib with current and compatibility version flags vers=`echo ${PACKAGE_VERSION} | sed -e 's/^\([[0-9]]\{1,5\}\)\(\(\.[[0-9]]\{1,3\}\)\{0,2\}\).*$/\1\2/p' -e d` SHLIB_LD="${SHLIB_LD} -current_version ${vers:-0} -compatibility_version ${vers:-0}" SHLIB_SUFFIX=".dylib" # Don't use -prebind when building for Mac OS X 10.4 or later only: AS_IF([test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F '10\\.' '{print int([$]2)}'`" -lt 4 -a \ "`echo "${CPPFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int([$]2)}'`" -lt 4], [ LDFLAGS="$LDFLAGS -prebind"]) LDFLAGS="$LDFLAGS -headerpad_max_install_names" AC_CACHE_CHECK([if ld accepts -search_paths_first flag], tcl_cv_ld_search_paths_first, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-search_paths_first" AC_TRY_LINK(, [int i;], tcl_cv_ld_search_paths_first=yes, tcl_cv_ld_search_paths_first=no) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_search_paths_first = yes], [ LDFLAGS="$LDFLAGS -Wl,-search_paths_first" ]) AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ AC_DEFINE(MODULE_SCOPE, [__private_extern__], [Compiler support for module scope symbols]) |
︙ | ︙ | |||
1683 1684 1685 1686 1687 1688 1689 | AS_IF([test "${TEA_WINDOWINGSYSTEM}" = x11], [ AC_CACHE_CHECK([for 64-bit X11], tcl_cv_lib_x11_64, [ for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -I/usr/X11R6/include" LDFLAGS="$LDFLAGS -L/usr/X11R6/lib -lX11" | | | | | | 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 | AS_IF([test "${TEA_WINDOWINGSYSTEM}" = x11], [ AC_CACHE_CHECK([for 64-bit X11], tcl_cv_lib_x11_64, [ for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -I/usr/X11R6/include" LDFLAGS="$LDFLAGS -L/usr/X11R6/lib -lX11" AC_TRY_LINK([#include <X11/Xlib.h>], [XrmInitialize();], tcl_cv_lib_x11_64=yes, tcl_cv_lib_x11_64=no) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done]) ]) AS_IF([test "${TEA_WINDOWINGSYSTEM}" = aqua], [ AC_CACHE_CHECK([for 64-bit Tk], tcl_cv_lib_tk_64, [ for v in CFLAGS CPPFLAGS LDFLAGS; do eval 'hold_'$v'="$'$v'";'$v'="`echo "$'$v' "|sed -e "s/-arch ppc / /g" -e "s/-arch i386 / /g"`"' done CPPFLAGS="$CPPFLAGS -DUSE_TCL_STUBS=1 -DUSE_TK_STUBS=1 ${TCL_INCLUDES} ${TK_INCLUDES}" LDFLAGS="$LDFLAGS ${TCL_STUB_LIB_SPEC} ${TK_STUB_LIB_SPEC}" AC_TRY_LINK([#include <tk.h>], [Tk_InitStubs(NULL, "", 0);], tcl_cv_lib_tk_64=yes, tcl_cv_lib_tk_64=no) for v in CFLAGS CPPFLAGS LDFLAGS; do eval $v'="$hold_'$v'"' done]) ]) # remove 64-bit arch flags from CFLAGS et al. if configuration # does not support 64-bit. AS_IF([test "$tcl_cv_lib_tk_64" = no -o "$tcl_cv_lib_x11_64" = no], [ |
︙ | ︙ | |||
1726 1727 1728 1729 1730 1731 1732 | AS_IF([test "$SHARED_BUILD" = 1], [ SHLIB_LD='ld -shared -expect_unresolved "*"' ], [ SHLIB_LD='ld -non_shared -expect_unresolved "*"' ]) SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ | | > | | | | | | | | > | 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 | AS_IF([test "$SHARED_BUILD" = 1], [ SHLIB_LD='ld -shared -expect_unresolved "*"' ], [ SHLIB_LD='ld -non_shared -expect_unresolved "*"' ]) SHLIB_SUFFIX=".so" AS_IF([test $doRpath = yes], [ CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}']) AS_IF([test "$GCC" = yes], [CFLAGS="$CFLAGS -mieee"], [ CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee"]) # see pthread_intro(3) for pthread support on osf1, k.furukawa AS_IF([test "${TCL_THREADS}" = 1], [ CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" LIBS=`echo $LIBS | sed s/-lpthreads//` AS_IF([test "$GCC" = yes], [ LIBS="$LIBS -lpthread -lmach -lexc" ], [ CFLAGS="$CFLAGS -pthread" LDFLAGS="$LDFLAGS -pthread" ]) ]) ;; QNX-6*) # QNX RTP # This may work for all QNX, but it was only reported for v6. SHLIB_CFLAGS="-fPIC" SHLIB_LD="ld -Bshareable -x" |
︙ | ︙ | |||
1779 1780 1781 1782 1783 1784 1785 | AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) SHLIB_CFLAGS="-KPIC" SHLIB_SUFFIX=".so" AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' | | | | 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 | AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, [Do we really want to follow the standard? Yes we do!]) SHLIB_CFLAGS="-KPIC" SHLIB_SUFFIX=".so" AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ], [ SHLIB_LD="/usr/ccs/bin/ld -G -z text" CC_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} ]) ;; SunOS-5*) # Note: If _REENTRANT isn't defined, then Solaris # won't define thread-safe library routines. |
︙ | ︙ | |||
1849 1850 1851 1852 1853 1854 1855 | ]) ], [AC_MSG_WARN([64bit mode not supported for $arch])])]) ]) SHLIB_SUFFIX=".so" AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' | | | 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 | ]) ], [AC_MSG_WARN([64bit mode not supported for $arch])])]) ]) SHLIB_SUFFIX=".so" AS_IF([test "$GCC" = yes], [ SHLIB_LD='${CC} -shared' CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} AS_IF([test "$do64bit_ok" = yes], [ AS_IF([test "$arch" = "sparcv9 sparc"], [ # We need to specify -static-libgcc or we need to # add the path to the sparv9 libgcc. # JH: static-libgcc is necessary for core Tcl, but may # not be necessary for extensions. |
︙ | ︙ | |||
1876 1877 1878 1879 1880 1881 1882 | case $system in SunOS-5.[[1-9]][[0-9]]*) # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -G -z text ${LDFLAGS_DEFAULT}';; *) SHLIB_LD='/usr/ccs/bin/ld -G -z text';; esac | | | < | | 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 | case $system in SunOS-5.[[1-9]][[0-9]]*) # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} -G -z text ${LDFLAGS_DEFAULT}';; *) SHLIB_LD='/usr/ccs/bin/ld -G -z text';; esac CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' ]) ;; UNIX_SV* | UnixWare-5*) SHLIB_CFLAGS="-KPIC" SHLIB_LD='${CC} -G' SHLIB_LD_LIBS="" SHLIB_SUFFIX=".so" # Some UNIX_SV* systems (unixware 1.1.2 for example) have linkers # that don't grok the -Bexport option. Test that it does. AC_CACHE_CHECK([for ld accepts -Bexport flag], tcl_cv_ld_Bexport, [ hold_ldflags=$LDFLAGS LDFLAGS="$LDFLAGS -Wl,-Bexport" AC_TRY_LINK(, [int i;], tcl_cv_ld_Bexport=yes, tcl_cv_ld_Bexport=no) LDFLAGS=$hold_ldflags]) AS_IF([test $tcl_cv_ld_Bexport = yes], [ LDFLAGS="$LDFLAGS -Wl,-Bexport" ]) CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; |
︙ | ︙ | |||
1923 1924 1925 1926 1927 1928 1929 | # libraries to the right flags for gcc, instead of those for the # standard manufacturer compiler. AS_IF([test "$GCC" = yes], [ case $system in AIX-*) ;; BSD/OS*) ;; | | | | 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 | # libraries to the right flags for gcc, instead of those for the # standard manufacturer compiler. AS_IF([test "$GCC" = yes], [ case $system in AIX-*) ;; BSD/OS*) ;; CYGWIN_*|MINGW32_*) ;; IRIX*) ;; NetBSD-*|FreeBSD-*|OpenBSD-*) ;; Darwin-*) ;; SCO_SV-3.2*) ;; windows) ;; *) SHLIB_CFLAGS="-fPIC" ;; esac]) AS_IF([test "$tcl_cv_cc_visibility_hidden" != yes], [ |
︙ | ︙ | |||
1947 1948 1949 1950 1951 1952 1953 | AS_IF([test "$UNSHARED_LIB_SUFFIX" = ""], [ # TEA specific: use PACKAGE_VERSION instead of VERSION UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a']) if test "${GCC}" = "yes" -a ${SHLIB_SUFFIX} = ".dll"; then AC_CACHE_CHECK(for SEH support in compiler, tcl_cv_seh, | | | | | | | | | | | | | | | | | > | | | < < < < | 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 | AS_IF([test "$UNSHARED_LIB_SUFFIX" = ""], [ # TEA specific: use PACKAGE_VERSION instead of VERSION UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a']) if test "${GCC}" = "yes" -a ${SHLIB_SUFFIX} = ".dll"; then AC_CACHE_CHECK(for SEH support in compiler, tcl_cv_seh, AC_TRY_RUN([ #define WIN32_LEAN_AND_MEAN #include <windows.h> #undef WIN32_LEAN_AND_MEAN int main(int argc, char** argv) { int a, b = 0; __try { a = 666 / b; } __except (EXCEPTION_EXECUTE_HANDLER) { return 0; } return 1; } ], tcl_cv_seh=yes, tcl_cv_seh=no, tcl_cv_seh=no) ) if test "$tcl_cv_seh" = "no" ; then AC_DEFINE(HAVE_NO_SEH, 1, [Defined when mingw does not support SEH]) fi # # Check to see if the excpt.h include file provided contains the # definition for EXCEPTION_DISPOSITION; if not, which is the case # with Cygwin's version as of 2002-04-10, define it to be int, # sufficient for getting the current code to work. # AC_CACHE_CHECK(for EXCEPTION_DISPOSITION support in include files, tcl_cv_eh_disposition, AC_TRY_COMPILE([ # define WIN32_LEAN_AND_MEAN # include <windows.h> # undef WIN32_LEAN_AND_MEAN ],[ EXCEPTION_DISPOSITION x; ], tcl_cv_eh_disposition=yes, tcl_cv_eh_disposition=no) ) if test "$tcl_cv_eh_disposition" = "no" ; then AC_DEFINE(EXCEPTION_DISPOSITION, int, [Defined when cygwin/mingw does not support EXCEPTION DISPOSITION]) fi # Check to see if winnt.h defines CHAR, SHORT, and LONG # even if VOID has already been #defined. The win32api # used by mingw and cygwin is known to do this. AC_CACHE_CHECK(for winnt.h that ignores VOID define, tcl_cv_winnt_ignore_void, AC_TRY_COMPILE([ #define VOID void #define WIN32_LEAN_AND_MEAN #include <windows.h> #undef WIN32_LEAN_AND_MEAN ], [ CHAR c; SHORT s; LONG l; ], tcl_cv_winnt_ignore_void=yes, tcl_cv_winnt_ignore_void=no) ) if test "$tcl_cv_winnt_ignore_void" = "yes" ; then AC_DEFINE(HAVE_WINNT_IGNORE_VOID, 1, [Defined when cygwin/mingw ignores VOID define in winnt.h]) fi fi # See if the compiler supports casting to a union type. # This is used to stop gcc from printing a compiler # warning when initializing a union member. AC_CACHE_CHECK(for cast to union support, tcl_cv_cast_to_union, AC_TRY_COMPILE([], [ union foo { int i; double d; }; union foo f = (union foo) (int) 0; ], tcl_cv_cast_to_union=yes, tcl_cv_cast_to_union=no) ) if test "$tcl_cv_cast_to_union" = "yes"; then AC_DEFINE(HAVE_CAST_TO_UNION, 1, [Defined when compiler supports casting to union type.]) fi AC_SUBST(CFLAGS_DEBUG) AC_SUBST(CFLAGS_OPTIMIZE) AC_SUBST(CFLAGS_WARNING) AC_SUBST(STLIB_LD) AC_SUBST(SHLIB_LD) AC_SUBST(SHLIB_LD_LIBS) AC_SUBST(SHLIB_CFLAGS) |
︙ | ︙ | |||
2084 2085 2086 2087 2088 2089 2090 | # USE_TERMIO # USE_SGTTY #-------------------------------------------------------------------- AC_DEFUN([TEA_SERIAL_PORT], [ AC_CHECK_HEADERS(sys/modem.h) AC_CACHE_CHECK([termios vs. termio vs. sgtty], tcl_cv_api_serial, [ | | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # USE_TERMIO # USE_SGTTY #-------------------------------------------------------------------- AC_DEFUN([TEA_SERIAL_PORT], [ AC_CHECK_HEADERS(sys/modem.h) AC_CACHE_CHECK([termios vs. termio vs. sgtty], tcl_cv_api_serial, [ AC_TRY_RUN([ #include <termios.h> int main() { struct termios t; if (tcgetattr(0, &t) == 0) { cfsetospeed(&t, 0); t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include <termio.h> int main() { struct termio t; if (ioctl(0, TCGETA, &t) == 0) { t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include <sgtty.h> int main() { struct sgttyb t; if (ioctl(0, TIOCGETP, &t) == 0) { t.sg_ospeed = 0; t.sg_flags |= ODDP | EVENP | RAW; return 0; } return 1; }], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no ; then AC_TRY_RUN([ #include <termios.h> #include <errno.h> int main() { struct termios t; if (tcgetattr(0, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { cfsetospeed(&t, 0); t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no; then AC_TRY_RUN([ #include <termio.h> #include <errno.h> int main() { struct termio t; if (ioctl(0, TCGETA, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; return 0; } return 1; }], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) fi if test $tcl_cv_api_serial = no; then AC_TRY_RUN([ #include <sgtty.h> #include <errno.h> int main() { struct sgttyb t; if (ioctl(0, TIOCGETP, &t) == 0 || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { t.sg_ospeed = 0; t.sg_flags |= ODDP | EVENP | RAW; return 0; } return 1; }], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=none, tcl_cv_api_serial=none) fi]) case $tcl_cv_api_serial in termios) AC_DEFINE(USE_TERMIOS, 1, [Use the termios API for serial lines]);; termio) AC_DEFINE(USE_TERMIO, 1, [Use the termio API for serial lines]);; sgtty) AC_DEFINE(USE_SGTTY, 1, [Use the sgtty API for serial lines]);; esac ]) #-------------------------------------------------------------------- # TEA_MISSING_POSIX_HEADERS # # Supply substitutes for missing POSIX header files. Special # notes: # - stdlib.h doesn't define strtol, strtoul, or # strtod in some versions of SunOS # - some versions of string.h don't declare procedures such # as strstr # # Arguments: # none # # Results: # # Defines some of the following vars: # NO_DIRENT_H # NO_ERRNO_H # NO_VALUES_H # HAVE_LIMITS_H or NO_LIMITS_H # NO_STDLIB_H # NO_STRING_H # NO_SYS_WAIT_H # NO_DLFCN_H # HAVE_SYS_PARAM_H # # HAVE_STRING_H ? # # tkUnixPort.h checks for HAVE_LIMITS_H, so do both HAVE and # CHECK on limits.h #-------------------------------------------------------------------- AC_DEFUN([TEA_MISSING_POSIX_HEADERS], [ AC_CACHE_CHECK([dirent.h], tcl_cv_dirent_h, [ AC_TRY_LINK([#include <sys/types.h> #include <dirent.h>], [ #ifndef _POSIX_SOURCE # ifdef __Lynx__ /* * Generate compilation error to make the test fail: Lynx headers * are only valid if really in the POSIX environment. */ missing_procedure(); # endif #endif DIR *d; struct dirent *entryPtr; char *p; d = opendir("foobar"); entryPtr = readdir(d); p = entryPtr->d_name; closedir(d); ], tcl_cv_dirent_h=yes, tcl_cv_dirent_h=no)]) if test $tcl_cv_dirent_h = no; then AC_DEFINE(NO_DIRENT_H, 1, [Do we have <dirent.h>?]) fi # TEA specific: AC_CHECK_HEADER(errno.h, , [AC_DEFINE(NO_ERRNO_H, 1, [Do we have <errno.h>?])]) AC_CHECK_HEADER(float.h, , [AC_DEFINE(NO_FLOAT_H, 1, [Do we have <float.h>?])]) AC_CHECK_HEADER(values.h, , [AC_DEFINE(NO_VALUES_H, 1, [Do we have <values.h>?])]) AC_CHECK_HEADER(limits.h, [AC_DEFINE(HAVE_LIMITS_H, 1, [Do we have <limits.h>?])], [AC_DEFINE(NO_LIMITS_H, 1, [Do we have <limits.h>?])]) AC_CHECK_HEADER(stdlib.h, tcl_ok=1, tcl_ok=0) AC_EGREP_HEADER(strtol, stdlib.h, , tcl_ok=0) AC_EGREP_HEADER(strtoul, stdlib.h, , tcl_ok=0) AC_EGREP_HEADER(strtod, stdlib.h, , tcl_ok=0) if test $tcl_ok = 0; then AC_DEFINE(NO_STDLIB_H, 1, [Do we have <stdlib.h>?]) fi AC_CHECK_HEADER(string.h, tcl_ok=1, tcl_ok=0) AC_EGREP_HEADER(strstr, string.h, , tcl_ok=0) AC_EGREP_HEADER(strerror, string.h, , tcl_ok=0) # See also memmove check below for a place where NO_STRING_H can be # set and why. if test $tcl_ok = 0; then AC_DEFINE(NO_STRING_H, 1, [Do we have <string.h>?]) fi AC_CHECK_HEADER(sys/wait.h, , [AC_DEFINE(NO_SYS_WAIT_H, 1, [Do we have <sys/wait.h>?])]) AC_CHECK_HEADER(dlfcn.h, , [AC_DEFINE(NO_DLFCN_H, 1, [Do we have <dlfcn.h>?])]) # OS/390 lacks sys/param.h (and doesn't need it, by chance). AC_HAVE_HEADERS(sys/param.h) ]) #-------------------------------------------------------------------- # TEA_PATH_X # # Locate the X11 header files and the X11 library archive. Try # the ac_path_x macro first, but if it doesn't find the X stuff # (e.g. because there's no xmkmf program) then check through |
︙ | ︙ | |||
2212 2213 2214 2215 2216 2217 2218 | ]) AC_DEFUN([TEA_PATH_UNIX_X], [ AC_PATH_X not_really_there="" if test "$no_x" = ""; then if test "$x_includes" = ""; then | | | | 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 | ]) AC_DEFUN([TEA_PATH_UNIX_X], [ AC_PATH_X not_really_there="" if test "$no_x" = ""; then if test "$x_includes" = ""; then AC_TRY_CPP([#include <X11/Xlib.h>], , not_really_there="yes") else if test ! -r $x_includes/X11/Xlib.h; then not_really_there="yes" fi fi fi if test "$no_x" = "yes" -o "$not_really_there" = "yes"; then AC_MSG_CHECKING([for X11 header files]) found_xincludes="no" AC_TRY_CPP([#include <X11/Xlib.h>], found_xincludes="yes", found_xincludes="no") if test "$found_xincludes" = "no"; then dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include" for i in $dirs ; do if test -r $i/X11/Xlib.h; then AC_MSG_RESULT([$i]) XINCLUDES=" -I$i" found_xincludes="yes" |
︙ | ︙ | |||
2328 2329 2330 2331 2332 2333 2334 | # Results: # # Defines some of the following vars: # USE_DELTA_FOR_TZ # HAVE_TM_GMTOFF # HAVE_TM_TZADJ # HAVE_TIMEZONE_VAR | < | | | < | | < | < | | | | < | | | | 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 | # Results: # # Defines some of the following vars: # USE_DELTA_FOR_TZ # HAVE_TM_GMTOFF # HAVE_TM_TZADJ # HAVE_TIMEZONE_VAR #-------------------------------------------------------------------- AC_DEFUN([TEA_TIME_HANDLER], [ AC_CHECK_HEADERS(sys/time.h) AC_HEADER_TIME AC_STRUCT_TIMEZONE AC_CHECK_FUNCS(gmtime_r localtime_r) AC_CACHE_CHECK([tm_tzadj in struct tm], tcl_cv_member_tm_tzadj, [ AC_TRY_COMPILE([#include <time.h>], [struct tm tm; tm.tm_tzadj;], tcl_cv_member_tm_tzadj=yes, tcl_cv_member_tm_tzadj=no)]) if test $tcl_cv_member_tm_tzadj = yes ; then AC_DEFINE(HAVE_TM_TZADJ, 1, [Should we use the tm_tzadj field of struct tm?]) fi AC_CACHE_CHECK([tm_gmtoff in struct tm], tcl_cv_member_tm_gmtoff, [ AC_TRY_COMPILE([#include <time.h>], [struct tm tm; tm.tm_gmtoff;], tcl_cv_member_tm_gmtoff=yes, tcl_cv_member_tm_gmtoff=no)]) if test $tcl_cv_member_tm_gmtoff = yes ; then AC_DEFINE(HAVE_TM_GMTOFF, 1, [Should we use the tm_gmtoff field of struct tm?]) fi # # Its important to include time.h in this check, as some systems # (like convex) have timezone functions, etc. # AC_CACHE_CHECK([long timezone variable], tcl_cv_timezone_long, [ AC_TRY_COMPILE([#include <time.h>], [extern long timezone; timezone += 1; exit (0);], tcl_cv_timezone_long=yes, tcl_cv_timezone_long=no)]) if test $tcl_cv_timezone_long = yes ; then AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) else # # On some systems (eg IRIX 6.2), timezone is a time_t and not a long. # AC_CACHE_CHECK([time_t timezone variable], tcl_cv_timezone_time, [ AC_TRY_COMPILE([#include <time.h>], [extern time_t timezone; timezone += 1; exit (0);], tcl_cv_timezone_time=yes, tcl_cv_timezone_time=no)]) if test $tcl_cv_timezone_time = yes ; then AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) fi fi ]) #-------------------------------------------------------------------- |
︙ | ︙ | |||
2407 2408 2409 2410 2411 2412 2413 | # strtod (=fixstrtod) #-------------------------------------------------------------------- AC_DEFUN([TEA_BUGGY_STRTOD], [ AC_CHECK_FUNC(strtod, tcl_strtod=1, tcl_strtod=0) if test "$tcl_strtod" = 1; then AC_CACHE_CHECK([for Solaris2.4/Tru64 strtod bugs], tcl_cv_strtod_buggy,[ | | < | | | | > > | > > > > > < < > > > | 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 | # strtod (=fixstrtod) #-------------------------------------------------------------------- AC_DEFUN([TEA_BUGGY_STRTOD], [ AC_CHECK_FUNC(strtod, tcl_strtod=1, tcl_strtod=0) if test "$tcl_strtod" = 1; then AC_CACHE_CHECK([for Solaris2.4/Tru64 strtod bugs], tcl_cv_strtod_buggy,[ AC_TRY_RUN([ extern double strtod(); int main() { char *infString="Inf", *nanString="NaN", *spaceString=" "; char *term; double value; value = strtod(infString, &term); if ((term != infString) && (term[-1] == 0)) { exit(1); } value = strtod(nanString, &term); if ((term != nanString) && (term[-1] == 0)) { exit(1); } value = strtod(spaceString, &term); if (term == (spaceString+1)) { exit(1); } exit(0); }], tcl_cv_strtod_buggy=ok, tcl_cv_strtod_buggy=buggy, tcl_cv_strtod_buggy=buggy)]) if test "$tcl_cv_strtod_buggy" = buggy; then AC_LIBOBJ([fixstrtod]) USE_COMPAT=1 AC_DEFINE(strtod, fixstrtod, [Do we want to use the strtod() in compat?]) fi fi ]) #-------------------------------------------------------------------- # TEA_TCL_LINK_LIBS # # Search for the libraries needed to link the Tcl shell. # Things like the math library (-lm) and socket stuff (-lsocket vs. # -lnsl) are dealt with here. # # Arguments: # Requires the following vars to be set in the Makefile: # DL_LIBS (not in TEA, only needed in core) # LIBS # MATH_LIBS # # Results: # # Substitutes the following vars: # TCL_LIBS # MATH_LIBS # # Might append to the following vars: # LIBS # # Might define the following vars: # HAVE_NET_ERRNO_H #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_LINK_LIBS], [ #-------------------------------------------------------------------- # On a few very rare systems, all of the libm.a stuff is # already in libc.a. Set compiler flags accordingly. # Also, Linux requires the "ieee" library for math to work # right (and it must appear before "-lm"). #-------------------------------------------------------------------- AC_CHECK_FUNC(sin, MATH_LIBS="", MATH_LIBS="-lm") AC_CHECK_LIB(ieee, main, [MATH_LIBS="-lieee $MATH_LIBS"]) #-------------------------------------------------------------------- # Interactive UNIX requires -linet instead of -lsocket, plus it # needs net/errno.h to define the socket-related error codes. #-------------------------------------------------------------------- AC_CHECK_LIB(inet, main, [LIBS="$LIBS -linet"]) |
︙ | ︙ | |||
2506 2507 2508 2509 2510 2511 2512 | if test "$tcl_checkBoth" = 1; then tk_oldLibs=$LIBS LIBS="$LIBS -lsocket -lnsl" AC_CHECK_FUNC(accept, tcl_checkNsl=0, [LIBS=$tk_oldLibs]) fi AC_CHECK_FUNC(gethostbyname, , [AC_CHECK_LIB(nsl, gethostbyname, [LIBS="$LIBS -lnsl"])]) | | > | | > | > < < | > | | | | 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 | if test "$tcl_checkBoth" = 1; then tk_oldLibs=$LIBS LIBS="$LIBS -lsocket -lnsl" AC_CHECK_FUNC(accept, tcl_checkNsl=0, [LIBS=$tk_oldLibs]) fi AC_CHECK_FUNC(gethostbyname, , [AC_CHECK_LIB(nsl, gethostbyname, [LIBS="$LIBS -lnsl"])]) # TEA specific: Don't perform the eval of the libraries here because # DL_LIBS won't be set until we call TEA_CONFIG_CFLAGS TCL_LIBS='${DL_LIBS} ${LIBS} ${MATH_LIBS}' AC_SUBST(TCL_LIBS) AC_SUBST(MATH_LIBS) ]) #-------------------------------------------------------------------- # TEA_TCL_EARLY_FLAGS # # Check for what flags are needed to be passed so the correct OS # features are available. # # Arguments: # None # # Results: # # Might define the following vars: # _ISOC99_SOURCE # _LARGEFILE64_SOURCE # _LARGEFILE_SOURCE64 #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_EARLY_FLAG],[ AC_CACHE_VAL([tcl_cv_flag_]translit($1,[A-Z],[a-z]), AC_TRY_COMPILE([$2], $3, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no, AC_TRY_COMPILE([[#define ]$1[ 1 ]$2], $3, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=yes, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no))) if test ["x${tcl_cv_flag_]translit($1,[A-Z],[a-z])[}" = "xyes"] ; then AC_DEFINE($1, 1, [Add the ]$1[ flag when building]) tcl_flags="$tcl_flags $1" fi ]) AC_DEFUN([TEA_TCL_EARLY_FLAGS],[ |
︙ | ︙ | |||
2572 2573 2574 2575 2576 2577 2578 | # None # # Results: # # Might define the following vars: # TCL_WIDE_INT_IS_LONG # TCL_WIDE_INT_TYPE | | < | | | | | | | | | | | < < < < < < < < < | | | | | | | 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 | # None # # Results: # # Might define the following vars: # TCL_WIDE_INT_IS_LONG # TCL_WIDE_INT_TYPE # HAVE_STRUCT_DIRENT64 # HAVE_STRUCT_STAT64 # HAVE_TYPE_OFF64_T #-------------------------------------------------------------------- AC_DEFUN([TEA_TCL_64BIT_FLAGS], [ AC_MSG_CHECKING([for 64-bit integer type]) AC_CACHE_VAL(tcl_cv_type_64bit,[ tcl_cv_type_64bit=none # See if the compiler knows natively about __int64 AC_TRY_COMPILE(,[__int64 value = (__int64) 0;], tcl_type_64bit=__int64, tcl_type_64bit="long long") # See if we should use long anyway Note that we substitute in the # type that is our current guess for a 64-bit type inside this check # program, so it should be modified only carefully... AC_TRY_COMPILE(,[switch (0) { case 1: case (sizeof(]${tcl_type_64bit}[)==sizeof(long)): ; }],tcl_cv_type_64bit=${tcl_type_64bit})]) if test "${tcl_cv_type_64bit}" = none ; then AC_DEFINE(TCL_WIDE_INT_IS_LONG, 1, [Are wide integers to be implemented with C 'long's?]) AC_MSG_RESULT([using long]) elif test "${tcl_cv_type_64bit}" = "__int64" \ -a "${TEA_PLATFORM}" = "windows" ; then # TEA specific: We actually want to use the default tcl.h checks in # this case to handle both TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER* AC_MSG_RESULT([using Tcl header defaults]) else AC_DEFINE_UNQUOTED(TCL_WIDE_INT_TYPE,${tcl_cv_type_64bit}, [What type should be used to define wide integers?]) AC_MSG_RESULT([${tcl_cv_type_64bit}]) # Now check for auxiliary declarations AC_CACHE_CHECK([for struct dirent64], tcl_cv_struct_dirent64,[ AC_TRY_COMPILE([#include <sys/types.h> #include <dirent.h>],[struct dirent64 p;], tcl_cv_struct_dirent64=yes,tcl_cv_struct_dirent64=no)]) if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then AC_DEFINE(HAVE_STRUCT_DIRENT64, 1, [Is 'struct dirent64' in <sys/types.h>?]) fi AC_CACHE_CHECK([for struct stat64], tcl_cv_struct_stat64,[ AC_TRY_COMPILE([#include <sys/stat.h>],[struct stat64 p; ], tcl_cv_struct_stat64=yes,tcl_cv_struct_stat64=no)]) if test "x${tcl_cv_struct_stat64}" = "xyes" ; then AC_DEFINE(HAVE_STRUCT_STAT64, 1, [Is 'struct stat64' in <sys/stat.h>?]) fi AC_CHECK_FUNCS(open64 lseek64) AC_MSG_CHECKING([for off64_t]) AC_CACHE_VAL(tcl_cv_type_off64_t,[ AC_TRY_COMPILE([#include <sys/types.h>],[off64_t offset; ], tcl_cv_type_off64_t=yes,tcl_cv_type_off64_t=no)]) dnl Define HAVE_TYPE_OFF64_T only when the off64_t type and the dnl functions lseek64 and open64 are defined. if test "x${tcl_cv_type_off64_t}" = "xyes" && \ test "x${ac_cv_func_lseek64}" = "xyes" && \ test "x${ac_cv_func_open64}" = "xyes" ; then AC_DEFINE(HAVE_TYPE_OFF64_T, 1, [Is off64_t in <sys/types.h>?]) AC_MSG_RESULT([yes]) |
︙ | ︙ | |||
2684 2685 2686 2687 2688 2689 2690 | # EXEEXT # Select the executable extension based on the host type. This # is a lightweight replacement for AC_EXEEXT that doesn't require # a compiler. #------------------------------------------------------------------------ AC_DEFUN([TEA_INIT], [ | > > | | | > > > > > > | > | | > | | 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 | # EXEEXT # Select the executable extension based on the host type. This # is a lightweight replacement for AC_EXEEXT that doesn't require # a compiler. #------------------------------------------------------------------------ AC_DEFUN([TEA_INIT], [ # TEA extensions pass this us the version of TEA they think they # are compatible with. TEA_VERSION="3.9" AC_MSG_CHECKING([for correct TEA configuration]) if test x"${PACKAGE_NAME}" = x ; then AC_MSG_ERROR([ The PACKAGE_NAME variable must be defined by your TEA configure.in]) fi if test x"$1" = x ; then AC_MSG_ERROR([ TEA version not specified.]) elif test "$1" != "${TEA_VERSION}" ; then AC_MSG_RESULT([warning: requested TEA version "$1", have "${TEA_VERSION}"]) else AC_MSG_RESULT([ok (TEA ${TEA_VERSION})]) fi # If the user did not set CFLAGS, set it now to keep macros # like AC_PROG_CC and AC_TRY_COMPILE from adding "-g -O2". if test "${CFLAGS+set}" != "set" ; then CFLAGS="" fi case "`uname -s`" in *win32*|*WIN32*|*MINGW32_*) AC_CHECK_PROG(CYGPATH, cygpath, cygpath -w, echo) EXEEXT=".exe" TEA_PLATFORM="windows" ;; *CYGWIN_*) CYGPATH=echo EXEEXT=".exe" # TEA_PLATFORM is determined later in LOAD_TCLCONFIG ;; *) CYGPATH=echo # Maybe we are cross-compiling.... case ${host_alias} in *mingw32*) EXEEXT=".exe" |
︙ | ︙ | |||
2741 2742 2743 2744 2745 2746 2747 | AC_MSG_NOTICE([configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}]) AC_SUBST(EXEEXT) AC_SUBST(CYGPATH) # This package name must be replaced statically for AC_SUBST to work AC_SUBST(PKG_LIB_FILE) | < < < < < | 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 | AC_MSG_NOTICE([configuring ${PACKAGE_NAME} ${PACKAGE_VERSION}]) AC_SUBST(EXEEXT) AC_SUBST(CYGPATH) # This package name must be replaced statically for AC_SUBST to work AC_SUBST(PKG_LIB_FILE) # Substitute STUB_LIB_FILE in case package creates a stub library too. AC_SUBST(PKG_STUB_LIB_FILE) # We AC_SUBST these here to ensure they are subst'ed, # in case the user doesn't call TEA_ADD_... AC_SUBST(PKG_STUB_SOURCES) AC_SUBST(PKG_STUB_OBJECTS) AC_SUBST(PKG_TCL_SOURCES) AC_SUBST(PKG_HEADERS) AC_SUBST(PKG_INCLUDES) AC_SUBST(PKG_LIBS) AC_SUBST(PKG_CFLAGS) ]) #------------------------------------------------------------------------ # TEA_ADD_SOURCES -- # # Specify one or more source files. Users should check for # the right platform before adding to their list. |
︙ | ︙ | |||
2950 2951 2952 2953 2954 2955 2956 | # PKG_LIBS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_LIBS], [ vars="$@" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib | | | 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 | # PKG_LIBS #------------------------------------------------------------------------ AC_DEFUN([TEA_ADD_LIBS], [ vars="$@" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then # Convert foo.lib to -lfoo for GCC. No-op if not *.lib i=`echo "$i" | sed -e 's/^\([[^-]].*\)\.lib[$]/-l\1/i'` fi PKG_LIBS="$PKG_LIBS $i" done AC_SUBST(PKG_LIBS) ]) #------------------------------------------------------------------------ |
︙ | ︙ | |||
3033 3034 3035 3036 3037 3038 3039 | fi ]) #------------------------------------------------------------------------ # TEA_SETUP_COMPILER_CC -- # # Do compiler checks the way we want. This is just a replacement | | > > > > > > > > > | 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 | fi ]) #------------------------------------------------------------------------ # TEA_SETUP_COMPILER_CC -- # # Do compiler checks the way we want. This is just a replacement # for AC_PROG_CC in TEA configure.in files to make them cleaner. # # Arguments: # none # # Results: # # Sets up CC var and other standard bits we need to make executables. #------------------------------------------------------------------------ AC_DEFUN([TEA_SETUP_COMPILER_CC], [ # Don't put any macros that use the compiler (e.g. AC_TRY_COMPILE) # in this macro, they need to go into TEA_SETUP_COMPILER instead. AC_PROG_CC AC_PROG_CPP INSTALL="\$(SHELL) \$(srcdir)/tclconfig/install-sh -c" AC_SUBST(INSTALL) INSTALL_DATA="\${INSTALL} -m 644" AC_SUBST(INSTALL_DATA) INSTALL_PROGRAM="\${INSTALL}" AC_SUBST(INSTALL_PROGRAM) INSTALL_SCRIPT="\${INSTALL}" AC_SUBST(INSTALL_SCRIPT) #-------------------------------------------------------------------- # Checks to see if the make program sets the $MAKE variable. #-------------------------------------------------------------------- AC_PROG_MAKE_SET |
︙ | ︙ | |||
3095 3096 3097 3098 3099 3100 3101 | # It makes compiling go faster. (This is only a performance feature.) #------------------------------------------------------------------------ if test -z "$no_pipe" -a -n "$GCC"; then AC_CACHE_CHECK([if the compiler understands -pipe], tcl_cv_cc_pipe, [ hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe" | | > > > > > > > > | 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 | # It makes compiling go faster. (This is only a performance feature.) #------------------------------------------------------------------------ if test -z "$no_pipe" -a -n "$GCC"; then AC_CACHE_CHECK([if the compiler understands -pipe], tcl_cv_cc_pipe, [ hold_cflags=$CFLAGS; CFLAGS="$CFLAGS -pipe" AC_TRY_COMPILE(,, tcl_cv_cc_pipe=yes, tcl_cv_cc_pipe=no) CFLAGS=$hold_cflags]) if test $tcl_cv_cc_pipe = yes; then CFLAGS="$CFLAGS -pipe" fi fi #-------------------------------------------------------------------- # Common compiler flag setup #-------------------------------------------------------------------- AC_C_BIGENDIAN if test "${TEA_PLATFORM}" = "unix" ; then TEA_TCL_LINK_LIBS TEA_MISSING_POSIX_HEADERS # Let the user call this, because if it triggers, they will # need a compat/strtod.c that is correct. Users can also # use Tcl_GetDouble(FromObj) instead. #TEA_BUGGY_STRTOD fi ]) #------------------------------------------------------------------------ # TEA_MAKE_LIB -- # # Generate a line that can be used to build a shared/unshared library # in a platform independent manner. |
︙ | ︙ | |||
3137 3138 3139 3140 3141 3142 3143 | # VC_MANIFEST_EMBED_DLL Makefile rule for embedded VC manifest in DLL # VC_MANIFEST_EMBED_EXE Makefile rule for embedded VC manifest in EXE #------------------------------------------------------------------------ AC_DEFUN([TEA_MAKE_LIB], [ if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then MAKE_STATIC_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_OBJECTS)" | | | < < < < < < < < < | > | < < < | < < | < < | | | 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 | # VC_MANIFEST_EMBED_DLL Makefile rule for embedded VC manifest in DLL # VC_MANIFEST_EMBED_EXE Makefile rule for embedded VC manifest in EXE #------------------------------------------------------------------------ AC_DEFUN([TEA_MAKE_LIB], [ if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then MAKE_STATIC_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} \${SHLIB_LD_LIBS} \${LDFLAGS_DEFAULT} -out:\[$]@ \$(PKG_OBJECTS)" AC_EGREP_CPP([manifest needed], [ #if defined(_MSC_VER) && _MSC_VER >= 1400 print("manifest needed") #endif ], [ # Could do a CHECK_PROG for mt, but should always be with MSVC8+ VC_MANIFEST_EMBED_DLL="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest -outputresource:\[$]@\;2 ; fi" VC_MANIFEST_EMBED_EXE="if test -f \[$]@.manifest ; then mt.exe -nologo -manifest \[$]@.manifest -outputresource:\[$]@\;1 ; fi" MAKE_SHARED_LIB="${MAKE_SHARED_LIB} ; ${VC_MANIFEST_EMBED_DLL}" TEA_ADD_CLEANFILES([*.manifest]) ]) MAKE_STUB_LIB="\${STLIB_LD} -nodefaultlib -out:\[$]@ \$(PKG_STUB_OBJECTS)" else MAKE_STATIC_LIB="\${STLIB_LD} \[$]@ \$(PKG_OBJECTS)" MAKE_SHARED_LIB="\${SHLIB_LD} -o \[$]@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" MAKE_STUB_LIB="\${STLIB_LD} \[$]@ \$(PKG_STUB_OBJECTS)" fi if test "${SHARED_BUILD}" = "1" ; then MAKE_LIB="${MAKE_SHARED_LIB} " else MAKE_LIB="${MAKE_STATIC_LIB} " fi #-------------------------------------------------------------------- # Shared libraries and static libraries have different names. # Use the double eval to make sure any variables in the suffix is # substituted. (@@@ Might not be necessary anymore) #-------------------------------------------------------------------- if test "${TEA_PLATFORM}" = "windows" ; then if test "${SHARED_BUILD}" = "1" ; then # We force the unresolved linking of symbols that are really in # the private libraries of Tcl and Tk. if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}`\"" fi SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\"" if test "$GCC" = "yes"; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} -static-libgcc" fi eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" else eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" if test "$GCC" = "yes"; then PKG_LIB_FILE=lib${PKG_LIB_FILE} fi fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" if test "$GCC" = "yes"; then PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE} fi # These aren't needed on Windows (either MSVC or gcc) RANLIB=: RANLIB_STUB=: else RANLIB_STUB="${RANLIB}" if test "${SHARED_BUILD}" = "1" ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TCL_STUB_LIB_SPEC}" if test x"${TK_BIN_DIR}" != x ; then SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}" fi eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" RANLIB=: else eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" fi # Some packages build their own stubs libraries eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" fi # These are escaped so that only CFLAGS is picked up at configure time. # The other values will be substituted at make time. CFLAGS="${CFLAGS} \${CFLAGS_DEFAULT} \${CFLAGS_WARNING}" if test "${SHARED_BUILD}" = "1" ; then CFLAGS="${CFLAGS} \${SHLIB_CFLAGS}" |
︙ | ︙ | |||
3767 3768 3769 3770 3771 3772 3773 | # check in a few common install locations if test x"${ac_cv_c_$1config}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ | < | 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 | # check in a few common install locations if test x"${ac_cv_c_$1config}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ ; do if test -f "$i/$1Config.sh" ; then ac_cv_c_$1config=`(cd $i; pwd)` break fi |
︙ | ︙ | |||
3909 3910 3911 3912 3913 3914 3915 | #-------------------------------------------------------------------- # These are for $1Config.sh #-------------------------------------------------------------------- # pkglibdir must be a fully qualified path and (not ${exec_prefix}/lib) eval pkglibdir="[$]{libdir}/$1${PACKAGE_VERSION}" if test "${TCL_LIB_VERSIONS_OK}" = "ok"; then | | | | | | | | | | | | | < < < < < < < < | < | < < < < > | < < < < | | < < < < < < < | < < < < < | < > | > | | < < < < < < < | < < < < < < | > | | | < < < | | | | > | | | < < | | < | > | < < < > > > > | | | < | | | | < | < > | | < | < < < < | < < < < < < > > > | | < < < < < > < | 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 | #-------------------------------------------------------------------- # These are for $1Config.sh #-------------------------------------------------------------------- # pkglibdir must be a fully qualified path and (not ${exec_prefix}/lib) eval pkglibdir="[$]{libdir}/$1${PACKAGE_VERSION}" if test "${TCL_LIB_VERSIONS_OK}" = "ok"; then eval $1_LIB_FLAG="-l$1${PACKAGE_VERSION}${DBGX}" eval $1_STUB_LIB_FLAG="-l$1stub${PACKAGE_VERSION}${DBGX}" else eval $1_LIB_FLAG="-l$1`echo ${PACKAGE_VERSION} | tr -d .`${DBGX}" eval $1_STUB_LIB_FLAG="-l$1stub`echo ${PACKAGE_VERSION} | tr -d .`${DBGX}" fi $1_BUILD_LIB_SPEC="-L`pwd` ${$1_LIB_FLAG}" $1_LIB_SPEC="-L${pkglibdir} ${$1_LIB_FLAG}" $1_BUILD_STUB_LIB_SPEC="-L`pwd` [$]{$1_STUB_LIB_FLAG}" $1_STUB_LIB_SPEC="-L${pkglibdir} [$]{$1_STUB_LIB_FLAG}" $1_BUILD_STUB_LIB_PATH="`pwd`/[$]{PKG_STUB_LIB_FILE}" $1_STUB_LIB_PATH="${pkglibdir}/[$]{PKG_STUB_LIB_FILE}" AC_SUBST($1_BUILD_LIB_SPEC) AC_SUBST($1_LIB_SPEC) AC_SUBST($1_BUILD_STUB_LIB_SPEC) AC_SUBST($1_STUB_LIB_SPEC) AC_SUBST($1_BUILD_STUB_LIB_PATH) AC_SUBST($1_STUB_LIB_PATH) AC_SUBST(MAJOR_VERSION) AC_SUBST(MINOR_VERSION) AC_SUBST(PATCHLEVEL) ]) #------------------------------------------------------------------------ # TEA_PATH_CELIB -- # # Locate Keuchel's celib emulation layer for targeting Win/CE # # Arguments: # none # # Results: # # Adds the following arguments to configure: # --with-celib=... # # Defines the following vars: # CELIB_DIR Full path to the directory containing # the include and platform lib files #------------------------------------------------------------------------ AC_DEFUN([TEA_PATH_CELIB], [ # First, look for one uninstalled. # the alternative search directory is invoked by --with-celib if test x"${no_celib}" = x ; then # we reset no_celib in case something fails here no_celib=true AC_ARG_WITH(celib,[ --with-celib=DIR use Windows/CE support library from DIR], with_celibconfig=${withval}) AC_MSG_CHECKING([for Windows/CE celib directory]) AC_CACHE_VAL(ac_cv_c_celibconfig,[ # First check to see if --with-celibconfig was specified. if test x"${with_celibconfig}" != x ; then if test -d "${with_celibconfig}/inc" ; then ac_cv_c_celibconfig=`(cd ${with_celibconfig}; pwd)` else AC_MSG_ERROR([${with_celibconfig} directory doesn't contain inc directory]) fi fi # then check for a celib library if test x"${ac_cv_c_celibconfig}" = x ; then for i in \ ../celib-palm-3.0 \ ../celib \ ../../celib-palm-3.0 \ ../../celib \ `ls -dr ../celib-*3.[[0-9]]* 2>/dev/null` \ ${srcdir}/../celib-palm-3.0 \ ${srcdir}/../celib \ `ls -dr ${srcdir}/../celib-*3.[[0-9]]* 2>/dev/null` \ ; do if test -d "$i/inc" ; then ac_cv_c_celibconfig=`(cd $i; pwd)` break fi done fi ]) if test x"${ac_cv_c_celibconfig}" = x ; then AC_MSG_ERROR([Cannot find celib support library directory]) else no_celib= CELIB_DIR=${ac_cv_c_celibconfig} CELIB_DIR=`echo "$CELIB_DIR" | sed -e 's!\\\!/!g'` AC_MSG_RESULT([found $CELIB_DIR]) fi fi ]) # Local Variables: # mode: autoconf # End: |
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 | # 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.7.14])" !if [echo DOTVERSION = \>> versions.vc] \ && [nmakehlp -V ..\configure.in AC_INIT >> versions.vc] !endif !include "versions.vc" VERSION = $(DOTVERSION:.=) STUBPREFIX = $(PROJECT)stub DLLOBJS = \ $(TMP_DIR)\tclsqlite3.obj #------------------------------------------------------------------------- # Target names and paths ( shouldn't need changing ) #------------------------------------------------------------------------- BINROOT = . ROOT = .. PRJIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib PRJLIBNAME = $(PROJECT)$(VERSION)$(SUFX).$(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) |
︙ | ︙ | |||
197 198 199 200 201 202 203 | GENERICDIR = $(ROOT)\generic WINDIR = $(ROOT)\win LIBDIR = $(ROOT)\library DOCDIR = $(ROOT)\doc TOOLSDIR = $(ROOT)\tools COMPATDIR = $(ROOT)\compat | < < < < < < < < < < < | | | | < < < < < < < < < < < | 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 | GENERICDIR = $(ROOT)\generic WINDIR = $(ROOT)\win LIBDIR = $(ROOT)\library DOCDIR = $(ROOT)\doc TOOLSDIR = $(ROOT)\tools COMPATDIR = $(ROOT)\compat #--------------------------------------------------------------------- # 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 -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 = $(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) #--------------------------------------------------------------------- # Link flags |
︙ | ︙ | |||
356 357 358 359 360 361 362 | $(PRJSTUBLIB): $(PRJSTUBOBJS) $(lib32) -nologo -out:$@ $(PRJSTUBOBJS) #--------------------------------------------------------------------- # Implicit rules #--------------------------------------------------------------------- | | | | > | | < > > | | < > > | 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 | $(PRJSTUBLIB): $(PRJSTUBOBJS) $(lib32) -nologo -out:$@ $(PRJSTUBOBJS) #--------------------------------------------------------------------- # Implicit rules #--------------------------------------------------------------------- {$(WINDIR)}.c{$(TMP_DIR)}.obj:: $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<< $< << {$(GENERICDIR)}.c{$(TMP_DIR)}.obj:: $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<< $< << {$(COMPATDIR)}.c{$(TMP_DIR)}.obj:: $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ @<< $< << {$(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 82 83 | * 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> #define NO_SHLWAPI_GDI #define NO_SHLWAPI_STREAM #define NO_SHLWAPI_REG #include <shlwapi.h> #pragma comment (lib, "user32.lib") #pragma comment (lib, "kernel32.lib") #pragma comment (lib, "shlwapi.lib") #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(const char *option); 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 const char *GetVersionFromFile(const char *filename, const char *match); 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, '\0'}; pipeinfo Err = {INVALID_HANDLE_VALUE, '\0'}; /* * exitcodes: 0 == no, 1 == yes, 2 == error */ int main( int argc, char *argv[]) { char msg[300]; DWORD dwWritten; int chars; /* * Make sure children (cl.exe and link.exe) are kept quiet. */ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); |
︙ | ︙ | |||
96 97 98 99 100 101 102 | "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': | | | | | 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | "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>\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]); 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, |
︙ | ︙ | |||
147 148 149 150 151 152 153 | "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; } | | < < | < < < < < < < < < < < < < < < | 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 | "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; } printf("%s\n", GetVersionFromFile(argv[2], argv[3])); return 0; 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]); } } 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]); |
︙ | ︙ | |||
271 272 273 274 275 276 277 | 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| | | | 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | 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, (LPVOID)&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. |
︙ | ︙ | |||
324 325 326 327 328 329 330 | || strstr(Err.buffer, "D9002") != NULL || strstr(Out.buffer, "D2021") != NULL || strstr(Err.buffer, "D2021") != NULL); } static int CheckForLinkerFeature( | | < < | | 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 | || strstr(Err.buffer, "D9002") != NULL || strstr(Out.buffer, "D2021") != NULL || strstr(Err.buffer, "D2021") != NULL); } static int CheckForLinkerFeature( const char *option) { STARTUPINFO si; PROCESS_INFORMATION pi; SECURITY_ATTRIBUTES sa; DWORD threadID; char msg[300]; BOOL ok; HANDLE hProcess, h, pipeThreads[2]; char cmdline[100]; hProcess = GetCurrentProcess(); ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES; |
︙ | ︙ | |||
381 382 383 384 385 386 387 | lstrcpy(cmdline, "link.exe -nologo "); /* * Append our option for testing. */ | < | < < < | | 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 | lstrcpy(cmdline, "link.exe -nologo "); /* * Append our option for testing. */ lstrcat(cmdline, option); 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, (LPVOID)&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. |
︙ | ︙ | |||
450 451 452 453 454 455 456 | /* * 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 || | | < < | 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 | /* * 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); } static DWORD WINAPI ReadFromPipe( LPVOID args) { pipeinfo *pi = (pipeinfo *) args; |
︙ | ︙ | |||
498 499 500 501 502 503 504 | * following the match where a version is anything acceptable to * package provide or package ifneeded. */ static const char * GetVersionFromFile( const char *filename, | | < > | | < | | < > | | | 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 | * 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) { size_t cbBuffer = 100; 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, cbBuffer, fp) != NULL) { LPSTR p, q; p = strstr(szBuffer, match); if (p != NULL) { /* * Skip to first digit. */ while (*p && !isdigit(*p)) { ++p; } /* * Find ending whitespace. */ q = p; while (*q && (isalnum(*q) || *q == '.')) { ++q; } memcpy(szBuffer, p, q - p); szBuffer[q-p] = 0; szResult = szBuffer; break; } } fclose(fp); } return szResult; } |
︙ | ︙ | |||
558 559 560 561 562 563 564 | 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) { | | | 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 | 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 = malloc(sizeof(list_item_t)); if (itemPtr) { itemPtr->key = strdup(key); itemPtr->value = strdup(value); itemPtr->nextPtr = NULL; while(*listPtrPtr) { listPtrPtr = &(*listPtrPtr)->nextPtr; |
︙ | ︙ | |||
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 | */ 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) { | > > | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | < < < < < < < < | < < < < < < < < < < < < | < < < < < < < < < < < < < < | < < < < | < < < < < < < | < < < < < < < < < < < < < < < < < | < < < | | < < < | 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 | */ static int SubstituteFile( const char *substitutions, const char *filename) { size_t cbBuffer = 1024; static char szBuffer[1024], szCopy[1024]; char *szResult = NULL; 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, cbBuffer, 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 */ #ifdef _DEBUG { 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, cbBuffer, 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(szBuffer); } list_free(&substPtr); } fclose(fp); return 0; } /* * 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]; char szTmp[MAX_PATH + 1]; char *p; GetCurrentDirectory(MAX_PATH, szCwd); while ((p = strchr(szPath, '/')) && *p) *p = '\\'; PathCombine(szTmp, szCwd, szPath); PathCanonicalize(szCwd, szTmp); printf("%s\n", szCwd); return 0; } /* * 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 61 62 63 64 65 66 67 | #! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, # Inc. timestamp='2007-07-22' # 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 2 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, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # 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. # Originally written by Per Bothner <per@bothner.com>. # Please send patches to <config-patches@gnu.org>. Submit a context # diff and a properly formatted ChangeLog entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit build system type. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -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 (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 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." |
︙ | ︙ | |||
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | esac 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. | > > < < < < | > > | < | | | | | > | | | | | < | | | | | | | | | | < | | < < < < < | | | > > > < | | < | < < < < < | < < | | | < < | | < < < < < | | | < < < | | | < < < < < < < | | | < < < < < < < | < < < < | | | < < < | < < < < < < | | | | | | | | | | | | | | | | | | > > > > > | < > > | | | | | | | 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 | esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # 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. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { 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) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; 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 ; set_cc_for_build= ;' # 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) >/dev/null 2>&1 ; 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 if [ "${UNAME_SYSTEM}" = "Linux" ] ; then eval $set_cc_for_build cat << EOF > $dummy.c #include <features.h> #ifdef __UCLIBC__ # ifdef __UCLIBC_CONFIG_VERSION__ LIBC=uclibc __UCLIBC_CONFIG_VERSION__ # else LIBC=uclibc # endif #else LIBC=gnu #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep LIBC= | sed -e 's: ::g'` fi # 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 tupples: *-*-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=`(/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 ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null 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 # 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/[-_].*/\./'` ;; 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}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${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 ;; 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'` exit ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; 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. |
︙ | ︙ | |||
374 375 376 377 378 379 380 | 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 ;; | < < < | | < < < < < < < < < < < < < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 | 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.*:*) 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:SunOS:5.*:* | i86xen:SunOS:5.*:*) echo i386-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) eval $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 ;; |
︙ | ︙ | |||
530 531 532 533 534 535 536 | m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 | 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 eval $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:*:[45]) 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/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` 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:BSD:*) 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 eval $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 eval $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 __LP64__ >/dev/null 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:*:*) eval $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 |
︙ | ︙ | |||
750 751 752 753 754 755 756 | } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < | < < < < < < < | < > | < | < < < | | > | | | | | | | < > > | | > > > > > | | | > > > | | | | | > > > > > > > > > > > > > > > | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < | | | | | < < < < < < < < < < < < | | | | < < < | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | | | | | | | | | | | | < < < | | | | | | | | < < < < < < < < < < | | | | | | | | | | | | | | | | < < < < < < | | | | | | < < < | | | < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < | | | < < < | | | < < < < < < | < | | | | | | | | < < < < < < < < < < < < | > > | | | | < < < < < < < < | | | > > > > > > > > | 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 | } 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 ;; *:FreeBSD:*:*) case ${UNAME_MACHINE} in pc98) echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:[3456]*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; EM64T | authenticamd) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-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-gnu`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 '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; arm*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; cris:Linux:*:*) echo cris-axis-linux-${LIBC} exit ;; crisv32:Linux:*:*) echo crisv32-axis-linux-${LIBC} exit ;; frv:Linux:*:*) echo frv-unknown-linux-${LIBC} exit ;; ia64: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:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips #undef mipsel #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mipsel #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips #else CPU= #endif #endif EOF eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' /^CPU/{ s: ::g p }'`" test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips64 #undef mips64el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mips64el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips64 #else CPU= #endif #endif EOF eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' /^CPU/{ s: ::g p }'`" test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; or32:Linux:*:*) echo or32-unknown-linux-${LIBC} exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-${LIBC} exit ;; ppc64:Linux:*:*) echo powerpc64-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 ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="gnulibc1" ; fi echo ${UNAME_MACHINE}-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 ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-${LIBC} exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux 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 ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-${LIBC} exit ;; xtensa:Linux:*:*) echo xtensa-unknown-linux-${LIBC} exit ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. # Set LC_ALL=C to ensure ld outputs messages in English. ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ | sed -ne '/supported targets:/!d s/[ ][ ]*/ /g s/.*supported targets: *// s/ .*// p'` case "$ld_supported_targets" in elf32-i386) TENTATIVE="${UNAME_MACHINE}-pc-linux-${LIBC}" ;; a.out-i386-linux) echo "${UNAME_MACHINE}-pc-linux-${LIBC}aout" exit ;; coff-i386) echo "${UNAME_MACHINE}-pc-linux-${LIBC}coff" exit ;; "") # Either a pre-BFD a.out linker (linux-gnuoldld) or # one that does not give us useful --help. echo "${UNAME_MACHINE}-pc-linux-${LIBC}oldld" exit ;; esac # This should get integrated into the C code below, but now we hack if [ "$LIBC" != "gnu" ] ; then echo "$TENTATIVE" && exit 0 ; fi # Determine whether the default compiler is a.out or elf eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include <features.h> #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 LIBC=gnu # else LIBC=gnulibc1 # endif # else LIBC=gnulibc1 # endif #else #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) LIBC=gnu #else LIBC=gnuaout #endif #endif #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' /^LIBC/{ s: ::g p }'`" test x"${LIBC}" != x && { echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit } test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; 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.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V: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 i386. echo i386-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; } ;; 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.0*:*) 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 ;; 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 ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac 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 ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-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. 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 ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c <<EOF #ifdef _SEQUENT_ # include <sys/types.h> # include <sys/utsname.h> #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 (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; |
︙ | ︙ | |||
1531 1532 1533 1534 1535 1536 1537 | #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) | | | > | | | | | | | > | | | | | | | | | | | | | | | | < < < < < | | < < < < < < < < < < < < | < | < < < < > < > | < > > > > > > > > > > > > > > > | > > > | > > | | | | | > | | | | | | | | | 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 | #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 printf ("vax-dec-ultrix\n"); exit (0); # 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; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 <<EOF $0: unable to guess system type This script, last modified $timestamp, has failed to recognize the operating system you are using. It is advised that you download the most up to date version of the config scripts from http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess and http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub If the version you run ($0) is already up to date, please send the following data and any information you think might be pertinent to <config-patches@gnu.org> in order to provide the needed 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 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: |
Added config.h.in.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 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 | /* config.h.in. Generated from configure.ac by autoheader. */ /* Define to 1 if you have the <dlfcn.h> header file. */ #undef HAVE_DLFCN_H /* Define to 1 if you have the `fdatasync' function. */ #undef HAVE_FDATASYNC /* Define to 1 if you have the `gmtime_r' function. */ #undef HAVE_GMTIME_R /* Define to 1 if the system has the type `int16_t'. */ #undef HAVE_INT16_T /* Define to 1 if the system has the type `int32_t'. */ #undef HAVE_INT32_T /* Define to 1 if the system has the type `int64_t'. */ #undef HAVE_INT64_T /* Define to 1 if the system has the type `int8_t'. */ #undef HAVE_INT8_T /* Define to 1 if the system has the type `intptr_t'. */ #undef HAVE_INTPTR_T /* Define to 1 if you have the <inttypes.h> header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the `isnan' function. */ #undef HAVE_ISNAN /* Define to 1 if you have the `localtime_r' function. */ #undef HAVE_LOCALTIME_R /* Define to 1 if you have the `localtime_s' function. */ #undef HAVE_LOCALTIME_S /* Define to 1 if you have the <malloc.h> header file. */ #undef HAVE_MALLOC_H /* Define to 1 if you have the `malloc_usable_size' function. */ #undef HAVE_MALLOC_USABLE_SIZE /* Define to 1 if you have the <memory.h> header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the pread() function. */ #undef HAVE_PREAD /* Define to 1 if you have the pread64() function. */ #undef HAVE_PREAD64 /* Define to 1 if you have the pwrite() function. */ #undef HAVE_PWRITE /* Define to 1 if you have the pwrite64() function. */ #undef HAVE_PWRITE64 /* Define to 1 if you have the <stdint.h> header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the <stdlib.h> header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the strchrnul() function */ #undef HAVE_STRCHRNUL /* Define to 1 if you have the <strings.h> header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the <string.h> header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the <sys/stat.h> header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the <sys/types.h> header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if the system has the type `uint16_t'. */ #undef HAVE_UINT16_T /* Define to 1 if the system has the type `uint32_t'. */ #undef HAVE_UINT32_T /* Define to 1 if the system has the type `uint64_t'. */ #undef HAVE_UINT64_T /* Define to 1 if the system has the type `uint8_t'. */ #undef HAVE_UINT8_T /* Define to 1 if the system has the type `uintptr_t'. */ #undef HAVE_UINTPTR_T /* Define to 1 if you have the <unistd.h> header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the `usleep' function. */ #undef HAVE_USLEEP /* Define to 1 if you have the utime() library function. */ #undef HAVE_UTIME /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS /* Define for large files, on AIX-style hosts. */ #undef _LARGE_FILES |
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 78 79 80 81 82 83 | #! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, # Inc. timestamp='2007-06-28' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # 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 2 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, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # 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. # Please send patches to <config-patches@gnu.org>. Submit a context # diff and a properly formatted ChangeLog entry. # # 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. # 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 $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -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 (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 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." |
︙ | ︙ | |||
85 86 87 88 89 90 91 | --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) | | | < < < < < | < < < < < < < < < < < | < | | | < | < | < | < < | < | | < < < < < < < < < | < < < < < < < | | < < < < < < < < < < < < | | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | < < < > | < < < | < < < < < < < | < | < < | > > | > > > | | < < < < < < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < < | < | < < | | < < < < | < | < < | < < < < < | < < | < < < | < < < < < < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | < < | < | < < | < < < | | < < < < < < < < < < < < < < < < < < | < < < | < < < < < < | < | | < | < < | < | | < | < < | < | < < < < < < < < < | | < < < < < < | < | < < < < | < < < < > | < | < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < > | < | < < | < < < | < < | < | < < < < < < < < < < < < < < < < | | < | < < < < < < < < < < | < < < < < < < < < < < | < < | < | < < < < | | < | < < | < < | < | | < | | | < < < < | < | < | < < < < | | < < | < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | < < < < | | | < < | | | < < < < | < < < < < < < < < < < < < < < | < < < > > | < < < | < < < < < < | < < < < | < < < | < | < < > | < < | < < < | < < < < < < < | < < < < > | | | < < < < < < < | < | < < < < < < < < | | < < < < < < > | < < < < < < < | < < < < < < < < < | < < < | < < < < > > | < < < < < < < < < < < < < < < < < < | < < < < | | < | < < < < < | < < < < < < < | < < | > | < < < < < | > | | < < < < < < < < < < < < > | < < > | < < < < < < < | < < < < < < > | < > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < < < < < < < < < < > | < < < < < > < | | < < < < < < | < | < > > | < | < < < < < | | > > > > > > | < < > > > | > > > > > > | | | | | | | | | | < > | | | < > | | < > > | > > > | < > > | < < < < < | > > > > > > > | < | > > | > > > > > | | < > | < < < | | | | > > | < < | | < | > | > > > > > > > | | < > > | > > > > | > > > > > > > > > > > > > > > > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > | > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > | | | | < < < < | < < < > | < < < < < < < | < < < < < | > < | < > | < > > | < < < < | | > < > | > | < < > | < | > | < < | | | | | | < > | < < > > | < < < | < > | | < | > | < > > | > | | < | | < | > > > > > | > | > > > > > | > | > > | > > > | > > > | > > > > > > > > > > > > > > > > | | > > > > | > > > > > > > > > > | > > | > > | > > > > > > > | < > > > > > > > > > > > > | > > > > > > > > > > > > > > > > | < | > > | > | > > | < | < < < < | > | < > > > > > > | > > > > > > > > > | | > > > > > | > > | < < > > > | < < < < > | < > > > > | > > > > | > | > > | < | < < < < > > | < < > > > > > > > > > > > | | | < > | | | < > | | | > | > > > > > | > > > > > > > > > > > > > > > > > > | > > > | > > > | > > > > > > | | > > > | > | > > | > | < > > > > > > > > > | < > | > > > | > > > > > > > > | > | > | < < < > > > > > > > > > > > > > | > > > | > | > > | > | > > > | < < < > | > > > | > > > > > | > > | < > > | | < > > > > > > > | | < > > > > > > | > | < > > > > > > > > > > > | > > > > > | > > | > | | > > | | | < < | | | | | | | | | < < < < < < | | | < | < < < < < < < < < < | | | < < < < < < < < < < > | < < < < < < < < < < < < | | | | | < | | | | | | | | | | | | | < | | | | | | | | | < < | | | | < < < | | | | | > > > | | | > > > > > > > > > > > > > < < < < | < < < | < < < < < < | < < < < < < | | | | | | | | | | | | | | | | | | | | | | | > > > > > > < < < < < < | | | | | | | | | | | | | | < > | | | | | | < < < < < | | | | | | < < < | | < < > > | | | | | | | | | | | < < < < < < < < < < < < < < < < < < | | | | | | > > > | | | | | | | | < < < | > > > | | | | | | | | | | | | | | | | | | | | > > > | | | | | | | | | | | < < < | | > | | | | | | | | | | | | < < < | | | | | | | | | | > | | | 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 | --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" 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 # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -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) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx | dvp \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | mcore | mep \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64vr | mips64vrel \ | mips64orion | mips64orionel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | mt \ | msp430 \ | nios | nios2 \ | ns16k | ns32k \ | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | score \ | sh | sh[1234] | sh[24]a | sh[24]a*eb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu | strongarm \ | tahoe | thumb | tic4x | tic80 | tron \ | v850 | v850e \ | we32k \ | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ | z8k) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; # 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) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64vr-* | mips64vrel-* \ | mips64orion-* | mips64orionel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]a*eb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tron-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ | xstormy16-* | xtensa-* \ | ymp-* \ | z8k-*) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; 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 ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; c90) basic_machine=c90-cray os=-unicos ;; 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 | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; 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 ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mipsEE* | ee | ps2) basic_machine=mips64r5900el-scei case $os in -linux*) ;; *) os=-elf ;; esac ;; iop) basic_machine=mipsel-scei os=-irx ;; dvp) basic_machine=dvp-scei os=-elf ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown 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 ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; 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 ;; np1) basic_machine=np1-gould ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; 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 ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tic55x | c55x*) basic_machine=tic55x-unknown os=-coff ;; tic6x | c6x*) basic_machine=tic6x-unknown os=-coff ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; 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 ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # 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) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/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. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First 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* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -irx*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -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 ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` 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 $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) 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 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; 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 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-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 ;; *-next) os=-nextstep3 ;; *-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 ;; *) 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. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -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 ;; -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 basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks '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.28.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.28.0' PACKAGE_STRING='sqlite 3.28.0' PACKAGE_BUGREPORT='' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include <stdio.h> #ifdef HAVE_SYS_TYPES_H |
︙ | ︙ | |||
766 767 768 769 770 771 772 | #ifdef HAVE_UNISTD_H # include <unistd.h> #endif" ac_subst_vars='LTLIBOBJS LIBOBJS BUILD_CFLAGS | < | 766 767 768 769 770 771 772 773 774 775 776 777 778 779 | #ifdef HAVE_UNISTD_H # include <unistd.h> #endif" ac_subst_vars='LTLIBOBJS LIBOBJS BUILD_CFLAGS USE_GCOV OPT_FEATURE_FLAGS HAVE_ZLIB USE_AMALGAMATION TARGET_DEBUG TARGET_HAVE_EDITLINE TARGET_HAVE_READLINE |
︙ | ︙ | |||
796 797 798 799 800 801 802 | SQLITE_OS_WIN SQLITE_OS_UNIX BUILD_EXEEXT TEMP_STORE ALLOWRELEASE SQLITE_THREADSAFE BUILD_CC | | | 795 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 VERSION_NUMBER RELEASE VERSION program_prefix TCLLIBDIR TCLSH_CMD INSTALL_DATA INSTALL_SCRIPT |
︙ | ︙ | |||
860 861 862 863 864 865 866 867 868 869 870 871 872 873 | pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir | > | 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 | pdfdir dvidir htmldir infodir docdir oldincludedir includedir runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir |
︙ | ︙ | |||
889 890 891 892 893 894 895 | enable_shared enable_static with_pic enable_fast_install with_gnu_ld enable_libtool_lock enable_largefile | < < < < > | 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 | enable_shared enable_static with_pic enable_fast_install with_gnu_ld enable_libtool_lock enable_largefile enable_threadsafe enable_releasemode enable_tempstore enable_tcl 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 enable_geopoly enable_rtree enable_session enable_gcov ' ac_precious_vars='build_alias |
︙ | ︙ | |||
964 965 966 967 968 969 970 971 972 973 974 975 976 977 | sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' | > | 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 | sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' |
︙ | ︙ | |||
1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 | ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; | > > > > > > > > > | 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 | ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; |
︙ | ︙ | |||
1353 1354 1355 1356 1357 1358 1359 | esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ | | | 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 | esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; |
︙ | ︙ | |||
1466 1467 1468 1469 1470 1471 1472 | # # 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 | | | 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 | # # 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.28.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. |
︙ | ︙ | |||
1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 | Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] | > | 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 | Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] |
︙ | ︙ | |||
1531 1532 1533 1534 1535 1536 1537 | --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 | | | 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 | --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.28.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] |
︙ | ︙ | |||
1557 1558 1559 1560 1561 1562 1563 | --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 | < < < > < < | 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 | --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 --enable-geopoly Enable the GEOPOLY extension --enable-rtree Enable the RTREE extension --enable-session Enable the SESSION extension --enable-gcov Enable coverage testing using gcov Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-pic try to use only PIC/non-PIC objects [default=use both] --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-tcl=DIR directory containing tcl configuration (tclConfig.sh) --with-readline-lib specify readline library --with-readline-inc specify readline include paths Some influential environment variables: CC C compiler command |
︙ | ︙ | |||
1661 1662 1663 1664 1665 1666 1667 | cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF | | | 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 | 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.28.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 |
︙ | ︙ | |||
2080 2081 2082 2083 2084 2085 2086 | 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. | | | 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 | 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.28.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { |
︙ | ︙ | |||
3938 3939 3940 3941 3942 3943 3944 | { $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 | | | | | 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 | { $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:3949: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 (eval echo "\"\$as_me:3952: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 (eval echo "\"\$as_me:3955: 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 |
︙ | ︙ | |||
5150 5151 5152 5153 5154 5155 5156 | ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. | | | 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 | ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '#line 5161 "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 |
︙ | ︙ | |||
6675 6676 6677 6678 6679 6680 6681 | # 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:'` | | | | 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 | # 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:6686: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:6690: \$? = $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 |
︙ | ︙ | |||
7014 7015 7016 7017 7018 7019 7020 | # 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:'` | | | | 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 | # 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:7025: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:7029: \$? = $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 |
︙ | ︙ | |||
7119 7120 7121 7122 7123 7124 7125 | # (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:'` | | | | 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 | # (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:7130: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:7134: \$? = $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 |
︙ | ︙ | |||
7174 7175 7176 7177 7178 7179 7180 | # (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:'` | | | | 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 | # (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:7185: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:7189: \$? = $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 |
︙ | ︙ | |||
9554 9555 9556 9557 9558 9559 9560 | 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 | | | 9558 9559 9560 9561 9562 9563 9564 9565 9566 9567 9568 9569 9570 9571 9572 | 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 9565 "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include <dlfcn.h> #endif #include <stdio.h> |
︙ | ︙ | |||
9650 9651 9652 9653 9654 9655 9656 | 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 | | | 9654 9655 9656 9657 9658 9659 9660 9661 9662 9663 9664 9665 9666 9667 9668 | 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 9661 "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include <dlfcn.h> #endif #include <stdio.h> |
︙ | ︙ | |||
9999 10000 10001 10002 10003 10004 10005 | cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <sys/types.h> /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ | | | 10003 10004 10005 10006 10007 10008 10009 10010 10011 10012 10013 10014 10015 10016 10017 | cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <sys/types.h> /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { |
︙ | ︙ | |||
10045 10046 10047 10048 10049 10050 10051 | cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <sys/types.h> /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ | | | 10049 10050 10051 10052 10053 10054 10055 10056 10057 10058 10059 10060 10061 10062 10063 | cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <sys/types.h> /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { |
︙ | ︙ | |||
10069 10070 10071 10072 10073 10074 10075 | /* end confdefs.h. */ #define _FILE_OFFSET_BITS 64 #include <sys/types.h> /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ | | | 10073 10074 10075 10076 10077 10078 10079 10080 10081 10082 10083 10084 10085 10086 10087 | /* end confdefs.h. */ #define _FILE_OFFSET_BITS 64 #include <sys/types.h> /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { |
︙ | ︙ | |||
10114 10115 10116 10117 10118 10119 10120 | cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <sys/types.h> /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ | | | 10118 10119 10120 10121 10122 10123 10124 10125 10126 10127 10128 10129 10130 10131 10132 | cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <sys/types.h> /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { |
︙ | ︙ | |||
10138 10139 10140 10141 10142 10143 10144 | /* end confdefs.h. */ #define _LARGE_FILES 1 #include <sys/types.h> /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ | | | 10142 10143 10144 10145 10146 10147 10148 10149 10150 10151 10152 10153 10154 10155 10156 | /* end confdefs.h. */ #define _LARGE_FILES 1 #include <sys/types.h> /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { |
︙ | ︙ | |||
10367 10368 10369 10370 10371 10372 10373 | 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 | fi if test "x${TCLLIBDIR+set}" != "xset" ; then TCLLIBDIR='$(libdir)' for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD}` ; do TCLLIBDIR=$i break done TCLLIBDIR="${TCLLIBDIR}/sqlite3" fi ######### # Set up an appropriate program prefix |
︙ | ︙ | |||
10392 10393 10394 10395 10396 10397 10398 | { $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;} | | < < < < < | < < < < | < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < | | 10394 10395 10396 10397 10398 10399 10400 10401 10402 10403 10404 10405 10406 10407 10408 10409 10410 10411 10412 | { $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;} VERSION_NUMBER=`cat $srcdir/VERSION \ | sed 's/[^0-9]/ /g' \ | awk '{printf "%d%03d%03d",$1,$2,$3}'` { $as_echo "$as_me:${as_lineno-$LINENO}: Version number set to $VERSION_NUMBER" >&5 $as_echo "$as_me: Version number set to $VERSION_NUMBER" >&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 |
︙ | ︙ | |||
11314 11315 11316 11317 11318 11319 11320 | ######### # check for debug enabled # Check whether --enable-debug was given. if test "${enable_debug+set}" = set; then : enableval=$enable_debug; fi | < < < < < < < | | 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 | ######### # 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 if test "${enable_amalgamation}" == "no" ; then USE_AMALGAMATION=0 fi ######### # Look for zlib. Only needed by extensions and by the sqlite3.exe shell for ac_header in zlib.h |
︙ | ︙ | |||
11484 11485 11486 11487 11488 11489 11490 | test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi else OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1" fi | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 11423 11424 11425 11426 11427 11428 11429 11430 11431 11432 11433 11434 11435 11436 | 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; |
︙ | ︙ | |||
11629 11630 11631 11632 11633 11634 11635 | ######### # 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 | < < < < < < < < < | < < | 11465 11466 11467 11468 11469 11470 11471 11472 11473 11474 11475 11476 11477 11478 11479 11480 11481 11482 11483 11484 11485 11486 11487 | ######### # 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 if test "${enable_fts4}" = "yes" ; then 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 |
︙ | ︙ | |||
11706 11707 11708 11709 11710 11711 11712 | $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 | < < < < < | < < | 11531 11532 11533 11534 11535 11536 11537 11538 11539 11540 11541 11542 11543 11544 11545 11546 11547 11548 11549 11550 11551 | $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 if test "${enable_fts5}" = "yes" ; then 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 |
︙ | ︙ | |||
11777 11778 11779 11780 11781 11782 11783 | $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 | > | > > > > > > | < > > < < | < < < < < < < | < < < < < < < < < < < < < < | < < < < < | 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 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 | $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 if test "${enable_json1}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_JSON1" 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 if test "${enable_udlimit}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT" 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 if test "${enable_geopoly}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_GEOPOLY" enable_rtree=yes fi ######### # See whether we should enable RTREE # Check whether --enable-rtree was given. if test "${enable_rtree+set}" = set; then : enableval=$enable_rtree; fi if test "${enable_rtree}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_RTREE" 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 if test "${enable_session}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_SESSION" OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_PREUPDATE_HOOK" fi ######### # attempt to duplicate any OMITS and ENABLES into the ${OPT_FEATURE_FLAGS} parameter for option in $CFLAGS $CPPFLAGS do case $option in |
︙ | ︙ | |||
11924 11925 11926 11927 11928 11929 11930 | if test "${use_gcov}" = "yes" ; then USE_GCOV=1 else USE_GCOV=0 fi | < < < < < < < < < < < | | 11722 11723 11724 11725 11726 11727 11728 11729 11730 11731 11732 11733 11734 11735 11736 11737 11738 11739 | if test "${use_gcov}" = "yes" ; then USE_GCOV=1 else USE_GCOV=0 fi ######### # Output the config header ac_config_headers="$ac_config_headers config.h" ######### # Generate the output files. # ac_config_files="$ac_config_files Makefile sqlite3.pc" |
︙ | ︙ | |||
12453 12454 12455 12456 12457 12458 12459 | 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=" | | | 12240 12241 12242 12243 12244 12245 12246 12247 12248 12249 12250 12251 12252 12253 12254 | 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.28.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 $@ |
︙ | ︙ | |||
12519 12520 12521 12522 12523 12524 12525 | 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="\\ | | | 12306 12307 12308 12309 12310 12311 12312 12313 12314 12315 12316 12317 12318 12319 12320 | 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.28.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." |
︙ | ︙ | |||
12901 12902 12903 12904 12905 12906 12907 | cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; | | | 12688 12689 12690 12691 12692 12693 12694 12695 12696 12697 12698 12699 12700 12701 12702 | cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "sqlite3.pc") CONFIG_FILES="$CONFIG_FILES sqlite3.pc" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done |
︙ | ︙ |
Changes to configure.ac.
︙ | ︙ | |||
66 67 68 69 70 71 72 | # # TARGET_EXEEXT # # The filename extension for executables on the # target platform. "" for Unix and ".exe" for windows. # # This configure.in file is easy to reuse on other projects. Just | | | | | 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 | # # TARGET_EXEEXT # # The filename extension for executables on the # target platform. "" for Unix and ".exe" for windows. # # This configure.in file is easy to reuse on other projects. Just # change the argument to AC_INIT(). And disable any features that # you don't need (for example BLT) by erasing or commenting out # the corresponding code. # AC_INIT(sqlite, m4_esyscmd([cat VERSION | tr -d '\n'])) dnl Make sure the local VERSION file matches this configure script sqlite_version_sanity_check=`cat $srcdir/VERSION | tr -d '\n'` if test "$PACKAGE_VERSION" != "$sqlite_version_sanity_check" ; then AC_MSG_ERROR([configure script is out of date: configure \$PACKAGE_VERSION = $PACKAGE_VERSION top level VERSION file = $sqlite_version_sanity_check please regen with autoconf]) fi ######### # Programs needed # AC_PROG_LIBTOOL AC_PROG_INSTALL ######### # Enable large file support (if special flags are necessary) # AC_SYS_LARGEFILE |
︙ | ︙ | |||
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 167 168 169 | 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 TCLLIBDIR=$i break 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) VERSION_NUMBER=[`cat $srcdir/VERSION \ | sed 's/[^0-9]/ /g' \ | awk '{printf "%d%03d%03d",$1,$2,$3}'`] AC_MSG_NOTICE(Version number set to $VERSION_NUMBER) AC_SUBST(VERSION_NUMBER) ######### # 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 |
︙ | ︙ | |||
225 226 227 228 229 230 231 | fi AC_SUBST(BUILD_CC) ########## # Do we want to support multithreaded use of sqlite # AC_ARG_ENABLE(threadsafe, | | | | | 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 | fi AC_SUBST(BUILD_CC) ########## # Do we want to support multithreaded use of sqlite # AC_ARG_ENABLE(threadsafe, AC_HELP_STRING([--disable-threadsafe],[Disable mutexing])) AC_MSG_CHECKING([whether to support threadsafe operation]) if test "$enable_threadsafe" = "no"; then SQLITE_THREADSAFE=0 AC_MSG_RESULT([no]) else SQLITE_THREADSAFE=1 AC_MSG_RESULT([yes]) fi AC_SUBST(SQLITE_THREADSAFE) if test "$SQLITE_THREADSAFE" = "1"; then AC_SEARCH_LIBS(pthread_create, pthread) AC_SEARCH_LIBS(pthread_mutexattr_init, pthread) fi ########## # Do we want to support release # AC_ARG_ENABLE(releasemode, AC_HELP_STRING([--enable-releasemode],[Support libtool link to release mode]),,enable_releasemode=no) AC_MSG_CHECKING([whether to support shared library linked as release mode or not]) if test "$enable_releasemode" = "no"; then ALLOWRELEASE="" AC_MSG_RESULT([no]) else ALLOWRELEASE="-release `cat $srcdir/VERSION`" AC_MSG_RESULT([yes]) fi AC_SUBST(ALLOWRELEASE) ########## # Do we want temporary databases in memory # AC_ARG_ENABLE(tempstore, AC_HELP_STRING([--enable-tempstore],[Use an in-ram database for temporary tables (never,no,yes,always)]),,enable_tempstore=no) AC_MSG_CHECKING([whether to use an in-ram database for temporary tables]) case "$enable_tempstore" in never ) TEMP_STORE=0 AC_MSG_RESULT([never]) ;; no ) |
︙ | ︙ | |||
300 301 302 303 304 305 306 | if test "$config_BUILD_EXEEXT" = ".exe"; then CYGWIN=yes AC_MSG_RESULT(yes) else AC_MSG_RESULT(unknown) fi if test "$CYGWIN" != "yes"; then | < < < < < < | < < | 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 | if test "$config_BUILD_EXEEXT" = ".exe"; then CYGWIN=yes AC_MSG_RESULT(yes) else AC_MSG_RESULT(unknown) fi if test "$CYGWIN" != "yes"; then AC_CYGWIN fi if test "$CYGWIN" = "yes"; then BUILD_EXEEXT=.exe else BUILD_EXEEXT=$EXEEXT fi if test x"$cross_compiling" = xno; then |
︙ | ︙ | |||
343 344 345 346 347 348 349 | # Figure out all the parameters needed to compile against Tcl. # # This code is derived from the SC_PATH_TCLCONFIG and SC_LOAD_TCLCONFIG # macros in the in the tcl.m4 file of the standard TCL distribution. # Those macros could not be used directly since we have to make some # minor changes to accomodate systems that do not have TCL installed. # | | | | 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 | # Figure out all the parameters needed to compile against Tcl. # # This code is derived from the SC_PATH_TCLCONFIG and SC_LOAD_TCLCONFIG # macros in the in the tcl.m4 file of the standard TCL distribution. # Those macros could not be used directly since we have to make some # minor changes to accomodate systems that do not have TCL installed. # AC_ARG_ENABLE(tcl, AC_HELP_STRING([--disable-tcl],[do not build TCL extension]), [use_tcl=$enableval],[use_tcl=yes]) if test "${use_tcl}" = "yes" ; then AC_ARG_WITH(tcl, AC_HELP_STRING([--with-tcl=DIR],[directory containing tcl configuration (tclConfig.sh)]), with_tclconfig=${withval}) AC_MSG_CHECKING([for Tcl configuration]) AC_CACHE_VAL(ac_cv_c_tclconfig,[ # First check to see if --with-tcl was specified. if test x"${with_tclconfig}" != x ; then if test -f "${with_tclconfig}/tclConfig.sh" ; then ac_cv_c_tclconfig=`(cd ${with_tclconfig}; pwd)` else |
︙ | ︙ | |||
528 529 530 531 532 533 534 | # that use "readline()" library. # TARGET_READLINE_LIBS="" TARGET_READLINE_INC="" TARGET_HAVE_READLINE=0 TARGET_HAVE_EDITLINE=0 AC_ARG_ENABLE([editline], | | | | | | 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 | # that use "readline()" library. # TARGET_READLINE_LIBS="" TARGET_READLINE_INC="" TARGET_HAVE_READLINE=0 TARGET_HAVE_EDITLINE=0 AC_ARG_ENABLE([editline], [AC_HELP_STRING([--enable-editline],[enable BSD editline support])], [with_editline=$enableval], [with_editline=auto]) AC_ARG_ENABLE([readline], [AC_HELP_STRING([--disable-readline],[disable readline support])], [with_readline=$enableval], [with_readline=auto]) if test x"$with_editline" != xno; then sLIBS=$LIBS LIBS="" TARGET_HAVE_EDITLINE=1 AC_SEARCH_LIBS(readline,edit,[with_readline=no],[TARGET_HAVE_EDITLINE=0]) TARGET_READLINE_LIBS=$LIBS LIBS=$sLIBS fi if test x"$with_readline" != xno; then found="yes" AC_ARG_WITH([readline-lib], [AC_HELP_STRING([--with-readline-lib],[specify readline library])], [with_readline_lib=$withval], [with_readline_lib="auto"]) if test "x$with_readline_lib" = xauto; then save_LIBS="$LIBS" LIBS="" AC_SEARCH_LIBS(tgetent, [readline ncurses curses termcap], [term_LIBS="$LIBS"], [term_LIBS=""]) AC_CHECK_LIB([readline], [readline], [TARGET_READLINE_LIBS="-lreadline"], [found="no"]) TARGET_READLINE_LIBS="$TARGET_READLINE_LIBS $term_LIBS" LIBS="$save_LIBS" else TARGET_READLINE_LIBS="$with_readline_lib" fi AC_ARG_WITH([readline-inc], [AC_HELP_STRING([--with-readline-inc],[specify readline include paths])], [with_readline_inc=$withval], [with_readline_inc="auto"]) if test "x$with_readline_inc" = xauto; then AC_CHECK_HEADER(readline.h, [found="yes"], [ found="no" if test "$cross_compiling" != yes; then for dir in /usr /usr/local /usr/local/readline /usr/contrib /mingw; do |
︙ | ︙ | |||
608 609 610 611 612 613 614 | # Figure out what C libraries are required to compile programs # that use "fdatasync()" function. # AC_SEARCH_LIBS(fdatasync, [rt]) ######### # check for debug enabled | | < < < < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | < < < < | < | < < < | < | < > | < > > > > > | < | < < < | < | < < < | < < < < | < | < < < | 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 | # Figure out what C libraries are required to compile programs # 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])) 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) AC_SEARCH_LIBS(deflate, z, [HAVE_ZLIB="-DSQLITE_HAVE_ZLIB=1"], [HAVE_ZLIB=""]) AC_SUBST(HAVE_ZLIB) ######### # See whether we should allow loadable extensions AC_ARG_ENABLE(load-extension, AC_HELP_STRING([--disable-load-extension], [Disable loading of external extensions]),,[enable_load_extension=yes]) 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 OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_MEMSYS5" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi AC_ARG_ENABLE(memsys3, AC_HELP_STRING([--enable-memsys3],[Enable MEMSYS3])) AC_MSG_CHECKING([whether to support MEMSYS3]) if test "${enable_memsys3}" = "yes" -a "${enable_memsys5}" = "no"; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_MEMSYS3" AC_MSG_RESULT([yes]) else 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])) if test "${enable_fts4}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS4" AC_SEARCH_LIBS([log],[m]) fi AC_ARG_ENABLE(fts5, AC_HELP_STRING([--enable-fts5], [Enable the FTS5 extension])) if test "${enable_fts5}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS5" AC_SEARCH_LIBS([log],[m]) fi ######### # See whether we should enable JSON1 AC_ARG_ENABLE(json1, AC_HELP_STRING([--enable-json1],[Enable the JSON1 extension])) if test "${enable_json1}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_JSON1" 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])) if test "${enable_udlimit}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT" 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]) if test "${enable_geopoly}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_GEOPOLY" enable_rtree=yes fi ######### # See whether we should enable RTREE AC_ARG_ENABLE(rtree, AC_HELP_STRING([--enable-rtree], [Enable the RTREE extension])) if test "${enable_rtree}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_RTREE" fi ######### # See whether we should enable the SESSION extension AC_ARG_ENABLE(session, AC_HELP_STRING([--enable-session], [Enable the SESSION extension])) if test "${enable_session}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_SESSION" OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_PREUPDATE_HOOK" fi ######### # attempt to duplicate any OMITS and ENABLES into the ${OPT_FEATURE_FLAGS} parameter for option in $CFLAGS $CPPFLAGS do case $option in |
︙ | ︙ | |||
838 839 840 841 842 843 844 | esac done BUILD_CFLAGS=$ac_temp_BUILD_CFLAGS ######### # See whether we should use GCOV | | < < < < < < < < < < < | | < | 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 | esac done BUILD_CFLAGS=$ac_temp_BUILD_CFLAGS ######### # See whether we should use GCOV AC_ARG_ENABLE(gcov, AC_HELP_STRING([--enable-gcov], [Enable coverage testing using gcov])) if test "${use_gcov}" = "yes" ; then USE_GCOV=1 else USE_GCOV=0 fi AC_SUBST(USE_GCOV) ######### # Output the config header AC_CONFIG_HEADERS(config.h) ######### # Generate the output files. # AC_SUBST(BUILD_CFLAGS) AC_OUTPUT([ Makefile sqlite3.pc ]) |
Deleted doc/json-enhancements.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
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 | <html> <head> <title>The Lemon Parser Generator</title> </head> <body bgcolor='white'> <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> <h2>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>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> <h2>Theory of Operation</h2> <p>The main goal of Lemon is to translate a context free grammar (CFG) for a particular language into C code that implements a parser for that language. The program has two inputs: <ul> <li>The grammar specification. <li>A parser template file. </ul> Typically, only the grammar specification is supplied by the programmer. Lemon comes with a default parser template which 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. <ul> <li>C code to implement the parser. <li>A header file defining an integer ID for each terminal symbol. <li>An information file that describes the states of the generated parser automaton. </ul> 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: <pre> lemon gram.y </pre> 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> <h3>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 <pre> lemon "-?" </pre> As of this writing, the following command-line options are supported: <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>" and "<tt><a href='#pifdef'>%ifndef</a></tt>" lines in the 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 existing. <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> <h3>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: <pre> void *pParser = ParseAlloc( malloc ); </pre> 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 <pre> ParseFree(pParser, free); </pre> 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: <pre> Parse(pParser, hTokenID, sTokenData, pArg); </pre> 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 |
︙ | ︙ | |||
231 232 233 234 235 236 237 | 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 | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | < | | 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 | 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: <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> 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 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: <pre> ParseFile(){ pParser = ParseAlloc( malloc ); while( GetNextToken(pTokenizer,&hTokenId, &sToken) ){ Parse(pParser, hTokenId, sToken); } Parse(pParser, 0, sToken); ParseFree(pParser, free ); } </pre> 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: <pre> ParseTrace(FILE *stream, char *zPrefix); </pre> 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> <h3>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. <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> 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, and to obviate the need for global variables.</p> <h2>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, 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> <h3>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 |
︙ | ︙ | |||
454 455 456 457 458 459 460 | <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> | < | | > | > | | | | | | | | | | | | | | | | | | | | | | | | | < | | < < < | | | < < < | | | | | | | | | | | | 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 | <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> <h3>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: <pre> expr ::= expr PLUS expr. expr ::= expr TIMES expr. expr ::= LPAREN expr RPAREN. expr ::= VALUE. </pre> </p> <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: <pre> expr ::= expr PLUS expr. { printf("Doing an addition...\n"); } </pre> </p> <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: <pre> expr -> expr PLUS expr { $$ = $1 + $3; }; </pre> But in Lemon, the same rule becomes the following: <pre> expr(A) ::= expr(B) PLUS expr(C). { A = B+C; } </pre> 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 <pre> expr(A) ::= expr(B) PLUS expr(C). { A = B; } </pre> 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 name='precrules'></a> <h3>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> <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> <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 <pre> a AND b OR c </pre> like this <pre> a AND (b OR c). </pre> 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 <pre> a AND b AND c </pre> is parsed like this <pre> (a AND b) AND c. </pre> The EXP operator is right-associative, though, so <pre> a EXP b EXP c </pre> is parsed like this <pre> a EXP (b EXP c). </pre> The nonassoc precedence is used for non-associative operators. So <pre> a EQ b EQ c </pre> 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 to 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> <p><pre> expr = MINUS expr. [NOT] </pre></p> <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: <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> Reduce-reduce conflicts are resolved this way: <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> <h3>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: <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'>%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'>%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_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> Each of these directives will be described separately in the following sections:</p> <a name='pcode'></a> <h4>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> <a name='default_destructor'></a> <h4>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 name='#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 name='default_type'></a> <h4>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 name='destructor'></a> <h4>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: <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> 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: <pre> %type nt {void*} %destructor nt { free($$); } nt(A) ::= ID NUM. { A = malloc( 100 ); } </pre> 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 |
︙ | ︙ | |||
790 791 792 793 794 795 796 | 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> | | | | | | | | | | | | | | | | | | | | | < | | | < < < < < < < < < < < | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | | | | | | | | | | | | | | | | 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 | 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 name='extraarg'></a> <h4>The <tt>%extra_argument</tt> directive</h4> 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> <p><pre> %extra_argument { MyStruct *pAbc } </pre></p> <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(). <a name='extractx'></a> <h4>The <tt>%extra_context</tt> directive</h4> The <tt>%extra_context</tt> directive instructs Lemon to add a 2th parameter to the parameter list of the ParseAlloc() and ParseInif() 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> <p><pre> %extra_context { MyStruct *pAbc } </pre></p> <p>Then the ParseAlloc() and ParseInit() functions will have an 2th parameter of type "MyStruct*" and all action routines will have access to a variable named "pAbc" that is the value of that 2th 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(). <a name='pfallback'></a> <h4>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: <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 name='pifdef'></a> <h4>The <tt>%ifdef</tt>, <tt>%ifndef</tt>, and <tt>%endif</tt> directives</h4> <p>The <tt>%ifdef</tt>, <tt>%ifndef</tt>, and <tt>%endif</tt> directives are similar to #ifdef, #ifndef, 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>Note that the argument to <tt>%ifdef</tt> and <tt>%ifndef</tt> must be a single preprocessor symbol name, not a general expression. There is no "<tt>%else</tt>" directive.</p> <a name='pinclude'></a> <h4>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> <p><pre> %include {#include <unistd.h>} </pre></p> <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 name='pleft'></a> <h4>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> <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> <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 name='pname'></a> <h4>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> <p><pre> %name Abcde </pre></p> <p>Putting this directive in the grammar file will cause Lemon to generate functions named <ul> <li> AbcdeAlloc(), <li> AbcdeFree(), <li> AbcdeTrace(), and <li> Abcde(). </ul> The <tt>%name</tt> directive allows you to generate two or more different parsers and link them all into the same executable.</p> <a name='pnonassoc'></a> <h4>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 name='parse_accept'></a> <h4>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> <p><pre> %parse_accept { printf("parsing complete!\n"); } </pre></p> <a name='parse_failure'></a> <h4>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> <p><pre> %parse_failure { fprintf(stderr,"Giving up. Parser is hopelessly lost...\n"); } </pre></p> <a name='pright'></a> <h4>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 name='stack_overflow'></a> <h4>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> <p><pre> %stack_overflow { fprintf(stderr,"Giving up. Parser stack overflow\n"); } </pre></p> <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: <pre> list ::= list element. // left-recursion. Good! list ::= . </pre> Not like this: <pre> list ::= element list. // right-recursion. Bad! list ::= . </pre></p> <a name='stack_size'></a> <h4>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> <p><pre> %stack_size 2000 </pre></p> <a name='start_symbol'></a> <h4>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> <p><pre> %start_symbol prog </pre></p> <a name='syntax_error'></a> <h4>The <tt>%syntax_error</tt> directive</h4> <p>See <a href='#error_processing'>Error Processing</a>.</p> <a name='token_class'></a> <h4>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 name='token_destructor'></a> <h4>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 name='token_prefix'></a> <h4>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: <pre> #define AND 1 #define MINUS 2 #define OR 3 #define PLUS 4 </pre> You can insert a statement into the grammar like this: <pre> %token_prefix TOKEN_ </pre> to cause Lemon to produce these symbols instead: <pre> #define TOKEN_AND 1 #define TOKEN_MINUS 2 #define TOKEN_OR 3 #define TOKEN_PLUS 4 </pre></p> <a name='token_type'></a><a name='ptype'></a> <h4>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 by a pointer to some kind of token structure. Like this:</p> <p><pre> %token_type {Token*} </pre></p> <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> <p><pre> %type expr {Expr*} </pre></p> <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 name='pwildcard'></a> <h4>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 name='error_processing'></a> <h3>Error Processing</h3> <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 |
︙ | ︙ | |||
1220 1221 1222 1223 1224 1225 1226 | 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> | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1056 1057 1058 1059 1060 1061 1062 1063 1064 | 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> |
Deleted doc/trusted-schema.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted doc/vdbesort-memory.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted doc/wal-lock.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
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 1707 | 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 223 | #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.
︙ | ︙ | |||
24 25 26 27 28 29 30 | set testprefix expert1 if {[info commands sqlite3_expert_new]==""} { finish_test return } | < < < < | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | 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 } |
︙ | ︙ | |||
76 77 78 79 80 81 82 | $expert destroy set tst [subst -nocommands {set {} [squish [join {$result}]]}] uplevel [list do_test $tn $tst [string trim [squish $res]]] } } 3 { | < < < < | | | | | < | < | | | | | | | | | | | | | | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | > | 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 | $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) SCAN TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE t1 USING COVERING INDEX t1_idx_000123a7 (a=?) } 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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE t6 USING INDEX t6_idx_00000063 (c=?) SEARCH TABLE 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 TABLE t7 USING INDEX t7_idx_00000061 (a=?) INDEX 2 SEARCH TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE t2 USING INDEX t2_idx_00000064 (d=?) SEARCH TABLE 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 TABLE t1 } } 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 4.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 4.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 4.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 4.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 | ** ************************************************************************* */ #include "sqlite3expert.h" #include <assert.h> #include <string.h> #include <stdio.h> | < < < < < < < < < < < < < < < < < | 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; |
︙ | ︙ | |||
693 694 695 696 697 698 699 | sqlite3 *db, /* Database connection to read details from */ const char *zTab, /* Table name */ IdxTable **ppOut, /* OUT: New object (if successful) */ char **pzErrmsg /* OUT: Error message (if not) */ ){ sqlite3_stmt *p1 = 0; int nCol = 0; | | | < < < < < | < < < < < | < | < < < < | | | < | | | | | 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 | sqlite3 *db, /* Database connection to read details from */ const char *zTab, /* Table name */ IdxTable **ppOut, /* OUT: New object (if successful) */ char **pzErrmsg /* OUT: Error message (if not) */ ){ 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; rc = idxPrintfPrepareStmt(db, &p1, pzErrmsg, "PRAGMA table_info=%Q", zTab); while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(p1) ){ const char *zCol = (const char*)sqlite3_column_text(p1, 1); nByte += 1 + STRLEN(zCol); rc = sqlite3_table_column_metadata( db, "main", zTab, zCol, 0, &zCol, 0, 0, 0 ); nByte += 1 + STRLEN(zCol); nCol++; } 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); int nCopy = STRLEN(zCol) + 1; pNew->aCol[nCol].zName = pCsr; pNew->aCol[nCol].iPk = sqlite3_column_int(p1, 5); memcpy(pCsr, zCol, nCopy); pCsr += nCopy; rc = sqlite3_table_column_metadata( db, "main", zTab, zCol, 0, &zCol, 0, 0, 0 ); if( rc==SQLITE_OK ){ nCopy = STRLEN(zCol) + 1; pNew->aCol[nCol].zColl = pCsr; memcpy(pCsr, zCol, nCopy); pCsr += nCopy; } nCol++; } idxFinalize(&rc, p1); if( rc!=SQLITE_OK ){ sqlite3_free(pNew); pNew = 0; }else{ pNew->zName = pCsr; memcpy(pNew->zName, zTab, nTab+1); } *ppOut = pNew; return rc; } /* |
︙ | ︙ | |||
816 817 818 819 820 821 822 | /* ** Return true if zId must be quoted in order to use it as an SQL ** identifier, or false otherwise. */ static int idxIdentifierRequiresQuotes(const char *zId){ int i; | < < < < | 783 784 785 786 787 788 789 790 791 792 793 794 795 796 | /* ** Return true if zId must be quoted in order to use it as an SQL ** identifier, or false otherwise. */ static int idxIdentifierRequiresQuotes(const char *zId){ int i; for(i=0; zId[i]; i++){ if( !(zId[i]=='_') && !(zId[i]>='0' && zId[i]<='9') && !(zId[i]>='a' && zId[i]<='z') && !(zId[i]>='A' && zId[i]<='Z') ){ return 1; |
︙ | ︙ | |||
896 897 898 899 900 901 902 | rc = idxPrintfPrepareStmt(dbm, &pIdxList, 0, "PRAGMA index_list=%Q", zTbl); while( rc==SQLITE_OK && sqlite3_step(pIdxList)==SQLITE_ROW ){ int bMatch = 1; IdxConstraint *pT = pTail; sqlite3_stmt *pInfo = 0; const char *zIdx = (const char*)sqlite3_column_text(pIdxList, 1); | < | 859 860 861 862 863 864 865 866 867 868 869 870 871 872 | rc = idxPrintfPrepareStmt(dbm, &pIdxList, 0, "PRAGMA index_list=%Q", zTbl); while( rc==SQLITE_OK && sqlite3_step(pIdxList)==SQLITE_ROW ){ int bMatch = 1; IdxConstraint *pT = pTail; sqlite3_stmt *pInfo = 0; const char *zIdx = (const char*)sqlite3_column_text(pIdxList, 1); /* Zero the IdxConstraint.bFlag values in the pEq list */ for(pIter=pEq; pIter; pIter=pIter->pLink) pIter->bFlag = 0; rc = idxPrintfPrepareStmt(dbm, &pInfo, 0, "PRAGMA index_xInfo=%Q", zIdx); while( rc==SQLITE_OK && sqlite3_step(pInfo)==SQLITE_ROW ){ int iIdx = sqlite3_column_int(pInfo, 0); |
︙ | ︙ | |||
942 943 944 945 946 947 948 | } idxFinalize(&rc, pIdxList); *pRc = rc; return 0; } | < < < < < < < < < < < < < | 904 905 906 907 908 909 910 911 912 913 914 915 916 917 | } idxFinalize(&rc, pIdxList); *pRc = rc; return 0; } static int idxCreateFromCons( sqlite3expert *p, IdxScan *pScan, IdxConstraint *pEq, IdxConstraint *pTail ){ sqlite3 *dbm = p->dbm; |
︙ | ︙ | |||
981 982 983 984 985 986 987 | 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; | < | < < | < | | | < | | < < < < < < < < < < < < < < < < < < | | < < < | < | 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 | 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; char *zName; /* Index name */ int i; for(i=0; zCols[i]; i++){ h += ((h<<3) + zCols[i]); } zName = sqlite3_mprintf("%s_idx_%08x", zTable, h); if( zName==0 ){ rc = SQLITE_NOMEM; }else{ if( idxIdentifierRequiresQuotes(zTable) ){ zFmt = "CREATE INDEX '%q' ON %Q(%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); idxHashAdd(&rc, &p->hIdx, zName, zIdx); } sqlite3_free(zName); sqlite3_free(zIdx); } } sqlite3_free(zCols); |
︙ | ︙ | |||
1179 1180 1181 1182 1183 1184 1185 | /* ** This function is called after candidate indexes have been created. It ** runs all the queries to see which indexes they prefer, and populates ** IdxStatement.zIdx and IdxStatement.zEQP with the results. */ | | | 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 | /* ** This function is called after candidate indexes have been created. It ** runs all the queries to see which indexes they prefer, and populates ** IdxStatement.zIdx and IdxStatement.zEQP with the results. */ int idxFindIndexes( sqlite3expert *p, char **pzErr /* OUT: Error message (sqlite3_malloc) */ ){ IdxStatement *pStmt; sqlite3 *dbm = p->dbm; int rc = SQLITE_OK; |
︙ | ︙ | |||
1202 1203 1204 1205 1206 1207 1208 | "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); | | < < < | < | < | 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 | "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 = STRLEN(zDetail); int i; for(i=0; i<nDetail; i++){ const char *zIdx = 0; if( memcmp(&zDetail[i], " USING INDEX ", 13)==0 ){ zIdx = &zDetail[i+13]; }else if( 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++; |
︙ | ︙ | |||
1297 1298 1299 1300 1301 1302 1303 | 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 = | | < | 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 | 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_master " "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 */ rc = idxPrintfPrepareStmt(p->db, &pSelect, pzErr, zSql, zTab, zTab); while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSelect) ){ const char *zCreate = (const char*)sqlite3_column_text(pSelect, 0); rc = sqlite3_exec(p->dbv, zCreate, 0, 0, pzErr); } idxFinalize(&rc, pSelect); /* Rename the table in the temp schema to zInt */ if( rc==SQLITE_OK ){ char *z = sqlite3_mprintf("ALTER TABLE temp.%Q RENAME TO %Q", zTab, zInt); |
︙ | ︙ | |||
1398 1399 1400 1401 1402 1403 1404 | /* 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, | | | | < | | 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 | /* 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_master " "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%%' " " UNION ALL " "SELECT type, name, sql, 2 FROM sqlite_master " "WHERE type = 'trigger'" " AND tbl_name IN(SELECT name FROM sqlite_master 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); if( zType[0]=='v' || zType[1]=='r' ){ rc = sqlite3_exec(p->dbv, zSql, 0, 0, pzErrmsg); }else{ IdxTable *pTab; rc = idxGetTableInfo(p->db, zName, &pTab, pzErrmsg); if( rc==SQLITE_OK ){ int i; char *zInner = 0; char *zOuter = 0; |
︙ | ︙ | |||
1550 1551 1552 1553 1554 1555 1556 | case SQLITE_FLOAT: pSlot->rVal = sqlite3_value_double(argv[1]); break; case SQLITE_BLOB: case SQLITE_TEXT: { int nByte = sqlite3_value_bytes(argv[1]); | < | < | < | | 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 | case SQLITE_FLOAT: pSlot->rVal = sqlite3_value_double(argv[1]); break; case SQLITE_BLOB: case SQLITE_TEXT: { int nByte = sqlite3_value_bytes(argv[1]); if( nByte>pSlot->nByte ){ char *zNew = (char*)sqlite3_realloc(pSlot->z, nByte*2); if( zNew==0 ){ sqlite3_result_error_nomem(pCtx); return; } pSlot->nByte = nByte*2; pSlot->z = zNew; } pSlot->n = nByte; if( pSlot->eType==SQLITE_BLOB ){ memcpy(pSlot->z, sqlite3_value_blob(argv[1]), nByte); }else{ memcpy(pSlot->z, sqlite3_value_text(argv[1]), nByte); } break; } } } static int idxLargestIndex(sqlite3 *db, int *pnMax, char **pzErr){ int rc = SQLITE_OK; const char *zMax = "SELECT max(i.seqno) FROM " " sqlite_master 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); |
︙ | ︙ | |||
1730 1731 1732 1733 1734 1735 1736 | 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 " | | | 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 | 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_master 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. */ |
︙ | ︙ | |||
1777 1778 1779 1780 1781 1782 1783 | rc = idxPrepareStmt(p->dbm, &pWrite, pzErr, zWrite); } while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pAllIndex) ){ i64 iRowid = sqlite3_column_int64(pAllIndex, 0); const char *zTab = (const char*)sqlite3_column_text(pAllIndex, 1); const char *zIdx = (const char*)sqlite3_column_text(pAllIndex, 2); | < | 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 | rc = idxPrepareStmt(p->dbm, &pWrite, pzErr, zWrite); } while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pAllIndex) ){ i64 iRowid = sqlite3_column_int64(pAllIndex, 0); const char *zTab = (const char*)sqlite3_column_text(pAllIndex, 1); const char *zIdx = (const char*)sqlite3_column_text(pAllIndex, 2); if( p->iSample<100 && iPrev!=iRowid ){ samplectx.target = (double)p->iSample / 100.0; samplectx.iTarget = p->iSample; samplectx.nRow = 0.0; samplectx.nRet = 0.0; rc = idxBuildSampleTable(p, zTab); if( rc!=SQLITE_OK ) break; |
︙ | ︙ | |||
1799 1800 1801 1802 1803 1804 1805 | ); } idxFinalize(&rc, pAllIndex); idxFinalize(&rc, pIndexXInfo); idxFinalize(&rc, pWrite); | < | | | | | < | | 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 | ); } idxFinalize(&rc, pAllIndex); idxFinalize(&rc, pIndexXInfo); idxFinalize(&rc, pWrite); 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_master", 0, 0, 0); } sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp."UNIQUE_TABLE_NAME,0,0,0); return rc; } /* |
︙ | ︙ | |||
1844 1845 1846 1847 1848 1849 1850 | sqlite3_db_config(pNew->dbm, SQLITE_DBCONFIG_TRIGGER_EQP, 1, (int*)0); } } /* Copy the entire schema of database [db] into [dbm]. */ if( rc==SQLITE_OK ){ | | | | | 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 | sqlite3_db_config(pNew->dbm, SQLITE_DBCONFIG_TRIGGER_EQP, 1, (int*)0); } } /* 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_master 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); } /* Create the vtab schema */ if( rc==SQLITE_OK ){ rc = idxCreateVtabSchema(pNew, pzErrmsg); |
︙ | ︙ | |||
1957 1958 1959 1960 1961 1962 1963 | /* 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); | < < < < | 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); } |
︙ | ︙ | |||
2041 2042 2043 2044 2045 2046 2047 | idxWriteFree(p->pWrite); idxHashClear(&p->hIdx); sqlite3_free(p->zCandidates); sqlite3_free(p); } } | | | 1946 1947 1948 1949 1950 1951 1952 1953 | idxWriteFree(p->pWrite); idxHashClear(&p->hIdx); sqlite3_free(p->zCandidates); sqlite3_free(p); } } #endif /* ifndef SQLITE_OMIT_VIRTUAL_TABLE */ |
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. ** ************************************************************************* */ #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*); |
Added ext/fts1/README.txt.
> > | 1 2 | This folder contains source code to the first full-text search extension for SQLite. |
Added ext/fts1/ft_hash.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 | /* ** 2001 September 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This is the implementation of generic hash-tables used in SQLite. ** We've modified it slightly to serve as a standalone hash table ** implementation for the full-text indexing module. */ #include <assert.h> #include <stdlib.h> #include <string.h> #include "ft_hash.h" void *malloc_and_zero(int n){ void *p = malloc(n); if( p ){ memset(p, 0, n); } return p; } /* Turn bulk memory into a hash table object by initializing the ** fields of the Hash structure. ** ** "pNew" is a pointer to the hash table that is to be initialized. ** keyClass is one of the constants HASH_INT, HASH_POINTER, ** HASH_BINARY, or HASH_STRING. The value of keyClass ** determines what kind of key the hash table will use. "copyKey" is ** true if the hash table should make its own private copy of keys and ** false if it should just use the supplied pointer. CopyKey only makes ** sense for HASH_STRING and HASH_BINARY and is ignored ** for other key classes. */ void HashInit(Hash *pNew, int keyClass, int copyKey){ assert( pNew!=0 ); assert( keyClass>=HASH_STRING && keyClass<=HASH_BINARY ); pNew->keyClass = keyClass; #if 0 if( keyClass==HASH_POINTER || keyClass==HASH_INT ) copyKey = 0; #endif pNew->copyKey = copyKey; pNew->first = 0; pNew->count = 0; pNew->htsize = 0; pNew->ht = 0; pNew->xMalloc = malloc_and_zero; pNew->xFree = free; } /* Remove all entries from a hash table. Reclaim all memory. ** Call this routine to delete a hash table or to reset a hash table ** to the empty state. */ void HashClear(Hash *pH){ HashElem *elem; /* For looping over all elements of the table */ assert( pH!=0 ); elem = pH->first; pH->first = 0; if( pH->ht ) pH->xFree(pH->ht); pH->ht = 0; pH->htsize = 0; while( elem ){ HashElem *next_elem = elem->next; if( pH->copyKey && elem->pKey ){ pH->xFree(elem->pKey); } pH->xFree(elem); elem = next_elem; } pH->count = 0; } #if 0 /* NOT USED */ /* ** Hash and comparison functions when the mode is HASH_INT */ static int intHash(const void *pKey, int nKey){ return nKey ^ (nKey<<8) ^ (nKey>>8); } static int intCompare(const void *pKey1, int n1, const void *pKey2, int n2){ return n2 - n1; } #endif #if 0 /* NOT USED */ /* ** Hash and comparison functions when the mode is HASH_POINTER */ static int ptrHash(const void *pKey, int nKey){ uptr x = Addr(pKey); return x ^ (x<<8) ^ (x>>8); } static int ptrCompare(const void *pKey1, int n1, const void *pKey2, int n2){ if( pKey1==pKey2 ) return 0; if( pKey1<pKey2 ) return -1; return 1; } #endif /* ** Hash and comparison functions when the mode is HASH_STRING */ static int strHash(const void *pKey, int nKey){ const char *z = (const char *)pKey; int h = 0; if( nKey<=0 ) nKey = (int) strlen(z); while( nKey > 0 ){ h = (h<<3) ^ h ^ *z++; nKey--; } return h & 0x7fffffff; } static int strCompare(const void *pKey1, int n1, const void *pKey2, int n2){ if( n1!=n2 ) return 1; return strncmp((const char*)pKey1,(const char*)pKey2,n1); } /* ** Hash and comparison functions when the mode is HASH_BINARY */ static int binHash(const void *pKey, int nKey){ int h = 0; const char *z = (const char *)pKey; while( nKey-- > 0 ){ h = (h<<3) ^ h ^ *(z++); } return h & 0x7fffffff; } static int binCompare(const void *pKey1, int n1, const void *pKey2, int n2){ if( n1!=n2 ) return 1; return memcmp(pKey1,pKey2,n1); } /* ** Return a pointer to the appropriate hash function given the key class. ** ** The C syntax in this function definition may be unfamilar to some ** programmers, so we provide the following additional explanation: ** ** The name of the function is "hashFunction". The function takes a ** single parameter "keyClass". The return value of hashFunction() ** is a pointer to another function. Specifically, the return value ** of hashFunction() is a pointer to a function that takes two parameters ** with types "const void*" and "int" and returns an "int". */ static int (*hashFunction(int keyClass))(const void*,int){ #if 0 /* HASH_INT and HASH_POINTER are never used */ switch( keyClass ){ case HASH_INT: return &intHash; case HASH_POINTER: return &ptrHash; case HASH_STRING: return &strHash; case HASH_BINARY: return &binHash;; default: break; } return 0; #else if( keyClass==HASH_STRING ){ return &strHash; }else{ assert( keyClass==HASH_BINARY ); return &binHash; } #endif } /* ** Return a pointer to the appropriate hash function given the key class. ** ** For help in interpreted the obscure C code in the function definition, ** see the header comment on the previous function. */ static int (*compareFunction(int keyClass))(const void*,int,const void*,int){ #if 0 /* HASH_INT and HASH_POINTER are never used */ switch( keyClass ){ case HASH_INT: return &intCompare; case HASH_POINTER: return &ptrCompare; case HASH_STRING: return &strCompare; case HASH_BINARY: return &binCompare; default: break; } return 0; #else if( keyClass==HASH_STRING ){ return &strCompare; }else{ assert( keyClass==HASH_BINARY ); return &binCompare; } #endif } /* Link an element into the hash table */ static void insertElement( Hash *pH, /* The complete hash table */ struct _ht *pEntry, /* The entry into which pNew is inserted */ HashElem *pNew /* The element to be inserted */ ){ HashElem *pHead; /* First element already in pEntry */ pHead = pEntry->chain; if( pHead ){ pNew->next = pHead; pNew->prev = pHead->prev; if( pHead->prev ){ pHead->prev->next = pNew; } else { pH->first = pNew; } pHead->prev = pNew; }else{ pNew->next = pH->first; if( pH->first ){ pH->first->prev = pNew; } pNew->prev = 0; pH->first = pNew; } pEntry->count++; pEntry->chain = pNew; } /* Resize the hash table so that it cantains "new_size" buckets. ** "new_size" must be a power of 2. The hash table might fail ** to resize if sqliteMalloc() fails. */ static void rehash(Hash *pH, int new_size){ struct _ht *new_ht; /* The new hash table */ HashElem *elem, *next_elem; /* For looping over existing elements */ int (*xHash)(const void*,int); /* The hash function */ assert( (new_size & (new_size-1))==0 ); new_ht = (struct _ht *)pH->xMalloc( new_size*sizeof(struct _ht) ); if( new_ht==0 ) return; if( pH->ht ) pH->xFree(pH->ht); pH->ht = new_ht; pH->htsize = new_size; xHash = hashFunction(pH->keyClass); for(elem=pH->first, pH->first=0; elem; elem = next_elem){ int h = (*xHash)(elem->pKey, elem->nKey) & (new_size-1); next_elem = elem->next; insertElement(pH, &new_ht[h], elem); } } /* This function (for internal use only) locates an element in an ** hash table that matches the given key. The hash for this key has ** already been computed and is passed as the 4th parameter. */ static HashElem *findElementGivenHash( const Hash *pH, /* The pH to be searched */ const void *pKey, /* The key we are searching for */ int nKey, int h /* The hash for this key. */ ){ HashElem *elem; /* Used to loop thru the element list */ int count; /* Number of elements left to test */ int (*xCompare)(const void*,int,const void*,int); /* comparison function */ if( pH->ht ){ struct _ht *pEntry = &pH->ht[h]; elem = pEntry->chain; count = pEntry->count; xCompare = compareFunction(pH->keyClass); while( count-- && elem ){ if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){ return elem; } elem = elem->next; } } return 0; } /* Remove a single entry from the hash table given a pointer to that ** element and a hash on the element's key. */ static void removeElementGivenHash( Hash *pH, /* The pH containing "elem" */ HashElem* elem, /* The element to be removed from the pH */ int h /* Hash value for the element */ ){ struct _ht *pEntry; if( elem->prev ){ elem->prev->next = elem->next; }else{ pH->first = elem->next; } if( elem->next ){ elem->next->prev = elem->prev; } pEntry = &pH->ht[h]; if( pEntry->chain==elem ){ pEntry->chain = elem->next; } pEntry->count--; if( pEntry->count<=0 ){ pEntry->chain = 0; } if( pH->copyKey && elem->pKey ){ pH->xFree(elem->pKey); } pH->xFree( elem ); pH->count--; if( pH->count<=0 ){ assert( pH->first==0 ); assert( pH->count==0 ); HashClear(pH); } } /* Attempt to locate an element of the hash table pH with a key ** that matches pKey,nKey. Return the data for this element if it is ** found, or NULL if there is no match. */ void *HashFind(const Hash *pH, const void *pKey, int nKey){ int h; /* A hash on key */ HashElem *elem; /* The element that matches key */ int (*xHash)(const void*,int); /* The hash function */ if( pH==0 || pH->ht==0 ) return 0; xHash = hashFunction(pH->keyClass); assert( xHash!=0 ); h = (*xHash)(pKey,nKey); assert( (pH->htsize & (pH->htsize-1))==0 ); elem = findElementGivenHash(pH,pKey,nKey, h & (pH->htsize-1)); return elem ? elem->data : 0; } /* Insert an element into the hash table pH. The key is pKey,nKey ** and the data is "data". ** ** If no element exists with a matching key, then a new ** element is created. A copy of the key is made if the copyKey ** flag is set. NULL is returned. ** ** If another element already exists with the same key, then the ** new data replaces the old data and the old data is returned. ** The key is not copied in this instance. If a malloc fails, then ** the new data is returned and the hash table is unchanged. ** ** If the "data" parameter to this function is NULL, then the ** element corresponding to "key" is removed from the hash table. */ void *HashInsert(Hash *pH, const void *pKey, int nKey, void *data){ int hraw; /* Raw hash value of the key */ int h; /* the hash of the key modulo hash table size */ HashElem *elem; /* Used to loop thru the element list */ HashElem *new_elem; /* New element added to the pH */ int (*xHash)(const void*,int); /* The hash function */ assert( pH!=0 ); xHash = hashFunction(pH->keyClass); assert( xHash!=0 ); hraw = (*xHash)(pKey, nKey); assert( (pH->htsize & (pH->htsize-1))==0 ); h = hraw & (pH->htsize-1); elem = findElementGivenHash(pH,pKey,nKey,h); if( elem ){ void *old_data = elem->data; if( data==0 ){ removeElementGivenHash(pH,elem,h); }else{ elem->data = data; } return old_data; } if( data==0 ) return 0; new_elem = (HashElem*)pH->xMalloc( sizeof(HashElem) ); if( new_elem==0 ) return data; if( pH->copyKey && pKey!=0 ){ new_elem->pKey = pH->xMalloc( nKey ); if( new_elem->pKey==0 ){ pH->xFree(new_elem); return data; } memcpy((void*)new_elem->pKey, pKey, nKey); }else{ new_elem->pKey = (void*)pKey; } new_elem->nKey = nKey; pH->count++; if( pH->htsize==0 ){ rehash(pH,8); if( pH->htsize==0 ){ pH->count = 0; pH->xFree(new_elem); return data; } } if( pH->count > pH->htsize ){ rehash(pH,pH->htsize*2); } assert( pH->htsize>0 ); assert( (pH->htsize & (pH->htsize-1))==0 ); h = hraw & (pH->htsize-1); insertElement(pH, &pH->ht[h], new_elem); new_elem->data = data; return 0; } |
Added ext/fts1/ft_hash.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 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 | /* ** 2001 September 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This is the header file for the generic hash-table implementation ** used in SQLite. We've modified it slightly to serve as a standalone ** hash table implementation for the full-text indexing module. ** */ #ifndef _HASH_H_ #define _HASH_H_ /* Forward declarations of structures. */ typedef struct Hash Hash; typedef struct HashElem HashElem; /* A complete hash table is an instance of the following structure. ** The internals of this structure are intended to be opaque -- client ** code should not attempt to access or modify the fields of this structure ** directly. Change this structure only by using the routines below. ** However, many of the "procedures" and "functions" for modifying and ** accessing this structure are really macros, so we can't really make ** this structure opaque. */ struct Hash { char keyClass; /* HASH_INT, _POINTER, _STRING, _BINARY */ char copyKey; /* True if copy of key made on insert */ int count; /* Number of entries in this table */ HashElem *first; /* The first element of the array */ void *(*xMalloc)(int); /* malloc() function to use */ void (*xFree)(void *); /* free() function to use */ int htsize; /* Number of buckets in the hash table */ struct _ht { /* the hash table */ 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. ** ** Again, this structure is intended to be opaque, but it can't really ** be opaque because it is used by macros. */ struct HashElem { HashElem *next, *prev; /* Next and previous elements in the table */ void *data; /* Data associated with this element */ void *pKey; int nKey; /* Key associated with this element */ }; /* ** There are 4 different modes of operation for a hash table: ** ** HASH_INT nKey is used as the key and pKey is ignored. ** ** HASH_POINTER pKey is used as the key and nKey is ignored. ** ** HASH_STRING pKey points to a string that is nKey bytes long ** (including the null-terminator, if any). Case ** is respected in comparisons. ** ** HASH_BINARY pKey points to binary data nKey bytes long. ** memcmp() is used to compare keys. ** ** A copy of the key is made for HASH_STRING and HASH_BINARY ** if the copyKey parameter to HashInit is 1. */ /* #define HASH_INT 1 // NOT USED */ /* #define HASH_POINTER 2 // NOT USED */ #define HASH_STRING 3 #define HASH_BINARY 4 /* ** Access routines. To delete, insert a NULL pointer. */ void HashInit(Hash*, int keytype, int copyKey); void *HashInsert(Hash*, const void *pKey, int nKey, void *pData); void *HashFind(const Hash*, const void *pKey, int nKey); void HashClear(Hash*); /* ** Macros for looping over all elements of a hash table. The idiom is ** like this: ** ** Hash h; ** HashElem *p; ** ... ** for(p=HashFirst(&h); p; p=HashNext(p)){ ** SomeStructure *pData = HashData(p); ** // do something with pData ** } */ #define HashFirst(H) ((H)->first) #define HashNext(E) ((E)->next) #define HashData(E) ((E)->data) #define HashKey(E) ((E)->pKey) #define HashKeysize(E) ((E)->nKey) /* ** Number of entries in a hash table */ #define HashCount(H) ((H)->count) #endif /* _HASH_H_ */ |
Added ext/fts1/fts1.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 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 | /* fts1 has a design flaw which can lead to database corruption (see ** below). It is recommended not to use it any longer, instead use ** fts3 (or higher). If you believe that your use of fts1 is safe, ** add -DSQLITE_ENABLE_BROKEN_FTS1=1 to your CFLAGS. */ #if (!defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS1)) \ && !defined(SQLITE_ENABLE_BROKEN_FTS1) #error fts1 has a design flaw and has been deprecated. #endif /* The flaw is that fts1 uses the content table's unaliased rowid as ** the unique docid. fts1 embeds the rowid in the index it builds, ** and expects the rowid to not change. The SQLite VACUUM operation ** will renumber such rowids, thereby breaking fts1. If you are using ** fts1 in a system which has disabled VACUUM, then you can continue ** to use it safely. Note that PRAGMA auto_vacuum does NOT disable ** VACUUM, though systems using auto_vacuum are unlikely to invoke ** VACUUM. ** ** fts1 should be safe even across VACUUM if you only insert documents ** and never delete. */ /* The author disclaims copyright to this source code. * * This is an SQLite module implementing full-text search. */ /* ** The code in this file is only compiled if: ** ** * The FTS1 module is being built as an extension ** (in which case SQLITE_CORE is not defined), or ** ** * The FTS1 module is being built into the core of ** SQLite (in which case SQLITE_ENABLE_FTS1 is defined). */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS1) #if defined(SQLITE_ENABLE_FTS1) && !defined(SQLITE_CORE) # define SQLITE_CORE 1 #endif #include <assert.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <ctype.h> #include "fts1.h" #include "fts1_hash.h" #include "fts1_tokenizer.h" #include "sqlite3.h" #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #if 0 # define TRACE(A) printf A; fflush(stdout) #else # define TRACE(A) #endif /* utility functions */ typedef struct StringBuffer { int len; /* length, not including null terminator */ int alloced; /* Space allocated for s[] */ char *s; /* Content of the string */ } StringBuffer; static void initStringBuffer(StringBuffer *sb){ sb->len = 0; sb->alloced = 100; sb->s = malloc(100); sb->s[0] = '\0'; } static void nappend(StringBuffer *sb, const char *zFrom, int nFrom){ if( sb->len + nFrom >= sb->alloced ){ sb->alloced = sb->len + nFrom + 100; sb->s = realloc(sb->s, sb->alloced+1); if( sb->s==0 ){ initStringBuffer(sb); return; } } memcpy(sb->s + sb->len, zFrom, nFrom); sb->len += nFrom; sb->s[sb->len] = 0; } static void append(StringBuffer *sb, const char *zFrom){ nappend(sb, zFrom, strlen(zFrom)); } /* We encode variable-length integers in little-endian order using seven bits * per byte as follows: ** ** KEY: ** A = 0xxxxxxx 7 bits of data and one flag bit ** B = 1xxxxxxx 7 bits of data and one flag bit ** ** 7 bits - A ** 14 bits - BA ** 21 bits - BBA ** and so on. */ /* We may need up to VARINT_MAX bytes to store an encoded 64-bit integer. */ #define VARINT_MAX 10 /* Write a 64-bit variable-length integer to memory starting at p[0]. * The length of data written will be between 1 and VARINT_MAX bytes. * The number of bytes written is returned. */ static int putVarint(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 <= VARINT_MAX ); return (int) (q - (unsigned char *)p); } /* 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. */ static int getVarint(const char *p, sqlite_int64 *v){ const unsigned char *q = (const unsigned char *) p; sqlite_uint64 x = 0, y = 1; while( (*q & 0x80) == 0x80 ){ x += y * (*q++ & 0x7f); y <<= 7; if( q - (unsigned char *)p >= VARINT_MAX ){ /* bad data */ assert( 0 ); return 0; } } x += y * (*q++); *v = (sqlite_int64) x; return (int) (q - (unsigned char *)p); } static int getVarint32(const char *p, int *pi){ sqlite_int64 i; int ret = getVarint(p, &i); *pi = (int) i; assert( *pi==i ); return ret; } /*** Document lists *** * * A document list holds a sorted list of varint-encoded document IDs. * * A doclist with type DL_POSITIONS_OFFSETS is stored like this: * * array { * varint docid; * array { * varint position; (delta from previous position plus POS_BASE) * varint startOffset; (delta from previous startOffset) * varint endOffset; (delta from startOffset) * } * } * * Here, array { X } means zero or more occurrences of X, adjacent in memory. * * A position list may hold positions for text in multiple columns. A position * POS_COLUMN is followed by a varint containing the index of the column for * following positions in the list. Any positions appearing before any * occurrences of POS_COLUMN are for column 0. * * A doclist with type DL_POSITIONS is like the above, but holds only docids * and positions without offset information. * * A doclist with type DL_DOCIDS is like the above, but holds only docids * without positions or offset information. * * On disk, every document list has positions and offsets, so we don't bother * to serialize a doclist's type. * * We don't yet delta-encode document IDs; doing so will probably be a * modest win. * * NOTE(shess) I've thought of a slightly (1%) better offset encoding. * After the first offset, estimate the next offset by using the * current token position and the previous token position and offset, * offset to handle some variance. So the estimate would be * (iPosition*w->iStartOffset/w->iPosition-64), which is delta-encoded * as normal. Offsets more than 64 chars from the estimate are * encoded as the delta to the previous start offset + 128. An * additional tiny increment can be gained by using the end offset of * the previous token to make the estimate a tiny bit more precise. */ /* It is not safe to call isspace(), tolower(), or isalnum() on ** hi-bit-set characters. This is the same solution used in the ** tokenizer. */ /* TODO(shess) The snippet-generation code should be using the ** tokenizer-generated tokens rather than doing its own local ** tokenization. */ /* TODO(shess) Is __isascii() a portable version of (c&0x80)==0? */ static int safe_isspace(char c){ return (c&0x80)==0 ? isspace((unsigned char)c) : 0; } static int safe_tolower(char c){ return (c&0x80)==0 ? tolower((unsigned char)c) : c; } static int safe_isalnum(char c){ return (c&0x80)==0 ? isalnum((unsigned char)c) : 0; } typedef enum DocListType { DL_DOCIDS, /* docids only */ DL_POSITIONS, /* docids + positions */ DL_POSITIONS_OFFSETS /* docids + positions + offsets */ } DocListType; /* ** By default, only positions and not offsets are stored in the doclists. ** To change this so that offsets are stored too, compile with ** ** -DDL_DEFAULT=DL_POSITIONS_OFFSETS ** */ #ifndef DL_DEFAULT # define DL_DEFAULT DL_POSITIONS #endif typedef struct DocList { char *pData; int nData; DocListType iType; int iLastColumn; /* the last column written */ int iLastPos; /* the last position written */ int iLastOffset; /* the last start offset written */ } DocList; enum { POS_END = 0, /* end of this position list */ POS_COLUMN, /* followed by new column number */ POS_BASE }; /* Initialize a new DocList to hold the given data. */ static void docListInit(DocList *d, DocListType iType, const char *pData, int nData){ d->nData = nData; if( nData>0 ){ d->pData = malloc(nData); memcpy(d->pData, pData, nData); } else { d->pData = NULL; } d->iType = iType; d->iLastColumn = 0; d->iLastPos = d->iLastOffset = 0; } /* Create a new dynamically-allocated DocList. */ static DocList *docListNew(DocListType iType){ DocList *d = (DocList *) malloc(sizeof(DocList)); docListInit(d, iType, 0, 0); return d; } static void docListDestroy(DocList *d){ free(d->pData); #ifndef NDEBUG memset(d, 0x55, sizeof(*d)); #endif } static void docListDelete(DocList *d){ docListDestroy(d); free(d); } static char *docListEnd(DocList *d){ return d->pData + d->nData; } /* Append a varint to a DocList's data. */ static void appendVarint(DocList *d, sqlite_int64 i){ char c[VARINT_MAX]; int n = putVarint(c, i); d->pData = realloc(d->pData, d->nData + n); memcpy(d->pData + d->nData, c, n); d->nData += n; } static void docListAddDocid(DocList *d, sqlite_int64 iDocid){ appendVarint(d, iDocid); if( d->iType>=DL_POSITIONS ){ appendVarint(d, POS_END); /* initially empty position list */ d->iLastColumn = 0; d->iLastPos = d->iLastOffset = 0; } } /* helper function for docListAddPos and docListAddPosOffset */ static void addPos(DocList *d, int iColumn, int iPos){ assert( d->nData>0 ); --d->nData; /* remove previous terminator */ if( iColumn!=d->iLastColumn ){ assert( iColumn>d->iLastColumn ); appendVarint(d, POS_COLUMN); appendVarint(d, iColumn); d->iLastColumn = iColumn; d->iLastPos = d->iLastOffset = 0; } assert( iPos>=d->iLastPos ); appendVarint(d, iPos-d->iLastPos+POS_BASE); d->iLastPos = iPos; } /* Add a position to the last position list in a doclist. */ static void docListAddPos(DocList *d, int iColumn, int iPos){ assert( d->iType==DL_POSITIONS ); addPos(d, iColumn, iPos); appendVarint(d, POS_END); /* add new terminator */ } /* ** Add a position and starting and ending offsets to a doclist. ** ** If the doclist is setup to handle only positions, then insert ** the position only and ignore the offsets. */ static void docListAddPosOffset( DocList *d, /* Doclist under construction */ int iColumn, /* Column the inserted term is part of */ int iPos, /* Position of the inserted term */ int iStartOffset, /* Starting offset of inserted term */ int iEndOffset /* Ending offset of inserted term */ ){ assert( d->iType>=DL_POSITIONS ); addPos(d, iColumn, iPos); if( d->iType==DL_POSITIONS_OFFSETS ){ assert( iStartOffset>=d->iLastOffset ); appendVarint(d, iStartOffset-d->iLastOffset); d->iLastOffset = iStartOffset; assert( iEndOffset>=iStartOffset ); appendVarint(d, iEndOffset-iStartOffset); } appendVarint(d, POS_END); /* add new terminator */ } /* ** A DocListReader object is a cursor into a doclist. Initialize ** the cursor to the beginning of the doclist by calling readerInit(). ** Then use routines ** ** peekDocid() ** readDocid() ** readPosition() ** skipPositionList() ** and so forth... ** ** to read information out of the doclist. When we reach the end ** of the doclist, atEnd() returns TRUE. */ typedef struct DocListReader { DocList *pDoclist; /* The document list we are stepping through */ char *p; /* Pointer to next unread byte in the doclist */ int iLastColumn; int iLastPos; /* the last position read, or -1 when not in a position list */ } DocListReader; /* ** Initialize the DocListReader r to point to the beginning of pDoclist. */ static void readerInit(DocListReader *r, DocList *pDoclist){ r->pDoclist = pDoclist; if( pDoclist!=NULL ){ r->p = pDoclist->pData; } r->iLastColumn = -1; r->iLastPos = -1; } /* ** Return TRUE if we have reached then end of pReader and there is ** nothing else left to read. */ static int atEnd(DocListReader *pReader){ return pReader->pDoclist==0 || (pReader->p >= docListEnd(pReader->pDoclist)); } /* Peek at the next docid without advancing the read pointer. */ static sqlite_int64 peekDocid(DocListReader *pReader){ sqlite_int64 ret; assert( !atEnd(pReader) ); assert( pReader->iLastPos==-1 ); getVarint(pReader->p, &ret); return ret; } /* Read the next docid. See also nextDocid(). */ static sqlite_int64 readDocid(DocListReader *pReader){ sqlite_int64 ret; assert( !atEnd(pReader) ); assert( pReader->iLastPos==-1 ); pReader->p += getVarint(pReader->p, &ret); if( pReader->pDoclist->iType>=DL_POSITIONS ){ pReader->iLastColumn = 0; pReader->iLastPos = 0; } return ret; } /* Read the next position and column index from a position list. * Returns the position, or -1 at the end of the list. */ static int readPosition(DocListReader *pReader, int *iColumn){ int i; int iType = pReader->pDoclist->iType; if( pReader->iLastPos==-1 ){ return -1; } assert( !atEnd(pReader) ); if( iType<DL_POSITIONS ){ return -1; } pReader->p += getVarint32(pReader->p, &i); if( i==POS_END ){ pReader->iLastColumn = pReader->iLastPos = -1; *iColumn = -1; return -1; } if( i==POS_COLUMN ){ pReader->p += getVarint32(pReader->p, &pReader->iLastColumn); pReader->iLastPos = 0; pReader->p += getVarint32(pReader->p, &i); assert( i>=POS_BASE ); } pReader->iLastPos += ((int) i)-POS_BASE; if( iType>=DL_POSITIONS_OFFSETS ){ /* Skip over offsets, ignoring them for now. */ int iStart, iEnd; pReader->p += getVarint32(pReader->p, &iStart); pReader->p += getVarint32(pReader->p, &iEnd); } *iColumn = pReader->iLastColumn; return pReader->iLastPos; } /* Skip past the end of a position list. */ static void skipPositionList(DocListReader *pReader){ DocList *p = pReader->pDoclist; if( p && p->iType>=DL_POSITIONS ){ int iColumn; while( readPosition(pReader, &iColumn)!=-1 ){} } } /* Skip over a docid, including its position list if the doclist has * positions. */ static void skipDocument(DocListReader *pReader){ readDocid(pReader); skipPositionList(pReader); } /* Skip past all docids which are less than [iDocid]. Returns 1 if a docid * matching [iDocid] was found. */ static int skipToDocid(DocListReader *pReader, sqlite_int64 iDocid){ sqlite_int64 d = 0; while( !atEnd(pReader) && (d=peekDocid(pReader))<iDocid ){ skipDocument(pReader); } return !atEnd(pReader) && d==iDocid; } /* Return the first document in a document list. */ static sqlite_int64 firstDocid(DocList *d){ DocListReader r; readerInit(&r, d); return readDocid(&r); } #ifdef SQLITE_DEBUG /* ** This routine is used for debugging purpose only. ** ** Write the content of a doclist to standard output. */ static void printDoclist(DocList *p){ DocListReader r; const char *zSep = ""; readerInit(&r, p); while( !atEnd(&r) ){ sqlite_int64 docid = readDocid(&r); if( docid==0 ){ skipPositionList(&r); continue; } printf("%s%lld", zSep, docid); zSep = ","; if( p->iType>=DL_POSITIONS ){ int iPos, iCol; const char *zDiv = ""; printf("("); while( (iPos = readPosition(&r, &iCol))>=0 ){ printf("%s%d:%d", zDiv, iCol, iPos); zDiv = ":"; } printf(")"); } } printf("\n"); fflush(stdout); } #endif /* SQLITE_DEBUG */ /* Trim the given doclist to contain only positions in column * [iRestrictColumn]. */ static void docListRestrictColumn(DocList *in, int iRestrictColumn){ DocListReader r; DocList out; assert( in->iType>=DL_POSITIONS ); readerInit(&r, in); docListInit(&out, DL_POSITIONS, NULL, 0); while( !atEnd(&r) ){ sqlite_int64 iDocid = readDocid(&r); int iPos, iColumn; docListAddDocid(&out, iDocid); while( (iPos = readPosition(&r, &iColumn)) != -1 ){ if( iColumn==iRestrictColumn ){ docListAddPos(&out, iColumn, iPos); } } } docListDestroy(in); *in = out; } /* Trim the given doclist by discarding any docids without any remaining * positions. */ static void docListDiscardEmpty(DocList *in) { DocListReader r; DocList out; /* TODO: It would be nice to implement this operation in place; that * could save a significant amount of memory in queries with long doclists. */ assert( in->iType>=DL_POSITIONS ); readerInit(&r, in); docListInit(&out, DL_POSITIONS, NULL, 0); while( !atEnd(&r) ){ sqlite_int64 iDocid = readDocid(&r); int match = 0; int iPos, iColumn; while( (iPos = readPosition(&r, &iColumn)) != -1 ){ if( !match ){ docListAddDocid(&out, iDocid); match = 1; } docListAddPos(&out, iColumn, iPos); } } docListDestroy(in); *in = out; } /* Helper function for docListUpdate() and docListAccumulate(). ** Splices a doclist element into the doclist represented by r, ** leaving r pointing after the newly spliced element. */ static void docListSpliceElement(DocListReader *r, sqlite_int64 iDocid, const char *pSource, int nSource){ DocList *d = r->pDoclist; char *pTarget; int nTarget, found; found = skipToDocid(r, iDocid); /* Describe slice in d to place pSource/nSource. */ pTarget = r->p; if( found ){ skipDocument(r); nTarget = r->p-pTarget; }else{ nTarget = 0; } /* The sense of the following is that there are three possibilities. ** If nTarget==nSource, we should not move any memory nor realloc. ** If nTarget>nSource, trim target and realloc. ** If nTarget<nSource, realloc then expand target. */ if( nTarget>nSource ){ memmove(pTarget+nSource, pTarget+nTarget, docListEnd(d)-(pTarget+nTarget)); } if( nTarget!=nSource ){ int iDoclist = pTarget-d->pData; d->pData = realloc(d->pData, d->nData+nSource-nTarget); pTarget = d->pData+iDoclist; } if( nTarget<nSource ){ memmove(pTarget+nSource, pTarget+nTarget, docListEnd(d)-(pTarget+nTarget)); } memcpy(pTarget, pSource, nSource); d->nData += nSource-nTarget; r->p = pTarget+nSource; } /* Insert/update pUpdate into the doclist. */ static void docListUpdate(DocList *d, DocList *pUpdate){ DocListReader reader; assert( d!=NULL && pUpdate!=NULL ); assert( d->iType==pUpdate->iType); readerInit(&reader, d); docListSpliceElement(&reader, firstDocid(pUpdate), pUpdate->pData, pUpdate->nData); } /* Propagate elements from pUpdate to pAcc, overwriting elements with ** matching docids. */ static void docListAccumulate(DocList *pAcc, DocList *pUpdate){ DocListReader accReader, updateReader; /* Handle edge cases where one doclist is empty. */ assert( pAcc!=NULL ); if( pUpdate==NULL || pUpdate->nData==0 ) return; if( pAcc->nData==0 ){ pAcc->pData = malloc(pUpdate->nData); memcpy(pAcc->pData, pUpdate->pData, pUpdate->nData); pAcc->nData = pUpdate->nData; return; } readerInit(&accReader, pAcc); readerInit(&updateReader, pUpdate); while( !atEnd(&updateReader) ){ char *pSource = updateReader.p; sqlite_int64 iDocid = readDocid(&updateReader); skipPositionList(&updateReader); docListSpliceElement(&accReader, iDocid, pSource, updateReader.p-pSource); } } /* ** Read the next docid off of pIn. Return 0 if we reach the end. * * TODO: This assumes that docids are never 0, but they may actually be 0 since * users can choose docids when inserting into a full-text table. Fix this. */ static sqlite_int64 nextDocid(DocListReader *pIn){ skipPositionList(pIn); return atEnd(pIn) ? 0 : readDocid(pIn); } /* ** pLeft and pRight are two DocListReaders that are pointing to ** positions lists of the same document: iDocid. ** ** If there are no instances in pLeft or pRight where the position ** of pLeft is one less than the position of pRight, then this ** routine adds nothing to pOut. ** ** If there are one or more instances where positions from pLeft ** are exactly one less than positions from pRight, then add a new ** document record to pOut. If pOut wants to hold positions, then ** include the positions from pRight that are one more than a ** position in pLeft. In other words: pRight.iPos==pLeft.iPos+1. ** ** pLeft and pRight are left pointing at the next document record. */ static void mergePosList( DocListReader *pLeft, /* Left position list */ DocListReader *pRight, /* Right position list */ sqlite_int64 iDocid, /* The docid from pLeft and pRight */ DocList *pOut /* Write the merged document record here */ ){ int iLeftCol, iLeftPos = readPosition(pLeft, &iLeftCol); int iRightCol, iRightPos = readPosition(pRight, &iRightCol); int match = 0; /* Loop until we've reached the end of both position lists. */ while( iLeftPos!=-1 && iRightPos!=-1 ){ if( iLeftCol==iRightCol && iLeftPos+1==iRightPos ){ if( !match ){ docListAddDocid(pOut, iDocid); match = 1; } if( pOut->iType>=DL_POSITIONS ){ docListAddPos(pOut, iRightCol, iRightPos); } iLeftPos = readPosition(pLeft, &iLeftCol); iRightPos = readPosition(pRight, &iRightCol); }else if( iRightCol<iLeftCol || (iRightCol==iLeftCol && iRightPos<iLeftPos+1) ){ iRightPos = readPosition(pRight, &iRightCol); }else{ iLeftPos = readPosition(pLeft, &iLeftCol); } } if( iLeftPos>=0 ) skipPositionList(pLeft); if( iRightPos>=0 ) skipPositionList(pRight); } /* We have two doclists: pLeft and pRight. ** Write the phrase intersection of these two doclists into pOut. ** ** A phrase intersection means that two documents only match ** if pLeft.iPos+1==pRight.iPos. ** ** The output pOut may or may not contain positions. If pOut ** does contain positions, they are the positions of pRight. */ static void docListPhraseMerge( DocList *pLeft, /* Doclist resulting from the words on the left */ DocList *pRight, /* Doclist for the next word to the right */ DocList *pOut /* Write the combined doclist here */ ){ DocListReader left, right; sqlite_int64 docidLeft, docidRight; readerInit(&left, pLeft); readerInit(&right, pRight); docidLeft = nextDocid(&left); docidRight = nextDocid(&right); while( docidLeft>0 && docidRight>0 ){ if( docidLeft<docidRight ){ docidLeft = nextDocid(&left); }else if( docidRight<docidLeft ){ docidRight = nextDocid(&right); }else{ mergePosList(&left, &right, docidLeft, pOut); docidLeft = nextDocid(&left); docidRight = nextDocid(&right); } } } /* We have two doclists: pLeft and pRight. ** Write the intersection of these two doclists into pOut. ** Only docids are matched. Position information is ignored. ** ** The output pOut never holds positions. */ static void docListAndMerge( DocList *pLeft, /* Doclist resulting from the words on the left */ DocList *pRight, /* Doclist for the next word to the right */ DocList *pOut /* Write the combined doclist here */ ){ DocListReader left, right; sqlite_int64 docidLeft, docidRight; assert( pOut->iType<DL_POSITIONS ); readerInit(&left, pLeft); readerInit(&right, pRight); docidLeft = nextDocid(&left); docidRight = nextDocid(&right); while( docidLeft>0 && docidRight>0 ){ if( docidLeft<docidRight ){ docidLeft = nextDocid(&left); }else if( docidRight<docidLeft ){ docidRight = nextDocid(&right); }else{ docListAddDocid(pOut, docidLeft); docidLeft = nextDocid(&left); docidRight = nextDocid(&right); } } } /* We have two doclists: pLeft and pRight. ** Write the union of these two doclists into pOut. ** Only docids are matched. Position information is ignored. ** ** The output pOut never holds positions. */ static void docListOrMerge( DocList *pLeft, /* Doclist resulting from the words on the left */ DocList *pRight, /* Doclist for the next word to the right */ DocList *pOut /* Write the combined doclist here */ ){ DocListReader left, right; sqlite_int64 docidLeft, docidRight, priorLeft; readerInit(&left, pLeft); readerInit(&right, pRight); docidLeft = nextDocid(&left); docidRight = nextDocid(&right); while( docidLeft>0 && docidRight>0 ){ if( docidLeft<=docidRight ){ docListAddDocid(pOut, docidLeft); }else{ docListAddDocid(pOut, docidRight); } priorLeft = docidLeft; if( docidLeft<=docidRight ){ docidLeft = nextDocid(&left); } if( docidRight>0 && docidRight<=priorLeft ){ docidRight = nextDocid(&right); } } while( docidLeft>0 ){ docListAddDocid(pOut, docidLeft); docidLeft = nextDocid(&left); } while( docidRight>0 ){ docListAddDocid(pOut, docidRight); docidRight = nextDocid(&right); } } /* We have two doclists: pLeft and pRight. ** Write into pOut all documents that occur in pLeft but not ** in pRight. ** ** Only docids are matched. Position information is ignored. ** ** The output pOut never holds positions. */ static void docListExceptMerge( DocList *pLeft, /* Doclist resulting from the words on the left */ DocList *pRight, /* Doclist for the next word to the right */ DocList *pOut /* Write the combined doclist here */ ){ DocListReader left, right; sqlite_int64 docidLeft, docidRight, priorLeft; readerInit(&left, pLeft); readerInit(&right, pRight); docidLeft = nextDocid(&left); docidRight = nextDocid(&right); while( docidLeft>0 && docidRight>0 ){ priorLeft = docidLeft; if( docidLeft<docidRight ){ docListAddDocid(pOut, docidLeft); } if( docidLeft<=docidRight ){ docidLeft = nextDocid(&left); } if( docidRight>0 && docidRight<=priorLeft ){ docidRight = nextDocid(&right); } } while( docidLeft>0 ){ docListAddDocid(pOut, docidLeft); docidLeft = nextDocid(&left); } } static char *string_dup_n(const char *s, int n){ char *str = malloc(n + 1); memcpy(str, s, n); str[n] = '\0'; return str; } /* Duplicate a string; the caller must free() the returned string. * (We don't use strdup() since it is not part of the standard C library and * may not be available everywhere.) */ static char *string_dup(const char *s){ return string_dup_n(s, strlen(s)); } /* Format a string, replacing each occurrence of the % character with * zDb.zName. This may be more convenient than sqlite_mprintf() * when one string is used repeatedly in a format string. * The caller must free() the returned string. */ static char *string_format(const char *zFormat, const char *zDb, const char *zName){ const char *p; size_t len = 0; size_t nDb = strlen(zDb); size_t nName = strlen(zName); size_t nFullTableName = nDb+1+nName; char *result; char *r; /* first compute length needed */ for(p = zFormat ; *p ; ++p){ len += (*p=='%' ? nFullTableName : 1); } len += 1; /* for null terminator */ r = result = malloc(len); for(p = zFormat; *p; ++p){ if( *p=='%' ){ memcpy(r, zDb, nDb); r += nDb; *r++ = '.'; memcpy(r, zName, nName); r += nName; } else { *r++ = *p; } } *r++ = '\0'; assert( r == result + len ); return result; } static int sql_exec(sqlite3 *db, const char *zDb, const char *zName, const char *zFormat){ char *zCommand = string_format(zFormat, zDb, zName); int rc; TRACE(("FTS1 sql: %s\n", zCommand)); rc = sqlite3_exec(db, zCommand, NULL, 0, NULL); free(zCommand); return rc; } static int sql_prepare(sqlite3 *db, const char *zDb, const char *zName, sqlite3_stmt **ppStmt, const char *zFormat){ char *zCommand = string_format(zFormat, zDb, zName); int rc; TRACE(("FTS1 prepare: %s\n", zCommand)); rc = sqlite3_prepare(db, zCommand, -1, ppStmt, NULL); free(zCommand); return rc; } /* end utility functions */ /* Forward reference */ typedef struct fulltext_vtab fulltext_vtab; /* A single term in a query is represented by an instances of ** the following structure. */ typedef struct QueryTerm { short int nPhrase; /* How many following terms are part of the same phrase */ short int iPhrase; /* This is the i-th term of a phrase. */ short int iColumn; /* Column of the index that must match this term */ signed char isOr; /* this term is preceded by "OR" */ signed char isNot; /* this term is preceded by "-" */ char *pTerm; /* text of the term. '\000' terminated. malloced */ int nTerm; /* Number of bytes in pTerm[] */ } QueryTerm; /* A query string is parsed into a Query structure. * * We could, in theory, allow query strings to be complicated * nested expressions with precedence determined by parentheses. * But none of the major search engines do this. (Perhaps the * feeling is that an parenthesized expression is two complex of * an idea for the average user to grasp.) Taking our lead from * the major search engines, we will allow queries to be a list * of terms (with an implied AND operator) or phrases in double-quotes, * with a single optional "-" before each non-phrase term to designate * negation and an optional OR connector. * * OR binds more tightly than the implied AND, which is what the * major search engines seem to do. So, for example: * * [one two OR three] ==> one AND (two OR three) * [one OR two three] ==> (one OR two) AND three * * A "-" before a term matches all entries that lack that term. * The "-" must occur immediately before the term with in intervening * space. This is how the search engines do it. * * A NOT term cannot be the right-hand operand of an OR. If this * occurs in the query string, the NOT is ignored: * * [one OR -two] ==> one OR two * */ typedef struct Query { fulltext_vtab *pFts; /* The full text index */ int nTerms; /* Number of terms in the query */ QueryTerm *pTerms; /* Array of terms. Space obtained from malloc() */ int nextIsOr; /* Set the isOr flag on the next inserted term */ int nextColumn; /* Next word parsed must be in this column */ int dfltColumn; /* The default column */ } Query; /* ** An instance of the following structure keeps track of generated ** matching-word offset information and snippets. */ typedef struct Snippet { int nMatch; /* Total number of matches */ int nAlloc; /* Space allocated for aMatch[] */ struct snippetMatch { /* One entry for each matching term */ char snStatus; /* Status flag for use while constructing snippets */ short int iCol; /* The column that contains the match */ short int iTerm; /* The index in Query.pTerms[] of the matching term */ short int nByte; /* Number of bytes in the term */ int iStart; /* The offset to the first character of the term */ } *aMatch; /* Points to space obtained from malloc */ char *zOffset; /* Text rendering of aMatch[] */ int nOffset; /* strlen(zOffset) */ char *zSnippet; /* Snippet text */ int nSnippet; /* strlen(zSnippet) */ } Snippet; typedef enum QueryType { QUERY_GENERIC, /* table scan */ QUERY_ROWID, /* lookup by rowid */ QUERY_FULLTEXT /* QUERY_FULLTEXT + [i] is a full-text search for column i*/ } QueryType; /* TODO(shess) CHUNK_MAX controls how much data we allow in segment 0 ** before we start aggregating into larger segments. Lower CHUNK_MAX ** means that for a given input we have more individual segments per ** term, which means more rows in the table and a bigger index (due to ** both more rows and bigger rowids). But it also reduces the average ** cost of adding new elements to the segment 0 doclist, and it seems ** to reduce the number of pages read and written during inserts. 256 ** was chosen by measuring insertion times for a certain input (first ** 10k documents of Enron corpus), though including query performance ** in the decision may argue for a larger value. */ #define CHUNK_MAX 256 typedef enum fulltext_statement { CONTENT_INSERT_STMT, CONTENT_SELECT_STMT, CONTENT_UPDATE_STMT, CONTENT_DELETE_STMT, TERM_SELECT_STMT, TERM_SELECT_ALL_STMT, TERM_INSERT_STMT, TERM_UPDATE_STMT, TERM_DELETE_STMT, MAX_STMT /* Always at end! */ } fulltext_statement; /* These must exactly match the enum above. */ /* TODO(adam): Is there some risk that a statement (in particular, ** pTermSelectStmt) will be used in two cursors at once, e.g. if a ** query joins a virtual table to itself? If so perhaps we should ** move some of these to the cursor object. */ static const char *const fulltext_zStatement[MAX_STMT] = { /* CONTENT_INSERT */ NULL, /* generated in contentInsertStatement() */ /* CONTENT_SELECT */ "select * from %_content where rowid = ?", /* CONTENT_UPDATE */ NULL, /* generated in contentUpdateStatement() */ /* CONTENT_DELETE */ "delete from %_content where rowid = ?", /* TERM_SELECT */ "select rowid, doclist from %_term where term = ? and segment = ?", /* TERM_SELECT_ALL */ "select doclist from %_term where term = ? order by segment", /* TERM_INSERT */ "insert into %_term (rowid, term, segment, doclist) values (?, ?, ?, ?)", /* TERM_UPDATE */ "update %_term set doclist = ? where rowid = ?", /* TERM_DELETE */ "delete from %_term where rowid = ?", }; /* ** A connection to a fulltext index is an instance of the following ** structure. The xCreate and xConnect methods create an instance ** of this structure and xDestroy and xDisconnect free that instance. ** All other methods receive a pointer to the structure as one of their ** arguments. */ struct fulltext_vtab { sqlite3_vtab base; /* Base class used by SQLite core */ sqlite3 *db; /* The database connection */ const char *zDb; /* logical database name */ const char *zName; /* virtual table name */ int nColumn; /* number of columns in virtual table */ char **azColumn; /* column names. malloced */ char **azContentColumn; /* column names in content table; malloced */ sqlite3_tokenizer *pTokenizer; /* tokenizer for inserts and queries */ /* Precompiled statements which we keep as long as the table is ** open. */ sqlite3_stmt *pFulltextStatements[MAX_STMT]; }; /* ** When the core wants to do a query, it create a cursor using a ** call to xOpen. This structure is an instance of a cursor. It ** is destroyed by xClose. */ typedef struct fulltext_cursor { sqlite3_vtab_cursor base; /* Base class used by SQLite core */ QueryType iCursorType; /* Copy of sqlite3_index_info.idxNum */ sqlite3_stmt *pStmt; /* Prepared statement in use by the cursor */ int eof; /* True if at End Of Results */ Query q; /* Parsed query string */ Snippet snippet; /* Cached snippet for the current row */ int iColumn; /* Column being searched */ DocListReader result; /* used when iCursorType == QUERY_FULLTEXT */ } fulltext_cursor; static struct fulltext_vtab *cursor_vtab(fulltext_cursor *c){ return (fulltext_vtab *) c->base.pVtab; } static const sqlite3_module fulltextModule; /* forward declaration */ /* Append a list of strings separated by commas to a StringBuffer. */ static void appendList(StringBuffer *sb, int nString, char **azString){ int i; for(i=0; i<nString; ++i){ if( i>0 ) append(sb, ", "); append(sb, azString[i]); } } /* Return a dynamically generated statement of the form * insert into %_content (rowid, ...) values (?, ...) */ static const char *contentInsertStatement(fulltext_vtab *v){ StringBuffer sb; int i; initStringBuffer(&sb); append(&sb, "insert into %_content (rowid, "); appendList(&sb, v->nColumn, v->azContentColumn); append(&sb, ") values (?"); for(i=0; i<v->nColumn; ++i) append(&sb, ", ?"); append(&sb, ")"); return sb.s; } /* Return a dynamically generated statement of the form * update %_content set [col_0] = ?, [col_1] = ?, ... * where rowid = ? */ static const char *contentUpdateStatement(fulltext_vtab *v){ StringBuffer sb; int i; initStringBuffer(&sb); append(&sb, "update %_content set "); for(i=0; i<v->nColumn; ++i) { if( i>0 ){ append(&sb, ", "); } append(&sb, v->azContentColumn[i]); append(&sb, " = ?"); } append(&sb, " where rowid = ?"); return sb.s; } /* Puts a freshly-prepared statement determined by iStmt in *ppStmt. ** If the indicated statement has never been prepared, it is prepared ** and cached, otherwise the cached version is reset. */ static int sql_get_statement(fulltext_vtab *v, fulltext_statement iStmt, sqlite3_stmt **ppStmt){ assert( iStmt<MAX_STMT ); if( v->pFulltextStatements[iStmt]==NULL ){ const char *zStmt; int rc; switch( iStmt ){ case CONTENT_INSERT_STMT: zStmt = contentInsertStatement(v); break; case CONTENT_UPDATE_STMT: zStmt = contentUpdateStatement(v); break; default: zStmt = fulltext_zStatement[iStmt]; } rc = sql_prepare(v->db, v->zDb, v->zName, &v->pFulltextStatements[iStmt], zStmt); if( zStmt != fulltext_zStatement[iStmt]) free((void *) zStmt); if( rc!=SQLITE_OK ) return rc; } else { int rc = sqlite3_reset(v->pFulltextStatements[iStmt]); if( rc!=SQLITE_OK ) return rc; } *ppStmt = v->pFulltextStatements[iStmt]; return SQLITE_OK; } /* Step the indicated statement, handling errors SQLITE_BUSY (by ** retrying) and SQLITE_SCHEMA (by re-preparing and transferring ** bindings to the new statement). ** TODO(adam): We should extend this function so that it can work with ** statements declared locally, not only globally cached statements. */ static int sql_step_statement(fulltext_vtab *v, fulltext_statement iStmt, sqlite3_stmt **ppStmt){ int rc; sqlite3_stmt *s = *ppStmt; assert( iStmt<MAX_STMT ); assert( s==v->pFulltextStatements[iStmt] ); while( (rc=sqlite3_step(s))!=SQLITE_DONE && rc!=SQLITE_ROW ){ if( rc==SQLITE_BUSY ) continue; if( rc!=SQLITE_ERROR ) return rc; /* If an SQLITE_SCHEMA error has occurred, then finalizing this * statement is going to delete the fulltext_vtab structure. If * the statement just executed is in the pFulltextStatements[] * array, it will be finalized twice. So remove it before * calling sqlite3_finalize(). */ v->pFulltextStatements[iStmt] = NULL; rc = sqlite3_finalize(s); break; } return rc; err: sqlite3_finalize(s); return rc; } /* Like sql_step_statement(), but convert SQLITE_DONE to SQLITE_OK. ** Useful for statements like UPDATE, where we expect no results. */ static int sql_single_step_statement(fulltext_vtab *v, fulltext_statement iStmt, sqlite3_stmt **ppStmt){ int rc = sql_step_statement(v, iStmt, ppStmt); return (rc==SQLITE_DONE) ? SQLITE_OK : rc; } /* insert into %_content (rowid, ...) values ([rowid], [pValues]) */ static int content_insert(fulltext_vtab *v, sqlite3_value *rowid, sqlite3_value **pValues){ sqlite3_stmt *s; int i; int rc = sql_get_statement(v, CONTENT_INSERT_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_value(s, 1, rowid); if( rc!=SQLITE_OK ) return rc; for(i=0; i<v->nColumn; ++i){ rc = sqlite3_bind_value(s, 2+i, pValues[i]); if( rc!=SQLITE_OK ) return rc; } return sql_single_step_statement(v, CONTENT_INSERT_STMT, &s); } /* update %_content set col0 = pValues[0], col1 = pValues[1], ... * where rowid = [iRowid] */ static int content_update(fulltext_vtab *v, sqlite3_value **pValues, sqlite_int64 iRowid){ sqlite3_stmt *s; int i; int rc = sql_get_statement(v, CONTENT_UPDATE_STMT, &s); if( rc!=SQLITE_OK ) return rc; for(i=0; i<v->nColumn; ++i){ rc = sqlite3_bind_value(s, 1+i, pValues[i]); if( rc!=SQLITE_OK ) return rc; } rc = sqlite3_bind_int64(s, 1+v->nColumn, iRowid); if( rc!=SQLITE_OK ) return rc; return sql_single_step_statement(v, CONTENT_UPDATE_STMT, &s); } static void freeStringArray(int nString, const char **pString){ int i; for (i=0 ; i < nString ; ++i) { if( pString[i]!=NULL ) free((void *) pString[i]); } free((void *) pString); } /* select * from %_content where rowid = [iRow] * The caller must delete the returned array and all strings in it. * null fields will be NULL in the returned array. * * TODO: Perhaps we should return pointer/length strings here for consistency * with other code which uses pointer/length. */ static int content_select(fulltext_vtab *v, sqlite_int64 iRow, const char ***pValues){ sqlite3_stmt *s; const char **values; int i; int rc; *pValues = NULL; rc = sql_get_statement(v, CONTENT_SELECT_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int64(s, 1, iRow); if( rc!=SQLITE_OK ) return rc; rc = sql_step_statement(v, CONTENT_SELECT_STMT, &s); if( rc!=SQLITE_ROW ) return rc; values = (const char **) malloc(v->nColumn * sizeof(const char *)); for(i=0; i<v->nColumn; ++i){ if( sqlite3_column_type(s, i)==SQLITE_NULL ){ values[i] = NULL; }else{ values[i] = string_dup((char*)sqlite3_column_text(s, i)); } } /* We expect only one row. We must execute another sqlite3_step() * to complete the iteration; otherwise the table will remain locked. */ rc = sqlite3_step(s); if( rc==SQLITE_DONE ){ *pValues = values; return SQLITE_OK; } freeStringArray(v->nColumn, values); return rc; } /* delete from %_content where rowid = [iRow ] */ static int content_delete(fulltext_vtab *v, sqlite_int64 iRow){ sqlite3_stmt *s; int rc = sql_get_statement(v, CONTENT_DELETE_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int64(s, 1, iRow); if( rc!=SQLITE_OK ) return rc; return sql_single_step_statement(v, CONTENT_DELETE_STMT, &s); } /* select rowid, doclist from %_term * where term = [pTerm] and segment = [iSegment] * If found, returns SQLITE_ROW; the caller must free the * returned doclist. If no rows found, returns SQLITE_DONE. */ static int term_select(fulltext_vtab *v, const char *pTerm, int nTerm, int iSegment, sqlite_int64 *rowid, DocList *out){ sqlite3_stmt *s; int rc = sql_get_statement(v, TERM_SELECT_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_text(s, 1, pTerm, nTerm, SQLITE_STATIC); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int(s, 2, iSegment); if( rc!=SQLITE_OK ) return rc; rc = sql_step_statement(v, TERM_SELECT_STMT, &s); if( rc!=SQLITE_ROW ) return rc; *rowid = sqlite3_column_int64(s, 0); docListInit(out, DL_DEFAULT, sqlite3_column_blob(s, 1), sqlite3_column_bytes(s, 1)); /* We expect only one row. We must execute another sqlite3_step() * to complete the iteration; otherwise the table will remain locked. */ rc = sqlite3_step(s); return rc==SQLITE_DONE ? SQLITE_ROW : rc; } /* Load the segment doclists for term pTerm and merge them in ** appropriate order into out. Returns SQLITE_OK if successful. If ** there are no segments for pTerm, successfully returns an empty ** doclist in out. ** ** Each document consists of 1 or more "columns". The number of ** columns is v->nColumn. If iColumn==v->nColumn, then return ** position information about all columns. If iColumn<v->nColumn, ** then only return position information about the iColumn-th column ** (where the first column is 0). */ static int term_select_all( fulltext_vtab *v, /* The fulltext index we are querying against */ int iColumn, /* If <nColumn, only look at the iColumn-th column */ const char *pTerm, /* The term whose posting lists we want */ int nTerm, /* Number of bytes in pTerm */ DocList *out /* Write the resulting doclist here */ ){ DocList doclist; sqlite3_stmt *s; int rc = sql_get_statement(v, TERM_SELECT_ALL_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_text(s, 1, pTerm, nTerm, SQLITE_STATIC); if( rc!=SQLITE_OK ) return rc; docListInit(&doclist, DL_DEFAULT, 0, 0); /* TODO(shess) Handle schema and busy errors. */ while( (rc=sql_step_statement(v, TERM_SELECT_ALL_STMT, &s))==SQLITE_ROW ){ DocList old; /* TODO(shess) If we processed doclists from oldest to newest, we ** could skip the malloc() involved with the following call. For ** now, I'd rather keep this logic similar to index_insert_term(). ** We could additionally drop elements when we see deletes, but ** that would require a distinct version of docListAccumulate(). */ docListInit(&old, DL_DEFAULT, sqlite3_column_blob(s, 0), sqlite3_column_bytes(s, 0)); if( iColumn<v->nColumn ){ /* querying a single column */ docListRestrictColumn(&old, iColumn); } /* doclist contains the newer data, so write it over old. Then ** steal accumulated result for doclist. */ docListAccumulate(&old, &doclist); docListDestroy(&doclist); doclist = old; } if( rc!=SQLITE_DONE ){ docListDestroy(&doclist); return rc; } docListDiscardEmpty(&doclist); *out = doclist; return SQLITE_OK; } /* insert into %_term (rowid, term, segment, doclist) values ([piRowid], [pTerm], [iSegment], [doclist]) ** Lets sqlite select rowid if piRowid is NULL, else uses *piRowid. ** ** NOTE(shess) piRowid is IN, with values of "space of int64" plus ** null, it is not used to pass data back to the caller. */ static int term_insert(fulltext_vtab *v, sqlite_int64 *piRowid, const char *pTerm, int nTerm, int iSegment, DocList *doclist){ sqlite3_stmt *s; int rc = sql_get_statement(v, TERM_INSERT_STMT, &s); if( rc!=SQLITE_OK ) return rc; if( piRowid==NULL ){ rc = sqlite3_bind_null(s, 1); }else{ rc = sqlite3_bind_int64(s, 1, *piRowid); } if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_text(s, 2, pTerm, nTerm, SQLITE_STATIC); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int(s, 3, iSegment); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_blob(s, 4, doclist->pData, doclist->nData, SQLITE_STATIC); if( rc!=SQLITE_OK ) return rc; return sql_single_step_statement(v, TERM_INSERT_STMT, &s); } /* update %_term set doclist = [doclist] where rowid = [rowid] */ static int term_update(fulltext_vtab *v, sqlite_int64 rowid, DocList *doclist){ sqlite3_stmt *s; int rc = sql_get_statement(v, TERM_UPDATE_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_blob(s, 1, doclist->pData, doclist->nData, SQLITE_STATIC); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int64(s, 2, rowid); if( rc!=SQLITE_OK ) return rc; return sql_single_step_statement(v, TERM_UPDATE_STMT, &s); } static int term_delete(fulltext_vtab *v, sqlite_int64 rowid){ sqlite3_stmt *s; int rc = sql_get_statement(v, TERM_DELETE_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int64(s, 1, rowid); if( rc!=SQLITE_OK ) return rc; return sql_single_step_statement(v, TERM_DELETE_STMT, &s); } /* ** Free the memory used to contain a fulltext_vtab structure. */ static void fulltext_vtab_destroy(fulltext_vtab *v){ int iStmt, i; TRACE(("FTS1 Destroy %p\n", v)); for( iStmt=0; iStmt<MAX_STMT; iStmt++ ){ if( v->pFulltextStatements[iStmt]!=NULL ){ sqlite3_finalize(v->pFulltextStatements[iStmt]); v->pFulltextStatements[iStmt] = NULL; } } if( v->pTokenizer!=NULL ){ v->pTokenizer->pModule->xDestroy(v->pTokenizer); v->pTokenizer = NULL; } free(v->azColumn); for(i = 0; i < v->nColumn; ++i) { sqlite3_free(v->azContentColumn[i]); } free(v->azContentColumn); free(v); } /* ** Token types for parsing the arguments to xConnect or xCreate. */ #define TOKEN_EOF 0 /* End of file */ #define TOKEN_SPACE 1 /* Any kind of whitespace */ #define TOKEN_ID 2 /* An identifier */ #define TOKEN_STRING 3 /* A string literal */ #define TOKEN_PUNCT 4 /* A single punctuation character */ /* ** If X is a character that can be used in an identifier then ** IdChar(X) will be true. Otherwise it is false. ** ** For ASCII, any character with the high-order bit set is ** allowed in an identifier. For 7-bit characters, ** sqlite3IsIdChar[X] must be 1. ** ** Ticket #1066. the SQL standard does not allow '$' in the ** middle of identfiers. But many SQL implementations do. ** SQLite will allow '$' in identifiers for compatibility. ** But the feature is undocumented. */ static const char isIdChar[] = { /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */ }; #define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && isIdChar[c-0x20])) /* ** Return the length of the token that begins at z[0]. ** Store the token type in *tokenType before returning. */ static int getToken(const char *z, int *tokenType){ int i, c; switch( *z ){ case 0: { *tokenType = TOKEN_EOF; return 0; } case ' ': case '\t': case '\n': case '\f': case '\r': { for(i=1; safe_isspace(z[i]); i++){} *tokenType = TOKEN_SPACE; return i; } case '`': case '\'': case '"': { int delim = z[0]; for(i=1; (c=z[i])!=0; i++){ if( c==delim ){ if( z[i+1]==delim ){ i++; }else{ break; } } } *tokenType = TOKEN_STRING; return i + (c!=0); } case '[': { for(i=1, c=z[0]; c!=']' && (c=z[i])!=0; i++){} *tokenType = TOKEN_ID; return i; } default: { if( !IdChar(*z) ){ break; } for(i=1; IdChar(z[i]); i++){} *tokenType = TOKEN_ID; return i; } } *tokenType = TOKEN_PUNCT; return 1; } /* ** A token extracted from a string is an instance of the following ** structure. */ typedef struct Token { const char *z; /* Pointer to token text. Not '\000' terminated */ short int n; /* Length of the token text in bytes. */ } Token; /* ** Given a input string (which is really one of the argv[] parameters ** passed into xConnect or xCreate) split the string up into tokens. ** Return an array of pointers to '\000' terminated strings, one string ** for each non-whitespace token. ** ** The returned array is terminated by a single NULL pointer. ** ** Space to hold the returned array is obtained from a single ** malloc and should be freed by passing the return value to free(). ** The individual strings within the token list are all a part of ** the single memory allocation and will all be freed at once. */ static char **tokenizeString(const char *z, int *pnToken){ int nToken = 0; Token *aToken = malloc( strlen(z) * sizeof(aToken[0]) ); int n = 1; int e, i; int totalSize = 0; char **azToken; char *zCopy; while( n>0 ){ n = getToken(z, &e); if( e!=TOKEN_SPACE ){ aToken[nToken].z = z; aToken[nToken].n = n; nToken++; totalSize += n+1; } z += n; } azToken = (char**)malloc( nToken*sizeof(char*) + totalSize ); zCopy = (char*)&azToken[nToken]; nToken--; for(i=0; i<nToken; i++){ azToken[i] = zCopy; n = aToken[i].n; memcpy(zCopy, aToken[i].z, n); zCopy[n] = 0; zCopy += n+1; } azToken[nToken] = 0; free(aToken); *pnToken = nToken; return azToken; } /* ** 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. ** ** Examples: ** ** "abc" becomes abc ** 'xyz' becomes xyz ** [pqr] becomes pqr ** `mno` becomes mno */ static void dequoteString(char *z){ int quote; int i, j; if( z==0 ) return; quote = z[0]; switch( quote ){ case '\'': break; case '"': break; case '`': break; /* For MySQL compatibility */ case '[': quote = ']'; break; /* For MS SqlServer compatibility */ default: return; } for(i=1, j=0; z[i]; i++){ if( z[i]==quote ){ if( z[i+1]==quote ){ z[j++] = quote; i++; }else{ z[j++] = 0; break; } }else{ z[j++] = z[i]; } } } /* ** The input azIn is a NULL-terminated list of tokens. Remove the first ** token and all punctuation tokens. Remove the quotes from ** around string literal tokens. ** ** Example: ** ** input: tokenize chinese ( 'simplifed' , 'mixed' ) ** output: chinese simplifed mixed ** ** Another example: ** ** input: delimiters ( '[' , ']' , '...' ) ** output: [ ] ... */ static void tokenListToIdList(char **azIn){ int i, j; if( azIn ){ for(i=0, j=-1; azIn[i]; i++){ if( safe_isalnum(azIn[i][0]) || azIn[i][1] ){ dequoteString(azIn[i]); if( j>=0 ){ azIn[j] = azIn[i]; } j++; } } azIn[j] = 0; } } /* ** Find the first alphanumeric token in the string zIn. Null-terminate ** this token. Remove any quotation marks. And return a pointer to ** the result. */ static char *firstToken(char *zIn, char **pzTail){ int n, ttype; while(1){ n = getToken(zIn, &ttype); if( ttype==TOKEN_SPACE ){ zIn += n; }else if( ttype==TOKEN_EOF ){ *pzTail = zIn; return 0; }else{ zIn[n] = 0; *pzTail = &zIn[1]; dequoteString(zIn); return zIn; } } /*NOTREACHED*/ } /* Return true if... ** ** * s begins with the string t, ignoring case ** * s is longer than t ** * The first character of s beyond t is not a alphanumeric ** ** Ignore leading space in *s. ** ** To put it another way, return true if the first token of ** s[] is t[]. */ static int startsWith(const char *s, const char *t){ while( safe_isspace(*s) ){ s++; } while( *t ){ if( safe_tolower(*s++)!=safe_tolower(*t++) ) return 0; } return *s!='_' && !safe_isalnum(*s); } /* ** An instance of this structure defines the "spec" of a ** full text index. This structure is populated by parseSpec ** and use by fulltextConnect and fulltextCreate. */ typedef struct TableSpec { const char *zDb; /* Logical database name */ const char *zName; /* Name of the full-text index */ int nColumn; /* Number of columns to be indexed */ char **azColumn; /* Original names of columns to be indexed */ char **azContentColumn; /* Column names for %_content */ char **azTokenizer; /* Name of tokenizer and its arguments */ } TableSpec; /* ** Reclaim all of the memory used by a TableSpec */ static void clearTableSpec(TableSpec *p) { free(p->azColumn); free(p->azContentColumn); free(p->azTokenizer); } /* Parse a CREATE VIRTUAL TABLE statement, which looks like this: * * CREATE VIRTUAL TABLE email * USING fts1(subject, body, tokenize mytokenizer(myarg)) * * We return parsed information in a TableSpec structure. * */ static int parseSpec(TableSpec *pSpec, int argc, const char *const*argv, char**pzErr){ int i, n; char *z, *zDummy; char **azArg; const char *zTokenizer = 0; /* argv[] entry describing the tokenizer */ assert( argc>=3 ); /* Current interface: ** argv[0] - module name ** argv[1] - database name ** argv[2] - table name ** argv[3..] - columns, optionally followed by tokenizer specification ** and snippet delimiters specification. */ /* Make a copy of the complete argv[][] array in a single allocation. ** The argv[][] array is read-only and transient. We can write to the ** copy in order to modify things and the copy is persistent. */ memset(pSpec, 0, sizeof(*pSpec)); for(i=n=0; i<argc; i++){ n += strlen(argv[i]) + 1; } azArg = malloc( sizeof(char*)*argc + n ); if( azArg==0 ){ return SQLITE_NOMEM; } z = (char*)&azArg[argc]; for(i=0; i<argc; i++){ azArg[i] = z; strcpy(z, argv[i]); z += strlen(z)+1; } /* Identify the column names and the tokenizer and delimiter arguments ** in the argv[][] array. */ pSpec->zDb = azArg[1]; pSpec->zName = azArg[2]; pSpec->nColumn = 0; pSpec->azColumn = azArg; zTokenizer = "tokenize simple"; for(i=3; i<argc; ++i){ if( startsWith(azArg[i],"tokenize") ){ zTokenizer = azArg[i]; }else{ z = azArg[pSpec->nColumn] = firstToken(azArg[i], &zDummy); pSpec->nColumn++; } } if( pSpec->nColumn==0 ){ azArg[0] = "content"; pSpec->nColumn = 1; } /* ** Construct the list of content column names. ** ** Each content column name will be of the form cNNAAAA ** where NN is the column number and AAAA is the sanitized ** column name. "sanitized" means that special characters are ** converted to "_". The cNN prefix guarantees that all column ** names are unique. ** ** The AAAA suffix is not strictly necessary. It is included ** for the convenience of people who might examine the generated ** %_content table and wonder what the columns are used for. */ pSpec->azContentColumn = malloc( pSpec->nColumn * sizeof(char *) ); if( pSpec->azContentColumn==0 ){ clearTableSpec(pSpec); return SQLITE_NOMEM; } for(i=0; i<pSpec->nColumn; i++){ char *p; pSpec->azContentColumn[i] = sqlite3_mprintf("c%d%s", i, azArg[i]); for (p = pSpec->azContentColumn[i]; *p ; ++p) { if( !safe_isalnum(*p) ) *p = '_'; } } /* ** Parse the tokenizer specification string. */ pSpec->azTokenizer = tokenizeString(zTokenizer, &n); tokenListToIdList(pSpec->azTokenizer); return SQLITE_OK; } /* ** Generate a CREATE TABLE statement that describes the schema of ** the virtual table. Return a pointer to this schema string. ** ** Space is obtained from sqlite3_mprintf() and should be freed ** using sqlite3_free(). */ static char *fulltextSchema( int nColumn, /* Number of columns */ const char *const* azColumn, /* List of columns */ const char *zTableName /* Name of the table */ ){ int i; char *zSchema, *zNext; const char *zSep = "("; zSchema = sqlite3_mprintf("CREATE TABLE x"); for(i=0; i<nColumn; i++){ zNext = sqlite3_mprintf("%s%s%Q", zSchema, zSep, azColumn[i]); sqlite3_free(zSchema); zSchema = zNext; zSep = ","; } zNext = sqlite3_mprintf("%s,%Q)", zSchema, zTableName); sqlite3_free(zSchema); return zNext; } /* ** Build a new sqlite3_vtab structure that will describe the ** fulltext index defined by spec. */ static int constructVtab( sqlite3 *db, /* The SQLite database connection */ TableSpec *spec, /* Parsed spec information from parseSpec() */ sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */ char **pzErr /* Write any error message here */ ){ int rc; int n; fulltext_vtab *v = 0; const sqlite3_tokenizer_module *m = NULL; char *schema; v = (fulltext_vtab *) malloc(sizeof(fulltext_vtab)); if( v==0 ) return SQLITE_NOMEM; memset(v, 0, sizeof(*v)); /* sqlite will initialize v->base */ v->db = db; v->zDb = spec->zDb; /* Freed when azColumn is freed */ v->zName = spec->zName; /* Freed when azColumn is freed */ v->nColumn = spec->nColumn; v->azContentColumn = spec->azContentColumn; spec->azContentColumn = 0; v->azColumn = spec->azColumn; spec->azColumn = 0; if( spec->azTokenizer==0 ){ return SQLITE_NOMEM; } /* TODO(shess) For now, add new tokenizers as else if clauses. */ if( spec->azTokenizer[0]==0 || startsWith(spec->azTokenizer[0], "simple") ){ sqlite3Fts1SimpleTokenizerModule(&m); }else if( startsWith(spec->azTokenizer[0], "porter") ){ sqlite3Fts1PorterTokenizerModule(&m); }else{ *pzErr = sqlite3_mprintf("unknown tokenizer: %s", spec->azTokenizer[0]); rc = SQLITE_ERROR; goto err; } for(n=0; spec->azTokenizer[n]; n++){} if( n ){ rc = m->xCreate(n-1, (const char*const*)&spec->azTokenizer[1], &v->pTokenizer); }else{ rc = m->xCreate(0, 0, &v->pTokenizer); } if( rc!=SQLITE_OK ) goto err; v->pTokenizer->pModule = m; /* TODO: verify the existence of backing tables foo_content, foo_term */ schema = fulltextSchema(v->nColumn, (const char*const*)v->azColumn, spec->zName); rc = sqlite3_declare_vtab(db, schema); sqlite3_free(schema); if( rc!=SQLITE_OK ) goto err; memset(v->pFulltextStatements, 0, sizeof(v->pFulltextStatements)); *ppVTab = &v->base; TRACE(("FTS1 Connect %p\n", v)); return rc; err: fulltext_vtab_destroy(v); return rc; } static int fulltextConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char **pzErr ){ TableSpec spec; int rc = parseSpec(&spec, argc, argv, pzErr); if( rc!=SQLITE_OK ) return rc; rc = constructVtab(db, &spec, ppVTab, pzErr); clearTableSpec(&spec); return rc; } /* The %_content table holds the text of each document, with ** the rowid used as the docid. ** ** The %_term table maps each term to a document list blob ** containing elements sorted by ascending docid, each element ** encoded as: ** ** docid varint-encoded ** token elements: ** position+1 varint-encoded as delta from previous position ** start offset varint-encoded as delta from previous start offset ** end offset varint-encoded as delta from start offset ** ** The sentinel position of 0 indicates the end of the token list. ** ** Additionally, doclist blobs are chunked into multiple segments, ** using segment to order the segments. New elements are added to ** the segment at segment 0, until it exceeds CHUNK_MAX. Then ** segment 0 is deleted, and the doclist is inserted at segment 1. ** If there is already a doclist at segment 1, the segment 0 doclist ** is merged with it, the segment 1 doclist is deleted, and the ** merged doclist is inserted at segment 2, repeating those ** operations until an insert succeeds. ** ** Since this structure doesn't allow us to update elements in place ** in case of deletion or update, these are simply written to ** segment 0 (with an empty token list in case of deletion), with ** docListAccumulate() taking care to retain lower-segment ** information in preference to higher-segment information. */ /* TODO(shess) Provide a VACUUM type operation which both removes ** deleted elements which are no longer necessary, and duplicated ** elements. I suspect this will probably not be necessary in ** practice, though. */ static int fulltextCreate(sqlite3 *db, void *pAux, int argc, const char * const *argv, sqlite3_vtab **ppVTab, char **pzErr){ int rc; TableSpec spec; StringBuffer schema; TRACE(("FTS1 Create\n")); rc = parseSpec(&spec, argc, argv, pzErr); if( rc!=SQLITE_OK ) return rc; initStringBuffer(&schema); append(&schema, "CREATE TABLE %_content("); appendList(&schema, spec.nColumn, spec.azContentColumn); append(&schema, ")"); rc = sql_exec(db, spec.zDb, spec.zName, schema.s); free(schema.s); if( rc!=SQLITE_OK ) goto out; rc = sql_exec(db, spec.zDb, spec.zName, "create table %_term(term text, segment integer, doclist blob, " "primary key(term, segment));"); if( rc!=SQLITE_OK ) goto out; rc = constructVtab(db, &spec, ppVTab, pzErr); out: clearTableSpec(&spec); return rc; } /* Decide how to handle an SQL query. */ static int fulltextBestIndex(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ int i; TRACE(("FTS1 BestIndex\n")); for(i=0; i<pInfo->nConstraint; ++i){ const struct sqlite3_index_constraint *pConstraint; pConstraint = &pInfo->aConstraint[i]; if( pConstraint->usable ) { if( pConstraint->iColumn==-1 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){ pInfo->idxNum = QUERY_ROWID; /* lookup by rowid */ TRACE(("FTS1 QUERY_ROWID\n")); } else if( pConstraint->iColumn>=0 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_MATCH ){ /* full-text search */ pInfo->idxNum = QUERY_FULLTEXT + pConstraint->iColumn; TRACE(("FTS1 QUERY_FULLTEXT %d\n", pConstraint->iColumn)); } else continue; pInfo->aConstraintUsage[i].argvIndex = 1; pInfo->aConstraintUsage[i].omit = 1; /* An arbitrary value for now. * TODO: Perhaps rowid matches should be considered cheaper than * full-text searches. */ pInfo->estimatedCost = 1.0; return SQLITE_OK; } } pInfo->idxNum = QUERY_GENERIC; return SQLITE_OK; } static int fulltextDisconnect(sqlite3_vtab *pVTab){ TRACE(("FTS1 Disconnect %p\n", pVTab)); fulltext_vtab_destroy((fulltext_vtab *)pVTab); return SQLITE_OK; } static int fulltextDestroy(sqlite3_vtab *pVTab){ fulltext_vtab *v = (fulltext_vtab *)pVTab; int rc; TRACE(("FTS1 Destroy %p\n", pVTab)); rc = sql_exec(v->db, v->zDb, v->zName, "drop table if exists %_content;" "drop table if exists %_term;" ); if( rc!=SQLITE_OK ) return rc; fulltext_vtab_destroy((fulltext_vtab *)pVTab); return SQLITE_OK; } static int fulltextOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ fulltext_cursor *c; c = (fulltext_cursor *) calloc(sizeof(fulltext_cursor), 1); /* sqlite will initialize c->base */ *ppCursor = &c->base; TRACE(("FTS1 Open %p: %p\n", pVTab, c)); return SQLITE_OK; } /* Free all of the dynamically allocated memory held by *q */ static void queryClear(Query *q){ int i; for(i = 0; i < q->nTerms; ++i){ free(q->pTerms[i].pTerm); } free(q->pTerms); memset(q, 0, sizeof(*q)); } /* Free all of the dynamically allocated memory held by the ** Snippet */ static void snippetClear(Snippet *p){ free(p->aMatch); free(p->zOffset); free(p->zSnippet); memset(p, 0, sizeof(*p)); } /* ** Append a single entry to the p->aMatch[] log. */ static void snippetAppendMatch( Snippet *p, /* Append the entry to this snippet */ int iCol, int iTerm, /* The column and query term */ int iStart, int nByte /* Offset and size of the match */ ){ int i; struct snippetMatch *pMatch; if( p->nMatch+1>=p->nAlloc ){ p->nAlloc = p->nAlloc*2 + 10; p->aMatch = realloc(p->aMatch, p->nAlloc*sizeof(p->aMatch[0]) ); if( p->aMatch==0 ){ p->nMatch = 0; p->nAlloc = 0; return; } } i = p->nMatch++; pMatch = &p->aMatch[i]; pMatch->iCol = iCol; pMatch->iTerm = iTerm; pMatch->iStart = iStart; pMatch->nByte = nByte; } /* ** Sizing information for the circular buffer used in snippetOffsetsOfColumn() */ #define FTS1_ROTOR_SZ (32) #define FTS1_ROTOR_MASK (FTS1_ROTOR_SZ-1) /* ** Add entries to pSnippet->aMatch[] for every match that occurs against ** document zDoc[0..nDoc-1] which is stored in column iColumn. */ static void snippetOffsetsOfColumn( Query *pQuery, Snippet *pSnippet, int iColumn, const char *zDoc, int nDoc ){ const sqlite3_tokenizer_module *pTModule; /* The tokenizer module */ sqlite3_tokenizer *pTokenizer; /* The specific tokenizer */ sqlite3_tokenizer_cursor *pTCursor; /* Tokenizer cursor */ fulltext_vtab *pVtab; /* The full text index */ int nColumn; /* Number of columns in the index */ const QueryTerm *aTerm; /* Query string terms */ int nTerm; /* Number of query string terms */ int i, j; /* Loop counters */ int rc; /* Return code */ unsigned int match, prevMatch; /* Phrase search bitmasks */ const char *zToken; /* Next token from the tokenizer */ int nToken; /* Size of zToken */ int iBegin, iEnd, iPos; /* Offsets of beginning and end */ /* The following variables keep a circular buffer of the last ** few tokens */ unsigned int iRotor = 0; /* Index of current token */ int iRotorBegin[FTS1_ROTOR_SZ]; /* Beginning offset of token */ int iRotorLen[FTS1_ROTOR_SZ]; /* Length of token */ pVtab = pQuery->pFts; nColumn = pVtab->nColumn; pTokenizer = pVtab->pTokenizer; pTModule = pTokenizer->pModule; rc = pTModule->xOpen(pTokenizer, zDoc, nDoc, &pTCursor); if( rc ) return; pTCursor->pTokenizer = pTokenizer; aTerm = pQuery->pTerms; nTerm = pQuery->nTerms; if( nTerm>=FTS1_ROTOR_SZ ){ nTerm = FTS1_ROTOR_SZ - 1; } prevMatch = 0; while(1){ rc = pTModule->xNext(pTCursor, &zToken, &nToken, &iBegin, &iEnd, &iPos); if( rc ) break; iRotorBegin[iRotor&FTS1_ROTOR_MASK] = iBegin; iRotorLen[iRotor&FTS1_ROTOR_MASK] = iEnd-iBegin; match = 0; for(i=0; i<nTerm; i++){ int iCol; iCol = aTerm[i].iColumn; if( iCol>=0 && iCol<nColumn && iCol!=iColumn ) continue; if( aTerm[i].nTerm!=nToken ) continue; if( memcmp(aTerm[i].pTerm, zToken, nToken) ) continue; if( aTerm[i].iPhrase>1 && (prevMatch & (1<<i))==0 ) continue; match |= 1<<i; if( i==nTerm-1 || aTerm[i+1].iPhrase==1 ){ for(j=aTerm[i].iPhrase-1; j>=0; j--){ int k = (iRotor-j) & FTS1_ROTOR_MASK; snippetAppendMatch(pSnippet, iColumn, i-j, iRotorBegin[k], iRotorLen[k]); } } } prevMatch = match<<1; iRotor++; } pTModule->xClose(pTCursor); } /* ** Compute all offsets for the current row of the query. ** If the offsets have already been computed, this routine is a no-op. */ static void snippetAllOffsets(fulltext_cursor *p){ int nColumn; int iColumn, i; int iFirst, iLast; fulltext_vtab *pFts; if( p->snippet.nMatch ) return; if( p->q.nTerms==0 ) return; pFts = p->q.pFts; nColumn = pFts->nColumn; iColumn = p->iCursorType - QUERY_FULLTEXT; if( iColumn<0 || iColumn>=nColumn ){ iFirst = 0; iLast = nColumn-1; }else{ iFirst = iColumn; iLast = iColumn; } for(i=iFirst; i<=iLast; i++){ const char *zDoc; int nDoc; zDoc = (const char*)sqlite3_column_text(p->pStmt, i+1); nDoc = sqlite3_column_bytes(p->pStmt, i+1); snippetOffsetsOfColumn(&p->q, &p->snippet, i, zDoc, nDoc); } } /* ** Convert the information in the aMatch[] array of the snippet ** into the string zOffset[0..nOffset-1]. */ static void snippetOffsetText(Snippet *p){ int i; int cnt = 0; StringBuffer sb; char zBuf[200]; if( p->zOffset ) return; initStringBuffer(&sb); for(i=0; i<p->nMatch; i++){ struct snippetMatch *pMatch = &p->aMatch[i]; zBuf[0] = ' '; sqlite3_snprintf(sizeof(zBuf)-1, &zBuf[cnt>0], "%d %d %d %d", pMatch->iCol, pMatch->iTerm, pMatch->iStart, pMatch->nByte); append(&sb, zBuf); cnt++; } p->zOffset = sb.s; p->nOffset = sb.len; } /* ** zDoc[0..nDoc-1] is phrase of text. aMatch[0..nMatch-1] are a set ** of matching words some of which might be in zDoc. zDoc is column ** number iCol. ** ** iBreak is suggested spot in zDoc where we could begin or end an ** excerpt. Return a value similar to iBreak but possibly adjusted ** to be a little left or right so that the break point is better. */ static int wordBoundary( int iBreak, /* The suggested break point */ const char *zDoc, /* Document text */ int nDoc, /* Number of bytes in zDoc[] */ struct snippetMatch *aMatch, /* Matching words */ int nMatch, /* Number of entries in aMatch[] */ int iCol /* The column number for zDoc[] */ ){ int i; if( iBreak<=10 ){ return 0; } if( iBreak>=nDoc-10 ){ return nDoc; } for(i=0; i<nMatch && aMatch[i].iCol<iCol; i++){} while( i<nMatch && aMatch[i].iStart+aMatch[i].nByte<iBreak ){ i++; } if( i<nMatch ){ if( aMatch[i].iStart<iBreak+10 ){ return aMatch[i].iStart; } if( i>0 && aMatch[i-1].iStart+aMatch[i-1].nByte>=iBreak ){ return aMatch[i-1].iStart; } } for(i=1; i<=10; i++){ if( safe_isspace(zDoc[iBreak-i]) ){ return iBreak - i + 1; } if( safe_isspace(zDoc[iBreak+i]) ){ return iBreak + i + 1; } } return iBreak; } /* ** If the StringBuffer does not end in white space, add a single ** space character to the end. */ static void appendWhiteSpace(StringBuffer *p){ if( p->len==0 ) return; if( safe_isspace(p->s[p->len-1]) ) return; append(p, " "); } /* ** Remove white space from teh end of the StringBuffer */ static void trimWhiteSpace(StringBuffer *p){ while( p->len>0 && safe_isspace(p->s[p->len-1]) ){ p->len--; } } /* ** Allowed values for Snippet.aMatch[].snStatus */ #define SNIPPET_IGNORE 0 /* It is ok to omit this match from the snippet */ #define SNIPPET_DESIRED 1 /* We want to include this match in the snippet */ /* ** Generate the text of a snippet. */ static void snippetText( fulltext_cursor *pCursor, /* The cursor we need the snippet for */ const char *zStartMark, /* Markup to appear before each match */ const char *zEndMark, /* Markup to appear after each match */ const char *zEllipsis /* Ellipsis mark */ ){ int i, j; struct snippetMatch *aMatch; int nMatch; int nDesired; StringBuffer sb; int tailCol; int tailOffset; int iCol; int nDoc; const char *zDoc; int iStart, iEnd; int tailEllipsis = 0; int iMatch; free(pCursor->snippet.zSnippet); pCursor->snippet.zSnippet = 0; aMatch = pCursor->snippet.aMatch; nMatch = pCursor->snippet.nMatch; initStringBuffer(&sb); for(i=0; i<nMatch; i++){ aMatch[i].snStatus = SNIPPET_IGNORE; } nDesired = 0; for(i=0; i<pCursor->q.nTerms; i++){ for(j=0; j<nMatch; j++){ if( aMatch[j].iTerm==i ){ aMatch[j].snStatus = SNIPPET_DESIRED; nDesired++; break; } } } iMatch = 0; tailCol = -1; tailOffset = 0; for(i=0; i<nMatch && nDesired>0; i++){ if( aMatch[i].snStatus!=SNIPPET_DESIRED ) continue; nDesired--; iCol = aMatch[i].iCol; zDoc = (const char*)sqlite3_column_text(pCursor->pStmt, iCol+1); nDoc = sqlite3_column_bytes(pCursor->pStmt, iCol+1); iStart = aMatch[i].iStart - 40; iStart = wordBoundary(iStart, zDoc, nDoc, aMatch, nMatch, iCol); if( iStart<=10 ){ iStart = 0; } if( iCol==tailCol && iStart<=tailOffset+20 ){ iStart = tailOffset; } if( (iCol!=tailCol && tailCol>=0) || iStart!=tailOffset ){ trimWhiteSpace(&sb); appendWhiteSpace(&sb); append(&sb, zEllipsis); appendWhiteSpace(&sb); } iEnd = aMatch[i].iStart + aMatch[i].nByte + 40; iEnd = wordBoundary(iEnd, zDoc, nDoc, aMatch, nMatch, iCol); if( iEnd>=nDoc-10 ){ iEnd = nDoc; tailEllipsis = 0; }else{ tailEllipsis = 1; } while( iMatch<nMatch && aMatch[iMatch].iCol<iCol ){ iMatch++; } while( iStart<iEnd ){ while( iMatch<nMatch && aMatch[iMatch].iStart<iStart && aMatch[iMatch].iCol<=iCol ){ iMatch++; } if( iMatch<nMatch && aMatch[iMatch].iStart<iEnd && aMatch[iMatch].iCol==iCol ){ nappend(&sb, &zDoc[iStart], aMatch[iMatch].iStart - iStart); iStart = aMatch[iMatch].iStart; append(&sb, zStartMark); nappend(&sb, &zDoc[iStart], aMatch[iMatch].nByte); append(&sb, zEndMark); iStart += aMatch[iMatch].nByte; for(j=iMatch+1; j<nMatch; j++){ if( aMatch[j].iTerm==aMatch[iMatch].iTerm && aMatch[j].snStatus==SNIPPET_DESIRED ){ nDesired--; aMatch[j].snStatus = SNIPPET_IGNORE; } } }else{ nappend(&sb, &zDoc[iStart], iEnd - iStart); iStart = iEnd; } } tailCol = iCol; tailOffset = iEnd; } trimWhiteSpace(&sb); if( tailEllipsis ){ appendWhiteSpace(&sb); append(&sb, zEllipsis); } pCursor->snippet.zSnippet = sb.s; pCursor->snippet.nSnippet = sb.len; } /* ** Close the cursor. For additional information see the documentation ** on the xClose method of the virtual table interface. */ static int fulltextClose(sqlite3_vtab_cursor *pCursor){ fulltext_cursor *c = (fulltext_cursor *) pCursor; TRACE(("FTS1 Close %p\n", c)); sqlite3_finalize(c->pStmt); queryClear(&c->q); snippetClear(&c->snippet); if( c->result.pDoclist!=NULL ){ docListDelete(c->result.pDoclist); } free(c); return SQLITE_OK; } static int fulltextNext(sqlite3_vtab_cursor *pCursor){ fulltext_cursor *c = (fulltext_cursor *) pCursor; sqlite_int64 iDocid; int rc; TRACE(("FTS1 Next %p\n", pCursor)); snippetClear(&c->snippet); if( c->iCursorType < QUERY_FULLTEXT ){ /* TODO(shess) Handle SQLITE_SCHEMA AND SQLITE_BUSY. */ rc = sqlite3_step(c->pStmt); switch( rc ){ case SQLITE_ROW: c->eof = 0; return SQLITE_OK; case SQLITE_DONE: c->eof = 1; return SQLITE_OK; default: c->eof = 1; return rc; } } else { /* full-text query */ rc = sqlite3_reset(c->pStmt); if( rc!=SQLITE_OK ) return rc; iDocid = nextDocid(&c->result); if( iDocid==0 ){ c->eof = 1; return SQLITE_OK; } rc = sqlite3_bind_int64(c->pStmt, 1, iDocid); if( rc!=SQLITE_OK ) return rc; /* TODO(shess) Handle SQLITE_SCHEMA AND SQLITE_BUSY. */ rc = sqlite3_step(c->pStmt); if( rc==SQLITE_ROW ){ /* the case we expect */ c->eof = 0; return SQLITE_OK; } /* an error occurred; abort */ return rc==SQLITE_DONE ? SQLITE_ERROR : rc; } } /* Return a DocList corresponding to the query term *pTerm. If *pTerm ** is the first term of a phrase query, go ahead and evaluate the phrase ** query and return the doclist for the entire phrase query. ** ** The result is stored in pTerm->doclist. */ static int docListOfTerm( fulltext_vtab *v, /* The full text index */ int iColumn, /* column to restrict to. No restrition if >=nColumn */ QueryTerm *pQTerm, /* Term we are looking for, or 1st term of a phrase */ DocList **ppResult /* Write the result here */ ){ DocList *pLeft, *pRight, *pNew; int i, rc; pLeft = docListNew(DL_POSITIONS); rc = term_select_all(v, iColumn, pQTerm->pTerm, pQTerm->nTerm, pLeft); if( rc ){ docListDelete(pLeft); return rc; } for(i=1; i<=pQTerm->nPhrase; i++){ pRight = docListNew(DL_POSITIONS); rc = term_select_all(v, iColumn, pQTerm[i].pTerm, pQTerm[i].nTerm, pRight); if( rc ){ docListDelete(pLeft); return rc; } pNew = docListNew(i<pQTerm->nPhrase ? DL_POSITIONS : DL_DOCIDS); docListPhraseMerge(pLeft, pRight, pNew); docListDelete(pLeft); docListDelete(pRight); pLeft = pNew; } *ppResult = pLeft; return SQLITE_OK; } /* Add a new term pTerm[0..nTerm-1] to the query *q. */ static void queryAdd(Query *q, const char *pTerm, int nTerm){ QueryTerm *t; ++q->nTerms; q->pTerms = realloc(q->pTerms, q->nTerms * sizeof(q->pTerms[0])); if( q->pTerms==0 ){ q->nTerms = 0; return; } t = &q->pTerms[q->nTerms - 1]; memset(t, 0, sizeof(*t)); t->pTerm = malloc(nTerm+1); memcpy(t->pTerm, pTerm, nTerm); t->pTerm[nTerm] = 0; t->nTerm = nTerm; t->isOr = q->nextIsOr; q->nextIsOr = 0; t->iColumn = q->nextColumn; q->nextColumn = q->dfltColumn; } /* ** Check to see if the string zToken[0...nToken-1] matches any ** column name in the virtual table. If it does, ** return the zero-indexed column number. If not, return -1. */ static int checkColumnSpecifier( fulltext_vtab *pVtab, /* The virtual table */ const char *zToken, /* Text of the token */ int nToken /* Number of characters in the token */ ){ int i; for(i=0; i<pVtab->nColumn; i++){ if( memcmp(pVtab->azColumn[i], zToken, nToken)==0 && pVtab->azColumn[i][nToken]==0 ){ return i; } } return -1; } /* ** Parse the text at pSegment[0..nSegment-1]. Add additional terms ** to the query being assemblied in pQuery. ** ** inPhrase is true if pSegment[0..nSegement-1] is contained within ** double-quotes. If inPhrase is true, then the first term ** is marked with the number of terms in the phrase less one and ** OR and "-" syntax is ignored. If inPhrase is false, then every ** term found is marked with nPhrase=0 and OR and "-" syntax is significant. */ static int tokenizeSegment( sqlite3_tokenizer *pTokenizer, /* The tokenizer to use */ const char *pSegment, int nSegment, /* Query expression being parsed */ int inPhrase, /* True if within "..." */ Query *pQuery /* Append results here */ ){ const sqlite3_tokenizer_module *pModule = pTokenizer->pModule; sqlite3_tokenizer_cursor *pCursor; int firstIndex = pQuery->nTerms; int iCol; int nTerm = 1; int rc = pModule->xOpen(pTokenizer, pSegment, nSegment, &pCursor); if( rc!=SQLITE_OK ) return rc; pCursor->pTokenizer = pTokenizer; while( 1 ){ const char *pToken; int nToken, iBegin, iEnd, iPos; rc = pModule->xNext(pCursor, &pToken, &nToken, &iBegin, &iEnd, &iPos); if( rc!=SQLITE_OK ) break; if( !inPhrase && pSegment[iEnd]==':' && (iCol = checkColumnSpecifier(pQuery->pFts, pToken, nToken))>=0 ){ pQuery->nextColumn = iCol; continue; } if( !inPhrase && pQuery->nTerms>0 && nToken==2 && pSegment[iBegin]=='O' && pSegment[iBegin+1]=='R' ){ pQuery->nextIsOr = 1; continue; } queryAdd(pQuery, pToken, nToken); if( !inPhrase && iBegin>0 && pSegment[iBegin-1]=='-' ){ pQuery->pTerms[pQuery->nTerms-1].isNot = 1; } pQuery->pTerms[pQuery->nTerms-1].iPhrase = nTerm; if( inPhrase ){ nTerm++; } } if( inPhrase && pQuery->nTerms>firstIndex ){ pQuery->pTerms[firstIndex].nPhrase = pQuery->nTerms - firstIndex - 1; } return pModule->xClose(pCursor); } /* Parse a query string, yielding a Query object pQuery. ** ** The calling function will need to queryClear() to clean up ** the dynamically allocated memory held by pQuery. */ static int parseQuery( fulltext_vtab *v, /* The fulltext index */ const char *zInput, /* Input text of the query string */ int nInput, /* Size of the input text */ int dfltColumn, /* Default column of the index to match against */ Query *pQuery /* Write the parse results here. */ ){ int iInput, inPhrase = 0; if( zInput==0 ) nInput = 0; if( nInput<0 ) nInput = strlen(zInput); pQuery->nTerms = 0; pQuery->pTerms = NULL; pQuery->nextIsOr = 0; pQuery->nextColumn = dfltColumn; pQuery->dfltColumn = dfltColumn; pQuery->pFts = v; for(iInput=0; iInput<nInput; ++iInput){ int i; for(i=iInput; i<nInput && zInput[i]!='"'; ++i){} if( i>iInput ){ tokenizeSegment(v->pTokenizer, zInput+iInput, i-iInput, inPhrase, pQuery); } iInput = i; if( i<nInput ){ assert( zInput[i]=='"' ); inPhrase = !inPhrase; } } if( inPhrase ){ /* unmatched quote */ queryClear(pQuery); return SQLITE_ERROR; } return SQLITE_OK; } /* Perform a full-text query using the search expression in ** zInput[0..nInput-1]. Return a list of matching documents ** in pResult. ** ** Queries must match column iColumn. Or if iColumn>=nColumn ** they are allowed to match against any column. */ static int fulltextQuery( fulltext_vtab *v, /* The full text index */ int iColumn, /* Match against this column by default */ const char *zInput, /* The query string */ int nInput, /* Number of bytes in zInput[] */ DocList **pResult, /* Write the result doclist here */ Query *pQuery /* Put parsed query string here */ ){ int i, iNext, rc; DocList *pLeft = NULL; DocList *pRight, *pNew, *pOr; int nNot = 0; QueryTerm *aTerm; rc = parseQuery(v, zInput, nInput, iColumn, pQuery); if( rc!=SQLITE_OK ) return rc; /* Merge AND terms. */ aTerm = pQuery->pTerms; for(i = 0; i<pQuery->nTerms; i=iNext){ if( aTerm[i].isNot ){ /* Handle all NOT terms in a separate pass */ nNot++; iNext = i + aTerm[i].nPhrase+1; continue; } iNext = i + aTerm[i].nPhrase + 1; rc = docListOfTerm(v, aTerm[i].iColumn, &aTerm[i], &pRight); if( rc ){ queryClear(pQuery); return rc; } while( iNext<pQuery->nTerms && aTerm[iNext].isOr ){ rc = docListOfTerm(v, aTerm[iNext].iColumn, &aTerm[iNext], &pOr); iNext += aTerm[iNext].nPhrase + 1; if( rc ){ queryClear(pQuery); return rc; } pNew = docListNew(DL_DOCIDS); docListOrMerge(pRight, pOr, pNew); docListDelete(pRight); docListDelete(pOr); pRight = pNew; } if( pLeft==0 ){ pLeft = pRight; }else{ pNew = docListNew(DL_DOCIDS); docListAndMerge(pLeft, pRight, pNew); docListDelete(pRight); docListDelete(pLeft); pLeft = pNew; } } if( nNot && pLeft==0 ){ /* We do not yet know how to handle a query of only NOT terms */ return SQLITE_ERROR; } /* Do the EXCEPT terms */ for(i=0; i<pQuery->nTerms; i += aTerm[i].nPhrase + 1){ if( !aTerm[i].isNot ) continue; rc = docListOfTerm(v, aTerm[i].iColumn, &aTerm[i], &pRight); if( rc ){ queryClear(pQuery); docListDelete(pLeft); return rc; } pNew = docListNew(DL_DOCIDS); docListExceptMerge(pLeft, pRight, pNew); docListDelete(pRight); docListDelete(pLeft); pLeft = pNew; } *pResult = pLeft; return rc; } /* ** This is the xFilter interface for the virtual table. See ** the virtual table xFilter method documentation for additional ** information. ** ** If idxNum==QUERY_GENERIC then do a full table scan against ** the %_content table. ** ** If idxNum==QUERY_ROWID then do a rowid lookup for a single entry ** in the %_content table. ** ** If idxNum>=QUERY_FULLTEXT then use the full text index. The ** column on the left-hand side of the MATCH operator is column ** number idxNum-QUERY_FULLTEXT, 0 indexed. argv[0] is the right-hand ** side of the MATCH operator. */ /* TODO(shess) Upgrade the cursor initialization and destruction to ** account for fulltextFilter() being called multiple times on the ** same cursor. The current solution is very fragile. Apply fix to ** fts2 as appropriate. */ static int fulltextFilter( sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ int idxNum, const char *idxStr, /* Which indexing scheme to use */ int argc, sqlite3_value **argv /* Arguments for the indexing scheme */ ){ fulltext_cursor *c = (fulltext_cursor *) pCursor; fulltext_vtab *v = cursor_vtab(c); int rc; char *zSql; TRACE(("FTS1 Filter %p\n",pCursor)); zSql = sqlite3_mprintf("select rowid, * from %%_content %s", idxNum==QUERY_GENERIC ? "" : "where rowid=?"); sqlite3_finalize(c->pStmt); rc = sql_prepare(v->db, v->zDb, v->zName, &c->pStmt, zSql); sqlite3_free(zSql); if( rc!=SQLITE_OK ) return rc; c->iCursorType = idxNum; switch( idxNum ){ case QUERY_GENERIC: break; case QUERY_ROWID: rc = sqlite3_bind_int64(c->pStmt, 1, sqlite3_value_int64(argv[0])); if( rc!=SQLITE_OK ) return rc; break; default: /* full-text search */ { const char *zQuery = (const char *)sqlite3_value_text(argv[0]); DocList *pResult; assert( idxNum<=QUERY_FULLTEXT+v->nColumn); assert( argc==1 ); queryClear(&c->q); rc = fulltextQuery(v, idxNum-QUERY_FULLTEXT, zQuery, -1, &pResult, &c->q); if( rc!=SQLITE_OK ) return rc; if( c->result.pDoclist!=NULL ) docListDelete(c->result.pDoclist); readerInit(&c->result, pResult); break; } } return fulltextNext(pCursor); } /* This is the xEof method of the virtual table. The SQLite core ** calls this routine to find out if it has reached the end of ** a query's results set. */ static int fulltextEof(sqlite3_vtab_cursor *pCursor){ fulltext_cursor *c = (fulltext_cursor *) pCursor; return c->eof; } /* This is the xColumn method of the virtual table. The SQLite ** core calls this method during a query when it needs the value ** of a column from the virtual table. This method needs to use ** one of the sqlite3_result_*() routines to store the requested ** value back in the pContext. */ static int fulltextColumn(sqlite3_vtab_cursor *pCursor, sqlite3_context *pContext, int idxCol){ fulltext_cursor *c = (fulltext_cursor *) pCursor; fulltext_vtab *v = cursor_vtab(c); if( idxCol<v->nColumn ){ sqlite3_value *pVal = sqlite3_column_value(c->pStmt, idxCol+1); sqlite3_result_value(pContext, pVal); }else if( idxCol==v->nColumn ){ /* The extra column whose name is the same as the table. ** Return a blob which is a pointer to the cursor */ sqlite3_result_blob(pContext, &c, sizeof(c), SQLITE_TRANSIENT); } return SQLITE_OK; } /* This is the xRowid method. The SQLite core calls this routine to ** retrive the rowid for the current row of the result set. The ** rowid should be written to *pRowid. */ static int fulltextRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ fulltext_cursor *c = (fulltext_cursor *) pCursor; *pRowid = sqlite3_column_int64(c->pStmt, 0); return SQLITE_OK; } /* Add all terms in [zText] to the given hash table. If [iColumn] > 0, * we also store positions and offsets in the hash table using the given * column number. */ static int buildTerms(fulltext_vtab *v, fts1Hash *terms, sqlite_int64 iDocid, const char *zText, int iColumn){ sqlite3_tokenizer *pTokenizer = v->pTokenizer; sqlite3_tokenizer_cursor *pCursor; const char *pToken; int nTokenBytes; int iStartOffset, iEndOffset, iPosition; int rc; rc = pTokenizer->pModule->xOpen(pTokenizer, zText, -1, &pCursor); if( rc!=SQLITE_OK ) return rc; pCursor->pTokenizer = pTokenizer; while( SQLITE_OK==pTokenizer->pModule->xNext(pCursor, &pToken, &nTokenBytes, &iStartOffset, &iEndOffset, &iPosition) ){ DocList *p; /* Positions can't be negative; we use -1 as a terminator internally. */ if( iPosition<0 ){ pTokenizer->pModule->xClose(pCursor); return SQLITE_ERROR; } p = fts1HashFind(terms, pToken, nTokenBytes); if( p==NULL ){ p = docListNew(DL_DEFAULT); docListAddDocid(p, iDocid); fts1HashInsert(terms, pToken, nTokenBytes, p); } if( iColumn>=0 ){ docListAddPosOffset(p, iColumn, iPosition, iStartOffset, iEndOffset); } } /* TODO(shess) Check return? Should this be able to cause errors at ** this point? Actually, same question about sqlite3_finalize(), ** though one could argue that failure there means that the data is ** not durable. *ponder* */ pTokenizer->pModule->xClose(pCursor); return rc; } /* Update the %_terms table to map the term [pTerm] to the given rowid. */ static int index_insert_term(fulltext_vtab *v, const char *pTerm, int nTerm, DocList *d){ sqlite_int64 iIndexRow; DocList doclist; int iSegment = 0, rc; rc = term_select(v, pTerm, nTerm, iSegment, &iIndexRow, &doclist); if( rc==SQLITE_DONE ){ docListInit(&doclist, DL_DEFAULT, 0, 0); docListUpdate(&doclist, d); /* TODO(shess) Consider length(doclist)>CHUNK_MAX? */ rc = term_insert(v, NULL, pTerm, nTerm, iSegment, &doclist); goto err; } if( rc!=SQLITE_ROW ) return SQLITE_ERROR; docListUpdate(&doclist, d); if( doclist.nData<=CHUNK_MAX ){ rc = term_update(v, iIndexRow, &doclist); goto err; } /* Doclist doesn't fit, delete what's there, and accumulate ** forward. */ rc = term_delete(v, iIndexRow); if( rc!=SQLITE_OK ) goto err; /* Try to insert the doclist into a higher segment bucket. On ** failure, accumulate existing doclist with the doclist from that ** bucket, and put results in the next bucket. */ iSegment++; while( (rc=term_insert(v, &iIndexRow, pTerm, nTerm, iSegment, &doclist))!=SQLITE_OK ){ sqlite_int64 iSegmentRow; DocList old; int rc2; /* Retain old error in case the term_insert() error was really an ** error rather than a bounced insert. */ rc2 = term_select(v, pTerm, nTerm, iSegment, &iSegmentRow, &old); if( rc2!=SQLITE_ROW ) goto err; rc = term_delete(v, iSegmentRow); if( rc!=SQLITE_OK ) goto err; /* Reusing lowest-number deleted row keeps the index smaller. */ if( iSegmentRow<iIndexRow ) iIndexRow = iSegmentRow; /* doclist contains the newer data, so accumulate it over old. ** Then steal accumulated data for doclist. */ docListAccumulate(&old, &doclist); docListDestroy(&doclist); doclist = old; iSegment++; } err: docListDestroy(&doclist); return rc; } /* Add doclists for all terms in [pValues] to the hash table [terms]. */ static int insertTerms(fulltext_vtab *v, fts1Hash *terms, sqlite_int64 iRowid, sqlite3_value **pValues){ int i; for(i = 0; i < v->nColumn ; ++i){ char *zText = (char*)sqlite3_value_text(pValues[i]); int rc = buildTerms(v, terms, iRowid, zText, i); if( rc!=SQLITE_OK ) return rc; } return SQLITE_OK; } /* Add empty doclists for all terms in the given row's content to the hash * table [pTerms]. */ static int deleteTerms(fulltext_vtab *v, fts1Hash *pTerms, sqlite_int64 iRowid){ const char **pValues; int i; int rc = content_select(v, iRowid, &pValues); if( rc!=SQLITE_OK ) return rc; for(i = 0 ; i < v->nColumn; ++i) { rc = buildTerms(v, pTerms, iRowid, pValues[i], -1); if( rc!=SQLITE_OK ) break; } freeStringArray(v->nColumn, pValues); return SQLITE_OK; } /* Insert a row into the %_content table; set *piRowid to be the ID of the * new row. Fill [pTerms] with new doclists for the %_term table. */ static int index_insert(fulltext_vtab *v, sqlite3_value *pRequestRowid, sqlite3_value **pValues, sqlite_int64 *piRowid, fts1Hash *pTerms){ int rc; rc = content_insert(v, pRequestRowid, pValues); /* execute an SQL INSERT */ if( rc!=SQLITE_OK ) return rc; *piRowid = sqlite3_last_insert_rowid(v->db); return insertTerms(v, pTerms, *piRowid, pValues); } /* Delete a row from the %_content table; fill [pTerms] with empty doclists * to be written to the %_term table. */ static int index_delete(fulltext_vtab *v, sqlite_int64 iRow, fts1Hash *pTerms){ int rc = deleteTerms(v, pTerms, iRow); if( rc!=SQLITE_OK ) return rc; return content_delete(v, iRow); /* execute an SQL DELETE */ } /* Update a row in the %_content table; fill [pTerms] with new doclists for the * %_term table. */ static int index_update(fulltext_vtab *v, sqlite_int64 iRow, sqlite3_value **pValues, fts1Hash *pTerms){ /* Generate an empty doclist for each term that previously appeared in this * row. */ int rc = deleteTerms(v, pTerms, iRow); if( rc!=SQLITE_OK ) return rc; rc = content_update(v, pValues, iRow); /* execute an SQL UPDATE */ if( rc!=SQLITE_OK ) return rc; /* Now add positions for terms which appear in the updated row. */ return insertTerms(v, pTerms, iRow, pValues); } /* This function implements the xUpdate callback; it is the top-level entry * point for inserting, deleting or updating a row in a full-text table. */ static int fulltextUpdate(sqlite3_vtab *pVtab, int nArg, sqlite3_value **ppArg, sqlite_int64 *pRowid){ fulltext_vtab *v = (fulltext_vtab *) pVtab; fts1Hash terms; /* maps term string -> PosList */ int rc; fts1HashElem *e; TRACE(("FTS1 Update %p\n", pVtab)); fts1HashInit(&terms, FTS1_HASH_STRING, 1); if( nArg<2 ){ rc = index_delete(v, sqlite3_value_int64(ppArg[0]), &terms); } else if( sqlite3_value_type(ppArg[0]) != SQLITE_NULL ){ /* An update: * ppArg[0] = old rowid * ppArg[1] = new rowid * ppArg[2..2+v->nColumn-1] = values * ppArg[2+v->nColumn] = value for magic column (we ignore this) */ sqlite_int64 rowid = sqlite3_value_int64(ppArg[0]); if( sqlite3_value_type(ppArg[1]) != SQLITE_INTEGER || sqlite3_value_int64(ppArg[1]) != rowid ){ rc = SQLITE_ERROR; /* we don't allow changing the rowid */ } else { assert( nArg==2+v->nColumn+1); rc = index_update(v, rowid, &ppArg[2], &terms); } } else { /* An insert: * ppArg[1] = requested rowid * ppArg[2..2+v->nColumn-1] = values * ppArg[2+v->nColumn] = value for magic column (we ignore this) */ assert( nArg==2+v->nColumn+1); rc = index_insert(v, ppArg[1], &ppArg[2], pRowid, &terms); } if( rc==SQLITE_OK ){ /* Write updated doclists to disk. */ for(e=fts1HashFirst(&terms); e; e=fts1HashNext(e)){ DocList *p = fts1HashData(e); rc = index_insert_term(v, fts1HashKey(e), fts1HashKeysize(e), p); if( rc!=SQLITE_OK ) break; } } /* clean up */ for(e=fts1HashFirst(&terms); e; e=fts1HashNext(e)){ DocList *p = fts1HashData(e); docListDelete(p); } fts1HashClear(&terms); return rc; } /* ** Implementation of the snippet() function for FTS1 */ static void snippetFunc( sqlite3_context *pContext, int argc, sqlite3_value **argv ){ fulltext_cursor *pCursor; if( argc<1 ) return; if( sqlite3_value_type(argv[0])!=SQLITE_BLOB || sqlite3_value_bytes(argv[0])!=sizeof(pCursor) ){ sqlite3_result_error(pContext, "illegal first argument to html_snippet",-1); }else{ const char *zStart = "<b>"; const char *zEnd = "</b>"; const char *zEllipsis = "<b>...</b>"; memcpy(&pCursor, sqlite3_value_blob(argv[0]), sizeof(pCursor)); if( argc>=2 ){ zStart = (const char*)sqlite3_value_text(argv[1]); if( argc>=3 ){ zEnd = (const char*)sqlite3_value_text(argv[2]); if( argc>=4 ){ zEllipsis = (const char*)sqlite3_value_text(argv[3]); } } } snippetAllOffsets(pCursor); snippetText(pCursor, zStart, zEnd, zEllipsis); sqlite3_result_text(pContext, pCursor->snippet.zSnippet, pCursor->snippet.nSnippet, SQLITE_STATIC); } } /* ** Implementation of the offsets() function for FTS1 */ static void snippetOffsetsFunc( sqlite3_context *pContext, int argc, sqlite3_value **argv ){ fulltext_cursor *pCursor; if( argc<1 ) return; if( sqlite3_value_type(argv[0])!=SQLITE_BLOB || sqlite3_value_bytes(argv[0])!=sizeof(pCursor) ){ sqlite3_result_error(pContext, "illegal first argument to offsets",-1); }else{ memcpy(&pCursor, sqlite3_value_blob(argv[0]), sizeof(pCursor)); snippetAllOffsets(pCursor); snippetOffsetText(&pCursor->snippet); sqlite3_result_text(pContext, pCursor->snippet.zOffset, pCursor->snippet.nOffset, SQLITE_STATIC); } } /* ** This routine implements the xFindFunction method for the FTS1 ** virtual table. */ static int fulltextFindFunction( sqlite3_vtab *pVtab, int nArg, const char *zName, void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), void **ppArg ){ if( strcmp(zName,"snippet")==0 ){ *pxFunc = snippetFunc; return 1; }else if( strcmp(zName,"offsets")==0 ){ *pxFunc = snippetOffsetsFunc; return 1; } return 0; } /* ** Rename an fts1 table. */ static int fulltextRename( sqlite3_vtab *pVtab, const char *zName ){ fulltext_vtab *p = (fulltext_vtab *)pVtab; int rc = SQLITE_NOMEM; char *zSql = sqlite3_mprintf( "ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';" "ALTER TABLE %Q.'%q_term' RENAME TO '%q_term';" , p->zDb, p->zName, zName , p->zDb, p->zName, zName ); if( zSql ){ rc = sqlite3_exec(p->db, zSql, 0, 0, 0); sqlite3_free(zSql); } return rc; } static const sqlite3_module fulltextModule = { /* iVersion */ 0, /* xCreate */ fulltextCreate, /* xConnect */ fulltextConnect, /* xBestIndex */ fulltextBestIndex, /* xDisconnect */ fulltextDisconnect, /* xDestroy */ fulltextDestroy, /* xOpen */ fulltextOpen, /* xClose */ fulltextClose, /* xFilter */ fulltextFilter, /* xNext */ fulltextNext, /* xEof */ fulltextEof, /* xColumn */ fulltextColumn, /* xRowid */ fulltextRowid, /* xUpdate */ fulltextUpdate, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindFunction */ fulltextFindFunction, /* xRename */ fulltextRename, }; int sqlite3Fts1Init(sqlite3 *db){ sqlite3_overload_function(db, "snippet", -1); sqlite3_overload_function(db, "offsets", -1); return sqlite3_create_module(db, "fts1", &fulltextModule, 0); } #if !SQLITE_CORE #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_fts1_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi){ SQLITE_EXTENSION_INIT2(pApi) return sqlite3Fts1Init(db); } #endif #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS1) */ |
Added ext/fts1/fts1.h.
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 | #include "sqlite3.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ int sqlite3Fts1Init(sqlite3 *db); #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ |
Added ext/fts1/fts1_hash.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 | /* ** 2001 September 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This is the implementation of generic hash-tables used in SQLite. ** We've modified it slightly to serve as a standalone hash table ** implementation for the full-text indexing module. */ #include <assert.h> #include <stdlib.h> #include <string.h> /* ** The code in this file is only compiled if: ** ** * The FTS1 module is being built as an extension ** (in which case SQLITE_CORE is not defined), or ** ** * The FTS1 module is being built into the core of ** SQLite (in which case SQLITE_ENABLE_FTS1 is defined). */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS1) #include "fts1_hash.h" static void *malloc_and_zero(int n){ void *p = malloc(n); if( p ){ memset(p, 0, n); } return p; } /* Turn bulk memory into a hash table object by initializing the ** fields of the Hash structure. ** ** "pNew" is a pointer to the hash table that is to be initialized. ** keyClass is one of the constants ** FTS1_HASH_BINARY or FTS1_HASH_STRING. The value of keyClass ** determines what kind of key the hash table will use. "copyKey" is ** true if the hash table should make its own private copy of keys and ** false if it should just use the supplied pointer. */ void sqlite3Fts1HashInit(fts1Hash *pNew, int keyClass, int copyKey){ assert( pNew!=0 ); assert( keyClass>=FTS1_HASH_STRING && keyClass<=FTS1_HASH_BINARY ); pNew->keyClass = keyClass; pNew->copyKey = copyKey; pNew->first = 0; pNew->count = 0; pNew->htsize = 0; pNew->ht = 0; pNew->xMalloc = malloc_and_zero; pNew->xFree = free; } /* Remove all entries from a hash table. Reclaim all memory. ** Call this routine to delete a hash table or to reset a hash table ** to the empty state. */ void sqlite3Fts1HashClear(fts1Hash *pH){ fts1HashElem *elem; /* For looping over all elements of the table */ assert( pH!=0 ); elem = pH->first; pH->first = 0; if( pH->ht ) pH->xFree(pH->ht); pH->ht = 0; pH->htsize = 0; while( elem ){ fts1HashElem *next_elem = elem->next; if( pH->copyKey && elem->pKey ){ pH->xFree(elem->pKey); } pH->xFree(elem); elem = next_elem; } pH->count = 0; } /* ** Hash and comparison functions when the mode is FTS1_HASH_STRING */ static int strHash(const void *pKey, int nKey){ const char *z = (const char *)pKey; int h = 0; if( nKey<=0 ) nKey = (int) strlen(z); while( nKey > 0 ){ h = (h<<3) ^ h ^ *z++; nKey--; } return h & 0x7fffffff; } static int strCompare(const void *pKey1, int n1, const void *pKey2, int n2){ if( n1!=n2 ) return 1; return strncmp((const char*)pKey1,(const char*)pKey2,n1); } /* ** Hash and comparison functions when the mode is FTS1_HASH_BINARY */ static int binHash(const void *pKey, int nKey){ int h = 0; const char *z = (const char *)pKey; while( nKey-- > 0 ){ h = (h<<3) ^ h ^ *(z++); } return h & 0x7fffffff; } static int binCompare(const void *pKey1, int n1, const void *pKey2, int n2){ if( n1!=n2 ) return 1; return memcmp(pKey1,pKey2,n1); } /* ** Return a pointer to the appropriate hash function given the key class. ** ** The C syntax in this function definition may be unfamilar to some ** programmers, so we provide the following additional explanation: ** ** The name of the function is "hashFunction". The function takes a ** single parameter "keyClass". The return value of hashFunction() ** is a pointer to another function. Specifically, the return value ** of hashFunction() is a pointer to a function that takes two parameters ** with types "const void*" and "int" and returns an "int". */ static int (*hashFunction(int keyClass))(const void*,int){ if( keyClass==FTS1_HASH_STRING ){ return &strHash; }else{ assert( keyClass==FTS1_HASH_BINARY ); return &binHash; } } /* ** Return a pointer to the appropriate hash function given the key class. ** ** For help in interpreted the obscure C code in the function definition, ** see the header comment on the previous function. */ static int (*compareFunction(int keyClass))(const void*,int,const void*,int){ if( keyClass==FTS1_HASH_STRING ){ return &strCompare; }else{ assert( keyClass==FTS1_HASH_BINARY ); return &binCompare; } } /* Link an element into the hash table */ static void insertElement( fts1Hash *pH, /* The complete hash table */ struct _fts1ht *pEntry, /* The entry into which pNew is inserted */ fts1HashElem *pNew /* The element to be inserted */ ){ fts1HashElem *pHead; /* First element already in pEntry */ pHead = pEntry->chain; if( pHead ){ pNew->next = pHead; pNew->prev = pHead->prev; if( pHead->prev ){ pHead->prev->next = pNew; } else { pH->first = pNew; } pHead->prev = pNew; }else{ pNew->next = pH->first; if( pH->first ){ pH->first->prev = pNew; } pNew->prev = 0; pH->first = pNew; } pEntry->count++; pEntry->chain = pNew; } /* Resize the hash table so that it cantains "new_size" buckets. ** "new_size" must be a power of 2. The hash table might fail ** to resize if sqliteMalloc() fails. */ static void rehash(fts1Hash *pH, int new_size){ struct _fts1ht *new_ht; /* The new hash table */ fts1HashElem *elem, *next_elem; /* For looping over existing elements */ int (*xHash)(const void*,int); /* The hash function */ assert( (new_size & (new_size-1))==0 ); new_ht = (struct _fts1ht *)pH->xMalloc( new_size*sizeof(struct _fts1ht) ); if( new_ht==0 ) return; if( pH->ht ) pH->xFree(pH->ht); pH->ht = new_ht; pH->htsize = new_size; xHash = hashFunction(pH->keyClass); for(elem=pH->first, pH->first=0; elem; elem = next_elem){ int h = (*xHash)(elem->pKey, elem->nKey) & (new_size-1); next_elem = elem->next; insertElement(pH, &new_ht[h], elem); } } /* This function (for internal use only) locates an element in an ** hash table that matches the given key. The hash for this key has ** already been computed and is passed as the 4th parameter. */ static fts1HashElem *findElementGivenHash( const fts1Hash *pH, /* The pH to be searched */ const void *pKey, /* The key we are searching for */ int nKey, int h /* The hash for this key. */ ){ fts1HashElem *elem; /* Used to loop thru the element list */ int count; /* Number of elements left to test */ int (*xCompare)(const void*,int,const void*,int); /* comparison function */ if( pH->ht ){ struct _fts1ht *pEntry = &pH->ht[h]; elem = pEntry->chain; count = pEntry->count; xCompare = compareFunction(pH->keyClass); while( count-- && elem ){ if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){ return elem; } elem = elem->next; } } return 0; } /* Remove a single entry from the hash table given a pointer to that ** element and a hash on the element's key. */ static void removeElementGivenHash( fts1Hash *pH, /* The pH containing "elem" */ fts1HashElem* elem, /* The element to be removed from the pH */ int h /* Hash value for the element */ ){ struct _fts1ht *pEntry; if( elem->prev ){ elem->prev->next = elem->next; }else{ pH->first = elem->next; } if( elem->next ){ elem->next->prev = elem->prev; } pEntry = &pH->ht[h]; if( pEntry->chain==elem ){ pEntry->chain = elem->next; } pEntry->count--; if( pEntry->count<=0 ){ pEntry->chain = 0; } if( pH->copyKey && elem->pKey ){ pH->xFree(elem->pKey); } pH->xFree( elem ); pH->count--; if( pH->count<=0 ){ assert( pH->first==0 ); assert( pH->count==0 ); fts1HashClear(pH); } } /* Attempt to locate an element of the hash table pH with a key ** that matches pKey,nKey. Return the data for this element if it is ** found, or NULL if there is no match. */ void *sqlite3Fts1HashFind(const fts1Hash *pH, const void *pKey, int nKey){ int h; /* A hash on key */ fts1HashElem *elem; /* The element that matches key */ int (*xHash)(const void*,int); /* The hash function */ if( pH==0 || pH->ht==0 ) return 0; xHash = hashFunction(pH->keyClass); assert( xHash!=0 ); h = (*xHash)(pKey,nKey); assert( (pH->htsize & (pH->htsize-1))==0 ); elem = findElementGivenHash(pH,pKey,nKey, h & (pH->htsize-1)); return elem ? elem->data : 0; } /* Insert an element into the hash table pH. The key is pKey,nKey ** and the data is "data". ** ** If no element exists with a matching key, then a new ** element is created. A copy of the key is made if the copyKey ** flag is set. NULL is returned. ** ** If another element already exists with the same key, then the ** new data replaces the old data and the old data is returned. ** The key is not copied in this instance. If a malloc fails, then ** the new data is returned and the hash table is unchanged. ** ** If the "data" parameter to this function is NULL, then the ** element corresponding to "key" is removed from the hash table. */ void *sqlite3Fts1HashInsert( fts1Hash *pH, /* The hash table to insert into */ const void *pKey, /* The key */ int nKey, /* Number of bytes in the key */ void *data /* The data */ ){ int hraw; /* Raw hash value of the key */ int h; /* the hash of the key modulo hash table size */ fts1HashElem *elem; /* Used to loop thru the element list */ fts1HashElem *new_elem; /* New element added to the pH */ int (*xHash)(const void*,int); /* The hash function */ assert( pH!=0 ); xHash = hashFunction(pH->keyClass); assert( xHash!=0 ); hraw = (*xHash)(pKey, nKey); assert( (pH->htsize & (pH->htsize-1))==0 ); h = hraw & (pH->htsize-1); elem = findElementGivenHash(pH,pKey,nKey,h); if( elem ){ void *old_data = elem->data; if( data==0 ){ removeElementGivenHash(pH,elem,h); }else{ elem->data = data; } return old_data; } if( data==0 ) return 0; new_elem = (fts1HashElem*)pH->xMalloc( sizeof(fts1HashElem) ); if( new_elem==0 ) return data; if( pH->copyKey && pKey!=0 ){ new_elem->pKey = pH->xMalloc( nKey ); if( new_elem->pKey==0 ){ pH->xFree(new_elem); return data; } memcpy((void*)new_elem->pKey, pKey, nKey); }else{ new_elem->pKey = (void*)pKey; } new_elem->nKey = nKey; pH->count++; if( pH->htsize==0 ){ rehash(pH,8); if( pH->htsize==0 ){ pH->count = 0; pH->xFree(new_elem); return data; } } if( pH->count > pH->htsize ){ rehash(pH,pH->htsize*2); } assert( pH->htsize>0 ); assert( (pH->htsize & (pH->htsize-1))==0 ); h = hraw & (pH->htsize-1); insertElement(pH, &pH->ht[h], new_elem); new_elem->data = data; return 0; } #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS1) */ |
Added ext/fts1/fts1_hash.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 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 | /* ** 2001 September 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This is the header file for the generic hash-table implementation ** used in SQLite. We've modified it slightly to serve as a standalone ** hash table implementation for the full-text indexing module. ** */ #ifndef _FTS1_HASH_H_ #define _FTS1_HASH_H_ /* Forward declarations of structures. */ typedef struct fts1Hash fts1Hash; typedef struct fts1HashElem fts1HashElem; /* A complete hash table is an instance of the following structure. ** The internals of this structure are intended to be opaque -- client ** code should not attempt to access or modify the fields of this structure ** directly. Change this structure only by using the routines below. ** However, many of the "procedures" and "functions" for modifying and ** accessing this structure are really macros, so we can't really make ** this structure opaque. */ struct fts1Hash { char keyClass; /* HASH_INT, _POINTER, _STRING, _BINARY */ char copyKey; /* True if copy of key made on insert */ int count; /* Number of entries in this table */ fts1HashElem *first; /* The first element of the array */ void *(*xMalloc)(int); /* malloc() function to use */ void (*xFree)(void *); /* free() function to use */ int htsize; /* Number of buckets in the hash table */ struct _fts1ht { /* the hash table */ int count; /* Number of entries with this hash */ fts1HashElem *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. ** ** Again, this structure is intended to be opaque, but it can't really ** be opaque because it is used by macros. */ struct fts1HashElem { fts1HashElem *next, *prev; /* Next and previous elements in the table */ void *data; /* Data associated with this element */ void *pKey; int nKey; /* Key associated with this element */ }; /* ** There are 2 different modes of operation for a hash table: ** ** FTS1_HASH_STRING pKey points to a string that is nKey bytes long ** (including the null-terminator, if any). Case ** is respected in comparisons. ** ** FTS1_HASH_BINARY pKey points to binary data nKey bytes long. ** memcmp() is used to compare keys. ** ** A copy of the key is made if the copyKey parameter to fts1HashInit is 1. */ #define FTS1_HASH_STRING 1 #define FTS1_HASH_BINARY 2 /* ** Access routines. To delete, insert a NULL pointer. */ void sqlite3Fts1HashInit(fts1Hash*, int keytype, int copyKey); void *sqlite3Fts1HashInsert(fts1Hash*, const void *pKey, int nKey, void *pData); void *sqlite3Fts1HashFind(const fts1Hash*, const void *pKey, int nKey); void sqlite3Fts1HashClear(fts1Hash*); /* ** Shorthand for the functions above */ #define fts1HashInit sqlite3Fts1HashInit #define fts1HashInsert sqlite3Fts1HashInsert #define fts1HashFind sqlite3Fts1HashFind #define fts1HashClear sqlite3Fts1HashClear /* ** Macros for looping over all elements of a hash table. The idiom is ** like this: ** ** fts1Hash h; ** fts1HashElem *p; ** ... ** for(p=fts1HashFirst(&h); p; p=fts1HashNext(p)){ ** SomeStructure *pData = fts1HashData(p); ** // do something with pData ** } */ #define fts1HashFirst(H) ((H)->first) #define fts1HashNext(E) ((E)->next) #define fts1HashData(E) ((E)->data) #define fts1HashKey(E) ((E)->pKey) #define fts1HashKeysize(E) ((E)->nKey) /* ** Number of entries in a hash table */ #define fts1HashCount(H) ((H)->count) #endif /* _FTS1_HASH_H_ */ |
Added ext/fts1/fts1_porter.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 | /* ** 2006 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. ** ************************************************************************* ** Implementation of the full-text-search tokenizer that implements ** a Porter stemmer. */ /* ** The code in this file is only compiled if: ** ** * The FTS1 module is being built as an extension ** (in which case SQLITE_CORE is not defined), or ** ** * The FTS1 module is being built into the core of ** SQLite (in which case SQLITE_ENABLE_FTS1 is defined). */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS1) #include <assert.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <ctype.h> #include "fts1_tokenizer.h" /* ** Class derived from sqlite3_tokenizer */ typedef struct porter_tokenizer { sqlite3_tokenizer base; /* Base class */ } porter_tokenizer; /* ** Class derived from sqlit3_tokenizer_cursor */ typedef struct porter_tokenizer_cursor { sqlite3_tokenizer_cursor base; const char *zInput; /* input we are tokenizing */ int nInput; /* size of the input */ int iOffset; /* current position in zInput */ int iToken; /* index of next token to be returned */ char *zToken; /* storage for current token */ int nAllocated; /* space allocated to zToken buffer */ } porter_tokenizer_cursor; /* Forward declaration */ static const sqlite3_tokenizer_module porterTokenizerModule; /* ** Create a new tokenizer instance. */ static int porterCreate( int argc, const char * const *argv, sqlite3_tokenizer **ppTokenizer ){ porter_tokenizer *t; t = (porter_tokenizer *) calloc(sizeof(*t), 1); if( t==NULL ) return SQLITE_NOMEM; *ppTokenizer = &t->base; return SQLITE_OK; } /* ** Destroy a tokenizer */ static int porterDestroy(sqlite3_tokenizer *pTokenizer){ free(pTokenizer); return SQLITE_OK; } /* ** Prepare to begin tokenizing a particular string. The input ** string to be tokenized is zInput[0..nInput-1]. A cursor ** used to incrementally tokenize this string is returned in ** *ppCursor. */ static int porterOpen( sqlite3_tokenizer *pTokenizer, /* The tokenizer */ const char *zInput, int nInput, /* String to be tokenized */ sqlite3_tokenizer_cursor **ppCursor /* OUT: Tokenization cursor */ ){ porter_tokenizer_cursor *c; c = (porter_tokenizer_cursor *) malloc(sizeof(*c)); if( c==NULL ) return SQLITE_NOMEM; c->zInput = zInput; if( zInput==0 ){ c->nInput = 0; }else if( nInput<0 ){ c->nInput = (int)strlen(zInput); }else{ c->nInput = nInput; } c->iOffset = 0; /* start tokenizing at the beginning */ c->iToken = 0; c->zToken = NULL; /* no space allocated, yet. */ c->nAllocated = 0; *ppCursor = &c->base; return SQLITE_OK; } /* ** Close a tokenization cursor previously opened by a call to ** porterOpen() above. */ static int porterClose(sqlite3_tokenizer_cursor *pCursor){ porter_tokenizer_cursor *c = (porter_tokenizer_cursor *) pCursor; free(c->zToken); free(c); return SQLITE_OK; } /* ** Vowel or consonant */ static const char cType[] = { 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 2, 1 }; /* ** isConsonant() and isVowel() determine if their first character in ** the string they point to is a consonant or a vowel, according ** to Porter ruls. ** ** A consonate is any letter other than 'a', 'e', 'i', 'o', or 'u'. ** 'Y' is a consonant unless it follows another consonant, ** in which case it is a vowel. ** ** In these routine, the letters are in reverse order. So the 'y' rule ** is that 'y' is a consonant unless it is followed by another ** consonent. */ static int isVowel(const char*); static int isConsonant(const char *z){ int j; char x = *z; if( x==0 ) return 0; assert( x>='a' && x<='z' ); j = cType[x-'a']; if( j<2 ) return j; return z[1]==0 || isVowel(z + 1); } static int isVowel(const char *z){ int j; char x = *z; if( x==0 ) return 0; assert( x>='a' && x<='z' ); j = cType[x-'a']; if( j<2 ) return 1-j; return isConsonant(z + 1); } /* ** Let any sequence of one or more vowels be represented by V and let ** C be sequence of one or more consonants. Then every word can be ** represented as: ** ** [C] (VC){m} [V] ** ** In prose: A word is an optional consonant followed by zero or ** vowel-consonant pairs followed by an optional vowel. "m" is the ** number of vowel consonant pairs. This routine computes the value ** of m for the first i bytes of a word. ** ** Return true if the m-value for z is 1 or more. In other words, ** return true if z contains at least one vowel that is followed ** by a consonant. ** ** In this routine z[] is in reverse order. So we are really looking ** for an instance of of a consonant followed by a vowel. */ static int m_gt_0(const char *z){ while( isVowel(z) ){ z++; } if( *z==0 ) return 0; while( isConsonant(z) ){ z++; } return *z!=0; } /* Like mgt0 above except we are looking for a value of m which is ** exactly 1 */ static int m_eq_1(const char *z){ while( isVowel(z) ){ z++; } if( *z==0 ) return 0; while( isConsonant(z) ){ z++; } if( *z==0 ) return 0; while( isVowel(z) ){ z++; } if( *z==0 ) return 1; while( isConsonant(z) ){ z++; } return *z==0; } /* Like mgt0 above except we are looking for a value of m>1 instead ** or m>0 */ static int m_gt_1(const char *z){ while( isVowel(z) ){ z++; } if( *z==0 ) return 0; while( isConsonant(z) ){ z++; } if( *z==0 ) return 0; while( isVowel(z) ){ z++; } if( *z==0 ) return 0; while( isConsonant(z) ){ z++; } return *z!=0; } /* ** Return TRUE if there is a vowel anywhere within z[0..n-1] */ static int hasVowel(const char *z){ while( isConsonant(z) ){ z++; } return *z!=0; } /* ** Return TRUE if the word ends in a double consonant. ** ** The text is reversed here. So we are really looking at ** the first two characters of z[]. */ static int doubleConsonant(const char *z){ return isConsonant(z) && z[0]==z[1] && isConsonant(z+1); } /* ** Return TRUE if the word ends with three letters which ** are consonant-vowel-consonent and where the final consonant ** is not 'w', 'x', or 'y'. ** ** The word is reversed here. So we are really checking the ** first three letters and the first one cannot be in [wxy]. */ static int star_oh(const char *z){ return z[0]!=0 && isConsonant(z) && z[0]!='w' && z[0]!='x' && z[0]!='y' && z[1]!=0 && isVowel(z+1) && z[2]!=0 && isConsonant(z+2); } /* ** If the word ends with zFrom and xCond() is true for the stem ** of the word that preceeds the zFrom ending, then change the ** ending to zTo. ** ** The input word *pz and zFrom are both in reverse order. zTo ** is in normal order. ** ** Return TRUE if zFrom matches. Return FALSE if zFrom does not ** match. Not that TRUE is returned even if xCond() fails and ** no substitution occurs. */ static int stem( char **pz, /* The word being stemmed (Reversed) */ const char *zFrom, /* If the ending matches this... (Reversed) */ const char *zTo, /* ... change the ending to this (not reversed) */ int (*xCond)(const char*) /* Condition that must be true */ ){ char *z = *pz; while( *zFrom && *zFrom==*z ){ z++; zFrom++; } if( *zFrom!=0 ) return 0; if( xCond && !xCond(z) ) return 1; while( *zTo ){ *(--z) = *(zTo++); } *pz = z; return 1; } /* ** This is the fallback stemmer used when the porter stemmer is ** inappropriate. The input word is copied into the output with ** US-ASCII case folding. If the input word is too long (more ** than 20 bytes if it contains no digits or more than 6 bytes if ** it contains digits) then word is truncated to 20 or 6 bytes ** by taking 10 or 3 bytes from the beginning and end. */ static void copy_stemmer(const char *zIn, int nIn, char *zOut, int *pnOut){ int i, mx, j; int hasDigit = 0; for(i=0; i<nIn; i++){ int c = zIn[i]; if( c>='A' && c<='Z' ){ zOut[i] = c - 'A' + 'a'; }else{ if( c>='0' && c<='9' ) hasDigit = 1; zOut[i] = c; } } mx = hasDigit ? 3 : 10; if( nIn>mx*2 ){ for(j=mx, i=nIn-mx; i<nIn; i++, j++){ zOut[j] = zOut[i]; } i = j; } zOut[i] = 0; *pnOut = i; } /* ** Stem the input word zIn[0..nIn-1]. Store the output in zOut. ** zOut is at least big enough to hold nIn bytes. Write the actual ** size of the output word (exclusive of the '\0' terminator) into *pnOut. ** ** Any upper-case characters in the US-ASCII character set ([A-Z]) ** are converted to lower case. Upper-case UTF characters are ** unchanged. ** ** Words that are longer than about 20 bytes are stemmed by retaining ** a few bytes from the beginning and the end of the word. If the ** word contains digits, 3 bytes are taken from the beginning and ** 3 bytes from the end. For long words without digits, 10 bytes ** are taken from each end. US-ASCII case folding still applies. ** ** If the input word contains not digits but does characters not ** in [a-zA-Z] then no stemming is attempted and this routine just ** copies the input into the input into the output with US-ASCII ** case folding. ** ** Stemming never increases the length of the word. So there is ** no chance of overflowing the zOut buffer. */ static void porter_stemmer(const char *zIn, int nIn, char *zOut, int *pnOut){ int i, j, c; char zReverse[28]; char *z, *z2; if( nIn<3 || nIn>=sizeof(zReverse)-7 ){ /* The word is too big or too small for the porter stemmer. ** Fallback to the copy stemmer */ copy_stemmer(zIn, nIn, zOut, pnOut); return; } for(i=0, j=sizeof(zReverse)-6; i<nIn; i++, j--){ c = zIn[i]; if( c>='A' && c<='Z' ){ zReverse[j] = c + 'a' - 'A'; }else if( c>='a' && c<='z' ){ zReverse[j] = c; }else{ /* The use of a character not in [a-zA-Z] means that we fallback ** to the copy stemmer */ copy_stemmer(zIn, nIn, zOut, pnOut); return; } } memset(&zReverse[sizeof(zReverse)-5], 0, 5); z = &zReverse[j+1]; /* Step 1a */ if( z[0]=='s' ){ if( !stem(&z, "sess", "ss", 0) && !stem(&z, "sei", "i", 0) && !stem(&z, "ss", "ss", 0) ){ z++; } } /* Step 1b */ z2 = z; if( stem(&z, "dee", "ee", m_gt_0) ){ /* Do nothing. The work was all in the test */ }else if( (stem(&z, "gni", "", hasVowel) || stem(&z, "de", "", hasVowel)) && z!=z2 ){ if( stem(&z, "ta", "ate", 0) || stem(&z, "lb", "ble", 0) || stem(&z, "zi", "ize", 0) ){ /* Do nothing. The work was all in the test */ }else if( doubleConsonant(z) && (*z!='l' && *z!='s' && *z!='z') ){ z++; }else if( m_eq_1(z) && star_oh(z) ){ *(--z) = 'e'; } } /* Step 1c */ if( z[0]=='y' && hasVowel(z+1) ){ z[0] = 'i'; } /* Step 2 */ switch( z[1] ){ case 'a': stem(&z, "lanoita", "ate", m_gt_0) || stem(&z, "lanoit", "tion", m_gt_0); break; case 'c': stem(&z, "icne", "ence", m_gt_0) || stem(&z, "icna", "ance", m_gt_0); break; case 'e': stem(&z, "rezi", "ize", m_gt_0); break; case 'g': stem(&z, "igol", "log", m_gt_0); break; case 'l': stem(&z, "ilb", "ble", m_gt_0) || stem(&z, "illa", "al", m_gt_0) || stem(&z, "iltne", "ent", m_gt_0) || stem(&z, "ile", "e", m_gt_0) || stem(&z, "ilsuo", "ous", m_gt_0); break; case 'o': stem(&z, "noitazi", "ize", m_gt_0) || stem(&z, "noita", "ate", m_gt_0) || stem(&z, "rota", "ate", m_gt_0); break; case 's': stem(&z, "msila", "al", m_gt_0) || stem(&z, "ssenevi", "ive", m_gt_0) || stem(&z, "ssenluf", "ful", m_gt_0) || stem(&z, "ssensuo", "ous", m_gt_0); break; case 't': stem(&z, "itila", "al", m_gt_0) || stem(&z, "itivi", "ive", m_gt_0) || stem(&z, "itilib", "ble", m_gt_0); break; } /* Step 3 */ switch( z[0] ){ case 'e': stem(&z, "etaci", "ic", m_gt_0) || stem(&z, "evita", "", m_gt_0) || stem(&z, "ezila", "al", m_gt_0); break; case 'i': stem(&z, "itici", "ic", m_gt_0); break; case 'l': stem(&z, "laci", "ic", m_gt_0) || stem(&z, "luf", "", m_gt_0); break; case 's': stem(&z, "ssen", "", m_gt_0); break; } /* Step 4 */ switch( z[1] ){ case 'a': if( z[0]=='l' && m_gt_1(z+2) ){ z += 2; } break; case 'c': if( z[0]=='e' && z[2]=='n' && (z[3]=='a' || z[3]=='e') && m_gt_1(z+4) ){ z += 4; } break; case 'e': if( z[0]=='r' && m_gt_1(z+2) ){ z += 2; } break; case 'i': if( z[0]=='c' && m_gt_1(z+2) ){ z += 2; } break; case 'l': if( z[0]=='e' && z[2]=='b' && (z[3]=='a' || z[3]=='i') && m_gt_1(z+4) ){ z += 4; } break; case 'n': if( z[0]=='t' ){ if( z[2]=='a' ){ if( m_gt_1(z+3) ){ z += 3; } }else if( z[2]=='e' ){ stem(&z, "tneme", "", m_gt_1) || stem(&z, "tnem", "", m_gt_1) || stem(&z, "tne", "", m_gt_1); } } break; case 'o': if( z[0]=='u' ){ if( m_gt_1(z+2) ){ z += 2; } }else if( z[3]=='s' || z[3]=='t' ){ stem(&z, "noi", "", m_gt_1); } break; case 's': if( z[0]=='m' && z[2]=='i' && m_gt_1(z+3) ){ z += 3; } break; case 't': stem(&z, "eta", "", m_gt_1) || stem(&z, "iti", "", m_gt_1); break; case 'u': if( z[0]=='s' && z[2]=='o' && m_gt_1(z+3) ){ z += 3; } break; case 'v': case 'z': if( z[0]=='e' && z[2]=='i' && m_gt_1(z+3) ){ z += 3; } break; } /* Step 5a */ if( z[0]=='e' ){ if( m_gt_1(z+1) ){ z++; }else if( m_eq_1(z+1) && !star_oh(z+1) ){ z++; } } /* Step 5b */ if( m_gt_1(z) && z[0]=='l' && z[1]=='l' ){ z++; } /* z[] is now the stemmed word in reverse order. Flip it back ** around into forward order and return. */ *pnOut = i = strlen(z); zOut[i] = 0; while( *z ){ zOut[--i] = *(z++); } } /* ** Characters that can be part of a token. We assume any character ** whose value is greater than 0x80 (any UTF character) can be ** part of a token. In other words, delimiters all must have ** values of 0x7f or lower. */ static const char isIdChar[] = { /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */ }; #define idChar(C) (((ch=C)&0x80)!=0 || (ch>0x2f && isIdChar[ch-0x30])) #define isDelim(C) (((ch=C)&0x80)==0 && (ch<0x30 || !isIdChar[ch-0x30])) /* ** Extract the next token from a tokenization cursor. The cursor must ** have been opened by a prior call to porterOpen(). */ static int porterNext( sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by porterOpen */ const char **pzToken, /* OUT: *pzToken is the token text */ int *pnBytes, /* OUT: Number of bytes in token */ int *piStartOffset, /* OUT: Starting offset of token */ int *piEndOffset, /* OUT: Ending offset of token */ int *piPosition /* OUT: Position integer of token */ ){ porter_tokenizer_cursor *c = (porter_tokenizer_cursor *) pCursor; const char *z = c->zInput; while( c->iOffset<c->nInput ){ int iStartOffset, ch; /* Scan past delimiter characters */ while( c->iOffset<c->nInput && isDelim(z[c->iOffset]) ){ c->iOffset++; } /* Count non-delimiter characters. */ iStartOffset = c->iOffset; while( c->iOffset<c->nInput && !isDelim(z[c->iOffset]) ){ c->iOffset++; } if( c->iOffset>iStartOffset ){ int n = c->iOffset-iStartOffset; if( n>c->nAllocated ){ c->nAllocated = n+20; c->zToken = realloc(c->zToken, c->nAllocated); if( c->zToken==NULL ) return SQLITE_NOMEM; } porter_stemmer(&z[iStartOffset], n, c->zToken, pnBytes); *pzToken = c->zToken; *piStartOffset = iStartOffset; *piEndOffset = c->iOffset; *piPosition = c->iToken++; return SQLITE_OK; } } return SQLITE_DONE; } /* ** The set of routines that implement the porter-stemmer tokenizer */ static const sqlite3_tokenizer_module porterTokenizerModule = { 0, porterCreate, porterDestroy, porterOpen, porterClose, porterNext, }; /* ** Allocate a new porter tokenizer. Return a pointer to the new ** tokenizer in *ppModule */ void sqlite3Fts1PorterTokenizerModule( sqlite3_tokenizer_module const**ppModule ){ *ppModule = &porterTokenizerModule; } #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS1) */ |
Added ext/fts1/fts1_tokenizer.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 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 | /* ** 2006 July 10 ** ** The author disclaims copyright to this source code. ** ************************************************************************* ** Defines the interface to tokenizers used by fulltext-search. There ** are three basic components: ** ** sqlite3_tokenizer_module is a singleton defining the tokenizer ** interface functions. This is essentially the class structure for ** tokenizers. ** ** sqlite3_tokenizer is used to define a particular tokenizer, perhaps ** including customization information defined at creation time. ** ** sqlite3_tokenizer_cursor is generated by a tokenizer to generate ** tokens from a particular input. */ #ifndef _FTS1_TOKENIZER_H_ #define _FTS1_TOKENIZER_H_ /* TODO(shess) Only used for SQLITE_OK and SQLITE_DONE at this time. ** If tokenizers are to be allowed to call sqlite3_*() functions, then ** we will need a way to register the API consistently. */ #include "sqlite3.h" /* ** Structures used by the tokenizer interface. */ typedef struct sqlite3_tokenizer sqlite3_tokenizer; typedef struct sqlite3_tokenizer_cursor sqlite3_tokenizer_cursor; typedef struct sqlite3_tokenizer_module sqlite3_tokenizer_module; struct sqlite3_tokenizer_module { int iVersion; /* currently 0 */ /* ** Create and destroy a tokenizer. argc/argv are passed down from ** the fulltext virtual table creation to allow customization. */ int (*xCreate)(int argc, const char *const*argv, sqlite3_tokenizer **ppTokenizer); int (*xDestroy)(sqlite3_tokenizer *pTokenizer); /* ** Tokenize a particular input. Call xOpen() to prepare to ** tokenize, xNext() repeatedly until it returns SQLITE_DONE, then ** xClose() to free any internal state. The pInput passed to ** xOpen() must exist until the cursor is closed. The ppToken ** result from xNext() is only valid until the next call to xNext() ** or until xClose() is called. */ /* TODO(shess) current implementation requires pInput to be ** nul-terminated. This should either be fixed, or pInput/nBytes ** should be converted to zInput. */ int (*xOpen)(sqlite3_tokenizer *pTokenizer, const char *pInput, int nBytes, sqlite3_tokenizer_cursor **ppCursor); int (*xClose)(sqlite3_tokenizer_cursor *pCursor); int (*xNext)(sqlite3_tokenizer_cursor *pCursor, const char **ppToken, int *pnBytes, int *piStartOffset, int *piEndOffset, int *piPosition); }; struct sqlite3_tokenizer { const sqlite3_tokenizer_module *pModule; /* The module for this tokenizer */ /* Tokenizer implementations will typically add additional fields */ }; struct sqlite3_tokenizer_cursor { sqlite3_tokenizer *pTokenizer; /* Tokenizer for this cursor. */ /* Tokenizer implementations will typically add additional fields */ }; /* ** Get the module for a tokenizer which generates tokens based on a ** set of non-token characters. The default is to break tokens at any ** non-alnum character, though the set of delimiters can also be ** specified by the first argv argument to xCreate(). */ /* TODO(shess) This doesn't belong here. Need some sort of ** registration process. */ void sqlite3Fts1SimpleTokenizerModule(sqlite3_tokenizer_module const**ppModule); void sqlite3Fts1PorterTokenizerModule(sqlite3_tokenizer_module const**ppModule); #endif /* _FTS1_TOKENIZER_H_ */ |
Added ext/fts1/fts1_tokenizer1.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 | /* ** The author disclaims copyright to this source code. ** ************************************************************************* ** Implementation of the "simple" full-text-search tokenizer. */ /* ** The code in this file is only compiled if: ** ** * The FTS1 module is being built as an extension ** (in which case SQLITE_CORE is not defined), or ** ** * The FTS1 module is being built into the core of ** SQLite (in which case SQLITE_ENABLE_FTS1 is defined). */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS1) #include <assert.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <ctype.h> #include "fts1_tokenizer.h" typedef struct simple_tokenizer { sqlite3_tokenizer base; char delim[128]; /* flag ASCII delimiters */ } simple_tokenizer; typedef struct simple_tokenizer_cursor { sqlite3_tokenizer_cursor base; const char *pInput; /* input we are tokenizing */ int nBytes; /* size of the input */ int iOffset; /* current position in pInput */ int iToken; /* index of next token to be returned */ char *pToken; /* storage for current token */ int nTokenAllocated; /* space allocated to zToken buffer */ } simple_tokenizer_cursor; /* Forward declaration */ static const sqlite3_tokenizer_module simpleTokenizerModule; static int isDelim(simple_tokenizer *t, unsigned char c){ return c<0x80 && t->delim[c]; } /* ** Create a new tokenizer instance. */ static int simpleCreate( int argc, const char * const *argv, sqlite3_tokenizer **ppTokenizer ){ simple_tokenizer *t; t = (simple_tokenizer *) calloc(sizeof(*t), 1); if( t==NULL ) return SQLITE_NOMEM; /* TODO(shess) Delimiters need to remain the same from run to run, ** else we need to reindex. One solution would be a meta-table to ** track such information in the database, then we'd only want this ** information on the initial create. */ if( argc>1 ){ int i, n = strlen(argv[1]); for(i=0; i<n; i++){ unsigned char ch = argv[1][i]; /* We explicitly don't support UTF-8 delimiters for now. */ if( ch>=0x80 ){ free(t); return SQLITE_ERROR; } t->delim[ch] = 1; } } else { /* Mark non-alphanumeric ASCII characters as delimiters */ int i; for(i=1; i<0x80; i++){ t->delim[i] = !isalnum(i); } } *ppTokenizer = &t->base; return SQLITE_OK; } /* ** Destroy a tokenizer */ static int simpleDestroy(sqlite3_tokenizer *pTokenizer){ free(pTokenizer); return SQLITE_OK; } /* ** Prepare to begin tokenizing a particular string. The input ** string to be tokenized is pInput[0..nBytes-1]. A cursor ** used to incrementally tokenize this string is returned in ** *ppCursor. */ static int simpleOpen( sqlite3_tokenizer *pTokenizer, /* The tokenizer */ const char *pInput, int nBytes, /* String to be tokenized */ sqlite3_tokenizer_cursor **ppCursor /* OUT: Tokenization cursor */ ){ simple_tokenizer_cursor *c; c = (simple_tokenizer_cursor *) malloc(sizeof(*c)); if( c==NULL ) return SQLITE_NOMEM; c->pInput = pInput; if( pInput==0 ){ c->nBytes = 0; }else if( nBytes<0 ){ c->nBytes = (int)strlen(pInput); }else{ c->nBytes = nBytes; } c->iOffset = 0; /* start tokenizing at the beginning */ c->iToken = 0; c->pToken = NULL; /* no space allocated, yet. */ c->nTokenAllocated = 0; *ppCursor = &c->base; return SQLITE_OK; } /* ** Close a tokenization cursor previously opened by a call to ** simpleOpen() above. */ static int simpleClose(sqlite3_tokenizer_cursor *pCursor){ simple_tokenizer_cursor *c = (simple_tokenizer_cursor *) pCursor; free(c->pToken); free(c); return SQLITE_OK; } /* ** Extract the next token from a tokenization cursor. The cursor must ** have been opened by a prior call to simpleOpen(). */ static int simpleNext( sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by simpleOpen */ const char **ppToken, /* OUT: *ppToken is the token text */ int *pnBytes, /* OUT: Number of bytes in token */ int *piStartOffset, /* OUT: Starting offset of token */ int *piEndOffset, /* OUT: Ending offset of token */ int *piPosition /* OUT: Position integer of token */ ){ simple_tokenizer_cursor *c = (simple_tokenizer_cursor *) pCursor; simple_tokenizer *t = (simple_tokenizer *) pCursor->pTokenizer; unsigned char *p = (unsigned char *)c->pInput; while( c->iOffset<c->nBytes ){ int iStartOffset; /* Scan past delimiter characters */ while( c->iOffset<c->nBytes && isDelim(t, p[c->iOffset]) ){ c->iOffset++; } /* Count non-delimiter characters. */ iStartOffset = c->iOffset; while( c->iOffset<c->nBytes && !isDelim(t, p[c->iOffset]) ){ c->iOffset++; } if( c->iOffset>iStartOffset ){ int i, n = c->iOffset-iStartOffset; if( n>c->nTokenAllocated ){ c->nTokenAllocated = n+20; c->pToken = realloc(c->pToken, c->nTokenAllocated); if( c->pToken==NULL ) return SQLITE_NOMEM; } for(i=0; i<n; i++){ /* TODO(shess) This needs expansion to handle UTF-8 ** case-insensitivity. */ unsigned char ch = p[iStartOffset+i]; c->pToken[i] = ch<0x80 ? tolower(ch) : ch; } *ppToken = c->pToken; *pnBytes = n; *piStartOffset = iStartOffset; *piEndOffset = c->iOffset; *piPosition = c->iToken++; return SQLITE_OK; } } return SQLITE_DONE; } /* ** The set of routines that implement the simple tokenizer */ static const sqlite3_tokenizer_module simpleTokenizerModule = { 0, simpleCreate, simpleDestroy, simpleOpen, simpleClose, simpleNext, }; /* ** Allocate a new simple tokenizer. Return a pointer to the new ** tokenizer in *ppModule */ void sqlite3Fts1SimpleTokenizerModule( sqlite3_tokenizer_module const**ppModule ){ *ppModule = &simpleTokenizerModule; } #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS1) */ |
Added ext/fts1/fulltext.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 | /* The author disclaims copyright to this source code. * * This is an SQLite module implementing full-text search. */ #include <assert.h> #if !defined(__APPLE__) #include <malloc.h> #else #include <stdlib.h> #endif #include <stdio.h> #include <string.h> #include <ctype.h> #include "fulltext.h" #include "ft_hash.h" #include "tokenizer.h" #include "sqlite3.h" #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 /* utility functions */ /* We encode variable-length integers in little-endian order using seven bits * per byte as follows: ** ** KEY: ** A = 0xxxxxxx 7 bits of data and one flag bit ** B = 1xxxxxxx 7 bits of data and one flag bit ** ** 7 bits - A ** 14 bits - BA ** 21 bits - BBA ** and so on. */ /* We may need up to VARINT_MAX bytes to store an encoded 64-bit integer. */ #define VARINT_MAX 10 /* Write a 64-bit variable-length integer to memory starting at p[0]. * The length of data written will be between 1 and VARINT_MAX bytes. * The number of bytes written is returned. */ static int putVarint(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 <= VARINT_MAX ); return (int) (q - (unsigned char *)p); } /* 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. */ static int getVarint(const char *p, sqlite_int64 *v){ const unsigned char *q = (const unsigned char *) p; sqlite_uint64 x = 0, y = 1; while( (*q & 0x80) == 0x80 ){ x += y * (*q++ & 0x7f); y <<= 7; if( q - (unsigned char *)p >= VARINT_MAX ){ /* bad data */ assert( 0 ); return 0; } } x += y * (*q++); *v = (sqlite_int64) x; return (int) (q - (unsigned char *)p); } static int getVarint32(const char *p, int *pi){ sqlite_int64 i; int ret = getVarint(p, &i); *pi = (int) i; assert( *pi==i ); return ret; } /*** Document lists *** * * A document list holds a sorted list of varint-encoded document IDs. * * A doclist with type DL_POSITIONS_OFFSETS is stored like this: * * array { * varint docid; * array { * varint position; (delta from previous position plus 1, or 0 for end) * varint startOffset; (delta from previous startOffset) * varint endOffset; (delta from startOffset) * } * } * * Here, array { X } means zero or more occurrences of X, adjacent in memory. * * A doclist with type DL_POSITIONS is like the above, but holds only docids * and positions without offset information. * * A doclist with type DL_DOCIDS is like the above, but holds only docids * without positions or offset information. * * On disk, every document list has positions and offsets, so we don't bother * to serialize a doclist's type. * * We don't yet delta-encode document IDs; doing so will probably be a * modest win. * * NOTE(shess) I've thought of a slightly (1%) better offset encoding. * After the first offset, estimate the next offset by using the * current token position and the previous token position and offset, * offset to handle some variance. So the estimate would be * (iPosition*w->iStartOffset/w->iPosition-64), which is delta-encoded * as normal. Offsets more than 64 chars from the estimate are * encoded as the delta to the previous start offset + 128. An * additional tiny increment can be gained by using the end offset of * the previous token to make the estimate a tiny bit more precise. */ typedef enum DocListType { DL_DOCIDS, /* docids only */ DL_POSITIONS, /* docids + positions */ DL_POSITIONS_OFFSETS /* docids + positions + offsets */ } DocListType; typedef struct DocList { char *pData; int nData; DocListType iType; int iLastPos; /* the last position written */ int iLastOffset; /* the last start offset written */ } DocList; /* Initialize a new DocList to hold the given data. */ static void docListInit(DocList *d, DocListType iType, const char *pData, int nData){ d->nData = nData; if( nData>0 ){ d->pData = malloc(nData); memcpy(d->pData, pData, nData); } else { d->pData = NULL; } d->iType = iType; d->iLastPos = 0; d->iLastOffset = 0; } /* Create a new dynamically-allocated DocList. */ static DocList *docListNew(DocListType iType){ DocList *d = (DocList *) malloc(sizeof(DocList)); docListInit(d, iType, 0, 0); return d; } static void docListDestroy(DocList *d){ free(d->pData); #ifndef NDEBUG memset(d, 0x55, sizeof(*d)); #endif } static void docListDelete(DocList *d){ docListDestroy(d); free(d); } static char *docListEnd(DocList *d){ return d->pData + d->nData; } /* Append a varint to a DocList's data. */ static void appendVarint(DocList *d, sqlite_int64 i){ char c[VARINT_MAX]; int n = putVarint(c, i); d->pData = realloc(d->pData, d->nData + n); memcpy(d->pData + d->nData, c, n); d->nData += n; } static void docListAddDocid(DocList *d, sqlite_int64 iDocid){ appendVarint(d, iDocid); d->iLastPos = 0; } /* Add a position to the last position list in a doclist. */ static void docListAddPos(DocList *d, int iPos){ assert( d->iType>=DL_POSITIONS ); appendVarint(d, iPos-d->iLastPos+1); d->iLastPos = iPos; } static void docListAddPosOffset(DocList *d, int iPos, int iStartOffset, int iEndOffset){ assert( d->iType==DL_POSITIONS_OFFSETS ); docListAddPos(d, iPos); appendVarint(d, iStartOffset-d->iLastOffset); d->iLastOffset = iStartOffset; appendVarint(d, iEndOffset-iStartOffset); } /* Terminate the last position list in the given doclist. */ static void docListAddEndPos(DocList *d){ appendVarint(d, 0); } typedef struct DocListReader { DocList *pDoclist; char *p; int iLastPos; /* the last position read */ } DocListReader; static void readerInit(DocListReader *r, DocList *pDoclist){ r->pDoclist = pDoclist; if( pDoclist!=NULL ){ r->p = pDoclist->pData; } r->iLastPos = 0; } static int readerAtEnd(DocListReader *pReader){ return pReader->p >= docListEnd(pReader->pDoclist); } /* Peek at the next docid without advancing the read pointer. */ static sqlite_int64 peekDocid(DocListReader *pReader){ sqlite_int64 ret; assert( !readerAtEnd(pReader) ); getVarint(pReader->p, &ret); return ret; } /* Read the next docid. */ static sqlite_int64 readDocid(DocListReader *pReader){ sqlite_int64 ret; assert( !readerAtEnd(pReader) ); pReader->p += getVarint(pReader->p, &ret); pReader->iLastPos = 0; return ret; } /* Read the next position from a position list. * Returns the position, or -1 at the end of the list. */ static int readPosition(DocListReader *pReader){ int i; int iType = pReader->pDoclist->iType; assert( iType>=DL_POSITIONS ); assert( !readerAtEnd(pReader) ); pReader->p += getVarint32(pReader->p, &i); if( i==0 ){ pReader->iLastPos = -1; return -1; } pReader->iLastPos += ((int) i)-1; if( iType>=DL_POSITIONS_OFFSETS ){ /* Skip over offsets, ignoring them for now. */ int iStart, iEnd; pReader->p += getVarint32(pReader->p, &iStart); pReader->p += getVarint32(pReader->p, &iEnd); } return pReader->iLastPos; } /* Skip past the end of a position list. */ static void skipPositionList(DocListReader *pReader){ while( readPosition(pReader)!=-1 ) ; } /* Skip over a docid, including its position list if the doclist has * positions. */ static void skipDocument(DocListReader *pReader){ readDocid(pReader); if( pReader->pDoclist->iType >= DL_POSITIONS ){ skipPositionList(pReader); } } static sqlite_int64 firstDocid(DocList *d){ DocListReader r; readerInit(&r, d); return readDocid(&r); } /* Doclist multi-tool. Pass pUpdate==NULL to delete the indicated docid; * otherwise pUpdate, which must contain only the single docid [iDocid], is * inserted (if not present) or updated (if already present). */ static int docListUpdate(DocList *d, sqlite_int64 iDocid, DocList *pUpdate){ int modified = 0; DocListReader reader; char *p; if( pUpdate!=NULL ){ assert( d->iType==pUpdate->iType); assert( iDocid==firstDocid(pUpdate) ); } readerInit(&reader, d); while( !readerAtEnd(&reader) && peekDocid(&reader)<iDocid ){ skipDocument(&reader); } p = reader.p; /* Delete if there is a matching element. */ if( !readerAtEnd(&reader) && iDocid==peekDocid(&reader) ){ skipDocument(&reader); memmove(p, reader.p, docListEnd(d) - reader.p); d->nData -= (reader.p - p); modified = 1; } /* Insert if indicated. */ if( pUpdate!=NULL ){ int iDoclist = p-d->pData; docListAddEndPos(pUpdate); d->pData = realloc(d->pData, d->nData+pUpdate->nData); p = d->pData + iDoclist; memmove(p+pUpdate->nData, p, docListEnd(d) - p); memcpy(p, pUpdate->pData, pUpdate->nData); d->nData += pUpdate->nData; modified = 1; } return modified; } /* Split the second half of doclist d into a separate doclist d2. Returns 1 * if successful, or 0 if d contains a single document and hence can't be * split. */ static int docListSplit(DocList *d, DocList *d2){ const char *pSplitPoint = d->pData + d->nData / 2; DocListReader reader; readerInit(&reader, d); while( reader.p<pSplitPoint ){ skipDocument(&reader); } if( readerAtEnd(&reader) ) return 0; docListInit(d2, d->iType, reader.p, docListEnd(d) - reader.p); d->nData = reader.p - d->pData; d->pData = realloc(d->pData, d->nData); return 1; } /* A DocListMerge computes the AND of an in-memory DocList [in] and a chunked * on-disk doclist, resulting in another in-memory DocList [out]. [in] * and [out] may or may not store position information according to the * caller's wishes. The on-disk doclist always comes with positions. * * The caller must read each chunk of the on-disk doclist in succession and * pass it to mergeBlock(). * * If [in] has positions, then the merge output contains only documents with * matching positions in the two input doclists. If [in] does not have * positions, then the merge output contains all documents common to the two * input doclists. * * If [in] is NULL, then the on-disk doclist is copied to [out] directly. * * A merge is performed using an integer [iOffset] provided by the caller. * [iOffset] is subtracted from each position in the on-disk doclist for the * purpose of position comparison; this is helpful in implementing phrase * searches. * * A DocListMerge is not yet able to propagate offsets through query * processing; we should add that capability soon. */ typedef struct DocListMerge { DocListReader in; DocList *pOut; int iOffset; } DocListMerge; static void mergeInit(DocListMerge *m, DocList *pIn, int iOffset, DocList *pOut){ readerInit(&m->in, pIn); m->pOut = pOut; m->iOffset = iOffset; /* can't handle offsets yet */ assert( pIn==NULL || pIn->iType <= DL_POSITIONS ); assert( pOut->iType <= DL_POSITIONS ); } /* A helper function for mergeBlock(), below. Merge the position lists * pointed to by m->in and pBlockReader. * If the merge matches, write [iDocid] to m->pOut; if m->pOut * has positions then write all matching positions as well. */ static void mergePosList(DocListMerge *m, sqlite_int64 iDocid, DocListReader *pBlockReader){ int block_pos = readPosition(pBlockReader); int in_pos = readPosition(&m->in); int match = 0; while( block_pos!=-1 || in_pos!=-1 ){ if( block_pos-m->iOffset==in_pos ){ if( !match ){ docListAddDocid(m->pOut, iDocid); match = 1; } if( m->pOut->iType >= DL_POSITIONS ){ docListAddPos(m->pOut, in_pos); } block_pos = readPosition(pBlockReader); in_pos = readPosition(&m->in); } else if( in_pos==-1 || (block_pos!=-1 && block_pos-m->iOffset<in_pos) ){ block_pos = readPosition(pBlockReader); } else { in_pos = readPosition(&m->in); } } if( m->pOut->iType >= DL_POSITIONS && match ){ docListAddEndPos(m->pOut); } } /* Merge one block of an on-disk doclist into a DocListMerge. */ static void mergeBlock(DocListMerge *m, DocList *pBlock){ DocListReader blockReader; assert( pBlock->iType >= DL_POSITIONS ); readerInit(&blockReader, pBlock); while( !readerAtEnd(&blockReader) ){ sqlite_int64 iDocid = readDocid(&blockReader); if( m->in.pDoclist!=NULL ){ while( 1 ){ if( readerAtEnd(&m->in) ) return; /* nothing more to merge */ if( peekDocid(&m->in)>=iDocid ) break; skipDocument(&m->in); } if( peekDocid(&m->in)>iDocid ){ /* [pIn] has no match with iDocid */ skipPositionList(&blockReader); /* skip this docid in the block */ continue; } readDocid(&m->in); } /* We have a document match. */ if( m->in.pDoclist==NULL || m->in.pDoclist->iType < DL_POSITIONS ){ /* We don't need to do a poslist merge. */ docListAddDocid(m->pOut, iDocid); if( m->pOut->iType >= DL_POSITIONS ){ /* Copy all positions to the output doclist. */ while( 1 ){ int pos = readPosition(&blockReader); if( pos==-1 ) break; docListAddPos(m->pOut, pos); } docListAddEndPos(m->pOut); } else skipPositionList(&blockReader); continue; } mergePosList(m, iDocid, &blockReader); } } static char *string_dup_n(const char *s, int n){ char *str = malloc(n + 1); memcpy(str, s, n); str[n] = '\0'; return str; } /* Duplicate a string; the caller must free() the returned string. * (We don't use strdup() since it's not part of the standard C library and * may not be available everywhere.) */ static char *string_dup(const char *s){ return string_dup_n(s, strlen(s)); } /* Format a string, replacing each occurrence of the % character with * zName. This may be more convenient than sqlite_mprintf() * when one string is used repeatedly in a format string. * The caller must free() the returned string. */ static char *string_format(const char *zFormat, const char *zName){ const char *p; size_t len = 0; size_t nName = strlen(zName); char *result; char *r; /* first compute length needed */ for(p = zFormat ; *p ; ++p){ len += (*p=='%' ? nName : 1); } len += 1; /* for null terminator */ r = result = malloc(len); for(p = zFormat; *p; ++p){ if( *p=='%' ){ memcpy(r, zName, nName); r += nName; } else { *r++ = *p; } } *r++ = '\0'; assert( r == result + len ); return result; } static int sql_exec(sqlite3 *db, const char *zName, const char *zFormat){ char *zCommand = string_format(zFormat, zName); int rc = sqlite3_exec(db, zCommand, NULL, 0, NULL); free(zCommand); return rc; } static int sql_prepare(sqlite3 *db, const char *zName, sqlite3_stmt **ppStmt, const char *zFormat){ char *zCommand = string_format(zFormat, zName); int rc = sqlite3_prepare(db, zCommand, -1, ppStmt, NULL); free(zCommand); return rc; } /* end utility functions */ #define QUERY_GENERIC 0 #define QUERY_FULLTEXT 1 #define CHUNK_MAX 1024 typedef enum fulltext_statement { CONTENT_INSERT_STMT, CONTENT_SELECT_STMT, CONTENT_DELETE_STMT, TERM_SELECT_STMT, TERM_CHUNK_SELECT_STMT, TERM_INSERT_STMT, TERM_UPDATE_STMT, TERM_DELETE_STMT, MAX_STMT /* Always at end! */ } fulltext_statement; /* These must exactly match the enum above. */ /* TODO(adam): Is there some risk that a statement (in particular, ** pTermSelectStmt) will be used in two cursors at once, e.g. if a ** query joins a virtual table to itself? If so perhaps we should ** move some of these to the cursor object. */ static const char *fulltext_zStatement[MAX_STMT] = { /* CONTENT_INSERT */ "insert into %_content (rowid, content) values (?, ?)", /* CONTENT_SELECT */ "select content from %_content where rowid = ?", /* CONTENT_DELETE */ "delete from %_content where rowid = ?", /* TERM_SELECT */ "select rowid, doclist from %_term where term = ? and first = ?", /* TERM_CHUNK_SELECT */ "select max(first) from %_term where term = ? and first <= ?", /* TERM_INSERT */ "insert into %_term (term, first, doclist) values (?, ?, ?)", /* TERM_UPDATE */ "update %_term set doclist = ? where rowid = ?", /* TERM_DELETE */ "delete from %_term where rowid = ?", }; typedef struct fulltext_vtab { sqlite3_vtab base; sqlite3 *db; const char *zName; /* virtual table name */ sqlite3_tokenizer *pTokenizer; /* tokenizer for inserts and queries */ /* Precompiled statements which we keep as long as the table is ** open. */ sqlite3_stmt *pFulltextStatements[MAX_STMT]; } fulltext_vtab; typedef struct fulltext_cursor { sqlite3_vtab_cursor base; int iCursorType; /* QUERY_GENERIC or QUERY_FULLTEXT */ sqlite3_stmt *pStmt; int eof; /* The following is used only when iCursorType == QUERY_FULLTEXT. */ DocListReader result; } fulltext_cursor; static struct fulltext_vtab *cursor_vtab(fulltext_cursor *c){ return (fulltext_vtab *) c->base.pVtab; } static sqlite3_module fulltextModule; /* forward declaration */ /* Puts a freshly-prepared statement determined by iStmt in *ppStmt. ** If the indicated statement has never been prepared, it is prepared ** and cached, otherwise the cached version is reset. */ static int sql_get_statement(fulltext_vtab *v, fulltext_statement iStmt, sqlite3_stmt **ppStmt){ assert( iStmt<MAX_STMT ); if( v->pFulltextStatements[iStmt]==NULL ){ int rc = sql_prepare(v->db, v->zName, &v->pFulltextStatements[iStmt], fulltext_zStatement[iStmt]); if( rc!=SQLITE_OK ) return rc; } else { int rc = sqlite3_reset(v->pFulltextStatements[iStmt]); if( rc!=SQLITE_OK ) return rc; } *ppStmt = v->pFulltextStatements[iStmt]; return SQLITE_OK; } /* Step the indicated statement, handling errors SQLITE_BUSY (by ** retrying) and SQLITE_SCHEMA (by re-preparing and transferring ** bindings to the new statement). ** TODO(adam): We should extend this function so that it can work with ** statements declared locally, not only globally cached statements. */ static int sql_step_statement(fulltext_vtab *v, fulltext_statement iStmt, sqlite3_stmt **ppStmt){ int rc; sqlite3_stmt *s = *ppStmt; assert( iStmt<MAX_STMT ); assert( s==v->pFulltextStatements[iStmt] ); while( (rc=sqlite3_step(s))!=SQLITE_DONE && rc!=SQLITE_ROW ){ sqlite3_stmt *pNewStmt; if( rc==SQLITE_BUSY ) continue; if( rc!=SQLITE_ERROR ) return rc; rc = sqlite3_reset(s); if( rc!=SQLITE_SCHEMA ) return SQLITE_ERROR; v->pFulltextStatements[iStmt] = NULL; /* Still in s */ rc = sql_get_statement(v, iStmt, &pNewStmt); if( rc!=SQLITE_OK ) goto err; *ppStmt = pNewStmt; rc = sqlite3_transfer_bindings(s, pNewStmt); if( rc!=SQLITE_OK ) goto err; rc = sqlite3_finalize(s); if( rc!=SQLITE_OK ) return rc; s = pNewStmt; } return rc; err: sqlite3_finalize(s); return rc; } /* Like sql_step_statement(), but convert SQLITE_DONE to SQLITE_OK. ** Useful for statements like UPDATE, where we expect no results. */ static int sql_single_step_statement(fulltext_vtab *v, fulltext_statement iStmt, sqlite3_stmt **ppStmt){ int rc = sql_step_statement(v, iStmt, ppStmt); return (rc==SQLITE_DONE) ? SQLITE_OK : rc; } /* insert into %_content (rowid, content) values ([rowid], [zContent]) */ static int content_insert(fulltext_vtab *v, sqlite3_value *rowid, const char *zContent, int nContent){ sqlite3_stmt *s; int rc = sql_get_statement(v, CONTENT_INSERT_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_value(s, 1, rowid); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_text(s, 2, zContent, nContent, SQLITE_STATIC); if( rc!=SQLITE_OK ) return rc; return sql_single_step_statement(v, CONTENT_INSERT_STMT, &s); } /* select content from %_content where rowid = [iRow] * The caller must delete the returned string. */ static int content_select(fulltext_vtab *v, sqlite_int64 iRow, char **pzContent){ sqlite3_stmt *s; int rc = sql_get_statement(v, CONTENT_SELECT_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int64(s, 1, iRow); if( rc!=SQLITE_OK ) return rc; rc = sql_step_statement(v, CONTENT_SELECT_STMT, &s); if( rc!=SQLITE_ROW ) return rc; *pzContent = string_dup((const char *)sqlite3_column_text(s, 0)); /* We expect only one row. We must execute another sqlite3_step() * to complete the iteration; otherwise the table will remain locked. */ rc = sqlite3_step(s); if( rc==SQLITE_DONE ) return SQLITE_OK; free(*pzContent); return rc; } /* delete from %_content where rowid = [iRow ] */ static int content_delete(fulltext_vtab *v, sqlite_int64 iRow){ sqlite3_stmt *s; int rc = sql_get_statement(v, CONTENT_DELETE_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int64(s, 1, iRow); if( rc!=SQLITE_OK ) return rc; return sql_single_step_statement(v, CONTENT_DELETE_STMT, &s); } /* select rowid, doclist from %_term where term = [zTerm] and first = [iFirst] * If found, returns SQLITE_OK; the caller must free the returned doclist. * If no rows found, returns SQLITE_ERROR. */ static int term_select(fulltext_vtab *v, const char *zTerm, int nTerm, sqlite_int64 iFirst, sqlite_int64 *rowid, DocList *out){ sqlite3_stmt *s; int rc = sql_get_statement(v, TERM_SELECT_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_text(s, 1, zTerm, nTerm, SQLITE_TRANSIENT); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int64(s, 2, iFirst); if( rc!=SQLITE_OK ) return rc; rc = sql_step_statement(v, TERM_SELECT_STMT, &s); if( rc!=SQLITE_ROW ) return rc==SQLITE_DONE ? SQLITE_ERROR : rc; *rowid = sqlite3_column_int64(s, 0); docListInit(out, DL_POSITIONS_OFFSETS, sqlite3_column_blob(s, 1), sqlite3_column_bytes(s, 1)); /* We expect only one row. We must execute another sqlite3_step() * to complete the iteration; otherwise the table will remain locked. */ rc = sqlite3_step(s); return rc==SQLITE_DONE ? SQLITE_OK : rc; } /* select max(first) from %_term where term = [zTerm] and first <= [iFirst] * If found, returns SQLITE_ROW and result in *piResult; if the query returns * NULL (meaning no row found) returns SQLITE_DONE. */ static int term_chunk_select(fulltext_vtab *v, const char *zTerm, int nTerm, sqlite_int64 iFirst, sqlite_int64 *piResult){ sqlite3_stmt *s; int rc = sql_get_statement(v, TERM_CHUNK_SELECT_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_text(s, 1, zTerm, nTerm, SQLITE_STATIC); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int64(s, 2, iFirst); if( rc!=SQLITE_OK ) return rc; rc = sql_step_statement(v, TERM_CHUNK_SELECT_STMT, &s); if( rc!=SQLITE_ROW ) return rc==SQLITE_DONE ? SQLITE_ERROR : rc; switch( sqlite3_column_type(s, 0) ){ case SQLITE_NULL: rc = SQLITE_DONE; break; case SQLITE_INTEGER: *piResult = sqlite3_column_int64(s, 0); break; default: return SQLITE_ERROR; } /* We expect only one row. We must execute another sqlite3_step() * to complete the iteration; otherwise the table will remain locked. */ if( sqlite3_step(s) != SQLITE_DONE ) return SQLITE_ERROR; return rc; } /* insert into %_term (term, first, doclist) values ([zTerm], [iFirst], [doclist]) */ static int term_insert(fulltext_vtab *v, const char *zTerm, int nTerm, sqlite_int64 iFirst, DocList *doclist){ sqlite3_stmt *s; int rc = sql_get_statement(v, TERM_INSERT_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_text(s, 1, zTerm, nTerm, SQLITE_STATIC); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int64(s, 2, iFirst); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_blob(s, 3, doclist->pData, doclist->nData, SQLITE_STATIC); if( rc!=SQLITE_OK ) return rc; return sql_single_step_statement(v, TERM_INSERT_STMT, &s); } /* update %_term set doclist = [doclist] where rowid = [rowid] */ static int term_update(fulltext_vtab *v, sqlite_int64 rowid, DocList *doclist){ sqlite3_stmt *s; int rc = sql_get_statement(v, TERM_UPDATE_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_blob(s, 1, doclist->pData, doclist->nData, SQLITE_STATIC); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int64(s, 2, rowid); if( rc!=SQLITE_OK ) return rc; return sql_single_step_statement(v, TERM_UPDATE_STMT, &s); } static int term_delete(fulltext_vtab *v, sqlite_int64 rowid){ sqlite3_stmt *s; int rc = sql_get_statement(v, TERM_DELETE_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int64(s, 1, rowid); if( rc!=SQLITE_OK ) return rc; return sql_single_step_statement(v, TERM_DELETE_STMT, &s); } static void fulltext_vtab_destroy(fulltext_vtab *v){ int iStmt; for( iStmt=0; iStmt<MAX_STMT; iStmt++ ){ if( v->pFulltextStatements[iStmt]!=NULL ){ sqlite3_finalize(v->pFulltextStatements[iStmt]); v->pFulltextStatements[iStmt] = NULL; } } if( v->pTokenizer!=NULL ){ v->pTokenizer->pModule->xDestroy(v->pTokenizer); v->pTokenizer = NULL; } free((void *) v->zName); free(v); } /* Current interface: ** argv[0] - module name ** argv[1] - database name ** argv[2] - table name ** argv[3] - tokenizer name (optional, a sensible default is provided) ** argv[4..] - passed to tokenizer (optional based on tokenizer) **/ static int fulltextConnect( sqlite3 *db, void *pAux, int argc, const char * const *argv, sqlite3_vtab **ppVTab, char **pzErr ){ int rc; fulltext_vtab *v; sqlite3_tokenizer_module *m = NULL; assert( argc>=3 ); v = (fulltext_vtab *) malloc(sizeof(fulltext_vtab)); /* sqlite will initialize v->base */ v->db = db; v->zName = string_dup(argv[2]); v->pTokenizer = NULL; if( argc==3 ){ get_simple_tokenizer_module(&m); } else { /* TODO(shess) For now, add new tokenizers as else if clauses. */ if( !strcmp(argv[3], "simple") ){ get_simple_tokenizer_module(&m); } else { assert( "unrecognized tokenizer"==NULL ); } } /* TODO(shess) Since tokenization impacts the index, the parameters ** to the tokenizer need to be identical when a persistent virtual ** table is re-created. One solution would be a meta-table to track ** such information in the database. Then we could verify that the ** information is identical on subsequent creates. */ /* TODO(shess) Why isn't argv already (const char **)? */ rc = m->xCreate(argc-3, (const char **) (argv+3), &v->pTokenizer); if( rc!=SQLITE_OK ) return rc; v->pTokenizer->pModule = m; /* TODO: verify the existence of backing tables foo_content, foo_term */ rc = sqlite3_declare_vtab(db, "create table x(content text)"); if( rc!=SQLITE_OK ) return rc; memset(v->pFulltextStatements, 0, sizeof(v->pFulltextStatements)); *ppVTab = &v->base; return SQLITE_OK; } static int fulltextCreate( sqlite3 *db, void *pAux, int argc, const char * const *argv, sqlite3_vtab **ppVTab, char **pzErr ){ int rc; assert( argc>=3 ); /* The %_content table holds the text of each full-text item, with ** the rowid used as the docid. ** ** The %_term table maps each term to a document list blob ** containing elements sorted by ascending docid, each element ** encoded as: ** ** docid varint-encoded ** token count varint-encoded ** "count" token elements (poslist): ** position varint-encoded as delta from previous position ** start offset varint-encoded as delta from previous start offset ** end offset varint-encoded as delta from start offset ** ** Additionally, doclist blobs can be chunked into multiple rows, ** using "first" to order the blobs. "first" is simply the first ** docid in the blob. */ /* ** NOTE(shess) That last sentence is incorrect in the face of ** deletion, which can leave a doclist that doesn't contain the ** first from that row. I _believe_ this does not matter to the ** operation of the system, but it might be reasonable to update ** appropriately in case this assumption becomes more important. */ rc = sql_exec(db, argv[2], "create table %_content(content text);" "create table %_term(term text, first integer, doclist blob);" "create index %_index on %_term(term, first)"); if( rc!=SQLITE_OK ) return rc; return fulltextConnect(db, pAux, argc, argv, ppVTab, pzErr); } /* Decide how to handle an SQL query. * At the moment, MATCH queries can include implicit boolean ANDs; we * haven't implemented phrase searches or OR yet. */ static int fulltextBestIndex(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ int i; for(i=0; i<pInfo->nConstraint; ++i){ const struct sqlite3_index_constraint *pConstraint; pConstraint = &pInfo->aConstraint[i]; if( pConstraint->iColumn==0 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_MATCH && pConstraint->usable ){ /* a full-text search */ pInfo->aConstraintUsage[i].argvIndex = 1; pInfo->aConstraintUsage[i].omit = 1; pInfo->idxNum = QUERY_FULLTEXT; pInfo->estimatedCost = 1.0; /* an arbitrary value for now */ return SQLITE_OK; } } pInfo->idxNum = QUERY_GENERIC; return SQLITE_OK; } static int fulltextDisconnect(sqlite3_vtab *pVTab){ fulltext_vtab_destroy((fulltext_vtab *)pVTab); return SQLITE_OK; } static int fulltextDestroy(sqlite3_vtab *pVTab){ fulltext_vtab *v = (fulltext_vtab *)pVTab; int rc = sql_exec(v->db, v->zName, "drop table %_content; drop table %_term"); if( rc!=SQLITE_OK ) return rc; fulltext_vtab_destroy((fulltext_vtab *)pVTab); return SQLITE_OK; } static int fulltextOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ fulltext_cursor *c; c = (fulltext_cursor *) calloc(sizeof(fulltext_cursor), 1); /* sqlite will initialize c->base */ *ppCursor = &c->base; return SQLITE_OK; } static int fulltextClose(sqlite3_vtab_cursor *pCursor){ fulltext_cursor *c = (fulltext_cursor *) pCursor; sqlite3_finalize(c->pStmt); if( c->result.pDoclist!=NULL ){ docListDelete(c->result.pDoclist); } free(c); return SQLITE_OK; } static int fulltextNext(sqlite3_vtab_cursor *pCursor){ fulltext_cursor *c = (fulltext_cursor *) pCursor; sqlite_int64 iDocid; int rc; switch( c->iCursorType ){ case QUERY_GENERIC: /* TODO(shess) Handle SQLITE_SCHEMA AND SQLITE_BUSY. */ rc = sqlite3_step(c->pStmt); switch( rc ){ case SQLITE_ROW: c->eof = 0; return SQLITE_OK; case SQLITE_DONE: c->eof = 1; return SQLITE_OK; default: c->eof = 1; return rc; } case QUERY_FULLTEXT: rc = sqlite3_reset(c->pStmt); if( rc!=SQLITE_OK ) return rc; if( readerAtEnd(&c->result)){ c->eof = 1; return SQLITE_OK; } iDocid = readDocid(&c->result); rc = sqlite3_bind_int64(c->pStmt, 1, iDocid); if( rc!=SQLITE_OK ) return rc; /* TODO(shess) Handle SQLITE_SCHEMA AND SQLITE_BUSY. */ rc = sqlite3_step(c->pStmt); if( rc==SQLITE_ROW ){ /* the case we expect */ c->eof = 0; return SQLITE_OK; } /* an error occurred; abort */ return rc==SQLITE_DONE ? SQLITE_ERROR : rc; default: assert( 0 ); return SQLITE_ERROR; /* not reached */ } } static int term_select_doclist(fulltext_vtab *v, const char *pTerm, int nTerm, sqlite3_stmt **ppStmt){ int rc; if( *ppStmt ){ rc = sqlite3_reset(*ppStmt); } else { rc = sql_prepare(v->db, v->zName, ppStmt, "select doclist from %_term where term = ? order by first"); } if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_text(*ppStmt, 1, pTerm, nTerm, SQLITE_TRANSIENT); if( rc!=SQLITE_OK ) return rc; return sqlite3_step(*ppStmt); /* TODO(adamd): handle schema error */ } /* Read the posting list for [zTerm]; AND it with the doclist [in] to * produce the doclist [out], using the given offset [iOffset] for phrase * matching. * (*pSelect) is used to hold an SQLite statement used inside this function; * the caller should initialize *pSelect to NULL before the first call. */ static int query_merge(fulltext_vtab *v, sqlite3_stmt **pSelect, const char *zTerm, DocList *pIn, int iOffset, DocList *out){ int rc; DocListMerge merge; if( pIn!=NULL && !pIn->nData ){ /* If [pIn] is already empty, there's no point in reading the * posting list to AND it in; return immediately. */ return SQLITE_OK; } rc = term_select_doclist(v, zTerm, -1, pSelect); if( rc!=SQLITE_ROW && rc!=SQLITE_DONE ) return rc; mergeInit(&merge, pIn, iOffset, out); while( rc==SQLITE_ROW ){ DocList block; docListInit(&block, DL_POSITIONS_OFFSETS, sqlite3_column_blob(*pSelect, 0), sqlite3_column_bytes(*pSelect, 0)); mergeBlock(&merge, &block); docListDestroy(&block); rc = sqlite3_step(*pSelect); if( rc!=SQLITE_ROW && rc!=SQLITE_DONE ){ return rc; } } return SQLITE_OK; } typedef struct QueryTerm { int is_phrase; /* true if this term begins a new phrase */ const char *zTerm; } QueryTerm; /* A parsed query. * * As an example, parsing the query ["four score" years "new nation"] will * yield a Query with 5 terms: * "four", is_phrase = 1 * "score", is_phrase = 0 * "years", is_phrase = 1 * "new", is_phrase = 1 * "nation", is_phrase = 0 */ typedef struct Query { int nTerms; QueryTerm *pTerm; } Query; static void query_add(Query *q, int is_phrase, const char *zTerm){ QueryTerm *t; ++q->nTerms; q->pTerm = realloc(q->pTerm, q->nTerms * sizeof(q->pTerm[0])); t = &q->pTerm[q->nTerms - 1]; t->is_phrase = is_phrase; t->zTerm = zTerm; } static void query_free(Query *q){ int i; for(i = 0; i < q->nTerms; ++i){ free((void *) q->pTerm[i].zTerm); } free(q->pTerm); } static int tokenize_segment(sqlite3_tokenizer *pTokenizer, const char *zQuery, int in_phrase, Query *pQuery){ sqlite3_tokenizer_module *pModule = pTokenizer->pModule; sqlite3_tokenizer_cursor *pCursor; int is_first = 1; int rc = pModule->xOpen(pTokenizer, zQuery, -1, &pCursor); if( rc!=SQLITE_OK ) return rc; pCursor->pTokenizer = pTokenizer; while( 1 ){ const char *zToken; int nToken, iStartOffset, iEndOffset, dummy_pos; rc = pModule->xNext(pCursor, &zToken, &nToken, &iStartOffset, &iEndOffset, &dummy_pos); if( rc!=SQLITE_OK ) break; query_add(pQuery, !in_phrase || is_first, string_dup_n(zToken, nToken)); is_first = 0; } return pModule->xClose(pCursor); } /* Parse a query string, yielding a Query object. */ static int parse_query(fulltext_vtab *v, const char *zQuery, Query *pQuery){ char *zQuery1 = string_dup(zQuery); int in_phrase = 0; char *s = zQuery1; pQuery->nTerms = 0; pQuery->pTerm = NULL; while( *s ){ char *t = s; while( *t ){ if( *t=='"' ){ *t++ = '\0'; break; } ++t; } if( *s ){ tokenize_segment(v->pTokenizer, s, in_phrase, pQuery); } s = t; in_phrase = !in_phrase; } free(zQuery1); return SQLITE_OK; } /* Perform a full-text query; return a list of documents in [pResult]. */ static int fulltext_query(fulltext_vtab *v, const char *zQuery, DocList **pResult){ Query q; int phrase_start = -1; int i; sqlite3_stmt *pSelect = NULL; DocList *d = NULL; int rc = parse_query(v, zQuery, &q); if( rc!=SQLITE_OK ) return rc; /* Merge terms. */ for(i = 0 ; i < q.nTerms ; ++i){ /* In each merge step, we need to generate positions whenever we're * processing a phrase which hasn't ended yet. */ int need_positions = i<q.nTerms-1 && !q.pTerm[i+1].is_phrase; DocList *next = docListNew(need_positions ? DL_POSITIONS : DL_DOCIDS); if( q.pTerm[i].is_phrase ){ phrase_start = i; } rc = query_merge(v, &pSelect, q.pTerm[i].zTerm, d, i - phrase_start, next); if( rc!=SQLITE_OK ) break; if( d!=NULL ){ docListDelete(d); } d = next; } sqlite3_finalize(pSelect); query_free(&q); *pResult = d; return rc; } static int fulltextFilter(sqlite3_vtab_cursor *pCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv){ fulltext_cursor *c = (fulltext_cursor *) pCursor; fulltext_vtab *v = cursor_vtab(c); int rc; const char *zStatement; c->iCursorType = idxNum; switch( idxNum ){ case QUERY_GENERIC: zStatement = "select rowid, content from %_content"; break; case QUERY_FULLTEXT: /* full-text search */ { const char *zQuery = (const char *)sqlite3_value_text(argv[0]); DocList *pResult; assert( argc==1 ); rc = fulltext_query(v, zQuery, &pResult); if( rc!=SQLITE_OK ) return rc; readerInit(&c->result, pResult); zStatement = "select rowid, content from %_content where rowid = ?"; break; } default: assert( 0 ); } rc = sql_prepare(v->db, v->zName, &c->pStmt, zStatement); if( rc!=SQLITE_OK ) return rc; return fulltextNext(pCursor); } static int fulltextEof(sqlite3_vtab_cursor *pCursor){ fulltext_cursor *c = (fulltext_cursor *) pCursor; return c->eof; } static int fulltextColumn(sqlite3_vtab_cursor *pCursor, sqlite3_context *pContext, int idxCol){ fulltext_cursor *c = (fulltext_cursor *) pCursor; const char *s; assert( idxCol==0 ); s = (const char *) sqlite3_column_text(c->pStmt, 1); sqlite3_result_text(pContext, s, -1, SQLITE_TRANSIENT); return SQLITE_OK; } static int fulltextRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ fulltext_cursor *c = (fulltext_cursor *) pCursor; *pRowid = sqlite3_column_int64(c->pStmt, 0); return SQLITE_OK; } /* Build a hash table containing all terms in zText. */ static int build_terms(Hash *terms, sqlite3_tokenizer *pTokenizer, const char *zText, sqlite_int64 iDocid){ sqlite3_tokenizer_cursor *pCursor; const char *pToken; int nTokenBytes; int iStartOffset, iEndOffset, iPosition; int rc = pTokenizer->pModule->xOpen(pTokenizer, zText, -1, &pCursor); if( rc!=SQLITE_OK ) return rc; pCursor->pTokenizer = pTokenizer; HashInit(terms, HASH_STRING, 1); while( SQLITE_OK==pTokenizer->pModule->xNext(pCursor, &pToken, &nTokenBytes, &iStartOffset, &iEndOffset, &iPosition) ){ DocList *p; /* Positions can't be negative; we use -1 as a terminator internally. */ if( iPosition<0 ) { rc = SQLITE_ERROR; goto err; } p = HashFind(terms, pToken, nTokenBytes); if( p==NULL ){ p = docListNew(DL_POSITIONS_OFFSETS); docListAddDocid(p, iDocid); HashInsert(terms, pToken, nTokenBytes, p); } docListAddPosOffset(p, iPosition, iStartOffset, iEndOffset); } err: /* TODO(shess) Check return? Should this be able to cause errors at ** this point? Actually, same question about sqlite3_finalize(), ** though one could argue that failure there means that the data is ** not durable. *ponder* */ pTokenizer->pModule->xClose(pCursor); return rc; } /* Update the %_terms table to map the term [zTerm] to the given rowid. */ static int index_insert_term(fulltext_vtab *v, const char *zTerm, int nTerm, sqlite_int64 iDocid, DocList *p){ sqlite_int64 iFirst; sqlite_int64 iIndexRow; DocList doclist; int rc = term_chunk_select(v, zTerm, nTerm, iDocid, &iFirst); if( rc==SQLITE_DONE ){ docListInit(&doclist, DL_POSITIONS_OFFSETS, 0, 0); if( docListUpdate(&doclist, iDocid, p) ){ rc = term_insert(v, zTerm, nTerm, iDocid, &doclist); docListDestroy(&doclist); return rc; } return SQLITE_OK; } if( rc!=SQLITE_ROW ) return SQLITE_ERROR; /* This word is in the index; add this document ID to its blob. */ rc = term_select(v, zTerm, nTerm, iFirst, &iIndexRow, &doclist); if( rc!=SQLITE_OK ) return rc; if( docListUpdate(&doclist, iDocid, p) ){ /* If the blob is too big, split it in half. */ if( doclist.nData>CHUNK_MAX ){ DocList half; if( docListSplit(&doclist, &half) ){ rc = term_insert(v, zTerm, nTerm, firstDocid(&half), &half); docListDestroy(&half); if( rc!=SQLITE_OK ) goto err; } } rc = term_update(v, iIndexRow, &doclist); } err: docListDestroy(&doclist); return rc; } /* Insert a row into the full-text index; set *piRowid to be the ID of the * new row. */ static int index_insert(fulltext_vtab *v, sqlite3_value *pRequestRowid, const char *zText, sqlite_int64 *piRowid){ Hash terms; /* maps term string -> PosList */ HashElem *e; int rc = content_insert(v, pRequestRowid, zText, -1); if( rc!=SQLITE_OK ) return rc; *piRowid = sqlite3_last_insert_rowid(v->db); if( !zText ) return SQLITE_OK; /* nothing to index */ rc = build_terms(&terms, v->pTokenizer, zText, *piRowid); if( rc!=SQLITE_OK ) return rc; for(e=HashFirst(&terms); e; e=HashNext(e)){ DocList *p = HashData(e); rc = index_insert_term(v, HashKey(e), HashKeysize(e), *piRowid, p); if( rc!=SQLITE_OK ) break; } for(e=HashFirst(&terms); e; e=HashNext(e)){ DocList *p = HashData(e); docListDelete(p); } HashClear(&terms); return rc; } static int index_delete_term(fulltext_vtab *v, const char *zTerm, int nTerm, sqlite_int64 iDocid){ sqlite_int64 iFirst; sqlite_int64 iIndexRow; DocList doclist; int rc = term_chunk_select(v, zTerm, nTerm, iDocid, &iFirst); if( rc!=SQLITE_ROW ) return SQLITE_ERROR; rc = term_select(v, zTerm, nTerm, iFirst, &iIndexRow, &doclist); if( rc!=SQLITE_OK ) return rc; if( docListUpdate(&doclist, iDocid, NULL) ){ if( doclist.nData>0 ){ rc = term_update(v, iIndexRow, &doclist); } else { /* empty posting list */ rc = term_delete(v, iIndexRow); } } docListDestroy(&doclist); return rc; } /* Delete a row from the full-text index. */ static int index_delete(fulltext_vtab *v, sqlite_int64 iRow){ char *zText; Hash terms; HashElem *e; int rc = content_select(v, iRow, &zText); if( rc!=SQLITE_OK ) return rc; rc = build_terms(&terms, v->pTokenizer, zText, iRow); free(zText); if( rc!=SQLITE_OK ) return rc; for(e=HashFirst(&terms); e; e=HashNext(e)){ rc = index_delete_term(v, HashKey(e), HashKeysize(e), iRow); if( rc!=SQLITE_OK ) break; } for(e=HashFirst(&terms); e; e=HashNext(e)){ DocList *p = HashData(e); docListDelete(p); } HashClear(&terms); return content_delete(v, iRow); } static int fulltextUpdate(sqlite3_vtab *pVtab, int nArg, sqlite3_value **ppArg, sqlite_int64 *pRowid){ fulltext_vtab *v = (fulltext_vtab *) pVtab; if( nArg<2 ){ return index_delete(v, sqlite3_value_int64(ppArg[0])); } if( sqlite3_value_type(ppArg[0]) != SQLITE_NULL ){ return SQLITE_ERROR; /* an update; not yet supported */ } assert( nArg==3 ); /* ppArg[1] = rowid, ppArg[2] = content */ return index_insert(v, ppArg[1], (const char *)sqlite3_value_text(ppArg[2]), pRowid); } static sqlite3_module fulltextModule = { 0, fulltextCreate, fulltextConnect, fulltextBestIndex, fulltextDisconnect, fulltextDestroy, fulltextOpen, fulltextClose, fulltextFilter, fulltextNext, fulltextEof, fulltextColumn, fulltextRowid, fulltextUpdate }; int fulltext_init(sqlite3 *db){ return sqlite3_create_module(db, "fulltext", &fulltextModule, 0); } #if !SQLITE_CORE #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_fulltext_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi){ SQLITE_EXTENSION_INIT2(pApi) return fulltext_init(db); } #endif |
Added ext/fts1/fulltext.h.
> > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 | #include "sqlite3.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ int fulltext_init(sqlite3 *db); #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ |
Added ext/fts1/simple_tokenizer.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 | /* ** The author disclaims copyright to this source code. ** ************************************************************************* ** Implementation of the "simple" full-text-search tokenizer. */ #include <assert.h> #if !defined(__APPLE__) #include <malloc.h> #else #include <stdlib.h> #endif #include <stdio.h> #include <string.h> #include <ctype.h> #include "tokenizer.h" /* Duplicate a string; the caller must free() the returned string. * (We don't use strdup() since it's not part of the standard C library and * may not be available everywhere.) */ /* TODO(shess) Copied from fulltext.c, consider util.c for such ** things. */ static char *string_dup(const char *s){ char *str = malloc(strlen(s) + 1); strcpy(str, s); return str; } typedef struct simple_tokenizer { sqlite3_tokenizer base; const char *zDelim; /* token delimiters */ } simple_tokenizer; typedef struct simple_tokenizer_cursor { sqlite3_tokenizer_cursor base; const char *pInput; /* input we are tokenizing */ int nBytes; /* size of the input */ const char *pCurrent; /* current position in pInput */ int iToken; /* index of next token to be returned */ char *zToken; /* storage for current token */ int nTokenBytes; /* actual size of current token */ int nTokenAllocated; /* space allocated to zToken buffer */ } simple_tokenizer_cursor; static sqlite3_tokenizer_module simpleTokenizerModule;/* forward declaration */ static int simpleCreate( int argc, const char **argv, sqlite3_tokenizer **ppTokenizer ){ simple_tokenizer *t; t = (simple_tokenizer *) malloc(sizeof(simple_tokenizer)); /* TODO(shess) Delimiters need to remain the same from run to run, ** else we need to reindex. One solution would be a meta-table to ** track such information in the database, then we'd only want this ** information on the initial create. */ if( argc>1 ){ t->zDelim = string_dup(argv[1]); } else { /* Build a string excluding alphanumeric ASCII characters */ char zDelim[0x80]; /* nul-terminated, so nul not a member */ int i, j; for(i=1, j=0; i<0x80; i++){ if( !isalnum(i) ){ zDelim[j++] = i; } } zDelim[j++] = '\0'; assert( j<=sizeof(zDelim) ); t->zDelim = string_dup(zDelim); } *ppTokenizer = &t->base; return SQLITE_OK; } static int simpleDestroy(sqlite3_tokenizer *pTokenizer){ simple_tokenizer *t = (simple_tokenizer *) pTokenizer; free((void *) t->zDelim); free(t); return SQLITE_OK; } static int simpleOpen( sqlite3_tokenizer *pTokenizer, const char *pInput, int nBytes, sqlite3_tokenizer_cursor **ppCursor ){ simple_tokenizer_cursor *c; c = (simple_tokenizer_cursor *) malloc(sizeof(simple_tokenizer_cursor)); c->pInput = pInput; c->nBytes = nBytes<0 ? (int) strlen(pInput) : nBytes; c->pCurrent = c->pInput; /* start tokenizing at the beginning */ c->iToken = 0; c->zToken = NULL; /* no space allocated, yet. */ c->nTokenBytes = 0; c->nTokenAllocated = 0; *ppCursor = &c->base; return SQLITE_OK; } static int simpleClose(sqlite3_tokenizer_cursor *pCursor){ simple_tokenizer_cursor *c = (simple_tokenizer_cursor *) pCursor; if( NULL!=c->zToken ){ free(c->zToken); } free(c); return SQLITE_OK; } static int simpleNext( sqlite3_tokenizer_cursor *pCursor, const char **ppToken, int *pnBytes, int *piStartOffset, int *piEndOffset, int *piPosition ){ simple_tokenizer_cursor *c = (simple_tokenizer_cursor *) pCursor; simple_tokenizer *t = (simple_tokenizer *) pCursor->pTokenizer; int ii; while( c->pCurrent-c->pInput<c->nBytes ){ int n = (int) strcspn(c->pCurrent, t->zDelim); if( n>0 ){ if( n+1>c->nTokenAllocated ){ c->zToken = realloc(c->zToken, n+1); } for(ii=0; ii<n; ii++){ /* TODO(shess) This needs expansion to handle UTF-8 ** case-insensitivity. */ char ch = c->pCurrent[ii]; c->zToken[ii] = (unsigned char)ch<0x80 ? tolower((unsigned char)ch):ch; } c->zToken[n] = '\0'; *ppToken = c->zToken; *pnBytes = n; *piStartOffset = (int) (c->pCurrent-c->pInput); *piEndOffset = *piStartOffset+n; *piPosition = c->iToken++; c->pCurrent += n + 1; return SQLITE_OK; } c->pCurrent += n + 1; /* TODO(shess) could strspn() to skip delimiters en masse. Needs ** to happen in two places, though, which is annoying. */ } return SQLITE_DONE; } static sqlite3_tokenizer_module simpleTokenizerModule = { 0, simpleCreate, simpleDestroy, simpleOpen, simpleClose, simpleNext, }; void get_simple_tokenizer_module( sqlite3_tokenizer_module **ppModule ){ *ppModule = &simpleTokenizerModule; } |
Added ext/fts1/tokenizer.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 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 | /* ** 2006 July 10 ** ** The author disclaims copyright to this source code. ** ************************************************************************* ** Defines the interface to tokenizers used by fulltext-search. There ** are three basic components: ** ** sqlite3_tokenizer_module is a singleton defining the tokenizer ** interface functions. This is essentially the class structure for ** tokenizers. ** ** sqlite3_tokenizer is used to define a particular tokenizer, perhaps ** including customization information defined at creation time. ** ** sqlite3_tokenizer_cursor is generated by a tokenizer to generate ** tokens from a particular input. */ #ifndef _TOKENIZER_H_ #define _TOKENIZER_H_ /* TODO(shess) Only used for SQLITE_OK and SQLITE_DONE at this time. ** If tokenizers are to be allowed to call sqlite3_*() functions, then ** we will need a way to register the API consistently. */ #include "sqlite3.h" /* ** Structures used by the tokenizer interface. */ typedef struct sqlite3_tokenizer sqlite3_tokenizer; typedef struct sqlite3_tokenizer_cursor sqlite3_tokenizer_cursor; typedef struct sqlite3_tokenizer_module sqlite3_tokenizer_module; struct sqlite3_tokenizer_module { int iVersion; /* currently 0 */ /* ** Create and destroy a tokenizer. argc/argv are passed down from ** the fulltext virtual table creation to allow customization. */ int (*xCreate)(int argc, const char **argv, sqlite3_tokenizer **ppTokenizer); int (*xDestroy)(sqlite3_tokenizer *pTokenizer); /* ** Tokenize a particular input. Call xOpen() to prepare to ** tokenize, xNext() repeatedly until it returns SQLITE_DONE, then ** xClose() to free any internal state. The pInput passed to ** xOpen() must exist until the cursor is closed. The ppToken ** result from xNext() is only valid until the next call to xNext() ** or until xClose() is called. */ /* TODO(shess) current implementation requires pInput to be ** nul-terminated. This should either be fixed, or pInput/nBytes ** should be converted to zInput. */ int (*xOpen)(sqlite3_tokenizer *pTokenizer, const char *pInput, int nBytes, sqlite3_tokenizer_cursor **ppCursor); int (*xClose)(sqlite3_tokenizer_cursor *pCursor); int (*xNext)(sqlite3_tokenizer_cursor *pCursor, const char **ppToken, int *pnBytes, int *piStartOffset, int *piEndOffset, int *piPosition); }; struct sqlite3_tokenizer { sqlite3_tokenizer_module *pModule; /* The module for this tokenizer */ /* Tokenizer implementations will typically add additional fields */ }; struct sqlite3_tokenizer_cursor { sqlite3_tokenizer *pTokenizer; /* Tokenizer for this cursor. */ /* Tokenizer implementations will typically add additional fields */ }; /* ** Get the module for a tokenizer which generates tokens based on a ** set of non-token characters. The default is to break tokens at any ** non-alnum character, though the set of delimiters can also be ** specified by the first argv argument to xCreate(). */ /* TODO(shess) This doesn't belong here. Need some sort of ** registration process. */ void get_simple_tokenizer_module(sqlite3_tokenizer_module **ppModule); #endif /* _TOKENIZER_H_ */ |
Added ext/fts2/README.tokenizers.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | 1. FTS2 Tokenizers When creating a new full-text table, FTS2 allows the user to select the text tokenizer implementation to be used when indexing text by specifying a "tokenizer" clause as part of the CREATE VIRTUAL TABLE statement: CREATE VIRTUAL TABLE <table-name> USING fts2( <columns ...> [, tokenizer <tokenizer-name> [<tokenizer-args>]] ); The built-in tokenizers (valid values to pass as <tokenizer name>) are "simple" and "porter". <tokenizer-args> should consist of zero or more white-space separated arguments to pass to the selected tokenizer implementation. The interpretation of the arguments, if any, depends on the individual tokenizer. 2. Custom Tokenizers FTS2 allows users to provide custom tokenizer implementations. The interface used to create a new tokenizer is defined and described in the fts2_tokenizer.h source file. Registering a new FTS2 tokenizer is similar to registering a new virtual table module with SQLite. The user passes a pointer to a structure containing pointers to various callback functions that make up the implementation of the new tokenizer type. For tokenizers, the structure (defined in fts2_tokenizer.h) is called "sqlite3_tokenizer_module". FTS2 does not expose a C-function that users call to register new tokenizer types with a database handle. Instead, the pointer must be encoded as an SQL blob value and passed to FTS2 through the SQL engine by evaluating a special scalar function, "fts2_tokenizer()". The fts2_tokenizer() function may be called with one or two arguments, as follows: SELECT fts2_tokenizer(<tokenizer-name>); SELECT fts2_tokenizer(<tokenizer-name>, <sqlite3_tokenizer_module ptr>); Where <tokenizer-name> is a string identifying the tokenizer and <sqlite3_tokenizer_module ptr> is a pointer to an sqlite3_tokenizer_module structure encoded as an SQL blob. If the second argument is present, it is registered as tokenizer <tokenizer-name> and a copy of it 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 fts2 extension is used in an environment where potentially malicious users may execute arbitrary SQL (i.e. gears), they should be prevented from invoking the fts2_tokenizer() function, possibly using the authorisation callback. See "Sample code" below for an example of calling the fts2_tokenizer() function from C code. 3. ICU Library Tokenizers If this extension is compiled with the SQLITE_ENABLE_ICU pre-processor symbol defined, then there exists a built-in tokenizer named "icu" implemented using the ICU library. The first argument passed to the xCreate() method (see fts2_tokenizer.h) of this tokenizer may be an ICU locale identifier. For example "tr_TR" for Turkish as used in Turkey, or "en_AU" for English as used in Australia. For example: "CREATE VIRTUAL TABLE thai_text USING fts2(text, tokenizer icu th_TH)" The ICU tokenizer implementation is very simple. It splits the input text according to the ICU rules for finding word boundaries and discards any tokens that consist entirely of white-space. This may be suitable for some applications in some locales, but not all. If more complex processing is required, for example to implement stemming or discard punctuation, this can be done by creating a tokenizer implementation that uses the ICU tokenizer as part of its implementation. When using the ICU tokenizer this way, it is safe to overwrite the contents of the strings returned by the xNext() method (see fts2_tokenizer.h). 4. Sample code. The following two code samples illustrate the way C code should invoke the fts2_tokenizer() scalar function: int registerTokenizer( sqlite3 *db, char *zName, const sqlite3_tokenizer_module *p ){ int rc; sqlite3_stmt *pStmt; const char zSql[] = "SELECT fts2_tokenizer(?, ?)"; rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); if( rc!=SQLITE_OK ){ return rc; } sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC); sqlite3_bind_blob(pStmt, 2, &p, sizeof(p), SQLITE_STATIC); sqlite3_step(pStmt); return sqlite3_finalize(pStmt); } int queryTokenizer( sqlite3 *db, char *zName, const sqlite3_tokenizer_module **pp ){ int rc; sqlite3_stmt *pStmt; const char zSql[] = "SELECT fts2_tokenizer(?)"; *pp = 0; 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 ){ memcpy(pp, sqlite3_column_blob(pStmt, 0), sizeof(*pp)); } } return sqlite3_finalize(pStmt); } |
Added ext/fts2/README.txt.
> > > > | 1 2 3 4 | This folder contains source code to the second full-text search extension for SQLite. While the API is the same, this version uses a substantially different storage schema from fts1, so tables will need to be rebuilt. |
Added ext/fts2/fts2.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 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 | /* fts2 has a design flaw which can lead to database corruption (see ** below). It is recommended not to use it any longer, instead use ** fts3 (or higher). If you believe that your use of fts2 is safe, ** add -DSQLITE_ENABLE_BROKEN_FTS2=1 to your CFLAGS. */ #if (!defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2)) \ && !defined(SQLITE_ENABLE_BROKEN_FTS2) #error fts2 has a design flaw and has been deprecated. #endif /* The flaw is that fts2 uses the content table's unaliased rowid as ** the unique docid. fts2 embeds the rowid in the index it builds, ** and expects the rowid to not change. The SQLite VACUUM operation ** will renumber such rowids, thereby breaking fts2. If you are using ** fts2 in a system which has disabled VACUUM, then you can continue ** to use it safely. Note that PRAGMA auto_vacuum does NOT disable ** VACUUM, though systems using auto_vacuum are unlikely to invoke ** VACUUM. ** ** Unlike fts1, which is safe across VACUUM if you never delete ** documents, fts2 has a second exposure to this flaw, in the segments ** table. So fts2 should be considered unsafe across VACUUM in all ** cases. */ /* ** 2006 Oct 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 is an SQLite module implementing full-text search. */ /* ** The code in this file is only compiled if: ** ** * The FTS2 module is being built as an extension ** (in which case SQLITE_CORE is not defined), or ** ** * The FTS2 module is being built into the core of ** SQLite (in which case SQLITE_ENABLE_FTS2 is defined). */ /* TODO(shess) Consider exporting this comment to an HTML file or the ** wiki. */ /* The full-text index is stored in a series of b+tree (-like) ** structures called segments which map terms to doclists. The ** structures are like b+trees in layout, but are constructed from the ** bottom up in optimal fashion and are not updatable. Since trees ** are built from the bottom up, things will be described from the ** bottom up. ** ** **** Varints **** ** The basic unit of encoding is a variable-length integer called a ** varint. We encode variable-length integers in little-endian order ** using seven bits * per byte as follows: ** ** KEY: ** A = 0xxxxxxx 7 bits of data and one flag bit ** B = 1xxxxxxx 7 bits of data and one flag bit ** ** 7 bits - A ** 14 bits - BA ** 21 bits - BBA ** and so on. ** ** This is identical to how sqlite encodes varints (see util.c). ** ** **** Document lists **** ** A doclist (document list) holds a docid-sorted list of hits for a ** given term. Doclists hold docids, and can optionally associate ** token positions and offsets with docids. ** ** A DL_POSITIONS_OFFSETS doclist is stored like this: ** ** array { ** varint docid; ** array { (position list for column 0) ** varint position; (delta from previous position plus POS_BASE) ** varint startOffset; (delta from previous startOffset) ** varint endOffset; (delta from startOffset) ** } ** array { ** varint POS_COLUMN; (marks start of position list for new column) ** varint column; (index of new column) ** array { ** varint position; (delta from previous position plus POS_BASE) ** varint startOffset;(delta from previous startOffset) ** varint endOffset; (delta from startOffset) ** } ** } ** varint POS_END; (marks end of positions for this document. ** } ** ** Here, array { X } means zero or more occurrences of X, adjacent in ** memory. A "position" is an index of a token in the token stream ** generated by the tokenizer, while an "offset" is a byte offset, ** both based at 0. Note that POS_END and POS_COLUMN occur in the ** same logical place as the position element, and act as sentinals ** ending a position list array. ** ** A DL_POSITIONS doclist omits the startOffset and endOffset ** information. A DL_DOCIDS doclist omits both the position and ** offset information, becoming an array of varint-encoded docids. ** ** On-disk data is stored as type DL_DEFAULT, so we don't serialize ** the type. Due to how deletion is implemented in the segmentation ** system, on-disk doclists MUST store at least positions. ** ** **** Segment leaf nodes **** ** Segment leaf nodes store terms and doclists, ordered by term. Leaf ** nodes are written using LeafWriter, and read using LeafReader (to ** iterate through a single leaf node's data) and LeavesReader (to ** iterate through a segment's entire leaf layer). Leaf nodes have ** the format: ** ** varint iHeight; (height from leaf level, always 0) ** varint nTerm; (length of first term) ** char pTerm[nTerm]; (content of first term) ** varint nDoclist; (length of term's associated doclist) ** char pDoclist[nDoclist]; (content of doclist) ** array { ** (further terms are delta-encoded) ** varint nPrefix; (length of prefix shared with previous term) ** varint nSuffix; (length of unshared suffix) ** char pTermSuffix[nSuffix];(unshared suffix of next term) ** varint nDoclist; (length of term's associated doclist) ** char pDoclist[nDoclist]; (content of doclist) ** } ** ** Here, array { X } means zero or more occurrences of X, adjacent in ** memory. ** ** Leaf nodes are broken into blocks which are stored contiguously in ** the %_segments table in sorted order. This means that when the end ** of a node is reached, the next term is in the node with the next ** greater node id. ** ** New data is spilled to a new leaf node when the current node ** exceeds LEAF_MAX bytes (default 2048). New data which itself is ** larger than STANDALONE_MIN (default 1024) is placed in a standalone ** node (a leaf node with a single term and doclist). The goal of ** these settings is to pack together groups of small doclists while ** making it efficient to directly access large doclists. The ** assumption is that large doclists represent terms which are more ** likely to be query targets. ** ** TODO(shess) It may be useful for blocking decisions to be more ** dynamic. For instance, it may make more sense to have a 2.5k leaf ** node rather than splitting into 2k and .5k nodes. My intuition is ** that this might extend through 2x or 4x the pagesize. ** ** **** Segment interior nodes **** ** Segment interior nodes store blockids for subtree nodes and terms ** to describe what data is stored by the each subtree. Interior ** nodes are written using InteriorWriter, and read using ** InteriorReader. InteriorWriters are created as needed when ** SegmentWriter creates new leaf nodes, or when an interior node ** itself grows too big and must be split. The format of interior ** nodes: ** ** varint iHeight; (height from leaf level, always >0) ** varint iBlockid; (block id of node's leftmost subtree) ** optional { ** varint nTerm; (length of first term) ** char pTerm[nTerm]; (content of first term) ** array { ** (further terms are delta-encoded) ** varint nPrefix; (length of shared prefix with previous term) ** varint nSuffix; (length of unshared suffix) ** char pTermSuffix[nSuffix]; (unshared suffix of next term) ** } ** } ** ** Here, optional { X } means an optional element, while array { X } ** means zero or more occurrences of X, adjacent in memory. ** ** An interior node encodes n terms separating n+1 subtrees. The ** subtree blocks are contiguous, so only the first subtree's blockid ** is encoded. The subtree at iBlockid will contain all terms less ** than the first term encoded (or all terms if no term is encoded). ** Otherwise, for terms greater than or equal to pTerm[i] but less ** than pTerm[i+1], the subtree for that term will be rooted at ** iBlockid+i. Interior nodes only store enough term data to ** distinguish adjacent children (if the rightmost term of the left ** child is "something", and the leftmost term of the right child is ** "wicked", only "w" is stored). ** ** New data is spilled to a new interior node at the same height when ** the current node exceeds INTERIOR_MAX bytes (default 2048). ** INTERIOR_MIN_TERMS (default 7) keeps large terms from monopolizing ** interior nodes and making the tree too skinny. The interior nodes ** at a given height are naturally tracked by interior nodes at ** height+1, and so on. ** ** **** Segment directory **** ** The segment directory in table %_segdir stores meta-information for ** merging and deleting segments, and also the root node of the ** segment's tree. ** ** The root node is the top node of the segment's tree after encoding ** the entire segment, restricted to ROOT_MAX bytes (default 1024). ** This could be either a leaf node or an interior node. If the top ** node requires more than ROOT_MAX bytes, it is flushed to %_segments ** and a new root interior node is generated (which should always fit ** within ROOT_MAX because it only needs space for 2 varints, the ** height and the blockid of the previous root). ** ** The meta-information in the segment directory is: ** level - segment level (see below) ** idx - index within level ** - (level,idx uniquely identify a segment) ** start_block - first leaf node ** leaves_end_block - last leaf node ** end_block - last block (including interior nodes) ** root - contents of root node ** ** If the root node is a leaf node, then start_block, ** leaves_end_block, and end_block are all 0. ** ** **** Segment merging **** ** To amortize update costs, segments are groups into levels and ** merged in matches. Each increase in level represents exponentially ** more documents. ** ** New documents (actually, document updates) are tokenized and ** written individually (using LeafWriter) to a level 0 segment, with ** incrementing idx. When idx reaches MERGE_COUNT (default 16), all ** level 0 segments are merged into a single level 1 segment. Level 1 ** is populated like level 0, and eventually MERGE_COUNT level 1 ** segments are merged to a single level 2 segment (representing ** MERGE_COUNT^2 updates), and so on. ** ** A segment merge traverses all segments at a given level in ** parallel, performing a straightforward sorted merge. Since segment ** leaf nodes are written in to the %_segments table in order, this ** merge traverses the underlying sqlite disk structures efficiently. ** After the merge, all segment blocks from the merged level are ** deleted. ** ** MERGE_COUNT controls how often we merge segments. 16 seems to be ** somewhat of a sweet spot for insertion performance. 32 and 64 show ** very similar performance numbers to 16 on insertion, though they're ** a tiny bit slower (perhaps due to more overhead in merge-time ** sorting). 8 is about 20% slower than 16, 4 about 50% slower than ** 16, 2 about 66% slower than 16. ** ** At query time, high MERGE_COUNT increases the number of segments ** which need to be scanned and merged. For instance, with 100k docs ** inserted: ** ** MERGE_COUNT segments ** 16 25 ** 8 12 ** 4 10 ** 2 6 ** ** This appears to have only a moderate impact on queries for very ** frequent terms (which are somewhat dominated by segment merge ** costs), and infrequent and non-existent terms still seem to be fast ** even with many segments. ** ** TODO(shess) That said, it would be nice to have a better query-side ** argument for MERGE_COUNT of 16. Also, it is possible/likely that ** optimizations to things like doclist merging will swing the sweet ** spot around. ** ** ** **** Handling of deletions and updates **** ** Since we're using a segmented structure, with no docid-oriented ** index into the term index, we clearly cannot simply update the term ** index when a document is deleted or updated. For deletions, we ** write an empty doclist (varint(docid) varint(POS_END)), for updates ** we simply write the new doclist. Segment merges overwrite older ** data for a particular docid with newer data, so deletes or updates ** will eventually overtake the earlier data and knock it out. The ** query logic likewise merges doclists so that newer data knocks out ** older data. ** ** TODO(shess) Provide a VACUUM type operation to clear out all ** deletions and duplications. This would basically be a forced merge ** into a single segment. */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2) #if defined(SQLITE_ENABLE_FTS2) && !defined(SQLITE_CORE) # define SQLITE_CORE 1 #endif #include <assert.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include "fts2.h" #include "fts2_hash.h" #include "fts2_tokenizer.h" #include "sqlite3.h" #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 /* TODO(shess) MAN, this thing needs some refactoring. At minimum, it ** would be nice to order the file better, perhaps something along the ** lines of: ** ** - utility functions ** - table setup functions ** - table update functions ** - table query functions ** ** Put the query functions last because they're likely to reference ** typedefs or functions from the table update section. */ #if 0 # define TRACE(A) printf A; fflush(stdout) #else # define TRACE(A) #endif /* It is not safe to call isspace(), tolower(), or isalnum() on ** hi-bit-set characters. This is the same solution used in the ** tokenizer. */ /* TODO(shess) The snippet-generation code should be using the ** tokenizer-generated tokens rather than doing its own local ** tokenization. */ /* TODO(shess) Is __isascii() a portable version of (c&0x80)==0? */ static int safe_isspace(char c){ return c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f'; } static int safe_tolower(char c){ return (c>='A' && c<='Z') ? (c - 'A' + 'a') : c; } static int safe_isalnum(char c){ return (c>='0' && c<='9') || (c>='A' && c<='Z') || (c>='a' && c<='z'); } typedef enum DocListType { DL_DOCIDS, /* docids only */ DL_POSITIONS, /* docids + positions */ DL_POSITIONS_OFFSETS /* docids + positions + offsets */ } DocListType; /* ** By default, only positions and not offsets are stored in the doclists. ** To change this so that offsets are stored too, compile with ** ** -DDL_DEFAULT=DL_POSITIONS_OFFSETS ** ** If DL_DEFAULT is set to DL_DOCIDS, your table can only be inserted ** into (no deletes or updates). */ #ifndef DL_DEFAULT # define DL_DEFAULT DL_POSITIONS #endif enum { POS_END = 0, /* end of this position list */ POS_COLUMN, /* followed by new column number */ POS_BASE }; /* MERGE_COUNT controls how often we merge segments (see comment at ** top of file). */ #define MERGE_COUNT 16 /* utility functions */ /* CLEAR() and SCRAMBLE() abstract memset() on a pointer to a single ** record to prevent errors of the form: ** ** my_function(SomeType *b){ ** memset(b, '\0', sizeof(b)); // sizeof(b)!=sizeof(*b) ** } */ /* TODO(shess) Obvious candidates for a header file. */ #define CLEAR(b) memset(b, '\0', sizeof(*(b))) #ifndef NDEBUG # define SCRAMBLE(b) memset(b, 0x55, sizeof(*(b))) #else # define SCRAMBLE(b) #endif /* We may need up to VARINT_MAX bytes to store an encoded 64-bit integer. */ #define VARINT_MAX 10 /* Write a 64-bit variable-length integer to memory starting at p[0]. * The length of data written will be between 1 and VARINT_MAX bytes. * The number of bytes written is returned. */ static int putVarint(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 <= VARINT_MAX ); return (int) (q - (unsigned char *)p); } /* 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. */ static int getVarint(const char *p, sqlite_int64 *v){ const unsigned char *q = (const unsigned char *) p; sqlite_uint64 x = 0, y = 1; while( (*q & 0x80) == 0x80 ){ x += y * (*q++ & 0x7f); y <<= 7; if( q - (unsigned char *)p >= VARINT_MAX ){ /* bad data */ assert( 0 ); return 0; } } x += y * (*q++); *v = (sqlite_int64) x; return (int) (q - (unsigned char *)p); } static int getVarint32(const char *p, int *pi){ sqlite_int64 i; int ret = getVarint(p, &i); *pi = (int) i; assert( *pi==i ); return ret; } /*******************************************************************/ /* DataBuffer is used to collect data into a buffer in piecemeal ** fashion. It implements the usual distinction between amount of ** data currently stored (nData) and buffer capacity (nCapacity). ** ** dataBufferInit - create a buffer with given initial capacity. ** dataBufferReset - forget buffer's data, retaining capacity. ** dataBufferDestroy - free buffer's data. ** dataBufferSwap - swap contents of two buffers. ** dataBufferExpand - expand capacity without adding data. ** dataBufferAppend - append data. ** dataBufferAppend2 - append two pieces of data at once. ** dataBufferReplace - replace buffer's data. */ typedef struct DataBuffer { char *pData; /* Pointer to malloc'ed buffer. */ int nCapacity; /* Size of pData buffer. */ int nData; /* End of data loaded into pData. */ } DataBuffer; static void dataBufferInit(DataBuffer *pBuffer, int nCapacity){ assert( nCapacity>=0 ); pBuffer->nData = 0; pBuffer->nCapacity = nCapacity; pBuffer->pData = nCapacity==0 ? NULL : sqlite3_malloc(nCapacity); } static void dataBufferReset(DataBuffer *pBuffer){ pBuffer->nData = 0; } static void dataBufferDestroy(DataBuffer *pBuffer){ if( pBuffer->pData!=NULL ) sqlite3_free(pBuffer->pData); SCRAMBLE(pBuffer); } static void dataBufferSwap(DataBuffer *pBuffer1, DataBuffer *pBuffer2){ DataBuffer tmp = *pBuffer1; *pBuffer1 = *pBuffer2; *pBuffer2 = tmp; } static void dataBufferExpand(DataBuffer *pBuffer, int nAddCapacity){ assert( nAddCapacity>0 ); /* TODO(shess) Consider expanding more aggressively. Note that the ** underlying malloc implementation may take care of such things for ** us already. */ if( pBuffer->nData+nAddCapacity>pBuffer->nCapacity ){ pBuffer->nCapacity = pBuffer->nData+nAddCapacity; pBuffer->pData = sqlite3_realloc(pBuffer->pData, pBuffer->nCapacity); } } static void dataBufferAppend(DataBuffer *pBuffer, const char *pSource, int nSource){ assert( nSource>0 && pSource!=NULL ); dataBufferExpand(pBuffer, nSource); memcpy(pBuffer->pData+pBuffer->nData, pSource, nSource); pBuffer->nData += nSource; } static void dataBufferAppend2(DataBuffer *pBuffer, const char *pSource1, int nSource1, const char *pSource2, int nSource2){ assert( nSource1>0 && pSource1!=NULL ); assert( nSource2>0 && pSource2!=NULL ); dataBufferExpand(pBuffer, nSource1+nSource2); memcpy(pBuffer->pData+pBuffer->nData, pSource1, nSource1); memcpy(pBuffer->pData+pBuffer->nData+nSource1, pSource2, nSource2); pBuffer->nData += nSource1+nSource2; } static void dataBufferReplace(DataBuffer *pBuffer, const char *pSource, int nSource){ dataBufferReset(pBuffer); dataBufferAppend(pBuffer, pSource, nSource); } /* StringBuffer is a null-terminated version of DataBuffer. */ typedef struct StringBuffer { DataBuffer b; /* Includes null terminator. */ } StringBuffer; static void initStringBuffer(StringBuffer *sb){ dataBufferInit(&sb->b, 100); dataBufferReplace(&sb->b, "", 1); } static int stringBufferLength(StringBuffer *sb){ return sb->b.nData-1; } static char *stringBufferData(StringBuffer *sb){ return sb->b.pData; } static void stringBufferDestroy(StringBuffer *sb){ dataBufferDestroy(&sb->b); } static void nappend(StringBuffer *sb, const char *zFrom, int nFrom){ assert( sb->b.nData>0 ); if( nFrom>0 ){ sb->b.nData--; dataBufferAppend2(&sb->b, zFrom, nFrom, "", 1); } } static void append(StringBuffer *sb, const char *zFrom){ nappend(sb, zFrom, strlen(zFrom)); } /* Append a list of strings separated by commas. */ static void appendList(StringBuffer *sb, int nString, char **azString){ int i; for(i=0; i<nString; ++i){ if( i>0 ) append(sb, ", "); append(sb, azString[i]); } } static int endsInWhiteSpace(StringBuffer *p){ return stringBufferLength(p)>0 && safe_isspace(stringBufferData(p)[stringBufferLength(p)-1]); } /* If the StringBuffer ends in something other than white space, add a ** single space character to the end. */ static void appendWhiteSpace(StringBuffer *p){ if( stringBufferLength(p)==0 ) return; if( !endsInWhiteSpace(p) ) append(p, " "); } /* Remove white space from the end of the StringBuffer */ static void trimWhiteSpace(StringBuffer *p){ while( endsInWhiteSpace(p) ){ p->b.pData[--p->b.nData-1] = '\0'; } } /*******************************************************************/ /* DLReader is used to read document elements from a doclist. The ** current docid is cached, so dlrDocid() is fast. DLReader does not ** own the doclist buffer. ** ** dlrAtEnd - true if there's no more data to read. ** dlrDocid - docid of current document. ** dlrDocData - doclist data for current document (including docid). ** dlrDocDataBytes - length of same. ** dlrAllDataBytes - length of all remaining data. ** dlrPosData - position data for current document. ** dlrPosDataLen - length of pos data for current document (incl POS_END). ** dlrStep - step to current document. ** dlrInit - initial for doclist of given type against given data. ** dlrDestroy - clean up. ** ** Expected usage is something like: ** ** DLReader reader; ** dlrInit(&reader, pData, nData); ** while( !dlrAtEnd(&reader) ){ ** // calls to dlrDocid() and kin. ** dlrStep(&reader); ** } ** dlrDestroy(&reader); */ typedef struct DLReader { DocListType iType; const char *pData; int nData; sqlite_int64 iDocid; int nElement; } DLReader; static int dlrAtEnd(DLReader *pReader){ assert( pReader->nData>=0 ); return pReader->nData==0; } static sqlite_int64 dlrDocid(DLReader *pReader){ assert( !dlrAtEnd(pReader) ); return pReader->iDocid; } static const char *dlrDocData(DLReader *pReader){ assert( !dlrAtEnd(pReader) ); return pReader->pData; } static int dlrDocDataBytes(DLReader *pReader){ assert( !dlrAtEnd(pReader) ); return pReader->nElement; } static int dlrAllDataBytes(DLReader *pReader){ assert( !dlrAtEnd(pReader) ); return pReader->nData; } /* TODO(shess) Consider adding a field to track iDocid varint length ** to make these two functions faster. This might matter (a tiny bit) ** for queries. */ static const char *dlrPosData(DLReader *pReader){ sqlite_int64 iDummy; int n = getVarint(pReader->pData, &iDummy); assert( !dlrAtEnd(pReader) ); return pReader->pData+n; } static int dlrPosDataLen(DLReader *pReader){ sqlite_int64 iDummy; int n = getVarint(pReader->pData, &iDummy); assert( !dlrAtEnd(pReader) ); return pReader->nElement-n; } static void dlrStep(DLReader *pReader){ assert( !dlrAtEnd(pReader) ); /* Skip past current doclist element. */ assert( pReader->nElement<=pReader->nData ); pReader->pData += pReader->nElement; pReader->nData -= pReader->nElement; /* If there is more data, read the next doclist element. */ if( pReader->nData!=0 ){ sqlite_int64 iDocidDelta; int iDummy, n = getVarint(pReader->pData, &iDocidDelta); pReader->iDocid += iDocidDelta; if( pReader->iType>=DL_POSITIONS ){ assert( n<pReader->nData ); while( 1 ){ n += getVarint32(pReader->pData+n, &iDummy); assert( n<=pReader->nData ); if( iDummy==POS_END ) break; if( iDummy==POS_COLUMN ){ n += getVarint32(pReader->pData+n, &iDummy); assert( n<pReader->nData ); }else if( pReader->iType==DL_POSITIONS_OFFSETS ){ n += getVarint32(pReader->pData+n, &iDummy); n += getVarint32(pReader->pData+n, &iDummy); assert( n<pReader->nData ); } } } pReader->nElement = n; assert( pReader->nElement<=pReader->nData ); } } static void dlrInit(DLReader *pReader, DocListType iType, const char *pData, int nData){ assert( pData!=NULL && nData!=0 ); pReader->iType = iType; pReader->pData = pData; pReader->nData = nData; pReader->nElement = 0; pReader->iDocid = 0; /* Load the first element's data. There must be a first element. */ dlrStep(pReader); } static void dlrDestroy(DLReader *pReader){ SCRAMBLE(pReader); } #ifndef NDEBUG /* Verify that the doclist can be validly decoded. Also returns the ** last docid found because it is convenient in other assertions for ** DLWriter. */ static void docListValidate(DocListType iType, const char *pData, int nData, sqlite_int64 *pLastDocid){ sqlite_int64 iPrevDocid = 0; assert( nData>0 ); assert( pData!=0 ); assert( pData+nData>pData ); while( nData!=0 ){ sqlite_int64 iDocidDelta; int n = getVarint(pData, &iDocidDelta); iPrevDocid += iDocidDelta; if( iType>DL_DOCIDS ){ int iDummy; while( 1 ){ n += getVarint32(pData+n, &iDummy); if( iDummy==POS_END ) break; if( iDummy==POS_COLUMN ){ n += getVarint32(pData+n, &iDummy); }else if( iType>DL_POSITIONS ){ n += getVarint32(pData+n, &iDummy); n += getVarint32(pData+n, &iDummy); } assert( n<=nData ); } } assert( n<=nData ); pData += n; nData -= n; } if( pLastDocid ) *pLastDocid = iPrevDocid; } #define ASSERT_VALID_DOCLIST(i, p, n, o) docListValidate(i, p, n, o) #else #define ASSERT_VALID_DOCLIST(i, p, n, o) assert( 1 ) #endif /*******************************************************************/ /* DLWriter is used to write doclist data to a DataBuffer. DLWriter ** always appends to the buffer and does not own it. ** ** dlwInit - initialize to write a given type doclistto a buffer. ** dlwDestroy - clear the writer's memory. Does not free buffer. ** dlwAppend - append raw doclist data to buffer. ** dlwCopy - copy next doclist from reader to writer. ** dlwAdd - construct doclist element and append to buffer. ** Only apply dlwAdd() to DL_DOCIDS doclists (else use PLWriter). */ typedef struct DLWriter { DocListType iType; DataBuffer *b; sqlite_int64 iPrevDocid; #ifndef NDEBUG int has_iPrevDocid; #endif } DLWriter; static void dlwInit(DLWriter *pWriter, DocListType iType, DataBuffer *b){ pWriter->b = b; pWriter->iType = iType; pWriter->iPrevDocid = 0; #ifndef NDEBUG pWriter->has_iPrevDocid = 0; #endif } static void dlwDestroy(DLWriter *pWriter){ SCRAMBLE(pWriter); } /* iFirstDocid is the first docid in the doclist in pData. It is ** needed because pData may point within a larger doclist, in which ** case the first item would be delta-encoded. ** ** iLastDocid is the final docid in the doclist in pData. It is ** needed to create the new iPrevDocid for future delta-encoding. The ** code could decode the passed doclist to recreate iLastDocid, but ** the only current user (docListMerge) already has decoded this ** information. */ /* TODO(shess) This has become just a helper for docListMerge. ** Consider a refactor to make this cleaner. */ static void dlwAppend(DLWriter *pWriter, const char *pData, int nData, sqlite_int64 iFirstDocid, sqlite_int64 iLastDocid){ sqlite_int64 iDocid = 0; char c[VARINT_MAX]; int nFirstOld, nFirstNew; /* Old and new varint len of first docid. */ #ifndef NDEBUG sqlite_int64 iLastDocidDelta; #endif /* Recode the initial docid as delta from iPrevDocid. */ nFirstOld = getVarint(pData, &iDocid); assert( nFirstOld<nData || (nFirstOld==nData && pWriter->iType==DL_DOCIDS) ); nFirstNew = putVarint(c, iFirstDocid-pWriter->iPrevDocid); /* Verify that the incoming doclist is valid AND that it ends with ** the expected docid. This is essential because we'll trust this ** docid in future delta-encoding. */ ASSERT_VALID_DOCLIST(pWriter->iType, pData, nData, &iLastDocidDelta); assert( iLastDocid==iFirstDocid-iDocid+iLastDocidDelta ); /* Append recoded initial docid and everything else. Rest of docids ** should have been delta-encoded from previous initial docid. */ if( nFirstOld<nData ){ dataBufferAppend2(pWriter->b, c, nFirstNew, pData+nFirstOld, nData-nFirstOld); }else{ dataBufferAppend(pWriter->b, c, nFirstNew); } pWriter->iPrevDocid = iLastDocid; } static void dlwCopy(DLWriter *pWriter, DLReader *pReader){ dlwAppend(pWriter, dlrDocData(pReader), dlrDocDataBytes(pReader), dlrDocid(pReader), dlrDocid(pReader)); } static void dlwAdd(DLWriter *pWriter, sqlite_int64 iDocid){ char c[VARINT_MAX]; int n = putVarint(c, iDocid-pWriter->iPrevDocid); /* Docids must ascend. */ assert( !pWriter->has_iPrevDocid || iDocid>pWriter->iPrevDocid ); assert( pWriter->iType==DL_DOCIDS ); dataBufferAppend(pWriter->b, c, n); pWriter->iPrevDocid = iDocid; #ifndef NDEBUG pWriter->has_iPrevDocid = 1; #endif } /*******************************************************************/ /* PLReader is used to read data from a document's position list. As ** the caller steps through the list, data is cached so that varints ** only need to be decoded once. ** ** plrInit, plrDestroy - create/destroy a reader. ** plrColumn, plrPosition, plrStartOffset, plrEndOffset - accessors ** plrAtEnd - at end of stream, only call plrDestroy once true. ** plrStep - step to the next element. */ typedef struct PLReader { /* These refer to the next position's data. nData will reach 0 when ** reading the last position, so plrStep() signals EOF by setting ** pData to NULL. */ const char *pData; int nData; DocListType iType; int iColumn; /* the last column read */ int iPosition; /* the last position read */ int iStartOffset; /* the last start offset read */ int iEndOffset; /* the last end offset read */ } PLReader; static int plrAtEnd(PLReader *pReader){ return pReader->pData==NULL; } static int plrColumn(PLReader *pReader){ assert( !plrAtEnd(pReader) ); return pReader->iColumn; } static int plrPosition(PLReader *pReader){ assert( !plrAtEnd(pReader) ); return pReader->iPosition; } static int plrStartOffset(PLReader *pReader){ assert( !plrAtEnd(pReader) ); return pReader->iStartOffset; } static int plrEndOffset(PLReader *pReader){ assert( !plrAtEnd(pReader) ); return pReader->iEndOffset; } static void plrStep(PLReader *pReader){ int i, n; assert( !plrAtEnd(pReader) ); if( pReader->nData==0 ){ pReader->pData = NULL; return; } n = getVarint32(pReader->pData, &i); if( i==POS_COLUMN ){ n += getVarint32(pReader->pData+n, &pReader->iColumn); pReader->iPosition = 0; pReader->iStartOffset = 0; n += getVarint32(pReader->pData+n, &i); } /* Should never see adjacent column changes. */ assert( i!=POS_COLUMN ); if( i==POS_END ){ pReader->nData = 0; pReader->pData = NULL; return; } pReader->iPosition += i-POS_BASE; if( pReader->iType==DL_POSITIONS_OFFSETS ){ n += getVarint32(pReader->pData+n, &i); pReader->iStartOffset += i; n += getVarint32(pReader->pData+n, &i); pReader->iEndOffset = pReader->iStartOffset+i; } assert( n<=pReader->nData ); pReader->pData += n; pReader->nData -= n; } static void plrInit(PLReader *pReader, DLReader *pDLReader){ pReader->pData = dlrPosData(pDLReader); pReader->nData = dlrPosDataLen(pDLReader); pReader->iType = pDLReader->iType; pReader->iColumn = 0; pReader->iPosition = 0; pReader->iStartOffset = 0; pReader->iEndOffset = 0; plrStep(pReader); } static void plrDestroy(PLReader *pReader){ SCRAMBLE(pReader); } /*******************************************************************/ /* PLWriter is used in constructing a document's position list. As a ** convenience, if iType is DL_DOCIDS, PLWriter becomes a no-op. ** PLWriter writes to the associated DLWriter's buffer. ** ** plwInit - init for writing a document's poslist. ** plwDestroy - clear a writer. ** plwAdd - append position and offset information. ** plwCopy - copy next position's data from reader to writer. ** plwTerminate - add any necessary doclist terminator. ** ** Calling plwAdd() after plwTerminate() may result in a corrupt ** doclist. */ /* TODO(shess) Until we've written the second item, we can cache the ** first item's information. Then we'd have three states: ** ** - initialized with docid, no positions. ** - docid and one position. ** - docid and multiple positions. ** ** Only the last state needs to actually write to dlw->b, which would ** be an improvement in the DLCollector case. */ typedef struct PLWriter { DLWriter *dlw; int iColumn; /* the last column written */ int iPos; /* the last position written */ int iOffset; /* the last start offset written */ } PLWriter; /* TODO(shess) In the case where the parent is reading these values ** from a PLReader, we could optimize to a copy if that PLReader has ** the same type as pWriter. */ static void plwAdd(PLWriter *pWriter, int iColumn, int iPos, int iStartOffset, int iEndOffset){ /* Worst-case space for POS_COLUMN, iColumn, iPosDelta, ** iStartOffsetDelta, and iEndOffsetDelta. */ char c[5*VARINT_MAX]; int n = 0; /* Ban plwAdd() after plwTerminate(). */ assert( pWriter->iPos!=-1 ); if( pWriter->dlw->iType==DL_DOCIDS ) return; if( iColumn!=pWriter->iColumn ){ n += putVarint(c+n, POS_COLUMN); n += putVarint(c+n, iColumn); pWriter->iColumn = iColumn; pWriter->iPos = 0; pWriter->iOffset = 0; } assert( iPos>=pWriter->iPos ); n += putVarint(c+n, POS_BASE+(iPos-pWriter->iPos)); pWriter->iPos = iPos; if( pWriter->dlw->iType==DL_POSITIONS_OFFSETS ){ assert( iStartOffset>=pWriter->iOffset ); n += putVarint(c+n, iStartOffset-pWriter->iOffset); pWriter->iOffset = iStartOffset; assert( iEndOffset>=iStartOffset ); n += putVarint(c+n, iEndOffset-iStartOffset); } dataBufferAppend(pWriter->dlw->b, c, n); } static void plwCopy(PLWriter *pWriter, PLReader *pReader){ plwAdd(pWriter, plrColumn(pReader), plrPosition(pReader), plrStartOffset(pReader), plrEndOffset(pReader)); } static void plwInit(PLWriter *pWriter, DLWriter *dlw, sqlite_int64 iDocid){ char c[VARINT_MAX]; int n; pWriter->dlw = dlw; /* Docids must ascend. */ assert( !pWriter->dlw->has_iPrevDocid || iDocid>pWriter->dlw->iPrevDocid ); n = putVarint(c, iDocid-pWriter->dlw->iPrevDocid); dataBufferAppend(pWriter->dlw->b, c, n); pWriter->dlw->iPrevDocid = iDocid; #ifndef NDEBUG pWriter->dlw->has_iPrevDocid = 1; #endif pWriter->iColumn = 0; pWriter->iPos = 0; pWriter->iOffset = 0; } /* TODO(shess) Should plwDestroy() also terminate the doclist? But ** then plwDestroy() would no longer be just a destructor, it would ** also be doing work, which isn't consistent with the overall idiom. ** Another option would be for plwAdd() to always append any necessary ** terminator, so that the output is always correct. But that would ** add incremental work to the common case with the only benefit being ** API elegance. Punt for now. */ static void plwTerminate(PLWriter *pWriter){ if( pWriter->dlw->iType>DL_DOCIDS ){ char c[VARINT_MAX]; int n = putVarint(c, POS_END); dataBufferAppend(pWriter->dlw->b, c, n); } #ifndef NDEBUG /* Mark as terminated for assert in plwAdd(). */ pWriter->iPos = -1; #endif } static void plwDestroy(PLWriter *pWriter){ SCRAMBLE(pWriter); } /*******************************************************************/ /* DLCollector wraps PLWriter and DLWriter to provide a ** dynamically-allocated doclist area to use during tokenization. ** ** dlcNew - malloc up and initialize a collector. ** dlcDelete - destroy a collector and all contained items. ** dlcAddPos - append position and offset information. ** dlcAddDoclist - add the collected doclist to the given buffer. ** dlcNext - terminate the current document and open another. */ typedef struct DLCollector { DataBuffer b; DLWriter dlw; PLWriter plw; } DLCollector; /* TODO(shess) This could also be done by calling plwTerminate() and ** dataBufferAppend(). I tried that, expecting nominal performance ** differences, but it seemed to pretty reliably be worth 1% to code ** it this way. I suspect it is the incremental malloc overhead (some ** percentage of the plwTerminate() calls will cause a realloc), so ** this might be worth revisiting if the DataBuffer implementation ** changes. */ static void dlcAddDoclist(DLCollector *pCollector, DataBuffer *b){ if( pCollector->dlw.iType>DL_DOCIDS ){ char c[VARINT_MAX]; int n = putVarint(c, POS_END); dataBufferAppend2(b, pCollector->b.pData, pCollector->b.nData, c, n); }else{ dataBufferAppend(b, pCollector->b.pData, pCollector->b.nData); } } static void dlcNext(DLCollector *pCollector, sqlite_int64 iDocid){ plwTerminate(&pCollector->plw); plwDestroy(&pCollector->plw); plwInit(&pCollector->plw, &pCollector->dlw, iDocid); } static void dlcAddPos(DLCollector *pCollector, int iColumn, int iPos, int iStartOffset, int iEndOffset){ plwAdd(&pCollector->plw, iColumn, iPos, iStartOffset, iEndOffset); } static DLCollector *dlcNew(sqlite_int64 iDocid, DocListType iType){ DLCollector *pCollector = sqlite3_malloc(sizeof(DLCollector)); dataBufferInit(&pCollector->b, 0); dlwInit(&pCollector->dlw, iType, &pCollector->b); plwInit(&pCollector->plw, &pCollector->dlw, iDocid); return pCollector; } static void dlcDelete(DLCollector *pCollector){ plwDestroy(&pCollector->plw); dlwDestroy(&pCollector->dlw); dataBufferDestroy(&pCollector->b); SCRAMBLE(pCollector); sqlite3_free(pCollector); } /* Copy the doclist data of iType in pData/nData into *out, trimming ** unnecessary data as we go. Only columns matching iColumn are ** copied, all columns copied if iColumn is -1. Elements with no ** matching columns are dropped. The output is an iOutType doclist. */ /* NOTE(shess) This code is only valid after all doclists are merged. ** If this is run before merges, then doclist items which represent ** deletion will be trimmed, and will thus not effect a deletion ** during the merge. */ static void docListTrim(DocListType iType, const char *pData, int nData, int iColumn, DocListType iOutType, DataBuffer *out){ DLReader dlReader; DLWriter dlWriter; assert( iOutType<=iType ); dlrInit(&dlReader, iType, pData, nData); dlwInit(&dlWriter, iOutType, out); while( !dlrAtEnd(&dlReader) ){ PLReader plReader; PLWriter plWriter; int match = 0; plrInit(&plReader, &dlReader); while( !plrAtEnd(&plReader) ){ if( iColumn==-1 || plrColumn(&plReader)==iColumn ){ if( !match ){ plwInit(&plWriter, &dlWriter, dlrDocid(&dlReader)); match = 1; } plwAdd(&plWriter, plrColumn(&plReader), plrPosition(&plReader), plrStartOffset(&plReader), plrEndOffset(&plReader)); } plrStep(&plReader); } if( match ){ plwTerminate(&plWriter); plwDestroy(&plWriter); } plrDestroy(&plReader); dlrStep(&dlReader); } dlwDestroy(&dlWriter); dlrDestroy(&dlReader); } /* Used by docListMerge() to keep doclists in the ascending order by ** docid, then ascending order by age (so the newest comes first). */ typedef struct OrderedDLReader { DLReader *pReader; /* TODO(shess) If we assume that docListMerge pReaders is ordered by ** age (which we do), then we could use pReader comparisons to break ** ties. */ int idx; } OrderedDLReader; /* Order eof to end, then by docid asc, idx desc. */ static int orderedDLReaderCmp(OrderedDLReader *r1, OrderedDLReader *r2){ if( dlrAtEnd(r1->pReader) ){ if( dlrAtEnd(r2->pReader) ) return 0; /* Both atEnd(). */ return 1; /* Only r1 atEnd(). */ } if( dlrAtEnd(r2->pReader) ) return -1; /* Only r2 atEnd(). */ if( dlrDocid(r1->pReader)<dlrDocid(r2->pReader) ) return -1; if( dlrDocid(r1->pReader)>dlrDocid(r2->pReader) ) return 1; /* Descending on idx. */ return r2->idx-r1->idx; } /* Bubble p[0] to appropriate place in p[1..n-1]. Assumes that ** p[1..n-1] is already sorted. */ /* TODO(shess) Is this frequent enough to warrant a binary search? ** Before implementing that, instrument the code to check. In most ** current usage, I expect that p[0] will be less than p[1] a very ** high proportion of the time. */ static void orderedDLReaderReorder(OrderedDLReader *p, int n){ while( n>1 && orderedDLReaderCmp(p, p+1)>0 ){ OrderedDLReader tmp = p[0]; p[0] = p[1]; p[1] = tmp; n--; p++; } } /* Given an array of doclist readers, merge their doclist elements ** into out in sorted order (by docid), dropping elements from older ** readers when there is a duplicate docid. pReaders is assumed to be ** ordered by age, oldest first. */ /* TODO(shess) nReaders must be <= MERGE_COUNT. This should probably ** be fixed. */ static void docListMerge(DataBuffer *out, DLReader *pReaders, int nReaders){ OrderedDLReader readers[MERGE_COUNT]; DLWriter writer; int i, n; const char *pStart = 0; int nStart = 0; sqlite_int64 iFirstDocid = 0, iLastDocid = 0; assert( nReaders>0 ); if( nReaders==1 ){ dataBufferAppend(out, dlrDocData(pReaders), dlrAllDataBytes(pReaders)); return; } assert( nReaders<=MERGE_COUNT ); n = 0; for(i=0; i<nReaders; i++){ assert( pReaders[i].iType==pReaders[0].iType ); readers[i].pReader = pReaders+i; readers[i].idx = i; n += dlrAllDataBytes(&pReaders[i]); } /* Conservatively size output to sum of inputs. Output should end ** up strictly smaller than input. */ dataBufferExpand(out, n); /* Get the readers into sorted order. */ while( i-->0 ){ orderedDLReaderReorder(readers+i, nReaders-i); } dlwInit(&writer, pReaders[0].iType, out); while( !dlrAtEnd(readers[0].pReader) ){ sqlite_int64 iDocid = dlrDocid(readers[0].pReader); /* If this is a continuation of the current buffer to copy, extend ** that buffer. memcpy() seems to be more efficient if it has a ** lots of data to copy. */ if( dlrDocData(readers[0].pReader)==pStart+nStart ){ nStart += dlrDocDataBytes(readers[0].pReader); }else{ if( pStart!=0 ){ dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid); } pStart = dlrDocData(readers[0].pReader); nStart = dlrDocDataBytes(readers[0].pReader); iFirstDocid = iDocid; } iLastDocid = iDocid; dlrStep(readers[0].pReader); /* Drop all of the older elements with the same docid. */ for(i=1; i<nReaders && !dlrAtEnd(readers[i].pReader) && dlrDocid(readers[i].pReader)==iDocid; i++){ dlrStep(readers[i].pReader); } /* Get the readers back into order. */ while( i-->0 ){ orderedDLReaderReorder(readers+i, nReaders-i); } } /* Copy over any remaining elements. */ if( nStart>0 ) dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid); dlwDestroy(&writer); } /* Helper function for posListUnion(). Compares the current position ** between left and right, returning as standard C idiom of <0 if ** left<right, >0 if left>right, and 0 if left==right. "End" always ** compares greater. */ static int posListCmp(PLReader *pLeft, PLReader *pRight){ assert( pLeft->iType==pRight->iType ); if( pLeft->iType==DL_DOCIDS ) return 0; if( plrAtEnd(pLeft) ) return plrAtEnd(pRight) ? 0 : 1; if( plrAtEnd(pRight) ) return -1; if( plrColumn(pLeft)<plrColumn(pRight) ) return -1; if( plrColumn(pLeft)>plrColumn(pRight) ) return 1; if( plrPosition(pLeft)<plrPosition(pRight) ) return -1; if( plrPosition(pLeft)>plrPosition(pRight) ) return 1; if( pLeft->iType==DL_POSITIONS ) return 0; if( plrStartOffset(pLeft)<plrStartOffset(pRight) ) return -1; if( plrStartOffset(pLeft)>plrStartOffset(pRight) ) return 1; if( plrEndOffset(pLeft)<plrEndOffset(pRight) ) return -1; if( plrEndOffset(pLeft)>plrEndOffset(pRight) ) return 1; return 0; } /* Write the union of position lists in pLeft and pRight to pOut. ** "Union" in this case meaning "All unique position tuples". Should ** work with any doclist type, though both inputs and the output ** should be the same type. */ static void posListUnion(DLReader *pLeft, DLReader *pRight, DLWriter *pOut){ PLReader left, right; PLWriter writer; assert( dlrDocid(pLeft)==dlrDocid(pRight) ); assert( pLeft->iType==pRight->iType ); assert( pLeft->iType==pOut->iType ); plrInit(&left, pLeft); plrInit(&right, pRight); plwInit(&writer, pOut, dlrDocid(pLeft)); while( !plrAtEnd(&left) || !plrAtEnd(&right) ){ int c = posListCmp(&left, &right); if( c<0 ){ plwCopy(&writer, &left); plrStep(&left); }else if( c>0 ){ plwCopy(&writer, &right); plrStep(&right); }else{ plwCopy(&writer, &left); plrStep(&left); plrStep(&right); } } plwTerminate(&writer); plwDestroy(&writer); plrDestroy(&left); plrDestroy(&right); } /* Write the union of doclists in pLeft and pRight to pOut. For ** docids in common between the inputs, the union of the position ** lists is written. Inputs and outputs are always type DL_DEFAULT. */ static void docListUnion( const char *pLeft, int nLeft, const char *pRight, int nRight, DataBuffer *pOut /* Write the combined doclist here */ ){ DLReader left, right; DLWriter writer; if( nLeft==0 ){ if( nRight!=0) dataBufferAppend(pOut, pRight, nRight); return; } if( nRight==0 ){ dataBufferAppend(pOut, pLeft, nLeft); return; } dlrInit(&left, DL_DEFAULT, pLeft, nLeft); dlrInit(&right, DL_DEFAULT, pRight, nRight); dlwInit(&writer, DL_DEFAULT, pOut); while( !dlrAtEnd(&left) || !dlrAtEnd(&right) ){ if( dlrAtEnd(&right) ){ dlwCopy(&writer, &left); dlrStep(&left); }else if( dlrAtEnd(&left) ){ dlwCopy(&writer, &right); dlrStep(&right); }else if( dlrDocid(&left)<dlrDocid(&right) ){ dlwCopy(&writer, &left); dlrStep(&left); }else if( dlrDocid(&left)>dlrDocid(&right) ){ dlwCopy(&writer, &right); dlrStep(&right); }else{ posListUnion(&left, &right, &writer); dlrStep(&left); dlrStep(&right); } } dlrDestroy(&left); dlrDestroy(&right); dlwDestroy(&writer); } /* pLeft and pRight are DLReaders positioned to the same docid. ** ** If there are no instances in pLeft or pRight where the position ** of pLeft is one less than the position of pRight, then this ** routine adds nothing to pOut. ** ** If there are one or more instances where positions from pLeft ** are exactly one less than positions from pRight, then add a new ** document record to pOut. If pOut wants to hold positions, then ** include the positions from pRight that are one more than a ** position in pLeft. In other words: pRight.iPos==pLeft.iPos+1. */ static void posListPhraseMerge(DLReader *pLeft, DLReader *pRight, DLWriter *pOut){ PLReader left, right; PLWriter writer; int match = 0; assert( dlrDocid(pLeft)==dlrDocid(pRight) ); assert( pOut->iType!=DL_POSITIONS_OFFSETS ); plrInit(&left, pLeft); plrInit(&right, pRight); while( !plrAtEnd(&left) && !plrAtEnd(&right) ){ if( plrColumn(&left)<plrColumn(&right) ){ plrStep(&left); }else if( plrColumn(&left)>plrColumn(&right) ){ plrStep(&right); }else if( plrPosition(&left)+1<plrPosition(&right) ){ plrStep(&left); }else if( plrPosition(&left)+1>plrPosition(&right) ){ plrStep(&right); }else{ if( !match ){ plwInit(&writer, pOut, dlrDocid(pLeft)); match = 1; } plwAdd(&writer, plrColumn(&right), plrPosition(&right), 0, 0); plrStep(&left); plrStep(&right); } } if( match ){ plwTerminate(&writer); plwDestroy(&writer); } plrDestroy(&left); plrDestroy(&right); } /* We have two doclists with positions: pLeft and pRight. ** Write the phrase intersection of these two doclists into pOut. ** ** A phrase intersection means that two documents only match ** if pLeft.iPos+1==pRight.iPos. ** ** iType controls the type of data written to pOut. If iType is ** DL_POSITIONS, the positions are those from pRight. */ static void docListPhraseMerge( const char *pLeft, int nLeft, const char *pRight, int nRight, DocListType iType, DataBuffer *pOut /* Write the combined doclist here */ ){ DLReader left, right; DLWriter writer; if( nLeft==0 || nRight==0 ) return; assert( iType!=DL_POSITIONS_OFFSETS ); dlrInit(&left, DL_POSITIONS, pLeft, nLeft); dlrInit(&right, DL_POSITIONS, pRight, nRight); dlwInit(&writer, iType, pOut); while( !dlrAtEnd(&left) && !dlrAtEnd(&right) ){ if( dlrDocid(&left)<dlrDocid(&right) ){ dlrStep(&left); }else if( dlrDocid(&right)<dlrDocid(&left) ){ dlrStep(&right); }else{ posListPhraseMerge(&left, &right, &writer); dlrStep(&left); dlrStep(&right); } } dlrDestroy(&left); dlrDestroy(&right); dlwDestroy(&writer); } /* We have two DL_DOCIDS doclists: pLeft and pRight. ** Write the intersection of these two doclists into pOut as a ** DL_DOCIDS doclist. */ static void docListAndMerge( const char *pLeft, int nLeft, const char *pRight, int nRight, DataBuffer *pOut /* Write the combined doclist here */ ){ DLReader left, right; DLWriter writer; if( nLeft==0 || nRight==0 ) return; dlrInit(&left, DL_DOCIDS, pLeft, nLeft); dlrInit(&right, DL_DOCIDS, pRight, nRight); dlwInit(&writer, DL_DOCIDS, pOut); while( !dlrAtEnd(&left) && !dlrAtEnd(&right) ){ if( dlrDocid(&left)<dlrDocid(&right) ){ dlrStep(&left); }else if( dlrDocid(&right)<dlrDocid(&left) ){ dlrStep(&right); }else{ dlwAdd(&writer, dlrDocid(&left)); dlrStep(&left); dlrStep(&right); } } dlrDestroy(&left); dlrDestroy(&right); dlwDestroy(&writer); } /* We have two DL_DOCIDS doclists: pLeft and pRight. ** Write the union of these two doclists into pOut as a ** DL_DOCIDS doclist. */ static void docListOrMerge( const char *pLeft, int nLeft, const char *pRight, int nRight, DataBuffer *pOut /* Write the combined doclist here */ ){ DLReader left, right; DLWriter writer; if( nLeft==0 ){ if( nRight!=0 ) dataBufferAppend(pOut, pRight, nRight); return; } if( nRight==0 ){ dataBufferAppend(pOut, pLeft, nLeft); return; } dlrInit(&left, DL_DOCIDS, pLeft, nLeft); dlrInit(&right, DL_DOCIDS, pRight, nRight); dlwInit(&writer, DL_DOCIDS, pOut); while( !dlrAtEnd(&left) || !dlrAtEnd(&right) ){ if( dlrAtEnd(&right) ){ dlwAdd(&writer, dlrDocid(&left)); dlrStep(&left); }else if( dlrAtEnd(&left) ){ dlwAdd(&writer, dlrDocid(&right)); dlrStep(&right); }else if( dlrDocid(&left)<dlrDocid(&right) ){ dlwAdd(&writer, dlrDocid(&left)); dlrStep(&left); }else if( dlrDocid(&right)<dlrDocid(&left) ){ dlwAdd(&writer, dlrDocid(&right)); dlrStep(&right); }else{ dlwAdd(&writer, dlrDocid(&left)); dlrStep(&left); dlrStep(&right); } } dlrDestroy(&left); dlrDestroy(&right); dlwDestroy(&writer); } /* We have two DL_DOCIDS doclists: pLeft and pRight. ** Write into pOut as DL_DOCIDS doclist containing all documents that ** occur in pLeft but not in pRight. */ static void docListExceptMerge( const char *pLeft, int nLeft, const char *pRight, int nRight, DataBuffer *pOut /* Write the combined doclist here */ ){ DLReader left, right; DLWriter writer; if( nLeft==0 ) return; if( nRight==0 ){ dataBufferAppend(pOut, pLeft, nLeft); return; } dlrInit(&left, DL_DOCIDS, pLeft, nLeft); dlrInit(&right, DL_DOCIDS, pRight, nRight); dlwInit(&writer, DL_DOCIDS, pOut); while( !dlrAtEnd(&left) ){ while( !dlrAtEnd(&right) && dlrDocid(&right)<dlrDocid(&left) ){ dlrStep(&right); } if( dlrAtEnd(&right) || dlrDocid(&left)<dlrDocid(&right) ){ dlwAdd(&writer, dlrDocid(&left)); } dlrStep(&left); } dlrDestroy(&left); dlrDestroy(&right); dlwDestroy(&writer); } static char *string_dup_n(const char *s, int n){ char *str = sqlite3_malloc(n + 1); memcpy(str, s, n); str[n] = '\0'; return str; } /* Duplicate a string; the caller must free() the returned string. * (We don't use strdup() since it is not part of the standard C library and * may not be available everywhere.) */ static char *string_dup(const char *s){ return string_dup_n(s, strlen(s)); } /* Format a string, replacing each occurrence of the % character with * zDb.zName. This may be more convenient than sqlite_mprintf() * when one string is used repeatedly in a format string. * The caller must free() the returned string. */ static char *string_format(const char *zFormat, const char *zDb, const char *zName){ const char *p; size_t len = 0; size_t nDb = strlen(zDb); size_t nName = strlen(zName); size_t nFullTableName = nDb+1+nName; char *result; char *r; /* first compute length needed */ for(p = zFormat ; *p ; ++p){ len += (*p=='%' ? nFullTableName : 1); } len += 1; /* for null terminator */ r = result = sqlite3_malloc(len); for(p = zFormat; *p; ++p){ if( *p=='%' ){ memcpy(r, zDb, nDb); r += nDb; *r++ = '.'; memcpy(r, zName, nName); r += nName; } else { *r++ = *p; } } *r++ = '\0'; assert( r == result + len ); return result; } static int sql_exec(sqlite3 *db, const char *zDb, const char *zName, const char *zFormat){ char *zCommand = string_format(zFormat, zDb, zName); int rc; TRACE(("FTS2 sql: %s\n", zCommand)); rc = sqlite3_exec(db, zCommand, NULL, 0, NULL); sqlite3_free(zCommand); return rc; } static int sql_prepare(sqlite3 *db, const char *zDb, const char *zName, sqlite3_stmt **ppStmt, const char *zFormat){ char *zCommand = string_format(zFormat, zDb, zName); int rc; TRACE(("FTS2 prepare: %s\n", zCommand)); rc = sqlite3_prepare_v2(db, zCommand, -1, ppStmt, NULL); sqlite3_free(zCommand); return rc; } /* end utility functions */ /* Forward reference */ typedef struct fulltext_vtab fulltext_vtab; /* A single term in a query is represented by an instances of ** the following structure. */ typedef struct QueryTerm { short int nPhrase; /* How many following terms are part of the same phrase */ short int iPhrase; /* This is the i-th term of a phrase. */ short int iColumn; /* Column of the index that must match this term */ signed char isOr; /* this term is preceded by "OR" */ signed char isNot; /* this term is preceded by "-" */ signed char isPrefix; /* this term is followed by "*" */ char *pTerm; /* text of the term. '\000' terminated. malloced */ int nTerm; /* Number of bytes in pTerm[] */ } QueryTerm; /* A query string is parsed into a Query structure. * * We could, in theory, allow query strings to be complicated * nested expressions with precedence determined by parentheses. * But none of the major search engines do this. (Perhaps the * feeling is that an parenthesized expression is two complex of * an idea for the average user to grasp.) Taking our lead from * the major search engines, we will allow queries to be a list * of terms (with an implied AND operator) or phrases in double-quotes, * with a single optional "-" before each non-phrase term to designate * negation and an optional OR connector. * * OR binds more tightly than the implied AND, which is what the * major search engines seem to do. So, for example: * * [one two OR three] ==> one AND (two OR three) * [one OR two three] ==> (one OR two) AND three * * A "-" before a term matches all entries that lack that term. * The "-" must occur immediately before the term with in intervening * space. This is how the search engines do it. * * A NOT term cannot be the right-hand operand of an OR. If this * occurs in the query string, the NOT is ignored: * * [one OR -two] ==> one OR two * */ typedef struct Query { fulltext_vtab *pFts; /* The full text index */ int nTerms; /* Number of terms in the query */ QueryTerm *pTerms; /* Array of terms. Space obtained from malloc() */ int nextIsOr; /* Set the isOr flag on the next inserted term */ int nextColumn; /* Next word parsed must be in this column */ int dfltColumn; /* The default column */ } Query; /* ** An instance of the following structure keeps track of generated ** matching-word offset information and snippets. */ typedef struct Snippet { int nMatch; /* Total number of matches */ int nAlloc; /* Space allocated for aMatch[] */ struct snippetMatch { /* One entry for each matching term */ char snStatus; /* Status flag for use while constructing snippets */ short int iCol; /* The column that contains the match */ short int iTerm; /* The index in Query.pTerms[] of the matching term */ short int nByte; /* Number of bytes in the term */ int iStart; /* The offset to the first character of the term */ } *aMatch; /* Points to space obtained from malloc */ char *zOffset; /* Text rendering of aMatch[] */ int nOffset; /* strlen(zOffset) */ char *zSnippet; /* Snippet text */ int nSnippet; /* strlen(zSnippet) */ } Snippet; typedef enum QueryType { QUERY_GENERIC, /* table scan */ QUERY_ROWID, /* lookup by rowid */ QUERY_FULLTEXT /* QUERY_FULLTEXT + [i] is a full-text search for column i*/ } QueryType; typedef enum fulltext_statement { CONTENT_INSERT_STMT, CONTENT_SELECT_STMT, CONTENT_UPDATE_STMT, CONTENT_DELETE_STMT, CONTENT_EXISTS_STMT, BLOCK_INSERT_STMT, BLOCK_SELECT_STMT, BLOCK_DELETE_STMT, BLOCK_DELETE_ALL_STMT, SEGDIR_MAX_INDEX_STMT, SEGDIR_SET_STMT, SEGDIR_SELECT_LEVEL_STMT, SEGDIR_SPAN_STMT, SEGDIR_DELETE_STMT, SEGDIR_SELECT_SEGMENT_STMT, SEGDIR_SELECT_ALL_STMT, SEGDIR_DELETE_ALL_STMT, SEGDIR_COUNT_STMT, MAX_STMT /* Always at end! */ } fulltext_statement; /* These must exactly match the enum above. */ /* TODO(shess): Is there some risk that a statement will be used in two ** cursors at once, e.g. if a query joins a virtual table to itself? ** If so perhaps we should move some of these to the cursor object. */ static const char *const fulltext_zStatement[MAX_STMT] = { /* CONTENT_INSERT */ NULL, /* generated in contentInsertStatement() */ /* CONTENT_SELECT */ "select * from %_content where rowid = ?", /* CONTENT_UPDATE */ NULL, /* generated in contentUpdateStatement() */ /* CONTENT_DELETE */ "delete from %_content where rowid = ?", /* CONTENT_EXISTS */ "select rowid from %_content limit 1", /* BLOCK_INSERT */ "insert into %_segments values (?)", /* BLOCK_SELECT */ "select block from %_segments where rowid = ?", /* BLOCK_DELETE */ "delete from %_segments where rowid between ? and ?", /* BLOCK_DELETE_ALL */ "delete from %_segments", /* SEGDIR_MAX_INDEX */ "select max(idx) from %_segdir where level = ?", /* SEGDIR_SET */ "insert into %_segdir values (?, ?, ?, ?, ?, ?)", /* SEGDIR_SELECT_LEVEL */ "select start_block, leaves_end_block, root from %_segdir " " where level = ? order by idx", /* SEGDIR_SPAN */ "select min(start_block), max(end_block) from %_segdir " " where level = ? and start_block <> 0", /* SEGDIR_DELETE */ "delete from %_segdir where level = ?", /* NOTE(shess): The first three results of the following two ** statements must match. */ /* SEGDIR_SELECT_SEGMENT */ "select start_block, leaves_end_block, root from %_segdir " " where level = ? and idx = ?", /* SEGDIR_SELECT_ALL */ "select start_block, leaves_end_block, root from %_segdir " " order by level desc, idx asc", /* SEGDIR_DELETE_ALL */ "delete from %_segdir", /* SEGDIR_COUNT */ "select count(*), ifnull(max(level),0) from %_segdir", }; /* ** A connection to a fulltext index is an instance of the following ** structure. The xCreate and xConnect methods create an instance ** of this structure and xDestroy and xDisconnect free that instance. ** All other methods receive a pointer to the structure as one of their ** arguments. */ struct fulltext_vtab { sqlite3_vtab base; /* Base class used by SQLite core */ sqlite3 *db; /* The database connection */ const char *zDb; /* logical database name */ const char *zName; /* virtual table name */ int nColumn; /* number of columns in virtual table */ char **azColumn; /* column names. malloced */ char **azContentColumn; /* column names in content table; malloced */ sqlite3_tokenizer *pTokenizer; /* tokenizer for inserts and queries */ /* Precompiled statements which we keep as long as the table is ** open. */ sqlite3_stmt *pFulltextStatements[MAX_STMT]; /* Precompiled statements used for segment merges. We run a ** separate select across the leaf level of each tree being merged. */ sqlite3_stmt *pLeafSelectStmts[MERGE_COUNT]; /* The statement used to prepare pLeafSelectStmts. */ #define LEAF_SELECT \ "select block from %_segments where rowid between ? and ? order by rowid" /* These buffer pending index updates during transactions. ** nPendingData estimates the memory size of the pending data. It ** doesn't include the hash-bucket overhead, nor any malloc ** overhead. When nPendingData exceeds kPendingThreshold, the ** buffer is flushed even before the transaction closes. ** pendingTerms stores the data, and is only valid when nPendingData ** is >=0 (nPendingData<0 means pendingTerms has not been ** initialized). iPrevDocid is the last docid written, used to make ** certain we're inserting in sorted order. */ int nPendingData; #define kPendingThreshold (1*1024*1024) sqlite_int64 iPrevDocid; fts2Hash pendingTerms; }; /* ** When the core wants to do a query, it create a cursor using a ** call to xOpen. This structure is an instance of a cursor. It ** is destroyed by xClose. */ typedef struct fulltext_cursor { sqlite3_vtab_cursor base; /* Base class used by SQLite core */ QueryType iCursorType; /* Copy of sqlite3_index_info.idxNum */ sqlite3_stmt *pStmt; /* Prepared statement in use by the cursor */ int eof; /* True if at End Of Results */ Query q; /* Parsed query string */ Snippet snippet; /* Cached snippet for the current row */ int iColumn; /* Column being searched */ DataBuffer result; /* Doclist results from fulltextQuery */ DLReader reader; /* Result reader if result not empty */ } fulltext_cursor; static struct fulltext_vtab *cursor_vtab(fulltext_cursor *c){ return (fulltext_vtab *) c->base.pVtab; } static const sqlite3_module fts2Module; /* forward declaration */ /* Return a dynamically generated statement of the form * insert into %_content (rowid, ...) values (?, ...) */ static const char *contentInsertStatement(fulltext_vtab *v){ StringBuffer sb; int i; initStringBuffer(&sb); append(&sb, "insert into %_content (rowid, "); appendList(&sb, v->nColumn, v->azContentColumn); append(&sb, ") values (?"); for(i=0; i<v->nColumn; ++i) append(&sb, ", ?"); append(&sb, ")"); return stringBufferData(&sb); } /* Return a dynamically generated statement of the form * update %_content set [col_0] = ?, [col_1] = ?, ... * where rowid = ? */ static const char *contentUpdateStatement(fulltext_vtab *v){ StringBuffer sb; int i; initStringBuffer(&sb); append(&sb, "update %_content set "); for(i=0; i<v->nColumn; ++i) { if( i>0 ){ append(&sb, ", "); } append(&sb, v->azContentColumn[i]); append(&sb, " = ?"); } append(&sb, " where rowid = ?"); return stringBufferData(&sb); } /* Puts a freshly-prepared statement determined by iStmt in *ppStmt. ** If the indicated statement has never been prepared, it is prepared ** and cached, otherwise the cached version is reset. */ static int sql_get_statement(fulltext_vtab *v, fulltext_statement iStmt, sqlite3_stmt **ppStmt){ assert( iStmt<MAX_STMT ); if( v->pFulltextStatements[iStmt]==NULL ){ const char *zStmt; int rc; switch( iStmt ){ case CONTENT_INSERT_STMT: zStmt = contentInsertStatement(v); break; case CONTENT_UPDATE_STMT: zStmt = contentUpdateStatement(v); break; default: zStmt = fulltext_zStatement[iStmt]; } rc = sql_prepare(v->db, v->zDb, v->zName, &v->pFulltextStatements[iStmt], zStmt); if( zStmt != fulltext_zStatement[iStmt]) sqlite3_free((void *) zStmt); if( rc!=SQLITE_OK ) return rc; } else { int rc = sqlite3_reset(v->pFulltextStatements[iStmt]); if( rc!=SQLITE_OK ) return rc; } *ppStmt = v->pFulltextStatements[iStmt]; return SQLITE_OK; } /* Like sqlite3_step(), but convert SQLITE_DONE to SQLITE_OK and ** SQLITE_ROW to SQLITE_ERROR. Useful for statements like UPDATE, ** where we expect no results. */ static int sql_single_step(sqlite3_stmt *s){ int rc = sqlite3_step(s); return (rc==SQLITE_DONE) ? SQLITE_OK : rc; } /* Like sql_get_statement(), but for special replicated LEAF_SELECT ** statements. idx -1 is a special case for an uncached version of ** the statement (used in the optimize implementation). */ /* TODO(shess) Write version for generic statements and then share ** that between the cached-statement functions. */ static int sql_get_leaf_statement(fulltext_vtab *v, int idx, sqlite3_stmt **ppStmt){ assert( idx>=-1 && idx<MERGE_COUNT ); if( idx==-1 ){ return sql_prepare(v->db, v->zDb, v->zName, ppStmt, LEAF_SELECT); }else if( v->pLeafSelectStmts[idx]==NULL ){ int rc = sql_prepare(v->db, v->zDb, v->zName, &v->pLeafSelectStmts[idx], LEAF_SELECT); if( rc!=SQLITE_OK ) return rc; }else{ int rc = sqlite3_reset(v->pLeafSelectStmts[idx]); if( rc!=SQLITE_OK ) return rc; } *ppStmt = v->pLeafSelectStmts[idx]; return SQLITE_OK; } /* insert into %_content (rowid, ...) values ([rowid], [pValues]) */ static int content_insert(fulltext_vtab *v, sqlite3_value *rowid, sqlite3_value **pValues){ sqlite3_stmt *s; int i; int rc = sql_get_statement(v, CONTENT_INSERT_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_value(s, 1, rowid); if( rc!=SQLITE_OK ) return rc; for(i=0; i<v->nColumn; ++i){ rc = sqlite3_bind_value(s, 2+i, pValues[i]); if( rc!=SQLITE_OK ) return rc; } return sql_single_step(s); } /* update %_content set col0 = pValues[0], col1 = pValues[1], ... * where rowid = [iRowid] */ static int content_update(fulltext_vtab *v, sqlite3_value **pValues, sqlite_int64 iRowid){ sqlite3_stmt *s; int i; int rc = sql_get_statement(v, CONTENT_UPDATE_STMT, &s); if( rc!=SQLITE_OK ) return rc; for(i=0; i<v->nColumn; ++i){ rc = sqlite3_bind_value(s, 1+i, pValues[i]); if( rc!=SQLITE_OK ) return rc; } rc = sqlite3_bind_int64(s, 1+v->nColumn, iRowid); if( rc!=SQLITE_OK ) return rc; return sql_single_step(s); } static void freeStringArray(int nString, const char **pString){ int i; for (i=0 ; i < nString ; ++i) { if( pString[i]!=NULL ) sqlite3_free((void *) pString[i]); } sqlite3_free((void *) pString); } /* select * from %_content where rowid = [iRow] * The caller must delete the returned array and all strings in it. * null fields will be NULL in the returned array. * * TODO: Perhaps we should return pointer/length strings here for consistency * with other code which uses pointer/length. */ static int content_select(fulltext_vtab *v, sqlite_int64 iRow, const char ***pValues){ sqlite3_stmt *s; const char **values; int i; int rc; *pValues = NULL; rc = sql_get_statement(v, CONTENT_SELECT_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int64(s, 1, iRow); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_step(s); if( rc!=SQLITE_ROW ) return rc; values = (const char **) sqlite3_malloc(v->nColumn * sizeof(const char *)); for(i=0; i<v->nColumn; ++i){ if( sqlite3_column_type(s, i)==SQLITE_NULL ){ values[i] = NULL; }else{ values[i] = string_dup((char*)sqlite3_column_text(s, i)); } } /* We expect only one row. We must execute another sqlite3_step() * to complete the iteration; otherwise the table will remain locked. */ rc = sqlite3_step(s); if( rc==SQLITE_DONE ){ *pValues = values; return SQLITE_OK; } freeStringArray(v->nColumn, values); return rc; } /* delete from %_content where rowid = [iRow ] */ static int content_delete(fulltext_vtab *v, sqlite_int64 iRow){ sqlite3_stmt *s; int rc = sql_get_statement(v, CONTENT_DELETE_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int64(s, 1, iRow); if( rc!=SQLITE_OK ) return rc; return sql_single_step(s); } /* Returns SQLITE_ROW if any rows exist in %_content, SQLITE_DONE if ** no rows exist, and any error in case of failure. */ static int content_exists(fulltext_vtab *v){ sqlite3_stmt *s; int rc = sql_get_statement(v, CONTENT_EXISTS_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_step(s); if( rc!=SQLITE_ROW ) return rc; /* We expect only one row. We must execute another sqlite3_step() * to complete the iteration; otherwise the table will remain locked. */ rc = sqlite3_step(s); if( rc==SQLITE_DONE ) return SQLITE_ROW; if( rc==SQLITE_ROW ) return SQLITE_ERROR; return rc; } /* insert into %_segments values ([pData]) ** returns assigned rowid in *piBlockid */ static int block_insert(fulltext_vtab *v, const char *pData, int nData, sqlite_int64 *piBlockid){ sqlite3_stmt *s; int rc = sql_get_statement(v, BLOCK_INSERT_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_blob(s, 1, pData, nData, SQLITE_STATIC); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_step(s); if( rc==SQLITE_ROW ) return SQLITE_ERROR; if( rc!=SQLITE_DONE ) return rc; *piBlockid = sqlite3_last_insert_rowid(v->db); return SQLITE_OK; } /* delete from %_segments ** where rowid between [iStartBlockid] and [iEndBlockid] ** ** Deletes the range of blocks, inclusive, used to delete the blocks ** which form a segment. */ static int block_delete(fulltext_vtab *v, sqlite_int64 iStartBlockid, sqlite_int64 iEndBlockid){ sqlite3_stmt *s; int rc = sql_get_statement(v, BLOCK_DELETE_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int64(s, 1, iStartBlockid); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int64(s, 2, iEndBlockid); if( rc!=SQLITE_OK ) return rc; return sql_single_step(s); } /* Returns SQLITE_ROW with *pidx set to the maximum segment idx found ** at iLevel. Returns SQLITE_DONE if there are no segments at ** iLevel. Otherwise returns an error. */ static int segdir_max_index(fulltext_vtab *v, int iLevel, int *pidx){ sqlite3_stmt *s; int rc = sql_get_statement(v, SEGDIR_MAX_INDEX_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int(s, 1, iLevel); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_step(s); /* Should always get at least one row due to how max() works. */ if( rc==SQLITE_DONE ) return SQLITE_DONE; if( rc!=SQLITE_ROW ) return rc; /* NULL means that there were no inputs to max(). */ if( SQLITE_NULL==sqlite3_column_type(s, 0) ){ rc = sqlite3_step(s); if( rc==SQLITE_ROW ) return SQLITE_ERROR; return rc; } *pidx = sqlite3_column_int(s, 0); /* We expect only one row. We must execute another sqlite3_step() * to complete the iteration; otherwise the table will remain locked. */ rc = sqlite3_step(s); if( rc==SQLITE_ROW ) return SQLITE_ERROR; if( rc!=SQLITE_DONE ) return rc; return SQLITE_ROW; } /* insert into %_segdir values ( ** [iLevel], [idx], ** [iStartBlockid], [iLeavesEndBlockid], [iEndBlockid], ** [pRootData] ** ) */ static int segdir_set(fulltext_vtab *v, int iLevel, int idx, sqlite_int64 iStartBlockid, sqlite_int64 iLeavesEndBlockid, sqlite_int64 iEndBlockid, const char *pRootData, int nRootData){ sqlite3_stmt *s; int rc = sql_get_statement(v, SEGDIR_SET_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int(s, 1, iLevel); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int(s, 2, idx); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int64(s, 3, iStartBlockid); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int64(s, 4, iLeavesEndBlockid); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int64(s, 5, iEndBlockid); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_blob(s, 6, pRootData, nRootData, SQLITE_STATIC); if( rc!=SQLITE_OK ) return rc; return sql_single_step(s); } /* Queries %_segdir for the block span of the segments in level ** iLevel. Returns SQLITE_DONE if there are no blocks for iLevel, ** SQLITE_ROW if there are blocks, else an error. */ static int segdir_span(fulltext_vtab *v, int iLevel, sqlite_int64 *piStartBlockid, sqlite_int64 *piEndBlockid){ sqlite3_stmt *s; int rc = sql_get_statement(v, SEGDIR_SPAN_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int(s, 1, iLevel); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_step(s); if( rc==SQLITE_DONE ) return SQLITE_DONE; /* Should never happen */ if( rc!=SQLITE_ROW ) return rc; /* This happens if all segments at this level are entirely inline. */ if( SQLITE_NULL==sqlite3_column_type(s, 0) ){ /* We expect only one row. We must execute another sqlite3_step() * to complete the iteration; otherwise the table will remain locked. */ int rc2 = sqlite3_step(s); if( rc2==SQLITE_ROW ) return SQLITE_ERROR; return rc2; } *piStartBlockid = sqlite3_column_int64(s, 0); *piEndBlockid = sqlite3_column_int64(s, 1); /* We expect only one row. We must execute another sqlite3_step() * to complete the iteration; otherwise the table will remain locked. */ rc = sqlite3_step(s); if( rc==SQLITE_ROW ) return SQLITE_ERROR; if( rc!=SQLITE_DONE ) return rc; return SQLITE_ROW; } /* Delete the segment blocks and segment directory records for all ** segments at iLevel. */ static int segdir_delete(fulltext_vtab *v, int iLevel){ sqlite3_stmt *s; sqlite_int64 iStartBlockid, iEndBlockid; int rc = segdir_span(v, iLevel, &iStartBlockid, &iEndBlockid); if( rc!=SQLITE_ROW && rc!=SQLITE_DONE ) return rc; if( rc==SQLITE_ROW ){ rc = block_delete(v, iStartBlockid, iEndBlockid); if( rc!=SQLITE_OK ) return rc; } /* Delete the segment directory itself. */ rc = sql_get_statement(v, SEGDIR_DELETE_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int64(s, 1, iLevel); if( rc!=SQLITE_OK ) return rc; return sql_single_step(s); } /* Delete entire fts index, SQLITE_OK on success, relevant error on ** failure. */ static int segdir_delete_all(fulltext_vtab *v){ sqlite3_stmt *s; int rc = sql_get_statement(v, SEGDIR_DELETE_ALL_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sql_single_step(s); if( rc!=SQLITE_OK ) return rc; rc = sql_get_statement(v, BLOCK_DELETE_ALL_STMT, &s); if( rc!=SQLITE_OK ) return rc; return sql_single_step(s); } /* Returns SQLITE_OK with *pnSegments set to the number of entries in ** %_segdir and *piMaxLevel set to the highest level which has a ** segment. Otherwise returns the SQLite error which caused failure. */ static int segdir_count(fulltext_vtab *v, int *pnSegments, int *piMaxLevel){ sqlite3_stmt *s; int rc = sql_get_statement(v, SEGDIR_COUNT_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_step(s); /* TODO(shess): This case should not be possible? Should stronger ** measures be taken if it happens? */ if( rc==SQLITE_DONE ){ *pnSegments = 0; *piMaxLevel = 0; return SQLITE_OK; } if( rc!=SQLITE_ROW ) return rc; *pnSegments = sqlite3_column_int(s, 0); *piMaxLevel = sqlite3_column_int(s, 1); /* We expect only one row. We must execute another sqlite3_step() * to complete the iteration; otherwise the table will remain locked. */ rc = sqlite3_step(s); if( rc==SQLITE_DONE ) return SQLITE_OK; if( rc==SQLITE_ROW ) return SQLITE_ERROR; return rc; } /* TODO(shess) clearPendingTerms() is far down the file because ** writeZeroSegment() is far down the file because LeafWriter is far ** down the file. Consider refactoring the code to move the non-vtab ** code above the vtab code so that we don't need this forward ** reference. */ static int clearPendingTerms(fulltext_vtab *v); /* ** Free the memory used to contain a fulltext_vtab structure. */ static void fulltext_vtab_destroy(fulltext_vtab *v){ int iStmt, i; TRACE(("FTS2 Destroy %p\n", v)); for( iStmt=0; iStmt<MAX_STMT; iStmt++ ){ if( v->pFulltextStatements[iStmt]!=NULL ){ sqlite3_finalize(v->pFulltextStatements[iStmt]); v->pFulltextStatements[iStmt] = NULL; } } for( i=0; i<MERGE_COUNT; i++ ){ if( v->pLeafSelectStmts[i]!=NULL ){ sqlite3_finalize(v->pLeafSelectStmts[i]); v->pLeafSelectStmts[i] = NULL; } } if( v->pTokenizer!=NULL ){ v->pTokenizer->pModule->xDestroy(v->pTokenizer); v->pTokenizer = NULL; } clearPendingTerms(v); sqlite3_free(v->azColumn); for(i = 0; i < v->nColumn; ++i) { sqlite3_free(v->azContentColumn[i]); } sqlite3_free(v->azContentColumn); sqlite3_free(v); } /* ** Token types for parsing the arguments to xConnect or xCreate. */ #define TOKEN_EOF 0 /* End of file */ #define TOKEN_SPACE 1 /* Any kind of whitespace */ #define TOKEN_ID 2 /* An identifier */ #define TOKEN_STRING 3 /* A string literal */ #define TOKEN_PUNCT 4 /* A single punctuation character */ /* ** If X is a character that can be used in an identifier then ** IdChar(X) will be true. Otherwise it is false. ** ** For ASCII, any character with the high-order bit set is ** allowed in an identifier. For 7-bit characters, ** sqlite3IsIdChar[X] must be 1. ** ** Ticket #1066. the SQL standard does not allow '$' in the ** middle of identfiers. But many SQL implementations do. ** SQLite will allow '$' in identifiers for compatibility. ** But the feature is undocumented. */ static const char isIdChar[] = { /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */ }; #define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && isIdChar[c-0x20])) /* ** Return the length of the token that begins at z[0]. ** Store the token type in *tokenType before returning. */ static int getToken(const char *z, int *tokenType){ int i, c; switch( *z ){ case 0: { *tokenType = TOKEN_EOF; return 0; } case ' ': case '\t': case '\n': case '\f': case '\r': { for(i=1; safe_isspace(z[i]); i++){} *tokenType = TOKEN_SPACE; return i; } case '`': case '\'': case '"': { int delim = z[0]; for(i=1; (c=z[i])!=0; i++){ if( c==delim ){ if( z[i+1]==delim ){ i++; }else{ break; } } } *tokenType = TOKEN_STRING; return i + (c!=0); } case '[': { for(i=1, c=z[0]; c!=']' && (c=z[i])!=0; i++){} *tokenType = TOKEN_ID; return i; } default: { if( !IdChar(*z) ){ break; } for(i=1; IdChar(z[i]); i++){} *tokenType = TOKEN_ID; return i; } } *tokenType = TOKEN_PUNCT; return 1; } /* ** A token extracted from a string is an instance of the following ** structure. */ typedef struct Token { const char *z; /* Pointer to token text. Not '\000' terminated */ short int n; /* Length of the token text in bytes. */ } Token; /* ** Given a input string (which is really one of the argv[] parameters ** passed into xConnect or xCreate) split the string up into tokens. ** Return an array of pointers to '\000' terminated strings, one string ** for each non-whitespace token. ** ** The returned array is terminated by a single NULL pointer. ** ** Space to hold the returned array is obtained from a single ** malloc and should be freed by passing the return value to free(). ** The individual strings within the token list are all a part of ** the single memory allocation and will all be freed at once. */ static char **tokenizeString(const char *z, int *pnToken){ int nToken = 0; Token *aToken = sqlite3_malloc( strlen(z) * sizeof(aToken[0]) ); int n = 1; int e, i; int totalSize = 0; char **azToken; char *zCopy; while( n>0 ){ n = getToken(z, &e); if( e!=TOKEN_SPACE ){ aToken[nToken].z = z; aToken[nToken].n = n; nToken++; totalSize += n+1; } z += n; } azToken = (char**)sqlite3_malloc( nToken*sizeof(char*) + totalSize ); zCopy = (char*)&azToken[nToken]; nToken--; for(i=0; i<nToken; i++){ azToken[i] = zCopy; n = aToken[i].n; memcpy(zCopy, aToken[i].z, n); zCopy[n] = 0; zCopy += n+1; } azToken[nToken] = 0; sqlite3_free(aToken); *pnToken = nToken; return azToken; } /* ** 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. ** ** Examples: ** ** "abc" becomes abc ** 'xyz' becomes xyz ** [pqr] becomes pqr ** `mno` becomes mno */ static void dequoteString(char *z){ int quote; int i, j; if( z==0 ) return; quote = z[0]; switch( quote ){ case '\'': break; case '"': break; case '`': break; /* For MySQL compatibility */ case '[': quote = ']'; break; /* For MS SqlServer compatibility */ default: return; } for(i=1, j=0; z[i]; i++){ if( z[i]==quote ){ if( z[i+1]==quote ){ z[j++] = quote; i++; }else{ z[j++] = 0; break; } }else{ z[j++] = z[i]; } } } /* ** The input azIn is a NULL-terminated list of tokens. Remove the first ** token and all punctuation tokens. Remove the quotes from ** around string literal tokens. ** ** Example: ** ** input: tokenize chinese ( 'simplifed' , 'mixed' ) ** output: chinese simplifed mixed ** ** Another example: ** ** input: delimiters ( '[' , ']' , '...' ) ** output: [ ] ... */ static void tokenListToIdList(char **azIn){ int i, j; if( azIn ){ for(i=0, j=-1; azIn[i]; i++){ if( safe_isalnum(azIn[i][0]) || azIn[i][1] ){ dequoteString(azIn[i]); if( j>=0 ){ azIn[j] = azIn[i]; } j++; } } azIn[j] = 0; } } /* ** Find the first alphanumeric token in the string zIn. Null-terminate ** this token. Remove any quotation marks. And return a pointer to ** the result. */ static char *firstToken(char *zIn, char **pzTail){ int n, ttype; while(1){ n = getToken(zIn, &ttype); if( ttype==TOKEN_SPACE ){ zIn += n; }else if( ttype==TOKEN_EOF ){ *pzTail = zIn; return 0; }else{ zIn[n] = 0; *pzTail = &zIn[1]; dequoteString(zIn); return zIn; } } /*NOTREACHED*/ } /* Return true if... ** ** * s begins with the string t, ignoring case ** * s is longer than t ** * The first character of s beyond t is not a alphanumeric ** ** Ignore leading space in *s. ** ** To put it another way, return true if the first token of ** s[] is t[]. */ static int startsWith(const char *s, const char *t){ while( safe_isspace(*s) ){ s++; } while( *t ){ if( safe_tolower(*s++)!=safe_tolower(*t++) ) return 0; } return *s!='_' && !safe_isalnum(*s); } /* ** An instance of this structure defines the "spec" of a ** full text index. This structure is populated by parseSpec ** and use by fulltextConnect and fulltextCreate. */ typedef struct TableSpec { const char *zDb; /* Logical database name */ const char *zName; /* Name of the full-text index */ int nColumn; /* Number of columns to be indexed */ char **azColumn; /* Original names of columns to be indexed */ char **azContentColumn; /* Column names for %_content */ char **azTokenizer; /* Name of tokenizer and its arguments */ } TableSpec; /* ** Reclaim all of the memory used by a TableSpec */ static void clearTableSpec(TableSpec *p) { sqlite3_free(p->azColumn); sqlite3_free(p->azContentColumn); sqlite3_free(p->azTokenizer); } /* Parse a CREATE VIRTUAL TABLE statement, which looks like this: * * CREATE VIRTUAL TABLE email * USING fts2(subject, body, tokenize mytokenizer(myarg)) * * We return parsed information in a TableSpec structure. * */ static int parseSpec(TableSpec *pSpec, int argc, const char *const*argv, char**pzErr){ int i, n; char *z, *zDummy; char **azArg; const char *zTokenizer = 0; /* argv[] entry describing the tokenizer */ assert( argc>=3 ); /* Current interface: ** argv[0] - module name ** argv[1] - database name ** argv[2] - table name ** argv[3..] - columns, optionally followed by tokenizer specification ** and snippet delimiters specification. */ /* Make a copy of the complete argv[][] array in a single allocation. ** The argv[][] array is read-only and transient. We can write to the ** copy in order to modify things and the copy is persistent. */ CLEAR(pSpec); for(i=n=0; i<argc; i++){ n += strlen(argv[i]) + 1; } azArg = sqlite3_malloc( sizeof(char*)*argc + n ); if( azArg==0 ){ return SQLITE_NOMEM; } z = (char*)&azArg[argc]; for(i=0; i<argc; i++){ azArg[i] = z; strcpy(z, argv[i]); z += strlen(z)+1; } /* Identify the column names and the tokenizer and delimiter arguments ** in the argv[][] array. */ pSpec->zDb = azArg[1]; pSpec->zName = azArg[2]; pSpec->nColumn = 0; pSpec->azColumn = azArg; zTokenizer = "tokenize simple"; for(i=3; i<argc; ++i){ if( startsWith(azArg[i],"tokenize") ){ zTokenizer = azArg[i]; }else{ z = azArg[pSpec->nColumn] = firstToken(azArg[i], &zDummy); pSpec->nColumn++; } } if( pSpec->nColumn==0 ){ azArg[0] = "content"; pSpec->nColumn = 1; } /* ** Construct the list of content column names. ** ** Each content column name will be of the form cNNAAAA ** where NN is the column number and AAAA is the sanitized ** column name. "sanitized" means that special characters are ** converted to "_". The cNN prefix guarantees that all column ** names are unique. ** ** The AAAA suffix is not strictly necessary. It is included ** for the convenience of people who might examine the generated ** %_content table and wonder what the columns are used for. */ pSpec->azContentColumn = sqlite3_malloc( pSpec->nColumn * sizeof(char *) ); if( pSpec->azContentColumn==0 ){ clearTableSpec(pSpec); return SQLITE_NOMEM; } for(i=0; i<pSpec->nColumn; i++){ char *p; pSpec->azContentColumn[i] = sqlite3_mprintf("c%d%s", i, azArg[i]); for (p = pSpec->azContentColumn[i]; *p ; ++p) { if( !safe_isalnum(*p) ) *p = '_'; } } /* ** Parse the tokenizer specification string. */ pSpec->azTokenizer = tokenizeString(zTokenizer, &n); tokenListToIdList(pSpec->azTokenizer); return SQLITE_OK; } /* ** Generate a CREATE TABLE statement that describes the schema of ** the virtual table. Return a pointer to this schema string. ** ** Space is obtained from sqlite3_mprintf() and should be freed ** using sqlite3_free(). */ static char *fulltextSchema( int nColumn, /* Number of columns */ const char *const* azColumn, /* List of columns */ const char *zTableName /* Name of the table */ ){ int i; char *zSchema, *zNext; const char *zSep = "("; zSchema = sqlite3_mprintf("CREATE TABLE x"); for(i=0; i<nColumn; i++){ zNext = sqlite3_mprintf("%s%s%Q", zSchema, zSep, azColumn[i]); sqlite3_free(zSchema); zSchema = zNext; zSep = ","; } zNext = sqlite3_mprintf("%s,%Q)", zSchema, zTableName); sqlite3_free(zSchema); return zNext; } /* ** Build a new sqlite3_vtab structure that will describe the ** fulltext index defined by spec. */ static int constructVtab( sqlite3 *db, /* The SQLite database connection */ fts2Hash *pHash, /* Hash table containing tokenizers */ TableSpec *spec, /* Parsed spec information from parseSpec() */ sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */ char **pzErr /* Write any error message here */ ){ int rc; int n; fulltext_vtab *v = 0; const sqlite3_tokenizer_module *m = NULL; char *schema; char const *zTok; /* Name of tokenizer to use for this fts table */ int nTok; /* Length of zTok, including nul terminator */ v = (fulltext_vtab *) sqlite3_malloc(sizeof(fulltext_vtab)); if( v==0 ) return SQLITE_NOMEM; CLEAR(v); /* sqlite will initialize v->base */ v->db = db; v->zDb = spec->zDb; /* Freed when azColumn is freed */ v->zName = spec->zName; /* Freed when azColumn is freed */ v->nColumn = spec->nColumn; v->azContentColumn = spec->azContentColumn; spec->azContentColumn = 0; v->azColumn = spec->azColumn; spec->azColumn = 0; if( spec->azTokenizer==0 ){ return SQLITE_NOMEM; } zTok = spec->azTokenizer[0]; if( !zTok ){ zTok = "simple"; } nTok = strlen(zTok)+1; m = (sqlite3_tokenizer_module *)sqlite3Fts2HashFind(pHash, zTok, nTok); if( !m ){ *pzErr = sqlite3_mprintf("unknown tokenizer: %s", spec->azTokenizer[0]); rc = SQLITE_ERROR; goto err; } for(n=0; spec->azTokenizer[n]; n++){} if( n ){ rc = m->xCreate(n-1, (const char*const*)&spec->azTokenizer[1], &v->pTokenizer); }else{ rc = m->xCreate(0, 0, &v->pTokenizer); } if( rc!=SQLITE_OK ) goto err; v->pTokenizer->pModule = m; /* TODO: verify the existence of backing tables foo_content, foo_term */ schema = fulltextSchema(v->nColumn, (const char*const*)v->azColumn, spec->zName); rc = sqlite3_declare_vtab(db, schema); sqlite3_free(schema); if( rc!=SQLITE_OK ) goto err; memset(v->pFulltextStatements, 0, sizeof(v->pFulltextStatements)); /* Indicate that the buffer is not live. */ v->nPendingData = -1; *ppVTab = &v->base; TRACE(("FTS2 Connect %p\n", v)); return rc; err: fulltext_vtab_destroy(v); return rc; } static int fulltextConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char **pzErr ){ TableSpec spec; int rc = parseSpec(&spec, argc, argv, pzErr); if( rc!=SQLITE_OK ) return rc; rc = constructVtab(db, (fts2Hash *)pAux, &spec, ppVTab, pzErr); clearTableSpec(&spec); return rc; } /* The %_content table holds the text of each document, with ** the rowid used as the docid. */ /* TODO(shess) This comment needs elaboration to match the updated ** code. Work it into the top-of-file comment at that time. */ static int fulltextCreate(sqlite3 *db, void *pAux, int argc, const char * const *argv, sqlite3_vtab **ppVTab, char **pzErr){ int rc; TableSpec spec; StringBuffer schema; TRACE(("FTS2 Create\n")); rc = parseSpec(&spec, argc, argv, pzErr); if( rc!=SQLITE_OK ) return rc; initStringBuffer(&schema); append(&schema, "CREATE TABLE %_content("); appendList(&schema, spec.nColumn, spec.azContentColumn); append(&schema, ")"); rc = sql_exec(db, spec.zDb, spec.zName, stringBufferData(&schema)); stringBufferDestroy(&schema); if( rc!=SQLITE_OK ) goto out; rc = sql_exec(db, spec.zDb, spec.zName, "create table %_segments(block blob);"); if( rc!=SQLITE_OK ) goto out; rc = sql_exec(db, spec.zDb, spec.zName, "create table %_segdir(" " level integer," " idx integer," " start_block integer," " leaves_end_block integer," " end_block integer," " root blob," " primary key(level, idx)" ");"); if( rc!=SQLITE_OK ) goto out; rc = constructVtab(db, (fts2Hash *)pAux, &spec, ppVTab, pzErr); out: clearTableSpec(&spec); return rc; } /* Decide how to handle an SQL query. */ static int fulltextBestIndex(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ int i; TRACE(("FTS2 BestIndex\n")); for(i=0; i<pInfo->nConstraint; ++i){ const struct sqlite3_index_constraint *pConstraint; pConstraint = &pInfo->aConstraint[i]; if( pConstraint->usable ) { if( pConstraint->iColumn==-1 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ ){ pInfo->idxNum = QUERY_ROWID; /* lookup by rowid */ TRACE(("FTS2 QUERY_ROWID\n")); } else if( pConstraint->iColumn>=0 && pConstraint->op==SQLITE_INDEX_CONSTRAINT_MATCH ){ /* full-text search */ pInfo->idxNum = QUERY_FULLTEXT + pConstraint->iColumn; TRACE(("FTS2 QUERY_FULLTEXT %d\n", pConstraint->iColumn)); } else continue; pInfo->aConstraintUsage[i].argvIndex = 1; pInfo->aConstraintUsage[i].omit = 1; /* An arbitrary value for now. * TODO: Perhaps rowid matches should be considered cheaper than * full-text searches. */ pInfo->estimatedCost = 1.0; return SQLITE_OK; } } pInfo->idxNum = QUERY_GENERIC; return SQLITE_OK; } static int fulltextDisconnect(sqlite3_vtab *pVTab){ TRACE(("FTS2 Disconnect %p\n", pVTab)); fulltext_vtab_destroy((fulltext_vtab *)pVTab); return SQLITE_OK; } static int fulltextDestroy(sqlite3_vtab *pVTab){ fulltext_vtab *v = (fulltext_vtab *)pVTab; int rc; TRACE(("FTS2 Destroy %p\n", pVTab)); rc = sql_exec(v->db, v->zDb, v->zName, "drop table if exists %_content;" "drop table if exists %_segments;" "drop table if exists %_segdir;" ); if( rc!=SQLITE_OK ) return rc; fulltext_vtab_destroy((fulltext_vtab *)pVTab); return SQLITE_OK; } static int fulltextOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ fulltext_cursor *c; c = (fulltext_cursor *) sqlite3_malloc(sizeof(fulltext_cursor)); if( c ){ memset(c, 0, sizeof(fulltext_cursor)); /* sqlite will initialize c->base */ *ppCursor = &c->base; TRACE(("FTS2 Open %p: %p\n", pVTab, c)); return SQLITE_OK; }else{ return SQLITE_NOMEM; } } /* Free all of the dynamically allocated memory held by *q */ static void queryClear(Query *q){ int i; for(i = 0; i < q->nTerms; ++i){ sqlite3_free(q->pTerms[i].pTerm); } sqlite3_free(q->pTerms); CLEAR(q); } /* Free all of the dynamically allocated memory held by the ** Snippet */ static void snippetClear(Snippet *p){ sqlite3_free(p->aMatch); sqlite3_free(p->zOffset); sqlite3_free(p->zSnippet); CLEAR(p); } /* ** Append a single entry to the p->aMatch[] log. */ static void snippetAppendMatch( Snippet *p, /* Append the entry to this snippet */ int iCol, int iTerm, /* The column and query term */ int iStart, int nByte /* Offset and size of the match */ ){ int i; struct snippetMatch *pMatch; if( p->nMatch+1>=p->nAlloc ){ p->nAlloc = p->nAlloc*2 + 10; p->aMatch = sqlite3_realloc(p->aMatch, p->nAlloc*sizeof(p->aMatch[0]) ); if( p->aMatch==0 ){ p->nMatch = 0; p->nAlloc = 0; return; } } i = p->nMatch++; pMatch = &p->aMatch[i]; pMatch->iCol = iCol; pMatch->iTerm = iTerm; pMatch->iStart = iStart; pMatch->nByte = nByte; } /* ** Sizing information for the circular buffer used in snippetOffsetsOfColumn() */ #define FTS2_ROTOR_SZ (32) #define FTS2_ROTOR_MASK (FTS2_ROTOR_SZ-1) /* ** Add entries to pSnippet->aMatch[] for every match that occurs against ** document zDoc[0..nDoc-1] which is stored in column iColumn. */ static void snippetOffsetsOfColumn( Query *pQuery, Snippet *pSnippet, int iColumn, const char *zDoc, int nDoc ){ const sqlite3_tokenizer_module *pTModule; /* The tokenizer module */ sqlite3_tokenizer *pTokenizer; /* The specific tokenizer */ sqlite3_tokenizer_cursor *pTCursor; /* Tokenizer cursor */ fulltext_vtab *pVtab; /* The full text index */ int nColumn; /* Number of columns in the index */ const QueryTerm *aTerm; /* Query string terms */ int nTerm; /* Number of query string terms */ int i, j; /* Loop counters */ int rc; /* Return code */ unsigned int match, prevMatch; /* Phrase search bitmasks */ const char *zToken; /* Next token from the tokenizer */ int nToken; /* Size of zToken */ int iBegin, iEnd, iPos; /* Offsets of beginning and end */ /* The following variables keep a circular buffer of the last ** few tokens */ unsigned int iRotor = 0; /* Index of current token */ int iRotorBegin[FTS2_ROTOR_SZ]; /* Beginning offset of token */ int iRotorLen[FTS2_ROTOR_SZ]; /* Length of token */ pVtab = pQuery->pFts; nColumn = pVtab->nColumn; pTokenizer = pVtab->pTokenizer; pTModule = pTokenizer->pModule; rc = pTModule->xOpen(pTokenizer, zDoc, nDoc, &pTCursor); if( rc ) return; pTCursor->pTokenizer = pTokenizer; aTerm = pQuery->pTerms; nTerm = pQuery->nTerms; if( nTerm>=FTS2_ROTOR_SZ ){ nTerm = FTS2_ROTOR_SZ - 1; } prevMatch = 0; while(1){ rc = pTModule->xNext(pTCursor, &zToken, &nToken, &iBegin, &iEnd, &iPos); if( rc ) break; iRotorBegin[iRotor&FTS2_ROTOR_MASK] = iBegin; iRotorLen[iRotor&FTS2_ROTOR_MASK] = iEnd-iBegin; match = 0; for(i=0; i<nTerm; i++){ int iCol; iCol = aTerm[i].iColumn; if( iCol>=0 && iCol<nColumn && iCol!=iColumn ) continue; if( aTerm[i].nTerm>nToken ) continue; if( !aTerm[i].isPrefix && aTerm[i].nTerm<nToken ) continue; assert( aTerm[i].nTerm<=nToken ); if( memcmp(aTerm[i].pTerm, zToken, aTerm[i].nTerm) ) continue; if( aTerm[i].iPhrase>1 && (prevMatch & (1<<i))==0 ) continue; match |= 1<<i; if( i==nTerm-1 || aTerm[i+1].iPhrase==1 ){ for(j=aTerm[i].iPhrase-1; j>=0; j--){ int k = (iRotor-j) & FTS2_ROTOR_MASK; snippetAppendMatch(pSnippet, iColumn, i-j, iRotorBegin[k], iRotorLen[k]); } } } prevMatch = match<<1; iRotor++; } pTModule->xClose(pTCursor); } /* ** Compute all offsets for the current row of the query. ** If the offsets have already been computed, this routine is a no-op. */ static void snippetAllOffsets(fulltext_cursor *p){ int nColumn; int iColumn, i; int iFirst, iLast; fulltext_vtab *pFts; if( p->snippet.nMatch ) return; if( p->q.nTerms==0 ) return; pFts = p->q.pFts; nColumn = pFts->nColumn; iColumn = (p->iCursorType - QUERY_FULLTEXT); if( iColumn<0 || iColumn>=nColumn ){ iFirst = 0; iLast = nColumn-1; }else{ iFirst = iColumn; iLast = iColumn; } for(i=iFirst; i<=iLast; i++){ const char *zDoc; int nDoc; zDoc = (const char*)sqlite3_column_text(p->pStmt, i+1); nDoc = sqlite3_column_bytes(p->pStmt, i+1); snippetOffsetsOfColumn(&p->q, &p->snippet, i, zDoc, nDoc); } } /* ** Convert the information in the aMatch[] array of the snippet ** into the string zOffset[0..nOffset-1]. */ static void snippetOffsetText(Snippet *p){ int i; int cnt = 0; StringBuffer sb; char zBuf[200]; if( p->zOffset ) return; initStringBuffer(&sb); for(i=0; i<p->nMatch; i++){ struct snippetMatch *pMatch = &p->aMatch[i]; zBuf[0] = ' '; sqlite3_snprintf(sizeof(zBuf)-1, &zBuf[cnt>0], "%d %d %d %d", pMatch->iCol, pMatch->iTerm, pMatch->iStart, pMatch->nByte); append(&sb, zBuf); cnt++; } p->zOffset = stringBufferData(&sb); p->nOffset = stringBufferLength(&sb); } /* ** zDoc[0..nDoc-1] is phrase of text. aMatch[0..nMatch-1] are a set ** of matching words some of which might be in zDoc. zDoc is column ** number iCol. ** ** iBreak is suggested spot in zDoc where we could begin or end an ** excerpt. Return a value similar to iBreak but possibly adjusted ** to be a little left or right so that the break point is better. */ static int wordBoundary( int iBreak, /* The suggested break point */ const char *zDoc, /* Document text */ int nDoc, /* Number of bytes in zDoc[] */ struct snippetMatch *aMatch, /* Matching words */ int nMatch, /* Number of entries in aMatch[] */ int iCol /* The column number for zDoc[] */ ){ int i; if( iBreak<=10 ){ return 0; } if( iBreak>=nDoc-10 ){ return nDoc; } for(i=0; i<nMatch && aMatch[i].iCol<iCol; i++){} while( i<nMatch && aMatch[i].iStart+aMatch[i].nByte<iBreak ){ i++; } if( i<nMatch ){ if( aMatch[i].iStart<iBreak+10 ){ return aMatch[i].iStart; } if( i>0 && aMatch[i-1].iStart+aMatch[i-1].nByte>=iBreak ){ return aMatch[i-1].iStart; } } for(i=1; i<=10; i++){ if( safe_isspace(zDoc[iBreak-i]) ){ return iBreak - i + 1; } if( safe_isspace(zDoc[iBreak+i]) ){ return iBreak + i + 1; } } return iBreak; } /* ** Allowed values for Snippet.aMatch[].snStatus */ #define SNIPPET_IGNORE 0 /* It is ok to omit this match from the snippet */ #define SNIPPET_DESIRED 1 /* We want to include this match in the snippet */ /* ** Generate the text of a snippet. */ static void snippetText( fulltext_cursor *pCursor, /* The cursor we need the snippet for */ const char *zStartMark, /* Markup to appear before each match */ const char *zEndMark, /* Markup to appear after each match */ const char *zEllipsis /* Ellipsis mark */ ){ int i, j; struct snippetMatch *aMatch; int nMatch; int nDesired; StringBuffer sb; int tailCol; int tailOffset; int iCol; int nDoc; const char *zDoc; int iStart, iEnd; int tailEllipsis = 0; int iMatch; sqlite3_free(pCursor->snippet.zSnippet); pCursor->snippet.zSnippet = 0; aMatch = pCursor->snippet.aMatch; nMatch = pCursor->snippet.nMatch; initStringBuffer(&sb); for(i=0; i<nMatch; i++){ aMatch[i].snStatus = SNIPPET_IGNORE; } nDesired = 0; for(i=0; i<pCursor->q.nTerms; i++){ for(j=0; j<nMatch; j++){ if( aMatch[j].iTerm==i ){ aMatch[j].snStatus = SNIPPET_DESIRED; nDesired++; break; } } } iMatch = 0; tailCol = -1; tailOffset = 0; for(i=0; i<nMatch && nDesired>0; i++){ if( aMatch[i].snStatus!=SNIPPET_DESIRED ) continue; nDesired--; iCol = aMatch[i].iCol; zDoc = (const char*)sqlite3_column_text(pCursor->pStmt, iCol+1); nDoc = sqlite3_column_bytes(pCursor->pStmt, iCol+1); iStart = aMatch[i].iStart - 40; iStart = wordBoundary(iStart, zDoc, nDoc, aMatch, nMatch, iCol); if( iStart<=10 ){ iStart = 0; } if( iCol==tailCol && iStart<=tailOffset+20 ){ iStart = tailOffset; } if( (iCol!=tailCol && tailCol>=0) || iStart!=tailOffset ){ trimWhiteSpace(&sb); appendWhiteSpace(&sb); append(&sb, zEllipsis); appendWhiteSpace(&sb); } iEnd = aMatch[i].iStart + aMatch[i].nByte + 40; iEnd = wordBoundary(iEnd, zDoc, nDoc, aMatch, nMatch, iCol); if( iEnd>=nDoc-10 ){ iEnd = nDoc; tailEllipsis = 0; }else{ tailEllipsis = 1; } while( iMatch<nMatch && aMatch[iMatch].iCol<iCol ){ iMatch++; } while( iStart<iEnd ){ while( iMatch<nMatch && aMatch[iMatch].iStart<iStart && aMatch[iMatch].iCol<=iCol ){ iMatch++; } if( iMatch<nMatch && aMatch[iMatch].iStart<iEnd && aMatch[iMatch].iCol==iCol ){ nappend(&sb, &zDoc[iStart], aMatch[iMatch].iStart - iStart); iStart = aMatch[iMatch].iStart; append(&sb, zStartMark); nappend(&sb, &zDoc[iStart], aMatch[iMatch].nByte); append(&sb, zEndMark); iStart += aMatch[iMatch].nByte; for(j=iMatch+1; j<nMatch; j++){ if( aMatch[j].iTerm==aMatch[iMatch].iTerm && aMatch[j].snStatus==SNIPPET_DESIRED ){ nDesired--; aMatch[j].snStatus = SNIPPET_IGNORE; } } }else{ nappend(&sb, &zDoc[iStart], iEnd - iStart); iStart = iEnd; } } tailCol = iCol; tailOffset = iEnd; } trimWhiteSpace(&sb); if( tailEllipsis ){ appendWhiteSpace(&sb); append(&sb, zEllipsis); } pCursor->snippet.zSnippet = stringBufferData(&sb); pCursor->snippet.nSnippet = stringBufferLength(&sb); } /* ** Close the cursor. For additional information see the documentation ** on the xClose method of the virtual table interface. */ static int fulltextClose(sqlite3_vtab_cursor *pCursor){ fulltext_cursor *c = (fulltext_cursor *) pCursor; TRACE(("FTS2 Close %p\n", c)); sqlite3_finalize(c->pStmt); queryClear(&c->q); snippetClear(&c->snippet); if( c->result.nData!=0 ) dlrDestroy(&c->reader); dataBufferDestroy(&c->result); sqlite3_free(c); return SQLITE_OK; } static int fulltextNext(sqlite3_vtab_cursor *pCursor){ fulltext_cursor *c = (fulltext_cursor *) pCursor; int rc; TRACE(("FTS2 Next %p\n", pCursor)); snippetClear(&c->snippet); if( c->iCursorType < QUERY_FULLTEXT ){ /* TODO(shess) Handle SQLITE_SCHEMA AND SQLITE_BUSY. */ rc = sqlite3_step(c->pStmt); switch( rc ){ case SQLITE_ROW: c->eof = 0; return SQLITE_OK; case SQLITE_DONE: c->eof = 1; return SQLITE_OK; default: c->eof = 1; return rc; } } else { /* full-text query */ rc = sqlite3_reset(c->pStmt); if( rc!=SQLITE_OK ) return rc; if( c->result.nData==0 || dlrAtEnd(&c->reader) ){ c->eof = 1; return SQLITE_OK; } rc = sqlite3_bind_int64(c->pStmt, 1, dlrDocid(&c->reader)); dlrStep(&c->reader); if( rc!=SQLITE_OK ) return rc; /* TODO(shess) Handle SQLITE_SCHEMA AND SQLITE_BUSY. */ rc = sqlite3_step(c->pStmt); if( rc==SQLITE_ROW ){ /* the case we expect */ c->eof = 0; return SQLITE_OK; } /* an error occurred; abort */ return rc==SQLITE_DONE ? SQLITE_ERROR : rc; } } /* TODO(shess) If we pushed LeafReader to the top of the file, or to ** another file, term_select() could be pushed above ** docListOfTerm(). */ static int termSelect(fulltext_vtab *v, int iColumn, const char *pTerm, int nTerm, int isPrefix, DocListType iType, DataBuffer *out); /* Return a DocList corresponding to the query term *pTerm. If *pTerm ** is the first term of a phrase query, go ahead and evaluate the phrase ** query and return the doclist for the entire phrase query. ** ** The resulting DL_DOCIDS doclist is stored in pResult, which is ** overwritten. */ static int docListOfTerm( fulltext_vtab *v, /* The full text index */ int iColumn, /* column to restrict to. No restriction if >=nColumn */ QueryTerm *pQTerm, /* Term we are looking for, or 1st term of a phrase */ DataBuffer *pResult /* Write the result here */ ){ DataBuffer left, right, new; int i, rc; /* No phrase search if no position info. */ assert( pQTerm->nPhrase==0 || DL_DEFAULT!=DL_DOCIDS ); /* This code should never be called with buffered updates. */ assert( v->nPendingData<0 ); dataBufferInit(&left, 0); rc = termSelect(v, iColumn, pQTerm->pTerm, pQTerm->nTerm, pQTerm->isPrefix, 0<pQTerm->nPhrase ? DL_POSITIONS : DL_DOCIDS, &left); if( rc ) return rc; for(i=1; i<=pQTerm->nPhrase && left.nData>0; i++){ dataBufferInit(&right, 0); rc = termSelect(v, iColumn, pQTerm[i].pTerm, pQTerm[i].nTerm, pQTerm[i].isPrefix, DL_POSITIONS, &right); if( rc ){ dataBufferDestroy(&left); return rc; } dataBufferInit(&new, 0); docListPhraseMerge(left.pData, left.nData, right.pData, right.nData, i<pQTerm->nPhrase ? DL_POSITIONS : DL_DOCIDS, &new); dataBufferDestroy(&left); dataBufferDestroy(&right); left = new; } *pResult = left; return SQLITE_OK; } /* Add a new term pTerm[0..nTerm-1] to the query *q. */ static void queryAdd(Query *q, const char *pTerm, int nTerm){ QueryTerm *t; ++q->nTerms; q->pTerms = sqlite3_realloc(q->pTerms, q->nTerms * sizeof(q->pTerms[0])); if( q->pTerms==0 ){ q->nTerms = 0; return; } t = &q->pTerms[q->nTerms - 1]; CLEAR(t); t->pTerm = sqlite3_malloc(nTerm+1); memcpy(t->pTerm, pTerm, nTerm); t->pTerm[nTerm] = 0; t->nTerm = nTerm; t->isOr = q->nextIsOr; t->isPrefix = 0; q->nextIsOr = 0; t->iColumn = q->nextColumn; q->nextColumn = q->dfltColumn; } /* ** Check to see if the string zToken[0...nToken-1] matches any ** column name in the virtual table. If it does, ** return the zero-indexed column number. If not, return -1. */ static int checkColumnSpecifier( fulltext_vtab *pVtab, /* The virtual table */ const char *zToken, /* Text of the token */ int nToken /* Number of characters in the token */ ){ int i; for(i=0; i<pVtab->nColumn; i++){ if( memcmp(pVtab->azColumn[i], zToken, nToken)==0 && pVtab->azColumn[i][nToken]==0 ){ return i; } } return -1; } /* ** Parse the text at pSegment[0..nSegment-1]. Add additional terms ** to the query being assemblied in pQuery. ** ** inPhrase is true if pSegment[0..nSegement-1] is contained within ** double-quotes. If inPhrase is true, then the first term ** is marked with the number of terms in the phrase less one and ** OR and "-" syntax is ignored. If inPhrase is false, then every ** term found is marked with nPhrase=0 and OR and "-" syntax is significant. */ static int tokenizeSegment( sqlite3_tokenizer *pTokenizer, /* The tokenizer to use */ const char *pSegment, int nSegment, /* Query expression being parsed */ int inPhrase, /* True if within "..." */ Query *pQuery /* Append results here */ ){ const sqlite3_tokenizer_module *pModule = pTokenizer->pModule; sqlite3_tokenizer_cursor *pCursor; int firstIndex = pQuery->nTerms; int iCol; int nTerm = 1; int rc = pModule->xOpen(pTokenizer, pSegment, nSegment, &pCursor); if( rc!=SQLITE_OK ) return rc; pCursor->pTokenizer = pTokenizer; while( 1 ){ const char *pToken; int nToken, iBegin, iEnd, iPos; rc = pModule->xNext(pCursor, &pToken, &nToken, &iBegin, &iEnd, &iPos); if( rc!=SQLITE_OK ) break; if( !inPhrase && pSegment[iEnd]==':' && (iCol = checkColumnSpecifier(pQuery->pFts, pToken, nToken))>=0 ){ pQuery->nextColumn = iCol; continue; } if( !inPhrase && pQuery->nTerms>0 && nToken==2 && pSegment[iBegin]=='O' && pSegment[iBegin+1]=='R' ){ pQuery->nextIsOr = 1; continue; } queryAdd(pQuery, pToken, nToken); if( !inPhrase && iBegin>0 && pSegment[iBegin-1]=='-' ){ pQuery->pTerms[pQuery->nTerms-1].isNot = 1; } if( iEnd<nSegment && pSegment[iEnd]=='*' ){ pQuery->pTerms[pQuery->nTerms-1].isPrefix = 1; } pQuery->pTerms[pQuery->nTerms-1].iPhrase = nTerm; if( inPhrase ){ nTerm++; } } if( inPhrase && pQuery->nTerms>firstIndex ){ pQuery->pTerms[firstIndex].nPhrase = pQuery->nTerms - firstIndex - 1; } return pModule->xClose(pCursor); } /* Parse a query string, yielding a Query object pQuery. ** ** The calling function will need to queryClear() to clean up ** the dynamically allocated memory held by pQuery. */ static int parseQuery( fulltext_vtab *v, /* The fulltext index */ const char *zInput, /* Input text of the query string */ int nInput, /* Size of the input text */ int dfltColumn, /* Default column of the index to match against */ Query *pQuery /* Write the parse results here. */ ){ int iInput, inPhrase = 0; if( zInput==0 ) nInput = 0; if( nInput<0 ) nInput = strlen(zInput); pQuery->nTerms = 0; pQuery->pTerms = NULL; pQuery->nextIsOr = 0; pQuery->nextColumn = dfltColumn; pQuery->dfltColumn = dfltColumn; pQuery->pFts = v; for(iInput=0; iInput<nInput; ++iInput){ int i; for(i=iInput; i<nInput && zInput[i]!='"'; ++i){} if( i>iInput ){ tokenizeSegment(v->pTokenizer, zInput+iInput, i-iInput, inPhrase, pQuery); } iInput = i; if( i<nInput ){ assert( zInput[i]=='"' ); inPhrase = !inPhrase; } } if( inPhrase ){ /* unmatched quote */ queryClear(pQuery); return SQLITE_ERROR; } return SQLITE_OK; } /* TODO(shess) Refactor the code to remove this forward decl. */ static int flushPendingTerms(fulltext_vtab *v); /* Perform a full-text query using the search expression in ** zInput[0..nInput-1]. Return a list of matching documents ** in pResult. ** ** Queries must match column iColumn. Or if iColumn>=nColumn ** they are allowed to match against any column. */ static int fulltextQuery( fulltext_vtab *v, /* The full text index */ int iColumn, /* Match against this column by default */ const char *zInput, /* The query string */ int nInput, /* Number of bytes in zInput[] */ DataBuffer *pResult, /* Write the result doclist here */ Query *pQuery /* Put parsed query string here */ ){ int i, iNext, rc; DataBuffer left, right, or, new; int nNot = 0; QueryTerm *aTerm; /* TODO(shess) Instead of flushing pendingTerms, we could query for ** the relevant term and merge the doclist into what we receive from ** the database. Wait and see if this is a common issue, first. ** ** A good reason not to flush is to not generate update-related ** error codes from here. */ /* Flush any buffered updates before executing the query. */ rc = flushPendingTerms(v); if( rc!=SQLITE_OK ) return rc; /* TODO(shess) I think that the queryClear() calls below are not ** necessary, because fulltextClose() already clears the query. */ rc = parseQuery(v, zInput, nInput, iColumn, pQuery); if( rc!=SQLITE_OK ) return rc; /* Empty or NULL queries return no results. */ if( pQuery->nTerms==0 ){ dataBufferInit(pResult, 0); return SQLITE_OK; } /* Merge AND terms. */ /* TODO(shess) I think we can early-exit if( i>nNot && left.nData==0 ). */ aTerm = pQuery->pTerms; for(i = 0; i<pQuery->nTerms; i=iNext){ if( aTerm[i].isNot ){ /* Handle all NOT terms in a separate pass */ nNot++; iNext = i + aTerm[i].nPhrase+1; continue; } iNext = i + aTerm[i].nPhrase + 1; rc = docListOfTerm(v, aTerm[i].iColumn, &aTerm[i], &right); if( rc ){ if( i!=nNot ) dataBufferDestroy(&left); queryClear(pQuery); return rc; } while( iNext<pQuery->nTerms && aTerm[iNext].isOr ){ rc = docListOfTerm(v, aTerm[iNext].iColumn, &aTerm[iNext], &or); iNext += aTerm[iNext].nPhrase + 1; if( rc ){ if( i!=nNot ) dataBufferDestroy(&left); dataBufferDestroy(&right); queryClear(pQuery); return rc; } dataBufferInit(&new, 0); docListOrMerge(right.pData, right.nData, or.pData, or.nData, &new); dataBufferDestroy(&right); dataBufferDestroy(&or); right = new; } if( i==nNot ){ /* first term processed. */ left = right; }else{ dataBufferInit(&new, 0); docListAndMerge(left.pData, left.nData, right.pData, right.nData, &new); dataBufferDestroy(&right); dataBufferDestroy(&left); left = new; } } if( nNot==pQuery->nTerms ){ /* We do not yet know how to handle a query of only NOT terms */ return SQLITE_ERROR; } /* Do the EXCEPT terms */ for(i=0; i<pQuery->nTerms; i += aTerm[i].nPhrase + 1){ if( !aTerm[i].isNot ) continue; rc = docListOfTerm(v, aTerm[i].iColumn, &aTerm[i], &right); if( rc ){ queryClear(pQuery); dataBufferDestroy(&left); return rc; } dataBufferInit(&new, 0); docListExceptMerge(left.pData, left.nData, right.pData, right.nData, &new); dataBufferDestroy(&right); dataBufferDestroy(&left); left = new; } *pResult = left; return rc; } /* ** This is the xFilter interface for the virtual table. See ** the virtual table xFilter method documentation for additional ** information. ** ** If idxNum==QUERY_GENERIC then do a full table scan against ** the %_content table. ** ** If idxNum==QUERY_ROWID then do a rowid lookup for a single entry ** in the %_content table. ** ** If idxNum>=QUERY_FULLTEXT then use the full text index. The ** column on the left-hand side of the MATCH operator is column ** number idxNum-QUERY_FULLTEXT, 0 indexed. argv[0] is the right-hand ** side of the MATCH operator. */ /* TODO(shess) Upgrade the cursor initialization and destruction to ** account for fulltextFilter() being called multiple times on the ** same cursor. The current solution is very fragile. Apply fix to ** fts2 as appropriate. */ static int fulltextFilter( sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ int idxNum, const char *idxStr, /* Which indexing scheme to use */ int argc, sqlite3_value **argv /* Arguments for the indexing scheme */ ){ fulltext_cursor *c = (fulltext_cursor *) pCursor; fulltext_vtab *v = cursor_vtab(c); int rc; TRACE(("FTS2 Filter %p\n",pCursor)); /* If the cursor has a statement that was not prepared according to ** idxNum, clear it. I believe all calls to fulltextFilter with a ** given cursor will have the same idxNum , but in this case it's ** easy to be safe. */ if( c->pStmt && c->iCursorType!=idxNum ){ sqlite3_finalize(c->pStmt); c->pStmt = NULL; } /* Get a fresh statement appropriate to idxNum. */ /* TODO(shess): Add a prepared-statement cache in the vt structure. ** The cache must handle multiple open cursors. Easier to cache the ** statement variants at the vt to reduce malloc/realloc/free here. ** Or we could have a StringBuffer variant which allowed stack ** construction for small values. */ if( !c->pStmt ){ char *zSql = sqlite3_mprintf("select rowid, * from %%_content %s", idxNum==QUERY_GENERIC ? "" : "where rowid=?"); rc = sql_prepare(v->db, v->zDb, v->zName, &c->pStmt, zSql); sqlite3_free(zSql); if( rc!=SQLITE_OK ) return rc; c->iCursorType = idxNum; }else{ sqlite3_reset(c->pStmt); assert( c->iCursorType==idxNum ); } switch( idxNum ){ case QUERY_GENERIC: break; case QUERY_ROWID: rc = sqlite3_bind_int64(c->pStmt, 1, sqlite3_value_int64(argv[0])); if( rc!=SQLITE_OK ) return rc; break; default: /* full-text search */ { const char *zQuery = (const char *)sqlite3_value_text(argv[0]); assert( idxNum<=QUERY_FULLTEXT+v->nColumn); assert( argc==1 ); queryClear(&c->q); if( c->result.nData!=0 ){ /* This case happens if the same cursor is used repeatedly. */ dlrDestroy(&c->reader); dataBufferReset(&c->result); }else{ dataBufferInit(&c->result, 0); } rc = fulltextQuery(v, idxNum-QUERY_FULLTEXT, zQuery, -1, &c->result, &c->q); if( rc!=SQLITE_OK ) return rc; if( c->result.nData!=0 ){ dlrInit(&c->reader, DL_DOCIDS, c->result.pData, c->result.nData); } break; } } return fulltextNext(pCursor); } /* This is the xEof method of the virtual table. The SQLite core ** calls this routine to find out if it has reached the end of ** a query's results set. */ static int fulltextEof(sqlite3_vtab_cursor *pCursor){ fulltext_cursor *c = (fulltext_cursor *) pCursor; return c->eof; } /* This is the xColumn method of the virtual table. The SQLite ** core calls this method during a query when it needs the value ** of a column from the virtual table. This method needs to use ** one of the sqlite3_result_*() routines to store the requested ** value back in the pContext. */ static int fulltextColumn(sqlite3_vtab_cursor *pCursor, sqlite3_context *pContext, int idxCol){ fulltext_cursor *c = (fulltext_cursor *) pCursor; fulltext_vtab *v = cursor_vtab(c); if( idxCol<v->nColumn ){ sqlite3_value *pVal = sqlite3_column_value(c->pStmt, idxCol+1); sqlite3_result_value(pContext, pVal); }else if( idxCol==v->nColumn ){ /* The extra column whose name is the same as the table. ** Return a blob which is a pointer to the cursor */ sqlite3_result_blob(pContext, &c, sizeof(c), SQLITE_TRANSIENT); } return SQLITE_OK; } /* This is the xRowid method. The SQLite core calls this routine to ** retrive the rowid for the current row of the result set. The ** rowid should be written to *pRowid. */ static int fulltextRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ fulltext_cursor *c = (fulltext_cursor *) pCursor; *pRowid = sqlite3_column_int64(c->pStmt, 0); return SQLITE_OK; } /* Add all terms in [zText] to pendingTerms table. If [iColumn] > 0, ** we also store positions and offsets in the hash table using that ** column number. */ static int buildTerms(fulltext_vtab *v, sqlite_int64 iDocid, const char *zText, int iColumn){ sqlite3_tokenizer *pTokenizer = v->pTokenizer; sqlite3_tokenizer_cursor *pCursor; const char *pToken; int nTokenBytes; int iStartOffset, iEndOffset, iPosition; int rc; rc = pTokenizer->pModule->xOpen(pTokenizer, zText, -1, &pCursor); if( rc!=SQLITE_OK ) return rc; pCursor->pTokenizer = pTokenizer; while( SQLITE_OK==(rc=pTokenizer->pModule->xNext(pCursor, &pToken, &nTokenBytes, &iStartOffset, &iEndOffset, &iPosition)) ){ DLCollector *p; int nData; /* Size of doclist before our update. */ /* Positions can't be negative; we use -1 as a terminator * internally. Token can't be NULL or empty. */ if( iPosition<0 || pToken == NULL || nTokenBytes == 0 ){ rc = SQLITE_ERROR; break; } p = fts2HashFind(&v->pendingTerms, pToken, nTokenBytes); if( p==NULL ){ nData = 0; p = dlcNew(iDocid, DL_DEFAULT); fts2HashInsert(&v->pendingTerms, pToken, nTokenBytes, p); /* Overhead for our hash table entry, the key, and the value. */ v->nPendingData += sizeof(struct fts2HashElem)+sizeof(*p)+nTokenBytes; }else{ nData = p->b.nData; if( p->dlw.iPrevDocid!=iDocid ) dlcNext(p, iDocid); } if( iColumn>=0 ){ dlcAddPos(p, iColumn, iPosition, iStartOffset, iEndOffset); } /* Accumulate data added by dlcNew or dlcNext, and dlcAddPos. */ v->nPendingData += p->b.nData-nData; } /* TODO(shess) Check return? Should this be able to cause errors at ** this point? Actually, same question about sqlite3_finalize(), ** though one could argue that failure there means that the data is ** not durable. *ponder* */ pTokenizer->pModule->xClose(pCursor); if( SQLITE_DONE == rc ) return SQLITE_OK; return rc; } /* Add doclists for all terms in [pValues] to pendingTerms table. */ static int insertTerms(fulltext_vtab *v, sqlite_int64 iRowid, sqlite3_value **pValues){ int i; for(i = 0; i < v->nColumn ; ++i){ char *zText = (char*)sqlite3_value_text(pValues[i]); int rc = buildTerms(v, iRowid, zText, i); if( rc!=SQLITE_OK ) return rc; } return SQLITE_OK; } /* Add empty doclists for all terms in the given row's content to ** pendingTerms. */ static int deleteTerms(fulltext_vtab *v, sqlite_int64 iRowid){ const char **pValues; int i, rc; /* TODO(shess) Should we allow such tables at all? */ if( DL_DEFAULT==DL_DOCIDS ) return SQLITE_ERROR; rc = content_select(v, iRowid, &pValues); if( rc!=SQLITE_OK ) return rc; for(i = 0 ; i < v->nColumn; ++i) { rc = buildTerms(v, iRowid, pValues[i], -1); if( rc!=SQLITE_OK ) break; } freeStringArray(v->nColumn, pValues); return SQLITE_OK; } /* TODO(shess) Refactor the code to remove this forward decl. */ static int initPendingTerms(fulltext_vtab *v, sqlite_int64 iDocid); /* Insert a row into the %_content table; set *piRowid to be the ID of the ** new row. Add doclists for terms to pendingTerms. */ static int index_insert(fulltext_vtab *v, sqlite3_value *pRequestRowid, sqlite3_value **pValues, sqlite_int64 *piRowid){ int rc; rc = content_insert(v, pRequestRowid, pValues); /* execute an SQL INSERT */ if( rc!=SQLITE_OK ) return rc; *piRowid = sqlite3_last_insert_rowid(v->db); rc = initPendingTerms(v, *piRowid); if( rc!=SQLITE_OK ) return rc; return insertTerms(v, *piRowid, pValues); } /* Delete a row from the %_content table; add empty doclists for terms ** to pendingTerms. */ static int index_delete(fulltext_vtab *v, sqlite_int64 iRow){ int rc = initPendingTerms(v, iRow); if( rc!=SQLITE_OK ) return rc; rc = deleteTerms(v, iRow); if( rc!=SQLITE_OK ) return rc; return content_delete(v, iRow); /* execute an SQL DELETE */ } /* Update a row in the %_content table; add delete doclists to ** pendingTerms for old terms not in the new data, add insert doclists ** to pendingTerms for terms in the new data. */ static int index_update(fulltext_vtab *v, sqlite_int64 iRow, sqlite3_value **pValues){ int rc = initPendingTerms(v, iRow); if( rc!=SQLITE_OK ) return rc; /* Generate an empty doclist for each term that previously appeared in this * row. */ rc = deleteTerms(v, iRow); if( rc!=SQLITE_OK ) return rc; rc = content_update(v, pValues, iRow); /* execute an SQL UPDATE */ if( rc!=SQLITE_OK ) return rc; /* Now add positions for terms which appear in the updated row. */ return insertTerms(v, iRow, pValues); } /*******************************************************************/ /* InteriorWriter is used to collect terms and block references into ** interior nodes in %_segments. See commentary at top of file for ** format. */ /* How large interior nodes can grow. */ #define INTERIOR_MAX 2048 /* Minimum number of terms per interior node (except the root). This ** prevents large terms from making the tree too skinny - must be >0 ** so that the tree always makes progress. Note that the min tree ** fanout will be INTERIOR_MIN_TERMS+1. */ #define INTERIOR_MIN_TERMS 7 #if INTERIOR_MIN_TERMS<1 # error INTERIOR_MIN_TERMS must be greater than 0. #endif /* ROOT_MAX controls how much data is stored inline in the segment ** directory. */ /* TODO(shess) Push ROOT_MAX down to whoever is writing things. It's ** only here so that interiorWriterRootInfo() and leafWriterRootInfo() ** can both see it, but if the caller passed it in, we wouldn't even ** need a define. */ #define ROOT_MAX 1024 #if ROOT_MAX<VARINT_MAX*2 # error ROOT_MAX must have enough space for a header. #endif /* InteriorBlock stores a linked-list of interior blocks while a lower ** layer is being constructed. */ typedef struct InteriorBlock { DataBuffer term; /* Leftmost term in block's subtree. */ DataBuffer data; /* Accumulated data for the block. */ struct InteriorBlock *next; } InteriorBlock; static InteriorBlock *interiorBlockNew(int iHeight, sqlite_int64 iChildBlock, const char *pTerm, int nTerm){ InteriorBlock *block = sqlite3_malloc(sizeof(InteriorBlock)); char c[VARINT_MAX+VARINT_MAX]; int n; if( block ){ memset(block, 0, sizeof(*block)); dataBufferInit(&block->term, 0); dataBufferReplace(&block->term, pTerm, nTerm); n = putVarint(c, iHeight); n += putVarint(c+n, iChildBlock); dataBufferInit(&block->data, INTERIOR_MAX); dataBufferReplace(&block->data, c, n); } return block; } #ifndef NDEBUG /* Verify that the data is readable as an interior node. */ static void interiorBlockValidate(InteriorBlock *pBlock){ const char *pData = pBlock->data.pData; int nData = pBlock->data.nData; int n, iDummy; sqlite_int64 iBlockid; assert( nData>0 ); assert( pData!=0 ); assert( pData+nData>pData ); /* Must lead with height of node as a varint(n), n>0 */ n = getVarint32(pData, &iDummy); assert( n>0 ); assert( iDummy>0 ); assert( n<nData ); pData += n; nData -= n; /* Must contain iBlockid. */ n = getVarint(pData, &iBlockid); assert( n>0 ); assert( n<=nData ); pData += n; nData -= n; /* Zero or more terms of positive length */ if( nData!=0 ){ /* First term is not delta-encoded. */ n = getVarint32(pData, &iDummy); assert( n>0 ); assert( iDummy>0 ); assert( n+iDummy>0); assert( n+iDummy<=nData ); pData += n+iDummy; nData -= n+iDummy; /* Following terms delta-encoded. */ while( nData!=0 ){ /* Length of shared prefix. */ n = getVarint32(pData, &iDummy); assert( n>0 ); assert( iDummy>=0 ); assert( n<nData ); pData += n; nData -= n; /* Length and data of distinct suffix. */ n = getVarint32(pData, &iDummy); assert( n>0 ); assert( iDummy>0 ); assert( n+iDummy>0); assert( n+iDummy<=nData ); pData += n+iDummy; nData -= n+iDummy; } } } #define ASSERT_VALID_INTERIOR_BLOCK(x) interiorBlockValidate(x) #else #define ASSERT_VALID_INTERIOR_BLOCK(x) assert( 1 ) #endif typedef struct InteriorWriter { int iHeight; /* from 0 at leaves. */ InteriorBlock *first, *last; struct InteriorWriter *parentWriter; DataBuffer term; /* Last term written to block "last". */ sqlite_int64 iOpeningChildBlock; /* First child block in block "last". */ #ifndef NDEBUG sqlite_int64 iLastChildBlock; /* for consistency checks. */ #endif } InteriorWriter; /* Initialize an interior node where pTerm[nTerm] marks the leftmost ** term in the tree. iChildBlock is the leftmost child block at the ** next level down the tree. */ static void interiorWriterInit(int iHeight, const char *pTerm, int nTerm, sqlite_int64 iChildBlock, InteriorWriter *pWriter){ InteriorBlock *block; assert( iHeight>0 ); CLEAR(pWriter); pWriter->iHeight = iHeight; pWriter->iOpeningChildBlock = iChildBlock; #ifndef NDEBUG pWriter->iLastChildBlock = iChildBlock; #endif block = interiorBlockNew(iHeight, iChildBlock, pTerm, nTerm); pWriter->last = pWriter->first = block; ASSERT_VALID_INTERIOR_BLOCK(pWriter->last); dataBufferInit(&pWriter->term, 0); } /* Append the child node rooted at iChildBlock to the interior node, ** with pTerm[nTerm] as the leftmost term in iChildBlock's subtree. */ static void interiorWriterAppend(InteriorWriter *pWriter, const char *pTerm, int nTerm, sqlite_int64 iChildBlock){ char c[VARINT_MAX+VARINT_MAX]; int n, nPrefix = 0; ASSERT_VALID_INTERIOR_BLOCK(pWriter->last); /* The first term written into an interior node is actually ** associated with the second child added (the first child was added ** in interiorWriterInit, or in the if clause at the bottom of this ** function). That term gets encoded straight up, with nPrefix left ** at 0. */ if( pWriter->term.nData==0 ){ n = putVarint(c, nTerm); }else{ while( nPrefix<pWriter->term.nData && pTerm[nPrefix]==pWriter->term.pData[nPrefix] ){ nPrefix++; } n = putVarint(c, nPrefix); n += putVarint(c+n, nTerm-nPrefix); } #ifndef NDEBUG pWriter->iLastChildBlock++; #endif assert( pWriter->iLastChildBlock==iChildBlock ); /* Overflow to a new block if the new term makes the current block ** too big, and the current block already has enough terms. */ if( pWriter->last->data.nData+n+nTerm-nPrefix>INTERIOR_MAX && iChildBlock-pWriter->iOpeningChildBlock>INTERIOR_MIN_TERMS ){ pWriter->last->next = interiorBlockNew(pWriter->iHeight, iChildBlock, pTerm, nTerm); pWriter->last = pWriter->last->next; pWriter->iOpeningChildBlock = iChildBlock; dataBufferReset(&pWriter->term); }else{ dataBufferAppend2(&pWriter->last->data, c, n, pTerm+nPrefix, nTerm-nPrefix); dataBufferReplace(&pWriter->term, pTerm, nTerm); } ASSERT_VALID_INTERIOR_BLOCK(pWriter->last); } /* Free the space used by pWriter, including the linked-list of ** InteriorBlocks, and parentWriter, if present. */ static int interiorWriterDestroy(InteriorWriter *pWriter){ InteriorBlock *block = pWriter->first; while( block!=NULL ){ InteriorBlock *b = block; block = block->next; dataBufferDestroy(&b->term); dataBufferDestroy(&b->data); sqlite3_free(b); } if( pWriter->parentWriter!=NULL ){ interiorWriterDestroy(pWriter->parentWriter); sqlite3_free(pWriter->parentWriter); } dataBufferDestroy(&pWriter->term); SCRAMBLE(pWriter); return SQLITE_OK; } /* If pWriter can fit entirely in ROOT_MAX, return it as the root info ** directly, leaving *piEndBlockid unchanged. Otherwise, flush ** pWriter to %_segments, building a new layer of interior nodes, and ** recursively ask for their root into. */ static int interiorWriterRootInfo(fulltext_vtab *v, InteriorWriter *pWriter, char **ppRootInfo, int *pnRootInfo, sqlite_int64 *piEndBlockid){ InteriorBlock *block = pWriter->first; sqlite_int64 iBlockid = 0; int rc; /* If we can fit the segment inline */ if( block==pWriter->last && block->data.nData<ROOT_MAX ){ *ppRootInfo = block->data.pData; *pnRootInfo = block->data.nData; return SQLITE_OK; } /* Flush the first block to %_segments, and create a new level of ** interior node. */ ASSERT_VALID_INTERIOR_BLOCK(block); rc = block_insert(v, block->data.pData, block->data.nData, &iBlockid); if( rc!=SQLITE_OK ) return rc; *piEndBlockid = iBlockid; pWriter->parentWriter = sqlite3_malloc(sizeof(*pWriter->parentWriter)); interiorWriterInit(pWriter->iHeight+1, block->term.pData, block->term.nData, iBlockid, pWriter->parentWriter); /* Flush additional blocks and append to the higher interior ** node. */ for(block=block->next; block!=NULL; block=block->next){ ASSERT_VALID_INTERIOR_BLOCK(block); rc = block_insert(v, block->data.pData, block->data.nData, &iBlockid); if( rc!=SQLITE_OK ) return rc; *piEndBlockid = iBlockid; interiorWriterAppend(pWriter->parentWriter, block->term.pData, block->term.nData, iBlockid); } /* Parent node gets the chance to be the root. */ return interiorWriterRootInfo(v, pWriter->parentWriter, ppRootInfo, pnRootInfo, piEndBlockid); } /****************************************************************/ /* InteriorReader is used to read off the data from an interior node ** (see comment at top of file for the format). */ typedef struct InteriorReader { const char *pData; int nData; DataBuffer term; /* previous term, for decoding term delta. */ sqlite_int64 iBlockid; } InteriorReader; static void interiorReaderDestroy(InteriorReader *pReader){ dataBufferDestroy(&pReader->term); SCRAMBLE(pReader); } /* TODO(shess) The assertions are great, but what if we're in NDEBUG ** and the blob is empty or otherwise contains suspect data? */ static void interiorReaderInit(const char *pData, int nData, InteriorReader *pReader){ int n, nTerm; /* Require at least the leading flag byte */ assert( nData>0 ); assert( pData[0]!='\0' ); CLEAR(pReader); /* Decode the base blockid, and set the cursor to the first term. */ n = getVarint(pData+1, &pReader->iBlockid); assert( 1+n<=nData ); pReader->pData = pData+1+n; pReader->nData = nData-(1+n); /* A single-child interior node (such as when a leaf node was too ** large for the segment directory) won't have any terms. ** Otherwise, decode the first term. */ if( pReader->nData==0 ){ dataBufferInit(&pReader->term, 0); }else{ n = getVarint32(pReader->pData, &nTerm); dataBufferInit(&pReader->term, nTerm); dataBufferReplace(&pReader->term, pReader->pData+n, nTerm); assert( n+nTerm<=pReader->nData ); pReader->pData += n+nTerm; pReader->nData -= n+nTerm; } } static int interiorReaderAtEnd(InteriorReader *pReader){ return pReader->term.nData==0; } static sqlite_int64 interiorReaderCurrentBlockid(InteriorReader *pReader){ return pReader->iBlockid; } static int interiorReaderTermBytes(InteriorReader *pReader){ assert( !interiorReaderAtEnd(pReader) ); return pReader->term.nData; } static const char *interiorReaderTerm(InteriorReader *pReader){ assert( !interiorReaderAtEnd(pReader) ); return pReader->term.pData; } /* Step forward to the next term in the node. */ static void interiorReaderStep(InteriorReader *pReader){ assert( !interiorReaderAtEnd(pReader) ); /* If the last term has been read, signal eof, else construct the ** next term. */ if( pReader->nData==0 ){ dataBufferReset(&pReader->term); }else{ int n, nPrefix, nSuffix; n = getVarint32(pReader->pData, &nPrefix); n += getVarint32(pReader->pData+n, &nSuffix); /* Truncate the current term and append suffix data. */ pReader->term.nData = nPrefix; dataBufferAppend(&pReader->term, pReader->pData+n, nSuffix); assert( n+nSuffix<=pReader->nData ); pReader->pData += n+nSuffix; pReader->nData -= n+nSuffix; } pReader->iBlockid++; } /* Compare the current term to pTerm[nTerm], returning strcmp-style ** results. If isPrefix, equality means equal through nTerm bytes. */ static int interiorReaderTermCmp(InteriorReader *pReader, const char *pTerm, int nTerm, int isPrefix){ const char *pReaderTerm = interiorReaderTerm(pReader); int nReaderTerm = interiorReaderTermBytes(pReader); int c, n = nReaderTerm<nTerm ? nReaderTerm : nTerm; if( n==0 ){ if( nReaderTerm>0 ) return -1; if( nTerm>0 ) return 1; return 0; } c = memcmp(pReaderTerm, pTerm, n); if( c!=0 ) return c; if( isPrefix && n==nTerm ) return 0; return nReaderTerm - nTerm; } /****************************************************************/ /* LeafWriter is used to collect terms and associated doclist data ** into leaf blocks in %_segments (see top of file for format info). ** Expected usage is: ** ** LeafWriter writer; ** leafWriterInit(0, 0, &writer); ** while( sorted_terms_left_to_process ){ ** // data is doclist data for that term. ** rc = leafWriterStep(v, &writer, pTerm, nTerm, pData, nData); ** if( rc!=SQLITE_OK ) goto err; ** } ** rc = leafWriterFinalize(v, &writer); **err: ** leafWriterDestroy(&writer); ** return rc; ** ** leafWriterStep() may write a collected leaf out to %_segments. ** leafWriterFinalize() finishes writing any buffered data and stores ** a root node in %_segdir. leafWriterDestroy() frees all buffers and ** InteriorWriters allocated as part of writing this segment. ** ** TODO(shess) Document leafWriterStepMerge(). */ /* Put terms with data this big in their own block. */ #define STANDALONE_MIN 1024 /* Keep leaf blocks below this size. */ #define LEAF_MAX 2048 typedef struct LeafWriter { int iLevel; int idx; sqlite_int64 iStartBlockid; /* needed to create the root info */ sqlite_int64 iEndBlockid; /* when we're done writing. */ DataBuffer term; /* previous encoded term */ DataBuffer data; /* encoding buffer */ /* bytes of first term in the current node which distinguishes that ** term from the last term of the previous node. */ int nTermDistinct; InteriorWriter parentWriter; /* if we overflow */ int has_parent; } LeafWriter; static void leafWriterInit(int iLevel, int idx, LeafWriter *pWriter){ CLEAR(pWriter); pWriter->iLevel = iLevel; pWriter->idx = idx; dataBufferInit(&pWriter->term, 32); /* Start out with a reasonably sized block, though it can grow. */ dataBufferInit(&pWriter->data, LEAF_MAX); } #ifndef NDEBUG /* Verify that the data is readable as a leaf node. */ static void leafNodeValidate(const char *pData, int nData){ int n, iDummy; if( nData==0 ) return; assert( nData>0 ); assert( pData!=0 ); assert( pData+nData>pData ); /* Must lead with a varint(0) */ n = getVarint32(pData, &iDummy); assert( iDummy==0 ); assert( n>0 ); assert( n<nData ); pData += n; nData -= n; /* Leading term length and data must fit in buffer. */ n = getVarint32(pData, &iDummy); assert( n>0 ); assert( iDummy>0 ); assert( n+iDummy>0 ); assert( n+iDummy<nData ); pData += n+iDummy; nData -= n+iDummy; /* Leading term's doclist length and data must fit. */ n = getVarint32(pData, &iDummy); assert( n>0 ); assert( iDummy>0 ); assert( n+iDummy>0 ); assert( n+iDummy<=nData ); ASSERT_VALID_DOCLIST(DL_DEFAULT, pData+n, iDummy, NULL); pData += n+iDummy; nData -= n+iDummy; /* Verify that trailing terms and doclists also are readable. */ while( nData!=0 ){ n = getVarint32(pData, &iDummy); assert( n>0 ); assert( iDummy>=0 ); assert( n<nData ); pData += n; nData -= n; n = getVarint32(pData, &iDummy); assert( n>0 ); assert( iDummy>0 ); assert( n+iDummy>0 ); assert( n+iDummy<nData ); pData += n+iDummy; nData -= n+iDummy; n = getVarint32(pData, &iDummy); assert( n>0 ); assert( iDummy>0 ); assert( n+iDummy>0 ); assert( n+iDummy<=nData ); ASSERT_VALID_DOCLIST(DL_DEFAULT, pData+n, iDummy, NULL); pData += n+iDummy; nData -= n+iDummy; } } #define ASSERT_VALID_LEAF_NODE(p, n) leafNodeValidate(p, n) #else #define ASSERT_VALID_LEAF_NODE(p, n) assert( 1 ) #endif /* Flush the current leaf node to %_segments, and adding the resulting ** blockid and the starting term to the interior node which will ** contain it. */ static int leafWriterInternalFlush(fulltext_vtab *v, LeafWriter *pWriter, int iData, int nData){ sqlite_int64 iBlockid = 0; const char *pStartingTerm; int nStartingTerm, rc, n; /* Must have the leading varint(0) flag, plus at least some ** valid-looking data. */ assert( nData>2 ); assert( iData>=0 ); assert( iData+nData<=pWriter->data.nData ); ASSERT_VALID_LEAF_NODE(pWriter->data.pData+iData, nData); rc = block_insert(v, pWriter->data.pData+iData, nData, &iBlockid); if( rc!=SQLITE_OK ) return rc; assert( iBlockid!=0 ); /* Reconstruct the first term in the leaf for purposes of building ** the interior node. */ n = getVarint32(pWriter->data.pData+iData+1, &nStartingTerm); pStartingTerm = pWriter->data.pData+iData+1+n; assert( pWriter->data.nData>iData+1+n+nStartingTerm ); assert( pWriter->nTermDistinct>0 ); assert( pWriter->nTermDistinct<=nStartingTerm ); nStartingTerm = pWriter->nTermDistinct; if( pWriter->has_parent ){ interiorWriterAppend(&pWriter->parentWriter, pStartingTerm, nStartingTerm, iBlockid); }else{ interiorWriterInit(1, pStartingTerm, nStartingTerm, iBlockid, &pWriter->parentWriter); pWriter->has_parent = 1; } /* Track the span of this segment's leaf nodes. */ if( pWriter->iEndBlockid==0 ){ pWriter->iEndBlockid = pWriter->iStartBlockid = iBlockid; }else{ pWriter->iEndBlockid++; assert( iBlockid==pWriter->iEndBlockid ); } return SQLITE_OK; } static int leafWriterFlush(fulltext_vtab *v, LeafWriter *pWriter){ int rc = leafWriterInternalFlush(v, pWriter, 0, pWriter->data.nData); if( rc!=SQLITE_OK ) return rc; /* Re-initialize the output buffer. */ dataBufferReset(&pWriter->data); return SQLITE_OK; } /* Fetch the root info for the segment. If the entire leaf fits ** within ROOT_MAX, then it will be returned directly, otherwise it ** will be flushed and the root info will be returned from the ** interior node. *piEndBlockid is set to the blockid of the last ** interior or leaf node written to disk (0 if none are written at ** all). */ static int leafWriterRootInfo(fulltext_vtab *v, LeafWriter *pWriter, char **ppRootInfo, int *pnRootInfo, sqlite_int64 *piEndBlockid){ /* we can fit the segment entirely inline */ if( !pWriter->has_parent && pWriter->data.nData<ROOT_MAX ){ *ppRootInfo = pWriter->data.pData; *pnRootInfo = pWriter->data.nData; *piEndBlockid = 0; return SQLITE_OK; } /* Flush remaining leaf data. */ if( pWriter->data.nData>0 ){ int rc = leafWriterFlush(v, pWriter); if( rc!=SQLITE_OK ) return rc; } /* We must have flushed a leaf at some point. */ assert( pWriter->has_parent ); /* Tenatively set the end leaf blockid as the end blockid. If the ** interior node can be returned inline, this will be the final ** blockid, otherwise it will be overwritten by ** interiorWriterRootInfo(). */ *piEndBlockid = pWriter->iEndBlockid; return interiorWriterRootInfo(v, &pWriter->parentWriter, ppRootInfo, pnRootInfo, piEndBlockid); } /* Collect the rootInfo data and store it into the segment directory. ** This has the effect of flushing the segment's leaf data to ** %_segments, and also flushing any interior nodes to %_segments. */ static int leafWriterFinalize(fulltext_vtab *v, LeafWriter *pWriter){ sqlite_int64 iEndBlockid; char *pRootInfo; int rc, nRootInfo; rc = leafWriterRootInfo(v, pWriter, &pRootInfo, &nRootInfo, &iEndBlockid); if( rc!=SQLITE_OK ) return rc; /* Don't bother storing an entirely empty segment. */ if( iEndBlockid==0 && nRootInfo==0 ) return SQLITE_OK; return segdir_set(v, pWriter->iLevel, pWriter->idx, pWriter->iStartBlockid, pWriter->iEndBlockid, iEndBlockid, pRootInfo, nRootInfo); } static void leafWriterDestroy(LeafWriter *pWriter){ if( pWriter->has_parent ) interiorWriterDestroy(&pWriter->parentWriter); dataBufferDestroy(&pWriter->term); dataBufferDestroy(&pWriter->data); } /* Encode a term into the leafWriter, delta-encoding as appropriate. ** Returns the length of the new term which distinguishes it from the ** previous term, which can be used to set nTermDistinct when a node ** boundary is crossed. */ static int leafWriterEncodeTerm(LeafWriter *pWriter, const char *pTerm, int nTerm){ char c[VARINT_MAX+VARINT_MAX]; int n, nPrefix = 0; assert( nTerm>0 ); while( nPrefix<pWriter->term.nData && pTerm[nPrefix]==pWriter->term.pData[nPrefix] ){ nPrefix++; /* Failing this implies that the terms weren't in order. */ assert( nPrefix<nTerm ); } if( pWriter->data.nData==0 ){ /* Encode the node header and leading term as: ** varint(0) ** varint(nTerm) ** char pTerm[nTerm] */ n = putVarint(c, '\0'); n += putVarint(c+n, nTerm); dataBufferAppend2(&pWriter->data, c, n, pTerm, nTerm); }else{ /* Delta-encode the term as: ** varint(nPrefix) ** varint(nSuffix) ** char pTermSuffix[nSuffix] */ n = putVarint(c, nPrefix); n += putVarint(c+n, nTerm-nPrefix); dataBufferAppend2(&pWriter->data, c, n, pTerm+nPrefix, nTerm-nPrefix); } dataBufferReplace(&pWriter->term, pTerm, nTerm); return nPrefix+1; } /* Used to avoid a memmove when a large amount of doclist data is in ** the buffer. This constructs a node and term header before ** iDoclistData and flushes the resulting complete node using ** leafWriterInternalFlush(). */ static int leafWriterInlineFlush(fulltext_vtab *v, LeafWriter *pWriter, const char *pTerm, int nTerm, int iDoclistData){ char c[VARINT_MAX+VARINT_MAX]; int iData, n = putVarint(c, 0); n += putVarint(c+n, nTerm); /* There should always be room for the header. Even if pTerm shared ** a substantial prefix with the previous term, the entire prefix ** could be constructed from earlier data in the doclist, so there ** should be room. */ assert( iDoclistData>=n+nTerm ); iData = iDoclistData-(n+nTerm); memcpy(pWriter->data.pData+iData, c, n); memcpy(pWriter->data.pData+iData+n, pTerm, nTerm); return leafWriterInternalFlush(v, pWriter, iData, pWriter->data.nData-iData); } /* Push pTerm[nTerm] along with the doclist data to the leaf layer of ** %_segments. */ static int leafWriterStepMerge(fulltext_vtab *v, LeafWriter *pWriter, const char *pTerm, int nTerm, DLReader *pReaders, int nReaders){ char c[VARINT_MAX+VARINT_MAX]; int iTermData = pWriter->data.nData, iDoclistData; int i, nData, n, nActualData, nActual, rc, nTermDistinct; ASSERT_VALID_LEAF_NODE(pWriter->data.pData, pWriter->data.nData); nTermDistinct = leafWriterEncodeTerm(pWriter, pTerm, nTerm); /* Remember nTermDistinct if opening a new node. */ if( iTermData==0 ) pWriter->nTermDistinct = nTermDistinct; iDoclistData = pWriter->data.nData; /* Estimate the length of the merged doclist so we can leave space ** to encode it. */ for(i=0, nData=0; i<nReaders; i++){ nData += dlrAllDataBytes(&pReaders[i]); } n = putVarint(c, nData); dataBufferAppend(&pWriter->data, c, n); docListMerge(&pWriter->data, pReaders, nReaders); ASSERT_VALID_DOCLIST(DL_DEFAULT, pWriter->data.pData+iDoclistData+n, pWriter->data.nData-iDoclistData-n, NULL); /* The actual amount of doclist data at this point could be smaller ** than the length we encoded. Additionally, the space required to ** encode this length could be smaller. For small doclists, this is ** not a big deal, we can just use memmove() to adjust things. */ nActualData = pWriter->data.nData-(iDoclistData+n); nActual = putVarint(c, nActualData); assert( nActualData<=nData ); assert( nActual<=n ); /* If the new doclist is big enough for force a standalone leaf ** node, we can immediately flush it inline without doing the ** memmove(). */ /* TODO(shess) This test matches leafWriterStep(), which does this ** test before it knows the cost to varint-encode the term and ** doclist lengths. At some point, change to ** pWriter->data.nData-iTermData>STANDALONE_MIN. */ if( nTerm+nActualData>STANDALONE_MIN ){ /* Push leaf node from before this term. */ if( iTermData>0 ){ rc = leafWriterInternalFlush(v, pWriter, 0, iTermData); if( rc!=SQLITE_OK ) return rc; pWriter->nTermDistinct = nTermDistinct; } /* Fix the encoded doclist length. */ iDoclistData += n - nActual; memcpy(pWriter->data.pData+iDoclistData, c, nActual); /* Push the standalone leaf node. */ rc = leafWriterInlineFlush(v, pWriter, pTerm, nTerm, iDoclistData); if( rc!=SQLITE_OK ) return rc; /* Leave the node empty. */ dataBufferReset(&pWriter->data); return rc; } /* At this point, we know that the doclist was small, so do the ** memmove if indicated. */ if( nActual<n ){ memmove(pWriter->data.pData+iDoclistData+nActual, pWriter->data.pData+iDoclistData+n, pWriter->data.nData-(iDoclistData+n)); pWriter->data.nData -= n-nActual; } /* Replace written length with actual length. */ memcpy(pWriter->data.pData+iDoclistData, c, nActual); /* If the node is too large, break things up. */ /* TODO(shess) This test matches leafWriterStep(), which does this ** test before it knows the cost to varint-encode the term and ** doclist lengths. At some point, change to ** pWriter->data.nData>LEAF_MAX. */ if( iTermData+nTerm+nActualData>LEAF_MAX ){ /* Flush out the leading data as a node */ rc = leafWriterInternalFlush(v, pWriter, 0, iTermData); if( rc!=SQLITE_OK ) return rc; pWriter->nTermDistinct = nTermDistinct; /* Rebuild header using the current term */ n = putVarint(pWriter->data.pData, 0); n += putVarint(pWriter->data.pData+n, nTerm); memcpy(pWriter->data.pData+n, pTerm, nTerm); n += nTerm; /* There should always be room, because the previous encoding ** included all data necessary to construct the term. */ assert( n<iDoclistData ); /* So long as STANDALONE_MIN is half or less of LEAF_MAX, the ** following memcpy() is safe (as opposed to needing a memmove). */ assert( 2*STANDALONE_MIN<=LEAF_MAX ); assert( n+pWriter->data.nData-iDoclistData<iDoclistData ); memcpy(pWriter->data.pData+n, pWriter->data.pData+iDoclistData, pWriter->data.nData-iDoclistData); pWriter->data.nData -= iDoclistData-n; } ASSERT_VALID_LEAF_NODE(pWriter->data.pData, pWriter->data.nData); return SQLITE_OK; } /* Push pTerm[nTerm] along with the doclist data to the leaf layer of ** %_segments. */ /* TODO(shess) Revise writeZeroSegment() so that doclists are ** constructed directly in pWriter->data. */ static int leafWriterStep(fulltext_vtab *v, LeafWriter *pWriter, const char *pTerm, int nTerm, const char *pData, int nData){ int rc; DLReader reader; dlrInit(&reader, DL_DEFAULT, pData, nData); rc = leafWriterStepMerge(v, pWriter, pTerm, nTerm, &reader, 1); dlrDestroy(&reader); return rc; } /****************************************************************/ /* LeafReader is used to iterate over an individual leaf node. */ typedef struct LeafReader { DataBuffer term; /* copy of current term. */ const char *pData; /* data for current term. */ int nData; } LeafReader; static void leafReaderDestroy(LeafReader *pReader){ dataBufferDestroy(&pReader->term); SCRAMBLE(pReader); } static int leafReaderAtEnd(LeafReader *pReader){ return pReader->nData<=0; } /* Access the current term. */ static int leafReaderTermBytes(LeafReader *pReader){ return pReader->term.nData; } static const char *leafReaderTerm(LeafReader *pReader){ assert( pReader->term.nData>0 ); return pReader->term.pData; } /* Access the doclist data for the current term. */ static int leafReaderDataBytes(LeafReader *pReader){ int nData; assert( pReader->term.nData>0 ); getVarint32(pReader->pData, &nData); return nData; } static const char *leafReaderData(LeafReader *pReader){ int n, nData; assert( pReader->term.nData>0 ); n = getVarint32(pReader->pData, &nData); return pReader->pData+n; } static void leafReaderInit(const char *pData, int nData, LeafReader *pReader){ int nTerm, n; assert( nData>0 ); assert( pData[0]=='\0' ); CLEAR(pReader); /* Read the first term, skipping the header byte. */ n = getVarint32(pData+1, &nTerm); dataBufferInit(&pReader->term, nTerm); dataBufferReplace(&pReader->term, pData+1+n, nTerm); /* Position after the first term. */ assert( 1+n+nTerm<nData ); pReader->pData = pData+1+n+nTerm; pReader->nData = nData-1-n-nTerm; } /* Step the reader forward to the next term. */ static void leafReaderStep(LeafReader *pReader){ int n, nData, nPrefix, nSuffix; assert( !leafReaderAtEnd(pReader) ); /* Skip previous entry's data block. */ n = getVarint32(pReader->pData, &nData); assert( n+nData<=pReader->nData ); pReader->pData += n+nData; pReader->nData -= n+nData; if( !leafReaderAtEnd(pReader) ){ /* Construct the new term using a prefix from the old term plus a ** suffix from the leaf data. */ n = getVarint32(pReader->pData, &nPrefix); n += getVarint32(pReader->pData+n, &nSuffix); assert( n+nSuffix<pReader->nData ); pReader->term.nData = nPrefix; dataBufferAppend(&pReader->term, pReader->pData+n, nSuffix); pReader->pData += n+nSuffix; pReader->nData -= n+nSuffix; } } /* strcmp-style comparison of pReader's current term against pTerm. ** If isPrefix, equality means equal through nTerm bytes. */ static int leafReaderTermCmp(LeafReader *pReader, const char *pTerm, int nTerm, int isPrefix){ int c, n = pReader->term.nData<nTerm ? pReader->term.nData : nTerm; if( n==0 ){ if( pReader->term.nData>0 ) return -1; if(nTerm>0 ) return 1; return 0; } c = memcmp(pReader->term.pData, pTerm, n); if( c!=0 ) return c; if( isPrefix && n==nTerm ) return 0; return pReader->term.nData - nTerm; } /****************************************************************/ /* LeavesReader wraps LeafReader to allow iterating over the entire ** leaf layer of the tree. */ typedef struct LeavesReader { int idx; /* Index within the segment. */ sqlite3_stmt *pStmt; /* Statement we're streaming leaves from. */ int eof; /* we've seen SQLITE_DONE from pStmt. */ LeafReader leafReader; /* reader for the current leaf. */ DataBuffer rootData; /* root data for inline. */ } LeavesReader; /* Access the current term. */ static int leavesReaderTermBytes(LeavesReader *pReader){ assert( !pReader->eof ); return leafReaderTermBytes(&pReader->leafReader); } static const char *leavesReaderTerm(LeavesReader *pReader){ assert( !pReader->eof ); return leafReaderTerm(&pReader->leafReader); } /* Access the doclist data for the current term. */ static int leavesReaderDataBytes(LeavesReader *pReader){ assert( !pReader->eof ); return leafReaderDataBytes(&pReader->leafReader); } static const char *leavesReaderData(LeavesReader *pReader){ assert( !pReader->eof ); return leafReaderData(&pReader->leafReader); } static int leavesReaderAtEnd(LeavesReader *pReader){ return pReader->eof; } /* loadSegmentLeaves() may not read all the way to SQLITE_DONE, thus ** leaving the statement handle open, which locks the table. */ /* TODO(shess) This "solution" is not satisfactory. Really, there ** should be check-in function for all statement handles which ** arranges to call sqlite3_reset(). This most likely will require ** modification to control flow all over the place, though, so for now ** just punt. ** ** Note the current system assumes that segment merges will run to ** completion, which is why this particular probably hasn't arisen in ** this case. Probably a brittle assumption. */ static int leavesReaderReset(LeavesReader *pReader){ return sqlite3_reset(pReader->pStmt); } static void leavesReaderDestroy(LeavesReader *pReader){ /* If idx is -1, that means we're using a non-cached statement ** handle in the optimize() case, so we need to release it. */ if( pReader->pStmt!=NULL && pReader->idx==-1 ){ sqlite3_finalize(pReader->pStmt); } leafReaderDestroy(&pReader->leafReader); dataBufferDestroy(&pReader->rootData); SCRAMBLE(pReader); } /* Initialize pReader with the given root data (if iStartBlockid==0 ** the leaf data was entirely contained in the root), or from the ** stream of blocks between iStartBlockid and iEndBlockid, inclusive. */ static int leavesReaderInit(fulltext_vtab *v, int idx, sqlite_int64 iStartBlockid, sqlite_int64 iEndBlockid, const char *pRootData, int nRootData, LeavesReader *pReader){ CLEAR(pReader); pReader->idx = idx; dataBufferInit(&pReader->rootData, 0); if( iStartBlockid==0 ){ /* Entire leaf level fit in root data. */ dataBufferReplace(&pReader->rootData, pRootData, nRootData); leafReaderInit(pReader->rootData.pData, pReader->rootData.nData, &pReader->leafReader); }else{ sqlite3_stmt *s; int rc = sql_get_leaf_statement(v, idx, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int64(s, 1, iStartBlockid); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int64(s, 2, iEndBlockid); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_step(s); if( rc==SQLITE_DONE ){ pReader->eof = 1; return SQLITE_OK; } if( rc!=SQLITE_ROW ) return rc; pReader->pStmt = s; leafReaderInit(sqlite3_column_blob(pReader->pStmt, 0), sqlite3_column_bytes(pReader->pStmt, 0), &pReader->leafReader); } return SQLITE_OK; } /* Step the current leaf forward to the next term. If we reach the ** end of the current leaf, step forward to the next leaf block. */ static int leavesReaderStep(fulltext_vtab *v, LeavesReader *pReader){ assert( !leavesReaderAtEnd(pReader) ); leafReaderStep(&pReader->leafReader); if( leafReaderAtEnd(&pReader->leafReader) ){ int rc; if( pReader->rootData.pData ){ pReader->eof = 1; return SQLITE_OK; } rc = sqlite3_step(pReader->pStmt); if( rc!=SQLITE_ROW ){ pReader->eof = 1; return rc==SQLITE_DONE ? SQLITE_OK : rc; } leafReaderDestroy(&pReader->leafReader); leafReaderInit(sqlite3_column_blob(pReader->pStmt, 0), sqlite3_column_bytes(pReader->pStmt, 0), &pReader->leafReader); } return SQLITE_OK; } /* Order LeavesReaders by their term, ignoring idx. Readers at eof ** always sort to the end. */ static int leavesReaderTermCmp(LeavesReader *lr1, LeavesReader *lr2){ if( leavesReaderAtEnd(lr1) ){ if( leavesReaderAtEnd(lr2) ) return 0; return 1; } if( leavesReaderAtEnd(lr2) ) return -1; return leafReaderTermCmp(&lr1->leafReader, leavesReaderTerm(lr2), leavesReaderTermBytes(lr2), 0); } /* Similar to leavesReaderTermCmp(), with additional ordering by idx ** so that older segments sort before newer segments. */ static int leavesReaderCmp(LeavesReader *lr1, LeavesReader *lr2){ int c = leavesReaderTermCmp(lr1, lr2); if( c!=0 ) return c; return lr1->idx-lr2->idx; } /* Assume that pLr[1]..pLr[nLr] are sorted. Bubble pLr[0] into its ** sorted position. */ static void leavesReaderReorder(LeavesReader *pLr, int nLr){ while( nLr>1 && leavesReaderCmp(pLr, pLr+1)>0 ){ LeavesReader tmp = pLr[0]; pLr[0] = pLr[1]; pLr[1] = tmp; nLr--; pLr++; } } /* Initializes pReaders with the segments from level iLevel, returning ** the number of segments in *piReaders. Leaves pReaders in sorted ** order. */ static int leavesReadersInit(fulltext_vtab *v, int iLevel, LeavesReader *pReaders, int *piReaders){ sqlite3_stmt *s; int i, rc = sql_get_statement(v, SEGDIR_SELECT_LEVEL_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int(s, 1, iLevel); if( rc!=SQLITE_OK ) return rc; i = 0; while( (rc = sqlite3_step(s))==SQLITE_ROW ){ sqlite_int64 iStart = sqlite3_column_int64(s, 0); sqlite_int64 iEnd = sqlite3_column_int64(s, 1); const char *pRootData = sqlite3_column_blob(s, 2); int nRootData = sqlite3_column_bytes(s, 2); assert( i<MERGE_COUNT ); rc = leavesReaderInit(v, i, iStart, iEnd, pRootData, nRootData, &pReaders[i]); if( rc!=SQLITE_OK ) break; i++; } if( rc!=SQLITE_DONE ){ while( i-->0 ){ leavesReaderDestroy(&pReaders[i]); } return rc; } *piReaders = i; /* Leave our results sorted by term, then age. */ while( i-- ){ leavesReaderReorder(pReaders+i, *piReaders-i); } return SQLITE_OK; } /* Merge doclists from pReaders[nReaders] into a single doclist, which ** is written to pWriter. Assumes pReaders is ordered oldest to ** newest. */ /* TODO(shess) Consider putting this inline in segmentMerge(). */ static int leavesReadersMerge(fulltext_vtab *v, LeavesReader *pReaders, int nReaders, LeafWriter *pWriter){ DLReader dlReaders[MERGE_COUNT]; const char *pTerm = leavesReaderTerm(pReaders); int i, nTerm = leavesReaderTermBytes(pReaders); assert( nReaders<=MERGE_COUNT ); for(i=0; i<nReaders; i++){ dlrInit(&dlReaders[i], DL_DEFAULT, leavesReaderData(pReaders+i), leavesReaderDataBytes(pReaders+i)); } return leafWriterStepMerge(v, pWriter, pTerm, nTerm, dlReaders, nReaders); } /* Forward ref due to mutual recursion with segdirNextIndex(). */ static int segmentMerge(fulltext_vtab *v, int iLevel); /* Put the next available index at iLevel into *pidx. If iLevel ** already has MERGE_COUNT segments, they are merged to a higher ** level to make room. */ static int segdirNextIndex(fulltext_vtab *v, int iLevel, int *pidx){ int rc = segdir_max_index(v, iLevel, pidx); if( rc==SQLITE_DONE ){ /* No segments at iLevel. */ *pidx = 0; }else if( rc==SQLITE_ROW ){ if( *pidx==(MERGE_COUNT-1) ){ rc = segmentMerge(v, iLevel); if( rc!=SQLITE_OK ) return rc; *pidx = 0; }else{ (*pidx)++; } }else{ return rc; } return SQLITE_OK; } /* Merge MERGE_COUNT segments at iLevel into a new segment at ** iLevel+1. If iLevel+1 is already full of segments, those will be ** merged to make room. */ static int segmentMerge(fulltext_vtab *v, int iLevel){ LeafWriter writer; LeavesReader lrs[MERGE_COUNT]; int i, rc, idx = 0; /* Determine the next available segment index at the next level, ** merging as necessary. */ rc = segdirNextIndex(v, iLevel+1, &idx); if( rc!=SQLITE_OK ) return rc; /* TODO(shess) This assumes that we'll always see exactly ** MERGE_COUNT segments to merge at a given level. That will be ** broken if we allow the developer to request preemptive or ** deferred merging. */ memset(&lrs, '\0', sizeof(lrs)); rc = leavesReadersInit(v, iLevel, lrs, &i); if( rc!=SQLITE_OK ) return rc; assert( i==MERGE_COUNT ); leafWriterInit(iLevel+1, idx, &writer); /* Since leavesReaderReorder() pushes readers at eof to the end, ** when the first reader is empty, all will be empty. */ while( !leavesReaderAtEnd(lrs) ){ /* Figure out how many readers share their next term. */ for(i=1; i<MERGE_COUNT && !leavesReaderAtEnd(lrs+i); i++){ if( 0!=leavesReaderTermCmp(lrs, lrs+i) ) break; } rc = leavesReadersMerge(v, lrs, i, &writer); if( rc!=SQLITE_OK ) goto err; /* Step forward those that were merged. */ while( i-->0 ){ rc = leavesReaderStep(v, lrs+i); if( rc!=SQLITE_OK ) goto err; /* Reorder by term, then by age. */ leavesReaderReorder(lrs+i, MERGE_COUNT-i); } } for(i=0; i<MERGE_COUNT; i++){ leavesReaderDestroy(&lrs[i]); } rc = leafWriterFinalize(v, &writer); leafWriterDestroy(&writer); if( rc!=SQLITE_OK ) return rc; /* Delete the merged segment data. */ return segdir_delete(v, iLevel); err: for(i=0; i<MERGE_COUNT; i++){ leavesReaderDestroy(&lrs[i]); } leafWriterDestroy(&writer); return rc; } /* Accumulate the union of *acc and *pData into *acc. */ static void docListAccumulateUnion(DataBuffer *acc, const char *pData, int nData) { DataBuffer tmp = *acc; dataBufferInit(acc, tmp.nData+nData); docListUnion(tmp.pData, tmp.nData, pData, nData, acc); dataBufferDestroy(&tmp); } /* TODO(shess) It might be interesting to explore different merge ** strategies, here. For instance, since this is a sorted merge, we ** could easily merge many doclists in parallel. With some ** comprehension of the storage format, we could merge all of the ** doclists within a leaf node directly from the leaf node's storage. ** It may be worthwhile to merge smaller doclists before larger ** doclists, since they can be traversed more quickly - but the ** results may have less overlap, making them more expensive in a ** different way. */ /* Scan pReader for pTerm/nTerm, and merge the term's doclist over ** *out (any doclists with duplicate docids overwrite those in *out). ** Internal function for loadSegmentLeaf(). */ static int loadSegmentLeavesInt(fulltext_vtab *v, LeavesReader *pReader, const char *pTerm, int nTerm, int isPrefix, DataBuffer *out){ /* doclist data is accumulated into pBuffers similar to how one does ** increment in binary arithmetic. If index 0 is empty, the data is ** stored there. If there is data there, it is merged and the ** results carried into position 1, with further merge-and-carry ** until an empty position is found. */ DataBuffer *pBuffers = NULL; int nBuffers = 0, nMaxBuffers = 0, rc; assert( nTerm>0 ); for(rc=SQLITE_OK; rc==SQLITE_OK && !leavesReaderAtEnd(pReader); rc=leavesReaderStep(v, pReader)){ /* TODO(shess) Really want leavesReaderTermCmp(), but that name is ** already taken to compare the terms of two LeavesReaders. Think ** on a better name. [Meanwhile, break encapsulation rather than ** use a confusing name.] */ int c = leafReaderTermCmp(&pReader->leafReader, pTerm, nTerm, isPrefix); if( c>0 ) break; /* Past any possible matches. */ if( c==0 ){ const char *pData = leavesReaderData(pReader); int iBuffer, nData = leavesReaderDataBytes(pReader); /* Find the first empty buffer. */ for(iBuffer=0; iBuffer<nBuffers; ++iBuffer){ if( 0==pBuffers[iBuffer].nData ) break; } /* Out of buffers, add an empty one. */ if( iBuffer==nBuffers ){ if( nBuffers==nMaxBuffers ){ DataBuffer *p; nMaxBuffers += 20; /* Manual realloc so we can handle NULL appropriately. */ p = sqlite3_malloc(nMaxBuffers*sizeof(*pBuffers)); if( p==NULL ){ rc = SQLITE_NOMEM; break; } if( nBuffers>0 ){ assert(pBuffers!=NULL); memcpy(p, pBuffers, nBuffers*sizeof(*pBuffers)); sqlite3_free(pBuffers); } pBuffers = p; } dataBufferInit(&(pBuffers[nBuffers]), 0); nBuffers++; } /* At this point, must have an empty at iBuffer. */ assert(iBuffer<nBuffers && pBuffers[iBuffer].nData==0); /* If empty was first buffer, no need for merge logic. */ if( iBuffer==0 ){ dataBufferReplace(&(pBuffers[0]), pData, nData); }else{ /* pAcc is the empty buffer the merged data will end up in. */ DataBuffer *pAcc = &(pBuffers[iBuffer]); DataBuffer *p = &(pBuffers[0]); /* Handle position 0 specially to avoid need to prime pAcc ** with pData/nData. */ dataBufferSwap(p, pAcc); docListAccumulateUnion(pAcc, pData, nData); /* Accumulate remaining doclists into pAcc. */ for(++p; p<pAcc; ++p){ docListAccumulateUnion(pAcc, p->pData, p->nData); /* dataBufferReset() could allow a large doclist to blow up ** our memory requirements. */ if( p->nCapacity<1024 ){ dataBufferReset(p); }else{ dataBufferDestroy(p); dataBufferInit(p, 0); } } } } } /* Union all the doclists together into *out. */ /* TODO(shess) What if *out is big? Sigh. */ if( rc==SQLITE_OK && nBuffers>0 ){ int iBuffer; for(iBuffer=0; iBuffer<nBuffers; ++iBuffer){ if( pBuffers[iBuffer].nData>0 ){ if( out->nData==0 ){ dataBufferSwap(out, &(pBuffers[iBuffer])); }else{ docListAccumulateUnion(out, pBuffers[iBuffer].pData, pBuffers[iBuffer].nData); } } } } while( nBuffers-- ){ dataBufferDestroy(&(pBuffers[nBuffers])); } if( pBuffers!=NULL ) sqlite3_free(pBuffers); return rc; } /* Call loadSegmentLeavesInt() with pData/nData as input. */ static int loadSegmentLeaf(fulltext_vtab *v, const char *pData, int nData, const char *pTerm, int nTerm, int isPrefix, DataBuffer *out){ LeavesReader reader; int rc; assert( nData>1 ); assert( *pData=='\0' ); rc = leavesReaderInit(v, 0, 0, 0, pData, nData, &reader); if( rc!=SQLITE_OK ) return rc; rc = loadSegmentLeavesInt(v, &reader, pTerm, nTerm, isPrefix, out); leavesReaderReset(&reader); leavesReaderDestroy(&reader); return rc; } /* Call loadSegmentLeavesInt() with the leaf nodes from iStartLeaf to ** iEndLeaf (inclusive) as input, and merge the resulting doclist into ** out. */ static int loadSegmentLeaves(fulltext_vtab *v, sqlite_int64 iStartLeaf, sqlite_int64 iEndLeaf, const char *pTerm, int nTerm, int isPrefix, DataBuffer *out){ int rc; LeavesReader reader; assert( iStartLeaf<=iEndLeaf ); rc = leavesReaderInit(v, 0, iStartLeaf, iEndLeaf, NULL, 0, &reader); if( rc!=SQLITE_OK ) return rc; rc = loadSegmentLeavesInt(v, &reader, pTerm, nTerm, isPrefix, out); leavesReaderReset(&reader); leavesReaderDestroy(&reader); return rc; } /* Taking pData/nData as an interior node, find the sequence of child ** nodes which could include pTerm/nTerm/isPrefix. Note that the ** interior node terms logically come between the blocks, so there is ** one more blockid than there are terms (that block contains terms >= ** the last interior-node term). */ /* TODO(shess) The calling code may already know that the end child is ** not worth calculating, because the end may be in a later sibling ** node. Consider whether breaking symmetry is worthwhile. I suspect ** it is not worthwhile. */ static void getChildrenContaining(const char *pData, int nData, const char *pTerm, int nTerm, int isPrefix, sqlite_int64 *piStartChild, sqlite_int64 *piEndChild){ InteriorReader reader; assert( nData>1 ); assert( *pData!='\0' ); interiorReaderInit(pData, nData, &reader); /* Scan for the first child which could contain pTerm/nTerm. */ while( !interiorReaderAtEnd(&reader) ){ if( interiorReaderTermCmp(&reader, pTerm, nTerm, 0)>0 ) break; interiorReaderStep(&reader); } *piStartChild = interiorReaderCurrentBlockid(&reader); /* Keep scanning to find a term greater than our term, using prefix ** comparison if indicated. If isPrefix is false, this will be the ** same blockid as the starting block. */ while( !interiorReaderAtEnd(&reader) ){ if( interiorReaderTermCmp(&reader, pTerm, nTerm, isPrefix)>0 ) break; interiorReaderStep(&reader); } *piEndChild = interiorReaderCurrentBlockid(&reader); interiorReaderDestroy(&reader); /* Children must ascend, and if !prefix, both must be the same. */ assert( *piEndChild>=*piStartChild ); assert( isPrefix || *piStartChild==*piEndChild ); } /* Read block at iBlockid and pass it with other params to ** getChildrenContaining(). */ static int loadAndGetChildrenContaining( fulltext_vtab *v, sqlite_int64 iBlockid, const char *pTerm, int nTerm, int isPrefix, sqlite_int64 *piStartChild, sqlite_int64 *piEndChild ){ sqlite3_stmt *s = NULL; int rc; assert( iBlockid!=0 ); assert( pTerm!=NULL ); assert( nTerm!=0 ); /* TODO(shess) Why not allow this? */ assert( piStartChild!=NULL ); assert( piEndChild!=NULL ); rc = sql_get_statement(v, BLOCK_SELECT_STMT, &s); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_bind_int64(s, 1, iBlockid); if( rc!=SQLITE_OK ) return rc; rc = sqlite3_step(s); if( rc==SQLITE_DONE ) return SQLITE_ERROR; if( rc!=SQLITE_ROW ) return rc; getChildrenContaining(sqlite3_column_blob(s, 0), sqlite3_column_bytes(s, 0), pTerm, nTerm, isPrefix, piStartChild, piEndChild); /* We expect only one row. We must execute another sqlite3_step() * to complete the iteration; otherwise the table will remain * locked. */ rc = sqlite3_step(s); if( rc==SQLITE_ROW ) return SQLITE_ERROR; if( rc!=SQLITE_DONE ) return rc; return SQLITE_OK; } /* Traverse the tree represented by pData[nData] looking for ** pTerm[nTerm], placing its doclist into *out. This is internal to ** loadSegment() to make error-handling cleaner. */ static int loadSegmentInt(fulltext_vtab *v, const char *pData, int nData, sqlite_int64 iLeavesEnd, const char *pTerm, int nTerm, int isPrefix, DataBuffer *out){ /* Special case where root is a leaf. */ if( *pData=='\0' ){ return loadSegmentLeaf(v, pData, nData, pTerm, nTerm, isPrefix, out); }else{ int rc; sqlite_int64 iStartChild, iEndChild; /* Process pData as an interior node, then loop down the tree ** until we find the set of leaf nodes to scan for the term. */ getChildrenContaining(pData, nData, pTerm, nTerm, isPrefix, &iStartChild, &iEndChild); while( iStartChild>iLeavesEnd ){ sqlite_int64 iNextStart, iNextEnd; rc = loadAndGetChildrenContaining(v, iStartChild, pTerm, nTerm, isPrefix, &iNextStart, &iNextEnd); if( rc!=SQLITE_OK ) return rc; /* If we've branched, follow the end branch, too. */ if( iStartChild!=iEndChild ){ sqlite_int64 iDummy; rc = loadAndGetChildrenContaining(v, iEndChild, pTerm, nTerm, isPrefix, &iDummy, &iNextEnd); if( rc!=SQLITE_OK ) return rc; } assert( iNextStart<=iNextEnd ); iStartChild = iNextStart; iEndChild = iNextEnd; } assert( iStartChild<=iLeavesEnd ); assert( iEndChild<=iLeavesEnd ); /* Scan through the leaf segments for doclists. */ return loadSegmentLeaves(v, iStartChild, iEndChild, pTerm, nTerm, isPrefix, out); } } /* Call loadSegmentInt() to collect the doclist for pTerm/nTerm, then ** merge its doclist over *out (any duplicate doclists read from the ** segment rooted at pData will overwrite those in *out). */ /* TODO(shess) Consider changing this to determine the depth of the ** leaves using either the first characters of interior nodes (when ** ==1, we're one level above the leaves), or the first character of ** the root (which will describe the height of the tree directly). ** Either feels somewhat tricky to me. */ /* TODO(shess) The current merge is likely to be slow for large ** doclists (though it should process from newest/smallest to ** oldest/largest, so it may not be that bad). It might be useful to ** modify things to allow for N-way merging. This could either be ** within a segment, with pairwise merges across segments, or across ** all segments at once. */ static int loadSegment(fulltext_vtab *v, const char *pData, int nData, sqlite_int64 iLeavesEnd, const char *pTerm, int nTerm, int isPrefix, DataBuffer *out){ DataBuffer result; int rc; assert( nData>1 ); /* This code should never be called with buffered updates. */ assert( v->nPendingData<0 ); dataBufferInit(&result, 0); rc = loadSegmentInt(v, pData, nData, iLeavesEnd, pTerm, nTerm, isPrefix, &result); if( rc==SQLITE_OK && result.nData>0 ){ if( out->nData==0 ){ DataBuffer tmp = *out; *out = result; result = tmp; }else{ DataBuffer merged; DLReader readers[2]; dlrInit(&readers[0], DL_DEFAULT, out->pData, out->nData); dlrInit(&readers[1], DL_DEFAULT, result.pData, result.nData); dataBufferInit(&merged, out->nData+result.nData); docListMerge(&merged, readers, 2); dataBufferDestroy(out); *out = merged; dlrDestroy(&readers[0]); dlrDestroy(&readers[1]); } } dataBufferDestroy(&result); return rc; } /* Scan the database and merge together the posting lists for the term ** into *out. */ static int termSelect(fulltext_vtab *v, int iColumn, const char *pTerm, int nTerm, int isPrefix, DocListType iType, DataBuffer *out){ DataBuffer doclist; sqlite3_stmt *s; int rc = sql_get_statement(v, SEGDIR_SELECT_ALL_STMT, &s); if( rc!=SQLITE_OK ) return rc; /* This code should never be called with buffered updates. */ assert( v->nPendingData<0 ); dataBufferInit(&doclist, 0); /* Traverse the segments from oldest to newest so that newer doclist ** elements for given docids overwrite older elements. */ while( (rc = sqlite3_step(s))==SQLITE_ROW ){ const char *pData = sqlite3_column_blob(s, 2); const int nData = sqlite3_column_bytes(s, 2); const sqlite_int64 iLeavesEnd = sqlite3_column_int64(s, 1); rc = loadSegment(v, pData, nData, iLeavesEnd, pTerm, nTerm, isPrefix, &doclist); if( rc!=SQLITE_OK ) goto err; } if( rc==SQLITE_DONE ){ if( doclist.nData!=0 ){ /* TODO(shess) The old term_select_all() code applied the column ** restrict as we merged segments, leading to smaller buffers. ** This is probably worthwhile to bring back, once the new storage ** system is checked in. */ if( iColumn==v->nColumn) iColumn = -1; docListTrim(DL_DEFAULT, doclist.pData, doclist.nData, iColumn, iType, out); } rc = SQLITE_OK; } err: dataBufferDestroy(&doclist); return rc; } /****************************************************************/ /* Used to hold hashtable data for sorting. */ typedef struct TermData { const char *pTerm; int nTerm; DLCollector *pCollector; } TermData; /* Orders TermData elements in strcmp fashion ( <0 for less-than, 0 ** for equal, >0 for greater-than). */ static int termDataCmp(const void *av, const void *bv){ const TermData *a = (const TermData *)av; const TermData *b = (const TermData *)bv; int n = a->nTerm<b->nTerm ? a->nTerm : b->nTerm; int c = memcmp(a->pTerm, b->pTerm, n); if( c!=0 ) return c; return a->nTerm-b->nTerm; } /* Order pTerms data by term, then write a new level 0 segment using ** LeafWriter. */ static int writeZeroSegment(fulltext_vtab *v, fts2Hash *pTerms){ fts2HashElem *e; int idx, rc, i, n; TermData *pData; LeafWriter writer; DataBuffer dl; /* Determine the next index at level 0, merging as necessary. */ rc = segdirNextIndex(v, 0, &idx); if( rc!=SQLITE_OK ) return rc; n = fts2HashCount(pTerms); pData = sqlite3_malloc(n*sizeof(TermData)); for(i = 0, e = fts2HashFirst(pTerms); e; i++, e = fts2HashNext(e)){ assert( i<n ); pData[i].pTerm = fts2HashKey(e); pData[i].nTerm = fts2HashKeysize(e); pData[i].pCollector = fts2HashData(e); } assert( i==n ); /* TODO(shess) Should we allow user-defined collation sequences, ** here? I think we only need that once we support prefix searches. */ if( n>1 ) qsort(pData, n, sizeof(*pData), termDataCmp); /* TODO(shess) Refactor so that we can write directly to the segment ** DataBuffer, as happens for segment merges. */ leafWriterInit(0, idx, &writer); dataBufferInit(&dl, 0); for(i=0; i<n; i++){ dataBufferReset(&dl); dlcAddDoclist(pData[i].pCollector, &dl); rc = leafWriterStep(v, &writer, pData[i].pTerm, pData[i].nTerm, dl.pData, dl.nData); if( rc!=SQLITE_OK ) goto err; } rc = leafWriterFinalize(v, &writer); err: dataBufferDestroy(&dl); sqlite3_free(pData); leafWriterDestroy(&writer); return rc; } /* If pendingTerms has data, free it. */ static int clearPendingTerms(fulltext_vtab *v){ if( v->nPendingData>=0 ){ fts2HashElem *e; for(e=fts2HashFirst(&v->pendingTerms); e; e=fts2HashNext(e)){ dlcDelete(fts2HashData(e)); } fts2HashClear(&v->pendingTerms); v->nPendingData = -1; } return SQLITE_OK; } /* If pendingTerms has data, flush it to a level-zero segment, and ** free it. */ static int flushPendingTerms(fulltext_vtab *v){ if( v->nPendingData>=0 ){ int rc = writeZeroSegment(v, &v->pendingTerms); if( rc==SQLITE_OK ) clearPendingTerms(v); return rc; } return SQLITE_OK; } /* If pendingTerms is "too big", or docid is out of order, flush it. ** Regardless, be certain that pendingTerms is initialized for use. */ static int initPendingTerms(fulltext_vtab *v, sqlite_int64 iDocid){ /* TODO(shess) Explore whether partially flushing the buffer on ** forced-flush would provide better performance. I suspect that if ** we ordered the doclists by size and flushed the largest until the ** buffer was half empty, that would let the less frequent terms ** generate longer doclists. */ if( iDocid<=v->iPrevDocid || v->nPendingData>kPendingThreshold ){ int rc = flushPendingTerms(v); if( rc!=SQLITE_OK ) return rc; } if( v->nPendingData<0 ){ fts2HashInit(&v->pendingTerms, FTS2_HASH_STRING, 1); v->nPendingData = 0; } v->iPrevDocid = iDocid; return SQLITE_OK; } /* This function implements the xUpdate callback; it is the top-level entry * point for inserting, deleting or updating a row in a full-text table. */ static int fulltextUpdate(sqlite3_vtab *pVtab, int nArg, sqlite3_value **ppArg, sqlite_int64 *pRowid){ fulltext_vtab *v = (fulltext_vtab *) pVtab; int rc; TRACE(("FTS2 Update %p\n", pVtab)); if( nArg<2 ){ rc = index_delete(v, sqlite3_value_int64(ppArg[0])); if( rc==SQLITE_OK ){ /* If we just deleted the last row in the table, clear out the ** index data. */ rc = content_exists(v); if( rc==SQLITE_ROW ){ rc = SQLITE_OK; }else if( rc==SQLITE_DONE ){ /* Clear the pending terms so we don't flush a useless level-0 ** segment when the transaction closes. */ rc = clearPendingTerms(v); if( rc==SQLITE_OK ){ rc = segdir_delete_all(v); } } } } else if( sqlite3_value_type(ppArg[0]) != SQLITE_NULL ){ /* An update: * ppArg[0] = old rowid * ppArg[1] = new rowid * ppArg[2..2+v->nColumn-1] = values * ppArg[2+v->nColumn] = value for magic column (we ignore this) */ sqlite_int64 rowid = sqlite3_value_int64(ppArg[0]); if( sqlite3_value_type(ppArg[1]) != SQLITE_INTEGER || sqlite3_value_int64(ppArg[1]) != rowid ){ rc = SQLITE_ERROR; /* we don't allow changing the rowid */ } else { assert( nArg==2+v->nColumn+1); rc = index_update(v, rowid, &ppArg[2]); } } else { /* An insert: * ppArg[1] = requested rowid * ppArg[2..2+v->nColumn-1] = values * ppArg[2+v->nColumn] = value for magic column (we ignore this) */ assert( nArg==2+v->nColumn+1); rc = index_insert(v, ppArg[1], &ppArg[2], pRowid); } return rc; } static int fulltextSync(sqlite3_vtab *pVtab){ TRACE(("FTS2 xSync()\n")); return flushPendingTerms((fulltext_vtab *)pVtab); } static int fulltextBegin(sqlite3_vtab *pVtab){ fulltext_vtab *v = (fulltext_vtab *) pVtab; TRACE(("FTS2 xBegin()\n")); /* Any buffered updates should have been cleared by the previous ** transaction. */ assert( v->nPendingData<0 ); return clearPendingTerms(v); } static int fulltextCommit(sqlite3_vtab *pVtab){ fulltext_vtab *v = (fulltext_vtab *) pVtab; TRACE(("FTS2 xCommit()\n")); /* Buffered updates should have been cleared by fulltextSync(). */ assert( v->nPendingData<0 ); return clearPendingTerms(v); } static int fulltextRollback(sqlite3_vtab *pVtab){ TRACE(("FTS2 xRollback()\n")); return clearPendingTerms((fulltext_vtab *)pVtab); } /* ** Implementation of the snippet() function for FTS2 */ static void snippetFunc( sqlite3_context *pContext, int argc, sqlite3_value **argv ){ fulltext_cursor *pCursor; if( argc<1 ) return; if( sqlite3_value_type(argv[0])!=SQLITE_BLOB || sqlite3_value_bytes(argv[0])!=sizeof(pCursor) ){ sqlite3_result_error(pContext, "illegal first argument to html_snippet",-1); }else{ const char *zStart = "<b>"; const char *zEnd = "</b>"; const char *zEllipsis = "<b>...</b>"; memcpy(&pCursor, sqlite3_value_blob(argv[0]), sizeof(pCursor)); if( argc>=2 ){ zStart = (const char*)sqlite3_value_text(argv[1]); if( argc>=3 ){ zEnd = (const char*)sqlite3_value_text(argv[2]); if( argc>=4 ){ zEllipsis = (const char*)sqlite3_value_text(argv[3]); } } } snippetAllOffsets(pCursor); snippetText(pCursor, zStart, zEnd, zEllipsis); sqlite3_result_text(pContext, pCursor->snippet.zSnippet, pCursor->snippet.nSnippet, SQLITE_STATIC); } } /* ** Implementation of the offsets() function for FTS2 */ static void snippetOffsetsFunc( sqlite3_context *pContext, int argc, sqlite3_value **argv ){ fulltext_cursor *pCursor; if( argc<1 ) return; if( sqlite3_value_type(argv[0])!=SQLITE_BLOB || sqlite3_value_bytes(argv[0])!=sizeof(pCursor) ){ sqlite3_result_error(pContext, "illegal first argument to offsets",-1); }else{ memcpy(&pCursor, sqlite3_value_blob(argv[0]), sizeof(pCursor)); snippetAllOffsets(pCursor); snippetOffsetText(&pCursor->snippet); sqlite3_result_text(pContext, pCursor->snippet.zOffset, pCursor->snippet.nOffset, SQLITE_STATIC); } } /* OptLeavesReader is nearly identical to LeavesReader, except that ** where LeavesReader is geared towards the merging of complete ** segment levels (with exactly MERGE_COUNT segments), OptLeavesReader ** is geared towards implementation of the optimize() function, and ** can merge all segments simultaneously. This version may be ** somewhat less efficient than LeavesReader because it merges into an ** accumulator rather than doing an N-way merge, but since segment ** size grows exponentially (so segment count logrithmically) this is ** probably not an immediate problem. */ /* TODO(shess): Prove that assertion, or extend the merge code to ** merge tree fashion (like the prefix-searching code does). */ /* TODO(shess): OptLeavesReader and LeavesReader could probably be ** merged with little or no loss of performance for LeavesReader. The ** merged code would need to handle >MERGE_COUNT segments, and would ** also need to be able to optionally optimize away deletes. */ typedef struct OptLeavesReader { /* Segment number, to order readers by age. */ int segment; LeavesReader reader; } OptLeavesReader; static int optLeavesReaderAtEnd(OptLeavesReader *pReader){ return leavesReaderAtEnd(&pReader->reader); } static int optLeavesReaderTermBytes(OptLeavesReader *pReader){ return leavesReaderTermBytes(&pReader->reader); } static const char *optLeavesReaderData(OptLeavesReader *pReader){ return leavesReaderData(&pReader->reader); } static int optLeavesReaderDataBytes(OptLeavesReader *pReader){ return leavesReaderDataBytes(&pReader->reader); } static const char *optLeavesReaderTerm(OptLeavesReader *pReader){ return leavesReaderTerm(&pReader->reader); } static int optLeavesReaderStep(fulltext_vtab *v, OptLeavesReader *pReader){ return leavesReaderStep(v, &pReader->reader); } static int optLeavesReaderTermCmp(OptLeavesReader *lr1, OptLeavesReader *lr2){ return leavesReaderTermCmp(&lr1->reader, &lr2->reader); } /* Order by term ascending, segment ascending (oldest to newest), with ** exhausted readers to the end. */ static int optLeavesReaderCmp(OptLeavesReader *lr1, OptLeavesReader *lr2){ int c = optLeavesReaderTermCmp(lr1, lr2); if( c!=0 ) return c; return lr1->segment-lr2->segment; } /* Bubble pLr[0] to appropriate place in pLr[1..nLr-1]. Assumes that ** pLr[1..nLr-1] is already sorted. */ static void optLeavesReaderReorder(OptLeavesReader *pLr, int nLr){ while( nLr>1 && optLeavesReaderCmp(pLr, pLr+1)>0 ){ OptLeavesReader tmp = pLr[0]; pLr[0] = pLr[1]; pLr[1] = tmp; nLr--; pLr++; } } /* optimize() helper function. Put the readers in order and iterate ** through them, merging doclists for matching terms into pWriter. ** Returns SQLITE_OK on success, or the SQLite error code which ** prevented success. */ static int optimizeInternal(fulltext_vtab *v, OptLeavesReader *readers, int nReaders, LeafWriter *pWriter){ int i, rc = SQLITE_OK; DataBuffer doclist, merged, tmp; /* Order the readers. */ i = nReaders; while( i-- > 0 ){ optLeavesReaderReorder(&readers[i], nReaders-i); } dataBufferInit(&doclist, LEAF_MAX); dataBufferInit(&merged, LEAF_MAX); /* Exhausted readers bubble to the end, so when the first reader is ** at eof, all are at eof. */ while( !optLeavesReaderAtEnd(&readers[0]) ){ /* Figure out how many readers share the next term. */ for(i=1; i<nReaders && !optLeavesReaderAtEnd(&readers[i]); i++){ if( 0!=optLeavesReaderTermCmp(&readers[0], &readers[i]) ) break; } /* Special-case for no merge. */ if( i==1 ){ /* Trim deletions from the doclist. */ dataBufferReset(&merged); docListTrim(DL_DEFAULT, optLeavesReaderData(&readers[0]), optLeavesReaderDataBytes(&readers[0]), -1, DL_DEFAULT, &merged); }else{ DLReader dlReaders[MERGE_COUNT]; int iReader, nReaders; /* Prime the pipeline with the first reader's doclist. After ** one pass index 0 will reference the accumulated doclist. */ dlrInit(&dlReaders[0], DL_DEFAULT, optLeavesReaderData(&readers[0]), optLeavesReaderDataBytes(&readers[0])); iReader = 1; assert( iReader<i ); /* Must execute the loop at least once. */ while( iReader<i ){ /* Merge 16 inputs per pass. */ for( nReaders=1; iReader<i && nReaders<MERGE_COUNT; iReader++, nReaders++ ){ dlrInit(&dlReaders[nReaders], DL_DEFAULT, optLeavesReaderData(&readers[iReader]), optLeavesReaderDataBytes(&readers[iReader])); } /* Merge doclists and swap result into accumulator. */ dataBufferReset(&merged); docListMerge(&merged, dlReaders, nReaders); tmp = merged; merged = doclist; doclist = tmp; while( nReaders-- > 0 ){ dlrDestroy(&dlReaders[nReaders]); } /* Accumulated doclist to reader 0 for next pass. */ dlrInit(&dlReaders[0], DL_DEFAULT, doclist.pData, doclist.nData); } /* Destroy reader that was left in the pipeline. */ dlrDestroy(&dlReaders[0]); /* Trim deletions from the doclist. */ dataBufferReset(&merged); docListTrim(DL_DEFAULT, doclist.pData, doclist.nData, -1, DL_DEFAULT, &merged); } /* Only pass doclists with hits (skip if all hits deleted). */ if( merged.nData>0 ){ rc = leafWriterStep(v, pWriter, optLeavesReaderTerm(&readers[0]), optLeavesReaderTermBytes(&readers[0]), merged.pData, merged.nData); if( rc!=SQLITE_OK ) goto err; } /* Step merged readers to next term and reorder. */ while( i-- > 0 ){ rc = optLeavesReaderStep(v, &readers[i]); if( rc!=SQLITE_OK ) goto err; optLeavesReaderReorder(&readers[i], nReaders-i); } } err: dataBufferDestroy(&doclist); dataBufferDestroy(&merged); return rc; } /* Implement optimize() function for FTS3. optimize(t) merges all ** segments in the fts index into a single segment. 't' is the magic ** table-named column. */ static void optimizeFunc(sqlite3_context *pContext, int argc, sqlite3_value **argv){ fulltext_cursor *pCursor; if( argc>1 ){ sqlite3_result_error(pContext, "excess arguments to optimize()",-1); }else if( sqlite3_value_type(argv[0])!=SQLITE_BLOB || sqlite3_value_bytes(argv[0])!=sizeof(pCursor) ){ sqlite3_result_error(pContext, "illegal first argument to optimize",-1); }else{ fulltext_vtab *v; int i, rc, iMaxLevel; OptLeavesReader *readers; int nReaders; LeafWriter writer; sqlite3_stmt *s; memcpy(&pCursor, sqlite3_value_blob(argv[0]), sizeof(pCursor)); v = cursor_vtab(pCursor); /* Flush any buffered updates before optimizing. */ rc = flushPendingTerms(v); if( rc!=SQLITE_OK ) goto err; rc = segdir_count(v, &nReaders, &iMaxLevel); if( rc!=SQLITE_OK ) goto err; if( nReaders==0 || nReaders==1 ){ sqlite3_result_text(pContext, "Index already optimal", -1, SQLITE_STATIC); return; } rc = sql_get_statement(v, SEGDIR_SELECT_ALL_STMT, &s); if( rc!=SQLITE_OK ) goto err; readers = sqlite3_malloc(nReaders*sizeof(readers[0])); if( readers==NULL ) goto err; /* Note that there will already be a segment at this position ** until we call segdir_delete() on iMaxLevel. */ leafWriterInit(iMaxLevel, 0, &writer); i = 0; while( (rc = sqlite3_step(s))==SQLITE_ROW ){ sqlite_int64 iStart = sqlite3_column_int64(s, 0); sqlite_int64 iEnd = sqlite3_column_int64(s, 1); const char *pRootData = sqlite3_column_blob(s, 2); int nRootData = sqlite3_column_bytes(s, 2); assert( i<nReaders ); rc = leavesReaderInit(v, -1, iStart, iEnd, pRootData, nRootData, &readers[i].reader); if( rc!=SQLITE_OK ) break; readers[i].segment = i; i++; } /* If we managed to successfully read them all, optimize them. */ if( rc==SQLITE_DONE ){ assert( i==nReaders ); rc = optimizeInternal(v, readers, nReaders, &writer); } while( i-- > 0 ){ leavesReaderDestroy(&readers[i].reader); } sqlite3_free(readers); /* If we've successfully gotten to here, delete the old segments ** and flush the interior structure of the new segment. */ if( rc==SQLITE_OK ){ for( i=0; i<=iMaxLevel; i++ ){ rc = segdir_delete(v, i); if( rc!=SQLITE_OK ) break; } if( rc==SQLITE_OK ) rc = leafWriterFinalize(v, &writer); } leafWriterDestroy(&writer); if( rc!=SQLITE_OK ) goto err; sqlite3_result_text(pContext, "Index optimized", -1, SQLITE_STATIC); return; /* TODO(shess): Error-handling needs to be improved along the ** lines of the dump_ functions. */ err: { char buf[512]; sqlite3_snprintf(sizeof(buf), buf, "Error in optimize: %s", sqlite3_errmsg(sqlite3_context_db_handle(pContext))); sqlite3_result_error(pContext, buf, -1); } } } #ifdef SQLITE_TEST /* Generate an error of the form "<prefix>: <msg>". If msg is NULL, ** pull the error from the context's db handle. */ static void generateError(sqlite3_context *pContext, const char *prefix, const char *msg){ char buf[512]; if( msg==NULL ) msg = sqlite3_errmsg(sqlite3_context_db_handle(pContext)); sqlite3_snprintf(sizeof(buf), buf, "%s: %s", prefix, msg); sqlite3_result_error(pContext, buf, -1); } /* Helper function to collect the set of terms in the segment into ** pTerms. The segment is defined by the leaf nodes between ** iStartBlockid and iEndBlockid, inclusive, or by the contents of ** pRootData if iStartBlockid is 0 (in which case the entire segment ** fit in a leaf). */ static int collectSegmentTerms(fulltext_vtab *v, sqlite3_stmt *s, fts2Hash *pTerms){ const sqlite_int64 iStartBlockid = sqlite3_column_int64(s, 0); const sqlite_int64 iEndBlockid = sqlite3_column_int64(s, 1); const char *pRootData = sqlite3_column_blob(s, 2); const int nRootData = sqlite3_column_bytes(s, 2); LeavesReader reader; int rc = leavesReaderInit(v, 0, iStartBlockid, iEndBlockid, pRootData, nRootData, &reader); if( rc!=SQLITE_OK ) return rc; while( rc==SQLITE_OK && !leavesReaderAtEnd(&reader) ){ const char *pTerm = leavesReaderTerm(&reader); const int nTerm = leavesReaderTermBytes(&reader); void *oldValue = sqlite3Fts2HashFind(pTerms, pTerm, nTerm); void *newValue = (void *)((char *)oldValue+1); /* From the comment before sqlite3Fts2HashInsert in fts2_hash.c, ** the data value passed is returned in case of malloc failure. */ if( newValue==sqlite3Fts2HashInsert(pTerms, pTerm, nTerm, newValue) ){ rc = SQLITE_NOMEM; }else{ rc = leavesReaderStep(v, &reader); } } leavesReaderDestroy(&reader); return rc; } /* Helper function to build the result string for dump_terms(). */ static int generateTermsResult(sqlite3_context *pContext, fts2Hash *pTerms){ int iTerm, nTerms, nResultBytes, iByte; char *result; TermData *pData; fts2HashElem *e; /* Iterate pTerms to generate an array of terms in pData for ** sorting. */ nTerms = fts2HashCount(pTerms); assert( nTerms>0 ); pData = sqlite3_malloc(nTerms*sizeof(TermData)); if( pData==NULL ) return SQLITE_NOMEM; nResultBytes = 0; for(iTerm = 0, e = fts2HashFirst(pTerms); e; iTerm++, e = fts2HashNext(e)){ nResultBytes += fts2HashKeysize(e)+1; /* Term plus trailing space */ assert( iTerm<nTerms ); pData[iTerm].pTerm = fts2HashKey(e); pData[iTerm].nTerm = fts2HashKeysize(e); pData[iTerm].pCollector = fts2HashData(e); /* unused */ } assert( iTerm==nTerms ); assert( nResultBytes>0 ); /* nTerms>0, nResultsBytes must be, too. */ result = sqlite3_malloc(nResultBytes); if( result==NULL ){ sqlite3_free(pData); return SQLITE_NOMEM; } if( nTerms>1 ) qsort(pData, nTerms, sizeof(*pData), termDataCmp); /* Read the terms in order to build the result. */ iByte = 0; for(iTerm=0; iTerm<nTerms; ++iTerm){ memcpy(result+iByte, pData[iTerm].pTerm, pData[iTerm].nTerm); iByte += pData[iTerm].nTerm; result[iByte++] = ' '; } assert( iByte==nResultBytes ); assert( result[nResultBytes-1]==' ' ); result[nResultBytes-1] = '\0'; /* Passes away ownership of result. */ sqlite3_result_text(pContext, result, nResultBytes-1, sqlite3_free); sqlite3_free(pData); return SQLITE_OK; } /* Implements dump_terms() for use in inspecting the fts2 index from ** tests. TEXT result containing the ordered list of terms joined by ** spaces. dump_terms(t, level, idx) dumps the terms for the segment ** specified by level, idx (in %_segdir), while dump_terms(t) dumps ** all terms in the index. In both cases t is the fts table's magic ** table-named column. */ static void dumpTermsFunc( sqlite3_context *pContext, int argc, sqlite3_value **argv ){ fulltext_cursor *pCursor; if( argc!=3 && argc!=1 ){ generateError(pContext, "dump_terms", "incorrect arguments"); }else if( sqlite3_value_type(argv[0])!=SQLITE_BLOB || sqlite3_value_bytes(argv[0])!=sizeof(pCursor) ){ generateError(pContext, "dump_terms", "illegal first argument"); }else{ fulltext_vtab *v; fts2Hash terms; sqlite3_stmt *s = NULL; int rc; memcpy(&pCursor, sqlite3_value_blob(argv[0]), sizeof(pCursor)); v = cursor_vtab(pCursor); /* If passed only the cursor column, get all segments. Otherwise ** get the segment described by the following two arguments. */ if( argc==1 ){ rc = sql_get_statement(v, SEGDIR_SELECT_ALL_STMT, &s); }else{ rc = sql_get_statement(v, SEGDIR_SELECT_SEGMENT_STMT, &s); if( rc==SQLITE_OK ){ rc = sqlite3_bind_int(s, 1, sqlite3_value_int(argv[1])); if( rc==SQLITE_OK ){ rc = sqlite3_bind_int(s, 2, sqlite3_value_int(argv[2])); } } } if( rc!=SQLITE_OK ){ generateError(pContext, "dump_terms", NULL); return; } /* Collect the terms for each segment. */ sqlite3Fts2HashInit(&terms, FTS2_HASH_STRING, 1); while( (rc = sqlite3_step(s))==SQLITE_ROW ){ rc = collectSegmentTerms(v, s, &terms); if( rc!=SQLITE_OK ) break; } if( rc!=SQLITE_DONE ){ sqlite3_reset(s); generateError(pContext, "dump_terms", NULL); }else{ const int nTerms = fts2HashCount(&terms); if( nTerms>0 ){ rc = generateTermsResult(pContext, &terms); if( rc==SQLITE_NOMEM ){ generateError(pContext, "dump_terms", "out of memory"); }else{ assert( rc==SQLITE_OK ); } }else if( argc==3 ){ /* The specific segment asked for could not be found. */ generateError(pContext, "dump_terms", "segment not found"); }else{ /* No segments found. */ /* TODO(shess): It should be impossible to reach this. This ** case can only happen for an empty table, in which case ** SQLite has no rows to call this function on. */ sqlite3_result_null(pContext); } } sqlite3Fts2HashClear(&terms); } } /* Expand the DL_DEFAULT doclist in pData into a text result in ** pContext. */ static void createDoclistResult(sqlite3_context *pContext, const char *pData, int nData){ DataBuffer dump; DLReader dlReader; assert( pData!=NULL && nData>0 ); dataBufferInit(&dump, 0); dlrInit(&dlReader, DL_DEFAULT, pData, nData); for( ; !dlrAtEnd(&dlReader); dlrStep(&dlReader) ){ char buf[256]; PLReader plReader; plrInit(&plReader, &dlReader); if( DL_DEFAULT==DL_DOCIDS || plrAtEnd(&plReader) ){ sqlite3_snprintf(sizeof(buf), buf, "[%lld] ", dlrDocid(&dlReader)); dataBufferAppend(&dump, buf, strlen(buf)); }else{ int iColumn = plrColumn(&plReader); sqlite3_snprintf(sizeof(buf), buf, "[%lld %d[", dlrDocid(&dlReader), iColumn); dataBufferAppend(&dump, buf, strlen(buf)); for( ; !plrAtEnd(&plReader); plrStep(&plReader) ){ if( plrColumn(&plReader)!=iColumn ){ iColumn = plrColumn(&plReader); sqlite3_snprintf(sizeof(buf), buf, "] %d[", iColumn); assert( dump.nData>0 ); dump.nData--; /* Overwrite trailing space. */ assert( dump.pData[dump.nData]==' '); dataBufferAppend(&dump, buf, strlen(buf)); } if( DL_DEFAULT==DL_POSITIONS_OFFSETS ){ sqlite3_snprintf(sizeof(buf), buf, "%d,%d,%d ", plrPosition(&plReader), plrStartOffset(&plReader), plrEndOffset(&plReader)); }else if( DL_DEFAULT==DL_POSITIONS ){ sqlite3_snprintf(sizeof(buf), buf, "%d ", plrPosition(&plReader)); }else{ assert( NULL=="Unhandled DL_DEFAULT value"); } dataBufferAppend(&dump, buf, strlen(buf)); } plrDestroy(&plReader); assert( dump.nData>0 ); dump.nData--; /* Overwrite trailing space. */ assert( dump.pData[dump.nData]==' '); dataBufferAppend(&dump, "]] ", 3); } } dlrDestroy(&dlReader); assert( dump.nData>0 ); dump.nData--; /* Overwrite trailing space. */ assert( dump.pData[dump.nData]==' '); dump.pData[dump.nData] = '\0'; assert( dump.nData>0 ); /* Passes ownership of dump's buffer to pContext. */ sqlite3_result_text(pContext, dump.pData, dump.nData, sqlite3_free); dump.pData = NULL; dump.nData = dump.nCapacity = 0; } /* Implements dump_doclist() for use in inspecting the fts2 index from ** tests. TEXT result containing a string representation of the ** doclist for the indicated term. dump_doclist(t, term, level, idx) ** dumps the doclist for term from the segment specified by level, idx ** (in %_segdir), while dump_doclist(t, term) dumps the logical ** doclist for the term across all segments. The per-segment doclist ** can contain deletions, while the full-index doclist will not ** (deletions are omitted). ** ** Result formats differ with the setting of DL_DEFAULTS. Examples: ** ** DL_DOCIDS: [1] [3] [7] ** DL_POSITIONS: [1 0[0 4] 1[17]] [3 1[5]] ** DL_POSITIONS_OFFSETS: [1 0[0,0,3 4,23,26] 1[17,102,105]] [3 1[5,20,23]] ** ** In each case the number after the outer '[' is the docid. In the ** latter two cases, the number before the inner '[' is the column ** associated with the values within. For DL_POSITIONS the numbers ** within are the positions, for DL_POSITIONS_OFFSETS they are the ** position, the start offset, and the end offset. */ static void dumpDoclistFunc( sqlite3_context *pContext, int argc, sqlite3_value **argv ){ fulltext_cursor *pCursor; if( argc!=2 && argc!=4 ){ generateError(pContext, "dump_doclist", "incorrect arguments"); }else if( sqlite3_value_type(argv[0])!=SQLITE_BLOB || sqlite3_value_bytes(argv[0])!=sizeof(pCursor) ){ generateError(pContext, "dump_doclist", "illegal first argument"); }else if( sqlite3_value_text(argv[1])==NULL || sqlite3_value_text(argv[1])[0]=='\0' ){ generateError(pContext, "dump_doclist", "empty second argument"); }else{ const char *pTerm = (const char *)sqlite3_value_text(argv[1]); const int nTerm = strlen(pTerm); fulltext_vtab *v; int rc; DataBuffer doclist; memcpy(&pCursor, sqlite3_value_blob(argv[0]), sizeof(pCursor)); v = cursor_vtab(pCursor); dataBufferInit(&doclist, 0); /* termSelect() yields the same logical doclist that queries are ** run against. */ if( argc==2 ){ rc = termSelect(v, v->nColumn, pTerm, nTerm, 0, DL_DEFAULT, &doclist); }else{ sqlite3_stmt *s = NULL; /* Get our specific segment's information. */ rc = sql_get_statement(v, SEGDIR_SELECT_SEGMENT_STMT, &s); if( rc==SQLITE_OK ){ rc = sqlite3_bind_int(s, 1, sqlite3_value_int(argv[2])); if( rc==SQLITE_OK ){ rc = sqlite3_bind_int(s, 2, sqlite3_value_int(argv[3])); } } if( rc==SQLITE_OK ){ rc = sqlite3_step(s); if( rc==SQLITE_DONE ){ dataBufferDestroy(&doclist); generateError(pContext, "dump_doclist", "segment not found"); return; } /* Found a segment, load it into doclist. */ if( rc==SQLITE_ROW ){ const sqlite_int64 iLeavesEnd = sqlite3_column_int64(s, 1); const char *pData = sqlite3_column_blob(s, 2); const int nData = sqlite3_column_bytes(s, 2); /* loadSegment() is used by termSelect() to load each ** segment's data. */ rc = loadSegment(v, pData, nData, iLeavesEnd, pTerm, nTerm, 0, &doclist); if( rc==SQLITE_OK ){ rc = sqlite3_step(s); /* Should not have more than one matching segment. */ if( rc!=SQLITE_DONE ){ sqlite3_reset(s); dataBufferDestroy(&doclist); generateError(pContext, "dump_doclist", "invalid segdir"); return; } rc = SQLITE_OK; } } } sqlite3_reset(s); } if( rc==SQLITE_OK ){ if( doclist.nData>0 ){ createDoclistResult(pContext, doclist.pData, doclist.nData); }else{ /* TODO(shess): This can happen if the term is not present, or ** if all instances of the term have been deleted and this is ** an all-index dump. It may be interesting to distinguish ** these cases. */ sqlite3_result_text(pContext, "", 0, SQLITE_STATIC); } }else if( rc==SQLITE_NOMEM ){ /* Handle out-of-memory cases specially because if they are ** generated in fts2 code they may not be reflected in the db ** handle. */ /* TODO(shess): Handle this more comprehensively. ** sqlite3ErrStr() has what I need, but is internal. */ generateError(pContext, "dump_doclist", "out of memory"); }else{ generateError(pContext, "dump_doclist", NULL); } dataBufferDestroy(&doclist); } } #endif /* ** This routine implements the xFindFunction method for the FTS2 ** virtual table. */ static int fulltextFindFunction( sqlite3_vtab *pVtab, int nArg, const char *zName, void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), void **ppArg ){ if( strcmp(zName,"snippet")==0 ){ *pxFunc = snippetFunc; return 1; }else if( strcmp(zName,"offsets")==0 ){ *pxFunc = snippetOffsetsFunc; return 1; }else if( strcmp(zName,"optimize")==0 ){ *pxFunc = optimizeFunc; return 1; #ifdef SQLITE_TEST /* NOTE(shess): These functions are present only for testing ** purposes. No particular effort is made to optimize their ** execution or how they build their results. */ }else if( strcmp(zName,"dump_terms")==0 ){ /* fprintf(stderr, "Found dump_terms\n"); */ *pxFunc = dumpTermsFunc; return 1; }else if( strcmp(zName,"dump_doclist")==0 ){ /* fprintf(stderr, "Found dump_doclist\n"); */ *pxFunc = dumpDoclistFunc; return 1; #endif } return 0; } /* ** Rename an fts2 table. */ static int fulltextRename( sqlite3_vtab *pVtab, const char *zName ){ fulltext_vtab *p = (fulltext_vtab *)pVtab; int rc = SQLITE_NOMEM; char *zSql = sqlite3_mprintf( "ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';" "ALTER TABLE %Q.'%q_segments' RENAME TO '%q_segments';" "ALTER TABLE %Q.'%q_segdir' RENAME TO '%q_segdir';" , p->zDb, p->zName, zName , p->zDb, p->zName, zName , p->zDb, p->zName, zName ); if( zSql ){ rc = sqlite3_exec(p->db, zSql, 0, 0, 0); sqlite3_free(zSql); } return rc; } static const sqlite3_module fts2Module = { /* iVersion */ 0, /* xCreate */ fulltextCreate, /* xConnect */ fulltextConnect, /* xBestIndex */ fulltextBestIndex, /* xDisconnect */ fulltextDisconnect, /* xDestroy */ fulltextDestroy, /* xOpen */ fulltextOpen, /* xClose */ fulltextClose, /* xFilter */ fulltextFilter, /* xNext */ fulltextNext, /* xEof */ fulltextEof, /* xColumn */ fulltextColumn, /* xRowid */ fulltextRowid, /* xUpdate */ fulltextUpdate, /* xBegin */ fulltextBegin, /* xSync */ fulltextSync, /* xCommit */ fulltextCommit, /* xRollback */ fulltextRollback, /* xFindFunction */ fulltextFindFunction, /* xRename */ fulltextRename, }; static void hashDestroy(void *p){ fts2Hash *pHash = (fts2Hash *)p; sqlite3Fts2HashClear(pHash); sqlite3_free(pHash); } /* ** The fts2 built-in tokenizers - "simple" and "porter" - are implemented ** in files fts2_tokenizer1.c and fts2_porter.c respectively. The following ** two forward declarations are for functions declared in these files ** used to retrieve the respective implementations. ** ** Calling sqlite3Fts2SimpleTokenizerModule() sets the value pointed ** to by the argument to point a the "simple" tokenizer implementation. ** Function ...PorterTokenizerModule() sets *pModule to point to the ** porter tokenizer/stemmer implementation. */ void sqlite3Fts2SimpleTokenizerModule(sqlite3_tokenizer_module const**ppModule); void sqlite3Fts2PorterTokenizerModule(sqlite3_tokenizer_module const**ppModule); void sqlite3Fts2IcuTokenizerModule(sqlite3_tokenizer_module const**ppModule); int sqlite3Fts2InitHashTable(sqlite3 *, fts2Hash *, const char *); /* ** Initialize the fts2 extension. If this extension is built as part ** of the sqlite library, then this function is called directly by ** SQLite. If fts2 is built as a dynamically loadable extension, this ** function is called by the sqlite3_extension_init() entry point. */ int sqlite3Fts2Init(sqlite3 *db){ int rc = SQLITE_OK; fts2Hash *pHash = 0; const sqlite3_tokenizer_module *pSimple = 0; const sqlite3_tokenizer_module *pPorter = 0; const sqlite3_tokenizer_module *pIcu = 0; sqlite3Fts2SimpleTokenizerModule(&pSimple); sqlite3Fts2PorterTokenizerModule(&pPorter); #ifdef SQLITE_ENABLE_ICU sqlite3Fts2IcuTokenizerModule(&pIcu); #endif /* Allocate and initialize the hash-table used to store tokenizers. */ pHash = sqlite3_malloc(sizeof(fts2Hash)); if( !pHash ){ rc = SQLITE_NOMEM; }else{ sqlite3Fts2HashInit(pHash, FTS2_HASH_STRING, 1); } /* Load the built-in tokenizers into the hash table */ if( rc==SQLITE_OK ){ if( sqlite3Fts2HashInsert(pHash, "simple", 7, (void *)pSimple) || sqlite3Fts2HashInsert(pHash, "porter", 7, (void *)pPorter) || (pIcu && sqlite3Fts2HashInsert(pHash, "icu", 4, (void *)pIcu)) ){ rc = SQLITE_NOMEM; } } /* Create the virtual table wrapper around the hash-table and overload ** the two scalar functions. If this is successful, register the ** module with sqlite. */ if( SQLITE_OK==rc && SQLITE_OK==(rc = sqlite3Fts2InitHashTable(db, pHash, "fts2_tokenizer")) && SQLITE_OK==(rc = sqlite3_overload_function(db, "snippet", -1)) && SQLITE_OK==(rc = sqlite3_overload_function(db, "offsets", -1)) && SQLITE_OK==(rc = sqlite3_overload_function(db, "optimize", -1)) #ifdef SQLITE_TEST && SQLITE_OK==(rc = sqlite3_overload_function(db, "dump_terms", -1)) && SQLITE_OK==(rc = sqlite3_overload_function(db, "dump_doclist", -1)) #endif ){ return sqlite3_create_module_v2( db, "fts2", &fts2Module, (void *)pHash, hashDestroy ); } /* An error has occurred. Delete the hash table and return the error code. */ assert( rc!=SQLITE_OK ); if( pHash ){ sqlite3Fts2HashClear(pHash); sqlite3_free(pHash); } return rc; } #if !SQLITE_CORE #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_fts2_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ SQLITE_EXTENSION_INIT2(pApi) return sqlite3Fts2Init(db); } #endif #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2) */ |
Added ext/fts2/fts2.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 | /* ** 2006 Oct 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 header file is used by programs that want to link against the ** FTS2 library. All it does is declare the sqlite3Fts2Init() interface. */ #include "sqlite3.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ int sqlite3Fts2Init(sqlite3 *db); #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ |
Added ext/fts2/fts2_hash.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 | /* ** 2001 September 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This is the implementation of generic hash-tables used in SQLite. ** We've modified it slightly to serve as a standalone hash table ** implementation for the full-text indexing module. */ /* ** The code in this file is only compiled if: ** ** * The FTS2 module is being built as an extension ** (in which case SQLITE_CORE is not defined), or ** ** * The FTS2 module is being built into the core of ** SQLite (in which case SQLITE_ENABLE_FTS2 is defined). */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2) #include <assert.h> #include <stdlib.h> #include <string.h> #include "sqlite3.h" #include "sqlite3ext.h" SQLITE_EXTENSION_INIT3 #include "fts2_hash.h" /* ** Malloc and Free functions */ static void *fts2HashMalloc(int n){ void *p = sqlite3_malloc(n); if( p ){ memset(p, 0, n); } return p; } static void fts2HashFree(void *p){ sqlite3_free(p); } /* Turn bulk memory into a hash table object by initializing the ** fields of the Hash structure. ** ** "pNew" is a pointer to the hash table that is to be initialized. ** keyClass is one of the constants ** FTS2_HASH_BINARY or FTS2_HASH_STRING. The value of keyClass ** determines what kind of key the hash table will use. "copyKey" is ** true if the hash table should make its own private copy of keys and ** false if it should just use the supplied pointer. */ void sqlite3Fts2HashInit(fts2Hash *pNew, int keyClass, int copyKey){ assert( pNew!=0 ); assert( keyClass>=FTS2_HASH_STRING && keyClass<=FTS2_HASH_BINARY ); pNew->keyClass = keyClass; pNew->copyKey = copyKey; pNew->first = 0; pNew->count = 0; pNew->htsize = 0; pNew->ht = 0; } /* Remove all entries from a hash table. Reclaim all memory. ** Call this routine to delete a hash table or to reset a hash table ** to the empty state. */ void sqlite3Fts2HashClear(fts2Hash *pH){ fts2HashElem *elem; /* For looping over all elements of the table */ assert( pH!=0 ); elem = pH->first; pH->first = 0; fts2HashFree(pH->ht); pH->ht = 0; pH->htsize = 0; while( elem ){ fts2HashElem *next_elem = elem->next; if( pH->copyKey && elem->pKey ){ fts2HashFree(elem->pKey); } fts2HashFree(elem); elem = next_elem; } pH->count = 0; } /* ** Hash and comparison functions when the mode is FTS2_HASH_STRING */ static int strHash(const void *pKey, int nKey){ const char *z = (const char *)pKey; int h = 0; if( nKey<=0 ) nKey = (int) strlen(z); while( nKey > 0 ){ h = (h<<3) ^ h ^ *z++; nKey--; } return h & 0x7fffffff; } static int strCompare(const void *pKey1, int n1, const void *pKey2, int n2){ if( n1!=n2 ) return 1; return strncmp((const char*)pKey1,(const char*)pKey2,n1); } /* ** Hash and comparison functions when the mode is FTS2_HASH_BINARY */ static int binHash(const void *pKey, int nKey){ int h = 0; const char *z = (const char *)pKey; while( nKey-- > 0 ){ h = (h<<3) ^ h ^ *(z++); } return h & 0x7fffffff; } static int binCompare(const void *pKey1, int n1, const void *pKey2, int n2){ if( n1!=n2 ) return 1; return memcmp(pKey1,pKey2,n1); } /* ** Return a pointer to the appropriate hash function given the key class. ** ** The C syntax in this function definition may be unfamilar to some ** programmers, so we provide the following additional explanation: ** ** The name of the function is "hashFunction". The function takes a ** single parameter "keyClass". The return value of hashFunction() ** is a pointer to another function. Specifically, the return value ** of hashFunction() is a pointer to a function that takes two parameters ** with types "const void*" and "int" and returns an "int". */ static int (*hashFunction(int keyClass))(const void*,int){ if( keyClass==FTS2_HASH_STRING ){ return &strHash; }else{ assert( keyClass==FTS2_HASH_BINARY ); return &binHash; } } /* ** Return a pointer to the appropriate hash function given the key class. ** ** For help in interpreted the obscure C code in the function definition, ** see the header comment on the previous function. */ static int (*compareFunction(int keyClass))(const void*,int,const void*,int){ if( keyClass==FTS2_HASH_STRING ){ return &strCompare; }else{ assert( keyClass==FTS2_HASH_BINARY ); return &binCompare; } } /* Link an element into the hash table */ static void insertElement( fts2Hash *pH, /* The complete hash table */ struct _fts2ht *pEntry, /* The entry into which pNew is inserted */ fts2HashElem *pNew /* The element to be inserted */ ){ fts2HashElem *pHead; /* First element already in pEntry */ pHead = pEntry->chain; if( pHead ){ pNew->next = pHead; pNew->prev = pHead->prev; if( pHead->prev ){ pHead->prev->next = pNew; } else { pH->first = pNew; } pHead->prev = pNew; }else{ pNew->next = pH->first; if( pH->first ){ pH->first->prev = pNew; } pNew->prev = 0; pH->first = pNew; } pEntry->count++; pEntry->chain = pNew; } /* Resize the hash table so that it cantains "new_size" buckets. ** "new_size" must be a power of 2. The hash table might fail ** to resize if sqliteMalloc() fails. */ static void rehash(fts2Hash *pH, int new_size){ struct _fts2ht *new_ht; /* The new hash table */ fts2HashElem *elem, *next_elem; /* For looping over existing elements */ int (*xHash)(const void*,int); /* The hash function */ assert( (new_size & (new_size-1))==0 ); new_ht = (struct _fts2ht *)fts2HashMalloc( new_size*sizeof(struct _fts2ht) ); if( new_ht==0 ) return; fts2HashFree(pH->ht); pH->ht = new_ht; pH->htsize = new_size; xHash = hashFunction(pH->keyClass); for(elem=pH->first, pH->first=0; elem; elem = next_elem){ int h = (*xHash)(elem->pKey, elem->nKey) & (new_size-1); next_elem = elem->next; insertElement(pH, &new_ht[h], elem); } } /* This function (for internal use only) locates an element in an ** hash table that matches the given key. The hash for this key has ** already been computed and is passed as the 4th parameter. */ static fts2HashElem *findElementGivenHash( const fts2Hash *pH, /* The pH to be searched */ const void *pKey, /* The key we are searching for */ int nKey, int h /* The hash for this key. */ ){ fts2HashElem *elem; /* Used to loop thru the element list */ int count; /* Number of elements left to test */ int (*xCompare)(const void*,int,const void*,int); /* comparison function */ if( pH->ht ){ struct _fts2ht *pEntry = &pH->ht[h]; elem = pEntry->chain; count = pEntry->count; xCompare = compareFunction(pH->keyClass); while( count-- && elem ){ if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){ return elem; } elem = elem->next; } } return 0; } /* Remove a single entry from the hash table given a pointer to that ** element and a hash on the element's key. */ static void removeElementGivenHash( fts2Hash *pH, /* The pH containing "elem" */ fts2HashElem* elem, /* The element to be removed from the pH */ int h /* Hash value for the element */ ){ struct _fts2ht *pEntry; if( elem->prev ){ elem->prev->next = elem->next; }else{ pH->first = elem->next; } if( elem->next ){ elem->next->prev = elem->prev; } pEntry = &pH->ht[h]; if( pEntry->chain==elem ){ pEntry->chain = elem->next; } pEntry->count--; if( pEntry->count<=0 ){ pEntry->chain = 0; } if( pH->copyKey && elem->pKey ){ fts2HashFree(elem->pKey); } fts2HashFree( elem ); pH->count--; if( pH->count<=0 ){ assert( pH->first==0 ); assert( pH->count==0 ); fts2HashClear(pH); } } /* Attempt to locate an element of the hash table pH with a key ** that matches pKey,nKey. Return the data for this element if it is ** found, or NULL if there is no match. */ void *sqlite3Fts2HashFind(const fts2Hash *pH, const void *pKey, int nKey){ int h; /* A hash on key */ fts2HashElem *elem; /* The element that matches key */ int (*xHash)(const void*,int); /* The hash function */ if( pH==0 || pH->ht==0 ) return 0; xHash = hashFunction(pH->keyClass); assert( xHash!=0 ); h = (*xHash)(pKey,nKey); assert( (pH->htsize & (pH->htsize-1))==0 ); elem = findElementGivenHash(pH,pKey,nKey, h & (pH->htsize-1)); return elem ? elem->data : 0; } /* Insert an element into the hash table pH. The key is pKey,nKey ** and the data is "data". ** ** If no element exists with a matching key, then a new ** element is created. A copy of the key is made if the copyKey ** flag is set. NULL is returned. ** ** If another element already exists with the same key, then the ** new data replaces the old data and the old data is returned. ** The key is not copied in this instance. If a malloc fails, then ** the new data is returned and the hash table is unchanged. ** ** If the "data" parameter to this function is NULL, then the ** element corresponding to "key" is removed from the hash table. */ void *sqlite3Fts2HashInsert( fts2Hash *pH, /* The hash table to insert into */ const void *pKey, /* The key */ int nKey, /* Number of bytes in the key */ void *data /* The data */ ){ int hraw; /* Raw hash value of the key */ int h; /* the hash of the key modulo hash table size */ fts2HashElem *elem; /* Used to loop thru the element list */ fts2HashElem *new_elem; /* New element added to the pH */ int (*xHash)(const void*,int); /* The hash function */ assert( pH!=0 ); xHash = hashFunction(pH->keyClass); assert( xHash!=0 ); hraw = (*xHash)(pKey, nKey); assert( (pH->htsize & (pH->htsize-1))==0 ); h = hraw & (pH->htsize-1); elem = findElementGivenHash(pH,pKey,nKey,h); if( elem ){ void *old_data = elem->data; if( data==0 ){ removeElementGivenHash(pH,elem,h); }else{ elem->data = data; } return old_data; } if( data==0 ) return 0; new_elem = (fts2HashElem*)fts2HashMalloc( sizeof(fts2HashElem) ); if( new_elem==0 ) return data; if( pH->copyKey && pKey!=0 ){ new_elem->pKey = fts2HashMalloc( nKey ); if( new_elem->pKey==0 ){ fts2HashFree(new_elem); return data; } memcpy((void*)new_elem->pKey, pKey, nKey); }else{ new_elem->pKey = (void*)pKey; } new_elem->nKey = nKey; pH->count++; if( pH->htsize==0 ){ rehash(pH,8); if( pH->htsize==0 ){ pH->count = 0; fts2HashFree(new_elem); return data; } } if( pH->count > pH->htsize ){ rehash(pH,pH->htsize*2); } assert( pH->htsize>0 ); assert( (pH->htsize & (pH->htsize-1))==0 ); h = hraw & (pH->htsize-1); insertElement(pH, &pH->ht[h], new_elem); new_elem->data = data; return 0; } #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2) */ |
Added ext/fts2/fts2_hash.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 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 | /* ** 2001 September 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This is the header file for the generic hash-table implementation ** used in SQLite. We've modified it slightly to serve as a standalone ** hash table implementation for the full-text indexing module. ** */ #ifndef _FTS2_HASH_H_ #define _FTS2_HASH_H_ /* Forward declarations of structures. */ typedef struct fts2Hash fts2Hash; typedef struct fts2HashElem fts2HashElem; /* A complete hash table is an instance of the following structure. ** The internals of this structure are intended to be opaque -- client ** code should not attempt to access or modify the fields of this structure ** directly. Change this structure only by using the routines below. ** However, many of the "procedures" and "functions" for modifying and ** accessing this structure are really macros, so we can't really make ** this structure opaque. */ struct fts2Hash { char keyClass; /* HASH_INT, _POINTER, _STRING, _BINARY */ char copyKey; /* True if copy of key made on insert */ int count; /* Number of entries in this table */ fts2HashElem *first; /* The first element of the array */ int htsize; /* Number of buckets in the hash table */ struct _fts2ht { /* the hash table */ int count; /* Number of entries with this hash */ fts2HashElem *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. ** ** Again, this structure is intended to be opaque, but it can't really ** be opaque because it is used by macros. */ struct fts2HashElem { fts2HashElem *next, *prev; /* Next and previous elements in the table */ void *data; /* Data associated with this element */ void *pKey; int nKey; /* Key associated with this element */ }; /* ** There are 2 different modes of operation for a hash table: ** ** FTS2_HASH_STRING pKey points to a string that is nKey bytes long ** (including the null-terminator, if any). Case ** is respected in comparisons. ** ** FTS2_HASH_BINARY pKey points to binary data nKey bytes long. ** memcmp() is used to compare keys. ** ** A copy of the key is made if the copyKey parameter to fts2HashInit is 1. */ #define FTS2_HASH_STRING 1 #define FTS2_HASH_BINARY 2 /* ** Access routines. To delete, insert a NULL pointer. */ void sqlite3Fts2HashInit(fts2Hash*, int keytype, int copyKey); void *sqlite3Fts2HashInsert(fts2Hash*, const void *pKey, int nKey, void *pData); void *sqlite3Fts2HashFind(const fts2Hash*, const void *pKey, int nKey); void sqlite3Fts2HashClear(fts2Hash*); /* ** Shorthand for the functions above */ #define fts2HashInit sqlite3Fts2HashInit #define fts2HashInsert sqlite3Fts2HashInsert #define fts2HashFind sqlite3Fts2HashFind #define fts2HashClear sqlite3Fts2HashClear /* ** Macros for looping over all elements of a hash table. The idiom is ** like this: ** ** fts2Hash h; ** fts2HashElem *p; ** ... ** for(p=fts2HashFirst(&h); p; p=fts2HashNext(p)){ ** SomeStructure *pData = fts2HashData(p); ** // do something with pData ** } */ #define fts2HashFirst(H) ((H)->first) #define fts2HashNext(E) ((E)->next) #define fts2HashData(E) ((E)->data) #define fts2HashKey(E) ((E)->pKey) #define fts2HashKeysize(E) ((E)->nKey) /* ** Number of entries in a hash table */ #define fts2HashCount(H) ((H)->count) #endif /* _FTS2_HASH_H_ */ |
Added ext/fts2/fts2_icu.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 | /* ** 2007 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. ** ************************************************************************* ** This file implements a tokenizer for fts2 based on the ICU library. ** ** $Id: fts2_icu.c,v 1.3 2008/12/18 05:30:26 danielk1977 Exp $ */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2) #ifdef SQLITE_ENABLE_ICU #include <assert.h> #include <string.h> #include "fts2_tokenizer.h" #include <unicode/ubrk.h> #include <unicode/ucol.h> #include <unicode/ustring.h> #include <unicode/utf16.h> typedef struct IcuTokenizer IcuTokenizer; typedef struct IcuCursor IcuCursor; struct IcuTokenizer { sqlite3_tokenizer base; char *zLocale; }; struct IcuCursor { sqlite3_tokenizer_cursor base; UBreakIterator *pIter; /* ICU break-iterator object */ int nChar; /* Number of UChar elements in pInput */ UChar *aChar; /* Copy of input using utf-16 encoding */ int *aOffset; /* Offsets of each character in utf-8 input */ int nBuffer; char *zBuffer; int iToken; }; /* ** Create a new tokenizer instance. */ static int icuCreate( int argc, /* Number of entries in argv[] */ const char * const *argv, /* Tokenizer creation arguments */ sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ ){ IcuTokenizer *p; int n = 0; if( argc>0 ){ n = strlen(argv[0])+1; } p = (IcuTokenizer *)sqlite3_malloc(sizeof(IcuTokenizer)+n); if( !p ){ return SQLITE_NOMEM; } memset(p, 0, sizeof(IcuTokenizer)); if( n ){ p->zLocale = (char *)&p[1]; memcpy(p->zLocale, argv[0], n); } *ppTokenizer = (sqlite3_tokenizer *)p; return SQLITE_OK; } /* ** Destroy a tokenizer */ static int icuDestroy(sqlite3_tokenizer *pTokenizer){ IcuTokenizer *p = (IcuTokenizer *)pTokenizer; sqlite3_free(p); return SQLITE_OK; } /* ** Prepare to begin tokenizing a particular string. The input ** string to be tokenized is pInput[0..nBytes-1]. A cursor ** used to incrementally tokenize this string is returned in ** *ppCursor. */ static int icuOpen( sqlite3_tokenizer *pTokenizer, /* The tokenizer */ const char *zInput, /* Input string */ int nInput, /* Length of zInput in bytes */ sqlite3_tokenizer_cursor **ppCursor /* OUT: Tokenization cursor */ ){ IcuTokenizer *p = (IcuTokenizer *)pTokenizer; IcuCursor *pCsr; const int32_t opt = U_FOLD_CASE_DEFAULT; UErrorCode status = U_ZERO_ERROR; int nChar; UChar32 c; int iInput = 0; int iOut = 0; *ppCursor = 0; if( nInput<0 ){ nInput = strlen(zInput); } nChar = nInput+1; pCsr = (IcuCursor *)sqlite3_malloc( sizeof(IcuCursor) + /* IcuCursor */ ((nChar+3)&~3) * sizeof(UChar) + /* IcuCursor.aChar[] */ (nChar+1) * sizeof(int) /* IcuCursor.aOffset[] */ ); if( !pCsr ){ return SQLITE_NOMEM; } memset(pCsr, 0, sizeof(IcuCursor)); pCsr->aChar = (UChar *)&pCsr[1]; pCsr->aOffset = (int *)&pCsr->aChar[(nChar+3)&~3]; pCsr->aOffset[iOut] = iInput; U8_NEXT(zInput, iInput, nInput, c); while( c>0 ){ int isError = 0; c = u_foldCase(c, opt); U16_APPEND(pCsr->aChar, iOut, nChar, c, isError); if( isError ){ sqlite3_free(pCsr); return SQLITE_ERROR; } pCsr->aOffset[iOut] = iInput; if( iInput<nInput ){ U8_NEXT(zInput, iInput, nInput, c); }else{ c = 0; } } pCsr->pIter = ubrk_open(UBRK_WORD, p->zLocale, pCsr->aChar, iOut, &status); if( !U_SUCCESS(status) ){ sqlite3_free(pCsr); return SQLITE_ERROR; } pCsr->nChar = iOut; ubrk_first(pCsr->pIter); *ppCursor = (sqlite3_tokenizer_cursor *)pCsr; return SQLITE_OK; } /* ** Close a tokenization cursor previously opened by a call to icuOpen(). */ static int icuClose(sqlite3_tokenizer_cursor *pCursor){ IcuCursor *pCsr = (IcuCursor *)pCursor; ubrk_close(pCsr->pIter); sqlite3_free(pCsr->zBuffer); sqlite3_free(pCsr); return SQLITE_OK; } /* ** Extract the next token from a tokenization cursor. */ static int icuNext( sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by simpleOpen */ const char **ppToken, /* OUT: *ppToken is the token text */ int *pnBytes, /* OUT: Number of bytes in token */ int *piStartOffset, /* OUT: Starting offset of token */ int *piEndOffset, /* OUT: Ending offset of token */ int *piPosition /* OUT: Position integer of token */ ){ IcuCursor *pCsr = (IcuCursor *)pCursor; int iStart = 0; int iEnd = 0; int nByte = 0; while( iStart==iEnd ){ UChar32 c; iStart = ubrk_current(pCsr->pIter); iEnd = ubrk_next(pCsr->pIter); if( iEnd==UBRK_DONE ){ return SQLITE_DONE; } while( iStart<iEnd ){ int iWhite = iStart; U8_NEXT(pCsr->aChar, iWhite, pCsr->nChar, c); if( u_isspace(c) ){ iStart = iWhite; }else{ break; } } assert(iStart<=iEnd); } do { UErrorCode status = U_ZERO_ERROR; if( nByte ){ char *zNew = sqlite3_realloc(pCsr->zBuffer, nByte); if( !zNew ){ return SQLITE_NOMEM; } pCsr->zBuffer = zNew; pCsr->nBuffer = nByte; } u_strToUTF8( pCsr->zBuffer, pCsr->nBuffer, &nByte, /* Output vars */ &pCsr->aChar[iStart], iEnd-iStart, /* Input vars */ &status /* Output success/failure */ ); } while( nByte>pCsr->nBuffer ); *ppToken = pCsr->zBuffer; *pnBytes = nByte; *piStartOffset = pCsr->aOffset[iStart]; *piEndOffset = pCsr->aOffset[iEnd]; *piPosition = pCsr->iToken++; return SQLITE_OK; } /* ** The set of routines that implement the simple tokenizer */ static const sqlite3_tokenizer_module icuTokenizerModule = { 0, /* iVersion */ icuCreate, /* xCreate */ icuDestroy, /* xCreate */ icuOpen, /* xOpen */ icuClose, /* xClose */ icuNext, /* xNext */ }; /* ** Set *ppModule to point at the implementation of the ICU tokenizer. */ void sqlite3Fts2IcuTokenizerModule( sqlite3_tokenizer_module const**ppModule ){ *ppModule = &icuTokenizerModule; } #endif /* defined(SQLITE_ENABLE_ICU) */ #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2) */ |
Added ext/fts2/fts2_porter.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 | /* ** 2006 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. ** ************************************************************************* ** Implementation of the full-text-search tokenizer that implements ** a Porter stemmer. */ /* ** The code in this file is only compiled if: ** ** * The FTS2 module is being built as an extension ** (in which case SQLITE_CORE is not defined), or ** ** * The FTS2 module is being built into the core of ** SQLite (in which case SQLITE_ENABLE_FTS2 is defined). */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2) #include <assert.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include "sqlite3.h" #include "sqlite3ext.h" SQLITE_EXTENSION_INIT3 #include "fts2_tokenizer.h" /* ** Class derived from sqlite3_tokenizer */ typedef struct porter_tokenizer { sqlite3_tokenizer base; /* Base class */ } porter_tokenizer; /* ** Class derived from sqlit3_tokenizer_cursor */ typedef struct porter_tokenizer_cursor { sqlite3_tokenizer_cursor base; const char *zInput; /* input we are tokenizing */ int nInput; /* size of the input */ int iOffset; /* current position in zInput */ int iToken; /* index of next token to be returned */ char *zToken; /* storage for current token */ int nAllocated; /* space allocated to zToken buffer */ } porter_tokenizer_cursor; /* Forward declaration */ static const sqlite3_tokenizer_module porterTokenizerModule; /* ** Create a new tokenizer instance. */ static int porterCreate( int argc, const char * const *argv, sqlite3_tokenizer **ppTokenizer ){ porter_tokenizer *t; t = (porter_tokenizer *) sqlite3_malloc(sizeof(*t)); if( t==NULL ) return SQLITE_NOMEM; memset(t, 0, sizeof(*t)); *ppTokenizer = &t->base; return SQLITE_OK; } /* ** Destroy a tokenizer */ static int porterDestroy(sqlite3_tokenizer *pTokenizer){ sqlite3_free(pTokenizer); return SQLITE_OK; } /* ** Prepare to begin tokenizing a particular string. The input ** string to be tokenized is zInput[0..nInput-1]. A cursor ** used to incrementally tokenize this string is returned in ** *ppCursor. */ static int porterOpen( sqlite3_tokenizer *pTokenizer, /* The tokenizer */ const char *zInput, int nInput, /* String to be tokenized */ sqlite3_tokenizer_cursor **ppCursor /* OUT: Tokenization cursor */ ){ porter_tokenizer_cursor *c; c = (porter_tokenizer_cursor *) sqlite3_malloc(sizeof(*c)); if( c==NULL ) return SQLITE_NOMEM; c->zInput = zInput; if( zInput==0 ){ c->nInput = 0; }else if( nInput<0 ){ c->nInput = (int)strlen(zInput); }else{ c->nInput = nInput; } c->iOffset = 0; /* start tokenizing at the beginning */ c->iToken = 0; c->zToken = NULL; /* no space allocated, yet. */ c->nAllocated = 0; *ppCursor = &c->base; return SQLITE_OK; } /* ** Close a tokenization cursor previously opened by a call to ** porterOpen() above. */ static int porterClose(sqlite3_tokenizer_cursor *pCursor){ porter_tokenizer_cursor *c = (porter_tokenizer_cursor *) pCursor; sqlite3_free(c->zToken); sqlite3_free(c); return SQLITE_OK; } /* ** Vowel or consonant */ static const char cType[] = { 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 2, 1 }; /* ** isConsonant() and isVowel() determine if their first character in ** the string they point to is a consonant or a vowel, according ** to Porter ruls. ** ** A consonate is any letter other than 'a', 'e', 'i', 'o', or 'u'. ** 'Y' is a consonant unless it follows another consonant, ** in which case it is a vowel. ** ** In these routine, the letters are in reverse order. So the 'y' rule ** is that 'y' is a consonant unless it is followed by another ** consonent. */ static int isVowel(const char*); static int isConsonant(const char *z){ int j; char x = *z; if( x==0 ) return 0; assert( x>='a' && x<='z' ); j = cType[x-'a']; if( j<2 ) return j; return z[1]==0 || isVowel(z + 1); } static int isVowel(const char *z){ int j; char x = *z; if( x==0 ) return 0; assert( x>='a' && x<='z' ); j = cType[x-'a']; if( j<2 ) return 1-j; return isConsonant(z + 1); } /* ** Let any sequence of one or more vowels be represented by V and let ** C be sequence of one or more consonants. Then every word can be ** represented as: ** ** [C] (VC){m} [V] ** ** In prose: A word is an optional consonant followed by zero or ** vowel-consonant pairs followed by an optional vowel. "m" is the ** number of vowel consonant pairs. This routine computes the value ** of m for the first i bytes of a word. ** ** Return true if the m-value for z is 1 or more. In other words, ** return true if z contains at least one vowel that is followed ** by a consonant. ** ** In this routine z[] is in reverse order. So we are really looking ** for an instance of of a consonant followed by a vowel. */ static int m_gt_0(const char *z){ while( isVowel(z) ){ z++; } if( *z==0 ) return 0; while( isConsonant(z) ){ z++; } return *z!=0; } /* Like mgt0 above except we are looking for a value of m which is ** exactly 1 */ static int m_eq_1(const char *z){ while( isVowel(z) ){ z++; } if( *z==0 ) return 0; while( isConsonant(z) ){ z++; } if( *z==0 ) return 0; while( isVowel(z) ){ z++; } if( *z==0 ) return 1; while( isConsonant(z) ){ z++; } return *z==0; } /* Like mgt0 above except we are looking for a value of m>1 instead ** or m>0 */ static int m_gt_1(const char *z){ while( isVowel(z) ){ z++; } if( *z==0 ) return 0; while( isConsonant(z) ){ z++; } if( *z==0 ) return 0; while( isVowel(z) ){ z++; } if( *z==0 ) return 0; while( isConsonant(z) ){ z++; } return *z!=0; } /* ** Return TRUE if there is a vowel anywhere within z[0..n-1] */ static int hasVowel(const char *z){ while( isConsonant(z) ){ z++; } return *z!=0; } /* ** Return TRUE if the word ends in a double consonant. ** ** The text is reversed here. So we are really looking at ** the first two characters of z[]. */ static int doubleConsonant(const char *z){ return isConsonant(z) && z[0]==z[1] && isConsonant(z+1); } /* ** Return TRUE if the word ends with three letters which ** are consonant-vowel-consonent and where the final consonant ** is not 'w', 'x', or 'y'. ** ** The word is reversed here. So we are really checking the ** first three letters and the first one cannot be in [wxy]. */ static int star_oh(const char *z){ return z[0]!=0 && isConsonant(z) && z[0]!='w' && z[0]!='x' && z[0]!='y' && z[1]!=0 && isVowel(z+1) && z[2]!=0 && isConsonant(z+2); } /* ** If the word ends with zFrom and xCond() is true for the stem ** of the word that preceeds the zFrom ending, then change the ** ending to zTo. ** ** The input word *pz and zFrom are both in reverse order. zTo ** is in normal order. ** ** Return TRUE if zFrom matches. Return FALSE if zFrom does not ** match. Not that TRUE is returned even if xCond() fails and ** no substitution occurs. */ static int stem( char **pz, /* The word being stemmed (Reversed) */ const char *zFrom, /* If the ending matches this... (Reversed) */ const char *zTo, /* ... change the ending to this (not reversed) */ int (*xCond)(const char*) /* Condition that must be true */ ){ char *z = *pz; while( *zFrom && *zFrom==*z ){ z++; zFrom++; } if( *zFrom!=0 ) return 0; if( xCond && !xCond(z) ) return 1; while( *zTo ){ *(--z) = *(zTo++); } *pz = z; return 1; } /* ** This is the fallback stemmer used when the porter stemmer is ** inappropriate. The input word is copied into the output with ** US-ASCII case folding. If the input word is too long (more ** than 20 bytes if it contains no digits or more than 6 bytes if ** it contains digits) then word is truncated to 20 or 6 bytes ** by taking 10 or 3 bytes from the beginning and end. */ static void copy_stemmer(const char *zIn, int nIn, char *zOut, int *pnOut){ int i, mx, j; int hasDigit = 0; for(i=0; i<nIn; i++){ int c = zIn[i]; if( c>='A' && c<='Z' ){ zOut[i] = c - 'A' + 'a'; }else{ if( c>='0' && c<='9' ) hasDigit = 1; zOut[i] = c; } } mx = hasDigit ? 3 : 10; if( nIn>mx*2 ){ for(j=mx, i=nIn-mx; i<nIn; i++, j++){ zOut[j] = zOut[i]; } i = j; } zOut[i] = 0; *pnOut = i; } /* ** Stem the input word zIn[0..nIn-1]. Store the output in zOut. ** zOut is at least big enough to hold nIn bytes. Write the actual ** size of the output word (exclusive of the '\0' terminator) into *pnOut. ** ** Any upper-case characters in the US-ASCII character set ([A-Z]) ** are converted to lower case. Upper-case UTF characters are ** unchanged. ** ** Words that are longer than about 20 bytes are stemmed by retaining ** a few bytes from the beginning and the end of the word. If the ** word contains digits, 3 bytes are taken from the beginning and ** 3 bytes from the end. For long words without digits, 10 bytes ** are taken from each end. US-ASCII case folding still applies. ** ** If the input word contains not digits but does characters not ** in [a-zA-Z] then no stemming is attempted and this routine just ** copies the input into the input into the output with US-ASCII ** case folding. ** ** Stemming never increases the length of the word. So there is ** no chance of overflowing the zOut buffer. */ static void porter_stemmer(const char *zIn, int nIn, char *zOut, int *pnOut){ int i, j, c; char zReverse[28]; char *z, *z2; if( nIn<3 || nIn>=sizeof(zReverse)-7 ){ /* The word is too big or too small for the porter stemmer. ** Fallback to the copy stemmer */ copy_stemmer(zIn, nIn, zOut, pnOut); return; } for(i=0, j=sizeof(zReverse)-6; i<nIn; i++, j--){ c = zIn[i]; if( c>='A' && c<='Z' ){ zReverse[j] = c + 'a' - 'A'; }else if( c>='a' && c<='z' ){ zReverse[j] = c; }else{ /* The use of a character not in [a-zA-Z] means that we fallback ** to the copy stemmer */ copy_stemmer(zIn, nIn, zOut, pnOut); return; } } memset(&zReverse[sizeof(zReverse)-5], 0, 5); z = &zReverse[j+1]; /* Step 1a */ if( z[0]=='s' ){ if( !stem(&z, "sess", "ss", 0) && !stem(&z, "sei", "i", 0) && !stem(&z, "ss", "ss", 0) ){ z++; } } /* Step 1b */ z2 = z; if( stem(&z, "dee", "ee", m_gt_0) ){ /* Do nothing. The work was all in the test */ }else if( (stem(&z, "gni", "", hasVowel) || stem(&z, "de", "", hasVowel)) && z!=z2 ){ if( stem(&z, "ta", "ate", 0) || stem(&z, "lb", "ble", 0) || stem(&z, "zi", "ize", 0) ){ /* Do nothing. The work was all in the test */ }else if( doubleConsonant(z) && (*z!='l' && *z!='s' && *z!='z') ){ z++; }else if( m_eq_1(z) && star_oh(z) ){ *(--z) = 'e'; } } /* Step 1c */ if( z[0]=='y' && hasVowel(z+1) ){ z[0] = 'i'; } /* Step 2 */ switch( z[1] ){ case 'a': stem(&z, "lanoita", "ate", m_gt_0) || stem(&z, "lanoit", "tion", m_gt_0); break; case 'c': stem(&z, "icne", "ence", m_gt_0) || stem(&z, "icna", "ance", m_gt_0); break; case 'e': stem(&z, "rezi", "ize", m_gt_0); break; case 'g': stem(&z, "igol", "log", m_gt_0); break; case 'l': stem(&z, "ilb", "ble", m_gt_0) || stem(&z, "illa", "al", m_gt_0) || stem(&z, "iltne", "ent", m_gt_0) || stem(&z, "ile", "e", m_gt_0) || stem(&z, "ilsuo", "ous", m_gt_0); break; case 'o': stem(&z, "noitazi", "ize", m_gt_0) || stem(&z, "noita", "ate", m_gt_0) || stem(&z, "rota", "ate", m_gt_0); break; case 's': stem(&z, "msila", "al", m_gt_0) || stem(&z, "ssenevi", "ive", m_gt_0) || stem(&z, "ssenluf", "ful", m_gt_0) || stem(&z, "ssensuo", "ous", m_gt_0); break; case 't': stem(&z, "itila", "al", m_gt_0) || stem(&z, "itivi", "ive", m_gt_0) || stem(&z, "itilib", "ble", m_gt_0); break; } /* Step 3 */ switch( z[0] ){ case 'e': stem(&z, "etaci", "ic", m_gt_0) || stem(&z, "evita", "", m_gt_0) || stem(&z, "ezila", "al", m_gt_0); break; case 'i': stem(&z, "itici", "ic", m_gt_0); break; case 'l': stem(&z, "laci", "ic", m_gt_0) || stem(&z, "luf", "", m_gt_0); break; case 's': stem(&z, "ssen", "", m_gt_0); break; } /* Step 4 */ switch( z[1] ){ case 'a': if( z[0]=='l' && m_gt_1(z+2) ){ z += 2; } break; case 'c': if( z[0]=='e' && z[2]=='n' && (z[3]=='a' || z[3]=='e') && m_gt_1(z+4) ){ z += 4; } break; case 'e': if( z[0]=='r' && m_gt_1(z+2) ){ z += 2; } break; case 'i': if( z[0]=='c' && m_gt_1(z+2) ){ z += 2; } break; case 'l': if( z[0]=='e' && z[2]=='b' && (z[3]=='a' || z[3]=='i') && m_gt_1(z+4) ){ z += 4; } break; case 'n': if( z[0]=='t' ){ if( z[2]=='a' ){ if( m_gt_1(z+3) ){ z += 3; } }else if( z[2]=='e' ){ stem(&z, "tneme", "", m_gt_1) || stem(&z, "tnem", "", m_gt_1) || stem(&z, "tne", "", m_gt_1); } } break; case 'o': if( z[0]=='u' ){ if( m_gt_1(z+2) ){ z += 2; } }else if( z[3]=='s' || z[3]=='t' ){ stem(&z, "noi", "", m_gt_1); } break; case 's': if( z[0]=='m' && z[2]=='i' && m_gt_1(z+3) ){ z += 3; } break; case 't': stem(&z, "eta", "", m_gt_1) || stem(&z, "iti", "", m_gt_1); break; case 'u': if( z[0]=='s' && z[2]=='o' && m_gt_1(z+3) ){ z += 3; } break; case 'v': case 'z': if( z[0]=='e' && z[2]=='i' && m_gt_1(z+3) ){ z += 3; } break; } /* Step 5a */ if( z[0]=='e' ){ if( m_gt_1(z+1) ){ z++; }else if( m_eq_1(z+1) && !star_oh(z+1) ){ z++; } } /* Step 5b */ if( m_gt_1(z) && z[0]=='l' && z[1]=='l' ){ z++; } /* z[] is now the stemmed word in reverse order. Flip it back ** around into forward order and return. */ *pnOut = i = strlen(z); zOut[i] = 0; while( *z ){ zOut[--i] = *(z++); } } /* ** Characters that can be part of a token. We assume any character ** whose value is greater than 0x80 (any UTF character) can be ** part of a token. In other words, delimiters all must have ** values of 0x7f or lower. */ static const char porterIdChar[] = { /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */ }; #define isDelim(C) (((ch=C)&0x80)==0 && (ch<0x30 || !porterIdChar[ch-0x30])) /* ** Extract the next token from a tokenization cursor. The cursor must ** have been opened by a prior call to porterOpen(). */ static int porterNext( sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by porterOpen */ const char **pzToken, /* OUT: *pzToken is the token text */ int *pnBytes, /* OUT: Number of bytes in token */ int *piStartOffset, /* OUT: Starting offset of token */ int *piEndOffset, /* OUT: Ending offset of token */ int *piPosition /* OUT: Position integer of token */ ){ porter_tokenizer_cursor *c = (porter_tokenizer_cursor *) pCursor; const char *z = c->zInput; while( c->iOffset<c->nInput ){ int iStartOffset, ch; /* Scan past delimiter characters */ while( c->iOffset<c->nInput && isDelim(z[c->iOffset]) ){ c->iOffset++; } /* Count non-delimiter characters. */ iStartOffset = c->iOffset; while( c->iOffset<c->nInput && !isDelim(z[c->iOffset]) ){ c->iOffset++; } if( c->iOffset>iStartOffset ){ int n = c->iOffset-iStartOffset; if( n>c->nAllocated ){ c->nAllocated = n+20; c->zToken = sqlite3_realloc(c->zToken, c->nAllocated); if( c->zToken==NULL ) return SQLITE_NOMEM; } porter_stemmer(&z[iStartOffset], n, c->zToken, pnBytes); *pzToken = c->zToken; *piStartOffset = iStartOffset; *piEndOffset = c->iOffset; *piPosition = c->iToken++; return SQLITE_OK; } } return SQLITE_DONE; } /* ** The set of routines that implement the porter-stemmer tokenizer */ static const sqlite3_tokenizer_module porterTokenizerModule = { 0, porterCreate, porterDestroy, porterOpen, porterClose, porterNext, }; /* ** Allocate a new porter tokenizer. Return a pointer to the new ** tokenizer in *ppModule */ void sqlite3Fts2PorterTokenizerModule( sqlite3_tokenizer_module const**ppModule ){ *ppModule = &porterTokenizerModule; } #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2) */ |
Added ext/fts2/fts2_tokenizer.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 | /* ** 2007 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. ** ****************************************************************************** ** ** This is part of an SQLite module implementing full-text search. ** This particular file implements the generic tokenizer interface. */ /* ** The code in this file is only compiled if: ** ** * The FTS2 module is being built as an extension ** (in which case SQLITE_CORE is not defined), or ** ** * The FTS2 module is being built into the core of ** SQLite (in which case SQLITE_ENABLE_FTS2 is defined). */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2) #include "sqlite3.h" #include "sqlite3ext.h" SQLITE_EXTENSION_INIT3 #include "fts2_hash.h" #include "fts2_tokenizer.h" #include <assert.h> /* ** Implementation of the SQL scalar function for accessing the underlying ** hash table. This function may be called as follows: ** ** SELECT <function-name>(<key-name>); ** SELECT <function-name>(<key-name>, <pointer>); ** ** where <function-name> is the name passed as the second argument ** to the sqlite3Fts2InitHashTable() function (e.g. 'fts2_tokenizer'). ** ** If the <pointer> argument is specified, it must be a blob value ** containing a pointer to be stored as the hash data corresponding ** to the string <key-name>. If <pointer> is not specified, then ** the string <key-name> must already exist in the has table. Otherwise, ** an error is returned. ** ** Whether or not the <pointer> argument is specified, the value returned ** is a blob containing the pointer stored as the hash data corresponding ** to string <key-name> (after the hash-table is updated, if applicable). */ static void scalarFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ fts2Hash *pHash; void *pPtr = 0; const unsigned char *zName; int nName; assert( argc==1 || argc==2 ); pHash = (fts2Hash *)sqlite3_user_data(context); zName = sqlite3_value_text(argv[0]); nName = sqlite3_value_bytes(argv[0])+1; if( argc==2 ){ void *pOld; int n = sqlite3_value_bytes(argv[1]); if( n!=sizeof(pPtr) ){ sqlite3_result_error(context, "argument type mismatch", -1); return; } pPtr = *(void **)sqlite3_value_blob(argv[1]); pOld = sqlite3Fts2HashInsert(pHash, (void *)zName, nName, pPtr); if( pOld==pPtr ){ sqlite3_result_error(context, "out of memory", -1); return; } }else{ pPtr = sqlite3Fts2HashFind(pHash, zName, nName); if( !pPtr ){ char *zErr = sqlite3_mprintf("unknown tokenizer: %s", zName); sqlite3_result_error(context, zErr, -1); sqlite3_free(zErr); return; } } sqlite3_result_blob(context, (void *)&pPtr, sizeof(pPtr), SQLITE_TRANSIENT); } #ifdef SQLITE_TEST #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif #include <string.h> /* ** Implementation of a special SQL scalar function for testing tokenizers ** designed to be used in concert with the Tcl testing framework. This ** function must be called with two arguments: ** ** SELECT <function-name>(<key-name>, <input-string>); ** SELECT <function-name>(<key-name>, <pointer>); ** ** where <function-name> is the name passed as the second argument ** to the sqlite3Fts2InitHashTable() function (e.g. 'fts2_tokenizer') ** concatenated with the string '_test' (e.g. 'fts2_tokenizer_test'). ** ** The return value is a string that may be interpreted as a Tcl ** list. For each token in the <input-string>, three elements are ** added to the returned list. The first is the token position, the ** second is the token text (folded, stemmed, etc.) and the third is the ** substring of <input-string> associated with the token. For example, ** using the built-in "simple" tokenizer: ** ** SELECT fts_tokenizer_test('simple', 'I don't see how'); ** ** will return the string: ** ** "{0 i I 1 dont don't 2 see see 3 how how}" ** */ static void testFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ fts2Hash *pHash; sqlite3_tokenizer_module *p; sqlite3_tokenizer *pTokenizer = 0; sqlite3_tokenizer_cursor *pCsr = 0; const char *zErr = 0; const char *zName; int nName; const char *zInput; int nInput; const char *zArg = 0; const char *zToken; int nToken; int iStart; int iEnd; int iPos; Tcl_Obj *pRet; assert( argc==2 || argc==3 ); nName = sqlite3_value_bytes(argv[0]); zName = (const char *)sqlite3_value_text(argv[0]); nInput = sqlite3_value_bytes(argv[argc-1]); zInput = (const char *)sqlite3_value_text(argv[argc-1]); if( argc==3 ){ zArg = (const char *)sqlite3_value_text(argv[1]); } pHash = (fts2Hash *)sqlite3_user_data(context); p = (sqlite3_tokenizer_module *)sqlite3Fts2HashFind(pHash, zName, nName+1); if( !p ){ char *zErr = sqlite3_mprintf("unknown tokenizer: %s", zName); sqlite3_result_error(context, zErr, -1); sqlite3_free(zErr); return; } pRet = Tcl_NewObj(); Tcl_IncrRefCount(pRet); if( SQLITE_OK!=p->xCreate(zArg ? 1 : 0, &zArg, &pTokenizer) ){ zErr = "error in xCreate()"; goto finish; } pTokenizer->pModule = p; if( SQLITE_OK!=p->xOpen(pTokenizer, zInput, nInput, &pCsr) ){ zErr = "error in xOpen()"; goto finish; } pCsr->pTokenizer = pTokenizer; while( SQLITE_OK==p->xNext(pCsr, &zToken, &nToken, &iStart, &iEnd, &iPos) ){ Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(iPos)); Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zToken, nToken)); zToken = &zInput[iStart]; nToken = iEnd-iStart; Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zToken, nToken)); } if( SQLITE_OK!=p->xClose(pCsr) ){ zErr = "error in xClose()"; goto finish; } if( SQLITE_OK!=p->xDestroy(pTokenizer) ){ zErr = "error in xDestroy()"; goto finish; } finish: if( zErr ){ sqlite3_result_error(context, zErr, -1); }else{ sqlite3_result_text(context, Tcl_GetString(pRet), -1, SQLITE_TRANSIENT); } Tcl_DecrRefCount(pRet); } static int registerTokenizer( sqlite3 *db, char *zName, const sqlite3_tokenizer_module *p ){ int rc; sqlite3_stmt *pStmt; const char zSql[] = "SELECT fts2_tokenizer(?, ?)"; rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); if( rc!=SQLITE_OK ){ return rc; } sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC); sqlite3_bind_blob(pStmt, 2, &p, sizeof(p), SQLITE_STATIC); sqlite3_step(pStmt); return sqlite3_finalize(pStmt); } static int queryFts2Tokenizer( sqlite3 *db, char *zName, const sqlite3_tokenizer_module **pp ){ int rc; sqlite3_stmt *pStmt; const char zSql[] = "SELECT fts2_tokenizer(?)"; *pp = 0; 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 ){ memcpy(pp, sqlite3_column_blob(pStmt, 0), sizeof(*pp)); } } return sqlite3_finalize(pStmt); } void sqlite3Fts2SimpleTokenizerModule(sqlite3_tokenizer_module const**ppModule); /* ** Implementation of the scalar function fts2_tokenizer_internal_test(). ** This function is used for testing only, it is not included in the ** build unless SQLITE_TEST is defined. ** ** The purpose of this is to test that the fts2_tokenizer() function ** can be used as designed by the C-code in the queryFts2Tokenizer and ** registerTokenizer() functions above. These two functions are repeated ** in the README.tokenizer file as an example, so it is important to ** test them. ** ** To run the tests, evaluate the fts2_tokenizer_internal_test() scalar ** function with no arguments. An assert() will fail if a problem is ** detected. i.e.: ** ** SELECT fts2_tokenizer_internal_test(); ** */ static void intTestFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ int rc; const sqlite3_tokenizer_module *p1; const sqlite3_tokenizer_module *p2; sqlite3 *db = (sqlite3 *)sqlite3_user_data(context); /* Test the query function */ sqlite3Fts2SimpleTokenizerModule(&p1); rc = queryFts2Tokenizer(db, "simple", &p2); assert( rc==SQLITE_OK ); assert( p1==p2 ); rc = queryFts2Tokenizer(db, "nosuchtokenizer", &p2); assert( rc==SQLITE_ERROR ); assert( p2==0 ); assert( 0==strcmp(sqlite3_errmsg(db), "unknown tokenizer: nosuchtokenizer") ); /* Test the storage function */ rc = registerTokenizer(db, "nosuchtokenizer", p1); assert( rc==SQLITE_OK ); rc = queryFts2Tokenizer(db, "nosuchtokenizer", &p2); assert( rc==SQLITE_OK ); assert( p2==p1 ); sqlite3_result_text(context, "ok", -1, SQLITE_STATIC); } #endif /* ** Set up SQL objects in database db used to access the contents of ** the hash table pointed to by argument pHash. The hash table must ** been initialized to use string keys, and to take a private copy ** of the key when a value is inserted. i.e. by a call similar to: ** ** sqlite3Fts2HashInit(pHash, FTS2_HASH_STRING, 1); ** ** This function adds a scalar function (see header comment above ** scalarFunc() in this file for details) and, if ENABLE_TABLE is ** defined at compilation time, a temporary virtual table (see header ** comment above struct HashTableVtab) to the database schema. Both ** provide read/write access to the contents of *pHash. ** ** The third argument to this function, zName, is used as the name ** of both the scalar and, if created, the virtual table. */ int sqlite3Fts2InitHashTable( sqlite3 *db, fts2Hash *pHash, const char *zName ){ int rc = SQLITE_OK; void *p = (void *)pHash; const int any = SQLITE_ANY; char *zTest = 0; char *zTest2 = 0; #ifdef SQLITE_TEST void *pdb = (void *)db; zTest = sqlite3_mprintf("%s_test", zName); zTest2 = sqlite3_mprintf("%s_internal_test", zName); if( !zTest || !zTest2 ){ rc = SQLITE_NOMEM; } #endif if( rc!=SQLITE_OK || (rc = sqlite3_create_function(db, zName, 1, any, p, scalarFunc, 0, 0)) || (rc = sqlite3_create_function(db, zName, 2, any, p, scalarFunc, 0, 0)) #ifdef SQLITE_TEST || (rc = sqlite3_create_function(db, zTest, 2, any, p, testFunc, 0, 0)) || (rc = sqlite3_create_function(db, zTest, 3, any, p, testFunc, 0, 0)) || (rc = sqlite3_create_function(db, zTest2, 0, any, pdb, intTestFunc, 0, 0)) #endif ); sqlite3_free(zTest); sqlite3_free(zTest2); return rc; } #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2) */ |
Added ext/fts2/fts2_tokenizer.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 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 | /* ** 2006 July 10 ** ** The author disclaims copyright to this source code. ** ************************************************************************* ** Defines the interface to tokenizers used by fulltext-search. There ** are three basic components: ** ** sqlite3_tokenizer_module is a singleton defining the tokenizer ** interface functions. This is essentially the class structure for ** tokenizers. ** ** sqlite3_tokenizer is used to define a particular tokenizer, perhaps ** including customization information defined at creation time. ** ** sqlite3_tokenizer_cursor is generated by a tokenizer to generate ** tokens from a particular input. */ #ifndef _FTS2_TOKENIZER_H_ #define _FTS2_TOKENIZER_H_ /* TODO(shess) Only used for SQLITE_OK and SQLITE_DONE at this time. ** If tokenizers are to be allowed to call sqlite3_*() functions, then ** we will need a way to register the API consistently. */ #include "sqlite3.h" /* ** Structures used by the tokenizer interface. When a new tokenizer ** implementation is registered, the caller provides a pointer to ** an sqlite3_tokenizer_module containing pointers to the callback ** functions that make up an implementation. ** ** When an fts2 table is created, it passes any arguments passed to ** the tokenizer clause of the CREATE VIRTUAL TABLE statement to the ** sqlite3_tokenizer_module.xCreate() function of the requested tokenizer ** implementation. The xCreate() function in turn returns an ** sqlite3_tokenizer structure representing the specific tokenizer to ** be used for the fts2 table (customized by the tokenizer clause arguments). ** ** To tokenize an input buffer, the sqlite3_tokenizer_module.xOpen() ** method is called. It returns an sqlite3_tokenizer_cursor object ** that may be used to tokenize a specific input buffer based on ** the tokenization rules supplied by a specific sqlite3_tokenizer ** object. */ typedef struct sqlite3_tokenizer_module sqlite3_tokenizer_module; typedef struct sqlite3_tokenizer sqlite3_tokenizer; typedef struct sqlite3_tokenizer_cursor sqlite3_tokenizer_cursor; struct sqlite3_tokenizer_module { /* ** Structure version. Should always be set to 0. */ int iVersion; /* ** Create a new tokenizer. The values in the argv[] array are the ** arguments passed to the "tokenizer" clause of the CREATE VIRTUAL ** TABLE statement that created the fts2 table. For example, if ** the following SQL is executed: ** ** CREATE .. USING fts2( ... , tokenizer <tokenizer-name> arg1 arg2) ** ** then argc is set to 2, and the argv[] array contains pointers ** to the strings "arg1" and "arg2". ** ** This method should return either SQLITE_OK (0), or an SQLite error ** code. If SQLITE_OK is returned, then *ppTokenizer should be set ** to point at the newly created tokenizer structure. The generic ** sqlite3_tokenizer.pModule variable should not be initialized by ** this callback. The caller will do so. */ int (*xCreate)( int argc, /* Size of argv array */ const char *const*argv, /* Tokenizer argument strings */ sqlite3_tokenizer **ppTokenizer /* OUT: Created tokenizer */ ); /* ** Destroy an existing tokenizer. The fts2 module calls this method ** exactly once for each successful call to xCreate(). */ int (*xDestroy)(sqlite3_tokenizer *pTokenizer); /* ** Create a tokenizer cursor to tokenize an input buffer. The caller ** is responsible for ensuring that the input buffer remains valid ** until the cursor is closed (using the xClose() method). */ int (*xOpen)( sqlite3_tokenizer *pTokenizer, /* Tokenizer object */ const char *pInput, int nBytes, /* Input buffer */ sqlite3_tokenizer_cursor **ppCursor /* OUT: Created tokenizer cursor */ ); /* ** Destroy an existing tokenizer cursor. The fts2 module calls this ** method exactly once for each successful call to xOpen(). */ int (*xClose)(sqlite3_tokenizer_cursor *pCursor); /* ** Retrieve the next token from the tokenizer cursor pCursor. This ** method should either return SQLITE_OK and set the values of the ** "OUT" variables identified below, or SQLITE_DONE to indicate that ** the end of the buffer has been reached, or an SQLite error code. ** ** *ppToken should be set to point at a buffer containing the ** normalized version of the token (i.e. after any case-folding and/or ** stemming has been performed). *pnBytes should be set to the length ** of this buffer in bytes. The input text that generated the token is ** identified by the byte offsets returned in *piStartOffset and ** *piEndOffset. ** ** The buffer *ppToken is set to point at is managed by the tokenizer ** implementation. It is only required to be valid until the next call ** to xNext() or xClose(). */ /* TODO(shess) current implementation requires pInput to be ** nul-terminated. This should either be fixed, or pInput/nBytes ** should be converted to zInput. */ int (*xNext)( sqlite3_tokenizer_cursor *pCursor, /* Tokenizer cursor */ const char **ppToken, int *pnBytes, /* OUT: Normalized text for token */ int *piStartOffset, /* OUT: Byte offset of token in input buffer */ int *piEndOffset, /* OUT: Byte offset of end of token in input buffer */ int *piPosition /* OUT: Number of tokens returned before this one */ ); }; struct sqlite3_tokenizer { const sqlite3_tokenizer_module *pModule; /* The module for this tokenizer */ /* Tokenizer implementations will typically add additional fields */ }; struct sqlite3_tokenizer_cursor { sqlite3_tokenizer *pTokenizer; /* Tokenizer for this cursor. */ /* Tokenizer implementations will typically add additional fields */ }; #endif /* _FTS2_TOKENIZER_H_ */ |
Added ext/fts2/fts2_tokenizer1.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 | /* ** 2006 Oct 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. ** ****************************************************************************** ** ** Implementation of the "simple" full-text-search tokenizer. */ /* ** The code in this file is only compiled if: ** ** * The FTS2 module is being built as an extension ** (in which case SQLITE_CORE is not defined), or ** ** * The FTS2 module is being built into the core of ** SQLite (in which case SQLITE_ENABLE_FTS2 is defined). */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2) #include <assert.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include "sqlite3.h" #include "sqlite3ext.h" SQLITE_EXTENSION_INIT3 #include "fts2_tokenizer.h" typedef struct simple_tokenizer { sqlite3_tokenizer base; char delim[128]; /* flag ASCII delimiters */ } simple_tokenizer; typedef struct simple_tokenizer_cursor { sqlite3_tokenizer_cursor base; const char *pInput; /* input we are tokenizing */ int nBytes; /* size of the input */ int iOffset; /* current position in pInput */ int iToken; /* index of next token to be returned */ char *pToken; /* storage for current token */ int nTokenAllocated; /* space allocated to zToken buffer */ } simple_tokenizer_cursor; /* Forward declaration */ static const sqlite3_tokenizer_module simpleTokenizerModule; static int simpleDelim(simple_tokenizer *t, unsigned char c){ return c<0x80 && t->delim[c]; } /* ** Create a new tokenizer instance. */ static int simpleCreate( int argc, const char * const *argv, sqlite3_tokenizer **ppTokenizer ){ simple_tokenizer *t; t = (simple_tokenizer *) sqlite3_malloc(sizeof(*t)); if( t==NULL ) return SQLITE_NOMEM; memset(t, 0, sizeof(*t)); /* TODO(shess) Delimiters need to remain the same from run to run, ** else we need to reindex. One solution would be a meta-table to ** track such information in the database, then we'd only want this ** information on the initial create. */ if( argc>1 ){ int i, n = strlen(argv[1]); for(i=0; i<n; i++){ unsigned char ch = argv[1][i]; /* We explicitly don't support UTF-8 delimiters for now. */ if( ch>=0x80 ){ sqlite3_free(t); return SQLITE_ERROR; } t->delim[ch] = 1; } } else { /* Mark non-alphanumeric ASCII characters as delimiters */ int i; for(i=1; i<0x80; i++){ t->delim[i] = !((i>='0' && i<='9') || (i>='A' && i<='Z') || (i>='a' && i<='z')); } } *ppTokenizer = &t->base; return SQLITE_OK; } /* ** Destroy a tokenizer */ static int simpleDestroy(sqlite3_tokenizer *pTokenizer){ sqlite3_free(pTokenizer); return SQLITE_OK; } /* ** Prepare to begin tokenizing a particular string. The input ** string to be tokenized is pInput[0..nBytes-1]. A cursor ** used to incrementally tokenize this string is returned in ** *ppCursor. */ static int simpleOpen( sqlite3_tokenizer *pTokenizer, /* The tokenizer */ const char *pInput, int nBytes, /* String to be tokenized */ sqlite3_tokenizer_cursor **ppCursor /* OUT: Tokenization cursor */ ){ simple_tokenizer_cursor *c; c = (simple_tokenizer_cursor *) sqlite3_malloc(sizeof(*c)); if( c==NULL ) return SQLITE_NOMEM; c->pInput = pInput; if( pInput==0 ){ c->nBytes = 0; }else if( nBytes<0 ){ c->nBytes = (int)strlen(pInput); }else{ c->nBytes = nBytes; } c->iOffset = 0; /* start tokenizing at the beginning */ c->iToken = 0; c->pToken = NULL; /* no space allocated, yet. */ c->nTokenAllocated = 0; *ppCursor = &c->base; return SQLITE_OK; } /* ** Close a tokenization cursor previously opened by a call to ** simpleOpen() above. */ static int simpleClose(sqlite3_tokenizer_cursor *pCursor){ simple_tokenizer_cursor *c = (simple_tokenizer_cursor *) pCursor; sqlite3_free(c->pToken); sqlite3_free(c); return SQLITE_OK; } /* ** Extract the next token from a tokenization cursor. The cursor must ** have been opened by a prior call to simpleOpen(). */ static int simpleNext( sqlite3_tokenizer_cursor *pCursor, /* Cursor returned by simpleOpen */ const char **ppToken, /* OUT: *ppToken is the token text */ int *pnBytes, /* OUT: Number of bytes in token */ int *piStartOffset, /* OUT: Starting offset of token */ int *piEndOffset, /* OUT: Ending offset of token */ int *piPosition /* OUT: Position integer of token */ ){ simple_tokenizer_cursor *c = (simple_tokenizer_cursor *) pCursor; simple_tokenizer *t = (simple_tokenizer *) pCursor->pTokenizer; unsigned char *p = (unsigned char *)c->pInput; while( c->iOffset<c->nBytes ){ int iStartOffset; /* Scan past delimiter characters */ while( c->iOffset<c->nBytes && simpleDelim(t, p[c->iOffset]) ){ c->iOffset++; } /* Count non-delimiter characters. */ iStartOffset = c->iOffset; while( c->iOffset<c->nBytes && !simpleDelim(t, p[c->iOffset]) ){ c->iOffset++; } if( c->iOffset>iStartOffset ){ int i, n = c->iOffset-iStartOffset; if( n>c->nTokenAllocated ){ c->nTokenAllocated = n+20; c->pToken = sqlite3_realloc(c->pToken, c->nTokenAllocated); if( c->pToken==NULL ) return SQLITE_NOMEM; } for(i=0; i<n; i++){ /* TODO(shess) This needs expansion to handle UTF-8 ** case-insensitivity. */ unsigned char ch = p[iStartOffset+i]; c->pToken[i] = (ch>='A' && ch<='Z') ? (ch - 'A' + 'a') : ch; } *ppToken = c->pToken; *pnBytes = n; *piStartOffset = iStartOffset; *piEndOffset = c->iOffset; *piPosition = c->iToken++; return SQLITE_OK; } } return SQLITE_DONE; } /* ** The set of routines that implement the simple tokenizer */ static const sqlite3_tokenizer_module simpleTokenizerModule = { 0, simpleCreate, simpleDestroy, simpleOpen, simpleClose, simpleNext, }; /* ** Allocate a new simple tokenizer. Return a pointer to the new ** tokenizer in *ppModule */ void sqlite3Fts2SimpleTokenizerModule( sqlite3_tokenizer_module const**ppModule ){ *ppModule = &simpleTokenizerModule; } #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS2) */ |
Added ext/fts2/mkfts2amal.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 | #!/usr/bin/tclsh # # This script builds a single C code file holding all of FTS2 code. # The name of the output file is fts2amal.c. To build this file, # first do: # # make target_source # # The make target above moves all of the source code files into # a subdirectory named "tsrc". (This script expects to find the files # there and will not work if they are not found.) # # After the "tsrc" directory has been created and populated, run # this script: # # tclsh mkfts2amal.tcl # # The amalgamated FTS2 code will be written into fts2amal.c # # Open the output file and write a header comment at the beginning # of the file. # set out [open fts2amal.c w] set today [clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S UTC" -gmt 1] puts $out [subst \ {/****************************************************************************** ** This file is an amalgamation of separate C source files from the SQLite ** Full Text Search extension 2 (fts2). By combining all the individual C ** code files into this single large file, the entire code can be compiled ** as a one translation unit. This allows many compilers to do optimizations ** that would not be possible if the files were compiled separately. It also ** makes the code easier to import into other projects. ** ** This amalgamation was generated on $today. */}] # These are the header files used by FTS2. 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 { fts2.h fts2_hash.h fts2_tokenizer.h sqlite3.h sqlite3ext.h } { set available_hdr($hdr) 1 } # 78 stars used for comment formatting. set s78 \ {*****************************************************************************} # Insert a comment into the code # proc section_comment {text} { global out s78 set n [string length $text] set nstar [expr {60 - $n}] set stars [string range $s78 0 $nstar] puts $out "/************** $text $stars/" } # Read the source file named $filename and write it into the # sqlite3.c output file. If any #include statements are seen, # process them approprately. # proc copy_file {filename} { global seen_hdr available_hdr out set tail [file tail $filename] section_comment "Begin file $tail" set in [open $filename r] while {![eof $in]} { set line [gets $in] if {[regexp {^#\s*include\s+["<]([^">]+)[">]} $line all hdr]} { if {[info exists available_hdr($hdr)]} { if {$available_hdr($hdr)} { section_comment "Include $hdr in the middle of $tail" copy_file tsrc/$hdr section_comment "Continuing where we left off in $tail" } } elseif {![info exists seen_hdr($hdr)]} { set seen_hdr($hdr) 1 puts $out $line } } elseif {[regexp {^#ifdef __cplusplus} $line]} { puts $out "#if 0" } elseif {[regexp {^#line} $line]} { # Skip #line directives. } else { puts $out $line } } close $in section_comment "End of $tail" } # Process the source files. Process files containing commonly # used subroutines first in order to help the compiler find # inlining opportunities. # foreach file { fts2.c fts2_hash.c fts2_porter.c fts2_tokenizer.c fts2_tokenizer1.c fts2_icu.c } { copy_file tsrc/$file } close $out |
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 177 178 | 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/fts3.c.
︙ | ︙ | |||
304 305 306 307 308 309 310 | #include "fts3.h" #ifndef SQLITE_CORE # include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #endif | < < < < < < > > > > > > > < < | 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 | #include "fts3.h" #ifndef SQLITE_CORE # include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #endif static int fts3EvalNext(Fts3Cursor *pCsr); static int fts3EvalStart(Fts3Cursor *pCsr); static int fts3TermSegReaderCursor( Fts3Cursor *, const char *, int, int, Fts3MultiSegReader **); #ifndef SQLITE_AMALGAMATION # if defined(SQLITE_DEBUG) int sqlite3Fts3Always(int b) { assert( b ); return b; } int sqlite3Fts3Never(int b) { assert( !b ); return b; } # endif #endif /* ** 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. */ int sqlite3_fts3_may_be_corrupt = 1; /* ** 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){ |
︙ | ︙ | |||
959 960 961 962 963 964 965 | if( p->zLanguageid ){ fts3Appendf(pRc, &zRet, ", ?"); } sqlite3_free(zFree); return zRet; } | < < < < < < < < < < < < < < < < > | > | | | > | < < > | | 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 | 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; const char *p; /* Iterator pointer */ int nInt = 0; /* Output value */ for(p=*pp; p[0]>='0' && p[0]<='9'; p++){ nInt = nInt * 10 + (p[0] - '0'); if( nInt>MAX_NPREFIX ){ nInt = 0; break; } } if( p==*pp ) return SQLITE_ERROR; *pnOut = nInt; *pp = p; 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 |
︙ | ︙ | |||
1174 1175 1176 1177 1178 1179 1180 | sqlite3 *db, /* The SQLite database connection */ void *pAux, /* Hash table containing tokenizers */ int argc, /* Number of elements in argv array */ const char * const *argv, /* xCreate/xConnect argument array */ sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */ char **pzErr /* Write any error message here */ ){ | | | 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 | sqlite3 *db, /* The SQLite database connection */ void *pAux, /* Hash table containing tokenizers */ int argc, /* Number of elements in argv array */ const char * const *argv, /* xCreate/xConnect argument array */ 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 */ |
︙ | ︙ | |||
1894 1895 1896 1897 1898 1899 1900 | ){ 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 */ | | < | | > < < < < | 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 | ){ 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 */ sqlite3_int64 iChild; /* Block id of child node to descend to */ /* 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 += sqlite3Fts3GetVarint(zCsr, &iChild); zCsr += sqlite3Fts3GetVarint(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 */ int nBuffer; /* Total term size */ /* 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); } isFirstTerm = 0; zCsr += fts3GetVarint32(zCsr, &nSuffix); assert( nPrefix>=0 && nSuffix>=0 ); if( nPrefix>zCsr-zNode || nSuffix>zEnd-zCsr || nSuffix==0 ){ rc = FTS_CORRUPT_VTAB; |
︙ | ︙ | |||
1964 1965 1966 1967 1968 1969 1970 | ** 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)) ){ | | | | | | 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 | ** 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 = iChild; piFirst = 0; } if( piLast && cmp<0 ){ *piLast = iChild; piLast = 0; } iChild++; }; if( piFirst ) *piFirst = iChild; if( piLast ) *piLast = iChild; finish_scan: sqlite3_free(zBuffer); return rc; } |
︙ | ︙ | |||
2065 2066 2067 2068 2069 2070 2071 | ** 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 */ ){ | | | 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 | ** 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( 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 |
︙ | ︙ | |||
2182 2183 2184 2185 2186 2187 2188 | ** 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 ){ | < | < | 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 | ** 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 ){ fts3GetDeltaVarint(pp, pi); *pi -= 2; }else{ *pi = POSITION_LIST_END; } } /* |
︙ | ︙ | |||
2264 2265 2266 2267 2268 2269 2270 | ** 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); | < < < | 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 | ** 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 ){ |
︙ | ︙ | |||
2335 2336 2337 2338 2339 2340 2341 | char *p2 = *pp2; int iCol1 = 0; int iCol2 = 0; /* Never set both isSaveLeft and isExact for the same invocation. */ assert( isSaveLeft==0 || isExact==0 ); | | | 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 | 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( p!=0 && *p1!=0 && *p2!=0 ); if( *p1==POS_COLUMN ){ p1++; p1 += fts3GetVarint32(p1, &iCol1); } if( *p2==POS_COLUMN ){ p2++; p2 += fts3GetVarint32(p2, &iCol2); |
︙ | ︙ | |||
2884 2885 2886 2887 2888 2889 2890 | ** not true for order=DESC. For example, a doclist containing (1, -1) ** may be smaller than (-1), as in the first example the -1 may be stored ** as a single-byte delta, whereas in the second it must be stored as a ** FTS3_VARINT_MAX byte varint. ** ** Similar padding is added in the fts3DoclistOrMerge() function. */ | | | 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 | ** not true for order=DESC. For example, a doclist containing (1, -1) ** may be smaller than (-1), as in the first example the -1 may be stored ** as a single-byte delta, whereas in the second it must be stored as a ** FTS3_VARINT_MAX byte varint. ** ** 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; } |
︙ | ︙ | |||
3476 3477 3478 3479 3480 3481 3482 | sqlite3_result_int64(pCtx, pCsr->iLangid); break; }else if( p->zLanguageid==0 ){ sqlite3_result_int(pCtx, 0); break; }else{ iCol = p->nColumn; | | | 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 | sqlite3_result_int64(pCtx, pCsr->iLangid); break; }else if( p->zLanguageid==0 ){ sqlite3_result_int(pCtx, 0); break; }else{ iCol = p->nColumn; /* 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 ){ |
︙ | ︙ | |||
3583 3584 3585 3586 3587 3588 3589 | } /* ** Implementation of xBegin() method. */ static int fts3BeginMethod(sqlite3_vtab *pVtab){ Fts3Table *p = (Fts3Table*)pVtab; | < < < < < | | < < > | | 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 | } /* ** 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 ); TESTONLY( p->inTransaction = 1 ); TESTONLY( p->mxSavepoint = -1; ); p->nLeafAdd = 0; return fts3SetHasStat(p); } /* ** 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(). */ |
︙ | ︙ | |||
3725 3726 3727 3728 3729 3730 3731 | "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]); | < < < < | 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 | "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) ){ |
︙ | ︙ | |||
4009 4010 4011 4012 4013 4014 4015 | /* ** This function is registered as the module destructor (called when an ** FTS3 enabled database connection is closed). It frees the memory ** allocated for the tokenizer hash table. */ static void hashDestroy(void *p){ | | < < | | < | 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 | /* ** This function is registered as the module destructor (called when an ** FTS3 enabled database connection is closed). It frees the memory ** allocated for the tokenizer hash table. */ static void hashDestroy(void *p){ Fts3Hash *pHash = (Fts3Hash *)p; sqlite3Fts3HashClear(pHash); sqlite3_free(pHash); } /* ** The fts3 built-in tokenizers - "simple", "porter" and "icu"- are ** implemented in files fts3_tokenizer1.c, fts3_porter.c and fts3_icu.c ** respectively. The following three forward declarations are for functions ** declared in these files used to retrieve the respective implementations. |
︙ | ︙ | |||
4044 4045 4046 4047 4048 4049 4050 | ** Initialize the fts3 extension. If this extension is built as part ** of the sqlite library, then this function is called directly by ** SQLite. If fts3 is built as a dynamically loadable extension, this ** function is called by the sqlite3_extension_init() entry point. */ int sqlite3Fts3Init(sqlite3 *db){ int rc = SQLITE_OK; | | | 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 | ** Initialize the fts3 extension. If this extension is built as part ** of the sqlite library, then this function is called directly by ** SQLite. If fts3 is built as a dynamically loadable extension, this ** function is called by the sqlite3_extension_init() entry point. */ int sqlite3Fts3Init(sqlite3 *db){ int rc = SQLITE_OK; Fts3Hash *pHash = 0; const sqlite3_tokenizer_module *pSimple = 0; const sqlite3_tokenizer_module *pPorter = 0; #ifndef SQLITE_DISABLE_FTS3_UNICODE const sqlite3_tokenizer_module *pUnicode = 0; #endif #ifdef SQLITE_ENABLE_ICU |
︙ | ︙ | |||
4072 4073 4074 4075 4076 4077 4078 | rc = sqlite3Fts3InitAux(db); if( rc!=SQLITE_OK ) return rc; sqlite3Fts3SimpleTokenizerModule(&pSimple); sqlite3Fts3PorterTokenizerModule(&pPorter); /* Allocate and initialize the hash-table used to store tokenizers. */ | | | < | | | | | | < < | < | | | 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 | rc = sqlite3Fts3InitAux(db); if( rc!=SQLITE_OK ) return rc; sqlite3Fts3SimpleTokenizerModule(&pSimple); sqlite3Fts3PorterTokenizerModule(&pPorter); /* Allocate and initialize the hash-table used to store tokenizers. */ pHash = sqlite3_malloc(sizeof(Fts3Hash)); if( !pHash ){ rc = SQLITE_NOMEM; }else{ sqlite3Fts3HashInit(pHash, FTS3_HASH_STRING, 1); } /* Load the built-in tokenizers into the hash table */ if( rc==SQLITE_OK ){ if( sqlite3Fts3HashInsert(pHash, "simple", 7, (void *)pSimple) || sqlite3Fts3HashInsert(pHash, "porter", 7, (void *)pPorter) #ifndef SQLITE_DISABLE_FTS3_UNICODE || sqlite3Fts3HashInsert(pHash, "unicode61", 10, (void *)pUnicode) #endif #ifdef SQLITE_ENABLE_ICU || (pIcu && sqlite3Fts3HashInsert(pHash, "icu", 4, (void *)pIcu)) #endif ){ rc = SQLITE_NOMEM; } } #ifdef SQLITE_TEST if( rc==SQLITE_OK ){ rc = sqlite3Fts3ExprInitTestInterface(db, pHash); } #endif /* Create the virtual table wrapper around the hash-table and overload ** the four scalar functions. If this is successful, register the ** module with sqlite. */ if( SQLITE_OK==rc && SQLITE_OK==(rc = sqlite3Fts3InitHashTable(db, pHash, "fts3_tokenizer")) && SQLITE_OK==(rc = sqlite3_overload_function(db, "snippet", -1)) && SQLITE_OK==(rc = sqlite3_overload_function(db, "offsets", 1)) && SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 1)) && SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 2)) && SQLITE_OK==(rc = sqlite3_overload_function(db, "optimize", 1)) ){ rc = sqlite3_create_module_v2( db, "fts3", &fts3Module, (void *)pHash, hashDestroy ); if( rc==SQLITE_OK ){ rc = sqlite3_create_module_v2( db, "fts4", &fts3Module, (void *)pHash, 0 ); } if( rc==SQLITE_OK ){ rc = sqlite3Fts3InitTok(db, (void *)pHash); } return rc; } /* An error has occurred. Delete the hash table and return the error code. */ assert( rc!=SQLITE_OK ); if( pHash ){ sqlite3Fts3HashClear(pHash); sqlite3_free(pHash); } return rc; } /* ** Allocate an Fts3MultiSegReader for each token in the expression headed |
︙ | ︙ | |||
4304 4305 4306 4307 4308 4309 4310 | ** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code. */ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){ int iToken; /* Used to iterate through phrase tokens */ char *aPoslist = 0; /* Position list for deferred tokens */ int nPoslist = 0; /* Number of bytes in aPoslist */ int iPrev = -1; /* Token number of previous deferred token */ | > | < < | 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 | ** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code. */ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){ int iToken; /* Used to iterate through phrase tokens */ char *aPoslist = 0; /* Position list for deferred tokens */ int nPoslist = 0; /* Number of bytes in aPoslist */ int iPrev = -1; /* Token number of previous deferred token */ assert( pPhrase->doclist.bFreeList==0 ); for(iToken=0; iToken<pPhrase->nToken; iToken++){ Fts3PhraseToken *pToken = &pPhrase->aToken[iToken]; Fts3DeferredToken *pDeferred = pToken->pDeferred; if( pDeferred ){ char *pList; int nList; int rc = sqlite3Fts3DeferredTokenList(pDeferred, &pList, &nList); if( rc!=SQLITE_OK ) return rc; if( pList==0 ){ sqlite3_free(aPoslist); pPhrase->doclist.pList = 0; pPhrase->doclist.nList = 0; return SQLITE_OK; }else if( aPoslist==0 ){ aPoslist = pList; nPoslist = nList; }else{ char *aOut = pList; char *p1 = aPoslist; char *p2 = aOut; assert( iPrev>=0 ); fts3PoslistPhraseMerge(&aOut, iToken-iPrev, 0, 1, &p1, &p2); sqlite3_free(aPoslist); aPoslist = pList; nPoslist = (int)(aOut - aPoslist); if( nPoslist==0 ){ sqlite3_free(aPoslist); pPhrase->doclist.pList = 0; pPhrase->doclist.nList = 0; return SQLITE_OK; } } iPrev = iToken; } |
︙ | ︙ | |||
4372 4373 4374 4375 4376 4377 4378 | nDistance = nMaxUndeferred - iPrev; }else{ p1 = pPhrase->doclist.pList; p2 = aPoslist; nDistance = iPrev - nMaxUndeferred; } | | < < | 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 | nDistance = nMaxUndeferred - iPrev; }else{ p1 = pPhrase->doclist.pList; p2 = aPoslist; nDistance = iPrev - nMaxUndeferred; } aOut = (char *)sqlite3_malloc(nPoslist+8); if( !aOut ){ sqlite3_free(aPoslist); return SQLITE_NOMEM; } pPhrase->doclist.pList = aOut; if( fts3PoslistPhraseMerge(&aOut, nDistance, 0, 1, &p1, &p2) ){ pPhrase->doclist.bFreeList = 1; pPhrase->doclist.nList = (int)(aOut - pPhrase->doclist.pList); }else{ sqlite3_free(aOut); pPhrase->doclist.pList = 0; pPhrase->doclist.nList = 0; } sqlite3_free(aPoslist); } } return SQLITE_OK; } #endif /* SQLITE_DISABLE_FTS4_DEFERRED */ /* ** Maximum number of tokens a phrase may have to be considered for the ** incremental doclists strategy. |
︙ | ︙ | |||
4485 4486 4487 4488 4489 4490 4491 | int *pnList, /* OUT: List length pointer */ u8 *pbEof /* OUT: End-of-file flag */ ){ char *p = *ppIter; assert( nDoclist>0 ); assert( *pbEof==0 ); | | | 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 | int *pnList, /* OUT: List length pointer */ u8 *pbEof /* OUT: End-of-file flag */ ){ char *p = *ppIter; assert( nDoclist>0 ); assert( *pbEof==0 ); assert( p || *piDocid==0 ); assert( !p || (p>aDoclist && p<&aDoclist[nDoclist]) ); if( p==0 ){ sqlite3_int64 iDocid = 0; char *pNext = 0; char *pDocid = aDoclist; char *pEnd = &aDoclist[nDoclist]; |
︙ | ︙ | |||
4540 4541 4542 4543 4544 4545 4546 | sqlite3_int64 *piDocid, /* IN/OUT: Docid pointer */ u8 *pbEof /* OUT: End-of-file flag */ ){ char *p = *ppIter; assert( nDoclist>0 ); assert( *pbEof==0 ); | | | 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 | sqlite3_int64 *piDocid, /* IN/OUT: Docid pointer */ u8 *pbEof /* OUT: End-of-file flag */ ){ char *p = *ppIter; assert( nDoclist>0 ); assert( *pbEof==0 ); assert( p || *piDocid==0 ); assert( !p || (p>=aDoclist && p<=&aDoclist[nDoclist]) ); if( p==0 ){ p = aDoclist; p += sqlite3Fts3GetVarint(p, piDocid); }else{ fts3PoslistCopy(0, &p); |
︙ | ︙ | |||
4741 4742 4743 4744 4745 4746 4747 | } } /* Check if the current entries really are a phrase match */ if( bEof==0 ){ int nList = 0; int nByte = a[p->nToken-1].nList; | | | 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 | } } /* 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; |
︙ | ︙ | |||
5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 | /* 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{ | > > < | 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 | /* 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; Fts3Expr **apOr; aTC = (Fts3TokenAndCost *)sqlite3_malloc64( sizeof(Fts3TokenAndCost) * nToken + sizeof(Fts3Expr *) * nOr * 2 ); apOr = (Fts3Expr **)&aTC[nToken]; if( !aTC ){ rc = SQLITE_NOMEM; }else{ int ii; Fts3TokenAndCost *pTC = aTC; Fts3Expr **ppOr = apOr; fts3EvalTokenCosts(pCsr, 0, pCsr->pExpr, &pTC, &ppOr, &rc); nToken = (int)(pTC-aTC); nOr = (int)(ppOr-apOr); |
︙ | ︙ | |||
5189 5190 5191 5192 5193 5194 5195 | ** 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 | | | 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 | ** 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. |
︙ | ︙ | |||
5224 5225 5226 5227 5228 5229 5230 | p2 = pOut = pPhrase->doclist.pList; res = fts3PoslistNearMerge( &pOut, aTmp, nParam1, nParam2, paPoslist, &p2 ); if( res ){ nNew = (int)(pOut - pPhrase->doclist.pList) - 1; | < < | > | | < | 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 | p2 = pOut = pPhrase->doclist.pList; res = fts3PoslistNearMerge( &pOut, aTmp, nParam1, nParam2, paPoslist, &p2 ); if( res ){ nNew = (int)(pOut - pPhrase->doclist.pList) - 1; assert( pPhrase->doclist.pList[nNew]=='\0' ); assert( nNew<=pPhrase->doclist.nList && 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; } |
︙ | ︙ | |||
5283 5284 5285 5286 5287 5288 5289 | ** really a match, taking into account deferred tokens and NEAR operators. */ static void fts3EvalNextRow( Fts3Cursor *pCsr, /* FTS Cursor handle */ Fts3Expr *pExpr, /* Expr. to advance to next matching row */ int *pRc /* IN/OUT: Error code */ ){ | | > | 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 | ** really a match, taking into account deferred tokens and NEAR operators. */ static void fts3EvalNextRow( Fts3Cursor *pCsr, /* FTS Cursor handle */ Fts3Expr *pExpr, /* Expr. to advance to next matching row */ int *pRc /* IN/OUT: Error code */ ){ if( *pRc==SQLITE_OK ){ int bDescDoclist = pCsr->bDesc; /* Used by DOCID_CMP() macro */ assert( pExpr->bEof==0 ); pExpr->bStart = 1; switch( pExpr->eType ){ case FTSQUERY_NEAR: case FTSQUERY_AND: { Fts3Expr *pLeft = pExpr->pLeft; Fts3Expr *pRight = pExpr->pRight; |
︙ | ︙ | |||
5337 5338 5339 5340 5341 5342 5343 | 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); } } | < | | | 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 | 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); assert( pLeft->bStart || pLeft->iDocid==pRight->iDocid ); assert( 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); |
︙ | ︙ | |||
5566 5567 5568 5569 5570 5571 5572 | fts3EvalTestExpr(pCsr, pExpr->pLeft, pRc) && !fts3EvalTestExpr(pCsr, pExpr->pRight, pRc) ); break; default: { #ifndef SQLITE_DISABLE_FTS4_DEFERRED | | | | > < | < < | 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 | fts3EvalTestExpr(pCsr, pExpr->pLeft, pRc) && !fts3EvalTestExpr(pCsr, pExpr->pRight, pRc) ); break; default: { #ifndef SQLITE_DISABLE_FTS4_DEFERRED if( pCsr->pDeferred && (pExpr->iDocid==pCsr->iPrevId || pExpr->bDeferred) ){ Fts3Phrase *pPhrase = pExpr->pPhrase; assert( pExpr->bDeferred || pPhrase->doclist.bFreeList==0 ); if( pExpr->bDeferred ){ fts3EvalInvalidatePoslist(pPhrase); } *pRc = fts3EvalDeferredPhrase(pCsr, pPhrase); bHit = (pPhrase->doclist.pList!=0); pExpr->iDocid = pCsr->iPrevId; }else #endif { bHit = (pExpr->bEof==0 && pExpr->iDocid==pCsr->iPrevId); } break; } } } return bHit; } |
︙ | ︙ | |||
5760 5761 5762 5763 5764 5765 5766 | } fts3EvalUpdateCounts(pExpr->pLeft, nCol); fts3EvalUpdateCounts(pExpr->pRight, nCol); } } | < < < < < < < < < < < < < < < < | 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 | } 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 ** populates the Fts3Expr.aMI[] array for expression pExpr. If pExpr is part ** of a NEAR expression, then it also allocates and populates the same array ** for all other phrases that are part of the NEAR expression. |
︙ | ︙ | |||
5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 | ){ int rc = SQLITE_OK; /* Return code */ assert( pExpr->eType==FTSQUERY_PHRASE ); if( pExpr->aMI==0 ){ Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; Fts3Expr *pRoot; /* Root of NEAR expression */ sqlite3_int64 iPrevId = pCsr->iPrevId; sqlite3_int64 iDocid; u8 bEof; /* Find the root of the NEAR expression */ pRoot = pExpr; | > | < < > | > > > > > | | 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 | ){ int rc = SQLITE_OK; /* Return code */ assert( pExpr->eType==FTSQUERY_PHRASE ); if( pExpr->aMI==0 ){ Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab; Fts3Expr *pRoot; /* Root of NEAR expression */ Fts3Expr *p; /* Iterator used for several purposes */ sqlite3_int64 iPrevId = pCsr->iPrevId; sqlite3_int64 iDocid; u8 bEof; /* Find the root of the NEAR expression */ pRoot = pExpr; while( pRoot->pParent && pRoot->pParent->eType==FTSQUERY_NEAR ){ pRoot = pRoot->pParent; } iDocid = pRoot->iDocid; 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 ){ do { /* Ensure the %_content statement is reset. */ if( pCsr->isRequireSeek==0 ) sqlite3_reset(pCsr->pStmt); |
︙ | ︙ | |||
5856 5857 5858 5859 5860 5861 5862 | ** do loop can not be written: ** ** do {...} while( pRoot->iDocid<iDocid && rc==SQLITE_OK ); */ fts3EvalRestart(pCsr, pRoot, &rc); do { fts3EvalNextRow(pCsr, pRoot, &rc); | | < | 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 | ** do loop can not be written: ** ** do {...} while( pRoot->iDocid<iDocid && rc==SQLITE_OK ); */ fts3EvalRestart(pCsr, pRoot, &rc); do { fts3EvalNextRow(pCsr, pRoot, &rc); assert( pRoot->bEof==0 ); }while( pRoot->iDocid!=iDocid && rc==SQLITE_OK ); } } return rc; } /* |
︙ | ︙ | |||
5971 5972 5973 5974 5975 5976 5977 | if( iDocid!=pCsr->iPrevId || pExpr->bEof ){ int rc = SQLITE_OK; int bDescDoclist = pTab->bDescIdx; /* For DOCID_CMP macro */ int bOr = 0; u8 bTreeEof = 0; Fts3Expr *p; /* Used to iterate from pExpr to root */ Fts3Expr *pNear; /* Most senior NEAR ancestor (or pExpr) */ | < < < < < < | | | | | < < | < | | | 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 | if( iDocid!=pCsr->iPrevId || pExpr->bEof ){ int rc = SQLITE_OK; int bDescDoclist = pTab->bDescIdx; /* For DOCID_CMP macro */ int bOr = 0; u8 bTreeEof = 0; Fts3Expr *p; /* Used to iterate from pExpr to root */ Fts3Expr *pNear; /* Most senior NEAR ancestor (or pExpr) */ int bMatch; /* Check if this phrase descends from an OR expression node. If not, ** return NULL. Otherwise, the entry that corresponds to docid ** pCsr->iPrevId may lie earlier in the doclist buffer. Or, if the ** tree that the node is part of has been marked as EOF, but the node ** itself is not EOF, then it may point to an earlier entry. */ pNear = pExpr; for(p=pExpr->pParent; p; p=p->pParent){ if( p->eType==FTSQUERY_OR ) bOr = 1; if( p->eType==FTSQUERY_NEAR ) pNear = p; if( p->bEof ) bTreeEof = 1; } if( bOr==0 ) return SQLITE_OK; /* This is the descendent of an OR node. In this case we cannot use ** an incremental phrase. Load the entire doclist for the phrase ** into memory in this case. */ if( pPhrase->bIncr ){ 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; bMatch = 1; for(p=pNear; p; p=p->pLeft){ u8 bEof = 0; |
︙ | ︙ |
Changes to ext/fts3/fts3Int.h.
︙ | ︙ | |||
130 131 132 133 134 135 136 | #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. */ | | | < < < | | | | | > > | | | 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 | #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. */ #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) 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. */ #ifdef SQLITE_COVERAGE_TEST # define ALWAYS(x) (1) # define NEVER(X) (0) #elif defined(SQLITE_DEBUG) # define ALWAYS(x) sqlite3Fts3Always((x)!=0) # define NEVER(x) sqlite3Fts3Never((x)!=0) int sqlite3Fts3Always(int b); int sqlite3Fts3Never(int b); #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 */ |
︙ | ︙ | |||
196 197 198 199 200 201 202 | #else # define TESTONLY(X) #endif #define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32)) #define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64) | < < | 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | #else # define TESTONLY(X) #endif #define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32)) #define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64) #endif /* SQLITE_AMALGAMATION */ #ifdef SQLITE_DEBUG int sqlite3Fts3Corrupt(void); # define FTS_CORRUPT_VTAB sqlite3Fts3Corrupt() #else # define FTS_CORRUPT_VTAB SQLITE_CORRUPT_VTAB |
︙ | ︙ | |||
554 555 556 557 558 559 560 | struct Fts3MultiSegReader { /* Used internally by sqlite3Fts3SegReaderXXX() calls */ Fts3SegReader **apSegment; /* Array of Fts3SegReader objects */ int nSegment; /* Size of apSegment array */ int nAdvance; /* How many seg-readers to advance */ Fts3SegFilter *pFilter; /* Pointer to filter object */ char *aBuffer; /* Buffer to merge doclists in */ | | | 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 | struct Fts3MultiSegReader { /* Used internally by sqlite3Fts3SegReaderXXX() calls */ Fts3SegReader **apSegment; /* Array of Fts3SegReader objects */ int nSegment; /* Size of apSegment array */ int nAdvance; /* How many seg-readers to advance */ Fts3SegFilter *pFilter; /* Pointer to filter object */ char *aBuffer; /* Buffer to merge doclists in */ int nBuffer; /* Allocated size of aBuffer[] in bytes */ int iColFilter; /* If >=0, filter for this column */ int bRestart; /* Used by fts3.c only. */ int nCost; /* Cost of running iterator */ int bLookup; /* True if a lookup of a single entry. */ |
︙ | ︙ | |||
590 591 592 593 594 595 596 | 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); | < | 587 588 589 590 591 592 593 594 595 596 597 598 599 600 | 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 ** ); |
︙ | ︙ | |||
617 618 619 620 621 622 623 | 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 | < | < < | 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 | 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); void sqlite3Fts3EvalPhraseCleanup(Fts3Phrase *); int sqlite3Fts3MsrIncrStart( Fts3Table*, Fts3MultiSegReader*, int, const char*, int); int sqlite3Fts3MsrIncrNext( Fts3Table *, Fts3MultiSegReader *, sqlite3_int64 *, char **, int *); int sqlite3Fts3EvalPhrasePoslist(Fts3Cursor *, Fts3Expr *, int iCol, char **); int sqlite3Fts3MsrOvfl(Fts3Cursor *, Fts3MultiSegReader *, int *); int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr); /* fts3_tokenize_vtab.c */ int sqlite3Fts3InitTok(sqlite3*, Fts3Hash *); /* fts3_unicode2.c (functions generated by parsing unicode text files) */ #ifndef SQLITE_DISABLE_FTS3_UNICODE int sqlite3FtsUnicodeFold(int, int); int sqlite3FtsUnicodeIsalnum(int); int sqlite3FtsUnicodeIsdiacritic(int); #endif #endif /* !SQLITE_CORE || SQLITE_ENABLE_FTS3 */ #endif /* _FTSINT_H */ |
Changes to ext/fts3/fts3_aux.c.
︙ | ︙ | |||
293 294 295 296 297 298 299 | return SQLITE_OK; } } if( fts3auxGrowStatArray(pCsr, 2) ) return SQLITE_NOMEM; memset(pCsr->aStat, 0, sizeof(struct Fts3auxColstats) * pCsr->nStat); iCol = 0; | < | 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. */ |
︙ | ︙ | |||
337 338 339 340 341 342 343 | pCsr->aStat[0].nOcc++; } break; /* State 3. The integer just read is a column number. */ default: assert( eState==3 ); iCol = (int)v; | < < < < > | 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 | 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; rc = SQLITE_OK; }else{ pCsr->isEof = 1; } return rc; } /* |
︙ | ︙ | |||
406 407 408 409 410 411 412 | } /* 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); | < | 402 403 404 405 406 407 408 409 410 411 412 413 414 415 | } /* 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]); |
︙ | ︙ |
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 | } /* ** Allocate nByte bytes of memory using sqlite3_malloc(). If successful, ** zero the memory before returning a pointer to it. If unsuccessful, ** return NULL. */ static void *fts3MallocZero(sqlite3_int64 nByte){ void *pRet = sqlite3_malloc64(nByte); if( pRet ) memset(pRet, 0, nByte); return pRet; } int sqlite3Fts3OpenTokenizer( sqlite3_tokenizer *pTokenizer, |
︙ | ︙ | |||
199 200 201 202 203 204 205 | 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; | | | 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | 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 *)fts3MallocZero(nByte); if( !pRet ){ rc = SQLITE_NOMEM; }else{ pRet->eType = FTSQUERY_PHRASE; pRet->pPhrase = (Fts3Phrase *)&pRet[1]; pRet->pPhrase->nToken = 1; pRet->pPhrase->iColumn = iCol; |
︙ | ︙ | |||
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 469 470 471 | 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' ){ nNear = 0; for(nKey=5; zInput[nKey]>='0' && zInput[nKey]<='9'; nKey++){ nNear = nNear * 10 + (zInput[nKey] - '0'); } } } /* 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 *)fts3MallocZero(sizeof(Fts3Expr)); if( !pRet ){ return SQLITE_NOMEM; } pRet->eType = pKey->eType; pRet->nNear = nNear; *ppExpr = pRet; *pnConsumed = (int)((zInput - z) + nKey); |
︙ | ︙ | |||
489 490 491 492 493 494 495 | return getNextString(pParse, &zInput[1], ii-1, ppExpr); } if( sqlite3_fts3_enable_parentheses ){ if( *zInput=='(' ){ int nConsumed = 0; pParse->nNest++; | < < < < < | 492 493 494 495 496 497 498 499 500 501 502 503 504 505 | 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); *pnConsumed = (int)(zInput - z) + 1 + nConsumed; return rc; }else if( *zInput==')' ){ pParse->nNest--; *pnConsumed = (int)((zInput - z) + 1); *ppExpr = 0; |
︙ | ︙ | |||
633 634 635 636 637 638 639 | if( p ){ int isPhrase; if( !sqlite3_fts3_enable_parentheses && p->eType==FTSQUERY_PHRASE && pParse->isNot ){ /* Create an implicit NOT operator. */ | | | 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 | if( p ){ int isPhrase; if( !sqlite3_fts3_enable_parentheses && p->eType==FTSQUERY_PHRASE && pParse->isNot ){ /* Create an implicit NOT operator. */ Fts3Expr *pNot = fts3MallocZero(sizeof(Fts3Expr)); if( !pNot ){ sqlite3Fts3ExprFree(p); rc = SQLITE_NOMEM; goto exprparse_out; } pNot->eType = FTSQUERY_NOT; pNot->pRight = p; |
︙ | ︙ | |||
667 668 669 670 671 672 673 | goto exprparse_out; } if( isPhrase && !isRequirePhrase ){ /* Insert an implicit AND operator. */ Fts3Expr *pAnd; assert( pRet && pPrev ); | | | 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 | goto exprparse_out; } if( isPhrase && !isRequirePhrase ){ /* Insert an implicit AND operator. */ Fts3Expr *pAnd; assert( pRet && pPrev ); pAnd = fts3MallocZero(sizeof(Fts3Expr)); if( !pAnd ){ sqlite3Fts3ExprFree(p); rc = SQLITE_NOMEM; goto exprparse_out; } pAnd->eType = FTSQUERY_AND; insertBinaryOperator(&pRet, pPrev, pAnd); |
︙ | ︙ |
Changes to ext/fts3/fts3_porter.c.
︙ | ︙ | |||
617 618 619 620 621 622 623 | } if( c->iOffset>iStartOffset ){ int n = c->iOffset-iStartOffset; if( n>c->nAllocated ){ char *pNew; c->nAllocated = n+20; | | | 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 | } if( c->iOffset>iStartOffset ){ int n = c->iOffset-iStartOffset; if( n>c->nAllocated ){ char *pNew; c->nAllocated = n+20; pNew = sqlite3_realloc(c->zToken, c->nAllocated); if( !pNew ) return SQLITE_NOMEM; c->zToken = pNew; } porter_stemmer(&z[iStartOffset], n, c->zToken, pnBytes); *pzToken = c->zToken; *piStartOffset = iStartOffset; *piEndOffset = c->iOffset; |
︙ | ︙ |
Changes to ext/fts3/fts3_snippet.c.
︙ | ︙ | |||
13 14 15 16 17 18 19 | #include "fts3Int.h" #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) #include <string.h> #include <assert.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 | #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 */ #define FTS3_MATCHINFO_LENGTH 'l' /* nCol values */ #define FTS3_MATCHINFO_LCS 's' /* nCol values */ #define FTS3_MATCHINFO_HITS 'x' /* 3*nCol*nPhrase values */ #define FTS3_MATCHINFO_LHITS 'y' /* nCol*nPhrase values */ #define FTS3_MATCHINFO_LHITS_BM 'b' /* nCol*nPhrase values */ /* ** The default value for the second argument to matchinfo(). */ #define FTS3_MATCHINFO_DEFAULT "pcx" /* ** Used as an fts3ExprIterate() context when loading phrase doclists to ** Fts3Expr.aDoclist[]/nDoclist. */ typedef struct LoadDoclistCtx LoadDoclistCtx; struct LoadDoclistCtx { Fts3Cursor *pCsr; /* FTS3 Cursor */ int nPhrase; /* Number of phrases seen so far */ int nToken; /* Number of tokens seen so far */ |
︙ | ︙ | |||
67 68 69 70 71 72 73 | 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 */ | | | | | 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 | 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 */ int iHead; /* Next value in position list */ char *pHead; /* Position list data following iHead */ int 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 */ u64 hlmask; /* Mask of snippet terms to highlight */ }; /* ** This type is used as an fts3ExprIterate() context object while ** accumulating the data returned by the matchinfo() function. */ typedef struct MatchInfo MatchInfo; struct MatchInfo { Fts3Cursor *pCursor; /* FTS3 Cursor */ int nCol; /* Number of columns in table */ int nPhrase; /* Number of matchable phrases in query */ |
︙ | ︙ | |||
134 135 136 137 138 139 140 | */ 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); | | > | 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | */ 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 = sqlite3_malloc64(nByte + nStr+1); if( pRet ){ memset(pRet, 0, nByte); 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; |
︙ | ︙ | |||
233 234 235 236 237 238 239 | ** 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. */ | | | | 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 | ** 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, int *piPos){ int iVal; *pp += fts3GetVarint32(*pp, &iVal); *piPos += (iVal-2); } /* ** Helper function for fts3ExprIterate() (see below). */ static int fts3ExprIterate2( Fts3Expr *pExpr, /* Expression to iterate phrases of */ int *piPhrase, /* Pointer to phrase counter */ int (*x)(Fts3Expr*,int,void*), /* Callback function to invoke for phrases */ void *pCtx /* Second argument to pass to callback */ ){ |
︙ | ︙ | |||
274 275 276 277 278 279 280 | ** For each phrase node found, the supplied callback function is invoked. ** ** If the callback function returns anything other than SQLITE_OK, ** the iteration is abandoned and the error code returned immediately. ** Otherwise, SQLITE_OK is returned after a callback has been made for ** all eligible phrase nodes. */ | | > | | | 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 | ** For each phrase node found, the supplied callback function is invoked. ** ** If the callback function returns anything other than SQLITE_OK, ** the iteration is abandoned and the error code returned immediately. ** Otherwise, SQLITE_OK is returned after a callback has been made for ** all eligible phrase nodes. */ static int fts3ExprIterate( Fts3Expr *pExpr, /* Expression to iterate phrases of */ int (*x)(Fts3Expr*,int,void*), /* Callback function to invoke for phrases */ void *pCtx /* Second argument to pass to callback */ ){ int iPhrase = 0; /* Variable used as the phrase counter */ return fts3ExprIterate2(pExpr, &iPhrase, x, pCtx); } /* ** This is an fts3ExprIterate() callback used while loading the doclists ** for each phrase into Fts3Expr.aDoclist[]/nDoclist. See also ** fts3ExprLoadDoclists(). */ static int fts3ExprLoadDoclistsCb(Fts3Expr *pExpr, int iPhrase, void *ctx){ int rc = SQLITE_OK; Fts3Phrase *pPhrase = pExpr->pPhrase; LoadDoclistCtx *p = (LoadDoclistCtx *)ctx; |
︙ | ︙ | |||
317 318 319 320 321 322 323 | */ static int fts3ExprLoadDoclists( Fts3Cursor *pCsr, /* Fts3 cursor for current query */ int *pnPhrase, /* OUT: Number of phrases in query */ int *pnToken /* OUT: Number of tokens in query */ ){ int rc; /* Return Code */ | | | | | | | 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 | */ static int fts3ExprLoadDoclists( Fts3Cursor *pCsr, /* Fts3 cursor for current query */ int *pnPhrase, /* OUT: Number of phrases in query */ int *pnToken /* OUT: Number of tokens in query */ ){ int rc; /* Return Code */ LoadDoclistCtx sCtx = {0,0,0}; /* Context for fts3ExprIterate() */ sCtx.pCsr = pCsr; rc = fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb, (void *)&sCtx); if( pnPhrase ) *pnPhrase = sCtx.nPhrase; if( pnToken ) *pnToken = sCtx.nToken; return rc; } static int fts3ExprPhraseCountCb(Fts3Expr *pExpr, int iPhrase, void *ctx){ (*(int *)ctx)++; pExpr->iPhrase = iPhrase; return SQLITE_OK; } static int fts3ExprPhraseCount(Fts3Expr *pExpr){ int nPhrase = 0; (void)fts3ExprIterate(pExpr, fts3ExprPhraseCountCb, (void *)&nPhrase); return nPhrase; } /* ** 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, int *piIter, int iNext){ char *pIter = *ppIter; if( pIter ){ int iIter = *piIter; while( iIter<iNext ){ if( 0==(*pIter & 0xFE) ){ iIter = -1; pIter = 0; break; } |
︙ | ︙ | |||
427 428 429 430 431 432 433 | 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; | | | 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 | 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; int 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 ); |
︙ | ︙ | |||
460 461 462 463 464 465 466 | *piToken = iStart; *piScore = iScore; *pmCover = mCover; *pmHighlight = mHighlight; } /* | | | < | | 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 | *piToken = iStart; *piScore = iScore; *pmCover = mCover; *pmHighlight = mHighlight; } /* ** This function is an fts3ExprIterate() callback used by fts3BestSnippet(). ** Each invocation populates an element of the SnippetIter.aPhrase[] array. */ static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){ SnippetIter *p = (SnippetIter *)ctx; SnippetPhrase *pPhrase = &p->aPhrase[iPhrase]; 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 ){ int iFirst = 0; pPhrase->pList = pCsr; fts3GetDeltaPosition(&pCsr, &iFirst); if( iFirst<0 ){ rc = FTS_CORRUPT_VTAB; }else{ pPhrase->pHead = pCsr; pPhrase->pTail = pCsr; |
︙ | ︙ | |||
539 540 541 542 543 544 545 | return rc; } /* Now that it is known how many phrases there are, allocate and zero ** the required space using malloc(). */ nByte = sizeof(SnippetPhrase) * nList; | | > < | < | 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 | 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 *)sqlite3_malloc64(nByte); if( !sIter.aPhrase ){ return SQLITE_NOMEM; } memset(sIter.aPhrase, 0, nByte); /* 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); } |
︙ | ︙ | |||
876 877 878 879 880 881 882 | 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); } | | | 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 | 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); } 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)); } |
︙ | ︙ | |||
915 916 917 918 919 920 921 | rc = fts3ExprLHits(pExpr, p); } } return rc; } /* | | | | | 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 | 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 ** FTS3_MATCHINFO_HITS matchinfo array. The global stats are those elements ** of the matchinfo array that are constant for all rows returned by the ** current query. ** ** Argument pCtx is actually a pointer to a struct of type MatchInfo. This ** function populates Matchinfo.aMatchinfo[] as follows: ** |
︙ | ︙ | |||
953 954 955 956 957 958 959 | MatchInfo *p = (MatchInfo *)pCtx; return sqlite3Fts3EvalPhraseStats( p->pCursor, pExpr, &p->aMatchinfo[3*iPhrase*p->nCol] ); } /* | | | 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 | MatchInfo *p = (MatchInfo *)pCtx; return sqlite3Fts3EvalPhraseStats( p->pCursor, pExpr, &p->aMatchinfo[3*iPhrase*p->nCol] ); } /* ** fts3ExprIterate() callback used to collect the "local" part of the ** FTS3_MATCHINFO_HITS array. The local stats are those elements of the ** array that are different for each row returned by the query. */ static int fts3ExprLocalHitsCb( Fts3Expr *pExpr, /* Phrase expression node */ int iPhrase, /* Phrase number */ void *pCtx /* Pointer to MatchInfo structure */ |
︙ | ︙ | |||
1108 1109 1110 1111 1112 1113 1114 | /* ** 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){ | | < < | 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 | /* ** 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 = pIter->pRead; sqlite3_int64 iRead; int rc = 0; pRead += sqlite3Fts3GetVarint(pRead, &iRead); if( iRead==0 || iRead==1 ){ pRead = 0; rc = 1; }else{ pIter->iPos += (int)(iRead-2); } |
︙ | ︙ | |||
1147 1148 1149 1150 1151 1152 1153 | 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. **/ | | > | | 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 | 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 = sqlite3_malloc64(sizeof(LcsIterator) * pCsr->nPhrase); if( !aIter ) return SQLITE_NOMEM; memset(aIter, 0, sizeof(LcsIterator) * pCsr->nPhrase); (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; } |
︙ | ︙ | |||
1326 1327 1328 1329 1330 1331 1332 | 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; } | | | | 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 | 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); break; } } pInfo->aMatchinfo += fts3MatchinfoSize(pInfo, zArg[i]); } |
︙ | ︙ | |||
1540 1541 1542 1543 1544 1545 1546 | typedef struct TermOffset TermOffset; typedef struct TermOffsetCtx TermOffsetCtx; struct TermOffset { char *pList; /* Position-list */ | | | | | | 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 | typedef struct TermOffset TermOffset; typedef struct TermOffsetCtx TermOffsetCtx; struct TermOffset { char *pList; /* Position-list */ int iPos; /* Position just read from pList */ int 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 */ int 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); |
︙ | ︙ | |||
1609 1610 1611 1612 1613 1614 1615 | 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. */ | | | | > < | < < | 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 | 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 *)sqlite3_malloc64(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. There is ** no way that this operation can fail, so the return code from ** fts3ExprIterate() can be discarded. */ sCtx.iCol = iCol; sCtx.iTerm = 0; (void)fts3ExprIterate(pCsr->pExpr, fts3ExprTermOffsetInit, (void*)&sCtx); /* 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. */ |
︙ | ︙ |
Changes to ext/fts3/fts3_test.c.
︙ | ︙ | |||
581 582 583 584 585 586 587 | */ static int SQLITE_TCLAPI fts3_may_be_corrupt( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ | < < | 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 | */ static int SQLITE_TCLAPI fts3_may_be_corrupt( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ 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)); 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 |
︙ | ︙ |
Changes to ext/fts3/fts3_tokenize_vtab.c.
︙ | ︙ | |||
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 | zModule = azDequote[0]; } rc = fts3tokQueryTokenizer((Fts3Hash*)pHash, zModule, &pMod, pzErr); } assert( (rc==SQLITE_OK)==(pMod!=0) ); if( rc==SQLITE_OK ){ const char * const *azArg = (const char * const *)&azDequote[1]; rc = pMod->xCreate((nDequote>1 ? nDequote-1 : 0), azArg, &pTok); } if( rc==SQLITE_OK ){ pTab = (Fts3tokTable *)sqlite3_malloc(sizeof(Fts3tokTable)); if( pTab==0 ){ rc = SQLITE_NOMEM; |
︙ | ︙ | |||
347 348 349 350 351 352 353 | 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{ | | | 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 | 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{ 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; } } } |
︙ | ︙ | |||
416 417 418 419 420 421 422 | return SQLITE_OK; } /* ** Register the fts3tok module with database connection db. Return SQLITE_OK ** if successful or an error code if sqlite3_create_module() fails. */ | | | 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 | return SQLITE_OK; } /* ** Register the fts3tok module with database connection db. Return SQLITE_OK ** if successful or an error code if sqlite3_create_module() fails. */ int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash){ static const sqlite3_module fts3tok_module = { 0, /* iVersion */ fts3tokConnectMethod, /* xCreate */ fts3tokConnectMethod, /* xConnect */ fts3tokBestIndexMethod, /* xBestIndex */ fts3tokDisconnectMethod, /* xDisconnect */ fts3tokDisconnectMethod, /* xDestroy */ |
︙ | ︙ | |||
445 446 447 448 449 450 451 | 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ 0 /* xShadowName */ }; int rc; /* Return code */ | | < < | 444 445 446 447 448 449 450 451 452 453 454 455 | 0, /* xSavepoint */ 0, /* xRelease */ 0, /* xRollbackTo */ 0 /* xShadowName */ }; int rc; /* Return code */ rc = sqlite3_create_module(db, "fts3tokenize", &fts3tok_module, (void*)pHash); return rc; } #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ |
Changes to ext/fts3/fts3_tokenizer1.c.
︙ | ︙ | |||
181 182 183 184 185 186 187 | } if( c->iOffset>iStartOffset ){ int i, n = c->iOffset-iStartOffset; if( n>c->nTokenAllocated ){ char *pNew; c->nTokenAllocated = n+20; | | | 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | } if( c->iOffset>iStartOffset ){ int i, n = c->iOffset-iStartOffset; if( n>c->nTokenAllocated ){ char *pNew; c->nTokenAllocated = n+20; pNew = sqlite3_realloc(c->pToken, c->nTokenAllocated); if( !pNew ) return SQLITE_NOMEM; c->pToken = pNew; } for(i=0; i<n; i++){ /* TODO(shess) This needs expansion to handle UTF-8 ** case-insensitivity. */ |
︙ | ︙ |
Changes to ext/fts3/fts3_unicode.c.
︙ | ︙ | |||
281 282 283 284 285 286 287 | return SQLITE_NOMEM; } memset(pCsr, 0, sizeof(unicode_cursor)); pCsr->aInput = (const unsigned char *)aInput; if( aInput==0 ){ pCsr->nInput = 0; | < | 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; |
︙ | ︙ |
Changes to ext/fts3/fts3_write.c.
︙ | ︙ | |||
337 338 339 340 341 342 343 | " 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) " | | < < | 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 | " 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 %Q.'%q_segdir' WHERE level = ? AND idx < ?", /* 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 |
︙ | ︙ | |||
645 646 647 648 649 650 651 | PendingList **pp, /* IN/OUT: Pointer to PendingList struct */ sqlite3_int64 i /* Value to append to data */ ){ PendingList *p = *pp; /* Allocate or grow the PendingList as required. */ if( !p ){ | | | | | | 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 | PendingList **pp, /* IN/OUT: Pointer to PendingList struct */ sqlite3_int64 i /* Value to append to data */ ){ PendingList *p = *pp; /* Allocate or grow the PendingList as required. */ if( !p ){ p = sqlite3_malloc(sizeof(*p) + 100); if( !p ){ return SQLITE_NOMEM; } p->nSpace = 100; p->aData = (char *)&p[1]; p->nData = 0; } else if( p->nData+FTS3_VARINT_MAX+1>p->nSpace ){ int nNew = p->nSpace * 2; p = sqlite3_realloc(p, sizeof(*p) + nNew); if( !p ){ sqlite3_free(*pp); *pp = 0; return SQLITE_NOMEM; } p->nSpace = nNew; p->aData = (char *)&p[1]; } /* Append the new serialized varint to the end of the list. */ p->nData += sqlite3Fts3PutVarint(&p->aData[p->nData], i); p->aData[p->nData] = '\0'; *pp = p; |
︙ | ︙ | |||
1218 1219 1220 1221 1222 1223 1224 | ); } if( rc==SQLITE_OK ){ int nByte = sqlite3_blob_bytes(p->pSegments); *pnBlob = nByte; if( paBlob ){ | | | 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 | ); } if( rc==SQLITE_OK ){ int nByte = sqlite3_blob_bytes(p->pSegments); *pnBlob = nByte; if( paBlob ){ char *aByte = sqlite3_malloc(nByte + FTS3_NODE_PADDING); if( !aByte ){ rc = SQLITE_NOMEM; }else{ if( pnLoad && nByte>(FTS3_NODE_CHUNK_THRESHOLD) ){ nByte = FTS3_NODE_CHUNKSIZE; *pnLoad = nByte; } |
︙ | ︙ | |||
1331 1332 1333 1334 1335 1336 1337 | 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; | < < < < | < < < < < | < | | 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 | Fts3HashElem *pElem = *(pReader->ppNextElem); sqlite3_free(pReader->aNode); pReader->aNode = 0; if( pElem ){ char *aCopy; PendingList *pList = (PendingList *)fts3HashData(pElem); int nCopy = pList->nData+1; pReader->zTerm = (char *)fts3HashKey(pElem); pReader->nTerm = fts3HashKeysize(pElem); aCopy = (char*)sqlite3_malloc(nCopy); if( !aCopy ) return SQLITE_NOMEM; memcpy(aCopy, pList->aData, nCopy); pReader->nNode = pReader->nDoclist = nCopy; pReader->aNode = pReader->aDoclist = aCopy; pReader->ppNextElem++; assert( pReader->aNode ); } |
︙ | ︙ | |||
1423 1424 1425 1426 1427 1428 1429 | /* 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]) | < | 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 | /* 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]) ){ return FTS_CORRUPT_VTAB; } return SQLITE_OK; } /* |
︙ | ︙ | |||
1595 1596 1597 1598 1599 1600 1601 | /* ** Free all allocations associated with the iterator passed as the ** second argument. */ void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){ if( pReader ){ | > | > | 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 | /* ** Free all allocations associated with the iterator passed as the ** second argument. */ void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){ if( pReader ){ if( !fts3SegReaderIsPending(pReader) ){ sqlite3_free(pReader->zTerm); } if( !fts3SegReaderIsRootOnly(pReader) ){ sqlite3_free(pReader->aNode); } sqlite3_blob_close(pReader->pBlob); } sqlite3_free(pReader); } |
︙ | ︙ | |||
1630 1631 1632 1633 1634 1635 1636 | #endif if( iStartLeaf==0 ){ if( iEndLeaf!=0 ) return FTS_CORRUPT_VTAB; nExtra = nRoot + FTS3_NODE_PADDING; } | | | 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 | #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; |
︙ | ︙ | |||
1722 1723 1724 1725 1726 1727 1728 | for(pE=fts3HashFirst(pHash); pE; pE=fts3HashNext(pE)){ char *zKey = (char *)fts3HashKey(pE); int nKey = fts3HashKeysize(pE); if( nTerm==0 || (nKey>=nTerm && 0==memcmp(zKey, zTerm, nTerm)) ){ if( nElem==nAlloc ){ Fts3HashElem **aElem2; nAlloc += 16; | | | 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 | for(pE=fts3HashFirst(pHash); pE; pE=fts3HashNext(pE)){ char *zKey = (char *)fts3HashKey(pE); int nKey = fts3HashKeysize(pE); if( nTerm==0 || (nKey>=nTerm && 0==memcmp(zKey, zTerm, nTerm)) ){ if( nElem==nAlloc ){ Fts3HashElem **aElem2; nAlloc += 16; aElem2 = (Fts3HashElem **)sqlite3_realloc( aElem, nAlloc*sizeof(Fts3HashElem *) ); if( !aElem2 ){ rc = SQLITE_NOMEM; nElem = 0; break; } |
︙ | ︙ | |||
1811 1812 1813 1814 1815 1816 1817 | } }else{ rc = (pLhs->aNode==0) - (pRhs->aNode==0); } if( rc==0 ){ rc = pRhs->iIdx - pLhs->iIdx; } | | | 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 | } }else{ rc = (pLhs->aNode==0) - (pRhs->aNode==0); } if( rc==0 ){ rc = pRhs->iIdx - pLhs->iIdx; } assert( 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: |
︙ | ︙ | |||
2007 2008 2009 2010 2011 2012 2013 | 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; | > | < | 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 | 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; UNUSED_PARAMETER(nNext); for(n=0; n<nPrev && zPrev[n]==zNext[n]; n++); return n; } /* ** Add term zTerm to the SegmentNode. It is guaranteed that zTerm is larger ** (according to memcmp) than the previous term. */ |
︙ | ︙ | |||
2056 2057 2058 2059 2060 2061 2062 | ** and the static node buffer (p->nNodeSize bytes) is not large ** enough. Use a separately malloced buffer instead This wastes ** p->nNodeSize bytes, but since this scenario only comes about when ** the database contain two terms that share a prefix of almost 2KB, ** this is not expected to be a serious problem. */ assert( pTree->aData==(char *)&pTree[1] ); | | | | 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 | ** and the static node buffer (p->nNodeSize bytes) is not large ** enough. Use a separately malloced buffer instead This wastes ** p->nNodeSize bytes, but since this scenario only comes about when ** the database contain two terms that share a prefix of almost 2KB, ** this is not expected to be a serious problem. */ assert( pTree->aData==(char *)&pTree[1] ); pTree->aData = (char *)sqlite3_malloc(nReq); if( !pTree->aData ){ return SQLITE_NOMEM; } } if( pTree->zTerm ){ /* There is no prefix-length field for first term in a node */ nData += sqlite3Fts3PutVarint(&pTree->aData[nData], nPrefix); } nData += sqlite3Fts3PutVarint(&pTree->aData[nData], nSuffix); memcpy(&pTree->aData[nData], &zTerm[nPrefix], nSuffix); pTree->nData = nData + nSuffix; pTree->nEntry++; if( isCopyTerm ){ if( pTree->nMalloc<nTerm ){ char *zNew = sqlite3_realloc(pTree->zMalloc, nTerm*2); if( !zNew ){ return SQLITE_NOMEM; } pTree->nMalloc = nTerm*2; pTree->zMalloc = zNew; } pTree->zTerm = pTree->zMalloc; |
︙ | ︙ | |||
2100 2101 2102 2103 2104 2105 2106 | ** current node. Create a new node (a right-sibling of the current node). ** If this is the first node in the tree, the term is added to it. ** ** Otherwise, the term is not added to the new node, it is left empty for ** now. Instead, the term is inserted into the parent of pTree. If pTree ** has no parent, one is created here. */ | | | 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 | ** current node. Create a new node (a right-sibling of the current node). ** If this is the first node in the tree, the term is added to it. ** ** Otherwise, the term is not added to the new node, it is left empty for ** now. Instead, the term is inserted into the parent of pTree. If pTree ** has no parent, one is created here. */ pNew = (SegmentNode *)sqlite3_malloc(sizeof(SegmentNode) + p->nNodeSize); if( !pNew ){ return SQLITE_NOMEM; } memset(pNew, 0, sizeof(SegmentNode)); pNew->nData = 1 + FTS3_VARINT_MAX; pNew->aData = (char *)&pNew[1]; |
︙ | ︙ | |||
2238 2239 2240 2241 2242 2243 2244 | const char *zTerm, /* Pointer to buffer containing term */ int nTerm, /* Size of term in bytes */ const char *aDoclist, /* Pointer to buffer containing doclist */ int nDoclist /* Size of doclist in bytes */ ){ int nPrefix; /* Size of term prefix in bytes */ int nSuffix; /* Size of term suffix in bytes */ | | | | | 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 | const char *zTerm, /* Pointer to buffer containing term */ int nTerm, /* Size of term in bytes */ const char *aDoclist, /* Pointer to buffer containing doclist */ int nDoclist /* Size of doclist in bytes */ ){ int nPrefix; /* Size of term prefix in bytes */ int nSuffix; /* Size of term suffix in bytes */ int nReq; /* Number of bytes required on leaf page */ int nData; SegmentWriter *pWriter = *ppWriter; if( !pWriter ){ int rc; sqlite3_stmt *pStmt; /* Allocate the SegmentWriter structure */ pWriter = (SegmentWriter *)sqlite3_malloc(sizeof(SegmentWriter)); if( !pWriter ) return SQLITE_NOMEM; memset(pWriter, 0, sizeof(SegmentWriter)); *ppWriter = pWriter; /* Allocate a buffer in which to accumulate data */ pWriter->aData = (char *)sqlite3_malloc(p->nNodeSize); if( !pWriter->aData ) return SQLITE_NOMEM; pWriter->nSize = p->nNodeSize; /* Find the next free blockid in the %_segments table */ rc = fts3SqlStmt(p, SQL_NEXT_SEGMENTS_ID, &pStmt, 0); if( rc!=SQLITE_OK ) return rc; if( SQLITE_ROW==sqlite3_step(pStmt) ){ |
︙ | ︙ | |||
2328 2329 2330 2331 2332 2333 2334 | /* Increase the total number of bytes written to account for the new entry. */ pWriter->nLeafData += nReq; /* If the buffer currently allocated is too small for this entry, realloc ** the buffer to make it large enough. */ if( nReq>pWriter->nSize ){ | | | 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 | /* Increase the total number of bytes written to account for the new entry. */ pWriter->nLeafData += nReq; /* If the buffer currently allocated is too small for this entry, realloc ** the buffer to make it large enough. */ if( nReq>pWriter->nSize ){ char *aNew = sqlite3_realloc(pWriter->aData, nReq); if( !aNew ) return SQLITE_NOMEM; pWriter->aData = aNew; pWriter->nSize = nReq; } assert( nData+nReq<=pWriter->nSize ); /* Append the prefix-compressed term and doclist to the buffer. */ |
︙ | ︙ | |||
2353 2354 2355 2356 2357 2358 2359 | /* 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 ){ | | | 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 | /* 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; } |
︙ | ︙ | |||
2509 2510 2511 2512 2513 2514 2515 | ** (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, | | | 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 | ** (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, ((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); |
︙ | ︙ | |||
2661 2662 2663 2664 2665 2666 2667 | ** ** If successful, return SQLITE_OK. Otherwise, if an OOM error is encountered ** trying to resize the buffer, return SQLITE_NOMEM. */ static int fts3MsrBufferData( Fts3MultiSegReader *pMsr, /* Multi-segment-reader handle */ char *pList, | | | | 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 | ** ** If successful, return SQLITE_OK. Otherwise, if an OOM error is encountered ** trying to resize the buffer, return SQLITE_NOMEM. */ static int fts3MsrBufferData( Fts3MultiSegReader *pMsr, /* Multi-segment-reader handle */ char *pList, int nList ){ if( nList>pMsr->nBuffer ){ 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; |
︙ | ︙ | |||
2722 2723 2724 2725 2726 2727 2728 | rc = fts3SegReaderNextDocid(p, apSegment[j], 0, 0); j++; } if( rc!=SQLITE_OK ) return rc; fts3SegReaderSort(pMsr->apSegment, nMerge, j, xCmp); if( nList>0 && fts3SegReaderIsPending(apSegment[0]) ){ | | | 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 | rc = fts3SegReaderNextDocid(p, apSegment[j], 0, 0); j++; } if( rc!=SQLITE_OK ) return rc; fts3SegReaderSort(pMsr->apSegment, nMerge, j, xCmp); if( nList>0 && fts3SegReaderIsPending(apSegment[0]) ){ rc = fts3MsrBufferData(pMsr, pList, nList+1); if( rc!=SQLITE_OK ) return rc; assert( (pMsr->aBuffer[nList] & 0xFE)==0x00 ); pList = pMsr->aBuffer; } if( pMsr->iColFilter>=0 ){ fts3ColumnFilter(pMsr->iColFilter, 1, &pList, &nList); |
︙ | ︙ | |||
2859 2860 2861 2862 2863 2864 2865 | pCsr->apSegment[i]->nOffsetList = 0; pCsr->apSegment[i]->iDocid = 0; } return SQLITE_OK; } | < < < < < < < < < < < < < | 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 | 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; |
︙ | ︙ | |||
2954 2955 2956 2957 2958 2959 2960 | if( nMerge==1 && !isIgnoreEmpty && !isFirst && (p->bDescIdx==0 || fts3SegReaderIsPending(apSegment[0])==0) ){ pCsr->nDoclist = apSegment[0]->nDoclist; if( fts3SegReaderIsPending(apSegment[0]) ){ | | < | 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 | if( nMerge==1 && !isIgnoreEmpty && !isFirst && (p->bDescIdx==0 || fts3SegReaderIsPending(apSegment[0])==0) ){ pCsr->nDoclist = apSegment[0]->nDoclist; if( fts3SegReaderIsPending(apSegment[0]) ){ rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist, pCsr->nDoclist); pCsr->aDoclist = pCsr->aBuffer; }else{ pCsr->aDoclist = apSegment[0]->aDoclist; } if( rc==SQLITE_OK ) rc = SQLITE_ROW; }else{ int nDoclist = 0; /* Size of doclist */ |
︙ | ︙ | |||
3007 3008 3009 3010 3011 3012 3013 | 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); | > > > > > > | | < < > | 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 | 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); if( nDoclist+nByte>pCsr->nBuffer ){ char *aNew; pCsr->nBuffer = (nDoclist+nByte)*2; aNew = sqlite3_realloc(pCsr->aBuffer, pCsr->nBuffer); if( !aNew ){ return SQLITE_NOMEM; } pCsr->aBuffer = aNew; } if( isFirst ){ char *a = &pCsr->aBuffer[nDoclist]; int nWrite; nWrite = sqlite3Fts3FirstFilter(iDelta, pList, nList, a); if( nWrite ){ |
︙ | ︙ | |||
3035 3036 3037 3038 3039 3040 3041 | } } } fts3SegReaderSort(apSegment, nMerge, j, xCmp); } if( nDoclist>0 ){ | < < < | 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 | } } } 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 ); |
︙ | ︙ | |||
3087 3088 3089 3090 3091 3092 3093 | i64 *piEndBlock, i64 *pnByte ){ const unsigned char *zText = sqlite3_column_text(pStmt, iCol); if( zText ){ int i; int iMul = 1; | | | | | 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 | i64 *piEndBlock, i64 *pnByte ){ const unsigned char *zText = sqlite3_column_text(pStmt, iCol); if( zText ){ int i; int iMul = 1; i64 iVal = 0; for(i=0; zText[i]>='0' && zText[i]<='9'; i++){ iVal = iVal*10 + (zText[i] - '0'); } *piEndBlock = 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 = (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. |
︙ | ︙ | |||
3748 3749 3750 3751 3752 3753 3754 | ** If an OOM error occurs, set *pRc to SQLITE_NOMEM and leave pBlob->a ** unmodified. Otherwise, if the allocation succeeds, update pBlob->nAlloc ** to reflect the new size of the pBlob->a[] buffer. */ static void blobGrowBuffer(Blob *pBlob, int nMin, int *pRc){ if( *pRc==SQLITE_OK && nMin>pBlob->nAlloc ){ int nAlloc = nMin; | | | 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 | ** If an OOM error occurs, set *pRc to SQLITE_NOMEM and leave pBlob->a ** unmodified. Otherwise, if the allocation succeeds, update pBlob->nAlloc ** to reflect the new size of the pBlob->a[] buffer. */ static void blobGrowBuffer(Blob *pBlob, int nMin, int *pRc){ if( *pRc==SQLITE_OK && nMin>pBlob->nAlloc ){ int nAlloc = nMin; char *a = (char *)sqlite3_realloc(pBlob->a, nAlloc); if( a ){ pBlob->nAlloc = nAlloc; pBlob->a = a; }else{ *pRc = SQLITE_NOMEM; } } |
︙ | ︙ | |||
3789 3790 3791 3792 3793 3794 3795 | } 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); | | | 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 | } 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 ){ 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; |
︙ | ︙ | |||
3897 3898 3899 3900 3901 3902 3903 | blobGrowBuffer(&pNode->key, nTerm, &rc); if( rc==SQLITE_OK ){ if( pNode->key.n ){ pBlk->n += sqlite3Fts3PutVarint(&pBlk->a[pBlk->n], nPrefix); } pBlk->n += sqlite3Fts3PutVarint(&pBlk->a[pBlk->n], nSuffix); | < < | 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 | blobGrowBuffer(&pNode->key, nTerm, &rc); if( rc==SQLITE_OK ){ if( pNode->key.n ){ pBlk->n += sqlite3Fts3PutVarint(&pBlk->a[pBlk->n], nPrefix); } pBlk->n += sqlite3Fts3PutVarint(&pBlk->a[pBlk->n], nSuffix); memcpy(&pBlk->a[pBlk->n], &zTerm[nPrefix], nSuffix); pBlk->n += nSuffix; memcpy(pNode->key.a, zTerm, nTerm); pNode->key.n = nTerm; } }else{ |
︙ | ︙ | |||
4021 4022 4023 4024 4025 4026 4027 | int nPrefix; /* Size of prefix shared with previous term */ int nSuffix; /* Size of suffix (nTerm - nPrefix) */ NodeWriter *pLeaf; /* Object used to write leaf nodes */ pLeaf = &pWriter->aNodeWriter[0]; nPrefix = fts3PrefixCompress(pLeaf->key.a, pLeaf->key.n, zTerm, nTerm); nSuffix = nTerm - nPrefix; | < | 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 | int nPrefix; /* Size of prefix shared with previous term */ int nSuffix; /* Size of suffix (nTerm - nPrefix) */ NodeWriter *pLeaf; /* Object used to write leaf nodes */ pLeaf = &pWriter->aNodeWriter[0]; nPrefix = fts3PrefixCompress(pLeaf->key.a, pLeaf->key.n, zTerm, nTerm); nSuffix = nTerm - nPrefix; nSpace = sqlite3Fts3VarintLen(nPrefix); nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix; nSpace += sqlite3Fts3VarintLen(nDoclist) + nDoclist; /* If the current block is not empty, and if adding this term/doclist ** to the current block would make it larger than Fts3Table.nNodeSize |
︙ | ︙ | |||
4186 4187 4188 4189 4190 4191 4192 | 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; | < | < < < | 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 | 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; res = (nCmp ? memcmp(zLhs, zRhs, nCmp) : 0); if( res==0 ) res = nLhs - nRhs; return res; } /* |
︙ | ︙ | |||
4313 4314 4315 4316 4317 4318 4319 | 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; | | | 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 | 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; |
︙ | ︙ | |||
4348 4349 4350 4351 4352 4353 4354 | 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 ){ | < < | < | | | 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 | 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 ){ 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); } |
︙ | ︙ | |||
4545 4546 4547 4548 4549 4550 4551 | if( rc==SQLITE_OK ){ int rc2; sqlite3_bind_int64(pSelect, 1, iAbsLevel); while( SQLITE_ROW==sqlite3_step(pSelect) ){ if( nIdx>=nAlloc ){ int *aNew; nAlloc += 16; | | | 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 | if( rc==SQLITE_OK ){ int rc2; sqlite3_bind_int64(pSelect, 1, iAbsLevel); while( SQLITE_ROW==sqlite3_step(pSelect) ){ if( nIdx>=nAlloc ){ int *aNew; nAlloc += 16; aNew = sqlite3_realloc(aIdx, nAlloc*sizeof(int)); if( !aNew ){ rc = SQLITE_NOMEM; break; } aIdx = aNew; } aIdx[nIdx++] = sqlite3_column_int(pSelect, 0); |
︙ | ︙ | |||
4834 4835 4836 4837 4838 4839 4840 | 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 ){ | | | 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 | 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 ){ memcpy(pHint->a, aHint, nHint); pHint->n = nHint; } } } rc2 = sqlite3_reset(pSelect); if( rc==SQLITE_OK ) rc = rc2; } |
︙ | ︙ | |||
4919 4920 4921 4922 4923 4924 4925 | int nSeg = 0; /* Number of input segments */ sqlite3_int64 iAbsLevel = 0; /* Absolute level number to work on */ Blob hint = {0, 0, 0}; /* Hint read from %_stat table */ int bDirtyHint = 0; /* True if blob 'hint' has been modified */ /* Allocate space for the cursor, filter and writer objects */ const int nAlloc = sizeof(*pCsr) + sizeof(*pFilter) + sizeof(*pWriter); | | | 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 | int nSeg = 0; /* Number of input segments */ sqlite3_int64 iAbsLevel = 0; /* Absolute level number to work on */ Blob hint = {0, 0, 0}; /* Hint read from %_stat table */ int bDirtyHint = 0; /* True if blob 'hint' has been modified */ /* Allocate space for the cursor, filter and writer objects */ const int nAlloc = sizeof(*pCsr) + sizeof(*pFilter) + sizeof(*pWriter); pWriter = (IncrmergeWriter *)sqlite3_malloc(nAlloc); if( !pWriter ) return SQLITE_NOMEM; pFilter = (Fts3SegFilter *)&pWriter[1]; pCsr = (Fts3MultiSegReader *)&pFilter[1]; rc = fts3IncrmergeHintLoad(p, &hint); while( rc==SQLITE_OK && nRem>0 ){ const i64 nMod = FTS3_SEGDIR_MAXLEVEL * p->nIndex; |
︙ | ︙ | |||
4982 4983 4984 4985 4986 4987 4988 | } /* 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; | < < < < < < | 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 | } /* 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; /* 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. */ memset(pWriter, 0, nAlloc); |
︙ | ︙ | |||
5555 5556 5557 5558 5559 5560 5561 | *ppData = 0; *pnData = 0; if( p->pList==0 ){ return SQLITE_OK; } | | | | 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 | *ppData = 0; *pnData = 0; if( p->pList==0 ){ return SQLITE_OK; } pRet = (char *)sqlite3_malloc(p->pList->nData); if( !pRet ) return SQLITE_NOMEM; nSkip = sqlite3Fts3GetVarint(p->pList->aData, &dummy); *pnData = p->pList->nData - nSkip; *ppData = pRet; memcpy(pRet, &p->pList->aData[nSkip], *pnData); return SQLITE_OK; } /* ** Add an entry for token pToken to the pCsr->pDeferred list. */ int sqlite3Fts3DeferToken( Fts3Cursor *pCsr, /* Fts3 table cursor */ Fts3PhraseToken *pToken, /* Token to defer */ int iCol /* Column that token must appear in (or -1) */ ){ Fts3DeferredToken *pDeferred; pDeferred = sqlite3_malloc(sizeof(*pDeferred)); if( !pDeferred ){ return SQLITE_NOMEM; } memset(pDeferred, 0, sizeof(*pDeferred)); pDeferred->pToken = pToken; pDeferred->pNext = pCsr->pDeferred; pDeferred->iCol = iCol; |
︙ | ︙ |
Added ext/fts3/mkfts3amal.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 | #!/usr/bin/tclsh # # This script builds a single C code file holding all of FTS3 code. # The name of the output file is fts3amal.c. To build this file, # first do: # # make target_source # # The make target above moves all of the source code files into # a subdirectory named "tsrc". (This script expects to find the files # there and will not work if they are not found.) # # After the "tsrc" directory has been created and populated, run # this script: # # tclsh mkfts3amal.tcl # # The amalgamated FTS3 code will be written into fts3amal.c # # Open the output file and write a header comment at the beginning # of the file. # set out [open fts3amal.c w] set today [clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S UTC" -gmt 1] puts $out [subst \ {/****************************************************************************** ** This file is an amalgamation of separate C source files from the SQLite ** Full Text Search extension 2 (fts3). By combining all the individual C ** code files into this single large file, the entire code can be compiled ** as a one translation unit. This allows many compilers to do optimizations ** that would not be possible if the files were compiled separately. It also ** makes the code easier to import into other projects. ** ** This amalgamation was generated on $today. */}] # These are the header files used by FTS3. 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 { fts3.h fts3_hash.h fts3_tokenizer.h sqlite3.h sqlite3ext.h } { set available_hdr($hdr) 1 } # 78 stars used for comment formatting. set s78 \ {*****************************************************************************} # Insert a comment into the code # proc section_comment {text} { global out s78 set n [string length $text] set nstar [expr {60 - $n}] set stars [string range $s78 0 $nstar] puts $out "/************** $text $stars/" } # Read the source file named $filename and write it into the # sqlite3.c output file. If any #include statements are seen, # process them approprately. # proc copy_file {filename} { global seen_hdr available_hdr out set tail [file tail $filename] section_comment "Begin file $tail" set in [open $filename r] while {![eof $in]} { set line [gets $in] if {[regexp {^#\s*include\s+["<]([^">]+)[">]} $line all hdr]} { if {[info exists available_hdr($hdr)]} { if {$available_hdr($hdr)} { section_comment "Include $hdr in the middle of $tail" copy_file tsrc/$hdr section_comment "Continuing where we left off in $tail" } } elseif {![info exists seen_hdr($hdr)]} { set seen_hdr($hdr) 1 puts $out $line } } elseif {[regexp {^#ifdef __cplusplus} $line]} { puts $out "#if 0" } elseif {[regexp {^#line} $line]} { # Skip #line directives. } else { puts $out $line } } close $in section_comment "End of $tail" } # Process the source files. Process files containing commonly # used subroutines first in order to help the compiler find # inlining opportunities. # foreach file { fts3.c fts3_hash.c fts3_porter.c fts3_tokenizer.c fts3_tokenizer1.c } { copy_file tsrc/$file } close $out |
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_master" " 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_master a, sqlite_master 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.
︙ | ︙ | |||
738 739 740 741 742 743 744 | int bToken = aArray[ aFts5UnicodeData[iTbl] & 0x1F ]; int n = (aFts5UnicodeData[iTbl] >> 5) + i; for(; i<128 && i<n; i++){ aAscii[i] = (u8)bToken; } iTbl++; } | < | 738 739 740 741 742 743 744 745 746 747 748 749 750 751 | int bToken = aArray[ aFts5UnicodeData[iTbl] & 0x1F ]; int n = (aFts5UnicodeData[iTbl] >> 5) + i; for(; i<128 && i<n; i++){ aAscii[i] = (u8)bToken; } iTbl++; } } }] } proc print_test_categories {lMap} { set lCP [list] |
︙ | ︙ |
Changes to ext/fts5/fts5.h.
︙ | ︙ | |||
155 156 157 158 159 160 161 | ** 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 | ** 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 functions ** "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 |
︙ | ︙ | |||
397 398 399 400 401 402 403 | ** 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, the ** In 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 | typedef sqlite3_uint64 u64; #ifndef ArraySize # define ArraySize(x) ((int)(sizeof(x) / sizeof(x[0]))) #endif #define testcase(x) #define ALWAYS(x) 1 #define NEVER(x) 0 #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. */ |
︙ | ︙ | |||
69 70 71 72 73 74 75 | /* ** 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 | < < < < < | 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" |
︙ | ︙ | |||
104 105 106 107 108 109 110 | # 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. */ | | | 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | # 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 |
︙ | ︙ | |||
191 192 193 194 195 196 197 | 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; | < < | | | | | < < | 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 | 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 */ #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 int sqlite3Fts5ConfigParse( Fts5Global*, sqlite3*, int, const char **, Fts5Config**, char** ); void sqlite3Fts5ConfigFree(Fts5Config*); int sqlite3Fts5ConfigDeclareVtab(Fts5Config *pConfig); |
︙ | ︙ | |||
282 283 284 285 286 287 288 | void sqlite3Fts5BufferZero(Fts5Buffer*); void sqlite3Fts5BufferSet(int*, Fts5Buffer*, int, const u8*); void sqlite3Fts5BufferAppendPrintf(int *, Fts5Buffer*, char *zFmt, ...); char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...); #define fts5BufferZero(x) sqlite3Fts5BufferZero(x) | | | 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 | void sqlite3Fts5BufferZero(Fts5Buffer*); void sqlite3Fts5BufferSet(int*, Fts5Buffer*, int, const u8*); void sqlite3Fts5BufferAppendPrintf(int *, Fts5Buffer*, char *zFmt, ...); char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...); #define fts5BufferZero(x) sqlite3Fts5BufferZero(x) #define fts5BufferAppendVarint(a,b,c) sqlite3Fts5BufferAppendVarint(a,b,c) #define fts5BufferFree(a) sqlite3Fts5BufferFree(a) #define fts5BufferAppendBlob(a,b,c,d) sqlite3Fts5BufferAppendBlob(a,b,c,d) #define fts5BufferSet(a,b,c,d) sqlite3Fts5BufferSet(a,b,c,d) #define fts5BufferGrow(pRc,pBuf,nn) ( \ (u32)((pBuf)->n) + (u32)(nn) <= (u32)((pBuf)->nSpace) ? 0 : \ sqlite3Fts5BufferSize((pRc),(pBuf),(nn)+(pBuf)->n) \ |
︙ | ︙ | |||
433 434 435 436 437 438 439 | int sqlite3Fts5IterNextFrom(Fts5IndexIter*, i64 iMatch); /* ** Close an iterator opened by sqlite3Fts5IndexQuery(). */ void sqlite3Fts5IterClose(Fts5IndexIter*); | < < < < < < < < | 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 | 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. ** |
︙ | ︙ | |||
498 499 500 501 502 503 504 | */ 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. */ | | | 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 | */ 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); /* ** Called during virtual module initialization to register UDF ** fts5_decode() with SQLite */ int sqlite3Fts5IndexInit(sqlite3*); |
︙ | ︙ | |||
568 569 570 571 572 573 574 | Fts5Index *pIndex; /* Full-text index */ }; int sqlite3Fts5GetTokenizer( Fts5Global*, const char **azArg, int nArg, | | > | 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 | Fts5Index *pIndex; /* Full-text index */ }; int sqlite3Fts5GetTokenizer( Fts5Global*, const char **azArg, int nArg, Fts5Tokenizer**, fts5_tokenizer**, char **pzErr ); Fts5Table *sqlite3Fts5TableFromCsrid(Fts5Global*, i64); int sqlite3Fts5FlushToDisk(Fts5Table*); |
︙ | ︙ | |||
652 653 654 655 656 657 658 | 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); | | | 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 | 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 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); |
︙ | ︙ | |||
697 698 699 700 701 702 703 | const char *p; /* Token text (not NULL terminated) */ int n; /* Size of buffer p in bytes */ }; /* Parse a MATCH expression. */ int sqlite3Fts5ExprNew( Fts5Config *pConfig, | < < < < < < < < < | 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 | 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 **); |
︙ | ︙ | |||
818 819 820 821 822 823 824 | **************************************************************************/ /************************************************************************** ** Interface to code in fts5_tokenizer.c. */ int sqlite3Fts5TokenizerInit(fts5_api*); | < < < < | 781 782 783 784 785 786 787 788 789 790 791 792 793 794 | **************************************************************************/ /************************************************************************** ** 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. */ |
︙ | ︙ |
Changes to ext/fts5/fts5_aux.c.
︙ | ︙ | |||
562 563 564 565 566 567 568 | 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 | 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 = 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; |
︙ | ︙ | |||
636 637 638 639 640 641 642 | 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 = SQLITE_OK; /* 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 */ |
︙ | ︙ | |||
668 669 670 671 672 673 674 | /* 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 691 692 | /* 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 the BM25 score for the current row. */ for(i=0; rc==SQLITE_OK && i<pData->nPhrase; i++){ score += pData->aIDF[i] * ( ( aFreq[i] * (k1 + 1.0) ) / ( aFreq[i] + k1 * (1 - b + b * D / pData->avgdl) ) ); } /* If no error has occurred, return the calculated score. Otherwise, ** throw an SQL exception. */ if( rc==SQLITE_OK ){ sqlite3_result_double(pCtx, -1.0 * score); }else{ sqlite3_result_error_code(pCtx, rc); } } int sqlite3Fts5AuxInit(fts5_api *pApi){ |
︙ | ︙ |
Changes to ext/fts5/fts5_buffer.c.
︙ | ︙ | |||
62 63 64 65 66 67 68 69 70 71 72 73 74 75 | */ 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; } } | > | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | */ void sqlite3Fts5BufferAppendBlob( int *pRc, Fts5Buffer *pBuf, u32 nData, const u8 *pData ){ assert_nc( *pRc || nData>=0 ); if( nData ){ if( fts5BufferGrow(pRc, pBuf, nData) ) return; memcpy(&pBuf->p[pBuf->n], pData, nData); pBuf->n += nData; } } |
︙ | ︙ | |||
171 172 173 174 175 176 177 | int i = *pi; if( i>=n ){ /* EOF */ *piOff = -1; return 1; }else{ i64 iOff = *piOff; | | | < < < < < < < < < | | < < < < | 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | int i = *pi; if( i>=n ){ /* EOF */ *piOff = -1; return 1; }else{ i64 iOff = *piOff; int iVal; fts5FastGetVarint32(a, i, iVal); if( iVal==1 ){ fts5FastGetVarint32(a, i, iVal); iOff = ((i64)iVal) << 32; fts5FastGetVarint32(a, i, iVal); } *piOff = iOff + ((iVal-2) & 0x7FFFFFFF); *pi = i; return 0; } } /* ** Advance the iterator object passed as the only argument. Return true |
︙ | ︙ | |||
231 232 233 234 235 236 237 | ** to iPos before returning. */ void sqlite3Fts5PoslistSafeAppend( Fts5Buffer *pBuf, i64 *piPrev, i64 iPos ){ | < | | | | | | | | < | 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | ** to iPos before returning. */ void sqlite3Fts5PoslistSafeAppend( Fts5Buffer *pBuf, i64 *piPrev, i64 iPos ){ 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 ){ |
︙ | ︙ |
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 (128*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( ALWAYS(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 |
︙ | ︙ | |||
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->pTok, &pConfig->pTokApi, 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 408 409 | /* ** 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->pTok, &pConfig->pTokApi, 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). |
︙ | ︙ | |||
533 534 535 536 537 538 539 | 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); | | | 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 | 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 = (u8*)&pRet->azCol[nArg]; 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 |
︙ | ︙ | |||
558 559 560 561 562 563 564 | int bOption = 0; int bMustBeCol = 0; z = fts5ConfigGobbleWord(&rc, zOrig, &zOne, &bMustBeCol); z = fts5ConfigSkipWhitespace(z); if( z && *z=='=' ){ bOption = 1; | < | < < < < | 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 | 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 ){ rc = fts5ConfigParseSpecial(pGlobal, pRet, zOne, zTwo?zTwo:"", pzErr); }else{ rc = fts5ConfigParseColumn(pRet, zOne, zTwo, pzErr); zOne = 0; } } } |
︙ | ︙ | |||
682 683 684 685 686 687 688 | ); assert( zSql || rc==SQLITE_NOMEM ); if( zSql ){ rc = sqlite3_declare_vtab(pConfig->db, zSql); sqlite3_free(zSql); } | | | 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 | ); 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 |
︙ | ︙ | |||
827 828 829 830 831 832 833 | 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); } | | | 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 | 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<=0 || pgsz>FTS5_MAX_PAGE_SIZE ){ *pbBadkey = 1; }else{ pConfig->pgsz = pgsz; } } else if( 0==sqlite3_stricmp(zKey, "hashsize") ){ |
︙ | ︙ | |||
880 881 882 883 884 885 886 | 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; | < | 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; |
︙ | ︙ |
Changes to ext/fts5/fts5_expr.c.
︙ | ︙ | |||
124 125 126 127 128 129 130 | 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 */ | < < | 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){ |
︙ | ︙ | |||
214 215 216 217 218 219 220 | } 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 */ | < < | 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 | } 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 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)); pEngine = sqlite3Fts5ParserAlloc(fts5ParseAlloc); if( pEngine==0 ){ return SQLITE_NOMEM; } sParse.pConfig = pConfig; do { t = fts5ExprGetToken(&sParse, &z, &token); sqlite3Fts5Parser(pEngine, t, token, &sParse); |
︙ | ︙ | |||
273 274 275 276 277 278 279 | }else{ pNew->pRoot = sParse.pExpr; } pNew->pIndex = 0; pNew->pConfig = pConfig; pNew->apExprPhrase = sParse.apPhrase; pNew->nPhrase = sParse.nPhrase; | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | }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; for(i=0; i<p->nChild; i++){ |
︙ | ︙ | |||
399 400 401 402 403 404 405 | if( p ){ sqlite3Fts5ParseNodeFree(p->pRoot); sqlite3_free(p->apExprPhrase); sqlite3_free(p); } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | 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; |
︙ | ︙ | |||
1512 1513 1514 1515 1516 1517 1518 | && 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. */ | | | | 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 | && 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 ){ assert( pRoot->bEof==0 && rc==SQLITE_OK ); rc = fts5ExprNodeNext(p, pRoot, 0, 0); } return rc; } /* ** Move to the next document |
︙ | ︙ | |||
1637 1638 1639 1640 1641 1642 1643 | if( pRet==0 ){ assert( pParse->rc!=SQLITE_OK ); sqlite3Fts5ParseNearsetFree(pNear); sqlite3Fts5ParsePhraseFree(pPhrase); }else{ if( pRet->nPhrase>0 ){ Fts5ExprPhrase *pLast = pRet->apPhrase[pRet->nPhrase-1]; | < < < | 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 | if( pRet==0 ){ assert( pParse->rc!=SQLITE_OK ); sqlite3Fts5ParseNearsetFree(pNear); sqlite3Fts5ParsePhraseFree(pPhrase); }else{ if( pRet->nPhrase>0 ){ Fts5ExprPhrase *pLast = pRet->apPhrase[pRet->nPhrase-1]; assert( pLast==pParse->apPhrase[pParse->nPhrase-2] ); if( pPhrase->nTerm==0 ){ fts5ExprPhraseFree(pPhrase); pRet->nPhrase--; pParse->nPhrase--; pPhrase = pLast; }else if( pLast->nTerm==0 ){ |
︙ | ︙ | |||
1755 1756 1757 1758 1759 1760 1761 | } void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p){ assert( pParse->pExpr==0 ); pParse->pExpr = p; } | < < < < < < < < < < < < < < | 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 | } 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( Fts5Parse *pParse, /* Parse context */ |
︙ | ︙ | |||
1804 1805 1806 1807 1808 1809 1810 | if( rc || (rc = sCtx.rc) ){ pParse->rc = rc; fts5ExprPhraseFree(sCtx.pPhrase); sCtx.pPhrase = 0; }else{ if( pAppend==0 ){ | > > | > > > | | > > | 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 | if( rc || (rc = sCtx.rc) ){ pParse->rc = rc; fts5ExprPhraseFree(sCtx.pPhrase); sCtx.pPhrase = 0; }else{ if( pAppend==0 ){ 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; fts5ExprPhraseFree(sCtx.pPhrase); return 0; } pParse->apPhrase = apNew; } 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 '""'). */ |
︙ | ︙ | |||
1888 1889 1890 1891 1892 1893 1894 | } }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)); } | | | 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 | } }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 ){ /* 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; |
︙ | ︙ | |||
2159 2160 2161 2162 2163 2164 2165 | void sqlite3Fts5ParseSetColset( Fts5Parse *pParse, Fts5ExprNode *pExpr, Fts5Colset *pColset ){ Fts5Colset *pFree = pColset; if( pParse->pConfig->eDetail==FTS5_DETAIL_NONE ){ | > | | | 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 | void sqlite3Fts5ParseSetColset( Fts5Parse *pParse, Fts5ExprNode *pExpr, Fts5Colset *pColset ){ Fts5Colset *pFree = pColset; if( pParse->pConfig->eDetail==FTS5_DETAIL_NONE ){ pParse->rc = SQLITE_ERROR; pParse->zErr = sqlite3_mprintf( "fts5: column queries are not supported (detail=none)" ); }else{ fts5ParseSetColset(pParse, pExpr, pColset, &pFree); } sqlite3_free(pFree); } |
︙ | ︙ | |||
2212 2213 2214 2215 2216 2217 2218 | p->nChild += pSub->nChild; sqlite3_free(pSub); }else{ p->apChild[p->nChild++] = pSub; } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 | 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 */ |
︙ | ︙ | |||
2297 2298 2299 2300 2301 2302 2303 | 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; | < < < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > | | | | | | | | | | | < | 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 | 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_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) ){ assert( pParse->rc==SQLITE_OK ); pParse->rc = SQLITE_ERROR; assert( pParse->zErr==0 ); pParse->zErr = sqlite3_mprintf( "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); |
︙ | ︙ | |||
2423 2424 2425 2426 2427 2428 2429 | pRet = sqlite3Fts5ParseNode(pParse, FTS5_AND, pLeft, pRight, 0); } } return pRet; } | < | 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 | pRet = sqlite3Fts5ParseNode(pParse, FTS5_AND, pLeft, pRight, 0); } } return pRet; } 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){ |
︙ | ︙ | |||
2567 2568 2569 2570 2571 2572 2573 | }else if( pExpr->eType==FTS5_STRING || pExpr->eType==FTS5_TERM ){ Fts5ExprNearset *pNear = pExpr->pNear; int i; int iTerm; if( pNear->pColset ){ | < | < < < < < < < | < | 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 | }else if( pExpr->eType==FTS5_STRING || pExpr->eType==FTS5_TERM ){ Fts5ExprNearset *pNear = pExpr->pNear; int i; int iTerm; if( pNear->pColset ){ int iCol = pNear->pColset->aiCol[0]; zRet = fts5PrintfAppend(zRet, "%s : ", pConfig->azCol[iCol]); if( zRet==0 ) return 0; } if( pNear->nPhrase>1 ){ zRet = fts5PrintfAppend(zRet, "NEAR("); if( zRet==0 ) return 0; } |
︙ | ︙ | |||
2691 2692 2693 2694 2695 2696 2697 | sqlite3_result_error_nomem(pCtx); return; } azConfig[0] = 0; azConfig[1] = "main"; azConfig[2] = "tbl"; for(i=3; iArg<nArg; iArg++){ | | < < | | 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 | sqlite3_result_error_nomem(pCtx); return; } azConfig[0] = 0; azConfig[1] = "main"; azConfig[2] = "tbl"; for(i=3; iArg<nArg; iArg++){ azConfig[i++] = (const char*)sqlite3_value_text(apVal[iArg]); } zExpr = (const char*)sqlite3_value_text(apVal[0]); rc = sqlite3Fts5ConfigParse(pGlobal, db, nConfig, azConfig, &pConfig, &zErr); if( rc==SQLITE_OK ){ rc = sqlite3Fts5ExprNew(pConfig, 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); |
︙ | ︙ | |||
2790 2791 2792 2793 2794 2795 2796 | 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)); } } | < < < < < < | 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 | 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)); } } /* ** 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){ 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); } /* Avoid warnings indicating that sqlite3Fts5ParserTrace() and ** sqlite3Fts5ParserFallback() are unused */ #ifndef NDEBUG (void)sqlite3Fts5ParserTrace; #endif (void)sqlite3Fts5ParserFallback; |
︙ | ︙ | |||
2869 2870 2871 2872 2873 2874 2875 | struct Fts5PoslistPopulator { Fts5PoslistWriter writer; int bOk; /* True if ok to populate */ int bMiss; }; | < < < < < < < < < | | 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 | struct Fts5PoslistPopulator { Fts5PoslistWriter writer; int bOk; /* True if ok to populate */ int bMiss; }; 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; } |
︙ | ︙ |
Changes to ext/fts5/fts5_hash.c.
︙ | ︙ | |||
302 303 304 305 306 307 308 309 310 311 312 313 314 315 | 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, | > | 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 | p->iSzPoslist = p->nData; if( pHash->eDetail!=FTS5_DETAIL_NONE ){ p->nData += 1; p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1); } nIncr += p->nData; }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, |
︙ | ︙ | |||
334 335 336 337 338 339 340 | 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 ){ | < | | | 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 | 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 ){ fts5HashAddPoslistSize(pHash, p, 0); p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iRowid - p->iRowid); 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( 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{ |
︙ | ︙ |
Changes to ext/fts5/fts5_index.c.
︙ | ︙ | |||
50 51 52 53 54 55 56 | #define FTS5_MAIN_PREFIX '0' #if FTS5_MAX_PREFIX_INDEXES > 31 # error "FTS5_MAX_PREFIX_INDEXES is too large" #endif | < < | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | #define FTS5_MAIN_PREFIX '0' #if FTS5_MAX_PREFIX_INDEXES > 31 # error "FTS5_MAX_PREFIX_INDEXES is too large" #endif /* ** Details: ** ** The %_data table managed by this module, ** ** CREATE TABLE %_data(id INTEGER PRIMARY KEY, block BLOB); ** |
︙ | ︙ | |||
237 238 239 240 241 242 243 244 245 246 247 248 249 250 | ((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 | > > > > > | 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 | ((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) /* ** Maximum segments permitted in a single index */ #define FTS5_MAX_SEGMENT 2000 #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 |
︙ | ︙ | |||
294 295 296 297 298 299 300 | int rc; /* Current error code */ /* State used by the fts5DataXXX() functions. */ sqlite3_blob *pReader; /* RO incr-blob open on %_data table */ sqlite3_stmt *pWriter; /* "INSERT ... %_data VALUES(?,?)" */ sqlite3_stmt *pDeleter; /* "DELETE FROM %_data ... id>=? AND id<=?" */ sqlite3_stmt *pIdxWriter; /* "INSERT ... %_idx VALUES(?,?,?,?)" */ | | | 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | int rc; /* Current error code */ /* State used by the fts5DataXXX() functions. */ sqlite3_blob *pReader; /* RO incr-blob open on %_data table */ sqlite3_stmt *pWriter; /* "INSERT ... %_data VALUES(?,?)" */ sqlite3_stmt *pDeleter; /* "DELETE FROM %_data ... id>=? AND id<=?" */ sqlite3_stmt *pIdxWriter; /* "INSERT ... %_idx VALUES(?,?,?,?)" */ sqlite3_stmt *pIdxDeleter; /* "DELETE FROM %_idx WHERE segid=? */ sqlite3_stmt *pIdxSelect; int nRead; /* Total number of blocks read */ sqlite3_stmt *pDataVersion; i64 iStructVersion; /* data_version when pStruct read */ Fts5Structure *pStruct; /* Current db structure (or NULL) */ }; |
︙ | ︙ | |||
429 430 431 432 433 434 435 | */ 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) */ | | | 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 | */ 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) */ int 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; |
︙ | ︙ | |||
598 599 600 601 602 603 604 | ** ** 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){ | < | < < | | | 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 | ** ** 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 = MIN(pLeft->n, pRight->n); int 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. */ static void fts5CloseReader(Fts5Index *p){ if( p->pReader ){ sqlite3_blob *pReader = p->pReader; p->pReader = 0; sqlite3_blob_close(pReader); } } |
︙ | ︙ | |||
644 645 646 647 648 649 650 | ** 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 ){ | | | 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 | ** 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 ){ fts5CloseReader(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 ){ |
︙ | ︙ | |||
686 687 688 689 690 691 692 | } if( rc!=SQLITE_OK ){ sqlite3_free(pRet); pRet = 0; }else{ /* TODO1: Fix this */ pRet->p[nByte] = 0x00; | < < | | 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 | } if( rc!=SQLITE_OK ){ sqlite3_free(pRet); pRet = 0; }else{ /* TODO1: Fix this */ pRet->p[nByte] = 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->szLeaf>pRet->nn ){ p->rc = FTS5_CORRUPT; fts5DataRelease(pRet); pRet = 0; } } return pRet; } |
︙ | ︙ | |||
823 824 825 826 827 828 829 | } } static void fts5StructureRef(Fts5Structure *pStruct){ pStruct->nRef++; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 821 822 823 824 825 826 827 828 829 830 831 832 833 834 | } } 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 ** to be more easily edited. |
︙ | ︙ | |||
976 977 978 979 980 981 982 | } *ppOut = pRet; return rc; } /* | < | < | 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 | } *ppOut = pRet; return rc; } /* ** */ static void fts5StructureAddLevel(int *pRc, Fts5Structure **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 */ ); |
︙ | ︙ | |||
1044 1045 1046 1047 1048 1049 1050 | 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); | | | 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 | 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->iCookie!=iCookie ){ p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie); } fts5DataRelease(pData); if( p->rc!=SQLITE_OK ){ fts5StructureRelease(pRet); pRet = 0; } |
︙ | ︙ | |||
1667 1668 1669 1670 1671 1672 1673 | } pIter->iLeafOffset = iOff; } } static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){ u8 *a = pIter->pLeaf->p; /* Buffer to read data from */ | | | 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 | } pIter->iLeafOffset = iOff; } } static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){ u8 *a = pIter->pLeaf->p; /* Buffer to read data from */ int 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; |
︙ | ︙ | |||
1700 1701 1702 1703 1704 1705 1706 | ** ** 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 */ | | | 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 | ** ** 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 */ int 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; } |
︙ | ︙ | |||
1774 1775 1776 1777 1778 1779 1780 | pIter->pSeg = pSeg; pIter->iLeafPgno = pSeg->pgnoFirst-1; fts5SegIterNextPage(p, pIter); } if( p->rc==SQLITE_OK ){ pIter->iLeafOffset = 4; | < | 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 | 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 ); assert_nc( fts5LeafFirstTermOff(pIter->pLeaf)==4 ); pIter->iPgidxOff = pIter->pLeaf->szLeaf+1; fts5SegIterLoadTerm(p, pIter, 0); fts5SegIterLoadNPos(p, pIter); } } |
︙ | ︙ | |||
1811 1812 1813 1814 1815 1816 1817 | if( n>pIter->iEndofDoclist ){ n = pIter->iEndofDoclist; } ASSERT_SZLEAF_OK(pIter->pLeaf); while( 1 ){ | | | | 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 | if( n>pIter->iEndofDoclist ){ n = pIter->iEndofDoclist; } ASSERT_SZLEAF_OK(pIter->pLeaf); while( 1 ){ i64 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], (u64*)&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 ){ |
︙ | ︙ | |||
1877 1878 1879 1880 1881 1882 1883 | pIter->pLeaf = pNew; pIter->iLeafOffset = pIter->iTermLeafOffset; } }else{ int iRowidOff; iRowidOff = fts5LeafFirstRowidOff(pNew); if( iRowidOff ){ | < < < | | < | 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 | pIter->pLeaf = pNew; pIter->iLeafOffset = pIter->iTermLeafOffset; } }else{ int iRowidOff; iRowidOff = fts5LeafFirstRowidOff(pNew); if( iRowidOff ){ pIter->pLeaf = pNew; pIter->iLeafOffset = iRowidOff; } } if( pIter->pLeaf ){ u8 *a = &pIter->pLeaf->p[pIter->iLeafOffset]; pIter->iLeafOffset += fts5GetVarint(a, (u64*)&pIter->iRowid); break; |
︙ | ︙ | |||
1929 1930 1931 1932 1933 1934 1935 | assert( pIter->flags & FTS5_SEGITER_REVERSE ); assert( pIter->pNextLeaf==0 ); UNUSED_PARAM(pbUnused); if( pIter->iRowidOffset>0 ){ u8 *a = pIter->pLeaf->p; int iOff; | | | | 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 | assert( pIter->flags & FTS5_SEGITER_REVERSE ); assert( pIter->pNextLeaf==0 ); UNUSED_PARAM(pbUnused); if( pIter->iRowidOffset>0 ){ u8 *a = pIter->pLeaf->p; int iOff; i64 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], (u64*)&iDelta); pIter->iRowid -= iDelta; }else{ fts5SegIterReverseNewPage(p, pIter); } } /* |
︙ | ︙ | |||
2131 2132 2133 2134 2135 2136 2137 | 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 | | > > > > > | | 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 | 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. ** ** Later: Switched back to fts5SegIterLoadNPos() because it supports ** detail=none mode. Not ideal. */ int nSz; assert( p->rc==SQLITE_OK ); assert( 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 ); } } } |
︙ | ︙ | |||
2162 2163 2164 2165 2166 2167 2168 | Fts5DlidxIter *pDlidx = pIter->pDlidx; Fts5Data *pLast = 0; int pgnoLast = 0; if( pDlidx ){ int iSegid = pIter->pSeg->iSegid; pgnoLast = fts5DlidxIterPgno(pDlidx); | | | 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 | Fts5DlidxIter *pDlidx = pIter->pDlidx; Fts5Data *pLast = 0; int pgnoLast = 0; if( pDlidx ){ int iSegid = pIter->pSeg->iSegid; pgnoLast = fts5DlidxIterPgno(pDlidx); pLast = fts5DataRead(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; |
︙ | ︙ | |||
2189 2190 2191 2192 2193 2194 2195 | 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); | | | 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 | 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 = fts5DataRead(p, iAbs); if( pNew ){ int iRowid, bTermless; iRowid = fts5LeafFirstRowidOff(pNew); bTermless = fts5LeafIsTermless(pNew); if( iRowid ){ SWAPVAL(Fts5Data*, pNew, pLast); pgnoLast = pgno; |
︙ | ︙ | |||
2220 2221 2222 2223 2224 2225 2226 | */ if( pLast ){ int iOff; fts5DataRelease(pIter->pLeaf); pIter->pLeaf = pLast; pIter->iLeafPgno = pgnoLast; iOff = fts5LeafFirstRowidOff(pLast); | < < < < > | 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 | */ 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); } } fts5SegIterReverseInitPage(p, pIter); } /* ** Iterator pIter currently points to the first rowid of a doclist. |
︙ | ︙ | |||
2283 2284 2285 2286 2287 2288 2289 | */ 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 */ ){ | | > | | | | 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 | */ 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 */ ){ int iOff; const u8 *a = pIter->pLeaf->p; int szLeaf = pIter->pLeaf->szLeaf; int n = pIter->pLeaf->nn; u32 nMatch = 0; u32 nKeep = 0; u32 nNew = 0; u32 iTermOff; int iPgidx; /* Current offset in pgidx */ int bEndOfPage = 0; assert( p->rc==SQLITE_OK ); iPgidx = szLeaf; iPgidx += fts5GetVarint32(&a[iPgidx], iTermOff); iOff = iTermOff; if( iOff>n ){ p->rc = FTS5_CORRUPT; return; } |
︙ | ︙ | |||
2362 2363 2364 2365 2366 2367 2368 | return; }else if( bEndOfPage ){ do { fts5SegIterNextPage(p, pIter); if( pIter->pLeaf==0 ) return; a = pIter->pLeaf->p; if( fts5LeafIsTermless(pIter->pLeaf)==0 ){ | | | | > | < | 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 | return; }else if( bEndOfPage ){ do { fts5SegIterNextPage(p, pIter); if( pIter->pLeaf==0 ) return; a = pIter->pLeaf->p; if( fts5LeafIsTermless(pIter->pLeaf)==0 ){ iPgidx = pIter->pLeaf->szLeaf; iPgidx += fts5GetVarint32(&pIter->pLeaf->p[iPgidx], iOff); if( iOff<4 || iOff>=pIter->pLeaf->szLeaf ){ p->rc = FTS5_CORRUPT; return; }else{ nKeep = 0; iTermOff = iOff; n = pIter->pLeaf->nn; iOff += fts5GetVarint32(&a[iOff], nNew); break; } } }while( 1 ); } search_success: pIter->iLeafOffset = iOff + nNew; if( pIter->iLeafOffset>n || nNew<1 ){ p->rc = FTS5_CORRUPT; return; } pIter->iTermLeafOffset = pIter->iLeafOffset; pIter->iTermLeafPgno = pIter->iLeafPgno; fts5BufferSet(&p->rc, &pIter->term, nKeep, pTerm); fts5BufferAppendBlob(&p->rc, &pIter->term, nNew, &a[iOff]); if( iPgidx>=n ){ |
︙ | ︙ | |||
2738 2739 2740 2741 2742 2743 2744 | }else{ fts5DataRelease(pIter->pNextLeaf); pIter->pNextLeaf = 0; pIter->iLeafPgno = iLeafPgno-1; fts5SegIterNextPage(p, pIter); assert( p->rc!=SQLITE_OK || pIter->iLeafPgno==iLeafPgno ); | | | 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 | }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 ){ 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; |
︙ | ︙ | |||
3127 3128 3129 3130 3131 3132 3133 | 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; | | < < < | 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 | 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 notmwork 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{ 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 ){ |
︙ | ︙ | |||
3170 3171 3172 3173 3174 3175 3176 | */ static void fts5SegiterPoslist( Fts5Index *p, Fts5SegIter *pSeg, Fts5Colset *pColset, Fts5Buffer *pBuf ){ | < < < < | 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 | */ static void fts5SegiterPoslist( Fts5Index *p, Fts5SegIter *pSeg, Fts5Colset *pColset, Fts5Buffer *pBuf ){ if( 0==fts5BufferGrow(&p->rc, pBuf, 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; |
︙ | ︙ | |||
3198 3199 3200 3201 3202 3203 3204 | fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistOffsetsCallback); } } } } /* | | | | | > > > > > > > > > | | > > > > > | > > > > > > > > > > > > | > > > > > | | > | | < < < | < | < < < < < < < | < < < < < | < < < < < < | | < < < < | < < < < | < < < < < | < < < | 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 | fts5ChunkIterate(p, pSeg, (void*)&sCtx, fts5PoslistOffsetsCallback); } } } } /* ** IN/OUT parameter (*pa) points to a position list n bytes in size. If ** the position list contains entries for column iCol, then (*pa) is set ** to point to the sub-position-list for that column and the number of ** bytes in it returned. Or, if the argument position list does not ** contain any entries for column iCol, return 0. */ static int fts5IndexExtractCol( const u8 **pa, /* IN/OUT: Pointer to poslist */ int n, /* IN: Size of poslist in bytes */ int iCol /* Column to extract from poslist */ ){ int iCurrent = 0; /* Anything before the first 0x01 is col 0 */ const u8 *p = *pa; const u8 *pEnd = &p[n]; /* One byte past end of position list */ while( iCol>iCurrent ){ /* Advance pointer p until it points to pEnd or an 0x01 byte that is ** not part of a varint. Note that it is not possible for a negative ** or extremely large varint to occur within an uncorrupted position ** list. So the last byte of each varint may be assumed to have a clear ** 0x80 bit. */ while( *p!=0x01 ){ while( *p++ & 0x80 ); if( p>=pEnd ) return 0; } *pa = p++; iCurrent = *p++; if( iCurrent & 0x80 ){ p--; p += fts5GetVarint32(p, iCurrent); } } if( iCol!=iCurrent ) return 0; /* 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 ); } return p - (*pa); } static void fts5IndexExtractColset( int *pRc, Fts5Colset *pColset, /* Colset to filter on */ const u8 *pPos, int nPos, /* Position list */ Fts5Buffer *pBuf /* Output buffer */ ){ if( *pRc==SQLITE_OK ){ int i; fts5BufferZero(pBuf); for(i=0; i<pColset->nCol; i++){ const u8 *pSub = pPos; int nSub = fts5IndexExtractCol(&pSub, nPos, pColset->aiCol[i]); if( nSub ){ fts5BufferAppendBlob(pRc, pBuf, nSub, pSub); } } } } /* ** xSetOutputs callback used by detail=none tables. */ static void fts5IterSetOutputs_None(Fts5Iter *pIter, Fts5SegIter *pSeg){ assert( pIter->pIndex->pConfig->eDetail==FTS5_DETAIL_NONE ); |
︙ | ︙ | |||
3383 3384 3385 3386 3387 3388 3389 | 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]; | > > > > | | | > > > < | 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 | 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]; if( pColset->nCol==1 ){ pIter->base.nData = fts5IndexExtractCol(&a, pSeg->nPos,pColset->aiCol[0]); pIter->base.pData = a; }else{ int *pRc = &pIter->pIndex->rc; fts5BufferZero(&pIter->poslist); fts5IndexExtractColset(pRc, pColset, a, pSeg->nPos, &pIter->poslist); pIter->base.pData = pIter->poslist.p; pIter->base.nData = pIter->poslist.n; } }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){ if( *pRc==SQLITE_OK ){ Fts5Config *pConfig = pIter->pIndex->pConfig; if( pConfig->eDetail==FTS5_DETAIL_NONE ){ pIter->xSetOutputs = fts5IterSetOutputs_None; } else if( pIter->pColset==0 ){ |
︙ | ︙ | |||
3470 3471 3472 3473 3474 3475 3476 | nSeg = pStruct->nSegment; nSeg += (p->pHash ? 1 : 0); }else{ nSeg = MIN(pStruct->aLevel[iLevel].nSeg, nSegment); } } *ppOut = pNew = fts5MultiIterAlloc(p, nSeg); | | < < < | 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 | nSeg = pStruct->nSegment; nSeg += (p->pHash ? 1 : 0); }else{ nSeg = MIN(pStruct->aLevel[iLevel].nSeg, nSegment); } } *ppOut = pNew = fts5MultiIterAlloc(p, nSeg); if( pNew==0 ) return; 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); } |
︙ | ︙ | |||
3537 3538 3539 3540 3541 3542 3543 | pNew->xSetOutputs(pNew, pSeg); } }else{ fts5MultiIterFree(pNew); *ppOut = 0; } | < < < < | 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 | 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( |
︙ | ︙ | |||
3588 3589 3590 3591 3592 3593 3594 | } /* ** Return true if the iterator is at EOF or if an error has occurred. ** False otherwise. */ static int fts5MultiIterEof(Fts5Index *p, Fts5Iter *pIter){ | < | | 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 | } /* ** Return true if the iterator is at EOF or if an error has occurred. ** False otherwise. */ static int fts5MultiIterEof(Fts5Index *p, Fts5Iter *pIter){ assert( p->rc || (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 |
︙ | ︙ | |||
4085 4086 4087 4088 4089 4090 4091 | } /* Write the rowid. */ if( pWriter->bFirstRowidInDoclist || pWriter->bFirstRowidInPage ){ fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid); }else{ assert_nc( p->rc || iRowid>pWriter->iPrevRowid ); | | < < | 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 | } /* 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; } } |
︙ | ︙ | |||
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); | < | 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 | } } /* 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); } |
︙ | ︙ | |||
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 */ ){ | | | 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 | ** 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 ){ 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; |
︙ | ︙ | |||
4619 4620 4621 4622 4623 4624 4625 | 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; | | | | 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 | 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; i64 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], (u64*)&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); |
︙ | ︙ | |||
4766 4767 4768 4769 4770 4771 4772 | nByte += (pStruct->nLevel+1) * sizeof(Fts5StructureLevel); pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte); if( pNew ){ Fts5StructureLevel *pLvl; nByte = nSeg * sizeof(Fts5StructureSegment); | | | | 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 | nByte += (pStruct->nLevel+1) * sizeof(Fts5StructureLevel); pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte); if( pNew ){ Fts5StructureLevel *pLvl; nByte = nSeg * sizeof(Fts5StructureSegment); pNew->nLevel = pStruct->nLevel+1; pNew->nRef = 1; pNew->nWriteCounter = pStruct->nWriteCounter; pLvl = &pNew->aLevel[pStruct->nLevel]; pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&p->rc, nByte); if( pLvl->aSeg ){ int iLvl, iSeg; int iSegOut = 0; /* Iterate through all segments, from oldest to newest. Add them to ** the new Fts5Level object so that pLvl->aSeg[0] is the oldest ** segment in the data structure. */ |
︙ | ︙ | |||
4851 4852 4853 4854 4855 4856 4857 | fts5StructureRelease(pStruct); } return fts5IndexReturn(p); } static void fts5AppendRowid( Fts5Index *p, | | | | < < < < | | | < | | | | | 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 | fts5StructureRelease(pStruct); } return fts5IndexReturn(p); } static void fts5AppendRowid( Fts5Index *p, i64 iDelta, Fts5Iter *pUnused, Fts5Buffer *pBuf ){ UNUSED_PARAM(pUnused); fts5BufferAppendVarint(&p->rc, pBuf, iDelta); } 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 ); if( p>=pIter->aEof ){ pIter->aPoslist = 0; }else{ i64 iDelta; p += fts5GetVarint(p, (u64*)&iDelta); pIter->iRowid += iDelta; /* Read position list size */ if( p[0] & 0x80 ){ int nPos; pIter->nSize = fts5GetVarint32(p, nPos); pIter->nPoslist = (nPos>>1); }else{ pIter->nPoslist = ((int)(p[0])) >> 1; pIter->nSize = 1; } pIter->aPoslist = p; } } static void fts5DoclistIterInit( Fts5Buffer *pBuf, Fts5DoclistIter *pIter ){ memset(pIter, 0, sizeof(*pIter)); pIter->aPoslist = pBuf->p; pIter->aEof = &pBuf->p[pBuf->n]; fts5DoclistIterNext(pIter); } #if 0 /* ** Append a doclist to buffer pBuf. ** ** This function assumes that space within the buffer has already been ** allocated. */ static void fts5MergeAppendDocid( Fts5Buffer *pBuf, /* Buffer to write to */ i64 *piLastRowid, /* IN/OUT: Previous rowid written (if any) */ i64 iRowid /* Rowid to append */ ){ assert( pBuf->n!=0 || (*piLastRowid)==0 ); fts5BufferSafeAppendVarint(pBuf, iRowid - *piLastRowid); *piLastRowid = iRowid; } #endif #define fts5MergeAppendDocid(pBuf, iLastRowid, iRowid) { \ assert( (pBuf)->n!=0 || (iLastRowid)==0 ); \ fts5BufferSafeAppendVarint((pBuf), (iRowid) - (iLastRowid)); \ (iLastRowid) = (iRowid); \ } /* ** Swap the contents of buffer *p1 with that of *p2. */ static void fts5BufferSwap(Fts5Buffer *p1, Fts5Buffer *p2){ Fts5Buffer tmp = *p1; |
︙ | ︙ | |||
4969 4970 4971 4972 4973 4974 4975 | /* ** 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 */ | < | | < < < | 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 | /* ** 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 */ Fts5Buffer *p2 /* Second list to merge */ ){ int i1 = 0; int i2 = 0; i64 iRowid1 = 0; i64 iRowid2 = 0; i64 iOut = 0; Fts5Buffer out; memset(&out, 0, sizeof(out)); 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) ){ |
︙ | ︙ | |||
5008 5009 5010 5011 5012 5013 5014 5015 | fts5NextRowid(p2, &i2, &iRowid2); } } fts5BufferSwap(&out, p1); fts5BufferFree(&out); } | < < < < < < < < | < < < < < < < < < < < < < | < < < < < < < < < < < < < | | | < | > < | < < < < > | | < > | | < < < < < < < < < < < < < < < < | | | | | | < < < < < < | > > | > > | > > > | | | < < | > | | > | | | < | | | | < | | > | | > > | > > > > > > | < < | | < < < | > | > > | < > | < > > | < < | | | > | | > > | < < < | | > > | | | > | | < < | | | < > | < < | | | > > | < < < | | > > | | < | | < | < < < > > > | > > | | < < > < | | < | | < < < < < < < < < < < < < < < < < < < < < < < < < | < | | | < | < < | < | < | < | < | < | < | 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 | fts5NextRowid(p2, &i2, &iRowid2); } } fts5BufferSwap(&out, p1); fts5BufferFree(&out); } /* ** Buffers p1 and p2 contain doclists. This function merges the content ** of the two doclists together and sets buffer p1 to the result before ** returning. ** ** If an error occurs, an error code is left in p->rc. If an error has ** already occurred, this function is a no-op. */ static void fts5MergePrefixLists( Fts5Index *p, /* FTS5 backend object */ Fts5Buffer *p1, /* First list to merge */ Fts5Buffer *p2 /* Second list to merge */ ){ if( p2->n ){ i64 iLastRowid = 0; Fts5DoclistIter i1; Fts5DoclistIter i2; Fts5Buffer out = {0, 0, 0}; Fts5Buffer tmp = {0, 0, 0}; /* The maximum size of the output is equal to the sum of the two ** 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. */ if( sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n + 9) ) return; fts5DoclistIterInit(p1, &i1); fts5DoclistIterInit(p2, &i2); while( 1 ){ if( i1.iRowid<i2.iRowid ){ /* Copy entry from i1 */ fts5MergeAppendDocid(&out, iLastRowid, i1.iRowid); fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.nPoslist+i1.nSize); fts5DoclistIterNext(&i1); if( i1.aPoslist==0 ) break; } else if( i2.iRowid!=i1.iRowid ){ /* Copy entry from i2 */ fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid); fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.nPoslist+i2.nSize); fts5DoclistIterNext(&i2); if( i2.aPoslist==0 ) break; } else{ /* Merge the two position lists. */ i64 iPos1 = 0; i64 iPos2 = 0; int iOff1 = 0; int iOff2 = 0; u8 *a1 = &i1.aPoslist[i1.nSize]; u8 *a2 = &i2.aPoslist[i2.nSize]; int nCopy; u8 *aCopy; i64 iPrev = 0; Fts5PoslistWriter writer; memset(&writer, 0, sizeof(writer)); fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid); fts5BufferZero(&tmp); sqlite3Fts5BufferSize(&p->rc, &tmp, i1.nPoslist + i2.nPoslist); if( p->rc ) break; sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1); sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2); assert( iPos1>=0 && iPos2>=0 ); if( iPos1<iPos2 ){ sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1); sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1); }else{ sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2); sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2); } if( iPos1>=0 && iPos2>=0 ){ while( 1 ){ if( iPos1<iPos2 ){ if( iPos1!=iPrev ){ sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1); } sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1); if( iPos1<0 ) break; }else{ assert_nc( iPos2!=iPrev ); sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2); sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2); if( iPos2<0 ) break; } } } if( iPos1>=0 ){ if( iPos1!=iPrev ){ sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1); } aCopy = &a1[iOff1]; nCopy = i1.nPoslist - iOff1; }else{ assert( iPos2>=0 && iPos2!=iPrev ); sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2); aCopy = &a2[iOff2]; nCopy = i2.nPoslist - iOff2; } if( nCopy>0 ){ fts5BufferSafeAppendBlob(&tmp, aCopy, nCopy); } /* WRITEPOSLISTSIZE */ fts5BufferSafeAppendVarint(&out, tmp.n * 2); fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n); fts5DoclistIterNext(&i1); fts5DoclistIterNext(&i2); assert( out.n<=(p1->n+p2->n+9) ); if( i1.aPoslist==0 || i2.aPoslist==0 ) break; } } if( i1.aPoslist ){ fts5MergeAppendDocid(&out, iLastRowid, i1.iRowid); fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.aEof - i1.aPoslist); } else if( i2.aPoslist ){ fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid); fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.aEof - i2.aPoslist); } assert( out.n<=(p1->n+p2->n+9) ); fts5BufferSet(&p->rc, p1, out.n, out.p); fts5BufferFree(&tmp); fts5BufferFree(&out); } } static void fts5SetupPrefixIter( Fts5Index *p, /* Index to read from */ int bDesc, /* True for "ORDER BY rowid DESC" */ const u8 *pToken, /* Buffer containing prefix to match */ int nToken, /* Size of buffer pToken in bytes */ Fts5Colset *pColset, /* Restrict matches to these columns */ Fts5Iter **ppIter /* OUT: New iterator */ ){ Fts5Structure *pStruct; Fts5Buffer *aBuf; const int nBuf = 32; void (*xMerge)(Fts5Index*, Fts5Buffer*, Fts5Buffer*); void (*xAppend)(Fts5Index*, i64, Fts5Iter*, Fts5Buffer*); if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){ xMerge = fts5MergeRowidLists; xAppend = fts5AppendRowid; }else{ 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)); 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++){ assert( i<nBuf ); if( aBuf[i].n==0 ){ fts5BufferSwap(&doclist, &aBuf[i]); fts5BufferZero(&doclist); }else{ xMerge(p, &doclist, &aBuf[i]); fts5BufferZero(&aBuf[i]); } } iLastRowid = 0; } xAppend(p, p1->base.iRowid-iLastRowid, p1, &doclist); iLastRowid = p1->base.iRowid; } for(i=0; i<nBuf; i++){ if( p->rc==SQLITE_OK ){ xMerge(p, &doclist, &aBuf[i]); } fts5BufferFree(&aBuf[i]); } 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; |
︙ | ︙ | |||
5359 5360 5361 5362 5363 5364 5365 | /* ** Commit data to disk. */ int sqlite3Fts5IndexSync(Fts5Index *p){ assert( p->rc==SQLITE_OK ); fts5IndexFlush(p); | | | < | 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 | /* ** Commit data to disk. */ int sqlite3Fts5IndexSync(Fts5Index *p){ assert( p->rc==SQLITE_OK ); fts5IndexFlush(p); fts5CloseReader(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){ fts5CloseReader(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); memset(&s, 0, sizeof(Fts5Structure)); fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0); fts5StructureWrite(p, &s); return fts5IndexReturn(p); } /* |
︙ | ︙ | |||
5473 5474 5475 5476 5477 5478 5479 | 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 ){ | < | < < < | 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 | 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++; if( n>=nByte ) break; } } } return n; } /* |
︙ | ︙ | |||
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 */ | < | | < < > | < | < < | | | | < | | 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 | 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. ** ** If the QUERY_TEST_NOIDX flag was specified, then this must be a ** prefix-query. Instead of using a prefix-index (if one exists), ** evaluate the prefix query using the main FTS index. This is used ** for internal sanity checking by the integrity-check in debug ** mode only. */ #ifdef SQLITE_DEBUG if( pConfig->bPrefixIndex==0 || (flags & FTS5INDEX_QUERY_TEST_NOIDX) ){ 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++){ if( pConfig->aPrefix[iIdx-1]==nChar ) break; } } 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; buf.p[0] = FTS5_MAIN_PREFIX; fts5SetupPrefixIter(p, bDesc, buf.p, nToken+1, pColset, &pRet); assert( p->rc!=SQLITE_OK || 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; fts5CloseReader(p); } *ppIter = (Fts5IndexIter*)pRet; sqlite3Fts5BufferFree(&buf); } return fts5IndexReturn(p); } |
︙ | ︙ | |||
5682 5683 5684 5685 5686 5687 5688 | /* ** Return the current term. */ const char *sqlite3Fts5IterTerm(Fts5IndexIter *pIndexIter, int *pn){ int n; const char *z = (const char*)fts5MultiIterTerm((Fts5Iter*)pIndexIter, &n); | < | | | 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 | /* ** 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; return &z[1]; } /* ** 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); fts5CloseReader(pIndex); } } /* ** Read and decode the "averages" record from the database. ** ** Parameter anSize must point to an array of size nCol, where nCol is |
︙ | ︙ | |||
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); | | | 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 | 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 && 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); |
︙ | ︙ | |||
5888 5889 5890 5891 5892 5893 5894 | } sqlite3Fts5IterClose(pIter); *pCksum = cksum; return rc; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 | } 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, |
︙ | ︙ | |||
5959 5960 5961 5962 5963 5964 5965 | /* 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 | | < < < < < < | | 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 | /* 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. */ if( p->nPendingData==0 ){ 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 ){ |
︙ | ︙ | |||
6089 6090 6091 6092 6093 6094 6095 | int rc2; int iIdxPrevLeaf = pSeg->pgnoFirst-1; int iDlidxPrevLeaf = pSeg->pgnoLast; if( pSeg->pgnoFirst==0 ) return; fts5IndexPrepareStmt(p, &pStmt, sqlite3_mprintf( | | < < > | 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 | 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", 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 */ int nIdxTerm = sqlite3_column_bytes(pStmt, 1); const char *zIdxTerm = (const char*)sqlite3_column_text(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); |
︙ | ︙ | |||
6221 6222 6223 6224 6225 6226 6227 | ** 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. */ | | < < < < | < > > | | | | > | 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 | ** 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 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 */ #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); /* Check that the internal nodes of each segment match the leaves */ if( pStruct ){ int iLvl, iSeg; 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. |
︙ | ︙ | |||
6276 6277 6278 6279 6280 6281 6282 | i64 iPos = 0; /* Position read from poslist */ int iOff = 0; /* Offset within poslist */ i64 iRowid = fts5MultiIterRowid(pIter); char *z = (char*)fts5MultiIterTerm(pIter, &n); /* If this is a new term, query for it. Update cksum3 with the results. */ fts5TestTerm(p, &term, z, n, cksum2, &cksum3); | < < | < | 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 | i64 iPos = 0; /* Position read from poslist */ int iOff = 0; /* Offset within poslist */ i64 iRowid = fts5MultiIterRowid(pIter); char *z = (char*)fts5MultiIterTerm(pIter, &n); /* If this is a new term, query for it. Update cksum3 with the results. */ fts5TestTerm(p, &term, z, n, cksum2, &cksum3); 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); if( p->rc==SQLITE_OK && 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. */ /* ** 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 */ |
︙ | ︙ | |||
6335 6336 6337 6338 6339 6340 6341 | iRowid >>= FTS5_DATA_HEIGHT_B; *pbDlidx = (int)(iRowid & 0x0001); iRowid >>= FTS5_DATA_DLI_B; *piSegid = (int)(iRowid & (((i64)1 << FTS5_DATA_ID_B) - 1)); } | < < < < | 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 | 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 */ |
︙ | ︙ | |||
6379 6380 6381 6382 6383 6384 6385 | sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " {id=%d leaves=%d..%d}", pSeg->iSegid, pSeg->pgnoFirst, pSeg->pgnoLast ); } sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "}"); } } | < < | 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 | 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. */ |
︙ | ︙ | |||
6406 6407 6408 6409 6410 6411 6412 | *pRc = rc; return; } fts5DebugStructure(pRc, pBuf, p); fts5StructureRelease(p); } | < < | 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 | *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. */ |
︙ | ︙ | |||
6431 6432 6433 6434 6435 6436 6437 | while( i<nBlob ){ u64 iVal; i += sqlite3Fts5GetVarint(&pBlob[i], &iVal); sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "%s%d", zSpace, (int)iVal); zSpace = " "; } } | < < < < | 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 | 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. |
︙ | ︙ | |||
6485 6486 6487 6488 6489 6490 6491 | iDocid += iDelta; sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " id=%lld", iDocid); } } return iOff; } | < < | 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 | 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. |
︙ | ︙ | |||
6528 6529 6530 6531 6532 6533 6534 | zApp = "*"; } } sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " %lld%s", iRowid, zApp); } } | < < | 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 | 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 */ |
︙ | ︙ | |||
6739 6740 6741 6742 6743 6744 6745 | 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); } | < < | 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 | 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 */ |
︙ | ︙ | |||
6775 6776 6777 6778 6779 6780 6781 | }else{ sqlite3_result_error(pCtx, "first arg to fts5_rowid() must be 'segment'" , -1 ); } } } | < < < < < < | 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 | }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); } |
Changes to ext/fts5/fts5_main.c.
︙ | ︙ | |||
18 19 20 21 22 23 24 | /* ** 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. */ | < < | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | /* ** 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; typedef struct Fts5FullTable Fts5FullTable; typedef struct Fts5Sorter Fts5Sorter; |
︙ | ︙ | |||
256 257 258 259 260 261 262 | case FTS5_BEGIN: assert( p->ts.eState==0 ); p->ts.eState = 1; p->ts.iSavepoint = -1; break; case FTS5_SYNC: | | | | | < < < | | 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 | case FTS5_BEGIN: assert( p->ts.eState==0 ); p->ts.eState = 1; p->ts.iSavepoint = -1; break; case FTS5_SYNC: assert( p->ts.eState==1 ); p->ts.eState = 2; break; case FTS5_COMMIT: assert( p->ts.eState==2 ); p->ts.eState = 0; break; case FTS5_ROLLBACK: assert( p->ts.eState==1 || p->ts.eState==2 || p->ts.eState==0 ); p->ts.eState = 0; break; case FTS5_SAVEPOINT: assert( p->ts.eState==1 ); assert( iSavepoint>=0 ); assert( iSavepoint>=p->ts.iSavepoint ); p->ts.iSavepoint = iSavepoint; break; case FTS5_RELEASE: assert( p->ts.eState==1 ); 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 ); assert( iSavepoint<=p->ts.iSavepoint ); p->ts.iSavepoint = iSavepoint; break; } } #else # define fts5CheckTransactionState(x,y,z) #endif |
︙ | ︙ | |||
462 463 464 465 466 467 468 | #endif { pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_UNIQUE; } #endif } | < < < < < < < < < < < < < < < < < | < | | | | < < < < < < < < < < < < < < < < < < < < < < < | 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 | #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: ** ** 1. A MATCH constraint against the special column. ** 2. A MATCH constraint against the "rank" column. ** 3. An == constraint against the rowid column. ** 4. A < or <= constraint against the rowid column. ** 5. A > or >= constraint against the rowid column. ** ** Within the ORDER BY, either: ** ** 5. ORDER BY rank [ASC|DESC] ** 6. ORDER BY rowid [ASC|DESC] ** ** 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 ** constraints also present. As follows: |
︙ | ︙ | |||
545 546 547 548 549 550 551 552 553 | ** 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; | > > | > > | > | > > > > > > > > > > > | | | < < | < < < < < < | < < < < < > | | | > > > < < < < < < < < < < < < < | < < < | < < < < < < < < < < < < < < | < | | | < < < < | < < < < | < < < | > | | | | | | | | > > > > > > > > > > | 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 | ** 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 bHasMatch; int iNext; int i; struct Constraint { int op; /* Mask against sqlite3_index_constraint.op */ int fts5op; /* FTS5 mask for idxFlags */ int iCol; /* 0==rowid, 1==tbl, 2==rank */ int omit; /* True to omit this if found */ int iConsIndex; /* Index in pInfo->aConstraint[] */ } aConstraint[] = { {SQLITE_INDEX_CONSTRAINT_MATCH|SQLITE_INDEX_CONSTRAINT_EQ, FTS5_BI_MATCH, 1, 1, -1}, {SQLITE_INDEX_CONSTRAINT_MATCH|SQLITE_INDEX_CONSTRAINT_EQ, FTS5_BI_RANK, 2, 1, -1}, {SQLITE_INDEX_CONSTRAINT_EQ, FTS5_BI_ROWID_EQ, 0, 0, -1}, {SQLITE_INDEX_CONSTRAINT_LT|SQLITE_INDEX_CONSTRAINT_LE, FTS5_BI_ROWID_LE, 0, 0, -1}, {SQLITE_INDEX_CONSTRAINT_GT|SQLITE_INDEX_CONSTRAINT_GE, FTS5_BI_ROWID_GE, 0, 0, -1}, }; int aColMap[3]; aColMap[0] = -1; aColMap[1] = nCol; aColMap[2] = nCol+1; 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 ); /* Set idxFlags flags for all WHERE clause terms that will be used. */ 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 && iCol>=0 && iCol<=nCol) || (p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol==nCol) ){ /* A MATCH operator or equivalent */ if( p->usable ){ idxFlags = (idxFlags & 0xFFFF) | FTS5_BI_MATCH | (iCol << 16); aConstraint[0].iConsIndex = i; }else{ /* As there exists an unusable MATCH constraint this is an ** unusable plan. Set a prohibitively high cost. */ pInfo->estimatedCost = 1e50; return SQLITE_OK; } }else if( p->op<=SQLITE_INDEX_CONSTRAINT_MATCH ){ int j; for(j=1; j<ArraySize(aConstraint); j++){ struct Constraint *pC = &aConstraint[j]; if( iCol==aColMap[pC->iCol] && (p->op & pC->op) && p->usable ){ pC->iConsIndex = i; idxFlags |= pC->fts5op; } } } } /* Set idxFlags flags for the ORDER BY clause */ if( pInfo->nOrderBy==1 ){ int iSort = pInfo->aOrderBy[0].iColumn; if( iSort==(pConfig->nCol+1) && BitFlagTest(idxFlags, FTS5_BI_MATCH) ){ 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. */ bHasMatch = BitFlagTest(idxFlags, FTS5_BI_MATCH); if( BitFlagTest(idxFlags, FTS5_BI_ROWID_EQ) ){ pInfo->estimatedCost = bHasMatch ? 100.0 : 10.0; if( bHasMatch==0 ) fts5SetUniqueFlag(pInfo); }else if( BitFlagAllTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){ pInfo->estimatedCost = bHasMatch ? 500.0 : 250000.0; }else if( BitFlagTest(idxFlags, FTS5_BI_ROWID_LE|FTS5_BI_ROWID_GE) ){ pInfo->estimatedCost = bHasMatch ? 750.0 : 750000.0; }else{ pInfo->estimatedCost = bHasMatch ? 1000.0 : 1000000.0; } /* Assign argvIndex values to each constraint in use. */ iNext = 1; for(i=0; i<ArraySize(aConstraint); i++){ struct Constraint *pC = &aConstraint[i]; if( pC->iConsIndex>=0 ){ pInfo->aConstraintUsage[pC->iConsIndex].argvIndex = iNext++; pInfo->aConstraintUsage[pC->iConsIndex].omit = (unsigned char)pC->omit; } } pInfo->idxNum = idxFlags; return SQLITE_OK; } static int fts5NewTransaction(Fts5FullTable *pTab){ |
︙ | ︙ | |||
768 769 770 771 772 773 774 | sqlite3_free(pCsr->apRankArg); if( CsrFlagTest(pCsr, FTS5CSR_FREE_ZRANK) ){ sqlite3_free(pCsr->zRank); sqlite3_free(pCsr->zRankArgs); } | < | 698 699 700 701 702 703 704 705 706 707 708 709 710 711 | 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. |
︙ | ︙ | |||
800 801 802 803 804 805 806 | static int fts5SorterNext(Fts5Cursor *pCsr){ Fts5Sorter *pSorter = pCsr->pSorter; int rc; rc = sqlite3_step(pSorter->pStmt); if( rc==SQLITE_DONE ){ rc = SQLITE_OK; | | | 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 | static int fts5SorterNext(Fts5Cursor *pCsr){ Fts5Sorter *pSorter = pCsr->pSorter; int rc; rc = sqlite3_step(pSorter->pStmt); if( rc==SQLITE_DONE ){ rc = SQLITE_OK; CsrFlagSet(pCsr, FTS5CSR_EOF); }else if( rc==SQLITE_ROW ){ const u8 *a; const u8 *aBlob; int nBlob; int i; int iOff = 0; rc = SQLITE_OK; |
︙ | ︙ | |||
919 920 921 922 923 924 925 | } case FTS5_PLAN_SORTED_MATCH: { rc = fts5SorterNext(pCsr); break; } | | < < < < < < < < < | 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 | } case FTS5_PLAN_SORTED_MATCH: { rc = fts5SorterNext(pCsr); break; } default: rc = sqlite3_step(pCsr->pStmt); if( rc!=SQLITE_ROW ){ CsrFlagSet(pCsr, FTS5CSR_EOF); rc = sqlite3_reset(pCsr->pStmt); }else{ rc = SQLITE_OK; } break; } } return rc; } |
︙ | ︙ | |||
1001 1002 1003 1004 1005 1006 1007 | ** 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, | | | 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 | ** 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(%s%s%s) %s", pConfig->zDb, pConfig->zName, zRank, pConfig->zName, (zRankArgs ? ", " : ""), (zRankArgs ? zRankArgs : ""), bDesc ? "DESC" : "ASC" ); pCsr->pSorter = pSorter; |
︙ | ︙ | |||
1057 1058 1059 1060 1061 1062 1063 | while( z[0]==' ' ) z++; for(n=0; z[n] && z[n]!=' '; n++); assert( pTab->p.base.zErrMsg==0 ); pCsr->ePlan = FTS5_PLAN_SPECIAL; | | | | 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 | while( z[0]==' ' ) z++; for(n=0; z[n] && z[n]!=' '; n++); assert( pTab->p.base.zErrMsg==0 ); pCsr->ePlan = FTS5_PLAN_SPECIAL; if( 0==sqlite3_strnicmp("reads", z, n) ){ pCsr->iSpecial = sqlite3Fts5IndexReads(pTab->p.pIndex); } else if( 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; } |
︙ | ︙ | |||
1201 1202 1203 1204 1205 1206 1207 | ** 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 */ | | > > < < < < < < > | < < < | > | | | > | < | < < < < < < < | < < < < < < < < < < < < < < < | < < < < < < | < < < < < | < < < < < < < < < < < < < < | < < < < | 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 | ** 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 *zUnused, /* 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 iVal = 0; /* Counter for apVal[] */ int bDesc; /* True if ORDER BY [rank|rowid] DESC */ int bOrderByRank; /* True if ORDER BY rank */ sqlite3_value *pMatch = 0; /* <tbl> MATCH ? expression (or NULL) */ 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; UNUSED_PARAM(zUnused); UNUSED_PARAM(nVal); 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( pzErrmsg==0 || pzErrmsg==&pTab->p.base.zErrMsg ); pConfig->pzErrmsg = &pTab->p.base.zErrMsg; /* Decode the arguments passed through to this function. ** ** Note: The following set of if(...) statements must be in the same ** order as the corresponding entries in the struct at the top of ** fts5BestIndexMethod(). */ if( BitFlagTest(idxNum, FTS5_BI_MATCH) ) pMatch = apVal[iVal++]; if( BitFlagTest(idxNum, FTS5_BI_RANK) ) pRank = apVal[iVal++]; if( BitFlagTest(idxNum, FTS5_BI_ROWID_EQ) ) pRowidEq = apVal[iVal++]; if( BitFlagTest(idxNum, FTS5_BI_ROWID_LE) ) pRowidLe = apVal[iVal++]; if( BitFlagTest(idxNum, FTS5_BI_ROWID_GE) ) pRowidGe = apVal[iVal++]; iCol = (idxNum>>16); assert( iCol>=0 && iCol<=pConfig->nCol ); assert( iVal==nVal ); 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. */ |
︙ | ︙ | |||
1333 1334 1335 1336 1337 1338 1339 | /* 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 ); | | | > > > > > > > > > > > > | | | | | | > > < | | < < | 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 | /* 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 && pMatch==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( pMatch ){ const char *zExpr = (const char*)sqlite3_value_text(apVal[0]); if( zExpr==0 ) zExpr = ""; rc = fts5CursorParseRank(pConfig, pCsr, pRank); if( rc==SQLITE_OK ){ if( zExpr[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, &zExpr[1]); }else{ char **pzErr = &pTab->p.base.zErrMsg; rc = sqlite3Fts5ExprNew(pConfig, iCol, zExpr, &pCsr->pExpr, pzErr); 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( pCsr->ePlan==FTS5_PLAN_ROWID ){ sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]); }else{ sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iFirstRowid); sqlite3_bind_int64(pCsr->pStmt, 2, pCsr->iLastRowid); } rc = fts5NextMethod(pCursor); } } 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. |
︙ | ︙ | |||
1463 1464 1465 1466 1467 1468 1469 | 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) ){ | < < < < < < < | 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 | 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) ){ assert( pCsr->pExpr ); sqlite3_reset(pCsr->pStmt); sqlite3_bind_int64(pCsr->pStmt, 1, fts5CursorRowid(pCsr)); rc = sqlite3_step(pCsr->pStmt); 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; } } } return rc; } static void fts5SetVtabError(Fts5FullTable *p, const char *zFormat, ...){ |
︙ | ︙ | |||
1544 1545 1546 1547 1548 1549 1550 | } }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) ){ | < | | 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 | } }else if( 0==sqlite3_stricmp("optimize", zCmd) ){ rc = sqlite3Fts5StorageOptimize(pTab->pStorage); }else if( 0==sqlite3_stricmp("merge", zCmd) ){ int nMerge = sqlite3_value_int(pVal); rc = sqlite3Fts5StorageMerge(pTab->pStorage, nMerge); }else if( 0==sqlite3_stricmp("integrity-check", zCmd) ){ rc = sqlite3Fts5StorageIntegrity(pTab->pStorage); #ifdef SQLITE_DEBUG }else if( 0==sqlite3_stricmp("prefix-index", zCmd) ){ pConfig->bPrefixIndex = sqlite3_value_int(pVal); #endif }else{ rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex); if( rc==SQLITE_OK ){ |
︙ | ︙ | |||
1621 1622 1623 1624 1625 1626 1627 | ){ 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. */ | | | 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 | ){ 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 ); |
︙ | ︙ | |||
1946 1947 1948 1949 1950 1951 1952 | iBest = i; } } if( iBest<0 ) break; nInst++; if( nInst>=pCsr->nInstAlloc ){ | | | < < | 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 | iBest = i; } } if( iBest<0 ) break; nInst++; if( nInst>=pCsr->nInstAlloc ){ pCsr->nInstAlloc = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32; aInst = (int*)sqlite3_realloc64( pCsr->aInst, pCsr->nInstAlloc*sizeof(int)*3 ); if( aInst ){ pCsr->aInst = aInst; }else{ rc = SQLITE_NOMEM; break; } } aInst = &pCsr->aInst[3 * (nInst-1)]; aInst[0] = iBest; |
︙ | ︙ | |||
2178 2179 2180 2181 2182 2183 2184 | Fts5PhraseIter *pIter, int *piCol, int *piOff ){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; int n; int rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n); if( rc==SQLITE_OK ){ | < | | 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 | Fts5PhraseIter *pIter, int *piCol, int *piOff ){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; int n; int rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n); if( rc==SQLITE_OK ){ pIter->b = &pIter->a[n]; *piCol = 0; *piOff = 0; fts5ApiPhraseNext(pCtx, pIter, piCol, piOff); } return rc; } |
︙ | ︙ | |||
2238 2239 2240 2241 2242 2243 2244 | 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 ){ | < | < | | 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 | 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 ){ pIter->b = &pIter->a[n]; *piCol = 0; fts5ApiPhraseNextColumn(pCtx, pIter, piCol); } }else{ int n; rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n); if( rc==SQLITE_OK ){ pIter->b = &pIter->a[n]; if( n<=0 ){ *piCol = -1; }else if( pIter->a[0]==0x01 ){ pIter->a += 1 + fts5GetVarint32(&pIter->a[1], *piCol); }else{ *piCol = 0; } |
︙ | ︙ | |||
2366 2367 2368 2369 2370 2371 2372 | i64 iCsrId; assert( argc>=1 ); pAux = (Fts5Auxiliary*)sqlite3_user_data(context); iCsrId = sqlite3_value_int64(argv[0]); pCsr = fts5CursorFromCsrid(pAux->pGlobal, iCsrId); | | | 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 | 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 ){ 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]); } } |
︙ | ︙ | |||
2502 2503 2504 2505 2506 2507 2508 | || 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) ){ | < < | 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 | || 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 |
︙ | ︙ | |||
2713 2714 2715 2716 2717 2718 2719 | return rc; } int sqlite3Fts5GetTokenizer( Fts5Global *pGlobal, const char **azArg, int nArg, | | > | < < | | | < < < < | | | 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 | return rc; } int sqlite3Fts5GetTokenizer( Fts5Global *pGlobal, const char **azArg, int nArg, Fts5Tokenizer **ppTok, fts5_tokenizer **ppTokApi, 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[1], (nArg?nArg-1:0), ppTok); *ppTokApi = &pMod->x; if( rc!=SQLITE_OK && pzErr ){ *pzErr = sqlite3_mprintf("error in tokenizer constructor"); } } if( rc!=SQLITE_OK ){ *ppTokApi = 0; *ppTok = 0; } return rc; } static void fts5ModuleDestroy(void *pCtx){ Fts5TokenizerModule *pTok, *pNextTok; |
︙ | ︙ | |||
2862 2863 2864 2865 2866 2867 2868 | if( rc==SQLITE_OK ){ rc = sqlite3_create_function( db, "fts5", 1, SQLITE_UTF8, p, fts5Fts5Func, 0, 0 ); } if( rc==SQLITE_OK ){ rc = sqlite3_create_function( | | < < | 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 | if( rc==SQLITE_OK ){ rc = sqlite3_create_function( db, "fts5", 1, SQLITE_UTF8, p, fts5Fts5Func, 0, 0 ); } if( rc==SQLITE_OK ){ rc = sqlite3_create_function( db, "fts5_source_id", 0, SQLITE_UTF8, p, fts5SourceIdFunc, 0, 0 ); } } /* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file ** fts5_test_mi.c is compiled and linked into the executable. And call ** its entry point to enable the matchinfo() demo. */ |
︙ | ︙ |
Changes to ext/fts5/fts5_storage.c.
︙ | ︙ | |||
134 135 136 137 138 139 140 | } if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ int f = SQLITE_PREPARE_PERSISTENT; if( eStmt>FTS5_STMT_LOOKUP ) f |= SQLITE_PREPARE_NO_VTAB; | < < | 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | } if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ int f = SQLITE_PREPARE_PERSISTENT; if( eStmt>FTS5_STMT_LOOKUP ) f |= SQLITE_PREPARE_NO_VTAB; rc = sqlite3_prepare_v3(pC->db, zSql, -1, f, &p->aStmt[eStmt], 0); sqlite3_free(zSql); if( rc!=SQLITE_OK && pzErrMsg ){ *pzErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pC->db)); } } } |
︙ | ︙ | |||
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; | < < | < < < < | | < < < < | < | 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 | 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); }else{ zText = (const char*)sqlite3_value_text(apVal[iCol-1]); nText = sqlite3_value_bytes(apVal[iCol-1]); } ctx.szCol = 0; rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, zText, nText, (void*)&ctx, fts5StorageInsertCallback ); p->aTotalSize[iCol-1] -= (i64)ctx.szCol; } } p->nTotalRow--; rc2 = sqlite3_reset(pSeek); if( rc==SQLITE_OK ) rc = rc2; return rc; } |
︙ | ︙ | |||
567 568 569 570 571 572 573 | /* ** Delete all entries in the FTS5 index. */ int sqlite3Fts5StorageDeleteAll(Fts5Storage *p){ Fts5Config *pConfig = p->pConfig; int rc; | < < | 554 555 556 557 558 559 560 561 562 563 564 565 566 567 | /* ** 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 ); |
︙ | ︙ | |||
620 621 622 623 624 625 626 | 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 ){ | < < < > > | 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 | i64 iRowid = sqlite3_column_int64(pScan, 0); sqlite3Fts5BufferZero(&buf); rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid); for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){ ctx.szCol = 0; if( pConfig->abUnindexed[ctx.iCol]==0 ){ rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, (const char*)sqlite3_column_text(pScan, ctx.iCol+1), sqlite3_column_bytes(pScan, ctx.iCol+1), (void*)&ctx, fts5StorageInsertCallback ); } sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol); p->aTotalSize[ctx.iCol] += (i64)ctx.szCol; } |
︙ | ︙ | |||
746 747 748 749 750 751 752 | 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 ){ | < < < > > | 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 | if( rc==SQLITE_OK ){ rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid); } for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){ ctx.szCol = 0; if( pConfig->abUnindexed[ctx.iCol]==0 ){ rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, (const char*)sqlite3_value_text(apVal[ctx.iCol+2]), sqlite3_value_bytes(apVal[ctx.iCol+2]), (void*)&ctx, fts5StorageInsertCallback ); } sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol); p->aTotalSize[ctx.iCol] += (i64)ctx.szCol; } |
︙ | ︙ | |||
881 882 883 884 885 886 887 | /* ** 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. */ | | | < < < < < | | | | | | | | | | | | | | | | | | | | | | | < < | | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | 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 | /* ** 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){ Fts5Config *pConfig = p->pConfig; int rc; /* Return code */ int *aColSize; /* Array of size pConfig->nCol */ i64 *aTotalSize; /* Array of size pConfig->nCol */ Fts5IntegrityCtx ctx; sqlite3_stmt *pScan; 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); /* 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 ){ rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, (const char*)sqlite3_column_text(pScan, i+1), sqlite3_column_bytes(pScan, i+1), (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); } sqlite3_free(aTotalSize); return rc; } /* |
︙ | ︙ | |||
1058 1059 1060 1061 1062 1063 1064 | 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); | | < < < | 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 | 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( rc==SQLITE_OK ){ int bCorrupt = 1; 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; } } return rc; } int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnToken){ int rc = fts5StorageLoadTotals(p, 0); |
︙ | ︙ |
Changes to ext/fts5/fts5_tcl.c.
︙ | ︙ | |||
25 26 27 28 29 30 31 | #ifdef SQLITE_ENABLE_FTS5 #include "fts5.h" #include <string.h> #include <assert.h> | < < | 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 |
︙ | ︙ | |||
1009 1010 1011 1012 1013 1014 1015 | */ static int SQLITE_TCLAPI f5tMayBeCorrupt( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ | < < | 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; |
︙ | ︙ |
Changes to ext/fts5/fts5_test_tok.c.
︙ | ︙ | |||
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 = (const char **)&azDequote[1]; int nArg = nDequote>0 ? nDequote-1 : 0; rc = pTab->tok.xCreate(pTokCtx, azArg, nArg, &pTab->pTok); } } if( rc!=SQLITE_OK ){ sqlite3_free(pTab); |
︙ | ︙ |
Changes to ext/fts5/fts5_tokenize.c.
︙ | ︙ | |||
1254 1255 1256 1257 1258 1259 1260 | sCtx.pCtx = pCtx; sCtx.aBuf = p->aBuf; return p->tokenizer.xTokenize( p->pTokenizer, (void*)&sCtx, flags, pText, nText, fts5PorterCb ); } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | 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, |
︙ | ︙ |
Changes to ext/fts5/fts5_unicode2.c.
︙ | ︙ | |||
769 770 771 772 773 774 775 | int bToken = aArray[ aFts5UnicodeData[iTbl] & 0x1F ]; int n = (aFts5UnicodeData[iTbl] >> 5) + i; for(; i<128 && i<n; i++){ aAscii[i] = (u8)bToken; } iTbl++; } | < < | 769 770 771 772 773 774 775 776 | int bToken = aArray[ aFts5UnicodeData[iTbl] & 0x1F ]; int n = (aFts5UnicodeData[iTbl] >> 5) + i; for(; i<128 && i<n; i++){ aAscii[i] = (u8)bToken; } iTbl++; } } |
Changes to ext/fts5/fts5_vocab.c.
︙ | ︙ | |||
46 47 48 49 50 51 52 | 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 */ | < < | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | 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 */ Fts5Table *pFts5; /* Associated FTS5 table */ int bEof; /* True if this cursor is at EOF */ Fts5IndexIter *pIter; /* Term/rowid iterator object */ 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; |
︙ | ︙ | |||
330 331 332 333 334 335 336 | Fts5VocabTable *pTab = (Fts5VocabTable*)pVTab; Fts5Table *pFts5 = 0; Fts5VocabCursor *pCsr = 0; int rc = SQLITE_OK; sqlite3_stmt *pStmt = 0; char *zSql = 0; | < < < < < < < < | < < | 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 | Fts5VocabTable *pTab = (Fts5VocabTable*)pVTab; Fts5Table *pFts5 = 0; Fts5VocabCursor *pCsr = 0; int rc = SQLITE_OK; sqlite3_stmt *pStmt = 0; char *zSql = 0; 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; if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){ i64 iId = sqlite3_column_int64(pStmt, 0); pFts5 = sqlite3Fts5TableFromCsrid(pTab->pGlobal, iId); } 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 ){ int 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); pCsr->pIter = 0; sqlite3_free(pCsr->zLeTerm); pCsr->nLeTerm = -1; pCsr->zLeTerm = 0; pCsr->bEof = 0; } |
︙ | ︙ | |||
469 470 471 472 473 474 475 476 | /* ** 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; | > < < < | 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 | /* ** 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 rc = SQLITE_OK; int nCol = pCsr->pFts5->pConfig->nCol; pCsr->rowid++; if( pTab->eType==FTS5_VOCAB_INSTANCE ){ return fts5VocabInstanceNext(pCsr); } if( pTab->eType==FTS5_VOCAB_COL ){ |
︙ | ︙ | |||
583 584 585 586 587 588 589 | if( sqlite3Fts5IterEof(pCsr->pIter) ) break; } } } } if( rc==SQLITE_OK && pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){ | | | < < | 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 | if( sqlite3Fts5IterEof(pCsr->pIter) ) break; } } } } if( rc==SQLITE_OK && pCsr->bEof==0 && pTab->eType==FTS5_VOCAB_COL ){ while( pCsr->aDoc[pCsr->iCol]==0 ) pCsr->iCol++; assert( pCsr->iCol<pCsr->pFts5->pConfig->nCol ); } return rc; } /* ** This is the xFilter implementation for the virtual table. */ |
︙ | ︙ | |||
647 648 649 650 651 652 653 | } } } if( rc==SQLITE_OK ){ Fts5Index *pIndex = pCsr->pFts5->pIndex; rc = sqlite3Fts5IndexQuery(pIndex, zTerm, nTerm, f, 0, &pCsr->pIter); | < < < | 631 632 633 634 635 636 637 638 639 640 641 642 643 644 | } } } if( rc==SQLITE_OK ){ Fts5Index *pIndex = pCsr->pFts5->pIndex; rc = sqlite3Fts5IndexQuery(pIndex, zTerm, nTerm, f, 0, &pCsr->pIter); } 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) |
︙ | ︙ |
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 | 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); 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...}} } ;# foreach_detail_mode finish_test |
Changes to ext/fts5/test/fts5ah.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2014 June 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. The # focus of this script is testing the FTS5 module. # | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # 2014 June 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. The # focus of this script is testing the FTS5 module. # source [file join [file dirname [info script]] fts5_common.tcl] set testprefix fts5ah # If SQLITE_ENABLE_FTS5 is defined, omit this file. ifcapable !fts5 { finish_test |
︙ | ︙ |
Changes to ext/fts5/test/fts5colset.test.
︙ | ︙ | |||
78 79 80 81 82 83 84 | } do_catchsql_test 4.1 { SELECT * FROM t1 WHERE rowid MATCH 'a' } {1 {unable to use function MATCH in the requested context}} } | < < < < < < < < < < < < < < < < < < < | 78 79 80 81 82 83 84 85 86 | } do_catchsql_test 4.1 { SELECT * FROM t1 WHERE rowid MATCH 'a' } {1 {unable to use function MATCH in the requested context}} } 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 | 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; } {} finish_test |
Changes to ext/fts5/test/fts5corrupt3.test.
︙ | ︙ | |||
763 764 765 766 767 768 769 | | 4080: 68 65 63 6b 0a 01 02 1d 6f 70 74 69 6d 69 7a 65 heck....optimize | end c13.db SELECT * FROM t1 WHERE t1 MATCH 'abandon'; }]} {} do_catchsql_test 13.1 { SELECT * FROM t1 WHERE t1 MATCH 'abandon'; | | | 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 | | 4080: 68 65 63 6b 0a 01 02 1d 6f 70 74 69 6d 69 7a 65 heck....optimize | end c13.db SELECT * FROM t1 WHERE t1 MATCH 'abandon'; }]} {} do_catchsql_test 13.1 { SELECT * FROM t1 WHERE t1 MATCH 'abandon'; } {1 {vtable constructor failed: t1}} #------------------------------------------------------------------------- reset_db do_test 14.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 28672 pagesize 4096 filename c14b.db |
︙ | ︙ | |||
954 955 956 957 958 959 960 | | 48: 01 00 00 10 10 04 02 02 00 00 00 00 00 00 00 00 ................ | 64: 70 00 00 00 00 00 00 00 00 00 00 00 70 00 00 00 p...........p... | end c16.db }]} {} do_catchsql_test 15.1 { INSERT INTO t1(t1) VALUES('integrity-check'); | | | 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 | | 48: 01 00 00 10 10 04 02 02 00 00 00 00 00 00 00 00 ................ | 64: 70 00 00 00 00 00 00 00 00 00 00 00 70 00 00 00 p...........p... | end c16.db }]} {} do_catchsql_test 15.1 { INSERT INTO t1(t1) VALUES('integrity-check'); } {1 {database disk image is malformed}} #--------------------------------------------------------------------------- # reset_db do_test 16.0 { sqlite3 db {} db deserialize [decode_hexdb { |
︙ | ︙ | |||
3899 3900 3901 3902 3903 3904 3905 | | 448: 54 55 41 4c 20 54 41 42 4c 45 20 74 31 20 55 53 TUAL TABLE t1 US | 464: 49 4e 47 20 66 74 73 35 28 61 2c 62 2c 63 29 00 ING fts5(a,b,c). | 480: 00 00 39 00 00 00 00 00 00 00 00 00 00 00 00 00 ..9............. | 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version. | end crash-fed6e90021ba5d.db }]} {} | | < > | | | 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 | | 448: 54 55 41 4c 20 54 41 42 4c 45 20 74 31 20 55 53 TUAL TABLE t1 US | 464: 49 4e 47 20 66 74 73 35 28 61 2c 62 2c 63 29 00 ING fts5(a,b,c). | 480: 00 00 39 00 00 00 00 00 00 00 00 00 00 00 00 00 ..9............. | 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version. | end crash-fed6e90021ba5d.db }]} {} do_execsql_test 33.1 { CREATE VIRTUAL TABLE t2 USING fts5vocab('t1','row'); CREATE VIRTUAL TABLE t3 USING fts5vocab('t1','col'); CREATE VIRTUAL TABLE t4 USING fts5vocab('t1','instance'); } do_catchsql_test 33.2 { SELECT * FROM t2; } {1 {database disk image is malformed}} do_catchsql_test 33.3 { SELECT * FROM t2, t3, t4 WHERE t2.term=t3.term AND t3.term=t4.term; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_test 34.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 40960 pagesize 4096 filename crash-a60a9da4c8932f.db |
︙ | ︙ | |||
4480 4481 4482 4483 4484 4485 4486 | | 4080: 00 00 03 03 02 01 03 03 02 02 01 02 02 01 0c e9 ................ | end crash-a6651222df1bd1.db }]} {} do_catchsql_test 36.1 { INSERT INTO t1(b) VALUES( x'78de3fa24af3733ca8769291a0fee3669f9fddefc5cba913e4225d4b6ce2b04f26b87fad3ee6f9b7d90a1ea62a169bf41e5d32707a6ca5c3d05e4bde05c9d89eaaa8c50e74333d2e9fcd7dfe95528a3a016aac1102d825c5cd70cf99d8a88e0ea7f798d4334386518b7ad359beb168b93aba059a2a3bd93112d65b44c12b9904ea786b204d80531cdf0504bf9b203dbe927061974caf7b9f30cbc3397b61f802e732012a6663d41c3607d6f1c0dbcfd489adac05ca500c0b04439d894cd93a840159225ef73b627e178b9f84b3ffe66cf22a963a8368813ff7961fc47f573211ccec95e0220dcbb3bf429f4a50ba54d7a53784ac51bfef346e6a'); | | | 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 | | 4080: 00 00 03 03 02 01 03 03 02 02 01 02 02 01 0c e9 ................ | end crash-a6651222df1bd1.db }]} {} do_catchsql_test 36.1 { INSERT INTO t1(b) VALUES( x'78de3fa24af3733ca8769291a0fee3669f9fddefc5cba913e4225d4b6ce2b04f26b87fad3ee6f9b7d90a1ea62a169bf41e5d32707a6ca5c3d05e4bde05c9d89eaaa8c50e74333d2e9fcd7dfe95528a3a016aac1102d825c5cd70cf99d8a88e0ea7f798d4334386518b7ad359beb168b93aba059a2a3bd93112d65b44c12b9904ea786b204d80531cdf0504bf9b203dbe927061974caf7b9f30cbc3397b61f802e732012a6663d41c3607d6f1c0dbcfd489adac05ca500c0b04439d894cd93a840159225ef73b627e178b9f84b3ffe66cf22a963a8368813ff7961fc47f573211ccec95e0220dcbb3bf429f4a50ba54d7a53784ac51bfef346e6a'); } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_test 37.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 40960 pagesize 4096 filename null-memcmp-param-1..db |
︙ | ︙ | |||
4633 4634 4635 4636 4637 4638 4639 | | 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 null-memcmp-param-1..db }]} {} do_catchsql_test 37.1 { SELECT * FROM t3; | | | | > | 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 | | 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 null-memcmp-param-1..db }]} {} do_catchsql_test 37.1 { SELECT * FROM t3; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_execsql_test 37.0 { CREATE VIRTUAL TABLE t1 USING fts5(b, c); INSERT INTO t1 VALUES('a', 'b'); SELECT quote(block) FROM t1_data WHERE rowid=10; } {X'000000000101010001010101'} do_execsql_test 37.1 { UPDATE t1_data SET block = X'FFFFFFFF0101010001010101' WHERE rowid = 10; SELECT rowid FROM t1('a'); } {1} #------------------------------------------------------------------------- reset_db do_execsql_test 38.0 { CREATE VIRTUAL TABLE t1 USING fts5(b, c); INSERT INTO t1 VALUES('a', 'b'); INSERT INTO t1 VALUES('a', 'b'); SELECT quote(block) FROM t1_data WHERE rowid=1; } {X'020202'} do_execsql_test 38.1 { SELECT * FROM t1('a b') ORDER BY rank; } {a b a b} do_execsql_test 38.2 { UPDATE t1_data SET block = X'000202' WHERE rowid=1; } breakpoint do_catchsql_test 38.3 { SELECT * FROM t1('a b') ORDER BY rank; } {1 {database disk image is malformed}} db close sqlite3 db test.db do_catchsql_test 38.4 { |
︙ | ︙ | |||
4890 4891 4892 4893 4894 4895 4896 | | 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-fd2a1313e5b5e9.db }]} {} do_catchsql_test 38.1 { UPDATE t1 SET b=quote(zeroblob(200)) WHERE t1 MATCH 'thread*'; | | | 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 | | 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-fd2a1313e5b5e9.db }]} {} do_catchsql_test 38.1 { UPDATE t1 SET b=quote(zeroblob(200)) WHERE t1 MATCH 'thread*'; } {0 {}} #------------------------------------------------------------------------- reset_db do_test 39.0 { sqlite3 db {} db deserialize [decode_hexdb { .open --hexdb |
︙ | ︙ | |||
5322 5323 5324 5325 5326 5327 5328 | | 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 03 0f f2 00 0f fc 0f f7 0f f2 00 00 ................ | 4080: 00 00 03 03 02 01 03 03 02 02 01 02 02 01 02 09 ................ | end crash2.txt.db }]} {} | | < > | | 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 | | 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 03 0f f2 00 0f fc 0f f7 0f f2 00 00 ................ | 4080: 00 00 03 03 02 01 03 03 02 02 01 02 02 01 02 09 ................ | end crash2.txt.db }]} {} do_execsql_test 40.1 { BEGIN; INSERT INTO t1(b) VALUES(X'819192e578de3fa24af3733ca8769291a0fee3669f9fddefc5cba913e4225d4b6ce2b04f26b87fad3ee6f9b7d90a1ea62a169bf41e5d32707a6ca5c3d05e4bde05c9d89eaaa8c50e74333d2e9fcd7dfe95528a3a016aac1102d825c5cd70cf99d8a88e0ea7f798d4334386518b7ad359beb168b93aba059a2a3bd93112d65b44c12b9904ea786b204d80531cdf0504bf9b203dbe927061974caf7b9f30cbc3397b61f802e732012a6663d41c3607d6f1c0dbcfd489adac05ca500c0b04439d894cd93a840159225ef73b627e178b9f84b3ffe66cf22a963a8368813ff7961fc47f573211ccec95e0220dcbb3bf429f4a50ba54d7a53784ac51bf'); INSERT INTO t1(b) VALUES(X'c8ae0d0e7c3175946e62ba2b449511d4eb504079984a20f77969f62206c9f3d7ea25358ab705e6978627290b6d48db9032f815a06a79a4f4b809841a0942eed12954ed166f666111812a508abc3bec87958846edaec0a6fe14564bc0a4b78f1c35ebcacca6bae29cc37ae9b59d8a2d7593af1e47dda0ece2268a98d20febafad037964f139851f9a57f48b3706b01721769071991412044cd6006f1d72eb6eb4aa5ad77e378176db8c15575fbeee47165e38a7c6c5a557ac2dfe11813976eaf6741cf593a9e457053a3c34cddfbe605a6e25419f993de8374fafcd3636509d8416a51dc7bcc14cfca322ae343078f47e23522431c17d0da0c033'); INSERT INTO t1(b) VALUES(X'dc29a94e873a45a4243fce9b912aaefbadf1d0423e0345793874b356eeb500b92fb05284c1601fe9bad3143f72162f10242cec27c44ebf764c8fc9fb0824e32c4161472a4f914f579e0e8274f08ca1a02e59b9d8eec1f31061f9ccb9ed97a6f06534e991f7992c761489e6a7724f6e9c2b581e77487ded3a986d53c4419bbd3e9747cee300e670dd7294874c77e2ed48da68eaa6c3ec954a09ac410493d98e34d6686e54fbbe80696705f10e040c66093efb40746b33600685c94c664c7942835a9e954866121d5dcfb2cb12e92521ea3df175ee17072502dad9b9c1565f801b2179799011eb7418bfa00323e3157589e648ff7378be233c79b7'); } do_catchsql_test 40.2 { INSERT INTO t1(a,b) VALUES(1,11),(2,22),(3, true ),(4,44); } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_execsql_test 41.0 { CREATE VIRTUAL TABLE t1 USING fts5(a,b,c); REPLACE INTO t1_data VALUES(1,X'255a5824'); REPLACE INTO t1_data VALUES(10,X'0a1000000102020002010101020101'); |
︙ | ︙ | |||
5785 5786 5787 5788 5789 5790 5791 | | 0: 0d 00 00 00 03 0f f2 00 0f fc 0f f7 0f f2 00 00 ................ | 4080: 00 00 03 03 02 01 03 03 02 02 01 02 02 01 02 09 ................ | end 89028ffd2c29b679e250.db }]} {} do_catchsql_test 43.1 { INSERT INTO t1(t1) VALUES('optimize'); | | | 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 | | 0: 0d 00 00 00 03 0f f2 00 0f fc 0f f7 0f f2 00 00 ................ | 4080: 00 00 03 03 02 01 03 03 02 02 01 02 02 01 02 09 ................ | end 89028ffd2c29b679e250.db }]} {} do_catchsql_test 43.1 { INSERT INTO t1(t1) VALUES('optimize'); } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_execsql_test 44.1 { CREATE VIRTUAL TABLE t1 USING fts5(a,b unindexed,c,tokenize="porter ascii"); REPLACE INTO t1_data VALUES(1,X'03090009'); REPLACE INTO t1_data VALUES(10,X'000000000103030003010101020101030101'); |
︙ | ︙ | |||
5808 5809 5810 5811 5812 5813 5814 | INSERT INTO t1_content VALUES(3,'a b c','g h i','g h i'); INSERT INTO t1_docsize VALUES(1,X'030003'); INSERT INTO t1_docsize VALUES(2,X'030003'); INSERT INTO t1_docsize VALUES(3,X'030003'); } {} do_catchsql_test 44.2 { | | | | | 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 | INSERT INTO t1_content VALUES(3,'a b c','g h i','g h i'); INSERT INTO t1_docsize VALUES(1,X'030003'); INSERT INTO t1_docsize VALUES(2,X'030003'); INSERT INTO t1_docsize VALUES(3,X'030003'); } {} do_catchsql_test 44.2 { INSERT INTO t1(t1) VALUES('integrity-check'); } {1 {database disk image is malformed}} do_catchsql_test 44.2 { SELECT snippet(t1, -1, '.', '..', '', 2 ) FROM t1('g h') ORDER BY rank; } {1 {database disk image is malformed}} #-------------------------------------------------------------------------- reset_db do_test 45.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 24576 pagesize 4096 filename crash-0b162c9e69b999.db |
︙ | ︙ | |||
6043 6044 6045 6046 6047 6048 6049 | INSERT INTO t1(t1, rank) VALUES('merge', 5); INSERT INTO t1(t1, rank) VALUES('merge', 5); INSERT INTO t1(t1, rank) VALUES('merge', 5); INSERT INTO t1(t1, rank) VALUES('merge', 5); INSERT INTO t1(t1, rank) VALUES('merge', 5); INSERT INTO t1(t1, rank) VALUES('merge', 5); INSERT INTO t1(t1, rank) VALUES('merge', 5); | | | 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 | INSERT INTO t1(t1, rank) VALUES('merge', 5); INSERT INTO t1(t1, rank) VALUES('merge', 5); INSERT INTO t1(t1, rank) VALUES('merge', 5); INSERT INTO t1(t1, rank) VALUES('merge', 5); INSERT INTO t1(t1, rank) VALUES('merge', 5); INSERT INTO t1(t1, rank) VALUES('merge', 5); INSERT INTO t1(t1, rank) VALUES('merge', 5); } {0 {}} #-------------------------------------------------------------------------- reset_db do_test 46.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 32768 pagesize 4096 filename crash-1ee8bd451dd1ad.db |
︙ | ︙ | |||
6261 6262 6263 6264 6265 6266 6267 | | 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-1ee8bd451dd1ad.db }]} {} do_catchsql_test 46.1 { SELECT snippet(t1,'[','', '--',-1,10) FROM t1('*'); | | | 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 | | 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-1ee8bd451dd1ad.db }]} {} do_catchsql_test 46.1 { SELECT snippet(t1,'[','', '--',-1,10) FROM t1('*'); } {0 {{}}} #-------------------------------------------------------------------------- reset_db do_test 47.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 40960 pagesize 4096 filename 4b6fc659283f2735616c.db |
︙ | ︙ | |||
6413 6414 6415 6416 6417 6418 6419 | | page 10 offset 36864 | 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 4b6fc659283f2735616c.db }]} {} do_catchsql_test 47.1 { | < < < < < | | | < | | 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 | | page 10 offset 36864 | 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 4b6fc659283f2735616c.db }]} {} do_catchsql_test 47.1 { SELECT snippet(t1, -1, '.', '..', '[', 50), highlight(t1, 2, '[', ']') FROM t1('g h') WHERE rank MATCH 'bm25(1.0, 1.0)' ORDER BY rank; } {1 {database disk image is malformed}} #-------------------------------------------------------------------------- reset_db do_test 48.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 32768 pagesize 4096 filename crash-44a8305b4bd86f.db |
︙ | ︙ | |||
6904 6905 6906 6907 6908 6909 6910 | do_catchsql_test 50.1 { SELECT term FROM t4 WHERE term LIKE '»as'; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db | | | 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 | do_catchsql_test 50.1 { SELECT term FROM t4 WHERE term LIKE '»as'; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_execsql_test 51.1 { BEGIN TRANSACTION; PRAGMA writable_schema=ON; CREATE VIRTUAL TABLE t1 USING fts5(a,b,c); CREATE TABLE IF NOT EXISTS 't1_data'(id INTEGER PRIMARY KEY, block BLOB); REPLACE INTO t1_data VALUES(1,X'2eb1182424'); REPLACE INTO t1_data VALUES(10,X'000000000102080002010101020107'); INSERT INTO t1_data VALUES(137438953473,X'0000032b0230300102060102060102061f0203010203010203010832303136303630390102070102070102070101340102050102050102050101350102040102040102040207303030303030301c023d010204010204010662696e6172790306010202030601020203060102020306010202030601020203060102020306010202030601020203060102020306010202030601020203060102020108636f6d70696c657201020201020201020201066462737461740702030102030102030204656275670402020102020102020107656e61626c6507020201020201020201020201020201020201020201020201020201020201020201020201020201020201020201020201020201020201020201020201020202087874656e73696f6e1f02040102040102040104667473340a02030102030102030401350d020301020301020301036763630102030102030102030206656f706f6c7910020301020301020301056a736f6e3113020301020301020301046c6f61641f020301020301020301036d61781c02020102020102020205656d6f72791c020301020301020304047379733516020301020301020301066e6f6361736502060102020306010202030601020213060102020306010202030601020203060102020306010202030601020203060102020306010202030601020201046f6d69741f0202010202010202010572747265651902030102030102030402696d010601020203060102020306010202030601020203060102020306010202030601020203060102020306010202030601020203060102020306010202010a7468726561647361666522020201020201020201047674616207020401020401020401017801060101020106010102010601010201060101020106010102010601010201060101020106010102010601010201060101020106010102010601010201060101020106010102010601010201060101020106010102010601010201060101020106010102ad060101020106010102010601010201060101020106010101010601010201060101020106010102010601010201060101020106010102010601010201060101020106010102010601010201060101020415130c0c124413110f47130efc0e11100f0e100f440f1040150f'); |
︙ | ︙ | |||
6972 6973 6974 6975 6976 6977 6978 | INSERT INTO t2 VALUES('integrity-check'); PRAGMA writable_schema=OFF; COMMIT; } {} do_catchsql_test 51.1 { SELECT max(rowid)==0 FROM t1('e*'); | | | 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 | INSERT INTO t2 VALUES('integrity-check'); PRAGMA writable_schema=OFF; COMMIT; } {} do_catchsql_test 51.1 { SELECT max(rowid)==0 FROM t1('e*'); } {0 0} #-------------------------------------------------------------------------- reset_db do_test 52.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 40960 pagesize 4096 filename crash-2b92f77ddfe191.db |
︙ | ︙ | |||
7126 7127 7128 7129 7130 7131 7132 | | 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-2b92f77ddfe191.db }]} {} do_catchsql_test 52.1 { SELECT fts5_decode(id, block) FROM t1_data; | | | 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 | | 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-2b92f77ddfe191.db }]} {} do_catchsql_test 52.1 { SELECT fts5_decode(id, block) FROM t1_data; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_test 53.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 24576 pagesize 4096 filename crash-dbe9b7614da103.db |
︙ | ︙ | |||
7342 7343 7344 7345 7346 7347 7348 | | 4080: 00 00 03 03 02 01 03 03 02 02 01 02 02 01 0c e9 ................ | end crash-dbe9b7614da103.db }]} {} do_catchsql_test 53.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; | | | 7337 7338 7339 7340 7341 7342 7343 7344 7345 7346 7347 7348 7349 7350 7351 | | 4080: 00 00 03 03 02 01 03 03 02 02 01 02 02 01 0c e9 ................ | end crash-dbe9b7614da103.db }]} {} do_catchsql_test 53.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; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_test 54.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 24576 pagesize 4096 filename crash-03a1855566d9ae.db |
︙ | ︙ | |||
7558 7559 7560 7561 7562 7563 7564 | | 0: 0d 00 00 00 03 0f f2 00 0f fc 0f f7 0f f2 00 00 ................ | 4080: 00 00 23 03 02 01 03 03 02 02 01 02 02 00 f2 09 ..#............. | end crash-03a1855566d9ae.db }]} {} do_catchsql_test 54.1 { SELECT rowid==-1 FROM t1('t*'); | | | 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 7564 7565 7566 7567 | | 0: 0d 00 00 00 03 0f f2 00 0f fc 0f f7 0f f2 00 00 ................ | 4080: 00 00 23 03 02 01 03 03 02 02 01 02 02 00 f2 09 ..#............. | end crash-03a1855566d9ae.db }]} {} do_catchsql_test 54.1 { SELECT rowid==-1 FROM t1('t*'); } {0 {0 0 0}} #------------------------------------------------------------------------- reset_db do_test 55.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 32768 pagesize 4096 filename crash-b366b5ac0d3887.db |
︙ | ︙ | |||
7773 7774 7775 7776 7777 7778 7779 | | 0: 0d 00 00 00 03 0f d6 00 0f f4 0f e9 0f d6 00 00 ................ | 4048: 00 00 00 00 00 00 11 03 02 2b 69 6e 74 65 77 72 .........+intewr | 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-b366b5ac0d3887.db }]} {} | | < > | 7768 7769 7770 7771 7772 7773 7774 7775 7776 7777 7778 7779 7780 7781 7782 7783 7784 7785 | | 0: 0d 00 00 00 03 0f d6 00 0f f4 0f e9 0f d6 00 00 ................ | 4048: 00 00 00 00 00 00 11 03 02 2b 69 6e 74 65 77 72 .........+intewr | 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-b366b5ac0d3887.db }]} {} do_execsql_test 55.1 { SAVEPOINT one; DELETE FROM t1 WHERE a MATCH 'ts'; } do_execsql_test 55.2 { ROLLBACK TO one; } #------------------------------------------------------------------------- reset_db |
︙ | ︙ | |||
8009 8010 8011 8012 8013 8014 8015 | # may return SQLITE_CONSTRAINT instead of SQLITE_CORRUPT. This is because # the corrupt db in the test over-reads the page buffer slightly, with # different results depending on whether or not the page-cache is in use. if {$res=="1 {constraint failed}"} { set res "1 {database disk image is malformed}" } set res | | | 8004 8005 8006 8007 8008 8009 8010 8011 8012 8013 8014 8015 8016 8017 8018 | # may return SQLITE_CONSTRAINT instead of SQLITE_CORRUPT. This is because # the corrupt db in the test over-reads the page buffer slightly, with # different results depending on whether or not the page-cache is in use. if {$res=="1 {constraint failed}"} { set res "1 {database disk image is malformed}" } set res } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_test 57.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 28672 pagesize 4096 filename x.db |
︙ | ︙ | |||
8127 8128 8129 8130 8131 8132 8133 | | 4064: 64 11 02 02 2b 69 6e 74 65 67 72 69 74 79 2d 63 d...+integrity-c | 4080: 68 65 63 6b 0a 01 02 1d 6f 70 74 69 6d 69 7a 65 heck....optimize | end x.db }]} {} do_catchsql_test 57.1 { INSERT INTO t1(t1) VALUES('optimize') | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 8122 8123 8124 8125 8126 8127 8128 8129 8130 8131 8132 8133 8134 | | 4064: 64 11 02 02 2b 69 6e 74 65 67 72 69 74 79 2d 63 d...+integrity-c | 4080: 68 65 63 6b 0a 01 02 1d 6f 70 74 69 6d 69 7a 65 heck....optimize | end x.db }]} {} do_catchsql_test 57.1 { INSERT INTO t1(t1) VALUES('optimize') } {1 {database disk image is malformed}} sqlite3_fts5_may_be_corrupt 0 finish_test |
Deleted ext/fts5/test/fts5corrupt4.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/fts5/test/fts5corrupt5.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/fts5/test/fts5corrupt6.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to ext/fts5/test/fts5delete.test.
︙ | ︙ | |||
46 47 48 49 50 51 52 | 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') } } } {} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 46 47 48 49 50 51 52 53 | 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 |
Changes to ext/fts5/test/fts5detail.test.
︙ | ︙ | |||
208 209 210 211 212 213 214 | 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)}} | < < < < | 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} { |
︙ | ︙ |
Changes to ext/fts5/test/fts5doclist.test.
︙ | ︙ | |||
38 39 40 41 42 43 44 | INSERT INTO ccc(x899) SELECT rnddoc(500) FROM ii; } do_execsql_test 1.2 { INSERT INTO ccc(ccc) VALUES('integrity-check'); } | < < < < < < < < < < < < < < < < < < < < < | 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 |
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 | 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.1 { SELECT fts5_expr_tcl() } {1 {wrong number of arguments to function fts5_expr_tcl}} 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; } {1 -1e-06} do_execsql_test 3.2 { SELECT rowid FROM e1 WHERE e1 MATCH '"/" OR "just"' } 1 |
︙ | ︙ |
Changes to ext/fts5/test/fts5fault4.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 | # This file is focused on OOM errors. # source [file join [file dirname [info script]] fts5_common.tcl] source $testdir/malloc_common.tcl set testprefix fts5fault4 | | < < < < | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | # This file is focused on OOM errors. # source [file join [file dirname [info script]] fts5_common.tcl] source $testdir/malloc_common.tcl set testprefix fts5fault4 # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts5 { finish_test return } #------------------------------------------------------------------------- # An OOM while dropping an fts5 table. # db func rnddoc fts5_rnddoc do_test 1.0 { execsql { CREATE VIRTUAL TABLE xx USING fts5(x) } } {} |
︙ | ︙ | |||
391 392 393 394 395 396 397 | faultsim_save_and_close do_faultsim_test 14.1 -faults oom-t* -prep { faultsim_restore_and_reopen db eval { SELECT * FROM "tbl one" } } -body { db eval { ALTER TABLE "tbl one" RENAME TO "tbl two" } } -test { | | | 387 388 389 390 391 392 393 394 395 396 397 | faultsim_save_and_close do_faultsim_test 14.1 -faults oom-t* -prep { faultsim_restore_and_reopen db eval { SELECT * FROM "tbl one" } } -body { db eval { ALTER TABLE "tbl one" RENAME TO "tbl two" } } -test { faultsim_test_result {0 {}} } finish_test |
Changes to ext/fts5/test/fts5faultB.test.
︙ | ︙ | |||
143 144 145 146 147 148 149 | } do_faultsim_test 5.1 -faults oom* -body { execsql { SELECT rowid FROM t1('^a OR ^b') } } -test { faultsim_test_result {0 {1 4}} } | < < < < < < < < < < < < < < < < < < < < < < | 143 144 145 146 147 148 149 150 151 | } 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 |
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 fts5faultA # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts5 { finish_test return } |
︙ | ︙ |
Deleted ext/fts5/test/fts5faultE.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 } {1 {database or disk is full}} 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 | 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 2.0 { 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 finish_test |
Changes to ext/fts5/test/fts5integrity.test.
︙ | ︙ | |||
184 185 186 187 188 189 190 | } { do_execsql_test 6.$tn.1 { DROP TABLE IF EXISTS hh; CREATE VIRTUAL TABLE hh USING fts5(y); INSERT INTO hh(hh, rank) VALUES('pgsz', $pgsz); WITH s(i) AS (SELECT 0 UNION ALL SELECT i+1 FROM s WHERE i<999) | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | } { do_execsql_test 6.$tn.1 { DROP TABLE IF EXISTS hh; CREATE VIRTUAL TABLE hh USING fts5(y); INSERT INTO hh(hh, rank) VALUES('pgsz', $pgsz); WITH s(i) AS (SELECT 0 UNION ALL SELECT i+1 FROM s WHERE i<999) INSERT INTO hh SELECT printf("%.3d%.3d%.3d %.3d%.3d%.3d",i,i,i,i+1,i+1,i+1) FROM s; WITH s(i) AS (SELECT 0 UNION ALL SELECT i+1 FROM s WHERE i<999) INSERT INTO hh SELECT printf("%.3d%.3d%.3d %.3d%.3d%.3d",i,i,i,i+1,i+1,i+1) FROM s; INSERT INTO hh(hh) VALUES('optimize'); } do_test 6.$tn.2 { set ok 0 for {set i 0} {$i < 1000} {incr i} { set T [format %.3d%.3d%.3d $i $i $i] 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 |
Changes to ext/fts5/test/fts5matchinfo.test.
︙ | ︙ | |||
487 488 489 490 491 492 493 | 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}} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 487 488 489 490 491 492 493 494 | 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 |
Deleted ext/fts5/test/fts5misc.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/fts5/test/fts5multi.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/fts5/test/fts5optimize2.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 TABLE t1 `--SCAN TABLE f1 VIRTUAL TABLE INDEX 65537: } do_eqp_test 1.2 { SELECT * FROM t1, f1 WHERE f1 > t1.x } { QUERY PLAN |--SCAN TABLE f1 VIRTUAL TABLE INDEX 0: `--SCAN TABLE t1 } do_eqp_test 1.3 { SELECT * FROM f1 WHERE f1 MATCH ? ORDER BY ff } { QUERY PLAN |--SCAN TABLE f1 VIRTUAL TABLE INDEX 65537: `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 1.4 { SELECT * FROM f1 ORDER BY rank } { QUERY PLAN |--SCAN TABLE f1 VIRTUAL TABLE INDEX 0: `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 1.5 { SELECT * FROM f1 WHERE rank MATCH ? } {SCAN TABLE f1 VIRTUAL TABLE INDEX 2:} finish_test |
Deleted ext/fts5/test/fts5prefix2.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to ext/fts5/test/fts5rank.test.
︙ | ︙ | |||
158 159 160 161 162 163 164 | 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} | < < < < < < < < < < < < < < < < < < | 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 |
Deleted ext/fts5/test/fts5savepoint.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to ext/fts5/test/fts5simple.test.
︙ | ︙ | |||
463 464 465 466 467 468 469 | } {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} | < < < < < < < < < < < < < | 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 |
Changes to ext/fts5/test/fts5tok1.test.
︙ | ︙ | |||
107 108 109 110 111 112 113 | } {1 {vtable constructor failed: tX}} do_catchsql_test 2.1 { CREATE VIRTUAL TABLE t4 USING fts5tokenize; SELECT * FROM t4; } {1 {SQL logic error}} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 107 108 109 110 111 112 113 114 115 | } {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 |
Deleted ext/fts5/test/fts5trigram.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/fts5/test/fts5ubsan.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to ext/fts5/test/fts5vocab.test.
︙ | ︙ | |||
538 539 540 541 542 543 544 | do_execsql_test 10.7.2 { SELECT * FROM t2 WHERE term>?; } do_execsql_test 10.7.3 { SELECT * FROM t2 WHERE term=?; } | < < < < | < < < < < < < | 538 539 540 541 542 543 544 545 546 | do_execsql_test 10.7.2 { SELECT * FROM t2 WHERE term>?; } do_execsql_test 10.7.3 { SELECT * FROM t2 WHERE term=?; } finish_test |
Changes to ext/fts5/test/fts5vocab2.test.
︙ | ︙ | |||
229 230 231 232 233 234 235 236 | 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}} } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 229 230 231 232 233 234 235 236 237 | 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}} } finish_test |
Changes to ext/fts5/tool/fts5txt2db.tcl.
︙ | ︙ | |||
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. # proc process_cmdline {} { cmdline::process ::A $::argv { {fts5 "use fts5 (this is the default)"} {fts4 "use fts4"} | < | 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 |
︙ | ︙ | |||
172 173 174 175 176 177 178 | 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)" } | < | 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. |
︙ | ︙ |
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 | # 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 date [string range $date 0 [string last . $date]-1] 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 | 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 -shared icu.c `icu-config --ldflags` -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. |
︙ | ︙ | |||
149 150 151 152 153 154 155 | problem and uses the same solution. However, since the ICU extension code does not include the SQLite file "limits.h", modifying the default value therein does not affect the ICU extension. The default value of SQLITE_MAX_LIKE_PATTERN_LENGTH used by the ICU extension LIKE operator is 50000, defined in source file "icu.c". | | | > > > | > > | > | 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | problem and uses the same solution. However, since the ICU extension code does not include the SQLite file "limits.h", modifying the default value therein does not affect the ICU extension. The default value of SQLITE_MAX_LIKE_PATTERN_LENGTH used by the ICU extension LIKE operator is 50000, defined in source file "icu.c". 3.3 Collation Sequence Security Issue Internally, SQLite assumes that indices stored in database files are sorted according to the collation sequence indicated by the SQL schema. Changing the definition of a collation sequence after an index has been built is therefore equivalent to database corruption. The SQLite library is not very well tested under these conditions, and may contain potential buffer overruns or other programming errors that could be exploited by a malicious programmer. If the ICU extension is used in an environment where potentially malicious users may execute arbitrary SQL (i.e. gears), they should be prevented from invoking the icu_load_collation() function, possibly using the authorisation callback. |
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( !prevEscape && uPattern==MATCH_ALL ){ /* 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( !prevEscape && uPattern==MATCH_ONE ){ /* Case 2. */ if( *zString==0 ) return 0; SQLITE_ICU_SKIP_UTF8(zString); }else if( !prevEscape && uPattern==(uint32_t)uEsc){ /* Case 3. */ prevEscape = 1; }else{ /* Case 4. */ uint32_t uString; SQLITE_ICU_READ_UTF8(zString, uString); |
︙ | ︙ | |||
295 296 297 298 299 300 301 | if( !zPattern ){ return; } pExpr = uregex_open(zPattern, -1, 0, 0, &status); if( U_SUCCESS(status) ){ sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete); | < | | | 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 | if( !zPattern ){ return; } pExpr = uregex_open(zPattern, -1, 0, 0, &status); if( U_SUCCESS(status) ){ sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete); }else{ assert(!pExpr); icuFunctionError(p, "uregex_open", status); return; } } /* Configure the text that the regular expression operates on. */ uregex_setText(pExpr, zString, -1, &status); |
︙ | ︙ | |||
496 497 498 499 500 501 502 | } } /* ** Register the ICU extension functions with database db. */ int sqlite3IcuInit(sqlite3 *db){ | < | | | | | | | | | | | | | | 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 | } } /* ** 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 */ unsigned short 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, 1, icuLoadCollation}, #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) {"regexp", 2, SQLITE_ANY|SQLITE_DETERMINISTIC, 0, icuRegexpFunc}, {"lower", 1, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16}, {"lower", 2, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16}, {"upper", 1, SQLITE_UTF16|SQLITE_DETERMINISTIC, 1, icuCaseFunc16}, {"upper", 2, SQLITE_UTF16|SQLITE_DETERMINISTIC, 1, icuCaseFunc16}, {"lower", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuCaseFunc16}, {"lower", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuCaseFunc16}, {"upper", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, 1, icuCaseFunc16}, {"upper", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 1, icuCaseFunc16}, {"like", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuLikeFunc}, {"like", 3, SQLITE_UTF8|SQLITE_DETERMINISTIC, 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 27 | #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 += -DLSM_MUTEX_PTHREADS=1 -I$(LSMDIR) -DHAVE_ZLIB lsm.so: $(LSMOBJ) $(TCCX) -shared -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 657 658 | 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 325 326 | 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 141 142 143 | 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 72 73 74 75 | 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_master 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 370 | } } 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 981 982 | } return rc; } /* ** End of background checkpointer. *************************************************************************/ |
Changes to ext/lsm1/lsmInt.h.
︙ | ︙ | |||
40 41 42 43 44 45 46 | # endif #else # ifndef LSM_DEBUG # define LSM_DEBUG # endif #endif | < < | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | # endif #else # ifndef LSM_DEBUG # define LSM_DEBUG # endif #endif /* ** Default values for various data structure parameters. These may be ** overridden by calls to lsm_config(). */ #define LSM_DFLT_PAGE_SIZE (4 * 1024) #define LSM_DFLT_BLOCK_SIZE (1 * 1024 * 1024) #define LSM_DFLT_AUTOFLUSH (1 * 1024 * 1024) |
︙ | ︙ | |||
403 404 405 406 407 408 409 | u32 aSnapshot[LSM_META_PAGE_SIZE / sizeof(u32)]; }; struct Segment { LsmPgno iFirst; /* First page of this run */ LsmPgno iLastPg; /* Last page of this run */ LsmPgno iRoot; /* Root page number (if any) */ | | | 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 | u32 aSnapshot[LSM_META_PAGE_SIZE / sizeof(u32)]; }; struct Segment { LsmPgno iFirst; /* First page of this run */ LsmPgno iLastPg; /* Last page of this run */ LsmPgno iRoot; /* Root page number (if any) */ int nSize; /* Size of this run in pages */ Redirect *pRedirect; /* Block redirects (or NULL) */ }; /* ** iSplitTopic/pSplitKey/nSplitKey: ** If nRight>0, this buffer contains a copy of the largest key that has |
︙ | ︙ | |||
851 852 853 854 855 856 857 | ** Functions from "lsm_varint.c". */ int lsmVarintPut32(u8 *, int); int lsmVarintGet32(u8 *, int *); int lsmVarintPut64(u8 *aData, i64 iVal); int lsmVarintGet64(const u8 *aData, i64 *piVal); | < < | 849 850 851 852 853 854 855 856 857 858 859 860 861 862 | ** Functions from "lsm_varint.c". */ int lsmVarintPut32(u8 *, int); int lsmVarintGet32(u8 *, int *); int lsmVarintPut64(u8 *aData, i64 iVal); int lsmVarintGet64(const u8 *aData, i64 *piVal); int lsmVarintLen32(int); int lsmVarintSize(u8 c); /* ** Functions from file "main.c". */ void lsmLogMessage(lsm_db *, int, const char *, ...); |
︙ | ︙ |
Changes to ext/lsm1/lsm_ckpt.c.
︙ | ︙ | |||
507 508 509 510 511 512 513 | Segment *pSegment /* Populate this structure */ ){ assert( pSegment->iFirst==0 && pSegment->iLastPg==0 ); assert( pSegment->nSize==0 && pSegment->iRoot==0 ); pSegment->iFirst = ckptGobble64(aIn, piIn); pSegment->iLastPg = ckptGobble64(aIn, piIn); pSegment->iRoot = ckptGobble64(aIn, piIn); | | | 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 | Segment *pSegment /* Populate this structure */ ){ assert( pSegment->iFirst==0 && pSegment->iLastPg==0 ); assert( pSegment->nSize==0 && pSegment->iRoot==0 ); pSegment->iFirst = ckptGobble64(aIn, piIn); pSegment->iLastPg = ckptGobble64(aIn, piIn); pSegment->iRoot = ckptGobble64(aIn, piIn); pSegment->nSize = (int)ckptGobble64(aIn, piIn); assert( pSegment->iFirst ); } static int ckptSetupMerge(lsm_db *pDb, u32 *aInt, int *piIn, Level *pLevel){ Merge *pMerge; /* Allocated Merge object */ int nInput; /* Number of input segments in merge */ int iIn = *piIn; /* Next value to read from aInt[] */ |
︙ | ︙ |
Changes to ext/lsm1/lsm_file.c.
︙ | ︙ | |||
211 212 213 214 215 216 217 | struct FileSystem { lsm_db *pDb; /* Database handle that owns this object */ lsm_env *pEnv; /* Environment pointer */ char *zDb; /* Database file name */ char *zLog; /* Database file name */ int nMetasize; /* Size of meta pages in bytes */ int nMetaRwSize; /* Read/written size of meta pages in bytes */ | | | | 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | struct FileSystem { lsm_db *pDb; /* Database handle that owns this object */ lsm_env *pEnv; /* Environment pointer */ char *zDb; /* Database file name */ char *zLog; /* Database file name */ int nMetasize; /* Size of meta pages in bytes */ int nMetaRwSize; /* Read/written size of meta pages in bytes */ int nPagesize; /* Database page-size in bytes */ int nBlocksize; /* Database block-size in bytes */ /* r/w file descriptors for both files. */ LsmFile *pLsmFile; /* Used after lsm_close() to link into list */ lsm_file *fdDb; /* Database file */ lsm_file *fdLog; /* Log file */ int szSector; /* Database file sector size */ |
︙ | ︙ | |||
885 886 887 888 889 890 891 | if( pFS->pCompress ){ if( iBlock==1 ){ iPg = pFS->nMetasize * 2 + 4; }else{ iPg = pFS->nBlocksize * (LsmPgno)(iBlock-1) + 4; } }else{ | | | 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 | if( pFS->pCompress ){ if( iBlock==1 ){ iPg = pFS->nMetasize * 2 + 4; }else{ iPg = pFS->nBlocksize * (LsmPgno)(iBlock-1) + 4; } }else{ const int nPagePerBlock = (pFS->nBlocksize / pFS->nPagesize); if( iBlock==1 ){ iPg = 1 + ((pFS->nMetasize*2 + pFS->nPagesize - 1) / pFS->nPagesize); }else{ iPg = 1 + (iBlock-1) * nPagePerBlock; } } return iPg; |
︙ | ︙ | |||
1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 | ** This function is never called in compressed database mode. */ static void fsGrowMapping( FileSystem *pFS, /* File system object */ i64 iSz, /* Minimum size to extend mapping to */ int *pRc /* IN/OUT: Error code */ ){ assert( PAGE_HASPREV==4 ); if( *pRc==LSM_OK && iSz>pFS->nMap ){ int rc; u8 *aOld = pFS->pMap; rc = lsmEnvRemap(pFS->pEnv, pFS->fdDb, iSz, &pFS->pMap, &pFS->nMap); if( rc==LSM_OK && pFS->pMap!=aOld ){ | > | 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 | ** This function is never called in compressed database mode. */ static void fsGrowMapping( FileSystem *pFS, /* File system object */ i64 iSz, /* Minimum size to extend mapping to */ int *pRc /* IN/OUT: Error code */ ){ assert( pFS->pCompress==0 ); assert( PAGE_HASPREV==4 ); if( *pRc==LSM_OK && iSz>pFS->nMap ){ int rc; u8 *aOld = pFS->pMap; rc = lsmEnvRemap(pFS->pEnv, pFS->fdDb, iSz, &pFS->pMap, &pFS->nMap); if( rc==LSM_OK && pFS->pMap!=aOld ){ |
︙ | ︙ | |||
1867 1868 1869 1870 1871 1872 1873 | int iBlk; assert( pRun->nSize>0 ); assert( 0==fsSegmentRedirects(pFS, pRun) ); assert( nPgno>0 && 0==fsPageRedirects(pFS, pRun, aPgno[0]) ); iBlk = fsPageToBlock(pFS, pRun->iFirst); | | | | | 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 | int iBlk; assert( pRun->nSize>0 ); assert( 0==fsSegmentRedirects(pFS, pRun) ); assert( nPgno>0 && 0==fsPageRedirects(pFS, pRun, aPgno[0]) ); iBlk = fsPageToBlock(pFS, pRun->iFirst); pRun->nSize += (int)(pRun->iFirst - fsFirstPageOnBlock(pFS, iBlk)); while( rc==LSM_OK ){ int iNext = 0; LsmPgno iFirst = firstOnBlock(pFS, iBlk, aPgno, nPgno); if( iFirst ){ pRun->iFirst = iFirst; break; } rc = fsBlockNext(pFS, pRun, iBlk, &iNext); if( rc==LSM_OK ) rc = fsFreeBlock(pFS, pSnapshot, pRun, iBlk); pRun->nSize -= (int)( 1 + fsLastPageOnBlock(pFS, iBlk) - fsFirstPageOnBlock(pFS, iBlk) ); iBlk = iNext; } pRun->nSize -= (int)(pRun->iFirst - fsFirstPageOnBlock(pFS, iBlk)); assert( pRun->nSize>0 ); } /* ** This function is only used in compressed database mode. ** ** Argument iPg is the page number (byte offset) of a page within segment |
︙ | ︙ |
Changes to ext/lsm1/lsm_main.c.
︙ | ︙ | |||
428 429 430 431 432 433 434 | } va_end(ap); return rc; } void lsmAppendSegmentList(LsmString *pStr, char *zPre, Segment *pSeg){ | | | 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 | } va_end(ap); return rc; } void lsmAppendSegmentList(LsmString *pStr, char *zPre, Segment *pSeg){ lsmStringAppendf(pStr, "%s{%d %d %d %d}", zPre, pSeg->iFirst, pSeg->iLastPg, pSeg->iRoot, pSeg->nSize ); } static int infoGetWorker(lsm_db *pDb, Snapshot **pp, int *pbUnlock){ int rc = LSM_OK; |
︙ | ︙ |
Changes to ext/lsm1/lsm_shared.c.
︙ | ︙ | |||
1302 1303 1304 1305 1306 1307 1308 | rc = lsmShmCacheChunks(db, 1); if( rc==LSM_OK ){ db->pShmhdr = (ShmHeader *)db->apShm[0]; } } } | < < < < < < < < < < < < < < < < < < | 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 | rc = lsmShmCacheChunks(db, 1); if( rc==LSM_OK ){ db->pShmhdr = (ShmHeader *)db->apShm[0]; } } } if( rc==LSM_OK ){ rc = lsmBeginReadTrans(db); } } return rc; } |
︙ | ︙ |
Changes to ext/lsm1/lsm_sorted.c.
︙ | ︙ | |||
521 522 523 524 525 526 527 | Page *pPg, /* Page to read from */ int iCell, /* Index of cell on page to read */ int *piTopic, /* OUT: Topic associated with this key */ int *pnKey, /* OUT: Size of key in bytes */ LsmBlob *pBlob /* If required, use this for dynamic memory */ ){ u8 *pKey; | | | | | 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 | Page *pPg, /* Page to read from */ int iCell, /* Index of cell on page to read */ int *piTopic, /* OUT: Topic associated with this key */ int *pnKey, /* OUT: Size of key in bytes */ LsmBlob *pBlob /* If required, use this for dynamic memory */ ){ u8 *pKey; int nDummy; int eType; u8 *aData; int nData; aData = fsPageData(pPg, &nData); assert( !(pageGetFlags(aData, nData) & SEGMENT_BTREE_FLAG) ); assert( iCell<pageGetNRec(aData, nData) ); pKey = pageGetCell(aData, nData, iCell); eType = *pKey++; pKey += lsmVarintGet32(pKey, &nDummy); pKey += lsmVarintGet32(pKey, pnKey); if( rtIsWrite(eType) ){ pKey += lsmVarintGet32(pKey, &nDummy); } *piTopic = rtTopic(eType); sortedReadData(pSeg, pPg, pKey-aData, *pnKey, (void **)&pKey, pBlob); return pKey; } |
︙ | ︙ | |||
653 654 655 656 657 658 659 | ); pCsr->eType |= LSM_SEPARATOR; } return rc; } | | | | | 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 | ); pCsr->eType |= LSM_SEPARATOR; } return rc; } static int btreeCursorPtr(u8 *aData, int nData, int iCell){ int nCell; nCell = pageGetNRec(aData, nData); if( iCell>=nCell ){ return (int)pageGetPtr(aData, nData); } return (int)pageGetRecordPtr(aData, nData, iCell); } static int btreeCursorNext(BtreeCursor *pCsr){ int rc = LSM_OK; BtreePg *pPg = &pCsr->aPg[pCsr->iPg]; int nCell; |
︙ | ︙ | |||
747 748 749 750 751 752 753 | } static int btreeCursorFirst(BtreeCursor *pCsr){ int rc; Page *pPg = 0; FileSystem *pFS = pCsr->pFS; | | | 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 | } static int btreeCursorFirst(BtreeCursor *pCsr){ int rc; Page *pPg = 0; FileSystem *pFS = pCsr->pFS; int iPg = (int)pCsr->pSeg->iRoot; do { rc = lsmFsDbPageGet(pFS, pCsr->pSeg, iPg, &pPg); assert( (rc==LSM_OK)==(pPg!=0) ); if( rc==LSM_OK ){ u8 *aData; int nData; |
︙ | ︙ | |||
775 776 777 778 779 780 781 | } } if( rc==LSM_OK ){ assert( pCsr->aPg[pCsr->nDepth].iCell==0 ); pCsr->aPg[pCsr->nDepth].pPage = pPg; pCsr->nDepth++; | | | 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 | } } if( rc==LSM_OK ){ assert( pCsr->aPg[pCsr->nDepth].iCell==0 ); pCsr->aPg[pCsr->nDepth].pPage = pPg; pCsr->nDepth++; iPg = (int)pageGetRecordPtr(aData, nData, 0); } } }while( rc==LSM_OK ); lsmFsPageRelease(pPg); pCsr->iPg = pCsr->nDepth-1; if( rc==LSM_OK && pCsr->nDepth ){ |
︙ | ︙ | |||
867 868 869 870 871 872 873 | /* Populate any other aPg[] array entries */ if( rc==LSM_OK && nDepth>1 ){ LsmBlob blob = {0,0,0}; void *pSeek; int nSeek; int iTopicSeek; int iPg = 0; | | | 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 | /* Populate any other aPg[] array entries */ if( rc==LSM_OK && nDepth>1 ){ LsmBlob blob = {0,0,0}; void *pSeek; int nSeek; int iTopicSeek; int iPg = 0; int iLoad = (int)pSeg->iRoot; Page *pPg = pCsr->aPg[nDepth-1].pPage; if( pageObjGetNRec(pPg)==0 ){ /* This can happen when pPg is the right-most leaf in the b-tree. ** In this case, set the iTopicSeek/pSeek/nSeek key to a value ** greater than any real key. */ assert( iCell==-1 ); |
︙ | ︙ | |||
899 900 901 902 903 904 905 | int iMin; int iMax; int iCell2; aData = fsPageData(pPg2, &nData); assert( (pageGetFlags(aData, nData) & SEGMENT_BTREE_FLAG) ); | | | 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 | int iMin; int iMax; int iCell2; aData = fsPageData(pPg2, &nData); assert( (pageGetFlags(aData, nData) & SEGMENT_BTREE_FLAG) ); iLoad = (int)pageGetPtr(aData, nData); iCell2 = pageGetNRec(aData, nData); iMax = iCell2-1; iMin = 0; while( iMax>=iMin ){ int iTry = (iMin+iMax)/2; void *pKey; int nKey; /* Key for cell iTry */ |
︙ | ︙ | |||
922 923 924 925 926 927 928 | res = sortedKeyCompare( xCmp, iTopicSeek, pSeek, nSeek, iTopic, pKey, nKey ); assert( res!=0 ); if( res<0 ){ | | | 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 | res = sortedKeyCompare( xCmp, iTopicSeek, pSeek, nSeek, iTopic, pKey, nKey ); assert( res!=0 ); if( res<0 ){ iLoad = (int)iPtr; iCell2 = iTry; iMax = iTry-1; }else{ iMin = iTry+1; } } |
︙ | ︙ | |||
1009 1010 1011 1012 1013 1014 1015 | /* ** Load a new page into the SegmentPtr object pPtr. */ static int segmentPtrLoadPage( FileSystem *pFS, SegmentPtr *pPtr, /* Load page into this SegmentPtr object */ | | | 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 | /* ** Load a new page into the SegmentPtr object pPtr. */ static int segmentPtrLoadPage( FileSystem *pFS, SegmentPtr *pPtr, /* Load page into this SegmentPtr object */ int iNew /* Page number of new page */ ){ Page *pPg = 0; /* The new page */ int rc; /* Return Code */ rc = lsmFsDbPageGet(pFS, pPtr->pSeg, iNew, &pPg); assert( rc==LSM_OK || pPg==0 ); segmentPtrSetPage(pPtr, pPg); |
︙ | ︙ | |||
1629 1630 1631 1632 1633 1634 1635 | static int segmentPtrSeek( MultiCursor *pCsr, /* Cursor context */ SegmentPtr *pPtr, /* Pointer to seek */ int iTopic, /* Key topic to seek to */ void *pKey, int nKey, /* Key to seek to */ int eSeek, /* Search bias - see above */ | | | 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 | static int segmentPtrSeek( MultiCursor *pCsr, /* Cursor context */ SegmentPtr *pPtr, /* Pointer to seek */ int iTopic, /* Key topic to seek to */ void *pKey, int nKey, /* Key to seek to */ int eSeek, /* Search bias - see above */ int *piPtr, /* OUT: FC pointer */ int *pbStop ){ int (*xCmp)(void *, int, void *, int) = pCsr->pDb->xCmp; int res = 0; /* Result of comparison operation */ int rc = LSM_OK; int iMin; int iMax; |
︙ | ︙ | |||
1755 1756 1757 1758 1759 1760 1761 | ){ assert( eSeek!=LSM_SEEK_EQ ); rc = segmentPtrAdvance(pCsr, pPtr, eSeek==LSM_SEEK_LE); } } assert( rc!=LSM_OK || assertSeekResult(pCsr,pPtr,iTopic,pKey,nKey,eSeek) ); | | | | | 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 | ){ assert( eSeek!=LSM_SEEK_EQ ); rc = segmentPtrAdvance(pCsr, pPtr, eSeek==LSM_SEEK_LE); } } assert( rc!=LSM_OK || assertSeekResult(pCsr,pPtr,iTopic,pKey,nKey,eSeek) ); *piPtr = (int)iPtrOut; return rc; } static int seekInBtree( MultiCursor *pCsr, /* Multi-cursor object */ Segment *pSeg, /* Seek within this segment */ int iTopic, void *pKey, int nKey, /* Key to seek to */ LsmPgno *aPg, /* OUT: Page numbers */ Page **ppPg /* OUT: Leaf (sorted-run) page reference */ ){ int i = 0; int rc; int iPg; Page *pPg = 0; LsmBlob blob = {0, 0, 0}; iPg = (int)pSeg->iRoot; do { LsmPgno *piFirst = 0; if( aPg ){ aPg[i++] = iPg; piFirst = &aPg[i]; } |
︙ | ︙ | |||
1795 1796 1797 1798 1799 1800 1801 | int nRec; int flags; aData = fsPageData(pPg, &nData); flags = pageGetFlags(aData, nData); if( (flags & SEGMENT_BTREE_FLAG)==0 ) break; | | | 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 | int nRec; int flags; aData = fsPageData(pPg, &nData); flags = pageGetFlags(aData, nData); if( (flags & SEGMENT_BTREE_FLAG)==0 ) break; iPg = (int)pageGetPtr(aData, nData); nRec = pageGetNRec(aData, nData); iMin = 0; iMax = nRec-1; while( iMax>=iMin ){ int iTry = (iMin+iMax)/2; void *pKeyT; int nKeyT; /* Key for cell iTry */ |
︙ | ︙ | |||
1821 1822 1823 1824 1825 1826 1827 | i++; } res = sortedKeyCompare( pCsr->pDb->xCmp, iTopic, pKey, nKey, iTopicT, pKeyT, nKeyT ); if( res<0 ){ | | | 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 | i++; } res = sortedKeyCompare( pCsr->pDb->xCmp, iTopic, pKey, nKey, iTopicT, pKeyT, nKeyT ); if( res<0 ){ iPg = (int)iPtr; iMax = iTry-1; }else{ iMin = iTry+1; } } lsmFsPageRelease(pPg); pPg = 0; |
︙ | ︙ | |||
1847 1848 1849 1850 1851 1852 1853 | } static int seekInSegment( MultiCursor *pCsr, SegmentPtr *pPtr, int iTopic, void *pKey, int nKey, | | | | | | 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 | } static int seekInSegment( MultiCursor *pCsr, SegmentPtr *pPtr, int iTopic, void *pKey, int nKey, int iPg, /* Page to search */ int eSeek, /* Search bias - see above */ int *piPtr, /* OUT: FC pointer */ int *pbStop /* OUT: Stop search flag */ ){ int iPtr = iPg; int rc = LSM_OK; if( pPtr->pSeg->iRoot ){ Page *pPg; assert( pPtr->pSeg->iRoot!=0 ); rc = seekInBtree(pCsr, pPtr->pSeg, iTopic, pKey, nKey, 0, &pPg); if( rc==LSM_OK ) segmentPtrSetPage(pPtr, pPg); }else{ if( iPtr==0 ){ iPtr = (int)pPtr->pSeg->iFirst; } if( rc==LSM_OK ){ rc = segmentPtrLoadPage(pCsr->pDb->pFS, pPtr, iPtr); } } if( rc==LSM_OK ){ |
︙ | ︙ | |||
1900 1901 1902 1903 1904 1905 1906 | int iTopic, /* Key topic to search for */ void *pKey, int nKey, /* Key to search for */ LsmPgno *piPgno, /* IN/OUT: fraction cascade pointer (or 0) */ int *pbStop /* OUT: See above */ ){ Level *pLvl = aPtr[0].pLevel; /* Level to seek within */ int rc = LSM_OK; /* Return code */ | | | | | | 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 | int iTopic, /* Key topic to search for */ void *pKey, int nKey, /* Key to search for */ LsmPgno *piPgno, /* IN/OUT: fraction cascade pointer (or 0) */ int *pbStop /* OUT: See above */ ){ Level *pLvl = aPtr[0].pLevel; /* Level to seek within */ int rc = LSM_OK; /* Return code */ int iOut = 0; /* Pointer to return to caller */ int res = -1; /* Result of xCmp(pKey, split) */ int nRhs = pLvl->nRight; /* Number of right-hand-side segments */ int bStop = 0; /* If this is a composite level (one currently undergoing an incremental ** merge), figure out if the search key is larger or smaller than the ** levels split-key. */ if( nRhs ){ res = sortedKeyCompare(pCsr->pDb->xCmp, iTopic, pKey, nKey, pLvl->iSplitTopic, pLvl->pSplitKey, pLvl->nSplitKey ); } /* If (res<0), then key pKey/nKey is smaller than the split-key (or this ** is not a composite level and there is no split-key). Search the ** left-hand-side of the level in this case. */ if( res<0 ){ int i; int iPtr = 0; if( nRhs==0 ) iPtr = (int)*piPgno; rc = seekInSegment( pCsr, &aPtr[0], iTopic, pKey, nKey, iPtr, eSeek, &iOut, &bStop ); if( rc==LSM_OK && nRhs>0 && eSeek==LSM_SEEK_GE && aPtr[0].pPg==0 ){ res = 0; } for(i=1; i<=nRhs; i++){ segmentPtrReset(&aPtr[i], LSM_SEGMENTPTR_FREE_THRESHOLD); } } if( res>=0 ){ int bHit = 0; /* True if at least one rhs is not EOF */ int iPtr = (int)*piPgno; int i; segmentPtrReset(&aPtr[0], LSM_SEGMENTPTR_FREE_THRESHOLD); for(i=1; rc==LSM_OK && i<=nRhs && bStop==0; i++){ SegmentPtr *pPtr = &aPtr[i]; iOut = 0; rc = seekInSegment( pCsr, pPtr, iTopic, pKey, nKey, iPtr, eSeek, &iOut, &bStop |
︙ | ︙ | |||
3357 3358 3359 3360 3361 3362 3363 | ** space). */ static int mergeWorkerPageOffset(u8 *aData, int nData){ int nRec; int iOff; int nKey; int eType; | < < | | 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 | ** space). */ static int mergeWorkerPageOffset(u8 *aData, int nData){ int nRec; int iOff; int nKey; int eType; nRec = lsmGetU16(&aData[SEGMENT_NRECORD_OFFSET(nData)]); iOff = lsmGetU16(&aData[SEGMENT_CELLPTR_OFFSET(nData, nRec-1)]); eType = aData[iOff++]; assert( eType==0 || eType==(LSM_SYSTEMKEY|LSM_SEPARATOR) || eType==(LSM_SEPARATOR) ); iOff += lsmVarintGet32(&aData[iOff], &nKey); iOff += lsmVarintGet32(&aData[iOff], &nKey); return iOff + (eType ? nKey : 0); } /* ** Following a checkpoint operation, database pages that are part of the |
︙ | ︙ | |||
3478 3479 3480 3481 3482 3483 3484 | p = &pMW->hier; if( p->apHier==0 && pSeg->iRoot!=0 ){ FileSystem *pFS = pMW->pDb->pFS; lsm_env *pEnv = pMW->pDb->pEnv; Page **apHier = 0; int nHier = 0; | | | 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 | p = &pMW->hier; if( p->apHier==0 && pSeg->iRoot!=0 ){ FileSystem *pFS = pMW->pDb->pFS; lsm_env *pEnv = pMW->pDb->pEnv; Page **apHier = 0; int nHier = 0; int iPg = (int)pSeg->iRoot; do { Page *pPg = 0; u8 *aData; int nData; int flags; |
︙ | ︙ | |||
3504 3505 3506 3507 3508 3509 3510 | break; } apHier = apNew; memmove(&apHier[1], &apHier[0], sizeof(Page *) * nHier); nHier++; apHier[0] = pPg; | | | 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 | break; } apHier = apNew; memmove(&apHier[1], &apHier[0], sizeof(Page *) * nHier); nHier++; apHier[0] = pPg; iPg = (int)pageGetPtr(aData, nData); }else{ lsmFsPageRelease(pPg); break; } }while( 1 ); if( rc==LSM_OK ){ |
︙ | ︙ | |||
3623 3624 3625 3626 3627 3628 3629 | /* If the key will fit on this page, break out of the loop here. ** The new entry will be written to page apHier[iLevel]. */ pOld = p->apHier[iLevel]; assert( lsmFsPageWritable(pOld) ); aData = fsPageData(pOld, &nData); if( eType==0 ){ | | | < | 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 | /* If the key will fit on this page, break out of the loop here. ** The new entry will be written to page apHier[iLevel]. */ pOld = p->apHier[iLevel]; assert( lsmFsPageWritable(pOld) ); aData = fsPageData(pOld, &nData); if( eType==0 ){ nByte = 2 + 1 + lsmVarintLen32((int)iPtr) + lsmVarintLen32((int)iKeyPg); }else{ nByte = 2 + 1 + lsmVarintLen32((int)iPtr) + lsmVarintLen32(nKey) + nKey; } nRec = pageGetNRec(aData, nData); nFree = SEGMENT_EOF(nData, nRec) - mergeWorkerPageOffset(aData, nData); if( nByte<=nFree ) break; /* Otherwise, this page is full. Set the right-hand-child pointer ** to iPtr and release it. */ lsmPutU64(&aData[SEGMENT_POINTER_OFFSET(nData)], iPtr); |
︙ | ︙ | |||
3671 3672 3673 3674 3675 3676 3677 | aData = fsPageData(p->apHier[iLevel], &nData); iOff = mergeWorkerPageOffset(aData, nData); nRec = pageGetNRec(aData, nData); lsmPutU16(&aData[SEGMENT_CELLPTR_OFFSET(nData, nRec)], (u16)iOff); lsmPutU16(&aData[SEGMENT_NRECORD_OFFSET(nData)], (u16)(nRec+1)); if( eType==0 ){ aData[iOff++] = 0x00; | | | | | 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 | aData = fsPageData(p->apHier[iLevel], &nData); iOff = mergeWorkerPageOffset(aData, nData); nRec = pageGetNRec(aData, nData); lsmPutU16(&aData[SEGMENT_CELLPTR_OFFSET(nData, nRec)], (u16)iOff); lsmPutU16(&aData[SEGMENT_NRECORD_OFFSET(nData)], (u16)(nRec+1)); if( eType==0 ){ aData[iOff++] = 0x00; iOff += lsmVarintPut32(&aData[iOff], (int)iPtr); iOff += lsmVarintPut32(&aData[iOff], (int)iKeyPg); }else{ aData[iOff++] = eType; iOff += lsmVarintPut32(&aData[iOff], (int)iPtr); iOff += lsmVarintPut32(&aData[iOff], nKey); memcpy(&aData[iOff], pKey, nKey); } return rc; } |
︙ | ︙ | |||
3871 3872 3873 3874 3875 3876 3877 | ** array. Otherwise, the main array. ** ** This function is used to write the blobs of data for keys and values. */ static int mergeWorkerData( MergeWorker *pMW, /* Merge worker object */ int bSep, /* True to write to separators run */ | | | 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 | ** array. Otherwise, the main array. ** ** This function is used to write the blobs of data for keys and values. */ static int mergeWorkerData( MergeWorker *pMW, /* Merge worker object */ int bSep, /* True to write to separators run */ int iFPtr, /* Footer ptr for new pages */ u8 *aWrite, /* Write data from this buffer */ int nWrite /* Size of aWrite[] in bytes */ ){ int rc = LSM_OK; /* Return code */ int nRem = nWrite; /* Number of bytes still to write */ while( rc==LSM_OK && nRem>0 ){ |
︙ | ︙ | |||
3915 3916 3917 3918 3919 3920 3921 | ** The MergeWorker passed as the only argument is working to merge two or ** more existing segments together (not to flush an in-memory tree). It ** has not yet written the first key to the first page of the output. */ static int mergeWorkerFirstPage(MergeWorker *pMW){ int rc = LSM_OK; /* Return code */ Page *pPg = 0; /* First page of run pSeg */ | | | | | | | | | | | | | 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 | ** The MergeWorker passed as the only argument is working to merge two or ** more existing segments together (not to flush an in-memory tree). It ** has not yet written the first key to the first page of the output. */ static int mergeWorkerFirstPage(MergeWorker *pMW){ int rc = LSM_OK; /* Return code */ Page *pPg = 0; /* First page of run pSeg */ int iFPtr = 0; /* Pointer value read from footer of pPg */ MultiCursor *pCsr = pMW->pCsr; assert( pMW->pPage==0 ); if( pCsr->pBtCsr ){ rc = LSM_OK; iFPtr = (int)pMW->pLevel->pNext->lhs.iFirst; }else if( pCsr->nPtr>0 ){ Segment *pSeg; pSeg = pCsr->aPtr[pCsr->nPtr-1].pSeg; rc = lsmFsDbPageGet(pMW->pDb->pFS, pSeg, pSeg->iFirst, &pPg); if( rc==LSM_OK ){ u8 *aData; /* Buffer for page pPg */ int nData; /* Size of aData[] in bytes */ aData = fsPageData(pPg, &nData); iFPtr = (int)pageGetPtr(aData, nData); lsmFsPageRelease(pPg); } } if( rc==LSM_OK ){ rc = mergeWorkerNextPage(pMW, iFPtr); if( pCsr->pPrevMergePtr ) *pCsr->pPrevMergePtr = iFPtr; pMW->aSave[0].bStore = 1; } return rc; } static int mergeWorkerWrite( MergeWorker *pMW, /* Merge worker object to write into */ int eType, /* One of SORTED_SEPARATOR, WRITE or DELETE */ void *pKey, int nKey, /* Key value */ void *pVal, int nVal, /* Value value */ int iPtr /* Absolute value of page pointer, or 0 */ ){ int rc = LSM_OK; /* Return code */ Merge *pMerge; /* Persistent part of level merge state */ int nHdr; /* Space required for this record header */ Page *pPg; /* Page to write to */ u8 *aData; /* Data buffer for page pWriter->pPage */ int nData = 0; /* Size of buffer aData[] in bytes */ int nRec = 0; /* Number of records on page pPg */ int iFPtr = 0; /* Value of pointer in footer of pPg */ int iRPtr = 0; /* Value of pointer written into record */ int iOff = 0; /* Current write offset within page pPg */ Segment *pSeg; /* Segment being written */ int flags = 0; /* If != 0, flags value for page footer */ int bFirst = 0; /* True for first key of output run */ pMerge = pMW->pLevel->pMerge; pSeg = &pMW->pLevel->lhs; if( pSeg->iFirst==0 && pMW->pPage==0 ){ rc = mergeWorkerFirstPage(pMW); bFirst = 1; } pPg = pMW->pPage; if( pPg ){ aData = fsPageData(pPg, &nData); nRec = pageGetNRec(aData, nData); iFPtr = (int)pageGetPtr(aData, nData); iRPtr = iPtr - iFPtr; } /* Figure out how much space is required by the new record. The space ** required is divided into two sections: the header and the body. The ** header consists of the intial varint fields. The body are the blobs ** of data that correspond to the key and value data. The entire header ** must be stored on the page. The body may overflow onto the next and ** subsequent pages. ** ** The header space is: ** ** 1) record type - 1 byte. ** 2) Page-pointer-offset - 1 varint ** 3) Key size - 1 varint ** 4) Value size - 1 varint (only if LSM_INSERT flag is set) */ if( rc==LSM_OK ){ nHdr = 1 + lsmVarintLen32(iRPtr) + lsmVarintLen32(nKey); if( rtIsWrite(eType) ) nHdr += lsmVarintLen32(nVal); /* If the entire header will not fit on page pPg, or if page pPg is ** marked read-only, advance to the next page of the output run. */ iOff = pMerge->iOutputOff; if( iOff<0 || pPg==0 || iOff+nHdr > SEGMENT_EOF(nData, nRec+1) ){ if( iOff>=0 && pPg ){ /* Zero any free space on the page */ assert( aData ); memset(&aData[iOff], 0, SEGMENT_EOF(nData, nRec)-iOff); } iFPtr = (int)*pMW->pCsr->pPrevMergePtr; iRPtr = iPtr - iFPtr; iOff = 0; nRec = 0; rc = mergeWorkerNextPage(pMW, iFPtr); pPg = pMW->pPage; } } |
︙ | ︙ | |||
4048 4049 4050 4051 4052 4053 4054 | /* Update the page footer. */ lsmPutU16(&aData[SEGMENT_NRECORD_OFFSET(nData)], (u16)(nRec+1)); lsmPutU16(&aData[SEGMENT_CELLPTR_OFFSET(nData, nRec)], (u16)iOff); if( flags ) lsmPutU16(&aData[SEGMENT_FLAGS_OFFSET(nData)], (u16)flags); /* Write the entry header into the current page. */ aData[iOff++] = (u8)eType; /* 1 */ | | | 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 | /* Update the page footer. */ lsmPutU16(&aData[SEGMENT_NRECORD_OFFSET(nData)], (u16)(nRec+1)); lsmPutU16(&aData[SEGMENT_CELLPTR_OFFSET(nData, nRec)], (u16)iOff); if( flags ) lsmPutU16(&aData[SEGMENT_FLAGS_OFFSET(nData)], (u16)flags); /* Write the entry header into the current page. */ aData[iOff++] = (u8)eType; /* 1 */ iOff += lsmVarintPut32(&aData[iOff], iRPtr); /* 2 */ iOff += lsmVarintPut32(&aData[iOff], nKey); /* 3 */ if( rtIsWrite(eType) ) iOff += lsmVarintPut32(&aData[iOff], nVal); /* 4 */ pMerge->iOutputOff = iOff; /* Write the key and data into the segment. */ assert( iFPtr==pageGetPtr(aData, nData) ); rc = mergeWorkerData(pMW, 0, iFPtr+iRPtr, pKey, nKey); |
︙ | ︙ | |||
4282 4283 4284 4285 4286 4287 4288 | rc = multiCursorGetVal(pCsr, iVal, &pVal, &nVal); if( pVal && rc==LSM_OK ){ assert( nVal>=0 ); rc = sortedBlobSet(pDb->pEnv, &pCsr->val, pVal, nVal); pVal = pCsr->val.pData; } if( rc==LSM_OK ){ | | | 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 | rc = multiCursorGetVal(pCsr, iVal, &pVal, &nVal); if( pVal && rc==LSM_OK ){ assert( nVal>=0 ); rc = sortedBlobSet(pDb->pEnv, &pCsr->val, pVal, nVal); pVal = pCsr->val.pData; } if( rc==LSM_OK ){ rc = mergeWorkerWrite(pMW, eType, pKey, nKey, pVal, nVal, (int)iPtr); } } } /* Advance the cursor to the next input record (assuming one exists). */ assert( lsmMCursorValid(pMW->pCsr) ); if( rc==LSM_OK ) rc = lsmMCursorNext(pMW->pCsr); |
︙ | ︙ | |||
4603 4604 4605 4606 4607 4608 4609 | int i; for(i=0; rc==LSM_OK && i<pCsr->nPtr; i++){ MergeInput *pInput = &pMerge->aInput[i]; if( pInput->iPg ){ SegmentPtr *pPtr; assert( pCsr->aPtr[i].pPg==0 ); pPtr = &pCsr->aPtr[i]; | | | 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 | int i; for(i=0; rc==LSM_OK && i<pCsr->nPtr; i++){ MergeInput *pInput = &pMerge->aInput[i]; if( pInput->iPg ){ SegmentPtr *pPtr; assert( pCsr->aPtr[i].pPg==0 ); pPtr = &pCsr->aPtr[i]; rc = segmentPtrLoadPage(pDb->pFS, pPtr, (int)pInput->iPg); if( rc==LSM_OK && pPtr->nCell>0 ){ rc = segmentPtrLoadCell(pPtr, pInput->iCell); } } } if( rc==LSM_OK && pCsr->pBtCsr ){ |
︙ | ︙ | |||
5468 5469 5470 5471 5472 5473 5474 | /* ** Return a string representation of the segment passed as the only argument. ** Space for the returned string is allocated using lsmMalloc(), and should ** be freed by the caller using lsmFree(). */ static char *segToString(lsm_env *pEnv, Segment *pSeg, int nMin){ | | | | | 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 | /* ** Return a string representation of the segment passed as the only argument. ** Space for the returned string is allocated using lsmMalloc(), and should ** be freed by the caller using lsmFree(). */ static char *segToString(lsm_env *pEnv, Segment *pSeg, int nMin){ int nSize = pSeg->nSize; LsmPgno iRoot = pSeg->iRoot; LsmPgno iFirst = pSeg->iFirst; LsmPgno iLast = pSeg->iLastPg; char *z; char *z1; char *z2; int nPad; z1 = lsmMallocPrintf(pEnv, "%d.%d", iFirst, iLast); if( iRoot ){ z2 = lsmMallocPrintf(pEnv, "root=%d", iRoot); }else{ z2 = lsmMallocPrintf(pEnv, "size=%d", nSize); } nPad = nMin - 2 - strlen(z1) - 1 - strlen(z2); nPad = LSM_MAX(0, nPad); if( iRoot ){ z = lsmMallocPrintf(pEnv, "/%s %*s%s\\", z1, nPad, "", z2); |
︙ | ︙ | |||
5535 5536 5537 5538 5539 5540 5541 | void sortedDumpPage(lsm_db *pDb, Segment *pRun, Page *pPg, int bVals){ LsmBlob blob = {0, 0, 0}; /* LsmBlob used for keys */ LsmString s; int i; int nRec; | | | | | | | 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 | void sortedDumpPage(lsm_db *pDb, Segment *pRun, Page *pPg, int bVals){ LsmBlob blob = {0, 0, 0}; /* LsmBlob used for keys */ LsmString s; int i; int nRec; int iPtr; int flags; u8 *aData; int nData; aData = fsPageData(pPg, &nData); nRec = pageGetNRec(aData, nData); iPtr = (int)pageGetPtr(aData, nData); flags = pageGetFlags(aData, nData); lsmStringInit(&s, pDb->pEnv); lsmStringAppendf(&s,"nCell=%d iPtr=%d flags=%d {", nRec, iPtr, flags); if( flags&SEGMENT_BTREE_FLAG ) iPtr = 0; for(i=0; i<nRec; i++){ Page *pRef = 0; /* Pointer to page iRef */ int iChar; u8 *aKey; int nKey = 0; /* Key */ u8 *aVal = 0; int nVal = 0; /* Value */ int iTopic; u8 *aCell; int iPgPtr; int eType; aCell = pageGetCell(aData, nData, i); eType = *aCell++; assert( (flags & SEGMENT_BTREE_FLAG) || eType!=0 ); aCell += lsmVarintGet32(aCell, &iPgPtr); if( eType==0 ){ LsmPgno iRef; /* Page number of referenced page */ aCell += lsmVarintGet64(aCell, &iRef); lsmFsDbPageGet(pDb->pFS, pRun, iRef, &pRef); aKey = pageGetKey(pRun, pRef, 0, &iTopic, &nKey, &blob); }else{ |
︙ | ︙ | |||
5589 5590 5591 5592 5593 5594 5595 | if( nVal>0 && bVals ){ lsmStringAppendf(&s, "##"); for(iChar=0; iChar<nVal; iChar++){ lsmStringAppendf(&s, "%c", isalnum(aVal[iChar]) ? aVal[iChar] : '.'); } } | | | 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 | if( nVal>0 && bVals ){ lsmStringAppendf(&s, "##"); for(iChar=0; iChar<nVal; iChar++){ lsmStringAppendf(&s, "%c", isalnum(aVal[iChar]) ? aVal[iChar] : '.'); } } lsmStringAppendf(&s, " %d", iPgPtr+iPtr); lsmFsPageRelease(pRef); } lsmStringAppend(&s, "}", 1); lsmLogMessage(pDb, LSM_OK, " Page %d: %s", lsmFsPageNumber(pPg), s.z); lsmStringClear(&s); |
︙ | ︙ | |||
5719 5720 5721 5722 5723 5724 5725 | } if( rc==LSM_OK ){ LsmBlob blob = {0, 0, 0, 0}; int nKeyWidth = 0; LsmString str; int nRec; | | | | | 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 | } if( rc==LSM_OK ){ LsmBlob blob = {0, 0, 0, 0}; int nKeyWidth = 0; LsmString str; int nRec; int iPtr; int flags2; int iCell; u8 *aData; int nData; /* Page data and size thereof */ aData = fsPageData(pPg, &nData); nRec = pageGetNRec(aData, nData); iPtr = (int)pageGetPtr(aData, nData); flags2 = pageGetFlags(aData, nData); lsmStringInit(&str, pDb->pEnv); lsmStringAppendf(&str, "Page : %lld (%d bytes)\n", iPg, nData); lsmStringAppendf(&str, "nRec : %d\n", nRec); lsmStringAppendf(&str, "iPtr : %d\n", iPtr); lsmStringAppendf(&str, "flags: %04x\n", flags2); lsmStringAppendf(&str, "\n"); for(iCell=0; iCell<nRec; iCell++){ int nKey; infoCellDump( pDb, pSeg, bIndirect, pPg, iCell, 0, 0, 0, &nKey, 0, 0, &blob |
︙ | ︙ |
Changes to ext/lsm1/lsm_unix.c.
︙ | ︙ | |||
224 225 226 227 228 229 230 | 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); | < < < < | 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; } |
︙ | ︙ | |||
413 414 415 416 417 418 419 | 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 ); | | < < < | 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 | 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]==0 ) return LSM_IOERR_BKPT; } *ppShm = p->apShm[iChunk]; return LSM_OK; } static void lsmPosixOsShmBarrier(void){ |
︙ | ︙ |
Changes to ext/lsm1/lsm_varint.c.
︙ | ︙ | |||
181 182 183 184 185 186 187 | } int lsmVarintLen32(int n){ u8 aData[9]; return lsmVarintPut32(aData, n); } | < < < < < | 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | } int lsmVarintLen32(int n){ u8 aData[9]; return lsmVarintPut32(aData, n); } /* ** The argument is the first byte of a varint. This function returns the ** total number of bytes in the entire varint (including the first byte). */ int lsmVarintSize(u8 c){ if( c<241 ) return 1; if( c<249 ) return 2; |
︙ | ︙ |
Changes to ext/lsm1/lsm_vtab.c.
︙ | ︙ | |||
22 23 24 25 26 27 28 | ** ** The keytype must be one of: UINT, TEXT, BLOB. All keys must be of that ** one type. "UINT" means unsigned integer. The values may be of any ** SQLite datatype: BLOB, TEXT, INTEGER, FLOAT, or NULL. ** ** The virtual table contains read-only hidden columns: ** | | | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | ** ** The keytype must be one of: UINT, TEXT, BLOB. All keys must be of that ** one type. "UINT" means unsigned integer. The values may be of any ** SQLite datatype: BLOB, TEXT, INTEGER, FLOAT, or NULL. ** ** The virtual table contains read-only hidden columns: ** ** lsm1_key A BLOB which is the raw LSM key. If the "keytype" ** is BLOB or TEXT then this column is exactly the ** same as the key. For the UINT keytype, this column ** will be a variable-length integer encoding of the key. ** ** lsm1_value A BLOB which is the raw LSM value. All of the value ** columns are packed into this BLOB using the encoding ** described below. |
︙ | ︙ | |||
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 && idxNum<16; 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 | 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' |} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
Changes to ext/misc/amatch.c.
︙ | ︙ | |||
896 897 898 899 900 901 902 | 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 ){ | < | 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 |
︙ | ︙ |
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 | ** ****************************************************************************** ** ** This file implements a VFS shim that allows an SQLite database to be ** appended onto the end of some other file, such as an executable. ** ** A special record must appear at the end of the file that identifies the ** file as an appended database and provides an offset to page 1. For ** best performance page 1 should be located at a disk page boundary, though ** that is not required. ** ** When opening a database using this VFS, the connection might treat ** the file as an ordinary SQLite database, or it might treat is as a ** database appended onto some other file. Here are the rules: ** ** (1) When opening a new empty file, that file is treated as an ordinary ** database. ** ** (2) When opening a file that begins with the standard SQLite prefix ** string "SQLite format 3", that file is treated as an ordinary ** database. ** ** (3) When opening a file that ends with the appendvfs trailer string ** "Start-Of-SQLite3-NNNNNNNN" that file is treated as an appended ** database. ** ** (4) If none of the above apply and the SQLITE_OPEN_CREATE flag is ** set, then a new database is appended to the already existing file. ** ** (5) Otherwise, SQLITE_CANTOPEN is returned. ** ** To avoid unnecessary complications with the PENDING_BYTE, the size of ** the file containing the database is limited to 1GB. This VFS will refuse ** to read or write past the 1GB mark. This restriction might be lifted in ** future versions. For now, if you need a large database, then keep the ** database in a separate file. ** ** If the file being opened is not an appended database, then this shim is ** a pass-through into the default underlying VFS. **/ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <string.h> #include <assert.h> /* The append mark at the end of the database is: ** ** Start-Of-SQLite3-NNNNNNNN ** 123456789 123456789 12345 ** ** The NNNNNNNN represents a 64-bit big-endian unsigned integer which is ** the offset to page 1. */ #define APND_MARK_PREFIX "Start-Of-SQLite3-" #define APND_MARK_PREFIX_SZ 17 #define APND_MARK_SIZE 25 /* ** Maximum size of the combined prefix + database + append-mark. This ** must be less than 0x40000000 to avoid locking issues on Windows. */ #define APND_MAX_SIZE (65536*15259) /* ** Forward declaration of objects used by this utility */ typedef struct sqlite3_vfs ApndVfs; typedef struct ApndFile ApndFile; /* Access to a lower-level VFS that (might) implement dynamic loading, ** access to randomness, etc. */ #define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData)) #define ORIGFILE(p) ((sqlite3_file*)(((ApndFile*)(p))+1)) /* An open file */ struct ApndFile { sqlite3_file base; /* IO methods */ sqlite3_int64 iPgOne; /* File offset to page 1 */ sqlite3_int64 iMark; /* Start of the append-mark */ }; /* ** Methods for ApndFile */ static int apndClose(sqlite3_file*); static int apndRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); |
︙ | ︙ | |||
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 | apndShmMap, /* xShmMap */ apndShmLock, /* xShmLock */ apndShmBarrier, /* xShmBarrier */ apndShmUnmap, /* xShmUnmap */ apndFetch, /* xFetch */ apndUnfetch /* xUnfetch */ }; /* ** Close an apnd-file. */ static int apndClose(sqlite3_file *pFile){ pFile = ORIGFILE(pFile); return pFile->pMethods->xClose(pFile); } /* ** Read data from an apnd-file. */ static int apndRead( sqlite3_file *pFile, void *zBuf, int iAmt, sqlite_int64 iOfst ){ | > > | | | < < | < < | < < < < < < > | < < < | < < < > | < < > | > > > > > > | | < | > > | > | < > | | > > | < | > > > | > > | | 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 | apndShmMap, /* xShmMap */ apndShmLock, /* xShmLock */ apndShmBarrier, /* xShmBarrier */ apndShmUnmap, /* xShmUnmap */ apndFetch, /* xFetch */ apndUnfetch /* xUnfetch */ }; /* ** Close an apnd-file. */ static int apndClose(sqlite3_file *pFile){ pFile = ORIGFILE(pFile); return pFile->pMethods->xClose(pFile); } /* ** Read data from an apnd-file. */ static int apndRead( sqlite3_file *pFile, void *zBuf, int iAmt, sqlite_int64 iOfst ){ ApndFile *p = (ApndFile *)pFile; pFile = ORIGFILE(pFile); return pFile->pMethods->xRead(pFile, zBuf, iAmt, iOfst+p->iPgOne); } /* ** Add the append-mark onto the end of the file. */ static int apndWriteMark(ApndFile *p, sqlite3_file *pFile){ int i; unsigned char a[APND_MARK_SIZE]; memcpy(a, APND_MARK_PREFIX, APND_MARK_PREFIX_SZ); for(i=0; i<8; i++){ a[APND_MARK_PREFIX_SZ+i] = (p->iPgOne >> (56 - i*8)) & 0xff; } return pFile->pMethods->xWrite(pFile, a, APND_MARK_SIZE, p->iMark); } /* ** Write data to an apnd-file. */ static int apndWrite( sqlite3_file *pFile, const void *zBuf, int iAmt, sqlite_int64 iOfst ){ int rc; ApndFile *p = (ApndFile *)pFile; pFile = ORIGFILE(pFile); if( iOfst+iAmt>=APND_MAX_SIZE ) return SQLITE_FULL; rc = pFile->pMethods->xWrite(pFile, zBuf, iAmt, iOfst+p->iPgOne); if( rc==SQLITE_OK && iOfst + iAmt + p->iPgOne > p->iMark ){ sqlite3_int64 sz = 0; rc = pFile->pMethods->xFileSize(pFile, &sz); if( rc==SQLITE_OK ){ p->iMark = sz - APND_MARK_SIZE; if( iOfst + iAmt + p->iPgOne > p->iMark ){ p->iMark = p->iPgOne + iOfst + iAmt; rc = apndWriteMark(p, pFile); } } } return rc; } /* ** Truncate an apnd-file. */ static int apndTruncate(sqlite3_file *pFile, sqlite_int64 size){ int rc; ApndFile *p = (ApndFile *)pFile; pFile = ORIGFILE(pFile); rc = pFile->pMethods->xTruncate(pFile, size+p->iPgOne+APND_MARK_SIZE); if( rc==SQLITE_OK ){ p->iMark = p->iPgOne+size; rc = apndWriteMark(p, pFile); } return rc; } /* ** Sync an apnd-file. */ static int apndSync(sqlite3_file *pFile, int flags){ pFile = ORIGFILE(pFile); return pFile->pMethods->xSync(pFile, flags); } /* ** Return the current file-size of an apnd-file. */ static int apndFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ ApndFile *p = (ApndFile *)pFile; int rc; pFile = ORIGFILE(p); rc = pFile->pMethods->xFileSize(pFile, pSize); if( rc==SQLITE_OK && p->iPgOne ){ *pSize -= p->iPgOne + APND_MARK_SIZE; } return rc; } /* ** Lock an apnd-file. */ static int apndLock(sqlite3_file *pFile, int eLock){ pFile = ORIGFILE(pFile); |
︙ | ︙ | |||
346 347 348 349 350 351 352 | 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){ | | < | | 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 | return pFile->pMethods->xCheckReservedLock(pFile, pResOut); } /* ** File control method. For custom operations on an apnd-file. */ static int apndFileControl(sqlite3_file *pFile, int op, void *pArg){ ApndFile *p = (ApndFile *)pFile; int rc; pFile = ORIGFILE(pFile); rc = pFile->pMethods->xFileControl(pFile, op, pArg); if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){ *(char**)pArg = sqlite3_mprintf("apnd(%lld)/%z", p->iPgOne, *(char**)pArg); } return rc; } /* ** Return the sector-size in bytes for an apnd-file. */ |
︙ | ︙ | |||
411 412 413 414 415 416 417 | static int apndFetch( sqlite3_file *pFile, sqlite3_int64 iOfst, int iAmt, void **pp ){ ApndFile *p = (ApndFile *)pFile; | < < < > > > > > > > > > > > > > | | < < < < < | | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | > < < < < | > | > | < < | < < | | < < | < > | < < < | > | | < | < < < < < < < < > > > < < < < < < < < < < > > > | 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 | static int apndFetch( sqlite3_file *pFile, sqlite3_int64 iOfst, int iAmt, void **pp ){ ApndFile *p = (ApndFile *)pFile; pFile = ORIGFILE(pFile); return pFile->pMethods->xFetch(pFile, iOfst+p->iPgOne, iAmt, pp); } /* Release a memory-mapped page */ static int apndUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){ ApndFile *p = (ApndFile *)pFile; pFile = ORIGFILE(pFile); return pFile->pMethods->xUnfetch(pFile, iOfst+p->iPgOne, pPage); } /* ** Check to see if the file is an ordinary SQLite database file. */ static int apndIsOrdinaryDatabaseFile(sqlite3_int64 sz, sqlite3_file *pFile){ int rc; char zHdr[16]; static const char aSqliteHdr[] = "SQLite format 3"; if( sz<512 ) return 0; rc = pFile->pMethods->xRead(pFile, zHdr, sizeof(zHdr), 0); if( rc ) return 0; return memcmp(zHdr, aSqliteHdr, sizeof(zHdr))==0; } /* ** Try to read the append-mark off the end of a file. Return the ** start of the appended database if the append-mark is present. If ** there is no append-mark, return -1; */ static sqlite3_int64 apndReadMark(sqlite3_int64 sz, sqlite3_file *pFile){ int rc, i; sqlite3_int64 iMark; unsigned char a[APND_MARK_SIZE]; if( sz<=APND_MARK_SIZE ) return -1; rc = pFile->pMethods->xRead(pFile, a, APND_MARK_SIZE, sz-APND_MARK_SIZE); if( rc ) return -1; if( memcmp(a, APND_MARK_PREFIX, APND_MARK_PREFIX_SZ)!=0 ) return -1; iMark = ((sqlite3_int64)(a[APND_MARK_PREFIX_SZ]&0x7f))<<56; for(i=1; i<8; i++){ iMark += (sqlite3_int64)a[APND_MARK_PREFIX_SZ+i]<<(56-8*i); } return iMark; } /* ** Open an apnd file handle. */ static int apndOpen( sqlite3_vfs *pVfs, const char *zName, sqlite3_file *pFile, int flags, int *pOutFlags ){ ApndFile *p; sqlite3_file *pSubFile; sqlite3_vfs *pSubVfs; int rc; sqlite3_int64 sz; pSubVfs = ORIGVFS(pVfs); if( (flags & SQLITE_OPEN_MAIN_DB)==0 ){ return pSubVfs->xOpen(pSubVfs, zName, pFile, flags, pOutFlags); } p = (ApndFile*)pFile; memset(p, 0, sizeof(*p)); pSubFile = ORIGFILE(pFile); p->base.pMethods = &apnd_io_methods; rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags); if( rc ) goto apnd_open_done; rc = pSubFile->pMethods->xFileSize(pSubFile, &sz); if( rc ){ pSubFile->pMethods->xClose(pSubFile); goto apnd_open_done; } if( apndIsOrdinaryDatabaseFile(sz, pSubFile) ){ memmove(pFile, pSubFile, pSubVfs->szOsFile); return SQLITE_OK; } p->iMark = 0; p->iPgOne = apndReadMark(sz, pFile); if( p->iPgOne>0 ){ return SQLITE_OK; } if( (flags & SQLITE_OPEN_CREATE)==0 ){ pSubFile->pMethods->xClose(pSubFile); rc = SQLITE_CANTOPEN; } p->iPgOne = (sz+0xfff) & ~(sqlite3_int64)0xfff; apnd_open_done: if( rc ) pFile->pMethods = 0; return rc; } /* ** All other VFS methods are pass-thrus. */ static int apndDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ return ORIGVFS(pVfs)->xDelete(ORIGVFS(pVfs), zPath, dirSync); } static int apndAccess( sqlite3_vfs *pVfs, const char *zPath, int flags, int *pResOut ){ return ORIGVFS(pVfs)->xAccess(ORIGVFS(pVfs), zPath, flags, pResOut); |
︙ | ︙ | |||
653 654 655 656 657 658 659 | ){ int rc = SQLITE_OK; sqlite3_vfs *pOrig; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; (void)db; pOrig = sqlite3_vfs_find(0); | < | 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; } |
Deleted ext/misc/base64.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/misc/base85.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/misc/basexx.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to ext/misc/blobio.c.
︙ | ︙ | |||
72 73 74 75 76 77 78 | 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); | | | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | 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 write failed", -1); }else{ sqlite3_result_blob(context, aData, nData, sqlite3_free); } } static void writeblobFunc( sqlite3_context *context, |
︙ | ︙ |
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_master ** hasRowid BOOLEAN, -- True if the btree has a rowid ** nEntry INT, -- Estimated number of enteries ** 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_master table. ** Considering only the first 5 fields, the only difference between ** this virtual table and the sqlite_master 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_master */ 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_master','sqlite_master',1,NULL " "UNION ALL " "SELECT rowid, type, name, tbl_name, rootpage, sql" " FROM \"%w\".sqlite_master 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 35 36 37 38 | ** 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_value(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*'); ** ** The default value of the third parameter is 'int32'. ** ** HOW IT WORKS ** |
︙ | ︙ | |||
52 53 54 55 56 57 58 | ** 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> | < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | > > < > < < | < < < < | 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 | ** 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 /* ** Allowed datatypes */ #define CARRAY_INT32 0 #define CARRAY_INT64 1 #define CARRAY_DOUBLE 2 #define CARRAY_TEXT 3 /* ** Names of types */ static const char *azType[] = { "int32", "int64", "double", "char*" }; /* 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; |
︙ | ︙ | |||
230 231 232 233 234 235 236 | return SQLITE_OK; } case CARRAY_TEXT: { const char **p = (const char**)pCur->pPtr; sqlite3_result_text(ctx, p[pCur->iRowid-1], -1, SQLITE_TRANSIENT); return SQLITE_OK; } | < < < < < < | 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | return SQLITE_OK; } case CARRAY_TEXT: { const char **p = (const char**)pCur->pPtr; sqlite3_result_text(ctx, p[pCur->iRowid-1], -1, SQLITE_TRANSIENT); return SQLITE_OK; } } } } sqlite3_result_int64(ctx, x); return SQLITE_OK; } |
︙ | ︙ | |||
272 273 274 275 276 277 278 | */ static int carrayFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ carray_cursor *pCur = (carray_cursor *)pVtabCursor; | < < | < < < < < < < < < < | | | | | | | | | | | | | | | | | | < | > > < < < < < | < | < | | 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 | */ static int carrayFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ carray_cursor *pCur = (carray_cursor *)pVtabCursor; if( idxNum ){ 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; } } }else{ pCur->pPtr = 0; pCur->iCnt = 0; } 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 2 if the pointer= and count= constraints exist, ** 3 if the ctype= constraint also exists, and is 0 otherwise. ** If idxNum is 0, then 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 */ |
︙ | ︙ | |||
356 357 358 359 360 361 362 | cntIdx = i; break; case CARRAY_COLUMN_CTYPE: ctypeIdx = i; break; } } | | < < < < | | > > | | | | | < | 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 | cntIdx = i; break; case CARRAY_COLUMN_CTYPE: ctypeIdx = i; break; } } if( ptrIdx>=0 && cntIdx>=0 ){ pIdxInfo->aConstraintUsage[ptrIdx].argvIndex = 1; pIdxInfo->aConstraintUsage[ptrIdx].omit = 1; pIdxInfo->aConstraintUsage[cntIdx].argvIndex = 2; pIdxInfo->aConstraintUsage[cntIdx].omit = 1; pIdxInfo->estimatedCost = (double)1; pIdxInfo->estimatedRows = 100; 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; |
︙ | ︙ | |||
406 407 408 409 410 411 412 | 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ }; | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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. |
︙ | ︙ | |||
532 533 534 535 536 537 538 | } sqlite3_result_pointer(context, p, "carray", 0); } #endif /* SQLITE_TEST */ #endif /* SQLITE_OMIT_VIRTUALTABLE */ | > > > | | 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 | } sqlite3_result_pointer(context, p, "carray", 0); } #endif /* SQLITE_TEST */ #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifdef _WIN32 __declspec(dllexport) #endif 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 |
︙ | ︙ |
Deleted ext/misc/carray.h.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/misc/cksumvfs.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to ext/misc/completion.c.
︙ | ︙ | |||
114 115 116 117 118 119 120 | /* 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 */ | < | 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 */ ")"); |
︙ | ︙ | |||
222 223 224 225 226 227 228 | 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" | | | 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | 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_master", zSql, zSep, zDb ); if( zSql==0 ) return SQLITE_NOMEM; zSep = " UNION "; } sqlite3_finalize(pS2); sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0); |
︙ | ︙ | |||
246 247 248 249 250 251 252 | 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" | | | 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | 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_master 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 | 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, 0, compressFunc, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "uncompress", 1, SQLITE_UTF8, 0, uncompressFunc, 0, 0); } return rc; } |
Changes to ext/misc/csv.c.
︙ | ︙ | |||
276 277 278 279 280 281 282 | } if( c=='\n' ){ p->nLine++; if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--; } p->cTerm = (char)c; } | < | 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | } if( c=='\n' ){ p->nLine++; if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--; } p->cTerm = (char)c; } if( p->z ) p->z[p->n] = 0; p->bNotFirst = 1; return p->z; } /* Forward references to the various virtual table methods implemented |
︙ | ︙ | |||
629 630 631 632 633 634 635 | 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]); } | < < < < < < < < < | 628 629 630 631 632 633 634 635 636 637 638 639 640 641 | 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]); } return SQLITE_OK; csvtab_connect_oom: rc = SQLITE_NOMEM; csv_errmsg(&sRdr, "out of memory"); csvtab_connect_error: |
︙ | ︙ | |||
747 748 749 750 751 752 753 | pCur->azVal[i] = zNew; pCur->aLen[i] = pCur->rdr.n+1; } memcpy(pCur->azVal[i], z, pCur->rdr.n+1); i++; } }while( pCur->rdr.cTerm==',' ); | | | 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 | pCur->azVal[i] = zNew; pCur->aLen[i] = pCur->rdr.n+1; } memcpy(pCur->azVal[i], z, pCur->rdr.n+1); i++; } }while( pCur->rdr.cTerm==',' ); if( z==0 || (pCur->rdr.cTerm==EOF && i<pTab->nCol) ){ pCur->iRowid = -1; }else{ pCur->iRowid++; while( i<pTab->nCol ){ sqlite3_free(pCur->azVal[i]); pCur->azVal[i] = 0; pCur->aLen[i] = 0; |
︙ | ︙ | |||
773 774 775 776 777 778 779 | 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 ){ | | | 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 | 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_STATIC); } return SQLITE_OK; } /* ** Return the rowid for the current row. */ |
︙ | ︙ | |||
808 809 810 811 812 813 814 | sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ CsvCursor *pCur = (CsvCursor*)pVtabCursor; CsvTable *pTab = (CsvTable*)pVtabCursor->pVtab; pCur->iRowid = 0; | < < < < < < | 798 799 800 801 802 803 804 805 806 807 808 809 810 811 | sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ CsvCursor *pCur = (CsvCursor*)pVtabCursor; CsvTable *pTab = (CsvTable*)pVtabCursor->pVtab; pCur->iRowid = 0; if( pCur->rdr.in==0 ){ assert( pCur->rdr.zIn==pTab->zData ); assert( pTab->iStart>=0 ); assert( (size_t)pTab->iStart<=pCur->rdr.nIn ); pCur->rdr.iIn = pTab->iStart; }else{ fseek(pCur->rdr.in, pTab->iStart, SEEK_SET); |
︙ | ︙ | |||
944 945 946 947 948 949 950 | ** connection. */ int sqlite3_csv_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ | | | 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 | ** connection. */ int sqlite3_csv_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ #ifndef SQLITE_OMIT_VIRTUALTABLE int rc; SQLITE_EXTENSION_INIT2(pApi); rc = sqlite3_create_module(db, "csv", &CsvModule, 0); #ifdef SQLITE_TEST if( rc==SQLITE_OK ){ rc = sqlite3_create_module(db, "csv_wr", &CsvModuleFauxWrite, 0); } #endif return rc; #else return SQLITE_OK; #endif } |
Changes to ext/misc/dbdump.c.
︙ | ︙ | |||
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_master;\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_master(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_master " "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'", zSchema ); run_schema_dump_query(&x, "SELECT name, type, sql FROM \"%w\".sqlite_master " "WHERE name=='sqlite_sequence'", zSchema ); output_sql_from_query(&x, "SELECT sql FROM sqlite_master " "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0 ); }else{ run_schema_dump_query(&x, "SELECT name, type, sql FROM \"%w\".sqlite_master " "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_master " "WHERE sql NOT NULL" " AND type IN ('index','trigger','view')" " AND tbl_name=%Q COLLATE nocase", zSchema, zTable ); } if( x.writableSchema ){ |
︙ | ︙ |
Deleted ext/misc/decimal.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to ext/misc/eval.c.
︙ | ︙ | |||
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 | 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, 0, sqlEvalFunc, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "eval", 2, SQLITE_UTF8, 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_master') ** 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 | ** 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. | < < < < < | 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> |
︙ | ︙ | |||
226 227 228 229 230 231 232 | fileIntervals.LowPart = pFileTime->dwLowDateTime; fileIntervals.HighPart = pFileTime->dwHighDateTime; return (fileIntervals.QuadPart - epochIntervals.QuadPart) / 10000000; } | < < < < < < < < < < < < < < < < | 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | 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, |
︙ | ︙ | |||
364 365 366 367 368 369 370 | static int writeFile( sqlite3_context *pCtx, /* Context to return bytes written in */ const char *zFile, /* File to write */ sqlite3_value *pData, /* Data to write */ mode_t mode, /* MODE parameter passed to writefile() */ sqlite3_int64 mtime /* MTIME parameter (or -1 to not set time) */ ){ | < | | 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 | static int writeFile( sqlite3_context *pCtx, /* Context to return bytes written in */ const char *zFile, /* File to write */ sqlite3_value *pData, /* Data to write */ mode_t mode, /* MODE parameter passed to writefile() */ sqlite3_int64 mtime /* MTIME parameter (or -1 to not set time) */ ){ #if !defined(_WIN32) && !defined(WIN32) if( S_ISLNK(mode) ){ const char *zTo = (const char*)sqlite3_value_text(pData); if( symlink(zTo, zFile)<0 ) return 1; }else #endif { if( S_ISDIR(mode) ){ if( mkdir(zFile, mode) ){ /* The mkdir() call to create the directory failed. This might not ** be an error though - if there is already a directory at the same |
︙ | ︙ | |||
412 413 414 415 416 417 418 | if( rc ) return 2; sqlite3_result_int64(pCtx, nWrite); } } if( mtime>=0 ){ #if defined(_WIN32) | < | 390 391 392 393 394 395 396 397 398 399 400 401 402 403 | 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; |
︙ | ︙ | |||
443 444 445 446 447 448 449 | if( hFile!=INVALID_HANDLE_VALUE ){ BOOL bResult = SetFileTime(hFile, NULL, &lastAccess, &lastWrite); CloseHandle(hFile); return !bResult; }else{ return 1; } | < | 420 421 422 423 424 425 426 427 428 429 430 431 432 433 | 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) ){ |
︙ | ︙ | |||
605 606 607 608 609 610 611 | (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)); | < | 581 582 583 584 585 586 587 588 589 590 591 592 593 594 | (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. |
︙ | ︙ | |||
999 1000 1001 1002 1003 1004 1005 | sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ | | < | < < < < < < < < < | 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 | sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ rc = sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0, readfileFunc, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "writefile", -1, SQLITE_UTF8, 0, writefileFunc, 0, 0); } if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "lsmode", 1, SQLITE_UTF8, 0, lsModeFunc, 0, 0); } if( rc==SQLITE_OK ){ rc = fsdirRegister(db); } return rc; } |
Changes to ext/misc/fossildelta.c.
︙ | ︙ | |||
32 33 34 35 36 37 38 | */ #include <string.h> #include <assert.h> #include <stdlib.h> #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 | < < < | 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 | */ #include <string.h> #include <assert.h> #include <stdlib.h> #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 /* ** 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; /* ** The width of a hash window in bytes. The algorithm only works if this ** is a power of 2. */ #define NHASH 16 |
︙ | ︙ | |||
818 819 820 821 822 823 824 | #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)); | < | 815 816 817 818 819 820 821 822 823 824 825 826 827 828 | #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)); } return rc; } /* ** This method is the destructor for deltaparsevtab_vtab objects. */ |
︙ | ︙ | |||
849 850 851 852 853 854 855 | } /* ** Destructor for a deltaparsevtab_cursor. */ static int deltaparsevtabClose(sqlite3_vtab_cursor *cur){ deltaparsevtab_cursor *pCur = (deltaparsevtab_cursor*)cur; | < | 845 846 847 848 849 850 851 852 853 854 855 856 857 858 | } /* ** Destructor for a deltaparsevtab_cursor. */ static int deltaparsevtabClose(sqlite3_vtab_cursor *cur){ deltaparsevtab_cursor *pCur = (deltaparsevtab_cursor*)cur; sqlite3_free(pCur); return SQLITE_OK; } /* ** Advance a deltaparsevtab_cursor to its next row of output. |
︙ | ︙ | |||
1067 1068 1069 1070 1071 1072 1073 | __declspec(dllexport) #endif int sqlite3_fossildelta_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ | < | | | | 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 | __declspec(dllexport) #endif int sqlite3_fossildelta_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, "delta_create", 2, SQLITE_UTF8, 0, deltaCreateFunc, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "delta_apply", 2, SQLITE_UTF8, 0, deltaApplyFunc, 0, 0); } if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "delta_output_size", 1, SQLITE_UTF8, 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.
︙ | ︙ | |||
536 537 538 539 540 541 542 | 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; | < < | 536 537 538 539 540 541 542 543 544 545 546 547 548 549 | 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; } } } *ppVtab = (sqlite3_vtab *)pNew; return rc; } |
︙ | ︙ |
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 | ** ** 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 */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <assert.h> #include <string.h> /* ** Implementation of the ieee754() function */ static void ieee754func( sqlite3_context *context, int argc, sqlite3_value **argv ){ if( argc==1 ){ sqlite3_int64 m, a; double r; int e; int isNeg; char zResult[100]; assert( sizeof(m)==sizeof(r) ); if( sqlite3_value_type(argv[0])!=SQLITE_FLOAT ) return; r = sqlite3_value_double(argv[0]); if( r<0.0 ){ isNeg = 1; r = -r; }else{ isNeg = 0; } memcpy(&a,&r,sizeof(a)); if( a==0 ){ e = 0; m = 0; }else{ e = a>>52; m = a & ((((sqlite3_int64)1)<<52)-1); m |= ((sqlite3_int64)1)<<52; while( e<1075 && m>0 && (m&1)==0 ){ m >>= 1; e++; } if( isNeg ) m = -m; } sqlite3_snprintf(sizeof(zResult), zResult, "ieee754(%lld,%d)", m, e-1075); sqlite3_result_text(context, zResult, -1, SQLITE_TRANSIENT); }else if( argc==2 ){ sqlite3_int64 m, e, a; double r; int isNeg = 0; m = sqlite3_value_int64(argv[0]); e = sqlite3_value_int64(argv[1]); if( m<0 ){ isNeg = 1; m = -m; if( m<0 ) return; }else if( m==0 && e>1000 && e<1000 ){ sqlite3_result_double(context, 0.0); return; } while( (m>>32)&0xffe00000 ){ m >>= 1; e++; } while( m!=0 && ((m>>32)&0xfff00000)==0 ){ m <<= 1; e--; } e += 1075; if( e<0 ) e = m = 0; 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); } } #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_ieee_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ rc = sqlite3_create_function(db, "ieee754", 1, SQLITE_UTF8, 0, ieee754func, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "ieee754", 2, SQLITE_UTF8, 0, ieee754func, 0, 0); } return rc; } |
Added ext/misc/json1.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 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 | /* ** 2015-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. ** ****************************************************************************** ** ** This SQLite extension implements JSON functions. The interface is ** modeled after MySQL JSON functions: ** ** https://dev.mysql.com/doc/refman/5.7/en/json.html ** ** For the time being, all JSON is stored as pure text. (We might add ** a JSONB type in the future which stores a binary encoding of JSON in ** a BLOB, but there is no support for JSONB in the current implementation. ** This implementation parses JSON text at 250 MB/s, so it is hard to see ** how JSONB might improve on that.) */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1) #if !defined(SQLITEINT_H) #include "sqlite3ext.h" #endif SQLITE_EXTENSION_INIT1 #include <assert.h> #include <string.h> #include <stdlib.h> #include <stdarg.h> /* Mark a function parameter as unused, to suppress nuisance compiler ** warnings. */ #ifndef UNUSED_PARAM # define UNUSED_PARAM(X) (void)(X) #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 */ # define safe_isdigit(x) sqlite3Isdigit(x) # define safe_isalnum(x) sqlite3Isalnum(x) # define safe_isxdigit(x) sqlite3Isxdigit(x) #else /* Use the standard library for separate compilation */ #include <ctype.h> /* amalgamator: keep */ # define safe_isdigit(x) isdigit((unsigned char)(x)) # define safe_isalnum(x) isalnum((unsigned char)(x)) # define safe_isxdigit(x) isxdigit((unsigned char)(x)) #endif /* ** Growing our own isspace() routine this way is twice as fast as ** the library isspace() function, resulting in a 7% overall performance ** increase for the parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os). */ static const char jsonIsSpace[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; #define safe_isspace(x) (jsonIsSpace[(unsigned char)x]) #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 ** that can be and is used to create strings other than JSON. */ struct JsonString { sqlite3_context *pCtx; /* Function context - put error messages here */ char *zBuf; /* Append JSON content here */ u64 nAlloc; /* Bytes of storage available in zBuf[] */ u64 nUsed; /* Bytes of zBuf[] currently used */ u8 bStatic; /* True if zBuf is static space */ u8 bErr; /* True if an error has been encountered */ char zSpace[100]; /* Initial static space */ }; /* JSON type values */ #define JSON_NULL 0 #define JSON_TRUE 1 #define JSON_FALSE 2 #define JSON_INT 3 #define JSON_REAL 4 #define JSON_STRING 5 #define JSON_ARRAY 6 #define JSON_OBJECT 7 /* The "subtype" set for JSON values */ #define JSON_SUBTYPE 74 /* Ascii for "J" */ /* ** Names of the various JSON types: */ static const char * const jsonType[] = { "null", "true", "false", "integer", "real", "text", "array", "object" }; /* Bit values for the JsonNode.jnFlag field */ #define JNODE_RAW 0x01 /* Content is raw, not JSON encoded */ #define JNODE_ESCAPE 0x02 /* Content is text with \ escapes */ #define JNODE_REMOVE 0x04 /* Do not output */ #define JNODE_REPLACE 0x08 /* Replace with JsonNode.u.iReplace */ #define JNODE_PATCH 0x10 /* Patch with JsonNode.u.pPatch */ #define JNODE_APPEND 0x20 /* More ARRAY/OBJECT entries at u.iAppend */ #define JNODE_LABEL 0x40 /* Is a label of an object */ /* 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 { const char *zJContent; /* Content for INT, REAL, and STRING */ u32 iAppend; /* More terms for ARRAY and OBJECT */ u32 iKey; /* Key for ARRAY objects in json_tree() */ u32 iReplace; /* Replacement content for JNODE_REPLACE */ JsonNode *pPatch; /* Node chain of patch for JNODE_PATCH */ } u; }; /* A completely parsed JSON string */ struct JsonParse { u32 nNode; /* Number of slots of aNode[] used */ u32 nAlloc; /* Number of slots of aNode[] allocated */ JsonNode *aNode; /* Array of nodes containing the parse */ const char *zJson; /* Original JSON string */ u32 *aUp; /* Index of parent of each node */ u8 oom; /* Set to true if out of memory */ u8 nErr; /* Number of errors seen */ u16 iDepth; /* Nesting depth */ int nJson; /* Length of the zJson string in bytes */ u32 iHold; /* Replace cache line with the lowest iHold value */ }; /* ** Maximum nesting depth of JSON for this implementation. ** ** This limit is needed to avoid a stack overflow in the recursive ** descent parser. A depth of 2000 is far deeper than any sane JSON ** should go. */ #define JSON_MAX_DEPTH 2000 /************************************************************************** ** Utility routines for dealing with JsonString objects **************************************************************************/ /* Set the JsonString object to an empty string */ static void jsonZero(JsonString *p){ p->zBuf = p->zSpace; p->nAlloc = sizeof(p->zSpace); p->nUsed = 0; p->bStatic = 1; } /* Initialize the JsonString object */ static void jsonInit(JsonString *p, sqlite3_context *pCtx){ p->pCtx = pCtx; p->bErr = 0; jsonZero(p); } /* Free all allocated memory and reset the JsonString object back to its ** initial state. */ static void jsonReset(JsonString *p){ if( !p->bStatic ) sqlite3_free(p->zBuf); jsonZero(p); } /* Report an out-of-memory (OOM) condition */ static void jsonOom(JsonString *p){ p->bErr = 1; sqlite3_result_error_nomem(p->pCtx); jsonReset(p); } /* Enlarge pJson->zBuf so that it can hold at least N more bytes. ** Return zero on success. Return non-zero on an OOM error */ static int jsonGrow(JsonString *p, u32 N){ u64 nTotal = N<p->nAlloc ? p->nAlloc*2 : p->nAlloc+N+10; char *zNew; if( p->bStatic ){ if( p->bErr ) return 1; zNew = sqlite3_malloc64(nTotal); if( zNew==0 ){ jsonOom(p); return SQLITE_NOMEM; } memcpy(zNew, p->zBuf, (size_t)p->nUsed); p->zBuf = zNew; p->bStatic = 0; }else{ zNew = sqlite3_realloc64(p->zBuf, nTotal); if( zNew==0 ){ jsonOom(p); return SQLITE_NOMEM; } p->zBuf = zNew; } 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. */ static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){ va_list ap; if( (p->nUsed + N >= p->nAlloc) && jsonGrow(p, N) ) return; va_start(ap, zFormat); sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap); va_end(ap); p->nUsed += (int)strlen(p->zBuf+p->nUsed); } /* Append a single character */ static void jsonAppendChar(JsonString *p, char c){ if( p->nUsed>=p->nAlloc && jsonGrow(p,1)!=0 ) return; p->zBuf[p->nUsed++] = c; } /* Append a comma separator to the output buffer, if the previous ** character is not '[' or '{'. */ static void jsonAppendSeparator(JsonString *p){ char c; if( p->nUsed==0 ) return; c = p->zBuf[p->nUsed-1]; if( c!='[' && c!='{' ) jsonAppendChar(p, ','); } /* 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( (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++] = '\\'; }else if( c<=0x1f ){ static const char aSpecial[] = { 0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; assert( sizeof(aSpecial)==32 ); assert( aSpecial['\b']=='b' ); assert( aSpecial['\f']=='f' ); assert( aSpecial['\n']=='n' ); assert( aSpecial['\r']=='r' ); assert( aSpecial['\t']=='t' ); if( aSpecial[c] ){ c = aSpecial[c]; goto json_simple_escape; } if( (p->nUsed+N+7+i > p->nAlloc) && jsonGrow(p,N+7-i)!=0 ) return; p->zBuf[p->nUsed++] = '\\'; p->zBuf[p->nUsed++] = 'u'; p->zBuf[p->nUsed++] = '0'; p->zBuf[p->nUsed++] = '0'; p->zBuf[p->nUsed++] = '0' + (c>>4); c = "0123456789abcdef"[c&0xf]; } p->zBuf[p->nUsed++] = c; } p->zBuf[p->nUsed++] = '"'; assert( p->nUsed<p->nAlloc ); } /* ** Append a function parameter value to the JSON string under ** construction. */ static void jsonAppendValue( JsonString *p, /* Append to this JSON string */ sqlite3_value *pValue /* Value to append */ ){ switch( sqlite3_value_type(pValue) ){ case SQLITE_NULL: { jsonAppendRaw(p, "null", 4); break; } case SQLITE_INTEGER: case SQLITE_FLOAT: { const char *z = (const char*)sqlite3_value_text(pValue); u32 n = (u32)sqlite3_value_bytes(pValue); jsonAppendRaw(p, z, n); break; } case SQLITE_TEXT: { const char *z = (const char*)sqlite3_value_text(pValue); u32 n = (u32)sqlite3_value_bytes(pValue); if( sqlite3_value_subtype(pValue)==JSON_SUBTYPE ){ jsonAppendRaw(p, z, n); }else{ jsonAppendString(p, z, n); } break; } default: { if( p->bErr==0 ){ sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1); p->bErr = 2; jsonReset(p); } break; } } } /* Make the JSON in p the result of the SQL function. */ static void jsonResult(JsonString *p){ if( p->bErr==0 ){ sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed, p->bStatic ? SQLITE_TRANSIENT : sqlite3_free, SQLITE_UTF8); jsonZero(p); } assert( p->bStatic ); } /************************************************************************** ** Utility routines for dealing with JsonNode and JsonParse objects **************************************************************************/ /* ** Return the number of consecutive JsonNode slots need to represent ** the parsed JSON at pNode. The minimum answer is 1. For ARRAY and ** OBJECT types, the number might be larger. ** ** Appended elements are not counted. The value returned is the number ** by which the JsonNode counter should increment in order to go to the ** next peer value. */ static u32 jsonNodeSize(JsonNode *pNode){ return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1; } /* ** Reclaim all memory allocated by a JsonParse object. But do not ** delete the JsonParse object itself. */ static void jsonParseReset(JsonParse *pParse){ sqlite3_free(pParse->aNode); pParse->aNode = 0; pParse->nNode = 0; pParse->nAlloc = 0; sqlite3_free(pParse->aUp); pParse->aUp = 0; } /* ** Free a JsonParse object that was obtained from sqlite3_malloc(). */ static void jsonParseFree(JsonParse *pParse){ jsonParseReset(pParse); sqlite3_free(pParse); } /* ** Convert the JsonNode pNode into a pure JSON string and ** append to pOut. Subsubstructure is also included. Return ** 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) ){ if( pNode->jnFlags & JNODE_REPLACE ){ jsonAppendValue(pOut, aReplace[pNode->u.iReplace]); return; } 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 ){ jsonAppendString(pOut, pNode->u.zJContent, pNode->n); break; } /* Fall through into the next case */ } case JSON_REAL: case JSON_INT: { 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; 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; pNode = &pNode[pNode->u.iAppend]; j = 1; } jsonAppendChar(pOut, '}'); break; } } } /* ** Return a JsonNode and all its descendents as a JSON string. */ static void jsonReturnJson( JsonNode *pNode, /* Node to return */ sqlite3_context *pCtx, /* Return value for this function */ sqlite3_value **aReplace /* Array of replacement values */ ){ 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 */ sqlite3_value **aReplace /* Array of replacement values */ ){ switch( pNode->eType ){ default: { assert( pNode->eType==JSON_NULL ); sqlite3_result_null(pCtx); break; } case JSON_TRUE: { sqlite3_result_int(pCtx, 1); break; } case JSON_FALSE: { sqlite3_result_int(pCtx, 0); break; } case JSON_INT: { sqlite3_int64 i = 0; const char *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; if( v==8 ){ if( pNode->u.zJContent[0]=='-' ){ sqlite3_result_int64(pCtx, SMALLEST_INT64); goto int_done; }else{ goto int_as_real; } } } i = i*10 + v; } if( pNode->u.zJContent[0]=='-' ){ i = -i; } sqlite3_result_int64(pCtx, i); int_done: break; int_as_real: /* fall through to real */; } case JSON_REAL: { double r; #ifdef SQLITE_AMALGAMATION const char *z = pNode->u.zJContent; sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8); #else 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 ){ 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 */ 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 = pNode->u.zJContent; char *zOut; u32 j; 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 = 0, k; for(k=0; k<4; i++, k++){ assert( i<n-2 ); c = z[i+1]; assert( safe_isxdigit(c) ); if( c<='9' ) v = v*16 + c - '0'; else if( c<='F' ) v = v*16 + c - 'A' + 10; else v = v*16 + c - 'a' + 10; } 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{ zOut[j++] = (char)(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' ){ c = '\n'; }else if( c=='r' ){ c = '\r'; }else if( c=='t' ){ c = '\t'; } zOut[j++] = c; } } } zOut[j] = 0; sqlite3_result_text(pCtx, zOut, j, sqlite3_free); } break; } case JSON_ARRAY: case JSON_OBJECT: { jsonReturnJson(pNode, pCtx, aReplace); break; } } } /* Forward reference */ static int jsonParseAddNode(JsonParse*,u32,u32,const char*); /* ** A macro to hint to the compiler that a function should not be ** inlined. */ #if defined(__GNUC__) # define JSON_NOINLINE __attribute__((noinline)) #elif defined(_MSC_VER) && _MSC_VER>=1310 # define JSON_NOINLINE __declspec(noinline) #else # define JSON_NOINLINE #endif static JSON_NOINLINE int jsonParseAddNodeExpand( JsonParse *pParse, /* Append the node to this object */ u32 eType, /* Node type */ u32 n, /* Content size or sub-node count */ 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 ); return jsonParseAddNode(pParse, eType, n, zContent); } /* ** Create a new JsonNode instance based on the arguments and append that ** instance to the JsonParse. Return the index in pParse->aNode[] of the ** new node, or -1 if a memory allocation fails. */ 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->nNode>=pParse->nAlloc ){ return jsonParseAddNodeExpand(pParse, eType, n, zContent); } p = &pParse->aNode[pParse->nNode]; p->eType = (u8)eType; p->jnFlags = 0; p->n = n; p->u.zJContent = zContent; return pParse->nNode++; } /* ** Return true if z[] begins with 4 (or more) hexadecimal digits */ static int jsonIs4Hex(const char *z){ int i; for(i=0; i<4; i++) if( !safe_isxdigit(z[i]) ) return 0; return 1; } /* ** Parse a single JSON value which begins at pParse->zJson[i]. Return the ** index of the first character past the end of the value parsed. ** ** Return negative for a syntax error. Special cases: return -2 if the ** first non-whitespace character is '}' and return -3 if the first ** non-whitespace character is ']'. */ static int jsonParseValue(JsonParse *pParse, u32 i){ char c; u32 j; int iThis; int x; JsonNode *pNode; const char *z = pParse->zJson; while( safe_isspace(z[i]) ){ i++; } if( (c = z[i])=='{' ){ /* Parse object */ iThis = jsonParseAddNode(pParse, JSON_OBJECT, 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); if( x<0 ){ pParse->iDepth--; if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1; return -1; } if( pParse->oom ) return -1; pNode = &pParse->aNode[pParse->nNode-1]; if( pNode->eType!=JSON_STRING ) return -1; pNode->jnFlags |= JNODE_LABEL; j = x; while( safe_isspace(z[j]) ){ j++; } if( z[j]!=':' ) return -1; j++; x = jsonParseValue(pParse, j); pParse->iDepth--; if( x<0 ) return -1; j = x; while( safe_isspace(z[j]) ){ j++; } c = z[j]; if( c==',' ) continue; if( c!='}' ) return -1; break; } 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; return -1; } j = x; while( safe_isspace(z[j]) ){ j++; } c = z[j]; if( c==',' ) continue; if( c!=']' ) return -1; break; } pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1; return j+1; }else if( c=='"' ){ /* Parse string */ u8 jnFlags = 0; j = i+1; for(;;){ c = z[j]; if( (c & ~0x1f)==0 ){ /* Control characters are not allowed in strings */ return -1; } if( c=='\\' ){ c = z[++j]; if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f' || c=='n' || c=='r' || c=='t' || (c=='u' && jsonIs4Hex(z+j+1)) ){ jnFlags = JNODE_ESCAPE; }else{ return -1; } }else if( c=='"' ){ break; } j++; } jsonParseAddNode(pParse, JSON_STRING, j+1-i, &z[i]); if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags; return j+1; }else if( c=='n' && strncmp(z+i,"null",4)==0 && !safe_isalnum(z[i+4]) ){ jsonParseAddNode(pParse, JSON_NULL, 0, 0); return i+4; }else if( c=='t' && strncmp(z+i,"true",4)==0 && !safe_isalnum(z[i+4]) ){ jsonParseAddNode(pParse, JSON_TRUE, 0, 0); return i+4; }else if( c=='f' && strncmp(z+i,"false",5)==0 && !safe_isalnum(z[i+5]) ){ jsonParseAddNode(pParse, JSON_FALSE, 0, 0); return i+5; }else if( c=='-' || (c>='0' && c<='9') ){ /* Parse number */ u8 seenDP = 0; u8 seenE = 0; assert( '-' < '0' ); if( c<='0' ){ j = c=='-' ? i+1 : i; if( z[j]=='0' && z[j+1]>='0' && z[j+1]<='9' ) return -1; } j = i+1; for(;; j++){ c = z[j]; if( c>='0' && c<='9' ) continue; if( c=='.' ){ if( z[j-1]=='-' ) return -1; if( seenDP ) return -1; seenDP = 1; continue; } if( c=='e' || c=='E' ){ if( z[j-1]<'0' ) return -1; if( seenE ) return -1; seenDP = seenE = 1; c = z[j+1]; if( c=='+' || c=='-' ){ j++; c = z[j+1]; } if( c<'0' || c>'9' ) return -1; continue; } break; } if( z[j-1]<'0' ) return -1; jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT, j - i, &z[i]); return j; }else if( c=='}' ){ return -2; /* End of {...} */ }else if( c==']' ){ return -3; /* End of [...] */ }else if( c==0 ){ return 0; /* End of file */ }else{ return -1; /* Syntax error */ } } /* ** Parse a complete JSON string. Return 0 on success or non-zero if there ** are any errors. If an error occurs, free all memory associated with ** pParse. ** ** pParse is uninitialized when this routine is called. */ static int jsonParse( JsonParse *pParse, /* Initialize and fill this JsonParse object */ sqlite3_context *pCtx, /* Report errors here */ const char *zJson /* Input JSON text to be parsed */ ){ int i; memset(pParse, 0, sizeof(*pParse)); if( zJson==0 ) return 1; pParse->zJson = zJson; i = jsonParseValue(pParse, 0); if( pParse->oom ) i = -1; if( i>0 ){ assert( pParse->iDepth==0 ); while( safe_isspace(zJson[i]) ) i++; if( zJson[i] ) i = -1; } if( i<=0 ){ if( pCtx!=0 ){ if( pParse->oom ){ sqlite3_result_error_nomem(pCtx); }else{ sqlite3_result_error(pCtx, "malformed JSON", -1); } } jsonParseReset(pParse); return 1; } return 0; } /* Mark node i of pParse as being a child of iParent. Call recursively ** to fill in all the descendants of node i. */ static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){ JsonNode *pNode = &pParse->aNode[i]; u32 j; pParse->aUp[i] = iParent; switch( pNode->eType ){ case JSON_ARRAY: { for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j)){ jsonParseFillInParentage(pParse, i+j, i); } break; } case JSON_OBJECT: { for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j+1)+1){ pParse->aUp[i+j] = i; jsonParseFillInParentage(pParse, i+j+1, i); } break; } default: { break; } } } /* ** 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; } /* ** Magic number used for the JSON parse cache in sqlite3_get_auxdata() */ #define JSON_CACHE_ID (-429938) /* First cache entry */ #define JSON_CACHE_SZ 4 /* Max number of cache entries */ /* ** Obtain a complete parse of the JSON found in the first argument ** of the argv array. Use the sqlite3_get_auxdata() cache for this ** parse if it is available. If the cache is not available or if it ** is no longer valid, parse the JSON again and return the new parse, ** and also register the new parse so that it will be available for ** future sqlite3_get_auxdata() calls. */ static JsonParse *jsonParseCached( sqlite3_context *pCtx, sqlite3_value **argv, sqlite3_context *pErrCtx ){ const char *zJson = (const char*)sqlite3_value_text(argv[0]); int nJson = sqlite3_value_bytes(argv[0]); JsonParse *p; JsonParse *pMatch = 0; int iKey; int iMinKey = 0; u32 iMinHold = 0xffffffff; u32 iMaxHold = 0; if( zJson==0 ) return 0; for(iKey=0; iKey<JSON_CACHE_SZ; iKey++){ p = (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iKey); if( p==0 ){ iMinKey = iKey; break; } if( pMatch==0 && p->nJson==nJson && memcmp(p->zJson,zJson,nJson)==0 ){ p->nErr = 0; pMatch = p; }else if( p->iHold<iMinHold ){ iMinHold = p->iHold; iMinKey = iKey; } if( p->iHold>iMaxHold ){ iMaxHold = p->iHold; } } 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); if( jsonParse(p, pErrCtx, p->zJson) ){ sqlite3_free(p); return 0; } p->nJson = nJson; p->iHold = iMaxHold+1; sqlite3_set_auxdata(pCtx, JSON_CACHE_ID+iMinKey, p, (void(*)(void*))jsonParseFree); return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iMinKey); } /* ** 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; } } /* forward declaration */ static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*,const char**); /* ** Search along zPath to find the node specified. Return a pointer ** to that node, or NULL if zPath is malformed or if there is no such ** node. ** ** If pApnd!=0, then try to append new nodes to complete zPath if it is ** possible to do so and if no existing node corresponds to zPath. If ** new nodes are appended *pApnd is set to 1. */ static JsonNode *jsonLookupStep( JsonParse *pParse, /* The JSON to search */ u32 iRoot, /* Begin the search at this node */ const char *zPath, /* The path to search */ 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; if( zPath[i] ){ i++; }else{ *pzErr = zPath; return 0; } }else{ zKey = zPath; for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){} nKey = i; } if( nKey==0 ){ *pzErr = zPath; return 0; } j = 1; for(;;){ while( j<=pRoot->n ){ 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); iLabel = jsonParseAddNode(pParse, JSON_STRING, i, zPath); zPath += i; pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr); if( pParse->oom ) return 0; if( pNode ){ pRoot = &pParse->aNode[iRoot]; pRoot->u.iAppend = iStart - iRoot; pRoot->jnFlags |= JNODE_APPEND; pParse->aNode[iLabel].jnFlags |= JNODE_RAW; } return pNode; } }else if( zPath[0]=='[' && safe_isdigit(zPath[1]) ){ if( pRoot->eType!=JSON_ARRAY ) return 0; i = 0; j = 1; while( safe_isdigit(zPath[j]) ){ i = i*10 + zPath[j] - '0'; j++; } if( zPath[j]!=']' ){ *pzErr = zPath; 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; 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]; pRoot->u.iAppend = iStart - iRoot; pRoot->jnFlags |= JNODE_APPEND; } return pNode; } }else{ *pzErr = zPath; } return 0; } /* ** Append content to pParse that will complete zPath. Return a pointer ** to the inserted node, or return NULL if the append fails. */ static JsonNode *jsonLookupAppend( JsonParse *pParse, /* Append content to the JSON parse */ const char *zPath, /* Description of content to append */ int *pApnd, /* Set this flag to 1 */ const char **pzErr /* Make this point to any syntax error */ ){ *pApnd = 1; if( zPath[0]==0 ){ jsonParseAddNode(pParse, JSON_NULL, 0, 0); return pParse->oom ? 0 : &pParse->aNode[pParse->nNode-1]; } if( zPath[0]=='.' ){ jsonParseAddNode(pParse, JSON_OBJECT, 0, 0); }else if( strncmp(zPath,"[0]",3)==0 ){ jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); }else{ return 0; } if( pParse->oom ) return 0; return jsonLookupStep(pParse, pParse->nNode-1, zPath, pApnd, pzErr); } /* ** Return the text of a syntax error message on a JSON path. Space is ** obtained from sqlite3_malloc(). */ static char *jsonPathSyntaxError(const char *zErr){ return sqlite3_mprintf("JSON path error near '%q'", zErr); } /* ** Do a node lookup using zPath. Return a pointer to the node on success. ** Return NULL if not found or if there is an error. ** ** On an error, write an error message into pCtx and increment the ** pParse->nErr counter. ** ** If pApnd!=NULL then try to append missing nodes and set *pApnd = 1 if ** nodes are appended. */ static JsonNode *jsonLookup( JsonParse *pParse, /* The JSON to search */ const char *zPath, /* The path to search */ int *pApnd, /* Append nodes to complete path if not NULL */ sqlite3_context *pCtx /* Report errors here, if not NULL */ ){ const char *zErr = 0; JsonNode *pNode = 0; char *zMsg; if( zPath==0 ) return 0; if( zPath[0]!='$' ){ zErr = zPath; goto lookup_err; } zPath++; pNode = jsonLookupStep(pParse, 0, zPath, pApnd, &zErr); if( zErr==0 ) return pNode; lookup_err: pParse->nErr++; assert( zErr!=0 && pCtx!=0 ); zMsg = jsonPathSyntaxError(zErr); if( zMsg ){ sqlite3_result_error(pCtx, zMsg, -1); sqlite3_free(zMsg); }else{ sqlite3_result_error_nomem(pCtx); } return 0; } /* ** Report the wrong number of arguments for json_insert(), json_replace() ** or json_set(). */ static void jsonWrongNumArgs( sqlite3_context *pCtx, const char *zFuncName ){ char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments", zFuncName); sqlite3_result_error(pCtx, zMsg, -1); sqlite3_free(zMsg); } /* ** Mark all NULL entries in the Object passed in as JNODE_REMOVE. */ static void jsonRemoveAllNulls(JsonNode *pNode){ int i, n; assert( pNode->eType==JSON_OBJECT ); n = pNode->n; for(i=2; i<=n; i += jsonNodeSize(&pNode[i])+1){ switch( pNode[i].eType ){ case JSON_NULL: pNode[i].jnFlags |= JNODE_REMOVE; break; case JSON_OBJECT: jsonRemoveAllNulls(&pNode[i]); break; } } } /**************************************************************************** ** SQL functions used for testing and debugging ****************************************************************************/ #ifdef SQLITE_DEBUG /* ** The json_parse(JSON) function returns a string which describes ** a parse of the JSON provided. Or it returns NULL if JSON is not ** well-formed. */ static void jsonParseFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonString s; /* Output string - not real JSON */ JsonParse x; /* The parse */ u32 i; assert( argc==1 ); if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; jsonParseFindParents(&x); jsonInit(&s, ctx); for(i=0; i<x.nNode; i++){ const char *zType; if( x.aNode[i].jnFlags & JNODE_LABEL ){ 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); } /* ** The json_test1(JSON) function return true (1) if the input is JSON ** text generated by another json function. It returns (0) if the input ** is not known to be JSON. */ static void jsonTest1Func( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ UNUSED_PARAM(argc); sqlite3_result_int(ctx, sqlite3_value_subtype(argv[0])==JSON_SUBTYPE); } #endif /* SQLITE_DEBUG */ /**************************************************************************** ** Scalar SQL function implementations ****************************************************************************/ /* ** Implementation of the json_QUOTE(VALUE) function. Return a JSON value ** corresponding to the SQL value input. Mostly this means putting ** double-quotes around strings and returning the unquoted string "null" ** when given a NULL input. */ static void jsonQuoteFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonString jx; UNUSED_PARAM(argc); jsonInit(&jx, ctx); jsonAppendValue(&jx, argv[0]); jsonResult(&jx); sqlite3_result_subtype(ctx, JSON_SUBTYPE); } /* ** Implementation of the json_array(VALUE,...) function. Return a JSON ** array that contains all values given in arguments. Or if any argument ** is a BLOB, throw an error. */ static void jsonArrayFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ int i; JsonString jx; jsonInit(&jx, ctx); jsonAppendChar(&jx, '['); for(i=0; i<argc; i++){ jsonAppendSeparator(&jx); jsonAppendValue(&jx, argv[i]); } jsonAppendChar(&jx, ']'); jsonResult(&jx); sqlite3_result_subtype(ctx, JSON_SUBTYPE); } /* ** json_array_length(JSON) ** json_array_length(JSON, PATH) ** ** Return the number of elements in the top-level JSON array. ** Return 0 if the input is not a well-formed JSON array. */ static void jsonArrayLengthFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse *p; /* The parse */ sqlite3_int64 n = 0; u32 i; JsonNode *pNode; p = jsonParseCached(ctx, argv, ctx); if( p==0 ) return; assert( p->nNode ); if( argc==2 ){ const char *zPath = (const char*)sqlite3_value_text(argv[1]); pNode = jsonLookup(p, zPath, 0, ctx); }else{ pNode = p->aNode; } if( pNode==0 ){ return; } if( pNode->eType==JSON_ARRAY ){ assert( (pNode->jnFlags & JNODE_APPEND)==0 ); for(i=1; i<=pNode->n; n++){ i += jsonNodeSize(&pNode[i]); } } sqlite3_result_int64(ctx, n); } /* ** json_extract(JSON, PATH, ...) ** ** Return the element described by PATH. Return NULL if there is no ** PATH element. If there are multiple PATHs, then return a JSON array ** with the result from each path. Throw an error if the JSON or any PATH ** is malformed. */ static void jsonExtractFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse *p; /* The parse */ JsonNode *pNode; const char *zPath; JsonString jx; int i; if( argc<2 ) return; p = jsonParseCached(ctx, argv, ctx); if( p==0 ) return; jsonInit(&jx, ctx); jsonAppendChar(&jx, '['); for(i=1; i<argc; i++){ zPath = (const char*)sqlite3_value_text(argv[i]); pNode = jsonLookup(p, zPath, 0, ctx); if( p->nErr ) break; if( argc>2 ){ jsonAppendSeparator(&jx); if( pNode ){ jsonRenderNode(pNode, &jx, 0); }else{ jsonAppendRaw(&jx, "null", 4); } }else if( pNode ){ jsonReturn(pNode, ctx, 0); } } if( argc>2 && i==argc ){ jsonAppendChar(&jx, ']'); jsonResult(&jx); sqlite3_result_subtype(ctx, JSON_SUBTYPE); } jsonReset(&jx); } /* This is the RFC 7396 MergePatch algorithm. */ static JsonNode *jsonMergePatch( JsonParse *pParse, /* The JSON parser that contains the TARGET */ u32 iTarget, /* Node of the TARGET in pParse */ JsonNode *pPatch /* The PATCH */ ){ u32 i, j; u32 iRoot; JsonNode *pTarget; if( pPatch->eType!=JSON_OBJECT ){ return pPatch; } assert( iTarget>=0 && iTarget<pParse->nNode ); pTarget = &pParse->aNode[iTarget]; assert( (pPatch->jnFlags & JNODE_APPEND)==0 ); if( pTarget->eType!=JSON_OBJECT ){ jsonRemoveAllNulls(pPatch); return pPatch; } 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; } /* ** Implementation of the json_mergepatch(JSON1,JSON2) function. Return a JSON ** object that is the result of running the RFC 7396 MergePatch() algorithm ** on the two arguments. */ static void jsonPatchFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse x; /* The JSON that is being patched */ JsonParse y; /* The patch */ JsonNode *pResult; /* The result of the merge */ UNUSED_PARAM(argc); if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; if( jsonParse(&y, ctx, (const char*)sqlite3_value_text(argv[1])) ){ jsonParseReset(&x); return; } pResult = jsonMergePatch(&x, 0, y.aNode); assert( pResult!=0 || x.oom ); if( pResult ){ jsonReturnJson(pResult, ctx, 0); }else{ sqlite3_result_error_nomem(ctx); } jsonParseReset(&x); jsonParseReset(&y); } /* ** Implementation of the json_object(NAME,VALUE,...) function. Return a JSON ** object that contains all name/value given in arguments. Or if any name ** is not a string or if any value is a BLOB, throw an error. */ static void jsonObjectFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ int i; JsonString jx; const char *z; u32 n; if( argc&1 ){ sqlite3_result_error(ctx, "json_object() requires an even number " "of arguments", -1); return; } jsonInit(&jx, ctx); jsonAppendChar(&jx, '{'); for(i=0; i<argc; i+=2){ if( sqlite3_value_type(argv[i])!=SQLITE_TEXT ){ sqlite3_result_error(ctx, "json_object() labels must be TEXT", -1); jsonReset(&jx); return; } jsonAppendSeparator(&jx); z = (const char*)sqlite3_value_text(argv[i]); n = (u32)sqlite3_value_bytes(argv[i]); jsonAppendString(&jx, z, n); jsonAppendChar(&jx, ':'); jsonAppendValue(&jx, argv[i+1]); } jsonAppendChar(&jx, '}'); jsonResult(&jx); sqlite3_result_subtype(ctx, JSON_SUBTYPE); } /* ** json_remove(JSON, PATH, ...) ** ** Remove the named elements from JSON and return the result. malformed ** JSON or PATH arguments result in an error. */ static void jsonRemoveFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse x; /* The parse */ JsonNode *pNode; const char *zPath; u32 i; if( argc<1 ) return; if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; assert( x.nNode ); for(i=1; i<(u32)argc; i++){ zPath = (const char*)sqlite3_value_text(argv[i]); if( zPath==0 ) goto remove_done; pNode = jsonLookup(&x, zPath, 0, ctx); if( x.nErr ) goto remove_done; if( pNode ) pNode->jnFlags |= JNODE_REMOVE; } if( (x.aNode[0].jnFlags & JNODE_REMOVE)==0 ){ jsonReturnJson(x.aNode, ctx, 0); } remove_done: jsonParseReset(&x); } /* ** json_replace(JSON, PATH, VALUE, ...) ** ** Replace the value at PATH with VALUE. If PATH does not already exist, ** this routine is a no-op. If JSON or PATH is malformed, throw an error. */ static void jsonReplaceFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse x; /* The parse */ JsonNode *pNode; const char *zPath; u32 i; if( argc<1 ) return; if( (argc&1)==0 ) { jsonWrongNumArgs(ctx, "replace"); return; } 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); } /* ** json_set(JSON, PATH, VALUE, ...) ** ** Set the value at PATH to VALUE. Create the PATH if it does not already ** exist. Overwrite existing values that do exist. ** If JSON or PATH is malformed, throw an error. ** ** json_insert(JSON, PATH, VALUE, ...) ** ** Create PATH and initialize it to VALUE. If PATH already exists, this ** routine is a no-op. If JSON or PATH is malformed, throw an error. */ static void jsonSetFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse x; /* The parse */ JsonNode *pNode; const char *zPath; u32 i; int bApnd; int bIsSet = *(int*)sqlite3_user_data(ctx); if( argc<1 ) return; if( (argc&1)==0 ) { jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert"); return; } 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]); bApnd = 0; 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); } /* ** json_type(JSON) ** json_type(JSON, PATH) ** ** Return the top-level "type" of a JSON string. Throw an error if ** either the JSON or PATH inputs are not well-formed. */ static void jsonTypeFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse *p; /* The parse */ const char *zPath; JsonNode *pNode; p = jsonParseCached(ctx, argv, ctx); if( p==0 ) return; if( argc==2 ){ zPath = (const char*)sqlite3_value_text(argv[1]); pNode = jsonLookup(p, zPath, 0, ctx); }else{ pNode = p->aNode; } if( pNode ){ sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC); } } /* ** json_valid(JSON) ** ** Return 1 if JSON is a well-formed JSON string according to RFC-7159. ** Return 0 otherwise. */ static void jsonValidFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse *p; /* The parse */ UNUSED_PARAM(argc); p = jsonParseCached(ctx, argv, 0); sqlite3_result_int(ctx, p!=0); } /**************************************************************************** ** Aggregate SQL function implementations ****************************************************************************/ /* ** json_group_array(VALUE) ** ** Return a JSON array composed of all values in the aggregate. */ static void jsonArrayStep( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ 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{ 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 ){ pStr->pCtx = ctx; jsonAppendChar(pStr, ']'); if( pStr->bErr ){ if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); assert( pStr->bStatic ); }else if( isFinal ){ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free); pStr->bStatic = 1; }else{ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT); pStr->nUsed--; } }else{ sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC); } sqlite3_result_subtype(ctx, JSON_SUBTYPE); } static void jsonArrayValue(sqlite3_context *ctx){ jsonArrayCompute(ctx, 0); } static void jsonArrayFinal(sqlite3_context *ctx){ jsonArrayCompute(ctx, 1); } #ifndef SQLITE_OMIT_WINDOWFUNC /* ** This method works for both json_group_array() and json_group_object(). ** It works by removing the first element of the group by searching forward ** to the first comma (",") that is not within a string and deleting all ** text through that comma. */ static void jsonGroupInverse( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ int i; int inStr = 0; char *z; 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; z[i]!=',' || inStr; i++){ assert( i<pStr->nUsed ); if( z[i]=='"' ){ inStr = !inStr; }else if( z[i]=='\\' ){ i++; } } pStr->nUsed -= i; memmove(&z[1], &z[i+1], (size_t)pStr->nUsed-1); } #else # define jsonGroupInverse 0 #endif /* ** json_group_obj(NAME,VALUE) ** ** Return a JSON object composed of all names and values in the aggregate. */ static void jsonObjectStep( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonString *pStr; const char *z; 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{ 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]); } } static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){ JsonString *pStr; pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); if( pStr ){ jsonAppendChar(pStr, '}'); if( pStr->bErr ){ if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); assert( pStr->bStatic ); }else if( isFinal ){ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free); pStr->bStatic = 1; }else{ sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT); pStr->nUsed--; } }else{ sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC); } sqlite3_result_subtype(ctx, JSON_SUBTYPE); } static void jsonObjectValue(sqlite3_context *ctx){ jsonObjectCompute(ctx, 0); } static void jsonObjectFinal(sqlite3_context *ctx){ jsonObjectCompute(ctx, 1); } #ifndef SQLITE_OMIT_VIRTUALTABLE /**************************************************************************** ** The json_each virtual table ****************************************************************************/ typedef struct JsonEachCursor JsonEachCursor; struct JsonEachCursor { sqlite3_vtab_cursor base; /* Base class - must be first */ u32 iRowid; /* The rowid */ u32 iBegin; /* The first node of the scan */ u32 i; /* Index in sParse.aNode[] of current row */ u32 iEnd; /* EOF when i equals or exceeds this value */ u8 eType; /* Type of top-level element */ u8 bRecursive; /* True for json_tree(). False for json_each() */ char *zJson; /* Input JSON */ char *zRoot; /* Path by which to filter zJson */ JsonParse sParse; /* Parse of the input JSON */ }; /* Constructor for the json_each virtual table */ static int jsonEachConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ sqlite3_vtab *pNew; int rc; /* Column numbers */ #define JEACH_KEY 0 #define JEACH_VALUE 1 #define JEACH_TYPE 2 #define JEACH_ATOM 3 #define JEACH_ID 4 #define JEACH_PARENT 5 #define JEACH_FULLKEY 6 #define JEACH_PATH 7 /* The xBestIndex method assumes that the JSON and ROOT columns are ** the last two columns in the table. Should this ever changes, be ** sure to update the xBestIndex method. */ #define JEACH_JSON 8 #define JEACH_ROOT 9 UNUSED_PARAM(pzErr); UNUSED_PARAM(argv); UNUSED_PARAM(argc); UNUSED_PARAM(pAux); 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); return SQLITE_OK; } /* constructor for a JsonEachCursor object for json_each(). */ static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ JsonEachCursor *pCur; UNUSED_PARAM(p); pCur = sqlite3_malloc( sizeof(*pCur) ); if( pCur==0 ) return SQLITE_NOMEM; memset(pCur, 0, sizeof(*pCur)); *ppCursor = &pCur->base; return SQLITE_OK; } /* constructor for a JsonEachCursor object for json_tree(). */ static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ int rc = jsonEachOpenEach(p, ppCursor); if( rc==SQLITE_OK ){ JsonEachCursor *pCur = (JsonEachCursor*)*ppCursor; pCur->bRecursive = 1; } return rc; } /* Reset a JsonEachCursor back to its original state. Free any memory ** held. */ static void jsonEachCursorReset(JsonEachCursor *p){ sqlite3_free(p->zJson); sqlite3_free(p->zRoot); jsonParseReset(&p->sParse); p->iRowid = 0; p->i = 0; p->iEnd = 0; p->eType = 0; p->zJson = 0; p->zRoot = 0; } /* Destructor for a jsonEachCursor object */ static int jsonEachClose(sqlite3_vtab_cursor *cur){ JsonEachCursor *p = (JsonEachCursor*)cur; jsonEachCursorReset(p); sqlite3_free(cur); return SQLITE_OK; } /* Return TRUE if the jsonEachCursor object has been advanced off the end ** of the JSON object */ static int jsonEachEof(sqlite3_vtab_cursor *cur){ JsonEachCursor *p = (JsonEachCursor*)cur; return p->i >= p->iEnd; } /* Advance the cursor to the next element for json_tree() */ static int jsonEachNext(sqlite3_vtab_cursor *cur){ JsonEachCursor *p = (JsonEachCursor*)cur; if( p->bRecursive ){ if( p->sParse.aNode[p->i].jnFlags & JNODE_LABEL ) p->i++; 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++; } } } }else{ switch( p->eType ){ case JSON_ARRAY: { p->i += jsonNodeSize(&p->sParse.aNode[p->i]); p->iRowid++; break; } case JSON_OBJECT: { p->i += 1 + jsonNodeSize(&p->sParse.aNode[p->i+1]); p->iRowid++; break; } default: { p->i = p->iEnd; break; } } } return SQLITE_OK; } /* Append the name of the path for element i to pStr */ static void jsonEachComputePath( JsonEachCursor *p, /* The cursor */ JsonString *pStr, /* Write the path here */ u32 i /* Path to this element */ ){ JsonNode *pNode, *pUp; u32 iUp; if( i==0 ){ jsonAppendChar(pStr, '$'); 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 */ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ int i /* Which column to return */ ){ JsonEachCursor *p = (JsonEachCursor*)cur; JsonNode *pThis = &p->sParse.aNode[p->i]; switch( i ){ case JEACH_KEY: { 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; } case JEACH_VALUE: { if( pThis->jnFlags & JNODE_LABEL ) pThis++; jsonReturn(pThis, ctx, 0); break; } case JEACH_TYPE: { if( pThis->jnFlags & JNODE_LABEL ) pThis++; sqlite3_result_text(ctx, jsonType[pThis->eType], -1, SQLITE_STATIC); break; } case JEACH_ATOM: { if( pThis->jnFlags & JNODE_LABEL ) pThis++; if( pThis->eType>=JSON_ARRAY ) break; jsonReturn(pThis, ctx, 0); break; } case JEACH_ID: { sqlite3_result_int64(ctx, (sqlite3_int64)p->i + ((pThis->jnFlags & JNODE_LABEL)!=0)); break; } case JEACH_PARENT: { if( p->i>p->iBegin && p->bRecursive ){ sqlite3_result_int64(ctx, (sqlite3_int64)p->sParse.aUp[p->i]); } break; } case JEACH_FULLKEY: { JsonString x; jsonInit(&x, ctx); if( p->bRecursive ){ jsonEachComputePath(p, &x, p->i); }else{ if( p->zRoot ){ 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; } case JEACH_JSON: { assert( i==JEACH_JSON ); sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC); break; } } return SQLITE_OK; } /* Return the current rowid value */ static int jsonEachRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ JsonEachCursor *p = (JsonEachCursor*)cur; *pRowid = p->iRowid; return SQLITE_OK; } /* The query strategy is to look for an equality constraint on the json ** column. Without such a constraint, the table cannot operate. idxNum is ** 1 if the constraint is found, 3 if the constraint and zRoot are found, ** and 0 otherwise. */ static int jsonEachBestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo ){ int i; /* Loop counter or computed array index */ int aIdx[2]; /* Index of constraints for JSON and ROOT */ int unusableMask = 0; /* Mask of unusable JSON and ROOT constraints */ int idxMask = 0; /* Mask of usable == constraints JSON and ROOT */ const struct sqlite3_index_constraint *pConstraint; /* This implementation assumes that JSON and ROOT are the last two ** columns in the table */ assert( JEACH_ROOT == JEACH_JSON+1 ); UNUSED_PARAM(tab); aIdx[0] = aIdx[1] = -1; 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; } } if( (unusableMask & ~idxMask)!=0 ){ /* If there are any unusable constraints on JSON or ROOT, then reject ** this entire plan */ return SQLITE_CONSTRAINT; } if( aIdx[0]<0 ){ /* No JSON input. Leave estimatedCost at the huge value that it was ** initialized to to discourage the query planner from selecting this ** plan. */ pIdxInfo->idxNum = 0; }else{ pIdxInfo->estimatedCost = 1.0; i = aIdx[0]; pIdxInfo->aConstraintUsage[i].argvIndex = 1; pIdxInfo->aConstraintUsage[i].omit = 1; if( aIdx[1]<0 ){ pIdxInfo->idxNum = 1; /* Only JSON supplied. Plan 1 */ }else{ i = aIdx[1]; pIdxInfo->aConstraintUsage[i].argvIndex = 2; pIdxInfo->aConstraintUsage[i].omit = 1; pIdxInfo->idxNum = 3; /* Both JSON and ROOT are supplied. Plan 3 */ } } return SQLITE_OK; } /* Start a search on a new JSON string */ static int jsonEachFilter( sqlite3_vtab_cursor *cur, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ JsonEachCursor *p = (JsonEachCursor*)cur; const char *z; const char *zRoot = 0; sqlite3_int64 n; UNUSED_PARAM(idxStr); UNUSED_PARAM(argc); jsonEachCursorReset(p); if( idxNum==0 ) return SQLITE_OK; z = (const char*)sqlite3_value_text(argv[0]); if( z==0 ) return SQLITE_OK; n = sqlite3_value_bytes(argv[0]); p->zJson = sqlite3_malloc64( n+1 ); if( p->zJson==0 ) return SQLITE_NOMEM; memcpy(p->zJson, z, (size_t)n+1); if( jsonParse(&p->sParse, 0, p->zJson) ){ int rc = SQLITE_NOMEM; if( p->sParse.oom==0 ){ sqlite3_free(cur->pVtab->zErrMsg); cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON"); if( cur->pVtab->zErrMsg ) rc = SQLITE_ERROR; } jsonEachCursorReset(p); return rc; }else if( p->bRecursive && jsonParseFindParents(&p->sParse) ){ jsonEachCursorReset(p); return SQLITE_NOMEM; }else{ JsonNode *pNode = 0; if( idxNum==3 ){ const char *zErr = 0; zRoot = (const char*)sqlite3_value_text(argv[1]); if( zRoot==0 ) return SQLITE_OK; n = sqlite3_value_bytes(argv[1]); p->zRoot = sqlite3_malloc64( n+1 ); if( p->zRoot==0 ) return SQLITE_NOMEM; memcpy(p->zRoot, zRoot, (size_t)n+1); if( zRoot[0]!='$' ){ zErr = zRoot; }else{ pNode = jsonLookupStep(&p->sParse, 0, p->zRoot+1, 0, &zErr); } if( zErr ){ sqlite3_free(cur->pVtab->zErrMsg); cur->pVtab->zErrMsg = jsonPathSyntaxError(zErr); jsonEachCursorReset(p); return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; }else if( pNode==0 ){ return SQLITE_OK; } }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--; } }else{ p->i++; } }else{ p->iEnd = p->i+1; } } return SQLITE_OK; } /* The methods of the json_each virtual table */ static sqlite3_module jsonEachModule = { 0, /* iVersion */ 0, /* xCreate */ jsonEachConnect, /* xConnect */ jsonEachBestIndex, /* xBestIndex */ jsonEachDisconnect, /* xDisconnect */ 0, /* xDestroy */ jsonEachOpenEach, /* xOpen - open a cursor */ jsonEachClose, /* xClose - close a cursor */ jsonEachFilter, /* xFilter - configure scan constraints */ jsonEachNext, /* xNext - advance a cursor */ jsonEachEof, /* xEof - check for end of scan */ jsonEachColumn, /* xColumn - read data */ jsonEachRowid, /* 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 */ }; /* The methods of the json_tree virtual table. */ static sqlite3_module jsonTreeModule = { 0, /* iVersion */ 0, /* xCreate */ jsonEachConnect, /* xConnect */ jsonEachBestIndex, /* xBestIndex */ jsonEachDisconnect, /* xDisconnect */ 0, /* xDestroy */ jsonEachOpenTree, /* xOpen - open a cursor */ jsonEachClose, /* xClose - close a cursor */ jsonEachFilter, /* xFilter - configure scan constraints */ jsonEachNext, /* xNext - advance a cursor */ jsonEachEof, /* xEof - check for end of scan */ jsonEachColumn, /* xColumn - read data */ jsonEachRowid, /* 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 */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ /**************************************************************************** ** The following routines are the only publically visible identifiers in this ** file. Call the following routines in order to register the various SQL ** functions and the virtual table implemented by this file. ****************************************************************************/ int sqlite3Json1Init(sqlite3 *db){ int rc = SQLITE_OK; unsigned int i; static const struct { const char *zName; int nArg; int flag; void (*xFunc)(sqlite3_context*,int,sqlite3_value**); } aFunc[] = { { "json", 1, 0, jsonRemoveFunc }, { "json_array", -1, 0, jsonArrayFunc }, { "json_array_length", 1, 0, jsonArrayLengthFunc }, { "json_array_length", 2, 0, jsonArrayLengthFunc }, { "json_extract", -1, 0, jsonExtractFunc }, { "json_insert", -1, 0, jsonSetFunc }, { "json_object", -1, 0, jsonObjectFunc }, { "json_patch", 2, 0, jsonPatchFunc }, { "json_quote", 1, 0, jsonQuoteFunc }, { "json_remove", -1, 0, jsonRemoveFunc }, { "json_replace", -1, 0, jsonReplaceFunc }, { "json_set", -1, 1, jsonSetFunc }, { "json_type", 1, 0, jsonTypeFunc }, { "json_type", 2, 0, jsonTypeFunc }, { "json_valid", 1, 0, jsonValidFunc }, #if SQLITE_DEBUG /* DEBUG and TESTING functions */ { "json_parse", 1, 0, jsonParseFunc }, { "json_test1", 1, 0, jsonTest1Func }, #endif }; static const struct { const char *zName; int nArg; void (*xStep)(sqlite3_context*,int,sqlite3_value**); void (*xFinal)(sqlite3_context*); void (*xValue)(sqlite3_context*); } aAgg[] = { { "json_group_array", 1, jsonArrayStep, jsonArrayFinal, jsonArrayValue }, { "json_group_object", 2, jsonObjectStep, jsonObjectFinal, jsonObjectValue }, }; #ifndef SQLITE_OMIT_VIRTUALTABLE static const struct { const char *zName; sqlite3_module *pModule; } aMod[] = { { "json_each", &jsonEachModule }, { "json_tree", &jsonTreeModule }, }; #endif for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){ rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg, SQLITE_UTF8 | SQLITE_DETERMINISTIC, (void*)&aFunc[i].flag, aFunc[i].xFunc, 0, 0); } #ifndef SQLITE_OMIT_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_UTF8 | SQLITE_DETERMINISTIC, 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); } #endif return rc; } #ifndef SQLITE_CORE #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_json_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ return sqlite3Json1Init(db); } #endif #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1) */ |
Changes to ext/misc/memvfs.c.
︙ | ︙ | |||
555 556 557 558 559 560 561 | sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); mem_vfs.pAppData = sqlite3_vfs_find(0); | < | 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 ){ |
︙ | ︙ |
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_master", (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 */ |
︙ | ︙ |
Changes to ext/misc/nextchar.c.
︙ | ︙ | |||
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 | sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ rc = sqlite3_create_function(db, "next_char", 3, SQLITE_UTF8, 0, nextCharFunc, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "next_char", 4, SQLITE_UTF8, 0, nextCharFunc, 0, 0); } if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "next_char", 5, SQLITE_UTF8, 0, nextCharFunc, 0, 0); } return rc; } |
Deleted ext/misc/noop.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to ext/misc/normalize.c.
︙ | ︙ | |||
282 283 284 285 286 287 288 | #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 | < < < < < < < | 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 |
︙ | ︙ | |||
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 */ | < | 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; } |
︙ | ︙ | |||
532 533 534 535 536 537 538 | 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 */ | < | 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; |
︙ | ︙ |
Changes to ext/misc/percentile.c.
︙ | ︙ | |||
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 | 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, 0, 0, percentStep, percentFinal); return rc; } |
Changes to ext/misc/prefixes.c.
︙ | ︙ | |||
75 76 77 78 79 80 81 | "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)); | < | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | "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)); } return rc; } /* ** This method is the destructor for prefixes_vtab objects. */ |
︙ | ︙ |
Deleted ext/misc/qpvtab.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to ext/misc/regexp.c.
︙ | ︙ | |||
68 69 70 71 72 73 74 | */ #define re_match sqlite3re_match #define re_compile sqlite3re_compile #define re_free sqlite3re_free /* The end-of-input character */ #define RE_EOF 0 /* End of input */ | < | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | */ #define re_match sqlite3re_match #define re_compile sqlite3re_compile #define re_free sqlite3re_free /* The end-of-input character */ #define RE_EOF 0 /* End of input */ /* The NFA is implemented as sequence of opcodes taken from the following ** set. Each opcode has a single integer argument. */ #define RE_OP_MATCH 1 /* Match the one character in the argument */ #define RE_OP_ANY 2 /* Match any one character. (Implements ".") */ #define RE_OP_ANYSTAR 3 /* Special optimized version of .* */ |
︙ | ︙ | |||
90 91 92 93 94 95 96 | #define RE_OP_WORD 11 /* Perl word character [A-Za-z0-9_] */ #define RE_OP_NOTWORD 12 /* Not a perl word character */ #define RE_OP_DIGIT 13 /* digit: [0-9] */ #define RE_OP_NOTDIGIT 14 /* Not a digit */ #define RE_OP_SPACE 15 /* space: [ \t\n\r\v\f] */ #define RE_OP_NOTSPACE 16 /* Not a digit */ #define RE_OP_BOUNDARY 17 /* Boundary between word and non-word */ | < < < < < < < < < < < < < < < < < < < < < < < < < < < | 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | #define RE_OP_WORD 11 /* Perl word character [A-Za-z0-9_] */ #define RE_OP_NOTWORD 12 /* Not a perl word character */ #define RE_OP_DIGIT 13 /* digit: [0-9] */ #define RE_OP_NOTDIGIT 14 /* Not a digit */ #define RE_OP_SPACE 15 /* space: [ \t\n\r\v\f] */ #define RE_OP_NOTSPACE 16 /* Not a digit */ #define RE_OP_BOUNDARY 17 /* Boundary between word and non-word */ /* Each opcode is a "state" in the NFA */ typedef unsigned short ReStateNumber; /* Because this is an NFA and not a DFA, multiple states can be active at ** once. An instance of the following object records all active states in ** the NFA. The implementation is optimized for the common case where the |
︙ | ︙ | |||
151 152 153 154 155 156 157 | struct ReCompiled { ReInput sIn; /* Regular expression text */ const char *zErr; /* Error message to return */ char *aOp; /* Operators for the virtual machine */ int *aArg; /* Arguments to each operator */ unsigned (*xNextChar)(ReInput*); /* Next character function */ unsigned char zInit[12]; /* Initial text to match */ | | | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | struct ReCompiled { ReInput sIn; /* Regular expression text */ const char *zErr; /* Error message to return */ char *aOp; /* Operators for the virtual machine */ int *aArg; /* Arguments to each operator */ unsigned (*xNextChar)(ReInput*); /* Next character function */ unsigned char zInit[12]; /* Initial text to match */ int nInit; /* Number of characters in zInit */ unsigned nState; /* Number of entries in aOp[] and aArg[] */ unsigned nAlloc; /* Slots allocated for aOp[] and aArg[] */ }; /* Add a state to the given state set if it is not already there */ static void re_add_state(ReStateSet *pSet, int newState){ unsigned i; |
︙ | ︙ | |||
180 181 182 183 184 185 186 | 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 167 | 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<=0x3ff || (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{ c = 0xfffd; |
︙ | ︙ | |||
224 225 226 227 228 229 230 | */ static int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){ ReStateSet aStateSet[2], *pThis, *pNext; ReStateNumber aSpace[100]; ReStateNumber *pToFree; unsigned int i = 0; unsigned int iSwap = 0; | | < | 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 | */ static int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){ ReStateSet aStateSet[2], *pThis, *pNext; ReStateNumber aSpace[100]; ReStateNumber *pToFree; unsigned int i = 0; unsigned int iSwap = 0; int c = RE_EOF+1; int cPrev = 0; int rc = 0; ReInput in; in.z = zIn; in.i = 0; in.mx = nIn>=0 ? nIn : (int)strlen((char const*)zIn); /* Look for the initial prefix match, if there is one. */ if( pRe->nInit ){ unsigned char x = pRe->zInit[0]; while( in.i+pRe->nInit<=in.mx && (zIn[in.i]!=x || strncmp((const char*)zIn+in.i, (const char*)pRe->zInit, pRe->nInit)!=0) ){ in.i++; } 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 ); |
︙ | ︙ | |||
272 273 274 275 276 277 278 | for(i=0; i<pThis->nState; i++){ 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; } | < < < < | | | | | 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 | for(i=0; i<pThis->nState; i++){ 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: { 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) ) 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) ) 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) ) 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: { |
︙ | ︙ | |||
326 327 328 329 330 331 332 | 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 | re_add_state(pThis, x+pRe->aArg[x]); break; } case RE_OP_ACCEPT: { rc = 1; goto re_match_end; } case RE_OP_CC_INC: case RE_OP_CC_EXC: { 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. |
︙ | ︙ | |||
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 | int iStart; unsigned c; const char *zErr; while( (c = p->xNextChar(&p->sIn))!=0 ){ iStart = p->nState; switch( c ){ 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++; | > | < < < < < < < < < | 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 | 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); re_append(p, RE_OP_FORK, iPrev - p->nState + 1); break; } case '+': { if( iPrev<0 ) return "'+' without operand"; re_append(p, RE_OP_FORK, iPrev - p->nState); break; } case '?': { if( iPrev<0 ) return "'?' without operand"; re_insert(p, iPrev, RE_OP_FORK, p->nState - iPrev+1); break; } case '{': { int m = 0, n = 0; int sz, j; if( iPrev<0 ) return "'{m,n}' without operand"; while( (c=rePeek(p))>='0' && c<='9' ){ m = m*10 + c - '0'; p->sIn.i++; } n = m; if( c==',' ){ p->sIn.i++; n = 0; while( (c=rePeek(p))>='0' && c<='9' ){ n = n*10 + c-'0'; p->sIn.i++; } } if( c!='}' ) return "unmatched '{'"; if( n>0 && n<m ) return "n less than m in '{m,n}'"; p->sIn.i++; sz = p->nState - iPrev; if( m==0 ){ if( n==0 ) return "both m and n are zero in '{m,n}'"; re_insert(p, iPrev, RE_OP_FORK, sz+1); n--; }else{ for(j=1; j<m; j++) re_copy(p, iPrev, sz); } for(j=m; j<n; j++){ re_append(p, RE_OP_FORK, sz+1); re_copy(p, iPrev, sz); |
︙ | ︙ | |||
652 653 654 655 656 657 658 | 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. */ | | | | 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 | 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. */ 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. */ 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 ){ |
︙ | ︙ | |||
695 696 697 698 699 700 701 | pRe->sIn.i = 0; pRe->sIn.mx = (int)strlen(zIn); zErr = re_subcompile_re(pRe); if( zErr ){ re_free(pRe); return zErr; } | > > > > | | | | | | | | 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 | pRe->sIn.i = 0; pRe->sIn.mx = (int)strlen(zIn); zErr = re_subcompile_re(pRe); if( zErr ){ re_free(pRe); return zErr; } if( rePeek(pRe)=='$' && pRe->sIn.i+1>=pRe->sIn.mx ){ re_append(pRe, RE_OP_MATCH, RE_EOF); re_append(pRe, RE_OP_ACCEPT, 0); *ppRe = pRe; }else if( pRe->sIn.i>=pRe->sIn.mx ){ re_append(pRe, RE_OP_ACCEPT, 0); *ppRe = pRe; }else{ re_free(pRe); return "unrecognized character"; } /* The following is a performance optimization. If the regex begins with ** ".*" (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 ){ for(j=0, i=1; j<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 ){ pRe->zInit[j++] = (unsigned char)(0xd0 | (x>>12)); pRe->zInit[j++] = 0x80 | ((x>>6)&0x3f); pRe->zInit[j++] = 0x80 | (x&0x3f); }else{ break; } } if( j>0 && pRe->zInit[j-1]==0 ) j--; |
︙ | ︙ | |||
743 744 745 746 747 748 749 | ** 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( | | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < < < < < < < < < < < < < < | 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 | ** 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() */ 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, 0); if( zErr ){ re_free(pRe); sqlite3_result_error(context, zErr, -1); return; } if( pRe==0 ){ sqlite3_result_error_nomem(context); return; } setAux = 1; } zStr = (const unsigned char*)sqlite3_value_text(argv[1]); if( zStr!=0 ){ sqlite3_result_int(context, re_match(pRe, zStr, -1)); } if( setAux ){ sqlite3_set_auxdata(context, 0, pRe, (void(*)(void*))re_free); } } /* ** Invoke this routine to register the regexp() function with the ** SQLite database connection. */ #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_regexp_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); rc = sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, 0, re_sql_func, 0, 0); return rc; } |
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 | 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, 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_master; 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_master 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 | ** (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 *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ 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 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)); } 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 *p, sqlite3_vtab_cursor **ppCursor){ series_cursor *pCur; pCur = sqlite3_malloc( sizeof(*pCur) ); if( pCur==0 ) return SQLITE_NOMEM; memset(pCur, 0, sizeof(*pCur)); *ppCursor = &pCur->base; return SQLITE_OK; } |
︙ | ︙ | |||
243 244 245 246 247 248 249 | ** 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 | | < | < | < < < < < | 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 | ** 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. ** ** 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 *idxStr, int argc, sqlite3_value **argv ){ series_cursor *pCur = (series_cursor *)pVtabCursor; int i = 0; 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<1 ) pCur->iStep = 1; }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 */ |
︙ | ︙ | |||
319 320 321 322 323 324 325 | ** ** (1) start = $value -- constraint exists ** (2) stop = $value -- constraint exists ** (4) step = $value -- constraint exists ** (8) output in descending order */ static int seriesBestIndex( | | < < < < < < < < < < < < < < < | | < < < < | 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 | ** ** (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 *tab, sqlite3_index_info *pIdxInfo ){ int i, j; /* Loop over constraints */ int idxNum = 0; /* The query plan bitmask */ 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( 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; } } 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; 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; |
︙ | ︙ | |||
425 426 427 428 429 430 431 | 0, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ | < < < < | | 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 | 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 if( sqlite3_libversion_number()<3008012 ){ *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 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)) | > > > > > > > > > > > > > > > > | 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 | typedef struct SHA1Context SHA1Context; struct SHA1Context { unsigned int state[5]; unsigned int count[2]; unsigned char buffer[64]; }; #if __GNUC__ && (defined(__i386__) || defined(__x86_64__)) /* * GCC by itself only generates left rotates. Use right rotates if * possible to be kinder to dinky implementations with iterative rotate * instructions. */ #define SHA_ROT(op, x, k) \ ({ unsigned int y; asm(op " %1,%0" : "=r" (y) : "I" (k), "0" (x)); y; }) #define rol(x,k) SHA_ROT("roll", x, k) #define ror(x,k) SHA_ROT("rorl", x, k) #else /* Generic C equivalent */ #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) #endif #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)) |
︙ | ︙ | |||
67 68 69 70 71 72 73 | z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=ror(w,2); #define R4(v,w,x,y,z,i) \ z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=ror(w,2); /* * Hash a single 512-bit block. This is the core of the algorithm. */ | | | 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=ror(w,2); #define R4(v,w,x,y,z,i) \ z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=ror(w,2); /* * Hash a single 512-bit block. This is the core of the algorithm. */ void SHA1Transform(unsigned int state[5], const unsigned char buffer[64]){ unsigned int qq[5]; /* a, b, c, d, e; */ static int one = 1; unsigned int block[16]; memcpy(block, buffer, 64); memcpy(qq,state,5*sizeof(unsigned int)); #define a qq[0] |
︙ | ︙ | |||
377 378 379 380 381 382 383 | sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ | | < | | < | 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 | 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, 0, sha1Func, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "sha1_query", 1, SQLITE_UTF8, 0, sha1QueryFunc, 0, 0); } return rc; } |
Changes to ext/misc/shathree.c.
︙ | ︙ | |||
15 16 17 18 19 20 21 | ** ** sha3(X,SIZE) ** sha3_query(Y,SIZE) ** ** The sha3(X) function computes the SHA3 hash of the input X, or NULL if ** X 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 | ** ** sha3(X,SIZE) ** sha3_query(Y,SIZE) ** ** The sha3(X) function computes the SHA3 hash of the input X, or NULL if ** X is NULL. ** ** The sha3_query(Y) function evalutes all queries in the SQL statements of Y ** and returns a hash of their results. ** ** The SIZE argument is optional. If omitted, the SHA3-256 hash algorithm ** is used. If SIZE is included it must be one of the integers 224, 256, ** 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. |
︙ | ︙ | |||
432 433 434 435 436 437 438 | */ static void SHA3Update( SHA3Context *p, const unsigned char *aData, unsigned int nData ){ unsigned int i = 0; | < | 429 430 431 432 433 434 435 436 437 438 439 440 441 442 | */ static void SHA3Update( SHA3Context *p, const unsigned char *aData, unsigned int nData ){ unsigned int i = 0; #if SHA3_BYTEORDER==1234 if( (p->nLoaded % 8)==0 && ((aData - (const unsigned char*)0)&7)==0 ){ for(; i+7<nData; i+=8){ p->u.s[p->nLoaded/8] ^= *(u64*)&aData[i]; p->nLoaded += 8; if( p->nLoaded>=p->nRate ){ KeccakF1600Step(p); |
︙ | ︙ | |||
527 528 529 530 531 532 533 | } sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT); } /* Compute a string using sqlite3_vsnprintf() with a maximum length ** of 50 bytes and add it to the hash. */ | | | 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 | } sqlite3_result_blob(context, SHA3Final(&cx), iSize/8, SQLITE_TRANSIENT); } /* Compute a string using sqlite3_vsnprintf() with a maximum length ** of 50 bytes and add it to the hash. */ static void hash_step_vformat( SHA3Context *p, /* Add content to this context */ const char *zFormat, ... ){ va_list ap; int n; char zBuf[50]; |
︙ | ︙ | |||
621 622 623 624 625 626 627 | sqlite3_finalize(pStmt); sqlite3_result_error(context, zMsg, -1); sqlite3_free(zMsg); return; } nCol = sqlite3_column_count(pStmt); z = sqlite3_sql(pStmt); | < | | | < | 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 | sqlite3_finalize(pStmt); sqlite3_result_error(context, zMsg, -1); sqlite3_free(zMsg); return; } nCol = sqlite3_column_count(pStmt); z = sqlite3_sql(pStmt); 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: { |
︙ | ︙ | |||
667 668 669 670 671 672 673 | x[0] = 'F'; SHA3Update(&cx,x,9); break; } case SQLITE_TEXT: { int n2 = sqlite3_column_bytes(pStmt, i); const unsigned char *z2 = sqlite3_column_text(pStmt, i); | | | | 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 | x[0] = 'F'; SHA3Update(&cx,x,9); break; } case SQLITE_TEXT: { int n2 = sqlite3_column_bytes(pStmt, i); const unsigned char *z2 = sqlite3_column_text(pStmt, i); hash_step_vformat(&cx,"T%d:",n2); SHA3Update(&cx, z2, n2); break; } case SQLITE_BLOB: { int n2 = sqlite3_column_bytes(pStmt, i); const unsigned char *z2 = sqlite3_column_blob(pStmt, i); hash_step_vformat(&cx,"B%d:",n2); SHA3Update(&cx, z2, n2); break; } } } } sqlite3_finalize(pStmt); |
︙ | ︙ | |||
698 699 700 701 702 703 704 | sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ | | < | | < | | < | | < | | 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 | 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, 0, sha3Func, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "sha3", 2, SQLITE_UTF8, 0, sha3Func, 0, 0); } if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "sha3_query", 1, SQLITE_UTF8, 0, sha3QueryFunc, 0, 0); } if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "sha3_query", 2, SQLITE_UTF8, 0, sha3QueryFunc, 0, 0); } return rc; } |
Changes to ext/misc/spellfix.c.
︙ | ︙ | |||
2065 2066 2067 2068 2069 2070 2071 | 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{ | < | 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 |
︙ | ︙ |
Changes to ext/misc/sqlar.c.
︙ | ︙ | |||
13 14 15 16 17 18 19 | ** 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> | < | 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. |
︙ | ︙ | |||
87 88 89 90 91 92 93 | 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); | < < | > | < | < | 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 | sz = sqlite3_value_int(argv[1]); if( sz<=0 || sz==(nData = sqlite3_value_bytes(argv[0])) ){ sqlite3_result_value(context, argv[0]); }else{ const Bytef *pData= sqlite3_value_blob(argv[0]); Bytef *pOut = sqlite3_malloc(sz); if( Z_OK!=uncompress(pOut, &sz, pData, nData) ){ sqlite3_result_error(context, "error in uncompress()", -1); }else{ sqlite3_result_blob(context, pOut, sz, SQLITE_TRANSIENT); } sqlite3_free(pOut); } } #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_sqlar_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ rc = sqlite3_create_function(db, "sqlar_compress", 1, SQLITE_UTF8, 0, sqlarCompressFunc, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "sqlar_uncompress", 2, SQLITE_UTF8, 0, sqlarUncompressFunc, 0, 0); } return rc; } |
Changes to ext/misc/stmt.c.
︙ | ︙ | |||
26 27 28 29 30 31 32 | #endif SQLITE_EXTENSION_INIT1 #include <assert.h> #include <string.h> #ifndef SQLITE_OMIT_VIRTUALTABLE | < < < < < < < < < < > | | 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 | #endif SQLITE_EXTENSION_INIT1 #include <assert.h> #include <string.h> #ifndef SQLITE_OMIT_VIRTUALTABLE /* stmt_vtab is a subclass of sqlite3_vtab which will ** serve as the underlying representation of a stmt virtual table */ typedef struct stmt_vtab stmt_vtab; struct stmt_vtab { sqlite3_vtab base; /* Base class - must be first */ sqlite3 *db; /* Database connection for this stmt vtab */ }; /* stmt_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 stmt_cursor stmt_cursor; struct stmt_cursor { sqlite3_vtab_cursor base; /* Base class - must be first */ sqlite3 *db; /* Database connection for this cursor */ sqlite3_stmt *pStmt; /* Statement cursor is currently pointing at */ sqlite3_int64 iRowid; /* The rowid */ }; /* ** The stmtConnect() method is invoked to create a new ** stmt_vtab that describes the stmt virtual table. ** ** Think of this routine as the constructor for stmt_vtab objects. |
︙ | ︙ | |||
93 94 95 96 97 98 99 | #define STMT_COLUMN_NAIDX 6 /* SQLITE_STMTSTATUS_AUTOINDEX */ #define STMT_COLUMN_NSTEP 7 /* SQLITE_STMTSTATUS_VM_STEP */ #define STMT_COLUMN_REPREP 8 /* SQLITE_STMTSTATUS_REPREPARE */ #define STMT_COLUMN_RUN 9 /* SQLITE_STMTSTATUS_RUN */ #define STMT_COLUMN_MEM 10 /* SQLITE_STMTSTATUS_MEMUSED */ | < < < < | | 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | #define STMT_COLUMN_NAIDX 6 /* SQLITE_STMTSTATUS_AUTOINDEX */ #define STMT_COLUMN_NSTEP 7 /* SQLITE_STMTSTATUS_VM_STEP */ #define STMT_COLUMN_REPREP 8 /* SQLITE_STMTSTATUS_REPREPARE */ #define STMT_COLUMN_RUN 9 /* SQLITE_STMTSTATUS_RUN */ #define STMT_COLUMN_MEM 10 /* SQLITE_STMTSTATUS_MEMUSED */ rc = sqlite3_declare_vtab(db, "CREATE TABLE x(sql,ncol,ro,busy,nscan,nsort,naidx,nstep," "reprep,run,mem)"); 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; } return rc; } |
︙ | ︙ | |||
123 124 125 126 127 128 129 | } /* ** Constructor for a new stmt_cursor object. */ static int stmtOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ stmt_cursor *pCur; | | < < < < < < < < < < < < | | | | | | > > > > > > > > > > | > > > > > > > > > > > > > > > > > | | < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | < < | 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 | } /* ** Constructor for a new stmt_cursor object. */ static int stmtOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ stmt_cursor *pCur; pCur = sqlite3_malloc( sizeof(*pCur) ); if( pCur==0 ) return SQLITE_NOMEM; memset(pCur, 0, sizeof(*pCur)); pCur->db = ((stmt_vtab*)p)->db; *ppCursor = &pCur->base; return SQLITE_OK; } /* ** Destructor for a stmt_cursor. */ static int stmtClose(sqlite3_vtab_cursor *cur){ sqlite3_free(cur); return SQLITE_OK; } /* ** Advance a stmt_cursor to its next row of output. */ static int stmtNext(sqlite3_vtab_cursor *cur){ stmt_cursor *pCur = (stmt_cursor*)cur; pCur->iRowid++; pCur->pStmt = sqlite3_next_stmt(pCur->db, pCur->pStmt); return SQLITE_OK; } /* ** Return values of columns for the row at which the stmt_cursor ** is currently pointing. */ static int stmtColumn( sqlite3_vtab_cursor *cur, /* The cursor */ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ int i /* Which column to return */ ){ stmt_cursor *pCur = (stmt_cursor*)cur; switch( i ){ case STMT_COLUMN_SQL: { sqlite3_result_text(ctx, sqlite3_sql(pCur->pStmt), -1, SQLITE_TRANSIENT); break; } case STMT_COLUMN_NCOL: { sqlite3_result_int(ctx, sqlite3_column_count(pCur->pStmt)); break; } case STMT_COLUMN_RO: { sqlite3_result_int(ctx, sqlite3_stmt_readonly(pCur->pStmt)); break; } case STMT_COLUMN_BUSY: { sqlite3_result_int(ctx, sqlite3_stmt_busy(pCur->pStmt)); break; } case 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: case STMT_COLUMN_NSTEP: case STMT_COLUMN_REPREP: case STMT_COLUMN_RUN: { sqlite3_result_int(ctx, sqlite3_stmt_status(pCur->pStmt, i-STMT_COLUMN_NSCAN+SQLITE_STMTSTATUS_FULLSCAN_STEP, 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 stmtRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ stmt_cursor *pCur = (stmt_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 stmtEof(sqlite3_vtab_cursor *cur){ stmt_cursor *pCur = (stmt_cursor*)cur; return pCur->pStmt==0; } /* ** This method is called to "rewind" the stmt_cursor object back ** to the first row of output. This method is always called at least ** once prior to any call to stmtColumn() or stmtRowid() or ** stmtEof(). */ static int stmtFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ stmt_cursor *pCur = (stmt_cursor *)pVtabCursor; pCur->pStmt = 0; pCur->iRowid = 0; return stmtNext(pVtabCursor); } /* ** SQLite will invoke this method one or more times while planning a query ** that uses the stmt virtual table. This routine needs to create ** a query plan for each invocation and compute an estimated cost for that ** plan. */ static int stmtBestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo ){ pIdxInfo->estimatedCost = (double)500; pIdxInfo->estimatedRows = 500; return SQLITE_OK; } /* ** This following structure defines all the methods for the |
︙ | ︙ |
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 | 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, 0, tointegerFunc, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "toreal", 1, SQLITE_UTF8, 0, torealFunc, 0, 0); } return rc; } |
Deleted ext/misc/uint.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/misc/urifuncs.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/misc/uuid.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to ext/misc/vfslog.c.
︙ | ︙ | |||
750 751 752 753 754 755 756 | } /* ** Register debugvfs as the default VFS for this process. */ int sqlite3_register_vfslog(const char *zArg){ vlog_vfs.pVfs = sqlite3_vfs_find(0); | < | 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); } |
Changes to ext/misc/vfsstat.c.
︙ | ︙ | |||
802 803 804 805 806 807 808 | sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); vstat_vfs.pVfs = sqlite3_vfs_find(0); | < | | 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 | 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 ){ rc = vstatRegister(db, pzErrMsg, pApi); if( rc==SQLITE_OK ){ rc = sqlite3_auto_extension(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 | 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)"); | < | 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){ |
︙ | ︙ | |||
216 217 218 219 220 221 222 | } if( pIdxInfo->nOrderBy==1 && pIdxInfo->aOrderBy[0].desc==0 ){ pIdxInfo->orderByConsumed = 1; } if( (idxNum & 12)==0 ){ | | | 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | } if( pIdxInfo->nOrderBy==1 && pIdxInfo->aOrderBy[0].desc==0 ){ pIdxInfo->orderByConsumed = 1; } if( (idxNum & 12)==0 ){ pIdxInfo->estimatedCost = (double)100000000; }else if( (idxNum & 3)==0 ){ pIdxInfo->estimatedCost = (double)5; }else{ pIdxInfo->estimatedCost = (double)1; } return SQLITE_OK; } |
︙ | ︙ |
Changes to ext/misc/zipfile.c.
︙ | ︙ | |||
32 33 34 35 36 37 38 | #include <zlib.h> #ifndef SQLITE_OMIT_VIRTUALTABLE #ifndef SQLITE_AMALGAMATION | < < < < < < < < < < < < < < | | < < < | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | #include <zlib.h> #ifndef SQLITE_OMIT_VIRTUALTABLE #ifndef SQLITE_AMALGAMATION typedef sqlite3_int64 i64; typedef unsigned char u8; typedef unsigned short u16; typedef unsigned long u32; #define MIN(a,b) ((a)<(b) ? (a) : (b)) #if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) # 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) |
︙ | ︙ | |||
348 349 350 351 352 353 354 | char **pzErr ){ int nByte = sizeof(ZipfileTab) + ZIPFILE_BUFFER_SIZE; int nFile = 0; const char *zFile = 0; ZipfileTab *pNew = 0; int rc; | < | 331 332 333 334 335 336 337 338 339 340 341 342 343 344 | char **pzErr ){ int nByte = sizeof(ZipfileTab) + ZIPFILE_BUFFER_SIZE; int nFile = 0; const char *zFile = 0; ZipfileTab *pNew = 0; int rc; /* If the table name is not "zipfile", require that the argument be ** specified. This stops zipfile tables from being created as: ** ** CREATE VIRTUAL TABLE zzz USING zipfile(); ** ** It does not prevent: |
︙ | ︙ | |||
383 384 385 386 387 388 389 | pNew->aBuffer = (u8*)&pNew[1]; if( zFile ){ pNew->zFile = (char*)&pNew->aBuffer[ZIPFILE_BUFFER_SIZE]; memcpy(pNew->zFile, zFile, nFile); zipfileDequote(pNew->zFile); } } | < | 365 366 367 368 369 370 371 372 373 374 375 376 377 378 | pNew->aBuffer = (u8*)&pNew[1]; if( zFile ){ pNew->zFile = (char*)&pNew->aBuffer[ZIPFILE_BUFFER_SIZE]; memcpy(pNew->zFile, zFile, nFile); zipfileDequote(pNew->zFile); } } *ppVtab = (sqlite3_vtab*)pNew; return rc; } /* ** Free the ZipfileEntry structure indicated by the only argument. */ |
︙ | ︙ | |||
537 538 539 540 541 542 543 | } static int zipfileAppendData( ZipfileTab *pTab, const u8 *aWrite, int nWrite ){ | < | | | | | | | | < < | 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 | } static int zipfileAppendData( ZipfileTab *pTab, const u8 *aWrite, int nWrite ){ size_t n; fseek(pTab->pWriteFd, (long)pTab->szCurrent, SEEK_SET); n = fwrite(aWrite, 1, nWrite, pTab->pWriteFd); if( (int)n!=nWrite ){ pTab->base.zErrMsg = sqlite3_mprintf("error in fwrite()"); return SQLITE_ERROR; } pTab->szCurrent += nWrite; return SQLITE_OK; } /* ** 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){ return ((u32)(aBuf[3]) << 24) + ((u32)(aBuf[2]) << 16) + ((u32)(aBuf[1]) << 8) + ((u32)(aBuf[0]) << 0); } /* |
︙ | ︙ | |||
721 722 723 724 725 726 727 | ** 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){ | < < | | | > > | | | > > > > > | | | > | | > > | > > | < > | | 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 | ** 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 = (1980 + ((pCDS->mDate >> 9) & 0x7F)); int M = ((pCDS->mDate >> 5) & 0x0F); int D = (pCDS->mDate & 0x1F); int B = -13; int sec = (pCDS->mTime & 0x1F)*2; int min = (pCDS->mTime >> 5) & 0x3F; int hr = (pCDS->mTime >> 11) & 0x1F; i64 JD; /* JD = INT(365.25 * (Y+4716)) + INT(30.6001 * (M+1)) + D + B - 1524.5 */ /* Calculate the JD in seconds for noon on the day in question */ if( M<3 ){ Y = Y-1; M = M+12; } JD = (i64)(24*60*60) * ( (int)(365.25 * (Y + 4716)) + (int)(30.6001 * (M + 1)) + D + B - 1524 ); /* Correct the JD for the time within the day */ JD += (hr-12) * 3600 + min * 60 + sec; /* Convert JD to unix timestamp (the JD epoch is 2440587.5) */ return (u32)(JD - (i64)(24405875) * 24*60*6); } /* ** 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. */ |
︙ | ︙ | |||
805 806 807 808 809 810 811 | FILE *pFile, /* If aBlob==0, read from this file */ i64 iOff, /* Offset of CDS record */ ZipfileEntry **ppEntry /* OUT: Pointer to new object */ ){ u8 *aRead; char **pzErr = &pTab->base.zErrMsg; int rc = SQLITE_OK; | < | 793 794 795 796 797 798 799 800 801 802 803 804 805 806 | FILE *pFile, /* If aBlob==0, read from this file */ i64 iOff, /* Offset of CDS record */ ZipfileEntry **ppEntry /* OUT: Pointer to new object */ ){ u8 *aRead; char **pzErr = &pTab->base.zErrMsg; int rc = SQLITE_OK; if( aBlob==0 ){ aRead = pTab->aBuffer; rc = zipfileReadData(pFile, aRead, ZIPFILE_CDS_FIXED_SZ, iOff, pzErr); }else{ aRead = (u8*)&aBlob[iOff]; } |
︙ | ︙ | |||
865 866 867 868 869 870 871 | ZipfileLFH lfh; if( pFile ){ rc = zipfileReadData(pFile, aRead, szFix, pNew->cds.iOffset, pzErr); }else{ aRead = (u8*)&aBlob[pNew->cds.iOffset]; } | | | 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 | ZipfileLFH lfh; if( pFile ){ rc = zipfileReadData(pFile, aRead, szFix, pNew->cds.iOffset, pzErr); }else{ aRead = (u8*)&aBlob[pNew->cds.iOffset]; } 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); } |
︙ | ︙ | |||
990 991 992 993 994 995 996 | ** case. */ static int zipfileDeflate( const u8 *aIn, int nIn, /* Input */ u8 **ppOut, int *pnOut, /* Output */ char **pzErr /* OUT: Error message */ ){ | < | < | < < < < < > > > > > > > | 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 | ** case. */ static int zipfileDeflate( const u8 *aIn, int nIn, /* Input */ u8 **ppOut, int *pnOut, /* Output */ char **pzErr /* OUT: Error message */ ){ sqlite3_int64 nAlloc = compressBound(nIn); u8 *aOut; int rc = SQLITE_OK; aOut = (u8*)sqlite3_malloc64(nAlloc); if( aOut==0 ){ rc = SQLITE_NOMEM; }else{ int res; z_stream str; memset(&str, 0, sizeof(str)); str.next_in = (Bytef*)aIn; str.avail_in = nIn; str.next_out = aOut; str.avail_out = nAlloc; deflateInit2(&str, 9, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); res = deflate(&str, Z_FINISH); if( res==Z_STREAM_END ){ *ppOut = aOut; *pnOut = (int)str.total_out; }else{ sqlite3_free(aOut); *pzErr = sqlite3_mprintf("zipfile: deflate() error"); rc = SQLITE_ERROR; |
︙ | ︙ | |||
1141 1142 1143 1144 1145 1146 1147 | 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; | < > | 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 | 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 ){ memset(pEOCD, 0, sizeof(ZipfileEOCD)); return SQLITE_OK; } nRead = (int)(MIN(szFile, ZIPFILE_BUFFER_SIZE)); iOff = szFile - nRead; rc = zipfileReadData(pFile, aRead, nRead, iOff, &pTab->base.zErrMsg); }else{ nRead = (int)(MIN(nBlob, ZIPFILE_BUFFER_SIZE)); |
︙ | ︙ | |||
1252 1253 1254 1255 1256 1257 1258 | ){ ZipfileTab *pTab = (ZipfileTab*)cur->pVtab; ZipfileCsr *pCsr = (ZipfileCsr*)cur; const char *zFile = 0; /* Zip file to scan */ int rc = SQLITE_OK; /* Return Code */ int bInMemory = 0; /* True for an in-memory zipfile */ | < < < < < < < < | | 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 | ){ ZipfileTab *pTab = (ZipfileTab*)cur->pVtab; ZipfileCsr *pCsr = (ZipfileCsr*)cur; const char *zFile = 0; /* Zip file to scan */ int rc = SQLITE_OK; /* Return Code */ int bInMemory = 0; /* True for an in-memory zipfile */ zipfileResetCursor(pCsr); if( pTab->zFile ){ zFile = pTab->zFile; }else if( idxNum==0 ){ zipfileCursorErr(pCsr, "zipfile() function requires an argument"); return SQLITE_ERROR; }else if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){ const u8 *aBlob = (const u8*)sqlite3_value_blob(argv[0]); int nBlob = sqlite3_value_bytes(argv[0]); assert( pTab->pFirstEntry==0 ); rc = zipfileLoadDirectory(pTab, aBlob, nBlob); pCsr->pFreeEntry = pTab->pFirstEntry; pTab->pFirstEntry = pTab->pLastEntry = 0; if( rc!=SQLITE_OK ) return rc; bInMemory = 1; }else{ zFile = (const char*)sqlite3_value_text(argv[0]); } if( 0==pTab->pWriteFd && 0==bInMemory ){ pCsr->pFile = fopen(zFile, "rb"); if( pCsr->pFile==0 ){ zipfileCursorErr(pCsr, "cannot open file: %s", zFile); rc = SQLITE_ERROR; }else{ rc = zipfileReadEOCD(pTab, 0, 0, pCsr->pFile, &pCsr->eocd); if( rc==SQLITE_OK ){ if( pCsr->eocd.nEntry==0 ){ |
︙ | ︙ | |||
1315 1316 1317 1318 1319 1320 1321 | static int zipfileBestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo ){ int i; int idx = -1; int unusable = 0; | < < > | 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 | static int zipfileBestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo ){ int i; int idx = -1; int unusable = 0; for(i=0; i<pIdxInfo->nConstraint; i++){ const struct sqlite3_index_constraint *pCons = &pIdxInfo->aConstraint[i]; 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; pIdxInfo->estimatedCost = 1000.0; pIdxInfo->idxNum = 1; }else if( unusable ){ return SQLITE_CONSTRAINT; } return SQLITE_OK; } |
︙ | ︙ | |||
1451 1452 1453 1454 1455 1456 1457 | /* ** 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); | | | < < < < | 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 | /* ** Both (const char*) arguments point to nul-terminated strings. Argument ** nB is the value of strlen(zB). This function returns 0 if the strings are ** identical, ignoring any trailing '/' character in either path. */ static int zipfileComparePath(const char *zA, const char *zB, int nB){ int nA = (int)strlen(zA); if( zA[nA-1]=='/' ) nA--; if( zB[nB-1]=='/' ) nB--; if( nA==nB && memcmp(zA, zB, nA)==0 ) return 0; return 1; } static int zipfileBegin(sqlite3_vtab *pVtab){ ZipfileTab *pTab = (ZipfileTab*)pVtab; int rc = SQLITE_OK; assert( pTab->pWriteFd==0 ); /* 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 ){ |
︙ | ︙ | |||
1497 1498 1499 1500 1501 1502 1503 | /* ** 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; | < | 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); |
︙ | ︙ | |||
1566 1567 1568 1569 1570 1571 1572 | char *zFree = 0; /* Also free this */ ZipfileEntry *pOld = 0; ZipfileEntry *pOld2 = 0; int bUpdate = 0; /* True for an update that modifies "name" */ int bIsDir = 0; u32 iCrc32 = 0; | < < | 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 | char *zFree = 0; /* Also free this */ ZipfileEntry *pOld = 0; ZipfileEntry *pOld2 = 0; int bUpdate = 0; /* True for an update that modifies "name" */ int bIsDir = 0; u32 iCrc32 = 0; if( pTab->pWriteFd==0 ){ rc = zipfileBegin(pVtab); if( rc!=SQLITE_OK ) return rc; } /* If this is a DELETE or UPDATE, find the archive entry to delete. */ if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){ |
︙ | ︙ | |||
1643 1644 1645 1646 1647 1648 1649 | 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]); | < | > < < | < < < | 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 | 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. */ if( zPath[nPath-1]!='/' ){ zFree = sqlite3_mprintf("%s/", zPath); if( zFree==0 ){ rc = SQLITE_NOMEM; } zPath = (const char*)zFree; nPath++; } } /* Check that we're not inserting a duplicate entry -OR- updating an ** entry with a path, thereby making it into a duplicate. */ if( (pOld==0 || bUpdate) && rc==SQLITE_OK ){ ZipfileEntry *p; |
︙ | ︙ | |||
1902 1903 1904 1905 1906 1907 1908 | static int zipfileFindFunction( sqlite3_vtab *pVtab, /* Virtual table handle */ int nArg, /* Number of SQL function arguments */ const char *zName, /* Name of SQL function */ void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */ void **ppArg /* OUT: User data for *pxFunc */ ){ | < | 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 | static int zipfileFindFunction( sqlite3_vtab *pVtab, /* Virtual table handle */ int nArg, /* Number of SQL function arguments */ const char *zName, /* Name of SQL function */ void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), /* OUT: Result */ void **ppArg /* OUT: User data for *pxFunc */ ){ if( sqlite3_stricmp("zipfile_cds", zName)==0 ){ *pxFunc = zipfileFunctionCds; *ppArg = (void*)pVtab; return 1; } return 0; } |
︙ | ︙ | |||
1948 1949 1950 1951 1952 1953 1954 | ** xStep() callback for the zipfile() aggregate. This can be called in ** any of the following ways: ** ** SELECT zipfile(name,data) ... ** SELECT zipfile(name,mode,mtime,data) ... ** SELECT zipfile(name,mode,mtime,data,method) ... */ | | | 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 | ** xStep() callback for the zipfile() aggregate. This can be called in ** any of the following ways: ** ** SELECT zipfile(name,data) ... ** SELECT zipfile(name,mode,mtime,data) ... ** SELECT zipfile(name,mode,mtime,data,method) ... */ void zipfileStep(sqlite3_context *pCtx, int nVal, sqlite3_value **apVal){ ZipfileCtx *p; /* Aggregate function context */ ZipfileEntry e; /* New entry to add to zip archive */ sqlite3_value *pName = 0; sqlite3_value *pMode = 0; sqlite3_value *pMtime = 0; sqlite3_value *pData = 0; |
︙ | ︙ | |||
2055 2056 2057 2058 2059 2060 2061 | /* 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 ){ | | | > < | 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 | /* 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( zName[nName-1]=='/' ){ zErr = sqlite3_mprintf("non-directory name must not end with /"); rc = SQLITE_ERROR; goto zipfile_step_out; } }else{ if( zName[nName-1]!='/' ){ zName = zFree = sqlite3_mprintf("%s/", zName); nName++; if( zName==0 ){ rc = SQLITE_NOMEM; goto zipfile_step_out; } }else{ while( nName>1 && zName[nName-2]=='/' ) nName--; } } /* Assemble the ZipfileEntry object for the new zip archive entry */ e.cds.iVersionMadeBy = ZIPFILE_NEWENTRY_MADEBY; |
︙ | ︙ | |||
2123 2124 2125 2126 2127 2128 2129 | } sqlite3_free(zErr); } /* ** xFinalize() callback for zipfile aggregate function. */ | | | 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 | } sqlite3_free(zErr); } /* ** 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; |
︙ | ︙ | |||
2180 2181 2182 2183 2184 2185 2186 | zipfileUpdate, /* xUpdate */ zipfileBegin, /* xBegin */ 0, /* xSync */ zipfileCommit, /* xCommit */ zipfileRollback, /* xRollback */ zipfileFindFunction, /* xFindMethod */ 0, /* xRename */ | < < < < < < < < | 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 | zipfileUpdate, /* xUpdate */ zipfileBegin, /* xBegin */ 0, /* xSync */ zipfileCommit, /* xCommit */ zipfileRollback, /* xRollback */ zipfileFindFunction, /* xFindMethod */ 0, /* xRename */ }; int rc = sqlite3_create_module(db, "zipfile" , &zipfileModule, 0); if( rc==SQLITE_OK ) rc = sqlite3_overload_function(db, "zipfile_cds", -1); 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 |
︙ | ︙ |
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->zName); } 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); |
︙ | ︙ | |||
179 180 181 182 183 184 185 | break; default: fprintf(stderr, "error=%d: %s\n", rc, zErrmsg); break; } | < < < < < < < | 179 180 181 182 183 184 185 186 187 188 | break; default: fprintf(stderr, "error=%d: %s\n", rc, zErrmsg); break; } sqlite3_free(zErrmsg); return (rc==SQLITE_OK || rc==SQLITE_DONE) ? 0 : 1; } |
Changes to ext/rbu/rbu1.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 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] | < > > | 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 | # 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 rbu1 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_rbu1 {filename} { forcedelete $filename |
︙ | ︙ | |||
127 128 129 130 131 132 133 | foreach {tn3 create_vfs destroy_vfs} { 1 {} {} 2 { sqlite3rbu_create_vfs -default myrbu "" } { sqlite3rbu_destroy_vfs myrbu } | < < < < < | 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 |
︙ | ︙ |
Changes to ext/rbu/rbu10.test.
1 2 3 4 5 6 7 8 9 10 11 12 | # 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. # #*********************************************************************** # | > | > | > | 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 | # 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. # #*********************************************************************** # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl set ::testprefix rbu10 #-------------------------------------------------------------------- # Test that UPDATE commands work even if the input columns are in a # different order to the output columns. # do_execsql_test 1.0 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); |
︙ | ︙ | |||
43 44 45 46 47 48 49 | #-------------------------------------------------------------------- # 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/rbu11.test.
1 2 3 4 5 6 7 8 9 10 11 12 | # 2015 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. # #*********************************************************************** # | > | > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # 2015 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. # #*********************************************************************** # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl set ::testprefix rbu11 #-------------------------------------------------------------------- # Test that the xAccess() method of an rbu vfs handles queries other # than SQLITE_ACCESS_EXISTS correctly. The test code below causes # SQLite to call xAccess(SQLITE_ACCESS_READWRITE) on the directory |
︙ | ︙ |
Changes to ext/rbu/rbu12.test.
1 2 3 4 5 6 7 8 9 10 11 12 | # 2015 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. # #*********************************************************************** # | > | > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # 2015 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. # #*********************************************************************** # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl source $testdir/lock_common.tcl set ::testprefix rbu12 set setup_sql { DROP TABLE IF EXISTS xx; DROP TABLE IF EXISTS xy; CREATE TABLE xx(a, b, c PRIMARY KEY); |
︙ | ︙ |
Changes to ext/rbu/rbu13.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # # Test an RBU update that features lots of different rbu_control strings # for UPDATE statements. This tests RBU's internal UPDATE statement cache. # | > | > | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # #*********************************************************************** # # Test an RBU update that features lots of different rbu_control strings # for UPDATE statements. This tests RBU's internal UPDATE statement cache. # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl source $testdir/lock_common.tcl set ::testprefix rbu13 do_execsql_test 1.0 { CREATE TABLE t1(a PRIMARY KEY, b, c, d, e, f, g, h); WITH ii(i) AS (SELECT 0 UNION ALL SELECT i+1 FROM ii WHERE i<127) INSERT INTO t1 SELECT i, 0, 0, 0, 0, 0, 0, 0 FROM ii; |
︙ | ︙ |
Changes to ext/rbu/rbu14.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # # Test that an RBU data_xxx table may be a view instead of a regular # table. # | > | > | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # #*********************************************************************** # # Test that an RBU data_xxx table may be a view instead of a regular # table. # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl source $testdir/lock_common.tcl set ::testprefix rbu14 foreach {tn schema} { 1 { CREATE TABLE t1(a PRIMARY KEY, b, c); |
︙ | ︙ |
Changes to ext/rbu/rbu3.test.
1 2 3 4 5 6 7 8 9 10 11 12 | # 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. # #*********************************************************************** # | > | > | > > > | 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 | # 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. # #*********************************************************************** # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl set ::testprefix rbu3 # Run the RBU in file $rbu on target database $target until completion. # proc run_rbu {target rbu} { sqlite3rbu rbu $target $rbu while { [rbu step]=="SQLITE_OK" } {} rbu close } forcedelete test.db-oal rbu.db db close sqlite3_shutdown sqlite3_config_uri 1 reset_db #-------------------------------------------------------------------- # Test that for an RBU to be applied, no corruption results if the # affinities on the source and target table do not match. # do_execsql_test 1.0 { |
︙ | ︙ |
Changes to ext/rbu/rbu5.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # # Test some properties of the pager_rbu_mode and rbu_mode pragmas. # source [file join [file dirname [info script]] rbu_common.tcl] | < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # #*********************************************************************** # # Test some properties of the pager_rbu_mode and rbu_mode pragmas. # source [file join [file dirname [info script]] rbu_common.tcl] set ::testprefix rbu5 # Return a list of the primary key columns for table $tbl in the database # opened by database handle $db. # proc pkcols {db tbl} { |
︙ | ︙ |
Changes to ext/rbu/rbu6.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # # This file contains tests for the RBU module. Specifically, it tests the # outcome of some other client writing to the database while an RBU update # is being applied. | > | > | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # #*********************************************************************** # # This file contains tests for the RBU module. Specifically, it tests the # outcome of some other client writing to the database while an RBU update # is being applied. if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl set ::testprefix rbu6 proc setup_test {} { reset_db execsql { CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE); CREATE TABLE t2(a INTEGER PRIMARY KEY, b UNIQUE); |
︙ | ︙ |
Changes to ext/rbu/rbu7.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # # This file contains tests for the RBU module. # | > | > | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # #*********************************************************************** # # This file contains tests for the RBU module. # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl set ::testprefix rbu7 # Test index: # # 1.*: That affinities are correctly applied to values within the # RBU database. # |
︙ | ︙ |
Changes to ext/rbu/rbu8.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # May you share freely, never taking more than you give. # #*********************************************************************** # # Test the rbu_delta() feature. # | > | > | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # May you share freely, never taking more than you give. # #*********************************************************************** # # Test the rbu_delta() feature. # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl set ::testprefix rbu8 do_execsql_test 1.0 { CREATE TABLE t1(x, y PRIMARY KEY, z); INSERT INTO t1 VALUES(NULL, 1, 'one'); INSERT INTO t1 VALUES(NULL, 2, 'two'); INSERT INTO t1 VALUES(NULL, 3, 'three'); |
︙ | ︙ |
Changes to ext/rbu/rbu9.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # May you share freely, never taking more than you give. # #*********************************************************************** # # Test RBU with virtual tables. And tables with no PRIMARY KEY declarations. # | > | > | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # May you share freely, never taking more than you give. # #*********************************************************************** # # Test RBU with virtual tables. And tables with no PRIMARY KEY declarations. # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl set ::testprefix rbu9 ifcapable !fts3 { finish_test return } |
︙ | ︙ |
Changes to ext/rbu/rbuA.test.
︙ | ︙ | |||
10 11 12 13 14 15 16 | #*********************************************************************** # # This file contains tests for the RBU module. More specifically, it # contains tests to ensure that it is an error to attempt to update # a wal mode database via RBU. # | > | > | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | #*********************************************************************** # # This file contains tests for the RBU module. More specifically, it # contains tests to ensure that it is an error to attempt to update # a wal mode database via RBU. # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl set ::testprefix rbuA set db_sql { CREATE TABLE t1(a PRIMARY KEY, b, c); } set rbu_sql { CREATE TABLE data_t1(a, b, c, rbu_control); |
︙ | ︙ |
Changes to ext/rbu/rbuB.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # May you share freely, never taking more than you give. # #*********************************************************************** # # source [file join [file dirname [info script]] rbu_common.tcl] | < | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # May you share freely, never taking more than you give. # #*********************************************************************** # # source [file join [file dirname [info script]] rbu_common.tcl] set ::testprefix rbuB db close sqlite3_shutdown test_sqlite3_log xLog reset_db |
︙ | ︙ | |||
45 46 47 48 49 50 51 | proc xLog {err msg} { lappend ::errlog $err } do_test 1.2 { run_rbu test.db rbu.db } {SQLITE_DONE} do_test 1.3 { set ::errlog | | | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | proc xLog {err msg} { lappend ::errlog $err } do_test 1.2 { run_rbu test.db rbu.db } {SQLITE_DONE} do_test 1.3 { set ::errlog } {SQLITE_NOTICE_RECOVER_WAL SQLITE_INTERNAL} do_execsql_test 1.4 { SELECT * FROM t1 } {1 2 3 4 5 6 7 8 9} db close sqlite3_shutdown test_sqlite3_log sqlite3_initialize finish_test |
Changes to ext/rbu/rbuC.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # Tests for RBU focused on the REPLACE operation (rbu_control column # contains integer value 2). # source [file join [file dirname [info script]] rbu_common.tcl] | < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # #*********************************************************************** # Tests for RBU focused on the REPLACE operation (rbu_control column # contains integer value 2). # source [file join [file dirname [info script]] rbu_common.tcl] set ::testprefix rbuC #------------------------------------------------------------------------- # This test is actually of an UPDATE directive. Just to establish that # these work with UNIQUE indexes before preceding to REPLACE. # do_execsql_test 1.0 { |
︙ | ︙ |
Changes to ext/rbu/rbu_common.tcl.
︙ | ︙ | |||
11 12 13 14 15 16 17 | # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl | < < < < < < < < < < | 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 proc check_prestep_state {target state} { set oal_exists [file exists $target-oal] set wal_exists [file exists $target-wal] set progress [rbu progress] if {($progress==0 && $state!="oal" && $state!="done") || ($oal_exists && $wal_exists) |
︙ | ︙ | |||
95 96 97 98 99 100 101 | } 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 109 110 | } 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] { 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] } |
Deleted ext/rbu/rbubusy.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to ext/rbu/rbucollate.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2018 March 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 [info script]] rbu_common.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 | # 2018 March 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 [info script]] rbu_common.tcl] set ::testprefix rbucollate ifcapable !icu_collations { finish_test return } db close sqlite3_shutdown sqlite3_config_uri 1 reset_db # Create a simple RBU database. That expects to write to a table: # # CREATE TABLE t1(a PRIMARY KEY, b, c); # proc create_rbu1 {filename} { forcedelete $filename sqlite3 rbu1 $filename |
︙ | ︙ |
Changes to ext/rbu/rbucrash.test.
1 2 3 4 5 6 7 8 9 10 11 12 | # 2014 October 22 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # | > | > | > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | # 2014 October 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. # #*********************************************************************** # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl set ::testprefix rbucrash db close forcedelete test.db-oal rbu.db sqlite3_shutdown sqlite3_config_uri 1 reset_db # Set up a target database and an rbu update database. The target # db is the usual "test.db", the rbu db is "test.db2". # forcedelete test.db2 do_execsql_test 1.0 { CREATE TABLE t1(a, b, c, PRIMARY KEY(a), UNIQUE(b)); |
︙ | ︙ |
Changes to ext/rbu/rbucrash2.test.
1 2 3 4 5 6 7 8 9 10 11 12 | # 2017 March 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. # #*********************************************************************** # | > | > | > > > > > > | 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 | # 2017 March 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 {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl set ::testprefix rbucrash2 db close forcedelete test.db-oal rbu.db sqlite3_shutdown sqlite3_config_uri 1 reset_db # Set up a target database and an rbu update database. The target # db is the usual "test.db", the rbu db is "test.db2". # forcedelete test.db2 do_execsql_test 1.0 { CREATE TABLE t1(a, b, c, PRIMARY KEY(a), UNIQUE(b)); |
︙ | ︙ |
Changes to ext/rbu/rbudiff.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # May you share freely, never taking more than you give. # #*********************************************************************** # # Tests for the [sqldiff --rbu] command. # # | > > | | < | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # May you share freely, never taking more than you give. # #*********************************************************************** # # Tests for the [sqldiff --rbu] command. # # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl set testprefix rbudiff set PROG [test_find_sqldiff] db close proc get_rbudiff_sql {db1 db2} { exec $::PROG --rbu $db1 $db2 |
︙ | ︙ | |||
258 259 260 261 262 263 264 | INSERT INTO t1 VALUES('a b c'); } 3 { creAte virTUal tablE t1 USING FTs5(c); INSERT INTO t1 VALUES('a b c'); | < < < < < < < < | 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | INSERT INTO t1 VALUES('a b c'); } 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'); } } { |
︙ | ︙ |
Changes to ext/rbu/rbudor.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # # This test file focuses on interactions between RBU and the feature # enabled by SQLITE_DIRECT_OVERFLOW_READ - Direct Overflow Read. # | > | > | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # #*********************************************************************** # # This test file focuses on interactions between RBU and the feature # enabled by SQLITE_DIRECT_OVERFLOW_READ - Direct Overflow Read. # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl set ::testprefix rbudor set bigA [string repeat a 5000] set bigB [string repeat b 5000] do_execsql_test 1.0 { PRAGMA page_size = 1024; CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB); |
︙ | ︙ |
Deleted ext/rbu/rbuexlock.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/rbu/rbuexpr.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to ext/rbu/rbufault.test.
1 2 3 4 5 6 7 8 9 10 11 12 | # 2014 October 22 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # | > | > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # 2014 October 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. # #*********************************************************************** # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl source $testdir/malloc_common.tcl set ::testprefix rbufault proc copy_if_exists {src target} { if {[file exists $src]} { forcecopy $src $target } else { |
︙ | ︙ |
Changes to ext/rbu/rbufault2.test.
1 2 3 4 5 6 7 8 9 10 11 12 | # 2014 October 22 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # | > | > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # 2014 October 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. # #*********************************************************************** # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl source $testdir/malloc_common.tcl set ::testprefix rbufault2 forcedelete rbu.db do_execsql_test 1.0 { CREATE TABLE target(x UNIQUE, y, z, PRIMARY KEY(y)); INSERT INTO target VALUES(1, 2, 3); |
︙ | ︙ | |||
46 47 48 49 50 51 52 | {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}} } | < < < < < < < < < | 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 |
Changes to ext/rbu/rbufault3.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # # This file contains fault injection tests for RBU vacuum operations. # source [file join [file dirname [info script]] rbu_common.tcl] | < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # #*********************************************************************** # # This file contains fault injection tests for RBU vacuum operations. # source [file join [file dirname [info script]] rbu_common.tcl] source $testdir/malloc_common.tcl set ::testprefix rbufault3 foreach {fault errlist} { oom-* { {1 SQLITE_NOMEM} {1 SQLITE_IOERR_NOMEM} |
︙ | ︙ | |||
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | 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 | > > | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | 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 forcedelete test.db2 } -body { sqlite3rbu_vacuum rbu test.db test.db2 rbu step rbu close } -test { eval [list faultsim_test_result {0 SQLITE_OK} {*}$::errlist] } } finish_test |
Changes to ext/rbu/rbufault4.test.
1 2 3 4 5 6 7 8 9 10 11 12 | # 2014 October 22 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # | > | > | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | # 2014 October 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. # #*********************************************************************** # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl source $testdir/malloc_common.tcl set ::testprefix rbufault4 for {set tn 1} {1} {incr tn} { reset_db do_execsql_test 1.0 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); CREATE INDEX i1b ON t1(b); CREATE INDEX i1c ON t1(c); INSERT INTO t1 VALUES(1, 2, 3); INSERT INTO t1 VALUES(4, 5, 6); } forcedelete test.db2 sqlite3rbu_vacuum rbu test.db test.db2 for {set i 0} {$i < $tn} {incr i} { rbu step } set rc [rbu close] if {$rc!="SQLITE_OK"} { if {$rc!="SQLITE_DONE"} {error $rc} |
︙ | ︙ | |||
50 51 52 53 54 55 56 | faultsim_test_result {0 {}} {1 SQLITE_NOMEM} {1 SQLITE_IOERR_NOMEM} sqlite3rbu_vacuum rbu test.db test.db2 while {[rbu step]=="SQLITE_OK"} {} set trc [rbu close] if {$trc!="SQLITE_DONE"} { error "Got $trc instead of SQLITE_DONE!" } | < < | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | faultsim_test_result {0 {}} {1 SQLITE_NOMEM} {1 SQLITE_IOERR_NOMEM} sqlite3rbu_vacuum rbu test.db test.db2 while {[rbu step]=="SQLITE_OK"} {} set trc [rbu close] if {$trc!="SQLITE_DONE"} { error "Got $trc instead of SQLITE_DONE!" } set rc [db one {PRAGMA integrity_check}] if {$rc!="ok"} { error "Got $rc instead of ok!" } } } finish_test |
Changes to ext/rbu/rbufts.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # # This file contains tests for the RBU module. More specifically, it # contains tests to ensure that RBU works with FTS tables. # | > | > | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # #*********************************************************************** # # This file contains tests for the RBU module. More specifically, it # contains tests to ensure that RBU works with FTS tables. # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl set ::testprefix rbufts ifcapable !fts3 { finish_test return } |
︙ | ︙ |
Deleted ext/rbu/rbumisc.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to ext/rbu/rbumulti.test.
1 2 3 4 5 6 7 8 9 10 11 | # 2018 January 11 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # | < < < > > | 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 | # 2018 January 11 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # This file contains tests of multiple RBU operations running # concurrently within the same process. # source [file join [file dirname [info script]] rbu_common.tcl] set ::testprefix rbumulti db close sqlite3_shutdown sqlite3_config_uri 1 autoinstall_test_functions proc build_db {db} { $db eval { CREATE TABLE t1(a PRIMARY KEY, b, c); CREATE INDEX i1 ON t1(b); |
︙ | ︙ |
Changes to ext/rbu/rbupartial.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 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] | < > > | 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 | # 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"} |
︙ | ︙ | |||
35 36 37 38 39 40 41 | 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'; | < < < < < < < < < | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | 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'; } 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'); |
︙ | ︙ | |||
84 85 86 87 88 89 90 | 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 | < < < < | 76 77 78 79 80 81 82 83 84 85 86 | 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 }] } finish_test |
Deleted ext/rbu/rbupass.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to ext/rbu/rbuprogress.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2016 March 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. # #*********************************************************************** # source [file join [file dirname [info script]] rbu_common.tcl] | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # 2016 March 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. # #*********************************************************************** # source [file join [file dirname [info script]] rbu_common.tcl] set ::testprefix rbuprogress proc create_db_file {filename sql} { forcedelete $filename sqlite3 tmpdb $filename tmpdb eval $sql |
︙ | ︙ | |||
411 412 413 414 415 416 417 | set R(nopk) $r1 set R(vtab) $r2 do_sp_test 5.$tn.$bReopen.$tn2.1 $bReopen test.db rbu.db $R($tn) } } } | < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
Deleted ext/rbu/rburename.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to ext/rbu/rburesume.test.
1 2 3 4 5 6 7 8 9 10 11 | # 2017 January 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. # #*********************************************************************** # | < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # 2017 January 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 contains tests for resumption of RBU operations in the # case where the previous RBU process crashed. # source [file join [file dirname [info script]] rbu_common.tcl] set ::testprefix rburesume forcedelete test.db-shm test.db-oal do_execsql_test 1.0 { CREATE TABLE t1(a PRIMARY KEY, b, c); CREATE INDEX t1a ON t1(a); CREATE INDEX t1b ON t1(b); |
︙ | ︙ | |||
96 97 98 99 100 101 102 | if {$rc == "SQLITE_DONE"} break } if {$rc == "SQLITE_DONE"} { rbu close break } | | | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | if {$rc == "SQLITE_DONE"} break } if {$rc == "SQLITE_DONE"} { rbu close break } foreach f {test.db test.db-oal test.db-wal test.db-shm test.db-vacuum} { set f2 [string map [list test.db test.db2] $f] if {[file exists $f]} { forcecopy $f $f2 } else { forcedelete $f2 } } |
︙ | ︙ | |||
155 156 157 158 159 160 161 | if {$rc == "SQLITE_DONE"} break } if {$rc == "SQLITE_DONE"} { rbu close break } | | | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | if {$rc == "SQLITE_DONE"} break } if {$rc == "SQLITE_DONE"} { rbu close break } foreach f {test.db test.db-oal test.db-wal test.db-shm test.db-vacuum} { set f2 [string map [list test.db test.db2] $f] if {[file exists $f]} { forcecopy $f $f2 } else { forcedelete $f2 } } |
︙ | ︙ | |||
222 223 224 225 226 227 228 | if {$rc == "SQLITE_DONE"} break } if {$rc == "SQLITE_DONE"} { rbu close break } | | | 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 | if {$rc == "SQLITE_DONE"} break } if {$rc == "SQLITE_DONE"} { rbu close break } foreach f {test.db test.db-oal test.db-wal test.db-shm test.db-vacuum} { set f2 [string map [list test.db test.db2] $f] if {[file exists $f]} { forcecopy $f $f2 } else { forcedelete $f2 } } |
︙ | ︙ |
Changes to ext/rbu/rbusave.test.
1 2 3 4 5 6 7 8 9 10 11 12 | # 2015 August 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. # #*********************************************************************** # | > | > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # 2015 August 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. # #*********************************************************************** # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl set ::testprefix rbusave do_execsql_test 1.0 { CREATE TABLE t1(a PRIMARY KEY, b, c) WITHOUT ROWID; CREATE TABLE t2(a INTEGER PRIMARY KEY, b, c); CREATE INDEX i1 ON t1(b); CREATE INDEX i2 ON t2(c, b); |
︙ | ︙ |
Changes to ext/rbu/rbusplit.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # May you share freely, never taking more than you give. # #*********************************************************************** # # source [file join [file dirname [info script]] rbu_common.tcl] | < > > | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # May you share freely, never taking more than you give. # #*********************************************************************** # # source [file join [file dirname [info script]] rbu_common.tcl] set ::testprefix rbusplit db close sqlite3_shutdown sqlite3_config_uri 1 autoinstall_test_functions proc build_db {db} { $db eval { CREATE TABLE t1(a PRIMARY KEY, b, c); CREATE TABLE t2(a PRIMARY KEY, b, c); |
︙ | ︙ |
Changes to ext/rbu/rbutemplimit.test.
1 2 3 4 5 6 7 8 9 10 11 | # 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. # #*********************************************************************** # | < < > > | 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 | # 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 rbutemplimit db close sqlite3_shutdown sqlite3_config_uri 1 proc setup_databases {} { forcedelete test.db2 forcedelete test.db sqlite3 db test.db execsql { -- Create target database schema. |
︙ | ︙ | |||
61 62 63 64 65 66 67 | } proc step_rbu_cachesize {target rbu stepsize cachesize temp_limit} { set res "" while 1 { sqlite3rbu rbu $target $rbu rbu temp_size_limit $temp_limit | < | 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] |
︙ | ︙ |
Changes to ext/rbu/rbuvacuum.test.
︙ | ︙ | |||
11 12 13 14 15 16 17 | # # 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] | < | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # # 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 rbuvacuum foreach step {0 1} { set ::testprefix rbuvacuum-step=$step reset_db |
︙ | ︙ |
Changes to ext/rbu/rbuvacuum2.test.
︙ | ︙ | |||
11 12 13 14 15 16 17 | # # 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] | < | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # # 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] foreach {step} {0 1} { foreach {ttt state} { s state.db t test.db-vacuum n {} } { set ::testprefix rbuvacuum2-$step$ttt |
︙ | ︙ | |||
195 196 197 198 199 200 201 | 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 | 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 do_test 5.$tn.3 { file attributes test.db-vacuum -permissions} $perm rbu close } } #------------------------------------------------------------------------- # Test the outcome of some other connection running a checkpoint while # the incremental checkpoint is suspended. |
︙ | ︙ | |||
224 225 226 227 228 229 230 | do_test 6.1 { sqlite3rbu_vacuum rbu test.db test.db2 while {[rbu state]!="checkpoint"} { rbu step } rbu close } {SQLITE_OK} | | | | < | | 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | do_test 6.1 { sqlite3rbu_vacuum rbu test.db test.db2 while {[rbu state]!="checkpoint"} { rbu step } rbu close } {SQLITE_OK} do_execsql_test 6.2 { SELECT 1 FROM sqlite_master LIMIT 1; PRAGMA wal_checkpoint; } {1 0 4 4} do_test 6.3 { sqlite3rbu_vacuum rbu test.db test.db2 while {[rbu step]!="SQLITE_DONE"} { rbu step } rbu close execsql { PRAGMA integrity_check } } {ok} |
︙ | ︙ |
Changes to ext/rbu/rbuvacuum3.test.
︙ | ︙ | |||
11 12 13 14 15 16 17 | # # 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] | < | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # # 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); |
︙ | ︙ |
Deleted ext/rbu/rbuvacuum4.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to ext/rbu/sqlite3rbu.c.
︙ | ︙ | |||
105 106 107 108 109 110 111 | /* ** Swap two objects of type TYPE. */ #if !defined(SQLITE_AMALGAMATION) # define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;} #endif | < < < < < < < | 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: |
︙ | ︙ | |||
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; | < | 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; |
︙ | ︙ | |||
230 231 232 233 234 235 236 | struct RbuUpdateStmt { char *zMask; /* Copy of update mask used with pUpdate */ sqlite3_stmt *pUpdate; /* Last update statement (or NULL) */ RbuUpdateStmt *pNext; }; | < < < < < | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | 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 |
︙ | ︙ | |||
284 285 286 287 288 289 290 | /* 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 */ | < < < | 271 272 273 274 275 276 277 278 279 280 281 282 283 284 | /* 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 |
︙ | ︙ | |||
389 390 391 392 393 394 395 | int nProgress; /* Rows processed for all objects */ RbuObjIter objiter; /* Iterator for skipping through tbl/idx */ const char *zVfsName; /* Name of automatically created rbu vfs */ rbu_file *pTargetFd; /* File handle open on target db */ int nPagePerSector; /* Pages per sector for pTargetFd */ i64 iOalSz; i64 nPhaseOneStep; | < < | 373 374 375 376 377 378 379 380 381 382 383 384 385 386 | int nProgress; /* Rows processed for all objects */ RbuObjIter objiter; /* Iterator for skipping through tbl/idx */ const char *zVfsName; /* Name of automatically created rbu vfs */ rbu_file *pTargetFd; /* File handle open on target db */ int nPagePerSector; /* Pages per sector for pTargetFd */ i64 iOalSz; i64 nPhaseOneStep; /* The following state variables are used as part of the incremental ** checkpoint stage (eStage==RBU_STAGE_CKPT). See comments surrounding ** function rbuSetupCheckpoint() for details. */ u32 iMaxFrame; /* Largest iWalFrame value in aFrame[] */ u32 mLock; int nFrame; /* Entries in aFrame[] array */ |
︙ | ︙ | |||
823 824 825 826 827 828 829 | pUp = pIter->pRbuUpdate; while( pUp ){ RbuUpdateStmt *pTmp = pUp->pNext; sqlite3_finalize(pUp->pUpdate); sqlite3_free(pUp); pUp = pTmp; } | < < < < < | 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 | 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){ |
︙ | ︙ | |||
949 950 951 952 953 954 955 | 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) ){ | < | 926 927 928 929 930 931 932 933 934 935 936 937 938 939 | 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++); |
︙ | ︙ | |||
980 981 982 983 984 985 986 | 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 " | | | | 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 | 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_master " "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_master " " WHERE type='index' AND tbl_name = ?" ); } pIter->bCleanup = 1; p->rc = rc; return rbuObjIterNext(p, pIter); |
︙ | ︙ | |||
1108 1109 1110 1111 1112 1113 1114 | ** 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; | | | | | | | | | < | 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 | ** 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; assert( *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; } /* |
︙ | ︙ | |||
1161 1162 1163 1164 1165 1166 1167 | ** (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: ** | | | | | | < < | | 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 | ** (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_master ){ ** 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_master ){ ** *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_master where name=%Q AND IsVirtual(%Q) ** 1) PRAGMA index_list = ? ** 2) SELECT count(*) FROM sqlite_master 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 LIKE 'create virtual%%'), rootpage" " FROM sqlite_master" " 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) ){ |
︙ | ︙ | |||
1225 1226 1227 1228 1229 1230 1231 | 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( | | | 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 | 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_master 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; |
︙ | ︙ | |||
1290 1291 1292 1293 1294 1295 1296 | } 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; | < < < | 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 | } 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 ){ |
︙ | ︙ | |||
1407 1408 1409 1410 1411 1412 1413 | 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); | < | | 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 | 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); pIter->abTblPk[iOrder] = (iPk!=0); pIter->abNotNull[iOrder] = (u8)bNotNull || (iPk!=0); iOrder++; } } rbuFinalize(p, pStmt); rbuObjIterCacheIndexedCols(p, pIter); |
︙ | ︙ | |||
1443 1444 1445 1446 1447 1448 1449 | const char *z = pIter->azTblCol[i]; zList = rbuMPrintf(p, "%z%s\"%w\"", zList, zSep, z); zSep = ", "; } return zList; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 | 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 ** to obtain the required information. |
︙ | ︙ | |||
1706 1707 1708 1709 1710 1711 1712 | ); } 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); | | < < < < < < < | | | | | | | | | | | | | | | | | | < | | | 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 | ); } 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; const char *zType; 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", |
︙ | ︙ | |||
2047 2048 2049 2050 2051 2052 2053 | 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, | | | 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 | 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_master 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); } } |
︙ | ︙ | |||
2216 2217 2218 2219 2220 2221 2222 | } static char *rbuObjIterGetIndexWhere(sqlite3rbu *p, RbuObjIter *pIter){ sqlite3_stmt *pStmt = 0; int rc = p->rc; char *zRet = 0; | < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | } static char *rbuObjIterGetIndexWhere(sqlite3rbu *p, RbuObjIter *pIter){ sqlite3_stmt *pStmt = 0; int rc = p->rc; char *zRet = 0; if( rc==SQLITE_OK ){ rc = prepareAndCollectError(p->dbMain, &pStmt, &p->zErrmsg, "SELECT trim(sql) FROM sqlite_master 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) ){ const char *zSql = (const char*)sqlite3_column_text(pStmt, 0); if( zSql ){ int nParen = 0; /* Number of open parenthesis */ int i; for(i=0; zSql[i]; i++){ char c = zSql[i]; if( c=='(' ){ nParen++; } else if( c==')' ){ nParen--; if( nParen==0 ){ i++; break; } }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; } } } if( zSql[i] ){ zRet = rbuStrndup(&zSql[i], &rc); } } } rc2 = sqlite3_finalize(pStmt); if( rc==SQLITE_OK ) rc = rc2; } |
︙ | ︙ | |||
2339 2340 2341 2342 2343 2344 2345 | 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 ); | < > | 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 | 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 ); zCollist = rbuObjIterGetIndexCols( p, pIter, &zImposterCols, &zImposterPK, &zWhere, &nBind ); zBind = rbuObjIterGetBindlist(p, nBind); zPart = rbuObjIterGetIndexWhere(p, pIter); /* Create the imposter table used to write to this index. */ sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 1); sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 1,tnum); rbuMPrintfExec(p, p->dbMain, "CREATE TABLE \"rbu_imp_%w\"( %s, PRIMARY KEY( %s ) ) WITHOUT ROWID", zTbl, zImposterCols, zImposterPK |
︙ | ︙ | |||
2375 2376 2377 2378 2379 2380 2381 | ); } /* Create the SELECT statement to read keys in sorted order */ if( p->rc==SQLITE_OK ){ char *zSql; if( rbuIsVacuum(p) ){ | < < < < < < < < < | < < | < | 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 | ); } /* Create the SELECT statement to read keys in sorted order */ if( p->rc==SQLITE_OK ){ char *zSql; if( rbuIsVacuum(p) ){ zSql = sqlite3_mprintf( "SELECT %s, 0 AS rbu_control FROM '%q' %s ORDER BY %s%s", zCollist, pIter->zDataTbl, zPart, zCollist, zLimit ); }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 |
︙ | ︙ | |||
2415 2416 2417 2418 2419 2420 2421 | zCollist, p->zStateDb, pIter->zDataTbl, zPart, zCollist, pIter->zDataTbl, zPart, (zPart ? "AND" : "WHERE"), zCollist, zLimit ); } | < | < < < | 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 | zCollist, p->zStateDb, pIter->zDataTbl, zPart, zCollist, pIter->zDataTbl, zPart, (zPart ? "AND" : "WHERE"), zCollist, zLimit ); } p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz, zSql); } sqlite3_free(zImposterCols); sqlite3_free(zImposterPK); sqlite3_free(zWhere); sqlite3_free(zBind); sqlite3_free(zPart); |
︙ | ︙ | |||
2519 2520 2521 2522 2523 2524 2525 | rbuObjIterPrepareTmpInsert(p, pIter, zCollist, zRbuRowid); } /* Create the SELECT statement to read keys from data_xxx */ if( p->rc==SQLITE_OK ){ const char *zRbuRowid = ""; | < < < < < < < < < < < < < < < < < < < | | | | | | | < < | | < < < | 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 | 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"; } p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz, sqlite3_mprintf( "SELECT %s,%s rbu_control%s FROM '%q'%s", zCollist, (rbuIsVacuum(p) ? "0 AS " : ""), zRbuRowid, pIter->zDataTbl, zLimit ) ); } sqlite3_free(zWhere); sqlite3_free(zOldlist); sqlite3_free(zNewlist); sqlite3_free(zBindings); } |
︙ | ︙ | |||
2734 2735 2736 2737 2738 2739 2740 | break; case RBU_STATE_COOKIE: pRet->iCookie = (u32)sqlite3_column_int64(pStmt, 1); break; case RBU_STATE_OALSZ: | | | 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 | break; case RBU_STATE_COOKIE: pRet->iCookie = (u32)sqlite3_column_int64(pStmt, 1); break; case RBU_STATE_OALSZ: pRet->iOalSz = (u32)sqlite3_column_int64(pStmt, 1); break; case RBU_STATE_PHASEONESTEP: pRet->nPhaseOneStep = sqlite3_column_int64(pStmt, 1); break; case RBU_STATE_DATATBL: |
︙ | ︙ | |||
2761 2762 2763 2764 2765 2766 2767 | 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. | < < < < | < < | | 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 | 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. */ static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){ assert( p->rc || (p->dbMain==0 && p->dbRbu==0) ); assert( p->rc || rbuIsVacuum(p) || p->zTarget!=0 ); /* Open the RBU database */ p->dbRbu = rbuOpenDbhandle(p, p->zRbu, 1); 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); } } /* If using separate RBU and state databases, attach the state database to ** the RBU db handle now. */ if( p->zState ){ rbuMPrintfExec(p, p->dbRbu, "ATTACH %Q AS stat", p->zState); |
︙ | ︙ | |||
2808 2809 2810 2811 2812 2813 2814 | #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, | | | 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 | #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_master" ); if( p->rc==SQLITE_OK && sqlite3_step(pCnt)==SQLITE_ROW && 1==sqlite3_column_int(pCnt, 0) ){ bOk = 1; } |
︙ | ︙ | |||
2912 2913 2914 2915 2916 2917 2918 | "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); } | | | 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 | "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_master"); /* 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); } |
︙ | ︙ | |||
3005 3006 3007 3008 3009 3010 3011 | /* 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 ){ | | | 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 | /* 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_master", 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: ** |
︙ | ︙ | |||
3027 3028 3029 3030 3031 3032 3033 | ** array. ** ** * Calls to xShmLock(UNLOCK) to release the exclusive shm WRITER, ** READ0 and CHECKPOINT locks taken as part of the checkpoint are ** no-ops. These locks will not be released until the connection ** is closed. ** | | | | | 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 | ** array. ** ** * Calls to xShmLock(UNLOCK) to release the exclusive shm WRITER, ** READ0 and CHECKPOINT locks taken as part of the checkpoint are ** no-ops. These locks will not be released until the connection ** is closed. ** ** * Attempting to xSync() the database file causes an SQLITE_INTERNAL ** error. ** ** As a result, unless an error (i.e. OOM or SQLITE_BUSY) occurs, the ** checkpoint below fails with SQLITE_INTERNAL, and leaves the aFrame[] ** array populated with a set of (frame -> page) mappings. Because the ** WRITER, CHECKPOINT and READ0 locks are still held, it is safe to copy ** data from the wal file into the database file according to the ** contents of aFrame[]. */ if( p->rc==SQLITE_OK ){ int rc2; p->eStage = RBU_STAGE_CAPTURE; rc2 = sqlite3_exec(p->dbMain, "PRAGMA main.wal_checkpoint=restart", 0, 0,0); if( rc2!=SQLITE_INTERNAL ) p->rc = rc2; } if( p->rc==SQLITE_OK && p->nFrame>0 ){ p->eStage = RBU_STAGE_CKPT; p->nStep = (pState ? pState->nRow : 0); p->aBuf = rbuMalloc(p, p->pgsz); p->iWalCksum = rbuShmChecksum(p); |
︙ | ︙ | |||
3087 3088 3089 3090 3091 3092 3093 | */ static int rbuCaptureWalRead(sqlite3rbu *pRbu, i64 iOff, int iAmt){ const u32 mReq = (1<<WAL_LOCK_WRITE)|(1<<WAL_LOCK_CKPT)|(1<<WAL_LOCK_READ0); u32 iFrame; if( pRbu->mLock!=mReq ){ pRbu->rc = SQLITE_BUSY; | | | 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 | */ static int rbuCaptureWalRead(sqlite3rbu *pRbu, i64 iOff, int iAmt){ const u32 mReq = (1<<WAL_LOCK_WRITE)|(1<<WAL_LOCK_CKPT)|(1<<WAL_LOCK_READ0); u32 iFrame; if( pRbu->mLock!=mReq ){ pRbu->rc = SQLITE_BUSY; return SQLITE_INTERNAL; } pRbu->pgsz = iAmt; if( pRbu->nFrame==pRbu->nFrameAlloc ){ int nNew = (pRbu->nFrameAlloc ? pRbu->nFrameAlloc : 64) * 2; RbuFrame *aNew; aNew = (RbuFrame*)sqlite3_realloc64(pRbu->aFrame, nNew * sizeof(RbuFrame)); |
︙ | ︙ | |||
3139 3140 3141 3142 3143 3144 3145 | iOff = (i64)(pFrame->iDbPage-1) * p->pgsz; p->rc = pDb->pMethods->xWrite(pDb, p->aBuf, p->pgsz, iOff); } /* | | < | < | < | < | | | | < < < < < < < < < < < < | 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 | 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. */ static void rbuLockDatabase(sqlite3rbu *p){ sqlite3_file *pReal = p->pTargetFd->pReal; assert( p->rc==SQLITE_OK ); p->rc = pReal->pMethods->xLock(pReal, SQLITE_LOCK_SHARED); if( p->rc==SQLITE_OK ){ p->rc = pReal->pMethods->xLock(pReal, SQLITE_LOCK_EXCLUSIVE); } } #if defined(_WIN32_WCE) static LPWSTR rbuWinUtf8ToUnicode(const char *zFilename){ int nChar; LPWSTR zWideFilename; |
︙ | ︙ | |||
3221 3222 3223 3224 3225 3226 3227 | /* 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. */ | | > | | | | | | | | > > > > | > | > > > | > | | > > > | > > | < | | > | < < < < | | < | | | > | 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 | /* 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. */ rbuLockDatabase(p); if( p->rc==SQLITE_OK ){ 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; #if defined(_WIN32_WCE) { LPWSTR zWideOal; LPWSTR zWideWal; zWideOal = rbuWinUtf8ToUnicode(zOal); if( zWideOal ){ zWideWal = rbuWinUtf8ToUnicode(zWal); if( zWideWal ){ if( MoveFileW(zWideOal, zWideWal) ){ p->rc = SQLITE_OK; }else{ p->rc = SQLITE_IOERR; } sqlite3_free(zWideWal); }else{ p->rc = SQLITE_IOERR_NOMEM; } sqlite3_free(zWideOal); }else{ p->rc = SQLITE_IOERR_NOMEM; } } #else p->rc = rename(zOal, zWal) ? SQLITE_IOERR : SQLITE_OK; #endif if( p->rc==SQLITE_OK ){ rbuOpenDatabase(p, 0); rbuSetupCheckpoint(p, 0); } } } sqlite3_free(zWal); sqlite3_free(zOal); } |
︙ | ︙ | |||
3601 3602 3603 3604 3605 3606 3607 | 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, | | | | | 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 | 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_master 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_master WHERE rootpage=0 OR rootpage IS NULL" ); } if( p->rc==SQLITE_OK ){ p->rc = prepareAndCollectError(p->dbMain, &pInsert, &p->zErrmsg, "INSERT INTO sqlite_master 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)); |
︙ | ︙ | |||
3826 3827 3828 3829 3830 3831 3832 | ** If there is a "*-oal" file in the file-system corresponding to the ** target database in the file-system, delete it. If an error occurs, ** leave an error code and error message in the rbu handle. */ static void rbuDeleteOalFile(sqlite3rbu *p){ char *zOal = rbuMPrintf(p, "%s-oal", p->zTarget); if( zOal ){ | | < | 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 | ** If there is a "*-oal" file in the file-system corresponding to the ** target database in the file-system, delete it. If an error occurs, ** leave an error code and error message in the rbu handle. */ static void rbuDeleteOalFile(sqlite3rbu *p){ char *zOal = rbuMPrintf(p, "%s-oal", p->zTarget); if( zOal ){ sqlite3_vfs *pVfs = sqlite3_vfs_find(0); assert( pVfs && p->rc==SQLITE_OK && p->zErrmsg==0 ); pVfs->xDelete(pVfs, zOal, 0); sqlite3_free(zOal); } } /* |
︙ | ︙ | |||
3881 3882 3883 3884 3885 3886 3887 | int nVal, sqlite3_value **apVal ){ sqlite3rbu *p = (sqlite3rbu*)sqlite3_user_data(pCtx); sqlite3_stmt *pStmt = 0; char *zErrmsg = 0; int rc; | < | | | | 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 | int nVal, sqlite3_value **apVal ){ sqlite3rbu *p = (sqlite3rbu*)sqlite3_user_data(pCtx); sqlite3_stmt *pStmt = 0; char *zErrmsg = 0; int rc; assert( nVal==1 ); rc = prepareFreeAndCollectError(p->dbMain, &pStmt, &zErrmsg, sqlite3_mprintf("SELECT count(*) FROM sqlite_master " "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(p->dbMain), -1); } } sqlite3_free(zErrmsg); } /* |
︙ | ︙ | |||
3937 3938 3939 3940 3941 3942 3943 | "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, | | | 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 | "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_master WHERE tbl_name = 'rbu_count'" ); } if( p->rc==SQLITE_OK ){ if( SQLITE_ROW==sqlite3_step(pStmt) ){ bExists = 1; } p->rc = sqlite3_finalize(pStmt); |
︙ | ︙ | |||
3979 3980 3981 3982 3983 3984 3985 | p = (sqlite3rbu*)sqlite3_malloc64(nByte); if( p ){ RbuState *pState = 0; /* Create the custom VFS. */ memset(p, 0, sizeof(sqlite3rbu)); | < | 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 | p = (sqlite3rbu*)sqlite3_malloc64(nByte); if( p ){ RbuState *pState = 0; /* Create the custom VFS. */ memset(p, 0, sizeof(sqlite3rbu)); rbuCreateVfs(p); /* Open the target, RBU and state databases */ if( p->rc==SQLITE_OK ){ char *pCsr = (char*)&p[1]; int bRetry = 0; if( zTarget ){ |
︙ | ︙ | |||
4005 4006 4007 4008 4009 4010 4011 | /* 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. */ | | | | 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 | /* 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, &bRetry); if( bRetry ){ rbuOpenDatabase(p, 0); } } if( p->rc==SQLITE_OK ){ pState = rbuLoadState(p); assert( pState || p->rc!=SQLITE_OK ); if( p->rc==SQLITE_OK ){ |
︙ | ︙ | |||
4102 4103 4104 4105 4106 4107 4108 | if( p->rc==SQLITE_OK ){ rbuSetupOal(p, pState); } } }else if( p->eStage==RBU_STAGE_MOVE ){ /* no-op */ }else if( p->eStage==RBU_STAGE_CKPT ){ | < < < < < < < < | 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 | 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; } } |
︙ | ︙ | |||
4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 | */ 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( | > | 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 | */ sqlite3rbu *sqlite3rbu_open( const char *zTarget, const char *zRbu, const char *zState ){ if( zTarget==0 || zRbu==0 ){ return rbuMisuseError(); } /* TODO: Check that zTarget and zRbu are non-NULL */ return openRbuHandle(zTarget, zRbu, zState); } /* ** Open a handle to begin or resume an RBU VACUUM operation. */ sqlite3rbu *sqlite3rbu_vacuum( |
︙ | ︙ | |||
4371 4372 4373 4374 4375 4376 4377 | if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbMain, "BEGIN IMMEDIATE", 0, 0,0); } p->rc = rc; return rc; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 | if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbMain, "BEGIN IMMEDIATE", 0, 0,0); } p->rc = rc; return rc; } /************************************************************************** ** Beginning of RBU VFS shim methods. The VFS shim modifies the behaviour ** of a standard VFS in the following ways: ** ** 1. Whenever the first page of a main database file is read or ** written, the value of the change-counter cookie is stored in ** rbu_file.iCookie. Similarly, the value of the "write-version" |
︙ | ︙ | |||
4475 4476 4477 4478 4479 4480 4481 | ** all xWrite() calls on the target database file perform no IO. ** Instead the frame and page numbers that would be read and written ** are recorded. Additionally, successful attempts to obtain exclusive ** xShmLock() WRITER, CHECKPOINTER and READ0 locks on the target ** database file are recorded. xShmLock() calls to unlock the same ** locks are no-ops (so that once obtained, these locks are never ** relinquished). Finally, calls to xSync() on the target database | | | 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 | ** all xWrite() calls on the target database file perform no IO. ** Instead the frame and page numbers that would be read and written ** are recorded. Additionally, successful attempts to obtain exclusive ** xShmLock() WRITER, CHECKPOINTER and READ0 locks on the target ** database file are recorded. xShmLock() calls to unlock the same ** locks are no-ops (so that once obtained, these locks are never ** relinquished). Finally, calls to xSync() on the target database ** file fail with SQLITE_INTERNAL errors. */ static void rbuUnlockShm(rbu_file *p){ assert( p->openFlags & SQLITE_OPEN_MAIN_DB ); if( p->pRbu ){ int (*xShmLock)(sqlite3_file*,int,int,int) = p->pReal->pMethods->xShmLock; int i; |
︙ | ︙ | |||
4584 4585 4586 4587 4588 4589 4590 | sqlite3_free(p->apShm[i]); } sqlite3_free(p->apShm); p->apShm = 0; sqlite3_free(p->zDel); if( p->openFlags & SQLITE_OPEN_MAIN_DB ){ | < < | < | 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 | sqlite3_free(p->apShm[i]); } sqlite3_free(p->apShm); p->apShm = 0; sqlite3_free(p->zDel); if( p->openFlags & SQLITE_OPEN_MAIN_DB ){ rbuMainlistRemove(p); rbuUnlockShm(p); p->pReal->pMethods->xShmUnmap(p->pReal, 0); } else if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){ rbuUpdateTempSize(p, 0); } assert( p->pMainNext==0 && p->pRbuVfs->pMain!=p ); /* Close the underlying file handle */ |
︙ | ︙ | |||
4757 4758 4759 4760 4761 4762 4763 | /* ** Sync an rbuVfs-file. */ static int rbuVfsSync(sqlite3_file *pFile, int flags){ rbu_file *p = (rbu_file *)pFile; if( p->pRbu && p->pRbu->eStage==RBU_STAGE_CAPTURE ){ if( p->openFlags & SQLITE_OPEN_MAIN_DB ){ | | | 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 | /* ** Sync an rbuVfs-file. */ static int rbuVfsSync(sqlite3_file *pFile, int flags){ rbu_file *p = (rbu_file *)pFile; if( p->pRbu && p->pRbu->eStage==RBU_STAGE_CAPTURE ){ if( p->openFlags & SQLITE_OPEN_MAIN_DB ){ return SQLITE_INTERNAL; } return SQLITE_OK; } return p->pReal->pMethods->xSync(p->pReal, flags); } /* |
︙ | ︙ | |||
4853 4854 4855 4856 4857 4858 4859 | 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; | > | > | 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 | 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; if( p->openFlags & SQLITE_OPEN_MAIN_DB ){ rbuMainlistAdd(p); } if( p->pWalFd ) p->pWalFd->pRbu = pRbu; rc = SQLITE_OK; } } return rc; } else if( op==SQLITE_FCNTL_RBUCNT ){ |
︙ | ︙ | |||
4908 4909 4910 4911 4912 4913 4914 | int rc = SQLITE_OK; #ifdef SQLITE_AMALGAMATION assert( WAL_CKPT_LOCK==1 ); #endif assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) ); | < < | < < | < < > > > > | > > > | | 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 | 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) ){ /* Magic number 1 is the WAL_CKPT_LOCK lock. Preventing SQLite from ** taking this lock also prevents any checkpoints from occurring. ** todo: really, it's not clear why this might occur, as ** wal_autocheckpoint ought to be turned off. */ if( ofst==WAL_LOCK_CKPT && n==1 ) rc = SQLITE_BUSY; }else{ int bCapture = 0; if( n==1 && (flags & SQLITE_SHM_EXCLUSIVE) && pRbu && pRbu->eStage==RBU_STAGE_CAPTURE && (ofst==WAL_LOCK_WRITE || ofst==WAL_LOCK_CKPT || ofst==WAL_LOCK_READ0) ){ 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 << ofst); } } } return rc; } |
︙ | ︙ | |||
4951 4952 4953 4954 4955 4956 4957 | 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) ); | | > | | < < < < < < | | | | | | | | > | | 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 | 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 || eStage==RBU_STAGE_MOVE ){ if( iRegion<=p->nShm ){ sqlite3_int64 nByte = (iRegion+1) * sizeof(char*); char **apNew = (char**)sqlite3_realloc64(p->apShm, nByte); 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 && p->apShm[iRegion]==0 ){ char *pNew = (char*)sqlite3_malloc64(szRegion); if( pNew==0 ){ rc = SQLITE_NOMEM; }else{ memset(pNew, 0, szRegion); p->apShm[iRegion] = pNew; } |
︙ | ︙ | |||
5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 | }else{ /* 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, | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | }else{ /* Release the checkpointer and writer locks */ rbuUnlockShm(p); rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag); } return rc; } /* ** A main database named zName has just been opened. The following ** function returns a pointer 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. */ static const char *rbuMainToWal(const char *zName, int flags){ int n = (int)strlen(zName); const char *z = &zName[n]; if( flags & SQLITE_OPEN_URI ){ int odd = 0; while( 1 ){ if( z[0]==0 ){ odd = 1 - odd; if( odd && z[1]==0 ) break; } z++; } z += 2; }else{ while( *z==0 ) z++; } z += (n + 8 + 1); return z; } /* ** Open an rbu file handle. */ static int rbuVfsOpen( sqlite3_vfs *pVfs, const char *zName, |
︙ | ︙ | |||
5048 5049 5050 5051 5052 5053 5054 | rbuVfsDeviceCharacteristics, /* xDeviceCharacteristics */ rbuVfsShmMap, /* xShmMap */ rbuVfsShmLock, /* xShmLock */ rbuVfsShmBarrier, /* xShmBarrier */ rbuVfsShmUnmap, /* xShmUnmap */ 0, 0 /* xFetch, xUnfetch */ }; | < < < < < < < < < < < < < < < < < < < | | > > > > | > | < > | > > > | > > > > > > | 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 | rbuVfsDeviceCharacteristics, /* xDeviceCharacteristics */ rbuVfsShmMap, /* xShmMap */ rbuVfsShmLock, /* xShmLock */ rbuVfsShmBarrier, /* xShmBarrier */ rbuVfsShmUnmap, /* xShmUnmap */ 0, 0 /* xFetch, xUnfetch */ }; rbu_vfs *pRbuVfs = (rbu_vfs*)pVfs; sqlite3_vfs *pRealVfs = pRbuVfs->pRealVfs; rbu_file *pFd = (rbu_file *)pFile; int rc = SQLITE_OK; const char *zOpen = zName; int oflags = flags; memset(pFd, 0, sizeof(rbu_file)); pFd->pReal = (sqlite3_file*)&pFd[1]; pFd->pRbuVfs = pRbuVfs; pFd->openFlags = flags; 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 = rbuMainToWal(zName, flags); } 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. This ** code ensures that the string passed to xOpen() is terminated by a ** pair of '\0' bytes in case the VFS attempts to extract a URI ** parameter from it. */ const char *zBase = zName; size_t nCopy; char *zCopy; if( rbuIsVacuum(pDb->pRbu) ){ zBase = sqlite3_db_filename(pDb->pRbu->dbRbu, "main"); zBase = rbuMainToWal(zBase, SQLITE_OPEN_URI); } nCopy = strlen(zBase); zCopy = sqlite3_malloc64(nCopy+2); if( zCopy ){ memcpy(zCopy, zBase, nCopy); zCopy[nCopy-3] = 'o'; zCopy[nCopy] = '\0'; zCopy[nCopy+1] = '\0'; zOpen = (const char*)(pFd->zDel = zCopy); }else{ rc = SQLITE_NOMEM; } pFd->pRbu = pDb->pRbu; } pDb->pWalFd = pFd; } } }else{ pFd->pRbu = pRbuVfs->pRbu; |
︙ | ︙ | |||
5121 5122 5123 5124 5125 5126 5127 | zOpen = 0; } if( rc==SQLITE_OK ){ rc = pRealVfs->xOpen(pRealVfs, zOpen, pFd->pReal, oflags, pOutFlags); } if( pFd->pReal->pMethods ){ | < < < < | < | 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 | zOpen = 0; } if( rc==SQLITE_OK ){ rc = pRealVfs->xOpen(pRealVfs, zOpen, pFd->pReal, oflags, pOutFlags); } if( pFd->pReal->pMethods ){ /* The xOpen() operation has succeeded. Set the sqlite3_file.pMethods ** pointer and, if the file is a main database file, link it into the ** mutex protected linked list of all such files. */ pFile->pMethods = &rbuvfs_io_methods; if( flags & SQLITE_OPEN_MAIN_DB ){ rbuMainlistAdd(pFd); } }else{ sqlite3_free(pFd->zDel); } |
︙ | ︙ | |||
5180 5181 5182 5183 5184 5185 5186 | ** 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); | | < | 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 | ** 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 && pDb->pRbu->eStage==RBU_STAGE_OAL ){ if( *pResOut ){ rc = SQLITE_CANTOPEN; }else{ sqlite3_int64 sz = 0; rc = rbuVfsFileSize(&pDb->base, &sz); *pResOut = (sz>0); } |
︙ | ︙ |
Changes to ext/rbu/sqlite3rbu.h.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 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. ** ************************************************************************* ** | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 | /* ** 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. ** ************************************************************************* ** ** This file contains the public interface for the RBU extension. */ /* ** SUMMARY ** ** Writing a transaction containing a large number of operations on ** b-tree indexes that are collectively larger than the available cache ** memory can be very inefficient. ** ** The problem is that in order to update a b-tree, the leaf page (at least) ** containing the entry being inserted or deleted must be modified. If the ** working set of leaves is larger than the available cache memory, then a ** single leaf that is modified more than once as part of the transaction ** may be loaded from or written to the persistent media multiple times. ** Additionally, because the index updates are likely to be applied in ** random order, access to pages within the database is also likely to be in ** random order, which is itself quite inefficient. ** ** One way to improve the situation is to sort the operations on each index ** by index key before applying them to the b-tree. This leads to an IO ** pattern that resembles a single linear scan through the index b-tree, ** and all but guarantees each modified leaf page is loaded and stored ** exactly once. SQLite uses this trick to improve the performance of ** CREATE INDEX commands. This extension allows it to be used to improve ** the performance of large transactions on existing databases. ** ** Additionally, this extension allows the work involved in writing the ** large transaction to be broken down into sub-transactions performed ** sequentially by separate processes. This is useful if the system cannot ** guarantee that a single update process will run for long enough to apply ** the entire update, for example because the update is being applied on a ** mobile device that is frequently rebooted. Even after the writer process ** has committed one or more sub-transactions, other database clients continue ** to read from the original database snapshot. In other words, partially ** applied transactions are not visible to other clients. ** ** "RBU" stands for "Resumable Bulk Update". As in a large database update ** transmitted via a wireless network to a mobile device. A transaction ** applied using this extension is hence refered to as an "RBU update". ** ** ** LIMITATIONS ** ** An "RBU update" transaction is subject to the following limitations: ** ** * The transaction must consist of INSERT, UPDATE and DELETE operations ** only. ** ** * INSERT statements may not use any default values. ** ** * UPDATE and DELETE statements must identify their target rows by ** non-NULL PRIMARY KEY values. Rows with NULL values stored in PRIMARY ** KEY fields may not be updated or deleted. If the table being written ** has no PRIMARY KEY, affected rows must be identified by rowid. ** ** * UPDATE statements may not modify PRIMARY KEY columns. ** ** * No triggers will be fired. ** ** * No foreign key violations are detected or reported. ** ** * CHECK constraints are not enforced. ** ** * No constraint handling mode except for "OR ROLLBACK" is supported. ** ** ** PREPARATION ** ** An "RBU update" is stored as a separate SQLite database. A database ** containing an RBU update is an "RBU database". For each table in the ** target database to be updated, the RBU database should contain a table ** named "data_<target name>" containing the same set of columns as the ** target table, and one more - "rbu_control". The data_% table should ** have no PRIMARY KEY or UNIQUE constraints, but each column should have ** the same type as the corresponding column in the target database. ** The "rbu_control" column should have no type at all. For example, if ** the target database contains: ** ** CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT, c UNIQUE); ** ** Then the RBU database should contain: ** ** CREATE TABLE data_t1(a INTEGER, b TEXT, c, rbu_control); ** ** The order of the columns in the data_% table does not matter. ** ** Instead of a regular table, the RBU database may also contain virtual ** tables or view named using the data_<target> naming scheme. ** ** Instead of the plain data_<target> naming scheme, RBU database tables ** may also be named data<integer>_<target>, where <integer> is any sequence ** of zero or more numeric characters (0-9). This can be significant because ** tables within the RBU database are always processed in order sorted by ** name. By judicious selection of the <integer> portion of the names ** of the RBU tables the user can therefore control the order in which they ** are processed. This can be useful, for example, to ensure that "external ** content" FTS4 tables are updated before their underlying content tables. ** ** If the target database table is a virtual table or a table that has no ** PRIMARY KEY declaration, the data_% table must also contain a column ** named "rbu_rowid". This column is mapped to the tables implicit primary ** key column - "rowid". Virtual tables for which the "rowid" column does ** not function like a primary key value cannot be updated using RBU. For ** example, if the target db contains either of the following: ** ** CREATE VIRTUAL TABLE x1 USING fts3(a, b); ** CREATE TABLE x1(a, b) ** ** then the RBU database should contain: ** |
︙ | ︙ | |||
132 133 134 135 136 137 138 | ** CREATE VIRTUAL TABLE ft1 USING fts4(a, b, languageid='langid'); ** ** Either of the following input table schemas may be used: ** ** CREATE TABLE data_ft1(a, b, langid, rbu_rowid, rbu_control); ** CREATE TABLE data_ft1(a, b, rbu_rowid, rbu_control); ** | | | | | | | | | | | | | | | | | | | 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 | ** CREATE VIRTUAL TABLE ft1 USING fts4(a, b, languageid='langid'); ** ** Either of the following input table schemas may be used: ** ** CREATE TABLE data_ft1(a, b, langid, rbu_rowid, rbu_control); ** CREATE TABLE data_ft1(a, b, rbu_rowid, rbu_control); ** ** For each row to INSERT into the target database as part of the RBU ** update, the corresponding data_% table should contain a single record ** with the "rbu_control" column set to contain integer value 0. The ** other columns should be set to the values that make up the new record ** to insert. ** ** If the target database table has an INTEGER PRIMARY KEY, it is not ** possible to insert a NULL value into the IPK column. Attempting to ** do so results in an SQLITE_MISMATCH error. ** ** For each row to DELETE from the target database as part of the RBU ** update, the corresponding data_% table should contain a single record ** with the "rbu_control" column set to contain integer value 1. The ** real primary key values of the row to delete should be stored in the ** corresponding columns of the data_% table. The values stored in the ** other columns are not used. ** ** For each row to UPDATE from the target database as part of the RBU ** update, the corresponding data_% table should contain a single record ** with the "rbu_control" column set to contain a value of type text. ** The real primary key values identifying the row to update should be ** stored in the corresponding columns of the data_% table row, as should ** the new values of all columns being update. The text value in the ** "rbu_control" column must contain the same number of characters as ** there are columns in the target database table, and must consist entirely ** of 'x' and '.' characters (or in some special cases 'd' - see below). For ** each column that is being updated, the corresponding character is set to ** 'x'. For those that remain as they are, the corresponding character of the ** rbu_control value should be set to '.'. For example, given the tables ** above, the update statement: ** ** UPDATE t1 SET c = 'usa' WHERE a = 4; ** ** is represented by the data_t1 row created by: ** ** INSERT INTO data_t1(a, b, c, rbu_control) VALUES(4, NULL, 'usa', '..x'); ** ** Instead of an 'x' character, characters of the rbu_control value specified ** for UPDATEs may also be set to 'd'. In this case, instead of updating the ** target table with the value stored in the corresponding data_% column, the ** user-defined SQL function "rbu_delta()" is invoked and the result stored in ** the target table column. rbu_delta() is invoked with two arguments - the ** original value currently stored in the target table column and the ** value specified in the data_xxx table. ** ** For example, this row: ** ** INSERT INTO data_t1(a, b, c, rbu_control) VALUES(4, NULL, 'usa', '..d'); ** ** is similar to an UPDATE statement such as: ** ** UPDATE t1 SET c = rbu_delta(c, 'usa') WHERE a = 4; ** ** Finally, if an 'f' character appears in place of a 'd' or 's' in an ** ota_control string, the contents of the data_xxx table column is assumed ** to be a "fossil delta" - a patch to be applied to a blob value in the ** format used by the fossil source-code management system. In this case ** the existing value within the target database table must be of type BLOB. ** It is replaced by the result of applying the specified fossil delta to ** itself. ** ** If the target database table is a virtual table or a table with no PRIMARY ** KEY, the rbu_control value should not include a character corresponding ** to the rbu_rowid value. For example, this: ** ** INSERT INTO data_ft1(a, b, rbu_rowid, rbu_control) ** VALUES(NULL, 'usa', 12, '.x'); ** ** causes a result similar to: ** ** UPDATE ft1 SET b = 'usa' WHERE rowid = 12; ** ** The data_xxx tables themselves should have no PRIMARY KEY declarations. |
︙ | ︙ | |||
539 540 541 542 543 544 545 | #define SQLITE_RBU_STATE_OAL 1 #define SQLITE_RBU_STATE_MOVE 2 #define SQLITE_RBU_STATE_CHECKPOINT 3 #define SQLITE_RBU_STATE_DONE 4 #define SQLITE_RBU_STATE_ERROR 5 SQLITE_API int sqlite3rbu_state(sqlite3rbu *pRbu); | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 539 540 541 542 543 544 545 546 547 548 549 550 551 552 | #define SQLITE_RBU_STATE_OAL 1 #define SQLITE_RBU_STATE_MOVE 2 #define SQLITE_RBU_STATE_CHECKPOINT 3 #define SQLITE_RBU_STATE_DONE 4 #define SQLITE_RBU_STATE_ERROR 5 SQLITE_API int sqlite3rbu_state(sqlite3rbu *pRbu); /* ** Create an RBU VFS named zName that accesses the underlying file-system ** via existing VFS zParent. Or, if the zParent parameter is passed NULL, ** then the new RBU VFS uses the default system VFS to access the file-system. ** The new object is registered as a non-default VFS with SQLite before ** returning. |
︙ | ︙ |
Changes to ext/rbu/test_rbu.c.
︙ | ︙ | |||
22 23 24 25 26 27 28 | #else # include "tcl.h" # ifndef SQLITE_TCLAPI # define SQLITE_TCLAPI # endif #endif #include <assert.h> | < < < < < < < < | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #else # include "tcl.h" # ifndef SQLITE_TCLAPI # define SQLITE_TCLAPI # endif #endif #include <assert.h> /* From main.c */ extern const char *sqlite3ErrName(int); extern int sqlite3TestMakePointerStr(Tcl_Interp*, char*, void*); void test_rbu_delta(sqlite3_context *pCtx, int nArg, sqlite3_value **apVal){ Tcl_Interp *interp = (Tcl_Interp*)sqlite3_user_data(pCtx); |
︙ | ︙ | |||
59 60 61 62 63 64 65 | }else{ Tcl_BackgroundError(interp); } Tcl_DecrRefCount(pScript); } | < < < < < < < < < < < < < < < | < | 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 | }else{ Tcl_BackgroundError(interp); } Tcl_DecrRefCount(pScript); } static int SQLITE_TCLAPI test_sqlite3rbu_cmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int ret = TCL_OK; sqlite3rbu *pRbu = (sqlite3rbu*)clientData; struct RbuCmd { const char *zName; int nArg; const char *zUsage; } aCmd[] = { {"step", 2, ""}, /* 0 */ {"close", 2, ""}, /* 1 */ {"create_rbu_delta", 2, ""}, /* 2 */ {"savestate", 2, ""}, /* 3 */ {"dbMain_eval", 3, "SQL"}, /* 4 */ {"bp_progress", 2, ""}, /* 5 */ {"db", 3, "RBU"}, /* 6 */ {"state", 2, ""}, /* 7 */ {"progress", 2, ""}, /* 8 */ {"close_no_error", 2, ""}, /* 9 */ {"temp_size_limit", 3, "LIMIT"}, /* 10 */ {"temp_size", 2, ""}, /* 11 */ {"dbRbu_eval", 3, "SQL"}, /* 12 */ {0,0,0} }; int iCmd; if( objc<2 ){ Tcl_WrongNumArgs(interp, 1, objv, "METHOD"); return TCL_ERROR; |
︙ | ︙ | |||
147 148 149 150 151 152 153 | Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); if( zErrmsg ){ Tcl_AppendResult(interp, " - ", zErrmsg, 0); sqlite3_free(zErrmsg); } ret = TCL_ERROR; } | < < | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); if( zErrmsg ){ Tcl_AppendResult(interp, " - ", zErrmsg, 0); sqlite3_free(zErrmsg); } ret = TCL_ERROR; } break; } case 2: /* create_rbu_delta */ { sqlite3 *db = sqlite3rbu_db(pRbu, 0); int rc = sqlite3_create_function( db, "rbu_delta", -1, SQLITE_UTF8, (void*)interp, test_rbu_delta, 0, 0 |
︙ | ︙ | |||
236 237 238 239 240 241 242 | } case 11: /* temp_size */ { sqlite3_int64 sz = sqlite3rbu_temp_size(pRbu); Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sz)); break; } | < < < < < < < < < < < < < < < < < < < < < < < < < | 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | } case 11: /* temp_size */ { sqlite3_int64 sz = sqlite3rbu_temp_size(pRbu); Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sz)); break; } default: /* seems unlikely */ assert( !"cannot happen" ); break; } return ret; } /* ** Tclcmd: sqlite3rbu CMD <target-db> <rbu-db> ?<state-db>? */ static int SQLITE_TCLAPI test_sqlite3rbu( ClientData clientData, Tcl_Interp *interp, int objc, |
︙ | ︙ | |||
294 295 296 297 298 299 300 | } zCmd = Tcl_GetString(objv[1]); zTarget = Tcl_GetString(objv[2]); zRbu = Tcl_GetString(objv[3]); if( objc==5 ) zStateDb = Tcl_GetString(objv[4]); pRbu = sqlite3rbu_open(zTarget, zRbu, zStateDb); | | | 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 | } zCmd = Tcl_GetString(objv[1]); zTarget = Tcl_GetString(objv[2]); zRbu = Tcl_GetString(objv[3]); if( objc==5 ) zStateDb = Tcl_GetString(objv[4]); pRbu = sqlite3rbu_open(zTarget, zRbu, zStateDb); Tcl_CreateObjCommand(interp, zCmd, test_sqlite3rbu_cmd, (ClientData)pRbu, 0); Tcl_SetObjResult(interp, objv[1]); return TCL_OK; } /* ** Tclcmd: sqlite3rbu_vacuum CMD <target-db> <state-db> */ |
︙ | ︙ | |||
323 324 325 326 327 328 329 | } zCmd = Tcl_GetString(objv[1]); zTarget = Tcl_GetString(objv[2]); if( objc==4 ) zStateDb = Tcl_GetString(objv[3]); if( zStateDb && zStateDb[0]=='\0' ) zStateDb = 0; pRbu = sqlite3rbu_vacuum(zTarget, zStateDb); | | | 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | } zCmd = Tcl_GetString(objv[1]); zTarget = Tcl_GetString(objv[2]); if( objc==4 ) zStateDb = Tcl_GetString(objv[3]); if( zStateDb && zStateDb[0]=='\0' ) zStateDb = 0; pRbu = sqlite3rbu_vacuum(zTarget, zStateDb); Tcl_CreateObjCommand(interp, zCmd, test_sqlite3rbu_cmd, (ClientData)pRbu, 0); Tcl_SetObjResult(interp, objv[1]); return TCL_OK; } /* ** Tclcmd: sqlite3rbu_create_vfs ?-default? NAME PARENT */ |
︙ | ︙ |
Deleted ext/recover/dbdata.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/recover/recover1.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/recover/recover_common.tcl.
|
| < < < < < < < < < < < < < < |
Deleted ext/recover/recoverclobber.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/recover/recovercorrupt.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/recover/recovercorrupt2.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/recover/recoverfault.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/recover/recoverfault2.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/recover/recoverold.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/recover/recoverpgsz.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/recover/recoverrowid.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/recover/recoverslowidx.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/recover/recoversql.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/recover/sqlite3recover.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/recover/sqlite3recover.h.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/recover/test_recover.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
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 | SQLITE_EXTENSION_INIT1 #ifndef SQLITE_AMALGAMATION # include <string.h> # include <stdio.h> # include <stdlib.h> # include <assert.h> # define ALWAYS(X) 1 # define NEVER(X) 0 typedef unsigned char u8; typedef unsigned short u16; 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_master 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/repair/sqlite3_checker.c.in.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** Read an SQLite database file and analyze its space utilization. Generate ** text on standard output. */ #define TCLSH_INIT_PROC sqlite3_checker_init_proc #define SQLITE_ENABLE_DBPAGE_VTAB 1 #undef SQLITE_THREADSAFE #define SQLITE_THREADSAFE 0 #undef SQLITE_ENABLE_COLUMN_METADATA #define SQLITE_OMIT_DECLTYPE 1 #define SQLITE_OMIT_DEPRECATED 1 #define SQLITE_OMIT_PROGRESS_CALLBACK 1 #define SQLITE_OMIT_SHARED_CACHE 1 | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /* ** Read an SQLite database file and analyze its space utilization. Generate ** text on standard output. */ #define TCLSH_INIT_PROC sqlite3_checker_init_proc #define SQLITE_ENABLE_DBPAGE_VTAB 1 #define SQLITE_ENABLE_JSON1 1 #undef SQLITE_THREADSAFE #define SQLITE_THREADSAFE 0 #undef SQLITE_ENABLE_COLUMN_METADATA #define SQLITE_OMIT_DECLTYPE 1 #define SQLITE_OMIT_DEPRECATED 1 #define SQLITE_OMIT_PROGRESS_CALLBACK 1 #define SQLITE_OMIT_SHARED_CACHE 1 |
︙ | ︙ |
Changes to ext/rtree/geopoly.c.
︙ | ︙ | |||
22 23 24 25 26 27 28 | #ifdef GEOPOLY_ENABLE_DEBUG static int geo_debug = 0; # define GEODEBUG(X) if(geo_debug)printf X #else # define GEODEBUG(X) #endif | > > > | > < | 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 | #ifdef GEOPOLY_ENABLE_DEBUG static int geo_debug = 0; # define GEODEBUG(X) if(geo_debug)printf X #else # define GEODEBUG(X) #endif #ifndef JSON_NULL /* The following stuff repeats things found in json1 */ /* ** 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 */ # define safe_isdigit(x) sqlite3Isdigit(x) # define safe_isalnum(x) sqlite3Isalnum(x) # define safe_isxdigit(x) sqlite3Isxdigit(x) #else /* Use the standard library for separate compilation */ #include <ctype.h> /* amalgamator: keep */ # define safe_isdigit(x) isdigit((unsigned char)(x)) # define safe_isalnum(x) isalnum((unsigned char)(x)) # define safe_isxdigit(x) isxdigit((unsigned char)(x)) #endif /* ** Growing our own isspace() routine this way is twice as fast as ** the library isspace() function. */ static const char geopolyIsSpace[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
︙ | ︙ | |||
60 61 62 63 64 65 66 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; | | | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; #define safe_isspace(x) (geopolyIsSpace[(unsigned char)x]) #endif /* JSON NULL - back to original code */ /* Compiler and version */ #ifndef GCC_VERSION #if defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC) # define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__) #else |
︙ | ︙ | |||
149 150 151 152 153 154 155 | t = a[1]; a[1] = a[2]; a[2] = t; } /* Skip whitespace. Return the next non-whitespace character. */ static char geopolySkipSpace(GeoParse *p){ | | | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | t = a[1]; a[1] = a[2]; a[2] = t; } /* Skip whitespace. Return the next non-whitespace character. */ static char geopolySkipSpace(GeoParse *p){ while( safe_isspace(p->z[0]) ) p->z++; return p->z[0]; } /* Parse out a number. Write the value into *pVal if pVal!=0. ** return non-zero on success and zero if the next token is not a number. */ static int geopolyParseNumber(GeoParse *p, GeoCoord *pVal){ |
︙ | ︙ | |||
298 299 300 301 302 303 304 | 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; | < | < < < < | 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | 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; |
︙ | ︙ | |||
358 359 360 361 362 363 364 | */ static void geopolyBlobFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); | < < | 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 | */ static void geopolyBlobFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); if( p ){ sqlite3_result_blob(context, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT); sqlite3_free(p); } } /* ** SQL function: geopoly_json(X) ** ** Interpret X as a polygon and render it as a JSON array ** of coordinates. Or, if X is not a valid polygon, return NULL. */ static void geopolyJsonFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ 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)); |
︙ | ︙ | |||
460 461 462 463 464 465 466 | double B = sqlite3_value_double(argv[2]); double C = sqlite3_value_double(argv[3]); 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; | < | 456 457 458 459 460 461 462 463 464 465 466 467 468 469 | double B = sqlite3_value_double(argv[2]); double C = sqlite3_value_double(argv[3]); 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; |
︙ | ︙ | |||
511 512 513 514 515 516 517 | */ static void geopolyAreaFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); | < | 506 507 508 509 510 511 512 513 514 515 516 517 518 519 | */ static void geopolyAreaFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); if( p ){ sqlite3_result_double(context, geopolyArea(p)); sqlite3_free(p); } } /* |
︙ | ︙ | |||
537 538 539 540 541 542 543 | */ static void geopolyCcwFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); | < | 531 532 533 534 535 536 537 538 539 540 541 542 543 544 | */ static void geopolyCcwFunc( sqlite3_context *context, 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; |
︙ | ︙ | |||
592 593 594 595 596 597 598 | ){ double x = sqlite3_value_double(argv[0]); double y = sqlite3_value_double(argv[1]); double r = sqlite3_value_double(argv[2]); int n = sqlite3_value_int(argv[3]); int i; GeoPoly *p; | < | 585 586 587 588 589 590 591 592 593 594 595 596 597 598 | ){ double x = sqlite3_value_double(argv[0]); double y = sqlite3_value_double(argv[1]); double r = sqlite3_value_double(argv[2]); int n = sqlite3_value_int(argv[3]); int i; GeoPoly *p; if( n<3 || r<=0.0 ) return; if( n>1000 ) n = 1000; p = sqlite3_malloc64( sizeof(*p) + (n-1)*2*sizeof(GeoCoord) ); if( p==0 ){ sqlite3_result_error_nomem(context); return; |
︙ | ︙ | |||
687 688 689 690 691 692 693 | }else{ sqlite3_free(p); aCoord[0].f = mnX; aCoord[1].f = mxX; aCoord[2].f = mnY; aCoord[3].f = mxY; } | < < < | 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 | }else{ sqlite3_free(p); aCoord[0].f = mnX; aCoord[1].f = mxX; aCoord[2].f = mnY; aCoord[3].f = mxY; } } return pOut; } /* ** Implementation of the geopoly_bbox(X) SQL function. */ static void geopolyBBoxFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyBBox(context, argv[0], 0, 0); if( p ){ sqlite3_result_blob(context, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT); sqlite3_free(p); } } |
︙ | ︙ | |||
730 731 732 733 734 735 736 | static void geopolyBBoxStep( sqlite3_context *context, int argc, sqlite3_value **argv ){ RtreeCoord a[4]; int rc = SQLITE_OK; | < | 719 720 721 722 723 724 725 726 727 728 729 730 731 732 | static void geopolyBBoxStep( sqlite3_context *context, int argc, sqlite3_value **argv ){ RtreeCoord a[4]; int rc = SQLITE_OK; (void)geopolyBBox(context, argv[0], a, &rc); if( rc==SQLITE_OK ){ GeoBBox *pBBox; pBBox = (GeoBBox*)sqlite3_aggregate_context(context, sizeof(*pBBox)); if( pBBox==0 ) return; if( pBBox->isInit==0 ){ pBBox->isInit = 1; |
︙ | ︙ | |||
819 820 821 822 823 824 825 | ){ GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0); double x0 = sqlite3_value_double(argv[1]); double y0 = sqlite3_value_double(argv[2]); int v = 0; int cnt = 0; int ii; | < < | 807 808 809 810 811 812 813 814 815 816 817 818 819 820 | ){ GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0); 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; } |
︙ | ︙ | |||
860 861 862 863 864 865 866 | static void geopolyWithinFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0); GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0); | < | 846 847 848 849 850 851 852 853 854 855 856 857 858 859 | static void geopolyWithinFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0); GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0); if( p1 && p2 ){ int x = geopolyOverlap(p1, p2); if( x<0 ){ sqlite3_result_error_nomem(context); }else{ sqlite3_result_int(context, x==2 ? 1 : x==4 ? 2 : 0); } |
︙ | ︙ | |||
1084 1085 1086 1087 1088 1089 1090 | 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); | | | 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 | 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->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; |
︙ | ︙ | |||
1143 1144 1145 1146 1147 1148 1149 | pSeg->y = pSeg->y0; pSeg->pNext = pActive; pActive = pSeg; needSort = 1; }else{ /* Remove a segment */ if( pActive==pThisEvent->pSeg ){ | | | | 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 | pSeg->y = pSeg->y0; pSeg->pNext = pActive; pActive = pSeg; needSort = 1; }else{ /* Remove a segment */ if( pActive==pThisEvent->pSeg ){ pActive = pActive->pNext; }else{ for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){ if( pSeg->pNext==pThisEvent->pSeg ){ pSeg->pNext = pSeg->pNext->pNext; break; } } } } pThisEvent = pThisEvent->pNext; } |
︙ | ︙ | |||
1191 1192 1193 1194 1195 1196 1197 | static void geopolyOverlapFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0); GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0); | < < < < < | 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 | static void geopolyOverlapFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0); GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0); if( p1 && p2 ){ int x = geopolyOverlap(p1, p2); if( x<0 ){ sqlite3_result_error_nomem(context); }else{ sqlite3_result_int(context, x); } } sqlite3_free(p1); sqlite3_free(p2); } /* ** Enable or disable debugging output */ static void geopolyDebugFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ #ifdef GEOPOLY_ENABLE_DEBUG geo_debug = sqlite3_value_int(argv[0]); #endif } /* ** This function is the implementation of both the xConnect and xCreate ** methods of the geopoly virtual table. ** |
︙ | ︙ | |||
1245 1246 1247 1248 1249 1250 1251 | 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; | < | 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 | 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); |
︙ | ︙ | |||
1362 1363 1364 1365 1366 1367 1368 | 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; | | | > > > > > | 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 | 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; sqlite3_stmt *pStmt; rtreeReference(pRtree); /* Reset the cursor to the same state as rtreeOpen() leaves it in. */ freeCursorConstraints(pCsr); sqlite3_free(pCsr->aPoint); pStmt = pCsr->pReadAux; memset(pCsr, 0, sizeof(RtreeCursor)); pCsr->base.pVtab = (sqlite3_vtab*)pRtree; pCsr->pReadAux = pStmt; 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]); |
︙ | ︙ | |||
1398 1399 1400 1401 1402 1403 1404 | ** with the configured constraints. */ rc = nodeAcquire(pRtree, 1, 0, &pRoot); if( rc==SQLITE_OK && idxNum<=3 ){ RtreeCoord bbox[4]; RtreeConstraint *p; assert( argc==1 ); | < | 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 | ** 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 ){ |
︙ | ︙ | |||
1489 1490 1491 1492 1493 1494 1495 | ** ------------------------------------------------ */ static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ int ii; int iRowidTerm = -1; int iFuncTerm = -1; int idxNum = 0; | < | 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 | ** ------------------------------------------------ */ static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ int ii; int iRowidTerm = -1; int iFuncTerm = -1; int idxNum = 0; for(ii=0; ii<pIdxInfo->nConstraint; ii++){ struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii]; if( !p->usable ) continue; if( p->iColumn<0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){ iRowidTerm = ii; break; |
︙ | ︙ | |||
1627 1628 1629 1630 1631 1632 1633 | cell.iRowid = newRowid; if( nData>1 /* not a DELETE */ && (!oldRowidValid /* INSERT */ || !sqlite3_value_nochange(aData[2]) /* UPDATE _shape */ || oldRowid!=newRowid) /* Rowid change */ ){ | < | 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 | 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; |
︙ | ︙ | |||
1710 1711 1712 1713 1714 1715 1716 | sqlite3_bind_blob(pUp, 2, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT); }else{ sqlite3_bind_value(pUp, 2, aData[2]); } sqlite3_free(p); nChange = 1; } | | | 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 | sqlite3_bind_blob(pUp, 2, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT); }else{ sqlite3_bind_value(pUp, 2, aData[2]); } sqlite3_free(p); nChange = 1; } for(jj=1; jj<pRtree->nAux; jj++){ nChange++; sqlite3_bind_value(pUp, jj+2, aData[jj+2]); } if( nChange ){ sqlite3_step(pUp); rc = sqlite3_reset(pUp); } |
︙ | ︙ | |||
1736 1737 1738 1739 1740 1741 1742 | static int geopolyFindFunction( sqlite3_vtab *pVtab, int nArg, const char *zName, void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), void **ppArg ){ | < < | 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 | static int geopolyFindFunction( sqlite3_vtab *pVtab, int nArg, const char *zName, void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), void **ppArg ){ if( sqlite3_stricmp(zName, "geopoly_overlap")==0 ){ *pxFunc = geopolyOverlapFunc; *ppArg = 0; return SQLITE_INDEX_CONSTRAINT_FUNCTION; } if( sqlite3_stricmp(zName, "geopoly_within")==0 ){ *pxFunc = geopolyWithinFunc; |
︙ | ︙ | |||
1807 1808 1809 1810 1811 1812 1813 | static const struct { void (*xStep)(sqlite3_context*,int,sqlite3_value**); void (*xFinal)(sqlite3_context*); const char *zName; } aAgg[] = { { geopolyBBoxStep, geopolyBBoxFinal, "geopoly_group_bbox" }, }; | | < < | < < < | < | | 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 | static const struct { void (*xStep)(sqlite3_context*,int,sqlite3_value**); 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 = aFunc[i].bPure ? SQLITE_UTF8|SQLITE_DETERMINISTIC : SQLITE_UTF8; 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, 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 | #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 | #ifndef SQLITE_CORE #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #else #include "sqlite3.h" #endif #include <string.h> #include <assert.h> #include <stdio.h> #ifndef 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; #endif /* The following macro is used to suppress compiler warnings. */ #ifndef UNUSED_PARAMETER # define UNUSED_PARAMETER(x) (void)(x) #endif |
︙ | ︙ | |||
148 149 150 151 152 153 154 | 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 */ | < < | 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 */ #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 */ |
︙ | ︙ | |||
342 343 344 345 346 347 348 | #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() */ | < < < < < < | 315 316 317 318 319 320 321 322 323 324 325 326 327 328 | #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 */ |
︙ | ︙ | |||
432 433 434 435 436 437 438 | #endif #endif /* The testcase() macro should already be defined in the amalgamation. If ** it is not, make it a no-op. */ #ifndef SQLITE_AMALGAMATION | < < < < | < < < < < < < < < < < < < < < < < < | 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 | #endif #endif /* The testcase() macro should already be defined in the amalgamation. If ** it is not, make it a no-op. */ #ifndef SQLITE_AMALGAMATION # define testcase(X) #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 |
︙ | ︙ | |||
497 498 499 500 501 502 503 | ** Functions to deserialize a 16 bit integer, 32 bit real number and ** 64 bit integer. The deserialized value is returned. */ static int readInt16(u8 *p){ return (p[0]<<8) + p[1]; } static void readCoord(u8 *p, RtreeCoord *pCoord){ | | | 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 | ** Functions to deserialize a 16 bit integer, 32 bit real number and ** 64 bit integer. The deserialized value is returned. */ static int readInt16(u8 *p){ return (p[0]<<8) + p[1]; } static void readCoord(u8 *p, RtreeCoord *pCoord){ assert( ((((char*)p) - (char*)0)&3)==0 ); /* p is always 4-byte aligned */ #if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 pCoord->u = _byteswap_ulong(*(u32*)p); #elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 pCoord->u = __builtin_bswap32(*(u32*)p); #elif SQLITE_BYTEORDER==4321 pCoord->u = *(u32*)p; #else |
︙ | ︙ | |||
551 552 553 554 555 556 557 | */ static void writeInt16(u8 *p, int i){ p[0] = (i>> 8)&0xFF; p[1] = (i>> 0)&0xFF; } static int writeCoord(u8 *p, RtreeCoord *pCoord){ u32 i; | | | 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 | */ static void writeInt16(u8 *p, int i){ p[0] = (i>> 8)&0xFF; p[1] = (i>> 0)&0xFF; } static int writeCoord(u8 *p, RtreeCoord *pCoord){ u32 i; assert( ((((char*)p) - (char*)0)&3)==0 ); /* p is always 4-byte aligned */ assert( sizeof(RtreeCoord)==4 ); assert( sizeof(u32)==4 ); #if SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000 i = __builtin_bswap32(pCoord->u); memcpy(p, &i, 4); #elif SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300 i = _byteswap_ulong(pCoord->u); |
︙ | ︙ | |||
685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 | static void nodeBlobReset(Rtree *pRtree){ if( pRtree->pNodeBlob && pRtree->inWrTrans==0 && pRtree->nCursor==0 ){ sqlite3_blob *pBlob = pRtree->pNodeBlob; pRtree->pNodeBlob = 0; sqlite3_blob_close(pBlob); } } /* ** Obtain a reference to an r-tree node. */ static int nodeAcquire( Rtree *pRtree, /* R-tree structure */ i64 iNode, /* Node number to load */ RtreeNode *pParent, /* Either the parent node or NULL */ RtreeNode **ppNode /* OUT: Acquired node */ ){ 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 ){ | > > > > > > > > > > > > > | > | | > > > | 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 | static void nodeBlobReset(Rtree *pRtree){ if( pRtree->pNodeBlob && pRtree->inWrTrans==0 && pRtree->nCursor==0 ){ sqlite3_blob *pBlob = pRtree->pNodeBlob; pRtree->pNodeBlob = 0; sqlite3_blob_close(pBlob); } } /* ** Check to see if pNode is the same as pParent or any of the parents ** of pParent. */ static int nodeInParentChain(const RtreeNode *pNode, const RtreeNode *pParent){ do{ if( pNode==pParent ) return 1; pParent = pParent->pParent; }while( pParent ); return 0; } /* ** Obtain a reference to an r-tree node. */ static int nodeAcquire( Rtree *pRtree, /* R-tree structure */ i64 iNode, /* Node number to load */ RtreeNode *pParent, /* Either the parent node or NULL */ RtreeNode **ppNode /* OUT: Acquired node */ ){ 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 ){ assert( !pParent || !pNode->pParent || pNode->pParent==pParent ); if( pParent && !pNode->pParent ){ if( nodeInParentChain(pNode, pParent) ){ RTREE_IS_CORRUPT(pRtree); return SQLITE_CORRUPT_VTAB; } pParent->nRef++; pNode->pParent = pParent; } pNode->nRef++; *ppNode = pNode; return SQLITE_OK; } if( pRtree->pNodeBlob ){ |
︙ | ︙ | |||
760 761 762 763 764 765 766 | /* 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. */ | | | 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 | /* 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( pNode && iNode==1 ){ pRtree->iDepth = readInt16(pNode->zData); if( pRtree->iDepth>RTREE_MAX_DEPTH ){ rc = SQLITE_CORRUPT_VTAB; RTREE_IS_CORRUPT(pRtree); } } |
︙ | ︙ | |||
1084 1085 1086 1087 1088 1089 1090 | *ppCursor = (sqlite3_vtab_cursor *)pCsr; return rc; } /* | | | < < < < < < < < < < > | > > | 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 | *ppCursor = (sqlite3_vtab_cursor *)pCsr; return rc; } /* ** Free the RtreeCursor.aConstraint[] array and its contents. */ static void freeCursorConstraints(RtreeCursor *pCsr){ 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; } } /* ** Rtree virtual table module xClose method. */ static int rtreeClose(sqlite3_vtab_cursor *cur){ Rtree *pRtree = (Rtree *)(cur->pVtab); int ii; RtreeCursor *pCsr = (RtreeCursor *)cur; assert( pRtree->nCursor>0 ); freeCursorConstraints(pCsr); sqlite3_finalize(pCsr->pReadAux); sqlite3_free(pCsr->aPoint); for(ii=0; ii<RTREE_CACHE_SZ; ii++) nodeRelease(pRtree, pCsr->aNode[ii]); sqlite3_free(pCsr); pRtree->nCursor--; nodeBlobReset(pRtree); return SQLITE_OK; } /* |
︙ | ︙ | |||
1277 1278 1279 1280 1281 1282 1283 | /* 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 | | < | < < | < < < < < < < < < | | | > | < | 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 | /* 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 ); assert( ((((char*)pCellData) - (char*)0)&3)==0 ); /* 4-byte aligned */ switch( p->op ){ case RTREE_LE: case RTREE_LT: case RTREE_EQ: RTREE_DECODE_COORD(eInt, pCellData, val); /* val now holds the lower bound of the coordinate pair */ if( p->u.rValue>=val ) return; if( p->op!=RTREE_EQ ) break; /* RTREE_LE and RTREE_LT end here */ /* Fall through for the RTREE_EQ case */ default: /* RTREE_GT or RTREE_GE, or fallthrough of RTREE_EQ */ pCellData += 4; RTREE_DECODE_COORD(eInt, pCellData, val); /* val now holds the upper bound of the coordinate pair */ if( p->u.rValue<=val ) return; } *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. |
︙ | ︙ | |||
1329 1330 1331 1332 1333 1334 1335 | 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 | | < | < < | | | | | | 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 | 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 ); 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_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. |
︙ | ︙ | |||
1375 1376 1377 1378 1379 1380 1381 | /* ** 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; | | < > | | < | 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 | /* ** 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( pParent ){ return nodeRowidIndex(pRtree, pParent, pNode->iNode, piIndex); } *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. |
︙ | ︙ | |||
1503 1504 1505 1506 1507 1508 1509 | || (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; | < | | 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 | || (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; if( 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; |
︙ | ︙ | |||
1565 1566 1567 1568 1569 1570 1571 | 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; | | | 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 | 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( 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; } |
︙ | ︙ | |||
1616 1617 1618 1619 1620 1621 1622 | int nConstraint = pCur->nConstraint; int ii; int eInt; RtreeSearchPoint x; eInt = pRtree->eCoordType==RTREE_COORD_INT32; while( (p = rtreeSearchPointFirst(pCur))!=0 && p->iLevel>0 ){ | < < > | < < < | < < > < < < < < < | 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 | 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; u8 *pCellData = pNode->zData + (4+pRtree->nBytesPerCell*p->iCell); 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 ) break; } p->iCell++; if( eWithin==NOT_WITHIN ) continue; x.iLevel = p->iLevel - 1; if( x.iLevel ){ x.id = readInt64(pCellData); x.iCell = 0; }else{ x.id = p->id; x.iCell = p->iCell - 1; } if( p->iCell>=nCell ){ RTREE_QUEUE_TRACE(pCur, "POP-S:"); |
︙ | ︙ | |||
1706 1707 1708 1709 1710 1711 1712 | ** 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); | | | | 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 | ** 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 && 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( 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); |
︙ | ︙ | |||
1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 | ){ 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. */ | > | > > > > > < < < < | < < < < | 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 | ){ Rtree *pRtree = (Rtree *)pVtabCursor->pVtab; RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; RtreeNode *pRoot = 0; int ii; int rc = SQLITE_OK; int iCell = 0; sqlite3_stmt *pStmt; rtreeReference(pRtree); /* Reset the cursor to the same state as rtreeOpen() leaves it in. */ freeCursorConstraints(pCsr); sqlite3_free(pCsr->aPoint); pStmt = pCsr->pReadAux; memset(pCsr, 0, sizeof(RtreeCursor)); pCsr->base.pVtab = (sqlite3_vtab*)pRtree; pCsr->pReadAux = pStmt; 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; rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode); 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); |
︙ | ︙ | |||
1887 1888 1889 1890 1891 1892 1893 | }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]; | < | < < < < < < < < < < < | < | 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 | }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]; 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{ #ifdef SQLITE_RTREE_INT_ONLY p->u.rValue = sqlite3_value_int64(argv[ii]); #else p->u.rValue = sqlite3_value_double(argv[ii]); #endif } } } } if( rc==SQLITE_OK ){ RtreeSearchPoint *pNew; pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1)); if( pNew==0 ) 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:"); |
︙ | ︙ | |||
2004 2005 2006 2007 2008 2009 2010 | } 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 | | | 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 | } 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; } |
︙ | ︙ | |||
2210 2211 2212 2213 2214 2215 2216 | sqlite3_int64 iBest = 0; RtreeDValue fMinGrowth = RTREE_ZERO; RtreeDValue fMinArea = RTREE_ZERO; int nCell = NCELL(pNode); RtreeCell cell; | | | 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 | sqlite3_int64 iBest = 0; RtreeDValue fMinGrowth = RTREE_ZERO; RtreeDValue fMinArea = RTREE_ZERO; int nCell = NCELL(pNode); RtreeCell cell; RtreeNode *pChild; 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. */ |
︙ | ︙ | |||
2257 2258 2259 2260 2261 2262 2263 | 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; | < < < < < < | < | 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 | 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; while( p->pParent ){ RtreeNode *pParent = p->pParent; RtreeCell cell; int iCell; if( (++cnt)>1000 || nodeParentIndex(pRtree, p, &iCell) ){ RTREE_IS_CORRUPT(pRtree); return SQLITE_CORRUPT_VTAB; } nodeGetCell(pRtree, pParent, iCell, &cell); if( !cellContains(pRtree, &cell, pCell) ){ cellUnion(pRtree, &cell, pCell); |
︙ | ︙ | |||
2558 2559 2560 2561 2562 2563 2564 | RtreeNode *pNode, int iHeight ){ int (*xSetMapping)(Rtree *, sqlite3_int64, sqlite3_int64); xSetMapping = ((iHeight==0)?rowidWrite:parentWrite); if( iHeight>0 ){ RtreeNode *pChild = nodeHashLookup(pRtree, iRowid); | < < < < < | 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 | 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, |
︙ | ︙ | |||
2658 2659 2660 2661 2662 2663 2664 | if( rc!=SQLITE_OK ){ goto splitnode_out; } }else{ RtreeNode *pParent = pLeft->pParent; int iCell; rc = nodeParentIndex(pRtree, pLeft, &iCell); | | < | | 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 | if( rc!=SQLITE_OK ){ goto splitnode_out; } }else{ RtreeNode *pParent = pLeft->pParent; int iCell; rc = nodeParentIndex(pRtree, pLeft, &iCell); if( rc==SQLITE_OK ){ nodeOverwriteCell(pRtree, pParent, &leftbbox, iCell); rc = AdjustTree(pRtree, pParent, &leftbbox); } if( rc!=SQLITE_OK ){ goto splitnode_out; } } if( (rc = rtreeInsertCell(pRtree, pRight->pParent, &rightbbox, iHeight+1)) ){ goto splitnode_out; } |
︙ | ︙ | |||
2738 2739 2740 2741 2742 2743 2744 | /* 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); | | | 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 | /* 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 ){ 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); |
︙ | ︙ | |||
2769 2770 2771 2772 2773 2774 2775 | /* 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); | < | 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 | /* 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; |
︙ | ︙ | |||
2992 2993 2994 2995 2996 2997 2998 | rc = SplitNode(pRtree, pNode, pCell, iHeight); }else{ pRtree->iReinsertHeight = iHeight; rc = Reinsert(pRtree, pNode, pCell, iHeight); } }else{ rc = AdjustTree(pRtree, pNode, pCell); | | | 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 | rc = SplitNode(pRtree, pNode, pCell, iHeight); }else{ pRtree->iReinsertHeight = iHeight; rc = Reinsert(pRtree, pNode, pCell, iHeight); } }else{ rc = AdjustTree(pRtree, pNode, pCell); if( rc==SQLITE_OK ){ if( iHeight==0 ){ rc = rowidWrite(pRtree, pCell->iRowid, pNode->iNode); }else{ rc = parentWrite(pRtree, pCell->iRowid, pNode->iNode); } } } |
︙ | ︙ | |||
3098 3099 3100 3101 3102 3103 3104 | ** 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); | | | 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 | ** 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); 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--; |
︙ | ︙ | |||
3231 3232 3233 3234 3235 3236 3237 | ** since the write might do a rebalance which would disrupt the read ** cursor. */ return SQLITE_LOCKED_VTAB; } rtreeReference(pRtree); assert(nData>=1); | | | 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 | ** since the write might do a rebalance which would disrupt the read ** cursor. */ return SQLITE_LOCKED_VTAB; } rtreeReference(pRtree); assert(nData>=1); cell.iRowid = 0; /* Used only to suppress a compiler warning */ /* Constraint handling. A write operation on an r-tree table may return ** SQLITE_CONSTRAINT for two reasons: ** ** 1. A duplicate rowid value, or ** 2. The supplied data violates the "x2>=x1" constraint. ** |
︙ | ︙ | |||
3433 3434 3435 3436 3437 3438 3439 | ** 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; | | > > > > > > > > > > | | 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 | ** 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 = 0; 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); }else if( rc!=SQLITE_NOMEM ){ rc = SQLITE_OK; } if( rc==SQLITE_OK ){ if( nRow==0 ){ pRtree->nRowEst = RTREE_DEFAULT_ROWEST; }else{ pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST); } } sqlite3_free(zSql); } return rc; } /* ** Return true if zName is the extension on one of the shadow tables used ** by this module. |
︙ | ︙ | |||
3603 3604 3605 3606 3607 3608 3609 | }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); | < | < < | 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 | }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); if( ii<pRtree->nAuxNotNull ){ sqlite3_str_appendf(p,"a%d=coalesce(?%d,a%d)",ii,ii+2,ii); }else{ 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; |
︙ | ︙ | |||
3703 3704 3705 3706 3707 3708 3709 | } } sqlite3_free(zSql); return rc; } | < < < < < < < < | 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 | } } 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 ** argv[2] -> table name |
︙ | ︙ | |||
3747 3748 3749 3750 3751 3752 3753 | "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 */ | | | | 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 | "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>RTREE_MAX_AUX_COLUMN+3 ){ *pzErr = sqlite3_mprintf("%s", aErrMsg[3]); return SQLITE_ERROR; } sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); /* Allocate the sqlite3_vtab structure */ nDb = (int)strlen(argv[1]); |
︙ | ︙ | |||
3776 3777 3778 3779 3780 3781 3782 | /* 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); | | < < | | < | < | 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 | /* 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", argv[3]); for(ii=4; ii<argc; ii++){ if( argv[ii][0]=='+' ){ pRtree->nAux++; sqlite3_str_appendf(pSql, ",%s", argv[ii]+1); }else if( pRtree->nAux>0 ){ break; }else{ pRtree->nDim2++; sqlite3_str_appendf(pSql, ",%s", argv[ii]); } } sqlite3_str_appendf(pSql, ");"); zSql = sqlite3_str_finish(pSql); if( !zSql ){ rc = SQLITE_NOMEM; }else if( ii<argc ){ |
︙ | ︙ | |||
3873 3874 3875 3876 3877 3878 3879 | 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]); | < | 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 | 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]); 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; |
︙ | ︙ | |||
3913 3914 3915 3916 3917 3918 3919 | ** 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 | < < | < < < | 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 | ** 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]); sqlite3_result_int(ctx, readInt16(zBlob)); } } /* ** Context object passed between the various routines that make up the ** implementation of integrity-check function rtreecheck(). */ |
︙ | ︙ | |||
4288 4289 4290 4291 4292 4293 4294 | /* 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); | < < < > | 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 | /* 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); } 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; |
︙ | ︙ | |||
4548 4549 4550 4551 4552 4553 4554 | 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)); | | < < < | 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 | 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 ) 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 | # # 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.2 { execsql { SELECT name FROM sqlite_master ORDER BY name } } {t1 t1_node t1_parent t1_rowid} do_test rtree-1.1.3 { execsql { DROP TABLE t1; SELECT name FROM sqlite_master ORDER BY name; } } {} |
︙ | ︙ | |||
111 112 113 114 115 116 117 | catchsql " CREATE VIRTUAL TABLE t1 USING rtree($columns); " } $X catchsql { DROP TABLE t1 } } | < < < | 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] { |
︙ | ︙ | |||
376 377 378 379 380 381 382 | 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); } } {} | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 | 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<3 } } {} do_test rtree-8.1.7 { execsql { SELECT ii FROM t6 WHERE x1<4 } } {1} do_test rtree-8.1.8 { execsql { SELECT ii FROM t6 WHERE x1<5 } } {1 2} #---------------------------------------------------------------------------- # Test cases rtree-9.* # # Test that ticket #3549 is fixed. do_test rtree-9.1 { execsql { |
︙ | ︙ | |||
610 611 612 613 614 615 616 | } do_execsql_test 14.5 { SELECT * FROM t10; } { 1 0.0 0.0 2 52.0 81.0 } | < < < < < < < < < < < < < < | | | 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 | } do_execsql_test 14.5 { SELECT * FROM t10; } { 1 0.0 0.0 2 52.0 81.0 } do_execsql_test 14.4 { DROP TABLE t10; CREATE VIRTUAL TABLE t10 USING rtree_i32(ii, x1, x2); INSERT INTO t10 VALUES(1, 'one', 'two'); INSERT INTO t10 VALUES(2, '52xyz', '81...'); INSERT INTO t10 VALUES(3, 42.3, 49.9); } do_execsql_test 14.5 { SELECT * FROM t10; } { 1 0 0 2 52 81 3 42 49 } |
︙ | ︙ | |||
707 708 709 710 711 712 713 | REINDEX t2; } {} do_execsql_test 17.2 { REINDEX; } {} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 657 658 659 660 661 662 663 664 665 | REINDEX t2; } {} do_execsql_test 17.2 { REINDEX; } {} expand_all_sql db finish_test |
Changes to ext/rtree/rtree2.test.
︙ | ︙ | |||
29 30 31 32 33 34 35 | if {[info exists G(isquick)] && $G(isquick)} { set ::NROW 100 set ::NSELECT 10 } foreach module {rtree_i32 rtree} { | < | | 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | 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] { lappend cols "$c REAL" } 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/rtree3.test.
︙ | ︙ | |||
19 20 21 22 23 24 25 | source $testdir/tester.tcl source $testdir/malloc_common.tcl ifcapable !rtree { finish_test return } | < < < < | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | source $testdir/tester.tcl source $testdir/malloc_common.tcl ifcapable !rtree { finish_test return } # Test summary: # # rtree3-1: Test OOM in simple CREATE TABLE, INSERT, DELETE and SELECT # commands on an almost empty table. # # rtree3-2: Test OOM in a DROP TABLE command. # |
︙ | ︙ | |||
196 197 198 199 200 201 202 | faultsim_delete_and_reopen execsql { CREATE VIRTUAL TABLE rt USING rtree(ii, x1, x2, y1, y2) } faultsim_save_and_close } {} do_faultsim_test rtree3-7 -faults oom-* -prep { faultsim_restore_and_reopen } -body { | | | | 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | faultsim_delete_and_reopen execsql { CREATE VIRTUAL TABLE rt USING rtree(ii, x1, x2, y1, y2) } faultsim_save_and_close } {} do_faultsim_test rtree3-7 -faults oom-* -prep { faultsim_restore_and_reopen } -body { execsql { ALTER TABLE rt RENAME TO rt2 } } -test { faultsim_test_result {0 {}} } do_faultsim_test rtree3-8 -faults oom-* -prep { catch { db close } } -body { sqlite3 db test.db } |
︙ | ︙ |
Changes to ext/rtree/rtree6.test.
︙ | ︙ | |||
75 76 77 78 79 80 81 | 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 | | | | | | | | | | | | | | 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 | 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 TABLE t1 VIRTUAL TABLE INDEX 2:C0 `--SEARCH TABLE 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 TABLE t1 VIRTUAL TABLE INDEX 2:C0 `--SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?) } do_eqp_test rtree6.2.3 { SELECT * FROM t1,t2 WHERE k=ii } { QUERY PLAN |--SCAN TABLE t1 VIRTUAL TABLE INDEX 2: `--SEARCH TABLE 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 TABLE t1 VIRTUAL TABLE INDEX 2:C0E1 `--SEARCH TABLE 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 TABLE t1 VIRTUAL TABLE INDEX 2:C0E1 `--SEARCH TABLE 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 TABLE t1 VIRTUAL TABLE INDEX 2: `--SEARCH TABLE 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 |
︙ | ︙ |
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; } {} 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 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | } 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} #------------------------------------------------------------------------- # Add some bad entries to the %_parent table. # create_t1 populate_t1 do_execsql_test rtreeA-6.1.0 { UPDATE t1_parent set parentnode = parentnode+1 } {} do_corruption_tests rtreeA-6.1 { 1 "DELETE FROM t1 WHERE rowid = 5" 2 "UPDATE t1 SET x1=x1+1, x2=x2+1" } do_execsql_test rtreeA-6.2 { SELECT rtreecheck('main', 't1')!="ok" } {1} #------------------------------------------------------------------------- # Truncated blobs in the _node table. # create_t1 populate_t1 |
︙ | ︙ |
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 TABLE t `--SCAN TABLE 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 TABLE t `--SCAN TABLE 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 TABLE t `--SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0 } do_eqp_test 1.5 { SELECT * FROM t, r_tree } { QUERY PLAN |--SCAN TABLE r_tree VIRTUAL TABLE INDEX 2: `--SCAN TABLE 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 TABLE t `--SCAN TABLE 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 TABLE t `--SCAN TABLE 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 TABLE t `--SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0 } do_eqp_test 2.5 { SELECT * FROM t, r_tree } { QUERY PLAN |--SCAN TABLE r_tree VIRTUAL TABLE INDEX 2: `--SCAN TABLE 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 TABLE t1 `--SCAN TABLE t2 } do_eqp_test 3.2.2 { SELECT * FROM t2 CROSS JOIN t1 } { QUERY PLAN |--SCAN TABLE t2 `--SCAN TABLE t1 } do_eqp_test 3.3.1 { SELECT * FROM t1 CROSS JOIN t3 } { QUERY PLAN |--SCAN TABLE t1 `--SCAN TABLE t3 VIRTUAL TABLE INDEX 2: } do_eqp_test 3.3.2 { SELECT * FROM t3 CROSS JOIN t1 } { QUERY PLAN |--SCAN TABLE t3 VIRTUAL TABLE INDEX 2: `--SCAN TABLE 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 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 TABLE t1 `--SCAN TABLE 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 TABLE rt VIRTUAL TABLE INDEX 2: `--SEARCH TABLE 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 TABLE t1 `--SCAN TABLE 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 TABLE t1 `--SCAN TABLE 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 TABLE xdir |--SCAN TABLE ydir `--SCAN TABLE 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 TABLE xdir |--SCAN TABLE rt VIRTUAL TABLE INDEX 2:B0D1 `--SCAN TABLE 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 TABLE xdir |--SCAN TABLE rt VIRTUAL TABLE INDEX 2:B0D1 `--SCAN TABLE 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 TABLE xdir |--SCAN TABLE rt VIRTUAL TABLE INDEX 2:B0D1 `--SCAN TABLE ydir } { 2 4 } finish_test |
Changes to ext/rtree/rtreeH.test.
︙ | ︙ | |||
39 40 41 42 43 44 45 | 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 {}} | < < < < < < < < < < < < < < < < < < < < < < < | 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 { |
︙ | ︙ |
Deleted ext/rtree/rtreeI.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to ext/rtree/rtreecheck.test.
︙ | ︙ | |||
113 114 115 116 117 118 119 | SELECT rtreecheck('r2') } {ok} sqlite3_db_config db DEFENSIVE 0 do_execsql_test 3.2 { BEGIN; UPDATE r2_node SET data = X'123456'; | | | | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | SELECT rtreecheck('r2') } {ok} sqlite3_db_config db DEFENSIVE 0 do_execsql_test 3.2 { BEGIN; UPDATE r2_node SET data = X'123456'; SELECT rtreecheck('r2')!="ok"; } {1} do_execsql_test 3.3 { ROLLBACK; UPDATE r2_node SET data = X'00001234'; SELECT rtreecheck('r2')!="ok"; } {1} do_execsql_test 4.0 { CREATE TABLE notanrtree(i); SELECT rtreecheck('notanrtree'); } {{Schema corrupt or not an rtree}} |
︙ | ︙ | |||
153 154 155 156 157 158 159 | ROLLBACK; BEGIN; UPDATE r3_node SET data = set_int32(data, 3, 0); UPDATE r3_node SET data = set_int32(data, 4, 0); SELECT rtreecheck('r3')=='ok' } 0 | < < < < < < < < < < < < < < < < < < < < < < < < | 153 154 155 156 157 158 159 160 | ROLLBACK; BEGIN; UPDATE r3_node SET data = set_int32(data, 3, 0); UPDATE r3_node SET data = set_int32(data, 4, 0); SELECT rtreecheck('r3')=='ok' } 0 finish_test |
Deleted ext/rtree/rtreedoc.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/rtree/rtreedoc2.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/rtree/rtreedoc3.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to ext/rtree/rtreefuzz001.test.
︙ | ︙ | |||
461 462 463 464 465 466 467 | | 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 { | < | | 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 | | 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 { SELECT rtreecheck('t1'); } } {1 {database disk image is malformed}} 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. |
︙ | ︙ | |||
771 772 773 774 775 776 777 | 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}} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 770 771 772 773 774 775 776 777 | 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}} finish_test |
Deleted ext/rtree/test_rtreedoc.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to ext/session/session1.test.
︙ | ︙ | |||
148 149 150 151 152 153 154 | 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 } {} | < < < < < < < < < < < < < < < < < < < < | 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 |
︙ | ︙ |
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 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 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, b PRIMARY KEY); CREATE TABLE t2(x, y, z); CREATE TABLE t3(a); CREATE TABLE aux.t1(a 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 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 } |
︙ | ︙ | |||
584 585 586 587 588 589 590 | SELECT enable(0); SELECT enable(-1); SELECT enable(1); SELECT enable(-1); } {0 0 1 1} S delete | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 584 585 586 587 588 589 590 591 | SELECT enable(0); SELECT enable(-1); SELECT enable(1); SELECT enable(-1); } {0 0 1 1} S delete finish_test |
Changes to ext/session/session6.test.
︙ | ︙ | |||
15 16 17 18 19 20 21 | 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} | < | 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 |
︙ | ︙ |
Changes to ext/session/session8.test.
︙ | ︙ | |||
59 60 61 62 63 64 65 | uplevel [list do_test $tn.1 "set {} $a" 0] uplevel [list do_test $tn.2 "set {} $b" 1] } do_execsql_test 1.1 { CREATE TABLE t1(a PRIMARY KEY, b); INSERT INTO t1 VALUES(1, 2); | | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | uplevel [list do_test $tn.1 "set {} $a" 0] uplevel [list do_test $tn.2 "set {} $b" 1] } do_execsql_test 1.1 { CREATE TABLE t1(a PRIMARY KEY, b); INSERT INTO t1 VALUES(1, 2); INSERT INTO t1 VALUES("abc", "xyz"); } do_then_undo 1.2 { INSERT INTO t1 VALUES(3, 4); } do_then_undo 1.3 { DELETE FROM t1 WHERE b=2; } do_then_undo 1.4 { UPDATE t1 SET b = 3 WHERE a = 1; } do_execsql_test 2.1 { CREATE TABLE t2(a, b PRIMARY KEY); |
︙ | ︙ |
Changes to ext/session/sessionH.test.
︙ | ︙ | |||
30 31 32 33 34 35 36 | VALUES(1) UNION ALL SELECT i+1 FROM s WHERe i<10000 ) INSERT INTO t1 SELECT 'abcde', randomblob(16), i FROM s; } compare_db db db2 } {} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 30 31 32 33 34 35 36 37 38 | VALUES(1) UNION ALL SELECT i+1 FROM s WHERe i<10000 ) INSERT INTO t1 SELECT 'abcde', randomblob(16), i FROM s; } compare_db db db2 } {} finish_test |
Changes to ext/session/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 "$data1" puts "$data2" error "table $tbl data mismatch" } } return "" } |
︙ | ︙ |
Changes to ext/session/sessionat.test.
︙ | ︙ | |||
16 17 18 19 20 21 22 | 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 | 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 db close sqlite3_shutdown test_sqlite3_log log proc log {code msg} { lappend ::log $code $msg } proc reset_test {} { |
︙ | ︙ | |||
239 240 241 242 243 244 245 | } proc xConfict {args} { return "OMIT" } do_test $tn.6.3 { sqlite3changeset_apply db $cinv xConflict execsql { SELECT * FROM t7 } } {1 1 ccc 2 2 ccc 3 3 ccc} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 | } proc xConfict {args} { return "OMIT" } do_test $tn.6.3 { sqlite3changeset_apply db $cinv xConflict execsql { SELECT * FROM t7 } } {1 1 ccc 2 2 ccc 3 3 ccc} }] } catch { db close } catch { db2 close } sqlite3_shutdown test_sqlite3_log finish_test |
Deleted ext/session/sessionbig.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to ext/session/sessioninvert.test.
︙ | ︙ | |||
151 152 153 154 155 156 157 | } {1 SQLITE_CORRUPT} do_test 3.2 { sqlite3changeset_apply_v2 db2 $P {} compare_db db db2 } {} | < < < < < < < < < < < < < < < < < < < < < < < < | 151 152 153 154 155 156 157 158 159 | } {1 SQLITE_CORRUPT} do_test 3.2 { sqlite3changeset_apply_v2 db2 $P {} compare_db db db2 } {} finish_test |
Deleted ext/session/sessionmem.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/session/sessionnoop.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/session/sessionsize.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to ext/session/sessionwor.test.
︙ | ︙ | |||
65 66 67 68 69 70 71 | foreach {tn wo} { 1 "" 2 "WITHOUT ROWID" } { reset_db | | < < | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | foreach {tn wo} { 1 "" 2 "WITHOUT ROWID" } { reset_db do_execsql_test 2.$tn.0 "CREATE TABLE t1(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}} } |
︙ | ︙ | |||
92 93 94 95 96 97 98 | } do_iterator_test 2.$tn.4 t1 { DELETE FROM t1; } { {DELETE t1 0 X. {i 1 t four} {}} } | < < < < < < < < < < < < < < < < < < < < < | 90 91 92 93 94 95 96 97 98 99 100 | } do_iterator_test 2.$tn.4 t1 { DELETE FROM t1; } { {DELETE t1 0 X. {i 1 t four} {}} } } finish_test |
Changes to ext/session/sqlite3session.c.
︙ | ︙ | |||
38 39 40 41 42 43 44 | /* ** Session handle structure. */ struct sqlite3_session { sqlite3 *db; /* Database handle session is attached to */ char *zDb; /* Name of database session is attached to */ | < < < | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | /* ** 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 */ }; /* |
︙ | ︙ | |||
89 90 91 92 93 94 95 | ** 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 */ | < | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | ** 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 */ |
︙ | ︙ | |||
289 290 291 292 293 294 295 | */ /* ** For each row modified during a session, there exists a single instance of ** this structure stored in a SessionTable.aChange[] hash table. */ struct SessionChange { | | | < | 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 | */ /* ** For each row modified during a session, there exists a single instance of ** this structure stored in a SessionTable.aChange[] hash table. */ struct SessionChange { int op; /* One of UPDATE, DELETE, INSERT */ int bIndirect; /* True if this change is "indirect" */ 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 |
︙ | ︙ | |||
416 417 418 419 420 421 422 | } 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); | | < < < < < < < < < < < < < < < < < < < < | 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 | } 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 ) 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; } /* ** 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: |
︙ | ︙ | |||
919 920 921 922 923 924 925 | ** 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. */ | | < < < < | < < | | 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 | ** 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(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 **)sqlite3_malloc64(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; } } sqlite3_free(pTab->apChange); pTab->nChange = nNew; pTab->apChange = apNew; } return SQLITE_OK; } |
︙ | ︙ | |||
986 987 988 989 990 991 992 | ** *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( | < | 955 956 957 958 959 960 961 962 963 964 965 966 967 968 | ** *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 */ |
︙ | ︙ | |||
1021 1022 1023 1024 1025 1026 1027 | "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{ | < < < < | < < < < < < | < < < < < < | | 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 | "SELECT 0, 'tbl', '', 0, '', 1 UNION ALL " "SELECT 1, 'idx', '', 0, '', 2 UNION ALL " "SELECT 2, 'stat', '', 0, '', 0" ); }else if( rc==SQLITE_ERROR ){ zPragma = sqlite3_mprintf(""); }else{ return rc; } }else{ zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis); } if( !zPragma ) return SQLITE_NOMEM; rc = sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0); sqlite3_free(zPragma); if( rc!=SQLITE_OK ) return rc; nByte = nThis + 1; 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 = sqlite3_malloc64(nByte); if( pAlloc==0 ){ rc = SQLITE_NOMEM; } } if( rc==SQLITE_OK ){ azCol = (char **)pAlloc; pAlloc = (u8 *)&azCol[nDbCol]; |
︙ | ︙ | |||
1100 1101 1102 1103 1104 1105 1106 | *pabPK = abPK; *pnCol = nDbCol; }else{ *pazCol = 0; *pabPK = 0; *pnCol = 0; if( pzTab ) *pzTab = 0; | | | 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 | *pabPK = abPK; *pnCol = nDbCol; }else{ *pazCol = 0; *pabPK = 0; *pnCol = 0; if( pzTab ) *pzTab = 0; sqlite3_free(azCol); } sqlite3_finalize(pStmt); return rc; } /* ** This function is only called from within a pre-update handler for a |
︙ | ︙ | |||
1122 1123 1124 1125 1126 1127 1128 | ** 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 ); | | < < < < < < | 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 | ** 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->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; } } } return (pSession->rc || pTab->abPK==0); } /* ** Versions of the four methods in object SessionHook for use with the |
︙ | ︙ | |||
1187 1188 1189 1190 1191 1192 1193 | return p->hook.xCount(p->hook.pCtx); } static int sessionStat1Depth(void *pCtx){ SessionStat1Ctx *p = (SessionStat1Ctx*)pCtx; return p->hook.xDepth(p->hook.pCtx); } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 | 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 |
︙ | ︙ | |||
1316 1317 1318 1319 1320 1321 1322 | ** 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 */ | | | 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 | ** number of columns in the table. */ if( pTab->nCol!=pSession->hook.xCount(pSession->hook.pCtx) ){ pSession->rc = SQLITE_SCHEMA; return; } /* Grow the hash table if required */ if( sessionGrowHash(0, pTab) ){ pSession->rc = SQLITE_NOMEM; return; } if( pTab->bStat1 ){ stat1.hook = pSession->hook; stat1.pSession = pSession; |
︙ | ︙ | |||
1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 | 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 */ | > | 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 | 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). */ SessionChange *pChange; /* New change object */ 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 */ |
︙ | ︙ | |||
1382 1383 1384 1385 1386 1387 1388 | /* 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 */ | | | | | | | | | | | | < < < < < < | 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 | /* 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 */ pChange = (SessionChange *)sqlite3_malloc64(nByte); if( !pChange ){ rc = SQLITE_NOMEM; goto error_out; }else{ memset(pChange, 0, sizeof(SessionChange)); pChange->aRecord = (u8 *)&pChange[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(&pChange->aRecord[nByte], p, &nByte); } /* Add the change to the hash-table */ if( pSession->bIndirect || pSession->hook.xDepth(pSession->hook.pCtx) ){ pChange->bIndirect = 1; } pChange->nRecord = nByte; pChange->op = op; pChange->pNext = pTab->apChange[iHash]; pTab->apChange[iHash] = pChange; }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; } } } /* If an error has occurred, mark the session object as failed. */ error_out: if( pTab->bStat1 ){ pSession->hook = stat1.hook; } if( rc!=SQLITE_OK ){ |
︙ | ︙ | |||
1464 1465 1466 1467 1468 1469 1470 | /* 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 ){ | | < < < < | 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 | /* 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 ){ for(pRet=pSession->pTable; pRet->pNext; pRet=pRet->pNext); assert( 0==sqlite3_strnicmp(pRet->zName, zName, nName+1) ); } } } assert( rc==SQLITE_OK || pRet==0 ); *ppTab = pRet; |
︙ | ︙ | |||
1495 1496 1497 1498 1499 1500 1501 | sqlite3_int64 iKey1, /* Rowid of row about to be deleted/updated */ sqlite3_int64 iKey2 /* New rowid value (for a rowid UPDATE) */ ){ sqlite3_session *pSession; int nDb = sqlite3Strlen30(zDb); assert( sqlite3_mutex_held(db->mutex) ); | < < | 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 | sqlite3_int64 iKey1, /* Rowid of row about to be deleted/updated */ sqlite3_int64 iKey2 /* New rowid value (for a rowid UPDATE) */ ){ sqlite3_session *pSession; int nDb = sqlite3Strlen30(zDb); assert( sqlite3_mutex_held(db->mutex) ); for(pSession=(sqlite3_session *)pCtx; pSession; pSession=pSession->pNext){ SessionTable *pTab; /* If this session is attached to a different database ("main", "temp" ** etc.), or if it is not currently enabled, there is nothing to do. Skip ** to the next session object attached to this database. */ |
︙ | ︙ | |||
1573 1574 1575 1576 1577 1578 1579 | return SQLITE_OK; } static int sessionDiffCount(void *pCtx){ SessionDiffCtx *p = (SessionDiffCtx*)pCtx; return p->nOldOff ? p->nOldOff : sqlite3_column_count(p->pStmt); } static int sessionDiffDepth(void *pCtx){ | < | 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 | return SQLITE_OK; } static int sessionDiffCount(void *pCtx){ SessionDiffCtx *p = (SessionDiffCtx*)pCtx; return p->nOldOff ? p->nOldOff : sqlite3_column_count(p->pStmt); } static int sessionDiffDepth(void *pCtx){ return 0; } /* ** Install the diff hooks on the session object passed as the only ** argument. */ |
︙ | ︙ | |||
1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 | zRet = sqlite3_mprintf("0"); } return zRet; } static char *sessionSelectFindNew( const char *zDb1, /* Pick rows in this db only */ const char *zDb2, /* But not in this one */ const char *zTbl, /* Table name */ const char *zExpr ){ char *zRet = sqlite3_mprintf( "SELECT * FROM \"%w\".\"%w\" WHERE NOT EXISTS (" | > | 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 | zRet = sqlite3_mprintf("0"); } return zRet; } static char *sessionSelectFindNew( int nCol, const char *zDb1, /* Pick rows in this db only */ const char *zDb2, /* But not in this one */ const char *zTbl, /* Table name */ const char *zExpr ){ char *zRet = sqlite3_mprintf( "SELECT * FROM \"%w\".\"%w\" WHERE NOT EXISTS (" |
︙ | ︙ | |||
1670 1671 1672 1673 1674 1675 1676 | sqlite3_session *pSession, SessionTable *pTab, const char *zDb1, const char *zDb2, char *zExpr ){ int rc = SQLITE_OK; | | | 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 | sqlite3_session *pSession, SessionTable *pTab, const char *zDb1, const char *zDb2, char *zExpr ){ int rc = SQLITE_OK; char *zStmt = sessionSelectFindNew(pTab->nCol, zDb1, zDb2, pTab->zName,zExpr); if( zStmt==0 ){ rc = SQLITE_NOMEM; }else{ sqlite3_stmt *pStmt; rc = sqlite3_prepare(pSession->db, zStmt, -1, &pStmt, 0); if( rc==SQLITE_OK ){ |
︙ | ︙ | |||
1767 1768 1769 1770 1771 1772 1773 | /* 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; | | < | < | 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 | /* 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(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 ){ *pzErrMsg = sqlite3_mprintf("table schemas do not match"); rc = SQLITE_SCHEMA; } if( bHasPk==0 ){ /* Ignore tables with no primary keys */ goto diff_out; } } |
︙ | ︙ | |||
1865 1866 1867 1868 1869 1870 1871 | 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. */ | | | | | | | 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 | 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(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; sqlite3_free(p); } } sqlite3_free((char*)pTab->azCol); /* cast works around VC++ bug */ sqlite3_free(pTab->apChange); sqlite3_free(pTab); } } /* ** Delete a session object previously allocated using sqlite3session_create(). */ void sqlite3session_delete(sqlite3_session *pSession){ |
︙ | ︙ | |||
1910 1911 1912 1913 1914 1915 1916 | } } sqlite3_mutex_leave(sqlite3_db_mutex(db)); sqlite3ValueFree(pSession->pZeroBlob); /* Delete all attached table objects. And the contents of their ** associated hash-tables. */ | | < | < | 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 | } } sqlite3_mutex_leave(sqlite3_db_mutex(db)); sqlite3ValueFree(pSession->pZeroBlob); /* Delete all attached table objects. And the contents of their ** associated hash-tables. */ sessionDeleteTable(pSession->pTable); /* Free the session object itself. */ sqlite3_free(pSession); } /* ** Set a table filter on a Session Object. */ void sqlite3session_table_filter( |
︙ | ︙ | |||
1961 1962 1963 1964 1965 1966 1967 | 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. */ | | < | 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 | 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. */ pTab = (SessionTable *)sqlite3_malloc64(sizeof(SessionTable) + nName + 1); 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 |
︙ | ︙ | |||
1992 1993 1994 1995 1996 1997 1998 | /* ** 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. */ | | < < | < < | < < < < < < < < < < < < | 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 | /* ** 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, size_t nByte, int *pRc){ if( *pRc==SQLITE_OK && p->nAlloc-p->nBuf<nByte ){ u8 *aNew; i64 nNew = p->nAlloc ? p->nAlloc : 128; do { nNew = nNew*2; }while( (nNew-p->nBuf)<nByte ); aNew = (u8 *)sqlite3_realloc64(p->aBuf, nNew); if( 0==aNew ){ *pRc = SQLITE_NOMEM; }else{ p->aBuf = aNew; p->nAlloc = nNew; |
︙ | ︙ | |||
2243 2244 2245 2246 2247 2248 2249 | 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 */ | < | 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 | 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 ){ |
︙ | ︙ | |||
2548 2549 2550 2551 2552 2553 2554 | 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 */ | | < < | | | | 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 | 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 ) ); /* 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 ){ *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; /* Number of columns in table */ u8 *abPK; /* 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(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, bPatchset, pTab, &rc); |
︙ | ︙ | |||
2608 2609 2610 2611 2612 2613 2614 | int iCol; sessionAppendByte(&buf, SQLITE_INSERT, &rc); sessionAppendByte(&buf, p->bIndirect, &rc); for(iCol=0; iCol<nCol; iCol++){ sessionAppendCol(&buf, pSel, iCol, &rc); } }else{ | < | 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 | 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, bPatchset, pSel, p, abPK); } }else if( p->op!=SQLITE_INSERT ){ rc = sessionAppendDelete(&buf, bPatchset, p, nCol, abPK); } if( rc==SQLITE_OK ){ rc = sqlite3_reset(pSel); |
︙ | ︙ | |||
2669 2670 2671 2672 2673 2674 2675 | ** 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 */ ){ | < < < | < < < < < < < | 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 | ** 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 */ ){ return sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset, ppChangeset); } /* ** Streaming version of sqlite3session_changeset(). */ int sqlite3session_changeset_strm( sqlite3_session *pSession, int (*xOutput)(void *pOut, const void *pData, int nData), void *pOut ){ return sessionGenerateChangeset(pSession, 0, 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 ){ return sessionGenerateChangeset(pSession, 1, 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 */ ){ return sessionGenerateChangeset(pSession, 1, 0, 0, pnPatchset, ppPatchset); } /* ** Enable or disable the session object passed as the first argument. */ int sqlite3session_enable(sqlite3_session *pSession, int bEnable){ |
︙ | ︙ | |||
2764 2765 2766 2767 2768 2769 2770 | ret = (pTab->nEntry>0); } sqlite3_mutex_leave(sqlite3_db_mutex(pSession->db)); return (ret==0); } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | | | | | 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 | 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 */ int bInvert /* True to invert changeset */ ){ 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; /* 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); } 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); } /* ** 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); } 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); } /* ** 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){ |
︙ | ︙ | |||
3005 3006 3007 3008 3009 3010 3011 | ** 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 */ | | < < < < | 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 | ** 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 i; /* Used to iterate through columns */ int rc = SQLITE_OK; 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 ){ apOut[i] = sqlite3ValueNew(0); if( !apOut[i] ) rc = SQLITE_NOMEM; } } } if( rc==SQLITE_OK ){ |
︙ | ︙ | |||
3193 3194 3195 3196 3197 3198 3199 | 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; | < < < < | | < | > | > > > > | < > | > | | | < < | 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 | 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; p->abPK = (u8*)&p->apValue[p->nCol*2]; p->zTab = (char*)&p->abPK[p->nCol]; return (p->rc = rc); } /* ** 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 i; u8 op; assert( (paRec==0 && pnRec==0) || (paRec && pnRec) ); /* 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++){ |
︙ | ︙ | |||
3297 3298 3299 3300 3301 3302 3303 | }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; | | | | 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 | }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); 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); 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 |
︙ | ︙ | |||
3325 3326 3327 3328 3329 3330 3331 | p->apValue[i+p->nCol] = 0; } } }else if( p->bInvert ){ if( p->op==SQLITE_INSERT ) p->op = SQLITE_DELETE; else if( p->op==SQLITE_DELETE ) p->op = SQLITE_INSERT; } | | < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 | p->apValue[i+p->nCol] = 0; } } }else if( p->bInvert ){ 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 ** callback by changeset_apply(). |
︙ | ︙ | |||
3649 3650 3651 3652 3653 3654 3655 | /* 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; | | | | 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 | /* 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]); if( rc==SQLITE_OK ){ rc = sessionReadRecord(pInput, nCol, 0, &apVal[nCol]); } /* 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)]; |
︙ | ︙ | |||
3695 3696 3697 3698 3699 3700 3701 | rc = xOutput(pOut, sOut.aBuf, sOut.nBuf); sOut.nBuf = 0; if( rc!=SQLITE_OK ) goto finished_invert; } } assert( rc==SQLITE_OK ); | | | | 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 | rc = xOutput(pOut, sOut.aBuf, sOut.nBuf); sOut.nBuf = 0; if( rc!=SQLITE_OK ) goto finished_invert; } } assert( rc==SQLITE_OK ); if( pnInverted ){ *pnInverted = sOut.nBuf; *ppInverted = sOut.aBuf; sOut.aBuf = 0; }else if( sOut.nBuf>0 ){ rc = xOutput(pOut, sOut.aBuf, sOut.nBuf); } finished_invert: sqlite3_free(sOut.aBuf); sqlite3_free(apVal); sqlite3_free(sPK.aBuf); |
︙ | ︙ | |||
3752 3753 3754 3755 3756 3757 3758 | sInput.pIn = pIn; rc = sessionChangesetInvert(&sInput, xOutput, pOut, 0, 0); sqlite3_free(sInput.buf.aBuf); return rc; } | < < < < < < < < > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | 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 */ sqlite3_stmt *pUpdate; /* UPDATE statement */ sqlite3_stmt *pInsert; /* INSERT statement */ sqlite3_stmt *pSelect; /* SELECT statement */ int nCol; /* Size of azCol[] and abPK[] arrays */ const char **azCol; /* Array of column names */ u8 *abPK; /* Boolean array - true if column is in PK */ int bStat1; /* True if table is sqlite_stat1 */ int bDeferConstraints; /* True to defer constraints */ SessionBuffer constraints; /* Deferred constraints are stored here */ SessionBuffer rebase; /* Rebase information (if any) here */ u8 bRebaseStarted; /* If table header is already in rebase */ u8 bRebase; /* True to collect rebase information */ }; /* ** 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)); ** ** The DELETE statement looks like this: |
︙ | ︙ | |||
3969 3970 3971 3972 3973 3974 3975 | ){ int i; const char *zSep = ""; int rc = SQLITE_OK; SessionBuffer buf = {0, 0, 0}; int nPk = 0; | | | 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 | ){ int i; const char *zSep = ""; int rc = SQLITE_OK; SessionBuffer buf = {0, 0, 0}; int nPk = 0; sessionAppendStr(&buf, "DELETE FROM ", &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); |
︙ | ︙ | |||
4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 | 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)); ** | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | 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 a statement to UPDATE a row from database db. ** Assuming a table structure like this: ** ** CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c)); ** ** The UPDATE statement looks like this: ** ** UPDATE x SET ** a = CASE WHEN ?2 THEN ?3 ELSE a END, ** b = CASE WHEN ?5 THEN ?6 ELSE b END, ** c = CASE WHEN ?8 THEN ?9 ELSE c END, ** d = CASE WHEN ?11 THEN ?12 ELSE d END ** WHERE a = ?1 AND c = ?7 AND (?13 OR ** (?5==0 OR b IS ?4) AND (?11==0 OR d IS ?10) AND ** ) ** ** For each column in the table, there are three variables to bind: ** ** ?(i*3+1) The old.* value of the column, if any. ** ?(i*3+2) A boolean flag indicating that the value is being modified. ** ?(i*3+3) The new.* value of the column, if any. ** ** Also, a boolean flag that, if set to true, causes the statement to update ** a row even if the non-PK values do not match. This is required if the ** conflict-handler is invoked with CHANGESET_DATA and returns ** CHANGESET_REPLACE. This is variable "?(nCol*3+1)". ** ** If successful, SQLITE_OK is returned and SessionApplyCtx.pUpdate is left ** pointing to the prepared version of the SQL statement. */ static int sessionUpdateRow( sqlite3 *db, /* Database handle */ const char *zTab, /* Table name */ SessionApplyCtx *p /* Session changeset-apply context */ ){ int rc = SQLITE_OK; int i; const char *zSep = ""; SessionBuffer buf = {0, 0, 0}; /* Append "UPDATE tbl SET " */ sessionAppendStr(&buf, "UPDATE ", &rc); sessionAppendIdent(&buf, zTab, &rc); sessionAppendStr(&buf, " SET ", &rc); /* Append the assignments */ for(i=0; i<p->nCol; i++){ sessionAppendStr(&buf, zSep, &rc); sessionAppendIdent(&buf, p->azCol[i], &rc); sessionAppendStr(&buf, " = CASE WHEN ?", &rc); sessionAppendInteger(&buf, i*3+2, &rc); sessionAppendStr(&buf, " THEN ?", &rc); sessionAppendInteger(&buf, i*3+3, &rc); sessionAppendStr(&buf, " ELSE ", &rc); sessionAppendIdent(&buf, p->azCol[i], &rc); sessionAppendStr(&buf, " END", &rc); zSep = ", "; } /* Append the PK part of the WHERE clause */ sessionAppendStr(&buf, " WHERE ", &rc); for(i=0; i<p->nCol; i++){ if( p->abPK[i] ){ sessionAppendIdent(&buf, p->azCol[i], &rc); sessionAppendStr(&buf, " = ?", &rc); sessionAppendInteger(&buf, i*3+1, &rc); sessionAppendStr(&buf, " AND ", &rc); } } /* Append the non-PK part of the WHERE clause */ sessionAppendStr(&buf, " (?", &rc); sessionAppendInteger(&buf, p->nCol*3+1, &rc); sessionAppendStr(&buf, " OR 1", &rc); for(i=0; i<p->nCol; i++){ if( !p->abPK[i] ){ sessionAppendStr(&buf, " AND (?", &rc); sessionAppendInteger(&buf, i*3+2, &rc); sessionAppendStr(&buf, "=0 OR ", &rc); sessionAppendIdent(&buf, p->azCol[i], &rc); sessionAppendStr(&buf, " IS ?", &rc); sessionAppendInteger(&buf, i*3+1, &rc); sessionAppendStr(&buf, ")", &rc); } } sessionAppendStr(&buf, ")", &rc); if( rc==SQLITE_OK ){ rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pUpdate, 0); } sqlite3_free(buf.aBuf); return rc; } /* ** Formulate and prepare an SQL statement to query table zTab by primary ** key. Assuming the following table structure: ** ** CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c)); ** |
︙ | ︙ | |||
4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 | int rc = sessionSelectRow(db, "sqlite_stat1", p); if( rc==SQLITE_OK ){ rc = sessionPrepare(db, &p->pInsert, "INSERT INTO main.sqlite_stat1 VALUES(?1, " "CASE WHEN length(?2)=0 AND typeof(?2)='blob' THEN NULL ELSE ?2 END, " "?3)" ); } if( rc==SQLITE_OK ){ rc = sessionPrepare(db, &p->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)" ); | > > > > > > > > > > > | 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 | int rc = sessionSelectRow(db, "sqlite_stat1", p); if( rc==SQLITE_OK ){ rc = sessionPrepare(db, &p->pInsert, "INSERT INTO main.sqlite_stat1 VALUES(?1, " "CASE WHEN length(?2)=0 AND typeof(?2)='blob' THEN NULL ELSE ?2 END, " "?3)" ); } if( rc==SQLITE_OK ){ rc = sessionPrepare(db, &p->pUpdate, "UPDATE main.sqlite_stat1 SET " "tbl = CASE WHEN ?2 THEN ?3 ELSE tbl END, " "idx = CASE WHEN ?5 THEN ?6 ELSE idx END, " "stat = CASE WHEN ?8 THEN ?9 ELSE stat END " "WHERE tbl=?1 AND idx IS " "CASE WHEN length(?4)=0 AND typeof(?4)='blob' THEN NULL ELSE ?4 END " "AND (?10 OR ?8=0 OR stat IS ?7)" ); } if( rc==SQLITE_OK ){ rc = sessionPrepare(db, &p->pDelete, "DELETE FROM main.sqlite_stat1 WHERE tbl=?1 AND idx IS " "CASE WHEN length(?2)=0 AND typeof(?2)='blob' THEN NULL ELSE ?2 END " "AND (?4 OR stat IS ?3)" ); |
︙ | ︙ | |||
4155 4156 4157 4158 4159 4160 4161 | ** 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] ){ | | | 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 | ** 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; (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); |
︙ | ︙ | |||
4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 | ** not require a reset(). ** ** If the iterator currently points to an INSERT record, bind values from the ** new.* record to the SELECT statement. Or, if it points to a DELETE or ** UPDATE, bind values from the old.* record. */ static int sessionSeekToRow( sqlite3_changeset_iter *pIter, /* Changeset iterator */ u8 *abPK, /* Primary key flags array */ sqlite3_stmt *pSelect /* SELECT statement from sessionSelectRow() */ ){ int rc; /* Return code */ int nCol; /* Number of columns in table */ int op; /* Changset operation (SQLITE_UPDATE etc.) */ | > | 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 | ** not require a reset(). ** ** If the iterator currently points to an INSERT record, bind values from the ** new.* record to the SELECT statement. Or, if it points to a DELETE or ** UPDATE, bind values from the old.* record. */ static int sessionSeekToRow( sqlite3 *db, /* Database handle */ sqlite3_changeset_iter *pIter, /* Changeset iterator */ u8 *abPK, /* Primary key flags array */ sqlite3_stmt *pSelect /* SELECT statement from sessionSelectRow() */ ){ int rc; /* Return code */ int nCol; /* Number of columns in table */ int op; /* Changset operation (SQLITE_UPDATE etc.) */ |
︙ | ︙ | |||
4316 4317 4318 4319 4320 4321 4322 | assert( eType==SQLITE_CHANGESET_CONFLICT || eType==SQLITE_CHANGESET_DATA ); assert( SQLITE_CHANGESET_CONFLICT+1==SQLITE_CHANGESET_CONSTRAINT ); assert( SQLITE_CHANGESET_DATA+1==SQLITE_CHANGESET_NOTFOUND ); /* Bind the new.* PRIMARY KEY values to the SELECT statement. */ if( pbReplace ){ | | | 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 | assert( eType==SQLITE_CHANGESET_CONFLICT || eType==SQLITE_CHANGESET_DATA ); assert( SQLITE_CHANGESET_CONFLICT+1==SQLITE_CHANGESET_CONSTRAINT ); assert( SQLITE_CHANGESET_DATA+1==SQLITE_CHANGESET_NOTFOUND ); /* Bind the new.* PRIMARY KEY values to the SELECT statement. */ if( pbReplace ){ rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect); }else{ rc = SQLITE_OK; } if( rc==SQLITE_ROW ){ /* There exists another row with the new.* primary key. */ pIter->pConflict = p->pSelect; |
︙ | ︙ | |||
4405 4406 4407 4408 4409 4410 4411 | int *pbRetry /* OUT: True to retry. */ ){ const char *zDummy; int op; int nCol; int rc = SQLITE_OK; | | | 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 | int *pbRetry /* OUT: True to retry. */ ){ const char *zDummy; int op; int nCol; int rc = SQLITE_OK; assert( p->pDelete && p->pUpdate && p->pInsert && p->pSelect ); assert( p->azCol && p->abPK ); assert( !pbReplace || *pbReplace==0 ); sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0); if( op==SQLITE_DELETE ){ |
︙ | ︙ | |||
4445 4446 4447 4448 4449 4450 4451 | rc = sessionConflictHandler( SQLITE_CHANGESET_CONFLICT, p, pIter, xConflict, pCtx, 0 ); } }else if( op==SQLITE_UPDATE ){ int i; | < < < < | > > | | > > > | | | 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 | 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); sqlite3_bind_int(p->pUpdate, i*3+2, !!pNew); if( pOld ){ rc = sessionBindValue(p->pUpdate, i*3+1, pOld); } if( rc==SQLITE_OK && pNew ){ rc = sessionBindValue(p->pUpdate, i*3+3, pNew); } } if( rc==SQLITE_OK ){ sqlite3_bind_int(p->pUpdate, nCol*3+1, pbRetry==0 || pIter->bPatchset); } 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(p->pUpdate); rc = sqlite3_reset(p->pUpdate); 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( |
︙ | ︙ | |||
4490 4491 4492 4493 4494 4495 4496 | }else{ assert( op==SQLITE_INSERT ); if( p->bStat1 ){ /* Check if there is a conflicting row. For sqlite_stat1, this needs ** to be done using a SELECT, as there is no PRIMARY KEY in the ** database schema to throw an exception if a duplicate is inserted. */ | | | 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 | }else{ assert( op==SQLITE_INSERT ); if( p->bStat1 ){ /* Check if there is a conflicting row. For sqlite_stat1, this needs ** to be done using a SELECT, as there is no PRIMARY KEY in the ** database schema to throw an exception if a duplicate is inserted. */ rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect); if( rc==SQLITE_ROW ){ rc = SQLITE_CONSTRAINT; sqlite3_reset(p->pSelect); } } if( rc==SQLITE_OK ){ |
︙ | ︙ | |||
4597 4598 4599 4600 4601 4602 4603 | int rc = SQLITE_OK; while( pApply->constraints.nBuf ){ sqlite3_changeset_iter *pIter2 = 0; SessionBuffer cons = pApply->constraints; memset(&pApply->constraints, 0, sizeof(SessionBuffer)); | | < < | 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 | 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, 0); 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; |
︙ | ︙ | |||
4666 4667 4668 4669 4670 4671 4672 | int bPatchset; assert( xConflict!=0 ); pIter->in.bNoDiscard = 1; memset(&sApply, 0, sizeof(sApply)); sApply.bRebase = (ppRebase && pnRebase); | < | 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 | 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); } |
︙ | ︙ | |||
4689 4690 4691 4692 4693 4694 4695 | u8 *abPK; rc = sessionRetryConstraints( db, pIter->bPatchset, zTab, &sApply, xConflict, pCtx ); if( rc!=SQLITE_OK ) break; | < > > | 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 | 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); sqlite3_finalize(sApply.pUpdate); sqlite3_finalize(sApply.pInsert); sqlite3_finalize(sApply.pSelect); sApply.db = db; sApply.pDelete = 0; sApply.pUpdate = 0; sApply.pInsert = 0; sApply.pSelect = 0; sApply.nCol = 0; sApply.azCol = 0; sApply.abPK = 0; sApply.bStat1 = 0; sApply.bDeferConstraints = 1; |
︙ | ︙ | |||
4723 4724 4725 4726 4727 4728 4729 | nTab = (int)strlen(zTab); sApply.azCol = (const char **)zTab; }else{ int nMinCol = 0; int i; sqlite3changeset_pk(pIter, &abPK, 0); | | | 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 | nTab = (int)strlen(zTab); sApply.azCol = (const char **)zTab; }else{ int nMinCol = 0; int i; sqlite3changeset_pk(pIter, &abPK, 0); rc = sessionTableInfo( 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; } |
︙ | ︙ | |||
4759 4760 4761 4762 4763 4764 4765 | sApply.nCol = nCol; if( 0==sqlite3_stricmp(zTab, "sqlite_stat1") ){ if( (rc = sessionStat1Sql(db, &sApply) ) ){ break; } sApply.bStat1 = 1; }else{ | | > | | | | 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 | sApply.nCol = nCol; if( 0==sqlite3_stricmp(zTab, "sqlite_stat1") ){ if( (rc = sessionStat1Sql(db, &sApply) ) ){ break; } sApply.bStat1 = 1; }else{ if((rc = sessionSelectRow(db, zTab, &sApply)) || (rc = sessionUpdateRow(db, zTab, &sApply)) || (rc = sessionDeleteRow(db, zTab, &sApply)) || (rc = sessionInsertRow(db, zTab, &sApply)) ){ break; } sApply.bStat1 = 0; } } nTab = sqlite3Strlen30(zTab); } |
︙ | ︙ | |||
4821 4822 4823 4824 4825 4826 4827 | 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; } | < > | 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 | 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); sqlite3_finalize(sApply.pUpdate); 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; } |
︙ | ︙ | |||
4854 4855 4856 4857 4858 4859 4860 | 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 */ | | | | 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 | 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 bInverse = !!(flags & SQLITE_CHANGESETAPPLY_INVERT); int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset,bInverse); if( rc==SQLITE_OK ){ rc = sessionChangesetApply( db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags ); } return rc; } |
︙ | ︙ | |||
4913 4914 4915 4916 4917 4918 4919 | ), 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); | | | 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 | ), 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); if( rc==SQLITE_OK ){ rc = sessionChangesetApply( db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags ); } return rc; } |
︙ | ︙ | |||
5201 5202 5203 5204 5205 5206 5207 | *ppTab = pTab; }else if( pTab->nCol!=nCol || memcmp(pTab->abPK, abPK, nCol) ){ rc = SQLITE_SCHEMA; break; } } | | | 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 | *ppTab = pTab; }else if( pTab->nCol!=nCol || memcmp(pTab->abPK, abPK, nCol) ){ rc = SQLITE_SCHEMA; break; } } if( sessionGrowHash(pIter->bPatchset, pTab) ){ rc = SQLITE_NOMEM; break; } iHash = sessionChangeHash( pTab, (pIter->bPatchset && op==SQLITE_DELETE), aRec, pTab->nChange ); |
︙ | ︙ | |||
5297 5298 5299 5300 5301 5302 5303 | } } } if( rc==SQLITE_OK ){ if( xOutput ){ if( buf.nBuf>0 ) rc = xOutput(pOut, buf.aBuf, buf.nBuf); | | | | 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 | } } } if( rc==SQLITE_OK ){ if( xOutput ){ if( buf.nBuf>0 ) rc = xOutput(pOut, buf.aBuf, buf.nBuf); }else{ *ppOut = buf.aBuf; *pnOut = buf.nBuf; buf.aBuf = 0; } } sqlite3_free(buf.aBuf); return rc; } |
︙ | ︙ | |||
5387 5388 5389 5390 5391 5392 5393 | } /* ** Delete a changegroup object. */ void sqlite3changegroup_delete(sqlite3_changegroup *pGrp){ if( pGrp ){ | | | 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 | } /* ** Delete a changegroup object. */ void sqlite3changegroup_delete(sqlite3_changegroup *pGrp){ if( pGrp ){ sessionDeleteTable(pGrp->pList); sqlite3_free(pGrp); } } /* ** Combine two changesets together. */ |
︙ | ︙ | |||
5533 5534 5535 5536 5537 5538 5539 | *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 ){ | | | | 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 | *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] ) bData = 1; memcpy(pOut, a1, n1); pOut += n1; }else if( a2[0]!=0xFF ){ bData = 1; memcpy(pOut, a2, n2); pOut += n2; }else{ *pOut++ = '\0'; } a1 += n1; |
︙ | ︙ | |||
5699 5700 5701 5702 5703 5704 5705 | } if( rc==SQLITE_OK ){ if( xOutput ){ if( sOut.nBuf>0 ){ rc = xOutput(pOut, sOut.aBuf, sOut.nBuf); } | | | 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 | } if( rc==SQLITE_OK ){ if( xOutput ){ if( sOut.nBuf>0 ){ rc = xOutput(pOut, sOut.aBuf, sOut.nBuf); } }else{ *ppOut = (void*)sOut.aBuf; *pnOut = sOut.nBuf; sOut.aBuf = 0; } } sqlite3_free(sOut.aBuf); return rc; |
︙ | ︙ | |||
5788 5789 5790 5791 5792 5793 5794 | } /* ** Destroy a rebaser object */ void sqlite3rebaser_delete(sqlite3_rebaser *p){ if( p ){ | | | 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 | } /* ** Destroy a rebaser object */ void sqlite3rebaser_delete(sqlite3_rebaser *p){ if( p ){ sessionDeleteTable(p->grp.pList); sqlite3_free(p); } } /* ** Global configuration */ |
︙ | ︙ |
Changes to ext/session/sqlite3session.h.
︙ | ︙ | |||
75 76 77 78 79 80 81 | ** ** 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); | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
︙ | ︙ | |||
228 229 230 231 232 233 234 | /* ** 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. | | | 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 | /* ** 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 is 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 */ |
︙ | ︙ | |||
351 352 353 354 355 356 357 | */ int sqlite3session_changeset( sqlite3_session *pSession, /* Session object */ int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */ void **ppChangeset /* OUT: Buffer containing changeset */ ); | < < < < < < < < < < < < < < < < | 319 320 321 322 323 324 325 326 327 328 329 330 331 332 | */ int sqlite3session_changeset( 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 |
︙ | ︙ | |||
418 419 420 421 422 423 424 | ** 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. ** | | | 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 | ** 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 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, |
︙ | ︙ | |||
484 485 486 487 488 489 490 | ** 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); | < < < < < < < < | 436 437 438 439 440 441 442 443 444 445 446 447 448 449 | ** 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 |
︙ | ︙ | |||
563 564 565 566 567 568 569 | #define SQLITE_CHANGESETSTART_INVERT 0x0002 /* ** CAPI3REF: Advance A Changeset Iterator ** METHOD: sqlite3_changeset_iter ** | | | 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 | #define SQLITE_CHANGESETSTART_INVERT 0x0002 /* ** CAPI3REF: Advance A Changeset Iterator ** METHOD: sqlite3_changeset_iter ** ** This function may only be used with iterators created by 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 |
︙ | ︙ | |||
594 595 596 597 598 599 600 | ** ** 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]. ** | < < < | < < < < | | | | < > | | > > | 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 | ** ** 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]. ** ** If argument pzTab is not NULL, then *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 pnCol is not NULL, then *pnCol is ** set to the number of columns in the table affected by the change. 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. Finally, if pOp is not NULL, then *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. ** ** 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 */ |
︙ | ︙ | |||
984 985 986 987 988 989 990 | ** ** 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 | | | | 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 | ** ** 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 ** 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 |
︙ | ︙ | |||
1160 1161 1162 1163 1164 1165 1166 | ** 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. | | | 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 | ** 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 applications 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. |
︙ | ︙ | |||
1470 1471 1472 1473 1474 1475 1476 | /* ** 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 | | | 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 | /* ** 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 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. */ |
︙ | ︙ |
Changes to ext/session/test_session.c.
︙ | ︙ | |||
94 95 96 97 98 99 100 | /* Delete the session object */ sqlite3session_delete(pSession); return rc; } /************************************************************************/ | < < < < < < < < < < < < | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | /* Delete the session object */ sqlite3session_delete(pSession); return rc; } /************************************************************************/ /* ** Tclcmd: sql_exec_changeset DB SQL */ static int SQLITE_TCLAPI test_sql_exec_changeset( void * clientData, Tcl_Interp *interp, int objc, |
︙ | ︙ | |||
135 136 137 138 139 140 141 | rc = sql_exec_changeset(db, zSql, &nChangeset, &pChangeset); if( rc!=SQLITE_OK ){ Tcl_ResetResult(interp); Tcl_AppendResult(interp, "error in sql_exec_changeset()", 0); return TCL_ERROR; } | < < < | < | 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 | rc = sql_exec_changeset(db, zSql, &nChangeset, &pChangeset); if( rc!=SQLITE_OK ){ Tcl_ResetResult(interp); Tcl_AppendResult(interp, "error in sql_exec_changeset()", 0); return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pChangeset, nChangeset)); sqlite3_free(pChangeset); return TCL_OK; } #define SESSION_STREAM_TCL_VAR "sqlite3session_streams" /* ** Attempt to find the global variable zVar within interpreter interp ** and extract an integer value from it. Return this value. ** ** 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; pObj = Tcl_ObjGetVar2(interp, Tcl_NewStringObj(zVar, -1), 0, TCL_GLOBAL_ONLY); 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)); |
︙ | ︙ | |||
239 240 241 242 243 244 245 | void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ TestSession *p = (TestSession*)clientData; sqlite3_session *pSession = p->pSession; | | < < < | 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 | void *clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ TestSession *p = (TestSession*)clientData; sqlite3_session *pSession = p->pSession; struct SessionSubcmd { const char *zSub; int nArg; const char *zMsg; int iSub; } 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 */ { 0 } }; int iSub; int rc; if( objc<2 ){ Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ..."); |
︙ | ︙ | |||
304 305 306 307 308 309 310 | if( iSub==7 ){ rc = sqlite3session_patchset(pSession, &o.n, &o.p); }else{ rc = sqlite3session_changeset(pSession, &o.n, &o.p); } } if( rc==SQLITE_OK ){ | < | 285 286 287 288 289 290 291 292 293 294 295 296 297 298 | if( iSub==7 ){ rc = sqlite3session_patchset(pSession, &o.n, &o.p); }else{ rc = sqlite3session_changeset(pSession, &o.n, &o.p); } } if( rc==SQLITE_OK ){ Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(o.p, o.n)); } sqlite3_free(o.p); if( rc!=SQLITE_OK ){ return test_session_error(interp, rc, 0); } break; |
︙ | ︙ | |||
363 364 365 366 367 368 369 | ); assert( rc!=SQLITE_OK || zErr==0 ); if( rc ){ return test_session_error(interp, rc, zErr); } break; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 343 344 345 346 347 348 349 350 351 352 353 354 355 356 | ); 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; |
︙ | ︙ | |||
417 418 419 420 421 422 423 | int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; Tcl_CmdInfo info; int rc; /* sqlite3session_create() return code */ TestSession *p; /* New wrapper object */ | < < < < < < < < | 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 | 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; } |
︙ | ︙ | |||
963 964 965 966 967 968 969 | ); }else{ rc = sqlite3changeset_invert(sIn.nData, sIn.aData, &sOut.n, &sOut.p); } if( rc!=SQLITE_OK ){ rc = test_session_error(interp, rc, 0); }else{ | < | 906 907 908 909 910 911 912 913 914 915 916 917 918 919 | ); }else{ rc = sqlite3changeset_invert(sIn.nData, sIn.aData, &sOut.n, &sOut.p); } if( rc!=SQLITE_OK ){ rc = test_session_error(interp, rc, 0); }else{ Tcl_SetObjResult(interp,Tcl_NewByteArrayObj((unsigned char*)sOut.p,sOut.n)); } sqlite3_free(sOut.p); return rc; } /* |
︙ | ︙ | |||
1012 1013 1014 1015 1016 1017 1018 | sLeft.nData, sLeft.aData, sRight.nData, sRight.aData, &sOut.n, &sOut.p ); } if( rc!=SQLITE_OK ){ rc = test_session_error(interp, rc, 0); }else{ | < | 954 955 956 957 958 959 960 961 962 963 964 965 966 967 | sLeft.nData, sLeft.aData, sRight.nData, sRight.aData, &sOut.n, &sOut.p ); } if( rc!=SQLITE_OK ){ rc = test_session_error(interp, rc, 0); }else{ Tcl_SetObjResult(interp,Tcl_NewByteArrayObj((unsigned char*)sOut.p,sOut.n)); } sqlite3_free(sOut.p); return rc; } /* |
︙ | ︙ | |||
1186 1187 1188 1189 1190 1191 1192 | */ static int SQLITE_TCLAPI test_rebaser_cmd( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ | | | 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 | */ static int SQLITE_TCLAPI test_rebaser_cmd( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ struct RebaseSubcmd { const char *zSub; int nArg; const char *zMsg; int iSub; } aSub[] = { { "configure", 1, "REBASE-BLOB" }, /* 0 */ { "delete", 0, "" }, /* 1 */ |
︙ | ︙ | |||
1248 1249 1250 1251 1252 1253 1254 | testStreamOutput, (void*)&sOut ); }else{ rc = sqlite3rebaser_rebase(p, sStr.nData, sStr.aData, &sOut.n, &sOut.p); } if( rc==SQLITE_OK ){ | < | 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 | testStreamOutput, (void*)&sOut ); }else{ rc = sqlite3rebaser_rebase(p, sStr.nData, sStr.aData, &sOut.n, &sOut.p); } if( rc==SQLITE_OK ){ Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(sOut.p, sOut.n)); } sqlite3_free(sOut.p); break; } } |
︙ | ︙ | |||
1295 1296 1297 1298 1299 1300 1301 1302 | Tcl_CreateObjCommand(interp, Tcl_GetString(objv[1]), test_rebaser_cmd, (ClientData)pNew, test_rebaser_del ); Tcl_SetObjResult(interp, objv[1]); return TCL_OK; } /* | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 | Tcl_CreateObjCommand(interp, Tcl_GetString(objv[1]), test_rebaser_cmd, (ClientData)pNew, test_rebaser_del ); Tcl_SetObjResult(interp, objv[1]); return TCL_OK; } /* ** tclcmd: sqlite3rebaser_configure OP VALUE */ static int SQLITE_TCLAPI test_sqlite3session_config( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ struct ConfigOpt { const char *zSub; int op; } aSub[] = { { "strm_size", SQLITE_SESSION_CONFIG_STRMSIZE }, { "invalid", 0 }, { 0 } }; |
︙ | ︙ | |||
1451 1452 1453 1454 1455 1456 1457 | { "sqlite3changeset_apply", test_sqlite3changeset_apply }, { "sqlite3changeset_apply_v2", test_sqlite3changeset_apply_v2 }, { "sqlite3changeset_apply_replace_all", test_sqlite3changeset_apply_replace_all }, { "sql_exec_changeset", test_sql_exec_changeset }, { "sqlite3rebaser_create", test_sqlite3rebaser_create }, { "sqlite3session_config", test_sqlite3session_config }, | < | 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 | { "sqlite3changeset_apply", test_sqlite3changeset_apply }, { "sqlite3changeset_apply_v2", test_sqlite3changeset_apply_v2 }, { "sqlite3changeset_apply_replace_all", test_sqlite3changeset_apply_replace_all }, { "sql_exec_changeset", test_sql_exec_changeset }, { "sqlite3rebaser_create", test_sqlite3rebaser_create }, { "sqlite3session_config", test_sqlite3session_config }, }; int i; for(i=0; i<sizeof(aCmd)/sizeof(struct Cmd); i++){ struct Cmd *p = &aCmd[i]; Tcl_CreateObjCommand(interp, p->zCmd, p->xProc, 0, 0); } return TCL_OK; } #endif /* SQLITE_TEST && SQLITE_SESSION && SQLITE_PREUPDATE_HOOK */ |
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; int 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); |
︙ | ︙ |
Deleted ext/wasm/EXPORTED_FUNCTIONS.fiddle.in.
|
| < < < < < < < < < < |
Deleted ext/wasm/GNUmakefile.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/README-dist.txt.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/README.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api.
|
| < < < |
Deleted ext/wasm/api/README.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/api/extern-post-js.c-pp.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/api/extern-pre-js.js.
|
| < < < < < < < |
Deleted ext/wasm/api/post-js-footer.js.
|
| < < < < |
Deleted ext/wasm/api/post-js-header.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/api/pre-js.c-pp.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/api/sqlite3-api-cleanup.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/api/sqlite3-api-glue.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/api/sqlite3-api-oo1.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/api/sqlite3-api-prologue.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/api/sqlite3-api-worker1.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/api/sqlite3-license-version-header.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/api/sqlite3-opfs-async-proxy.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/api/sqlite3-v-helper.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/api/sqlite3-vfs-opfs.c-pp.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/api/sqlite3-wasi.h.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/api/sqlite3-wasm.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/api/sqlite3-worker1-promiser.c-pp.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/api/sqlite3-worker1.c-pp.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/batch-runner.html.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/batch-runner.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/c-pp.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/common/SqliteTestUtil.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/common/emscripten.css.
|
| < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/common/testing.css.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/common/whwasmutil.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/demo-123-worker.html.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/demo-123.html.
|
| < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/demo-123.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/demo-jsstorage.html.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/demo-jsstorage.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/demo-worker1-promiser.html.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/demo-worker1-promiser.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/demo-worker1.html.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/demo-worker1.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/dist.make.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/fiddle.make.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/fiddle/emscripten.css.
|
| < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/fiddle/fiddle-worker.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/fiddle/fiddle.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/fiddle/index.html.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/index-dist.html.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/index.html.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/jaccwabyt/jaccwabyt.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/jaccwabyt/jaccwabyt.md.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/module-symbols.html.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/scratchpad-wasmfs-main.html.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/scratchpad-wasmfs-main.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/speedtest1-wasmfs.html.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/speedtest1-worker.html.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/speedtest1-worker.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/speedtest1.html.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/split-speedtest1-script.sh.
|
| < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/sql/000-mandelbrot.sql.
|
| < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/sql/001-sudoku.sql.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/test-opfs-vfs.html.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/test-opfs-vfs.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/tester1-worker.html.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/tester1.c-pp.html.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/tester1.c-pp.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/tests/opfs/concurrency/index.html.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/tests/opfs/concurrency/test.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/tests/opfs/concurrency/worker.js.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/version-info.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted ext/wasm/wasmfs.make.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to magic.txt.
1 2 3 4 5 6 7 8 9 10 11 | # This file contains suggested magic(5) text for the unix file(1) # utility for recognizing SQLite3 databases. # # When SQLite is used as an application file format, it is desirable to # have file(1) recognize the database file as being with the specific # application. You can set the application_id for a database file # using: # # PRAGMA application_id = INTEGER; # # INTEGER can be any signed 32-bit integer. That integer is written as | | | | | < | 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 | # This file contains suggested magic(5) text for the unix file(1) # utility for recognizing SQLite3 databases. # # When SQLite is used as an application file format, it is desirable to # have file(1) recognize the database file as being with the specific # application. You can set the application_id for a database file # using: # # PRAGMA application_id = INTEGER; # # INTEGER can be any signed 32-bit integer. That integer is written as # a 4-byte big-endian integer into offset 68 of the database header. # # The Monotone application used "PRAGMA user_version=1598903374;" to set # its identifier long before "PRAGMA application_id" became available. # The user_version is very similar to application_id except that it is # stored at offset 68 instead of offset 60. The application_id pragma # is preferred. The rule using offset 60 for Monotone is for historical # compatibility only. # 0 string =SQLite\ format\ 3 >68 belong =0x0f055112 Fossil checkout - >68 belong =0x0f055113 Fossil global configuration - >68 belong =0x0f055111 Fossil repository - >68 belong =0x42654462 Bentley Systems BeSQLite Database - >68 belong =0x42654c6e Bentley Systems Localization File - >60 belong =0x5f4d544e Monotone source repository - >68 belong =0x47504b47 OGC GeoPackage file - >68 belong =0x47503130 OGC GeoPackage version 1.0 file - >68 belong =0x45737269 Esri Spatially-Enabled Database - >68 belong =0x4d504258 MBTiles tileset - >0 string =SQLite SQLite3 database |
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. |
︙ | ︙ | |||
60 61 62 63 64 65 66 | date.o dbpage.o dbstat.o delete.o expr.o \ fault.o fkey.o \ fts3.o fts3_aux.o fts3_expr.o fts3_hash.o fts3_icu.o fts3_porter.o \ fts3_snippet.o fts3_tokenizer.o fts3_tokenizer1.o \ fts3_tokenize_vtab.o \ fts3_unicode.o fts3_unicode2.o \ fts3_write.o fts5.o func.o global.o hash.o \ | | | < | | 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 | date.o dbpage.o dbstat.o delete.o expr.o \ fault.o fkey.o \ fts3.o fts3_aux.o fts3_expr.o fts3_hash.o fts3_icu.o fts3_porter.o \ fts3_snippet.o fts3_tokenizer.o fts3_tokenizer1.o \ fts3_tokenize_vtab.o \ fts3_unicode.o fts3_unicode2.o \ fts3_write.o fts5.o func.o global.o hash.o \ icu.o insert.o json1.o legacy.o loadext.o \ main.o malloc.o mem0.o mem1.o mem2.o mem3.o mem5.o \ memdb.o memjournal.o \ mutex.o mutex_noop.o mutex_unix.o mutex_w32.o \ notify.o opcodes.o os.o os_unix.o os_win.o \ pager.o pcache.o pcache1.o pragma.o prepare.o printf.o \ random.o resolve.o rowset.o rtree.o \ select.o sqlite3rbu.o status.o 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 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 = \ |
︙ | ︙ | |||
107 108 109 110 111 112 113 | $(TOP)/src/fkey.c \ $(TOP)/src/func.c \ $(TOP)/src/global.c \ $(TOP)/src/hash.c \ $(TOP)/src/hash.h \ $(TOP)/src/hwtime.h \ $(TOP)/src/insert.c \ | < | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | $(TOP)/src/fkey.c \ $(TOP)/src/func.c \ $(TOP)/src/global.c \ $(TOP)/src/hash.c \ $(TOP)/src/hash.h \ $(TOP)/src/hwtime.h \ $(TOP)/src/insert.c \ $(TOP)/src/legacy.c \ $(TOP)/src/loadext.c \ $(TOP)/src/main.c \ $(TOP)/src/malloc.c \ $(TOP)/src/mem0.c \ $(TOP)/src/mem1.c \ $(TOP)/src/mem2.c \ |
︙ | ︙ | |||
130 131 132 133 134 135 136 | $(TOP)/src/mutex_unix.c \ $(TOP)/src/mutex_w32.c \ $(TOP)/src/notify.c \ $(TOP)/src/os.c \ $(TOP)/src/os.h \ $(TOP)/src/os_common.h \ $(TOP)/src/os_setup.h \ | < | 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | $(TOP)/src/mutex_unix.c \ $(TOP)/src/mutex_w32.c \ $(TOP)/src/notify.c \ $(TOP)/src/os.c \ $(TOP)/src/os.h \ $(TOP)/src/os_common.h \ $(TOP)/src/os_setup.h \ $(TOP)/src/os_unix.c \ $(TOP)/src/os_win.c \ $(TOP)/src/os_win.h \ $(TOP)/src/pager.c \ $(TOP)/src/pager.h \ $(TOP)/src/parse.y \ $(TOP)/src/pcache.c \ |
︙ | ︙ | |||
173 174 175 176 177 178 179 | $(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 \ | < > > > > > > > > > > > > > > > > > > | 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 | $(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 \ $(TOP)/src/wherecode.c \ $(TOP)/src/whereexpr.c \ $(TOP)/src/whereInt.h \ $(TOP)/src/window.c # Source code for extensions # SRC += \ $(TOP)/ext/fts1/fts1.c \ $(TOP)/ext/fts1/fts1.h \ $(TOP)/ext/fts1/fts1_hash.c \ $(TOP)/ext/fts1/fts1_hash.h \ $(TOP)/ext/fts1/fts1_porter.c \ $(TOP)/ext/fts1/fts1_tokenizer.h \ $(TOP)/ext/fts1/fts1_tokenizer1.c SRC += \ $(TOP)/ext/fts2/fts2.c \ $(TOP)/ext/fts2/fts2.h \ $(TOP)/ext/fts2/fts2_hash.c \ $(TOP)/ext/fts2/fts2_hash.h \ $(TOP)/ext/fts2/fts2_icu.c \ $(TOP)/ext/fts2/fts2_porter.c \ $(TOP)/ext/fts2/fts2_tokenizer.h \ $(TOP)/ext/fts2/fts2_tokenizer.c \ $(TOP)/ext/fts2/fts2_tokenizer1.c SRC += \ $(TOP)/ext/fts3/fts3.c \ $(TOP)/ext/fts3/fts3.h \ $(TOP)/ext/fts3/fts3Int.h \ $(TOP)/ext/fts3/fts3_aux.c \ $(TOP)/ext/fts3/fts3_expr.c \ $(TOP)/ext/fts3/fts3_hash.c \ $(TOP)/ext/fts3/fts3_hash.h \ |
︙ | ︙ | |||
224 225 226 227 228 229 230 231 232 233 234 235 236 237 | SRC += \ $(TOP)/ext/userauth/userauth.c \ $(TOP)/ext/userauth/sqlite3userauth.h SRC += \ $(TOP)/ext/rbu/sqlite3rbu.c \ $(TOP)/ext/rbu/sqlite3rbu.h SRC += \ $(TOP)/ext/misc/stmt.c # FTS5 things # FTS5_HDR = \ $(TOP)/ext/fts5/fts5.h \ | > | 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 | SRC += \ $(TOP)/ext/userauth/userauth.c \ $(TOP)/ext/userauth/sqlite3userauth.h SRC += \ $(TOP)/ext/rbu/sqlite3rbu.c \ $(TOP)/ext/rbu/sqlite3rbu.h SRC += \ $(TOP)/ext/misc/json1.c \ $(TOP)/ext/misc/stmt.c # FTS5 things # FTS5_HDR = \ $(TOP)/ext/fts5/fts5.h \ |
︙ | ︙ | |||
294 295 296 297 298 299 300 301 302 303 304 305 306 307 | $(TOP)/ext/rbu/test_rbu.c \ $(TOP)/src/test1.c \ $(TOP)/src/test2.c \ $(TOP)/src/test3.c \ $(TOP)/src/test4.c \ $(TOP)/src/test5.c \ $(TOP)/src/test6.c \ $(TOP)/src/test8.c \ $(TOP)/src/test9.c \ $(TOP)/src/test_autoext.c \ $(TOP)/src/test_async.c \ $(TOP)/src/test_backup.c \ $(TOP)/src/test_bestindex.c \ $(TOP)/src/test_blob.c \ | > | 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 | $(TOP)/ext/rbu/test_rbu.c \ $(TOP)/src/test1.c \ $(TOP)/src/test2.c \ $(TOP)/src/test3.c \ $(TOP)/src/test4.c \ $(TOP)/src/test5.c \ $(TOP)/src/test6.c \ $(TOP)/src/test7.c \ $(TOP)/src/test8.c \ $(TOP)/src/test9.c \ $(TOP)/src/test_autoext.c \ $(TOP)/src/test_async.c \ $(TOP)/src/test_backup.c \ $(TOP)/src/test_bestindex.c \ $(TOP)/src/test_blob.c \ |
︙ | ︙ | |||
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 | $(TOP)/src/test_mutex.c \ $(TOP)/src/test_onefile.c \ $(TOP)/src/test_osinst.c \ $(TOP)/src/test_pcache.c \ $(TOP)/src/test_quota.c \ $(TOP)/src/test_rtree.c \ $(TOP)/src/test_schema.c \ $(TOP)/src/test_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 \ | > < < < < < | < < < < > < < < | < | 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 | $(TOP)/src/test_mutex.c \ $(TOP)/src/test_onefile.c \ $(TOP)/src/test_osinst.c \ $(TOP)/src/test_pcache.c \ $(TOP)/src/test_quota.c \ $(TOP)/src/test_rtree.c \ $(TOP)/src/test_schema.c \ $(TOP)/src/test_server.c \ $(TOP)/src/test_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/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/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 #TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c #TESTSRC += $(TOP)/ext/fts3/fts3_tokenizer.c TESTSRC2 = \ $(TOP)/src/attach.c \ $(TOP)/src/backup.c \ $(TOP)/src/btree.c \ $(TOP)/src/build.c \ $(TOP)/src/date.c \ $(TOP)/src/dbpage.c \ $(TOP)/src/dbstat.c \ $(TOP)/src/expr.c \ $(TOP)/src/func.c \ $(TOP)/src/global.c \ $(TOP)/src/insert.c \ $(TOP)/src/wal.c \ $(TOP)/src/main.c \ $(TOP)/src/mem5.c \ $(TOP)/src/os.c \ $(TOP)/src/os_unix.c \ $(TOP)/src/os_win.c \ $(TOP)/src/pager.c \ $(TOP)/src/pragma.c \ $(TOP)/src/prepare.c \ $(TOP)/src/printf.c \ $(TOP)/src/random.c \ $(TOP)/src/pcache.c \ $(TOP)/src/pcache1.c \ $(TOP)/src/select.c \ $(TOP)/src/threads.c \ $(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/test_session.c # Header files used by all library source files. # HDR = \ $(TOP)/src/btree.h \ $(TOP)/src/btreeInt.h \ $(TOP)/src/hash.h \ |
︙ | ︙ | |||
458 459 460 461 462 463 464 465 466 467 468 469 470 471 | $(TOP)/src/vdbeInt.h \ $(TOP)/src/vxworks.h \ $(TOP)/src/whereInt.h # Header files used by extensions # EXTHDR += \ $(TOP)/ext/fts3/fts3.h \ $(TOP)/ext/fts3/fts3Int.h \ $(TOP)/ext/fts3/fts3_hash.h \ $(TOP)/ext/fts3/fts3_tokenizer.h EXTHDR += \ $(TOP)/ext/rtree/rtree.h \ $(TOP)/ext/rtree/geopoly.c | > > > > > > > > | 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 | $(TOP)/src/vdbeInt.h \ $(TOP)/src/vxworks.h \ $(TOP)/src/whereInt.h # Header files used by extensions # EXTHDR += \ $(TOP)/ext/fts1/fts1.h \ $(TOP)/ext/fts1/fts1_hash.h \ $(TOP)/ext/fts1/fts1_tokenizer.h EXTHDR += \ $(TOP)/ext/fts2/fts2.h \ $(TOP)/ext/fts2/fts2_hash.h \ $(TOP)/ext/fts2/fts2_tokenizer.h EXTHDR += \ $(TOP)/ext/fts3/fts3.h \ $(TOP)/ext/fts3/fts3Int.h \ $(TOP)/ext/fts3/fts3_hash.h \ $(TOP)/ext/fts3/fts3_tokenizer.h EXTHDR += \ $(TOP)/ext/rtree/rtree.h \ $(TOP)/ext/rtree/geopoly.c |
︙ | ︙ | |||
503 504 505 506 507 508 509 | # Standard options to testfixture # TESTOPTS = --verbose=file --output=test-out.txt # Extra compiler options for various shell tools # | | | | | | | | | < < < < < < < | | | | 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 | # Standard options to testfixture # TESTOPTS = --verbose=file --output=test-out.txt # Extra compiler options for various shell tools # SHELL_OPT += -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5 SHELL_OPT += -DSQLITE_ENABLE_RTREE SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC SHELL_OPT += -DSQLITE_INTROSPECTION_PRAGMAS 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_DESERIALIZE FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS4 FUZZCHECK_OPT += -DSQLITE_ENABLE_RTREE FUZZCHECK_OPT += -DSQLITE_ENABLE_GEOPOLY FUZZCHECK_OPT += -DSQLITE_ENABLE_DBSTAT_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 libsqlite3.a sqlite3$(EXE) libsqlite3.a: $(LIBOBJ) $(AR) libsqlite3.a $(LIBOBJ) $(RANLIB) libsqlite3.a sqlite3$(EXE): shell.c libsqlite3.a sqlite3.h $(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) |
︙ | ︙ | |||
575 576 577 578 579 580 581 582 583 | $(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 \ | > < | | | 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 | $(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_ENABLE_DESERIALIZE \ -DSQLITE_DEBUG \ -DSQLITE_ENABLE_DBSTAT_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 \ -DSQLITE_ENABLE_MEMSYS5 $(FUZZCHECK_OPT) \ $(TOP)/test/ossfuzz.c $(TOP)/test/ossshell.c sqlite3.c $(TLIBS) $(THREADLIB) sessionfuzz$(EXE): $(TOP)/test/sessionfuzz.c sqlite3.c sqlite3.h |
︙ | ︙ | |||
647 648 649 650 651 652 653 | 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 | | > > > > > > | 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 | echo '#endif /* USE_SYSTEM_SQLITE */' >>tclsqlite3.c cat $(TOP)/src/tclsqlite.c >>tclsqlite3.c sqlite3ext.h: target_source cp tsrc/sqlite3ext.h . sqlite3.c-debug: target_source $(TOP)/tool/mksqlite3c.tcl tclsh $(TOP)/tool/mksqlite3c.tcl --linemacros echo '#ifndef USE_SYSTEM_SQLITE' >tclsqlite3.c cat sqlite3.c >>tclsqlite3.c echo '#endif /* USE_SYSTEM_SQLITE */' >>tclsqlite3.c echo '#line 1 "tclsqlite.c"' >>tclsqlite3.c cat $(TOP)/src/tclsqlite.c >>tclsqlite3.c sqlite3-all.c: sqlite3.c $(TOP)/tool/split-sqlite3c.tcl tclsh $(TOP)/tool/split-sqlite3c.tcl fts2amal.c: target_source $(TOP)/ext/fts2/mkfts2amal.tcl tclsh $(TOP)/ext/fts2/mkfts2amal.tcl fts3amal.c: target_source $(TOP)/ext/fts3/mkfts3amal.tcl tclsh $(TOP)/ext/fts3/mkfts3amal.tcl # Rules to build the LEMON compiler generator # lemon: $(TOP)/tool/lemon.c $(TOP)/tool/lempar.c $(BCC) -o lemon $(TOP)/tool/lemon.c cp $(TOP)/tool/lempar.c . |
︙ | ︙ | |||
707 708 709 710 711 712 713 | 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 | < < < < < < < | < < | < < < < < < < > > > > > > > > > > > > > > > > > > | 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 | 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 keywordhash.h: $(TOP)/tool/mkkeywordhash.c $(BCC) -o mkkeywordhash $(OPTS) $(TOP)/tool/mkkeywordhash.c ./mkkeywordhash >keywordhash.h # Source files that go into making shell.c SHELL_SRC = \ $(TOP)/src/shell.c.in \ $(TOP)/ext/misc/appendvfs.c \ $(TOP)/ext/misc/shathree.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/completion.c \ $(TOP)/ext/misc/sqlar.c \ $(TOP)/ext/expert/sqlite3expert.c \ $(TOP)/ext/expert/sqlite3expert.h \ $(TOP)/ext/misc/zipfile.c \ $(TOP)/ext/misc/memtrace.c \ $(TOP)/src/test_windirent.c shell.c: $(SHELL_SRC) $(TOP)/tool/mkshellc.tcl tclsh $(TOP)/tool/mkshellc.tcl >shell.c # Rules to build the extension objects. # icu.o: $(TOP)/ext/icu/icu.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/icu/icu.c fts2.o: $(TOP)/ext/fts2/fts2.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2.c fts2_hash.o: $(TOP)/ext/fts2/fts2_hash.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2_hash.c fts2_icu.o: $(TOP)/ext/fts2/fts2_icu.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2_icu.c fts2_porter.o: $(TOP)/ext/fts2/fts2_porter.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2_porter.c fts2_tokenizer.o: $(TOP)/ext/fts2/fts2_tokenizer.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2_tokenizer.c fts2_tokenizer1.o: $(TOP)/ext/fts2/fts2_tokenizer1.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts2/fts2_tokenizer1.c fts3.o: $(TOP)/ext/fts3/fts3.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3.c fts3_aux.o: $(TOP)/ext/fts3/fts3_aux.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_aux.c fts3_expr.o: $(TOP)/ext/fts3/fts3_expr.c $(HDR) $(EXTHDR) |
︙ | ︙ | |||
790 791 792 793 794 795 796 | 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 | | > > > | | 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 | fts3_unicode2.o: $(TOP)/ext/fts3/fts3_unicode2.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_unicode2.c fts3_write.o: $(TOP)/ext/fts3/fts3_write.c $(HDR) $(EXTHDR) $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_write.c fts5.o: fts5.c $(TCCX) -DSQLITE_CORE -c fts5.c json1.o: $(TOP)/ext/misc/json1.c $(TCCX) -DSQLITE_CORE -c $(TOP)/ext/misc/json1.c stmt.o: $(TOP)/ext/misc/stmt.c $(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 |
︙ | ︙ | |||
874 875 876 877 878 879 880 | # 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 | < < > > > > > > > > > > | < < < < < < < < < < | < < < < | 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 | # 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 \ $(TOP)/ext/session/test_session.c $(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS) \ $(TESTSRC) $(TOP)/src/tclsqlite.c sqlite3.c \ $(TOP)/ext/session/test_session.c \ -o testfixture$(EXE) $(LIBTCL) $(THREADLIB) fts3-testfixture$(EXE): sqlite3.c fts3amal.c $(TESTSRC) $(TOP)/src/tclsqlite.c $(TCCX) $(TCL_FLAGS) $(TESTFIXTURE_FLAGS) \ -DSQLITE_ENABLE_FTS3=1 \ $(TESTSRC) $(TOP)/src/tclsqlite.c sqlite3.c fts3amal.c \ -o testfixture$(EXE) $(LIBTCL) $(THREADLIB) coretestprogs: $(TESTPROGS) testprogs: coretestprogs srcck1$(EXE) fuzzcheck$(EXE) sessionfuzz$(EXE) fulltest: $(TESTPROGS) fuzztest ./testfixture$(EXE) $(TOP)/test/all.test $(TESTOPTS) soaktest: $(TESTPROGS) ./testfixture$(EXE) $(TOP)/test/all.test -soak=1 $(TESTOPTS) fulltestonly: $(TESTPROGS) fuzztest ./testfixture$(EXE) $(TOP)/test/full.test $(TESTOPTS) 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 fastfuzztest: fuzzcheck$(EXE) $(FUZZDATA) sessionfuzz$(EXE) $(TOP)/test/sessionfuzz-data1.db ./fuzzcheck$(EXE) --limit-mem 100M $(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 --timeout 600 $(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: fastfuzztest 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) # 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 \ |
︙ | ︙ | |||
1047 1048 1049 1050 1051 1052 1053 | 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) | < < < | | | 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 | 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 # amalgamation-tarball: sqlite3.c TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --normal snapshot-tarball: sqlite3.c TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --snapshot # Standard install and cleanup targets # install: sqlite3 libsqlite3.a sqlite3.h mv sqlite3 /usr/bin |
︙ | ︙ | |||
1112 1113 1114 1115 1116 1117 1118 | 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 | < | 1119 1120 1121 1122 1123 1124 1125 | 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 |
Deleted sqlite_cfg.h.in.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/alter.c.
︙ | ︙ | |||
25 26 27 28 29 30 31 | ** (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){ | | < | < < < < < < < | | | | | | | | < < < < | < < < < < < < < < < < < < < < < < < < < | | | | 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 | ** (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_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, const char *zDb, int bTemp){ sqlite3NestedParse(pParse, "SELECT 1 " "FROM \"%w\".%s " "WHERE name NOT LIKE 'sqlite_%%'" " AND sql NOT LIKE 'create virtual%%'" " AND sqlite_rename_test(%Q, sql, type, name, %d)=NULL ", zDb, MASTER_NAME, zDb, bTemp ); if( bTemp==0 ){ sqlite3NestedParse(pParse, "SELECT 1 " "FROM temp.%s " "WHERE name NOT LIKE 'sqlite_%%'" " AND sql NOT LIKE 'create virtual%%'" " AND sqlite_rename_test(%Q, sql, type, name, 1)=NULL ", MASTER_NAME, zDb ); } } /* ** 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){ Vdbe *v = pParse->pVdbe; if( v ){ sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iDb, 0); if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, 1, 0); } } /* ** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy" ** command. */ |
︙ | ︙ | |||
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | 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. */ | > > > | < < < | | 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 | 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() */ u32 savedDbFlags; /* Saved value of db->mDbFlags */ savedDbFlags = db->mDbFlags; 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; db->mDbFlags |= DBFLAG_PreferBuiltin; /* 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) ){ 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( pTab->pSelect ){ sqlite3ErrorMsg(pParse, "view %s may not be altered", pTab->zName); goto exit_rename_table; } #endif #ifndef SQLITE_OMIT_AUTHORIZATION /* Invoke the authorization callback. */ |
︙ | ︙ | |||
210 211 212 213 214 215 216 | /* 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, | | | | | | < | | | | | | < | < < < < < < < < < < < < < < | 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 | /* 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\".%s 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 'sqlite_%%'" , zDb, MASTER_NAME, zDb, zTabName, zName, (iDb==1), zTabName ); /* Update the tbl_name and name columns of the sqlite_master table ** as required. */ sqlite3NestedParse(pParse, "UPDATE %Q.%s SET " "tbl_name = %Q, " "name = CASE " "WHEN type='table' THEN %Q " "WHEN name LIKE 'sqlite_autoindex%%' 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, MASTER_NAME, 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_master 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) " "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); renameTestSchema(pParse, zDb, iDb==1); exit_rename_table: sqlite3SrcListDelete(db, pSrc); sqlite3DbFree(db, zName); db->mDbFlags = savedDbFlags; } /* ** This function is called after an "ALTER TABLE ... ADD" statement ** has been parsed. Argument pColDef contains the text of the new ** column definition. ** |
︙ | ︙ | |||
320 321 322 323 324 325 326 | Column *pCol; /* The new column */ Expr *pDflt; /* Default value for the new column */ sqlite3 *db; /* The database connection; */ Vdbe *v; /* The prepared statement under construction */ int r1; /* Temporary registers */ db = pParse->db; | < | < | > > > > > > > > | < < < < < < < < < < < | | | > | | | | > | < | | | | | | | | | | | | | < | > | | | < < < < > | < < < | < | | > < < | | | | > > | > | | < < < < < < < < < < < < < < < < | 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 | Column *pCol; /* The new column */ Expr *pDflt; /* Default value for the new column */ sqlite3 *db; /* The database connection; */ Vdbe *v; /* The prepared statement under construction */ int r1; /* Temporary registers */ db = pParse->db; if( pParse->nErr || db->mallocFailed ) return; pNew = pParse->pNewTable; 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 = pCol->pDflt; 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 /* 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; } /* 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( (db->flags&SQLITE_ForeignKeys) && pNew->pFKey && pDflt ){ sqlite3ErrorMsg(pParse, "Cannot add a REFERENCES column with non-NULL default value"); return; } if( pCol->notNull && !pDflt ){ sqlite3ErrorMsg(pParse, "Cannot add a NOT NULL column with default value NULL"); return; } /* 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 ){ sqlite3ErrorMsg(pParse, "Cannot add a column with non-constant default"); return; } sqlite3ValueFree(pVal); } /* Modify the CREATE TABLE statement. */ zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n); if( zCol ){ char *zEnd = &zCol[pColDef->n-1]; u32 savedDbFlags = db->mDbFlags; while( zEnd>zCol && (*zEnd==';' || sqlite3Isspace(*zEnd)) ){ *zEnd-- = '\0'; } db->mDbFlags |= DBFLAG_PreferBuiltin; sqlite3NestedParse(pParse, "UPDATE \"%w\".%s SET " "sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d) " "WHERE type = 'table' AND name = %Q", zDb, MASTER_NAME, pNew->addColOffset, zCol, pNew->addColOffset+1, zTab ); sqlite3DbFree(db, zCol); db->mDbFlags = savedDbFlags; } /* 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. */ v = sqlite3GetVdbe(pParse); if( v ){ 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); } /* ** 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. ** |
︙ | ︙ | |||
494 495 496 497 498 499 500 | 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. */ | | < < | | 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 | 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( pTab->pSelect ){ 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; } assert( pTab->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_" |
︙ | ︙ | |||
531 532 533 534 535 536 537 | 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]; | | | > < < | | | | < | | | 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 | 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->zName = sqlite3DbStrDup(db, pCol->zName); pCol->zColl = 0; pCol->pDflt = 0; } pNew->pSchema = db->aDb[iDb].pSchema; pNew->addColOffset = pTab->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){ const char *zType = 0; #ifndef SQLITE_OMIT_VIEW if( pTab->pSelect ){ zType = "view"; } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ zType = "virtual table"; } #endif if( zType ){ sqlite3ErrorMsg( pParse, "cannot rename columns of %s \"%s\"", zType, pTab->zName ); return 1; } return 0; } #else /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */ # define isRealTable(x,y) (0) #endif /* ** Handles the following parser reduction: ** ** cmd ::= ALTER TABLE pSrc RENAME COLUMN pOld TO pNew */ |
︙ | ︙ | |||
605 606 607 608 609 610 611 | /* 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; | | | | < < < < | | | | | | > | | | 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 | /* 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) ) 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].zName, zOld) ) break; } if( iCol==pTab->nCol ){ sqlite3ErrorMsg(pParse, "no such column: \"%s\"", zOld); goto exit_rename_column; } /* 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_master 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\".%s SET " "sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, %d) " "WHERE name NOT LIKE 'sqlite_%%' AND (type != 'index' OR tbl_name = %Q)" " AND sql NOT LIKE 'create virtual%%'", zDb, MASTER_NAME, zDb, pTab->zName, iCol, zNew, bQuote, iSchema==1, pTab->zName ); sqlite3NestedParse(pParse, "UPDATE temp.%s SET " "sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, 1) " "WHERE type IN ('trigger', 'view')", MASTER_NAME, zDb, pTab->zName, iCol, zNew, bQuote ); /* Drop and reload the database schema. */ renameReloadSchema(pParse, iSchema); renameTestSchema(pParse, zDb, iSchema==1); exit_rename_column: sqlite3SrcListDelete(db, pSrc); sqlite3DbFree(db, zOld); sqlite3DbFree(db, zNew); return; } |
︙ | ︙ | |||
690 691 692 693 694 695 696 | ** 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 { | | | 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 | ** 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 { 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. |
︙ | ︙ | |||
732 733 734 735 736 737 738 | ** ** 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. */ | | < < | | | | < | < < < < < | | | | | | < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < < < | | < < | < < | < < < | | | | > | < | | | > > > > > > > > > > > > > > > > < < < < < | 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 | ** ** 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, void *pPtr){ if( pParse->nErr==0 && pParse->db->mallocFailed==0 ){ RenameToken *p; u8 i = 0; for(p=pParse->pRename; p; p=p->pNext){ if( p->p ){ assert( p->p!=pPtr ); i += *(u8*)(p->p); } } } } #else # define renameTokenCheckAll(x,y) #endif /* ** Remember that the parser tree element pPtr was created using ** the token pToken. ** ** In other words, construct a new RenameToken object and add it ** 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. */ void *sqlite3RenameTokenMap(Parse *pParse, void *pPtr, Token *pToken){ RenameToken *pNew; assert( pPtr || pParse->db->mallocFailed ); renameTokenCheckAll(pParse, pPtr); 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, void *pTo, 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, (void*)pExpr); return WRC_Continue; } /* ** Remove all nodes that are part of expression pExpr from the rename list. */ void sqlite3RenameExprUnmap(Parse *pParse, Expr *pExpr){ Walker sWalker; memset(&sWalker, 0, sizeof(Walker)); sWalker.pParse = pParse; sWalker.xExprCallback = renameUnmapExprCb; sqlite3WalkExpr(&sWalker, pExpr); } /* ** 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++){ sqlite3RenameTokenRemap(pParse, 0, (void*)pEList->a[i].zName); } } } /* ** 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, remove it ** from the Parse object and add it to the list maintained by the ** RenameCtx object passed as the second argument. */ static void renameTokenFind(Parse *pParse, struct RenameCtx *pCtx, void *pPtr){ RenameToken **pp; assert( pPtr!=0 ); for(pp=&pParse->pRename; (*pp); pp=&(*pp)->pNext){ if( (*pp)->p==pPtr ){ RenameToken *pToken = *pp; *pp = pToken->pNext; pToken->pNext = pCtx->pList; pCtx->pList = pToken; pCtx->nList++; break; } } } /* ** Iterate through the Select objects that are part of WITH clauses attached ** to select statement pSelect. */ static void renameWalkWith(Walker *pWalker, Select *pSelect){ if( pSelect->pWith ){ int i; for(i=0; i<pSelect->pWith->nCte; i++){ Select *p = pSelect->pWith->a[i].pSelect; NameContext sNC; memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pWalker->pParse; sqlite3SelectPrep(sNC.pParse, p, &sNC); sqlite3WalkSelect(pWalker, p); } } } /* ** 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){ renameWalkWith(pWalker, p); return WRC_Continue; } /* ** This is a Walker expression callback. ** |
︙ | ︙ | |||
1010 1011 1012 1013 1014 1015 1016 | 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 | | < | 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 | 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 && p->pTab==pExpr->y.pTab ){ renameTokenFind(pWalker->pParse, p, (void*)pExpr); } return WRC_Continue; } |
︙ | ︙ | |||
1051 1052 1053 1054 1055 1056 1057 | ** 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, | | | | | | | < < | < | | | | < > | < < < | | < | < > > > > | | > > > | | 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 | ** 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, int bPost, 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", zT, zN, (bPost ? " after rename" : ""), 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, ExprList *pEList, const char *zOld ){ if( pEList ){ int i; for(i=0; i<pEList->nExpr; i++){ char *zName = pEList->a[i].zName; if( 0==sqlite3_stricmp(zName, zOld) ){ renameTokenFind(pParse, pCtx, (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, IdList *pIdList, const char *zOld ){ if( pIdList ){ int i; for(i=0; i<pIdList->nId; i++){ char *zName = pIdList->a[i].zName; if( 0==sqlite3_stricmp(zName, zOld) ){ renameTokenFind(pParse, pCtx, (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 */ int bTable, /* 1 -> RENAME TABLE, 0 -> RENAME COLUMN */ 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 = (bTable ? PARSE_MODE_RENAME_TABLE : PARSE_MODE_RENAME_COLUMN); p->db = db; p->nQueryLoop = 1; rc = sqlite3RunParser(p, zSql, &zErr); 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; } #ifdef SQLITE_DEBUG /* Ensure that all mappings in the Parse.pRename list really do map to ** a part of the input string. */ |
︙ | ︙ | |||
1181 1182 1183 1184 1185 1186 1187 | 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 */ ){ | | | | | < < < | | | | | | | | | | | | | < < < < | < | | < | | > > < < < > > | | | | | | < < < < < < < < < < < < < < < < < | 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 | 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 */ ){ int nNew = sqlite3Strlen30(zNew); int nSql = sqlite3Strlen30(zSql); sqlite3 *db = sqlite3_context_db_handle(pCtx); int rc = SQLITE_OK; char *zQuot; char *zOut; int nQuot; /* 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); } if( bQuote ){ zNew = zQuot; nNew = nQuot; } /* 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. All that remains is to construct and ** return the edited SQL string. */ assert( nQuot>=nNew ); zOut = sqlite3DbMallocZero(db, nSql + pRename->nList*nQuot + 1); if( zOut ){ int nOut = nSql; memcpy(zOut, zSql, nSql); while( pRename->pList ){ int iOff; /* Offset of token to replace in zOut */ RenameToken *pBest = renameColumnTokenNext(pRename); u32 nReplace; const char *zReplace; if( sqlite3IsIdChar(*pBest->t.z) ){ nReplace = nNew; zReplace = zNew; }else{ nReplace = nQuot; zReplace = zQuot; } iOff = pBest->t.z - zSql; if( pBest->t.n!=nReplace ){ memmove(&zOut[iOff + nReplace], &zOut[iOff + pBest->t.n], nOut - (iOff + pBest->t.n) ); |
︙ | ︙ | |||
1281 1282 1283 1284 1285 1286 1287 | /* ** 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. */ | | | 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 | /* ** 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, const char *zDb){ sqlite3 *db = pParse->db; Trigger *pNew = pParse->pNewTrigger; TriggerStep *pStep; NameContext sNC; int rc = SQLITE_OK; memset(&sNC, 0, sizeof(sNC)); |
︙ | ︙ | |||
1312 1313 1314 1315 1316 1317 1318 | 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 ){ | < < | < < | < < | < | < | | < | < < | < < < < < < < < | < < < | | | > | < < < | 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 | 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 ){ Table *pTarget = sqlite3LocateTable(pParse, 0, pStep->zTarget, zDb); if( pTarget==0 ){ rc = SQLITE_ERROR; }else if( SQLITE_OK==(rc = sqlite3ViewGetColumnNames(pParse, pTarget)) ){ SrcList sSrc; memset(&sSrc, 0, sizeof(sSrc)); sSrc.nSrc = 1; sSrc.a[0].zName = pStep->zTarget; sSrc.a[0].pTab = pTarget; sNC.pSrcList = &sSrc; if( 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 ){ Upsert *pUpsert = pStep->pUpsert; assert( rc==SQLITE_OK ); pUpsert->pUpsertSrc = &sSrc; 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; } } } return rc; } /* |
︙ | ︙ | |||
1401 1402 1403 1404 1405 1406 1407 | if( pStep->pUpsert ){ Upsert *pUpsert = pStep->pUpsert; sqlite3WalkExprList(pWalker, pUpsert->pUpsertTarget); sqlite3WalkExprList(pWalker, pUpsert->pUpsertSet); sqlite3WalkExpr(pWalker, pUpsert->pUpsertWhere); sqlite3WalkExpr(pWalker, pUpsert->pUpsertTargetWhere); } | < < < < < < | 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. */ |
︙ | ︙ | |||
1428 1429 1430 1431 1432 1433 1434 | while( (pIdx = pParse->pNewIndex)!=0 ){ pParse->pNewIndex = pIdx->pNext; sqlite3FreeIndex(db, pIdx); } sqlite3DeleteTrigger(db, pParse->pNewTrigger); sqlite3DbFree(db, pParse->zErrMsg); renameTokenFree(db, pParse->pRename); | | | | < | 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 | 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); } /* ** SQL function: ** ** sqlite_rename_column(zSql, iCol, bQuote, zNew, zTable, zOld) ** ** 0. zSql: SQL statement to rewrite ** 1. type: Type of object ("table", "view" etc.) ** 2. object: Name of object ** 3. Database: Database name (e.g. "main") ** 4. Table: Table name ** 5. iCol: Index of column to rename ** 6. zNew: New column name ** 7. bQuote: Non-zero if the new column name should be quoted. ** 8. bTemp: True if zSql comes from temp schema ** ** Do a column rename operation on the CREATE statement given in zSql. ** The iCol-th column (left-most is 0) of table zTable is renamed from zCol ** into zNew. The name should be quoted if bQuote is true. ** ** This function is used internally by the ALTER TABLE RENAME COLUMN command. ** It is only accessible to SQL created using sqlite3NestedParse(). It is ** not reachable from ordinary SQL passed into sqlite3_prepare(). */ static void renameColumnFunc( sqlite3_context *context, int NotUsed, sqlite3_value **argv ){ sqlite3 *db = sqlite3_context_db_handle(context); |
︙ | ︙ | |||
1491 1492 1493 1494 1495 1496 1497 | if( iCol<0 ) return; sqlite3BtreeEnterAll(db); pTab = sqlite3FindTable(db, zTable, zDb); if( pTab==0 || iCol>=pTab->nCol ){ sqlite3BtreeLeaveAll(db); return; } | | | < | | | | > < | | | < < < < < < | < | < < | | | 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 | if( iCol<0 ) return; sqlite3BtreeEnterAll(db); pTab = sqlite3FindTable(db, zTable, zDb); if( pTab==0 || iCol>=pTab->nCol ){ sqlite3BtreeLeaveAll(db); return; } zOld = pTab->aCol[iCol].zName; memset(&sCtx, 0, sizeof(sCtx)); sCtx.iCol = ((iCol==pTab->iPKey) ? -1 : iCol); #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = 0; #endif rc = renameParseSql(&sParse, zDb, 0, 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 ){ Select *pSelect = sParse.pNewTable->pSelect; if( pSelect ){ sParse.rc = SQLITE_OK; sqlite3SelectPrep(&sParse, sParse.pNewTable->pSelect, 0); rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc); if( rc==SQLITE_OK ){ sqlite3WalkSelect(&sWalker, pSelect); } if( rc!=SQLITE_OK ) goto renameColumnFunc_done; }else{ /* A regular table */ int bFKOnly = sqlite3_stricmp(zTable, sParse.pNewTable->zName); FKey *pFKey; assert( sParse.pNewTable->pSelect==0 ); sCtx.pTab = sParse.pNewTable; if( bFKOnly==0 ){ renameTokenFind( &sParse, &sCtx, (void*)sParse.pNewTable->aCol[iCol].zName ); 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); } } for(pFKey=sParse.pNewTable->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, (bTemp ? 0 : zDb)); 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 ){ |
︙ | ︙ | |||
1602 1603 1604 1605 1606 1607 1608 | } assert( rc==SQLITE_OK ); rc = renameEditSql(context, &sCtx, zSql, zNew, bQuote); renameColumnFunc_done: if( rc!=SQLITE_OK ){ | < < | | | < < < < < < < < | | | 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 | } assert( rc==SQLITE_OK ); rc = renameEditSql(context, &sCtx, zSql, zNew, bQuote); renameColumnFunc_done: if( rc!=SQLITE_OK ){ if( sParse.zErrMsg ){ renameColumnParseError(context, 0, 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 && 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( pSrc==0 ){ assert( pWalker->pParse->db->mallocFailed ); return WRC_Abort; } for(i=0; i<pSrc->nSrc; i++){ struct SrcList_item *pItem = &pSrc->a[i]; if( pItem->pTab==p->pTab ){ renameTokenFind(pWalker->pParse, p, pItem->zName); } } renameWalkWith(pWalker, pSelect); return WRC_Continue; |
︙ | ︙ | |||
1715 1716 1717 1718 1719 1720 1721 | sCtx.pTab = sqlite3FindTable(db, zOld, zDb); memset(&sWalker, 0, sizeof(Walker)); sWalker.pParse = &sParse; sWalker.xExprCallback = renameTableExprCb; sWalker.xSelectCallback = renameTableSelectCb; sWalker.u.pRename = &sCtx; | | | < < < | | < < | < | < < < | | 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 | 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, 1, db, zInput, bTemp); if( rc==SQLITE_OK ){ int isLegacy = (db->flags & SQLITE_LegacyAlter); if( sParse.pNewTable ){ Table *pTab = sParse.pNewTable; if( pTab->pSelect ){ if( isLegacy==0 ){ NameContext sNC; memset(&sNC, 0, sizeof(sNC)); sNC.pParse = &sParse; sqlite3SelectPrep(&sParse, pTab->pSelect, &sNC); if( sParse.nErr ) rc = sParse.rc; sqlite3WalkSelect(&sWalker, pTab->pSelect); } }else{ /* Modify any FK definitions to point to the new table. */ #ifndef SQLITE_OMIT_FOREIGN_KEY if( isLegacy==0 || (db->flags & SQLITE_ForeignKeys) ){ FKey *pFKey; for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){ if( sqlite3_stricmp(pFKey->zTo, zOld)==0 ){ renameTokenFind(&sParse, &sCtx, (void*)pFKey->zTo); } } } #endif |
︙ | ︙ | |||
1785 1786 1787 1788 1789 1790 1791 | if( 0==sqlite3_stricmp(sParse.pNewTrigger->table, zOld) && sCtx.pTab->pSchema==pTrigger->pTabSchema ){ renameTokenFind(&sParse, &sCtx, sParse.pNewTrigger->table); } if( isLegacy==0 ){ | | < < < < < < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | < | < | < < < < < < | < | | | < < | < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | < < | 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 | 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, bTemp ? 0 : zDb); 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, 0, 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; } /* ** 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. ** ** 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); #ifndef SQLITE_OMIT_AUTHORIZATION sqlite3_xauth xAuth = db->xAuth; db->xAuth = 0; #endif UNUSED_PARAMETER(NotUsed); if( zDb && zInput ){ int rc; Parse sParse; rc = renameParseSql(&sParse, zDb, 1, db, zInput, bTemp); if( rc==SQLITE_OK ){ if( isLegacy==0 && sParse.pNewTable && sParse.pNewTable->pSelect ){ NameContext sNC; memset(&sNC, 0, sizeof(sNC)); sNC.pParse = &sParse; sqlite3SelectPrep(&sParse, sParse.pNewTable->pSelect, &sNC); if( sParse.nErr ) rc = sParse.rc; } else if( sParse.pNewTrigger ){ if( isLegacy==0 ){ rc = renameResolveTrigger(&sParse, bTemp ? 0 : zDb); } 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 ){ renameColumnParseError(context, 1, argv[2], argv[3], &sParse); } renameParseCleanup(&sParse); } #ifndef SQLITE_OMIT_AUTHORIZATION db->xAuth = xAuth; #endif } /* ** 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, 5, renameTableTest), }; 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 and later and with ** SQLITE_ENABLE_STAT3 defined. The functionality of sqlite_stat3 ** is a superset of sqlite_stat2. 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. It is ** not possible to enable both STAT3 and STAT4 at the same time. If they ** are both enabled, then STAT4 takes precedence. ** ** 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 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. ** | > > > > > > | 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 | ** integer in the equivalent columns in sqlite_stat4. */ #ifndef SQLITE_OMIT_ANALYZE #include "sqliteInt.h" #if defined(SQLITE_ENABLE_STAT4) # define IsStat4 1 # define IsStat3 0 #elif defined(SQLITE_ENABLE_STAT3) # define IsStat4 0 # define IsStat3 1 #else # define IsStat4 0 # define IsStat3 0 # undef SQLITE_STAT4_SAMPLES # define SQLITE_STAT4_SAMPLES 1 #endif #define IsStat34 (IsStat3+IsStat4) /* 1 for STAT3 or STAT4. 0 otherwise */ /* ** 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. ** |
︙ | ︙ | |||
173 174 175 176 177 178 179 180 181 182 | 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 | > > > > > < | < < < < < < | | > | | | | | | | | < < | | < < < < > | | | | | | | | | | | | | | | | < | | | | < | | < > > | | | | | | < | | | | | < | | | < > > < < < | < < > > | | | | | | 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 | 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" }, { "sqlite_stat3", 0 }, #elif defined(SQLITE_ENABLE_STAT3) { "sqlite_stat3", "tbl,idx,neq,nlt,ndlt,sample" }, { "sqlite_stat4", 0 }, #else { "sqlite_stat3", 0 }, { "sqlite_stat4", 0 }, #endif }; int i; sqlite3 *db = pParse->db; Db *pDb; Vdbe *v = sqlite3GetVdbe(pParse); int aRoot[ArraySize(aTable)]; u8 aCreateTbl[ArraySize(aTable)]; 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; if( (pStat = sqlite3FindTable(db, zTab, pDb->zDbSName))==0 ){ if( aTable[i].zCols ){ /* 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] = 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; aCreateTbl[i] = 0; sqlite3TableLock(pParse, iDb, aRoot[i], 1, zTab); if( zWhere ){ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE %s=%Q", pDb->zDbSName, zTab, zWhereType, zWhere ); #ifdef SQLITE_ENABLE_PREUPDATE_HOOK }else if( db->xPreUpdateCallback ){ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s", pDb->zDbSName, zTab); #endif }else{ /* The sqlite_stat[134] table already exists. Delete all rows. */ sqlite3VdbeAddOp2(v, OP_Clear, aRoot[i], iDb); } } } /* Open the sqlite_stat[134] tables for writing. */ for(i=0; aTable[i].zCols; i++){ assert( i<ArraySize(aTable) ); sqlite3VdbeAddOp4Int(v, OP_OpenWrite, iStatCur+i, 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 Stat4Accum Stat4Accum; typedef struct Stat4Sample Stat4Sample; struct Stat4Sample { tRowcnt *anEq; /* sqlite_stat4.nEq */ tRowcnt *anDLt; /* sqlite_stat4.nDLt */ #ifdef SQLITE_ENABLE_STAT3_OR_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 Stat4Accum { tRowcnt nRow; /* Number of rows in the entire table */ tRowcnt nPSample; /* How often to do a periodic sample */ int nCol; /* Number of columns in index + pk/rowid */ int nKeyCol; /* Number of index columns w/o the pk/rowid */ int mxSample; /* Maximum number of samples to accumulate */ Stat4Sample current; /* Current row as a Stat4Sample */ u32 iPrn; /* Pseudo-random number used for sampling */ Stat4Sample *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() */ Stat4Sample *a; /* Array of mxSample Stat4Sample objects */ sqlite3 *db; /* Database connection, for malloc() */ }; /* Reclaim memory used by a Stat4Sample */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 static void sampleClear(sqlite3 *db, Stat4Sample *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_STAT3_OR_STAT4 static void sampleSetRowid(sqlite3 *db, Stat4Sample *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_STAT3_OR_STAT4 static void sampleSetRowidInt64(sqlite3 *db, Stat4Sample *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_STAT3_OR_STAT4 static void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *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 Stat4Accum structure. */ static void stat4Destructor(void *pOld){ Stat4Accum *p = (Stat4Accum*)pOld; #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 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) SQL function. The three 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: The number of rows in the index (note 2) ** ** 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. ** ** Note 2: C is only used for STAT3 and STAT4. ** ** 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 Stat4Accum object in heap memory. The return ** value is a pointer to the Stat4Accum object. The datatype of the ** return value is BLOB, but it is really just a pointer to the Stat4Accum ** object. */ static void statInit( sqlite3_context *context, int argc, sqlite3_value **argv ){ Stat4Accum *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; /* Database connection */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 int mxSample = SQLITE_STAT4_SAMPLES; #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 Stat4Accum object */ n = sizeof(*p) + sizeof(tRowcnt)*nColUp /* Stat4Accum.anEq */ + sizeof(tRowcnt)*nColUp /* Stat4Accum.anDLt */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + sizeof(tRowcnt)*nColUp /* Stat4Accum.anLt */ + sizeof(Stat4Sample)*(nCol+mxSample) /* Stat4Accum.aBest[], a[] */ + sizeof(tRowcnt)*3*nColUp*(nCol+mxSample) #endif ; db = sqlite3_context_db_handle(context); p = sqlite3DbMallocZero(db, n); if( p==0 ){ sqlite3_result_error_nomem(context); return; } p->db = db; p->nRow = 0; p->nCol = nCol; p->nKeyCol = nKeyCol; p->current.anDLt = (tRowcnt*)&p[1]; p->current.anEq = &p->current.anDLt[nColUp]; #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 { u8 *pSpace; /* Allocated space not yet assigned */ int i; /* Used to iterate through p->aSample[] */ p->iGet = -1; p->mxSample = mxSample; p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[2])/(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 Stat4Accum.a[] and aBest[] arrays */ p->a = (struct Stat4Sample*)&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), stat4Destructor); } static const FuncDef statInitFuncdef = { 2+IsStat34, /* nArg */ SQLITE_UTF8, /* funcFlags */ 0, /* pUserData */ 0, /* pNext */ statInit, /* xSFunc */ 0, /* xFinalize */ 0, 0, /* xValue, xInverse */ "stat_init", /* zName */ |
︙ | ︙ | |||
504 505 506 507 508 509 510 | ** 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( | | | | | | | | > > > > | | > | | | | | > | > > > | > | < | > | | 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 | ** 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( Stat4Accum *pAccum, Stat4Sample *pNew, Stat4Sample *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_STAT3_OR_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( Stat4Accum *pAccum, Stat4Sample *pNew, Stat4Sample *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; #ifdef SQLITE_ENABLE_STAT4 if( nEqNew==nEqOld ){ if( pNew->iCol<pOld->iCol ) return 1; return (pNew->iCol==pOld->iCol && sampleIsBetterPost(pAccum, pNew, pOld)); } return 0; #else return (nEqNew==nEqOld && pNew->iHash>pOld->iHash); #endif } /* ** 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(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){ Stat4Sample *pSample = 0; int i; assert( IsStat4 || nEqZero==0 ); #ifdef SQLITE_ENABLE_STAT4 /* Stat4Accum.nMaxEqZero is set to the maximum number of leading 0 ** values in the anEq[] array of any sample in Stat4Accum.a[]. In ** other words, if nMaxEqZero is n, then it is guaranteed that there ** are no samples with Stat4Sample.anEq[m]==0 for (m>=n). */ if( nEqZero>p->nMaxEqZero ){ p->nMaxEqZero = nEqZero; } if( pNew->isPSample==0 ){ Stat4Sample *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--){ Stat4Sample *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; } } #endif /* If necessary, remove sample iMin to make room for the new sample. */ if( p->nSample>=p->mxSample ){ Stat4Sample *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. */ #ifdef SQLITE_ENABLE_STAT4 assert( p->nSample==0 || pNew->anLt[p->nCol-1] > p->a[p->nSample-1].anLt[p->nCol-1] ); #endif /* 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); #ifdef SQLITE_ENABLE_STAT4 find_new_min: #endif 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_STAT3_OR_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(Stat4Accum *p, int iChng){ #ifdef SQLITE_ENABLE_STAT4 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--){ Stat4Sample *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 |
︙ | ︙ | |||
672 673 674 675 676 677 678 | 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; } | > | > > > > > > > > > > > > > > > > > > > > > | > > > > | > | < | | < < < | | < | < | | < | < < | | | | | | | > > > | > < > < < < | < < | | | | | | | | < | | < < < < < < > | | > > > > | | > < | > > | > | | < < | > > > > > > > > > | | > | < > > | | > > | | | > | | < | | < | < < < < < < < < < < < < < < < < < < < | < < < < | 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 | 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 #if defined(SQLITE_ENABLE_STAT3) && !defined(SQLITE_ENABLE_STAT4) if( iChng==0 ){ tRowcnt nLt = p->current.anLt[0]; tRowcnt nEq = p->current.anEq[0]; /* Check if this is to be a periodic sample. If so, add it. */ if( (nLt/p->nPSample)!=(nLt+nEq)/p->nPSample ){ p->current.isPSample = 1; sampleInsert(p, &p->current, 0); p->current.isPSample = 0; }else /* Or if it is a non-periodic sample. Add it in this case too. */ if( p->nSample<p->mxSample || sampleIsBetter(p, &p->current, &p->a[p->iMin]) ){ sampleInsert(p, &p->current, 0); } } #endif #ifndef SQLITE_ENABLE_STAT3_OR_STAT4 UNUSED_PARAMETER( p ); UNUSED_PARAMETER( iChng ); #endif } /* ** Implementation of the stat_push SQL function: stat_push(P,C,R) ** Arguments: ** ** P Pointer to the Stat4Accum 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. ** ** This SQL function always returns NULL. It's purpose it to accumulate ** statistical data and/or samples in the Stat4Accum object about the ** index being analyzed. The stat_get() SQL function will later be used to ** extract relevant information for constructing the sqlite_statN tables. ** ** The R parameter is only used for STAT3 and STAT4 */ static void statPush( sqlite3_context *context, int argc, sqlite3_value **argv ){ int i; /* The three function arguments */ Stat4Accum *p = (Stat4Accum*)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 */ samplePushPrevious(p, iChng); /* 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_STAT3_OR_STAT4 p->current.anLt[i] += p->current.anEq[i]; #endif p->current.anEq[i] = 1; } } p->nRow++; #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 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; #endif #ifdef SQLITE_ENABLE_STAT4 { tRowcnt 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); } } } #endif } static const FuncDef statPushFuncdef = { 2+IsStat34, /* 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 Stat4Accum object by prior calls to stat_push(). The P parameter ** has type BLOB but it is really just a pointer to the Stat4Accum 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 poiner to a Stat4Accum object, never a ** NULL. ** ** If neither STAT3 nor STAT4 are 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 ){ Stat4Accum *p = (Stat4Accum*)sqlite3_value_blob(argv[0]); #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 /* STAT3 and STAT4 have 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 ); 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 stabbing 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 */ char *z; int i; char *zRet = sqlite3MallocZero( (p->nKeyCol+1)*25 ); if( zRet==0 ){ sqlite3_result_error_nomem(context); return; } sqlite3_snprintf(24, zRet, "%llu", (u64)p->nRow); z = zRet + sqlite3Strlen30(zRet); for(i=0; i<p->nKeyCol; i++){ u64 nDistinct = p->current.anDLt[i] + 1; u64 iVal = (p->nRow + nDistinct - 1) / nDistinct; sqlite3_snprintf(24, z, " %llu", iVal); z += sqlite3Strlen30(z); assert( p->current.anEq[i] ); } assert( z[0]=='\0' && z>zRet ); sqlite3_result_text(context, zRet, -1, sqlite3_free); } #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 else if( eCall==STAT_GET_ROWID ){ if( p->iGet<0 ){ samplePushPrevious(p, 0); p->iGet = 0; } if( p->iGet<p->nSample ){ Stat4Sample *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; 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; } } if( IsStat3 ){ sqlite3_result_int64(context, (i64)aCnt[0]); }else{ char *zRet = sqlite3MallocZero(p->nCol * 25); if( zRet==0 ){ sqlite3_result_error_nomem(context); }else{ int i; char *z = zRet; for(i=0; i<p->nCol; i++){ sqlite3_snprintf(24, z, "%llu ", (u64)aCnt[i]); z += sqlite3Strlen30(z); } assert( z[0]=='\0' && z>zRet ); z[-1] = '\0'; sqlite3_result_text(context, zRet, -1, sqlite3_free); } } } #endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ #ifndef SQLITE_DEBUG UNUSED_PARAMETER( argc ); #endif } static const FuncDef statGetFuncdef = { 1+IsStat34, /* nArg */ SQLITE_UTF8, /* funcFlags */ 0, /* pUserData */ 0, /* pNext */ statGet, /* xSFunc */ 0, /* xFinalize */ 0, 0, /* xValue, xInverse */ "stat_get", /* zName */ {0} }; static void callStatGet(Vdbe *v, int regStat4, int iParam, int regOut){ assert( regOut!=regStat4 && regOut!=regStat4+1 ); #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 sqlite3VdbeAddOp2(v, OP_Integer, iParam, regStat4+1); #elif SQLITE_DEBUG assert( iParam==STAT_GET_STAT1 ); #else UNUSED_PARAMETER( iParam ); #endif sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4, regOut, (char*)&statGetFuncdef, P4_FUNCDEF); sqlite3VdbeChangeP5(v, 1 + IsStat34); } /* ** Generate code to do an analysis of all indices associated with ** a single table. */ static void analyzeOneTable( Parse *pParse, /* Parser context */ |
︙ | ︙ | |||
981 982 983 984 985 986 987 | 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 */ | | > > < | | 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 | 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 regStat4 = iMem++; /* Register to hold Stat4Accum object */ int regChng = iMem++; /* Index of changed index field */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 int regRowid = iMem++; /* Rowid argument passed to stat_push() */ #endif int regTemp = iMem++; /* Temporary use register */ int regTabname = iMem++; /* Register containing table name */ int regIdxname = iMem++; /* Register containing index name */ int regStat1 = iMem++; /* Value for the stat column of sqlite_stat1 */ int regPrev = iMem; /* MUST BE LAST (see below) */ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK Table *pStat1 = 0; #endif pParse->nMem = MAX(pParse->nMem, iMem); v = sqlite3GetVdbe(pParse); if( v==0 || NEVER(pTab==0) ){ return; } if( pTab->tnum==0 ){ /* 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; } |
︙ | ︙ | |||
1026 1027 1028 1029 1030 1031 1032 | if( db->xPreUpdateCallback ){ pStat1 = (Table*)sqlite3DbMallocZero(db, sizeof(Table) + 13); if( pStat1==0 ) return; pStat1->zName = (char*)&pStat1[1]; memcpy(pStat1->zName, "sqlite_stat1", 13); pStat1->nCol = 3; pStat1->iPKey = -1; | | | 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 | if( db->xPreUpdateCallback ){ pStat1 = (Table*)sqlite3DbMallocZero(db, sizeof(Table) + 13); if( pStat1==0 ) return; pStat1->zName = (char*)&pStat1[1]; memcpy(pStat1->zName, "sqlite_stat1", 13); pStat1->nCol = 3; pStat1->iPKey = -1; sqlite3VdbeAddOp4(pParse->pVdbe, OP_Noop, 0, 0, 0,(char*)pStat1,P4_DYNBLOB); } #endif /* Establish a read-lock on the table at the shared-cache level. ** Open a read-only cursor on the table. Also allocate a cursor number ** to use for scanning indexes (iIdxCur). No index cursor is opened at ** this time though. */ |
︙ | ︙ | |||
1113 1114 1115 1116 1117 1118 1119 | 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 | | > > > < < < | < | < < < < | < < < < | | | > > > | 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 | 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) the number of rows in the index, ** ** ** The third argument is only used for STAT3 and STAT4 */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat4+3); #endif sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1); sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2); sqlite3VdbeAddOp4(v, OP_Function0, 0, regStat4+1, regStat4, (char*)&statInitFuncdef, P4_FUNCDEF); sqlite3VdbeChangeP5(v, 2+IsStat34); /* Implementation of the following: ** ** Rewind csr ** if eof(csr) goto end_of_scan; ** regChng = 0 ** goto next_push_0; ** */ addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur); VdbeCoverage(v); 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); |
︙ | ︙ | |||
1175 1176 1177 1178 1179 1180 1181 | 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); | < < | | | < | | | | | | | | | | | | | | | | < | < | | < < < < < < | | < < < < < < | | | < > | | | | > > > > | | 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 | 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: ** regRowid = idx(rowid) // STAT34 only ** stat_push(P, regChng, regRowid) // 3rd parameter STAT34 only ** Next csr ** if !eof(csr) goto next_row; */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 assert( regRowid==(regStat4+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 = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]); assert( k>=0 && k<pIdx->nColumn ); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j); VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName)); } sqlite3VdbeAddOp3(v, OP_MakeRecord, regKey, pPk->nKeyCol, regRowid); sqlite3ReleaseTempRange(pParse, regKey, pPk->nKeyCol); } #endif assert( regChng==(regStat4+1) ); sqlite3VdbeAddOp4(v, OP_Function0, 1, regStat4, regTemp, (char*)&statPushFuncdef, P4_FUNCDEF); sqlite3VdbeChangeP5(v, 2+IsStat34); sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v); /* Add the entry to the stat1 table. */ callStatGet(v, regStat4, STAT_GET_STAT1, regStat1); assert( "BBB"[0]==SQLITE_AFF_TEXT ); sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid); sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regTemp, regNewRowid); #ifdef SQLITE_ENABLE_PREUPDATE_HOOK sqlite3VdbeChangeP4(v, -1, (char*)pStat1, P4_TABLE); #endif sqlite3VdbeChangeP5(v, OPFLAG_APPEND); /* Add the entries to the stat3 or stat4 table. */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 { int regEq = regStat1; int regLt = regStat1+1; 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(v, regStat4, STAT_GET_ROWID, regSampleRowid); addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regSampleRowid); VdbeCoverage(v); callStatGet(v, regStat4, STAT_GET_NEQ, regEq); callStatGet(v, regStat4, STAT_GET_NLT, regLt); callStatGet(v, regStat4, STAT_GET_NDLT, regDLt); sqlite3VdbeAddOp4Int(v, seekOp, iTabCur, addrNext, regSampleRowid, 0); VdbeCoverage(v); #ifdef SQLITE_ENABLE_STAT3 sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, 0, regSample); #else for(i=0; i<nCol; i++){ sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, i, regCol+i); } sqlite3VdbeAddOp3(v, OP_MakeRecord, regCol, nCol, regSample); #endif 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_STAT3_OR_STAT4 */ /* End of analysis */ sqlite3VdbeJumpHere(v, addrRewind); } /* Create a single sqlite_stat1 entry containing NULL as the index |
︙ | ︙ | |||
1468 1469 1470 1471 1472 1473 1474 | Index *pIndex /* Handle extra flags for this index, if not NULL */ ){ char *z = zIntArray; int c; int i; tRowcnt v; | | | | < < | | 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 | Index *pIndex /* Handle extra flags for this index, if not NULL */ ){ char *z = zIntArray; int c; int i; tRowcnt v; #ifdef SQLITE_ENABLE_STAT3_OR_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_STAT3_OR_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_STAT3_OR_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 ){ pIndex->szIdxRow = sqlite3LogEst(sqlite3Atoi(z+3)); }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)); } |
︙ | ︙ | |||
1557 1558 1559 1560 1561 1562 1563 | pIndex = sqlite3FindIndex(pInfo->db, argv[1], pInfo->zDatabase); } z = argv[2]; if( pIndex ){ tRowcnt *aiRowEst = 0; int nCol = pIndex->nKeyCol+1; | | | 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 | pIndex = sqlite3FindIndex(pInfo->db, argv[1], pInfo->zDatabase); } z = argv[2]; if( pIndex ){ tRowcnt *aiRowEst = 0; int nCol = pIndex->nKeyCol+1; #ifdef SQLITE_ENABLE_STAT3_OR_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); } |
︙ | ︙ | |||
1593 1594 1595 1596 1597 1598 1599 | } /* ** If the Index.aSample variable is not NULL, delete the aSample[] array ** and its contents. */ void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){ | < < | | | | | 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 | } /* ** If the Index.aSample variable is not NULL, delete the aSample[] array ** and its contents. */ void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){ #ifdef SQLITE_ENABLE_STAT3_OR_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_STAT3_OR_STAT4 */ } #ifdef SQLITE_ENABLE_STAT3_OR_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; |
︙ | ︙ | |||
1692 1693 1694 1695 1696 1697 1698 | Table *pTab = sqlite3FindTable(db, zName, zDb); if( pTab && !HasRowid(pTab) ) pIdx = sqlite3PrimaryKeyIndex(pTab); } return pIdx; } /* | | | > > | 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 | Table *pTab = sqlite3FindTable(db, zName, zDb); if( pTab && !HasRowid(pTab) ) pIdx = sqlite3PrimaryKeyIndex(pTab); } return pIdx; } /* ** Load the content from either the sqlite_stat4 or sqlite_stat3 table ** into the relevant Index.aSample[] arrays. ** ** Arguments zSql1 and zSql2 must point to SQL statements that return ** data equivalent to the following (statements are different for stat3, ** see the caller of this function for details): ** ** 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 */ int bStat3, /* Assume single column records only */ 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 */ |
︙ | ︙ | |||
1738 1739 1740 1741 1742 1743 1744 | 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); | | > > | > | | | | | > | 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 | 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 || bStat3 || pIdx->nSample==0 ); /* Index.nSample is non-zero at this point if data has already been ** loaded from the stat4 table. In this case ignore stat3 data. */ if( pIdx==0 || pIdx->nSample ) continue; if( bStat3==0 ){ 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); |
︙ | ︙ | |||
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 | | > | 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 | 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. In this case ignore stat3 data. */ nCol = pIdx->nSampleCol; if( bStat3 && nCol>1 ) continue; 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); |
︙ | ︙ | |||
1821 1822 1823 1824 1825 1826 1827 | } rc = sqlite3_finalize(pStmt); if( rc==SQLITE_OK ) initAvgEq(pPrevIdx); return rc; } /* | | < | < < | > > > > > > > > > | | | | | | < | | < < | | | | 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 | } rc = sqlite3_finalize(pStmt); if( rc==SQLITE_OK ) initAvgEq(pPrevIdx); return rc; } /* ** Load content from the sqlite_stat4 and sqlite_stat3 tables into ** the Index.aSample[] arrays of all indices. */ static int loadStat4(sqlite3 *db, const char *zDb){ int rc = SQLITE_OK; /* Result codes from subroutines */ assert( db->lookaside.bDisable ); if( sqlite3FindTable(db, "sqlite_stat4", zDb) ){ rc = loadStatTbl(db, 0, "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx", "SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4", zDb ); } if( rc==SQLITE_OK && sqlite3FindTable(db, "sqlite_stat3", zDb) ){ rc = loadStatTbl(db, 1, "SELECT idx,count(*) FROM %Q.sqlite_stat3 GROUP BY idx", "SELECT idx,neq,nlt,ndlt,sqlite_record(sample) FROM %Q.sqlite_stat3", zDb ); } return rc; } #endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ /* ** Load the content of the sqlite_stat1 and sqlite_stat3/4 tables. The ** contents of sqlite_stat1 are used to populate the Index.aiRowEst[] ** arrays. The contents of sqlite_stat3/4 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_STAT3/4 was defined ** during compilation and the sqlite_stat3/4 table is present, no data is ** read from it. ** ** If SQLITE_ENABLE_STAT3/4 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; 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_STAT3_OR_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( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)!=0 ){ 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_STAT3_OR_STAT4 if( rc==SQLITE_OK ){ db->lookaside.bDisable++; rc = loadStat4(db, sInfo.zDatabase); db->lookaside.bDisable--; } 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.
︙ | ︙ | |||
41 42 43 44 45 46 47 | }else{ pExpr->op = TK_STRING; } } return rc; } | < < < < < < < < < < < | 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | }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 ** ** SELECT sqlite_attach(x, y, z) |
︙ | ︙ | |||
81 82 83 84 85 86 87 | sqlite3 *db = sqlite3_context_db_handle(context); const char *zName; const char *zFile; char *zPath = 0; char *zErr = 0; unsigned int flags; Db *aNew; /* New array of Db pointers */ | | | < < < < < < < < | | | | < | < < < < > | | | 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 | sqlite3 *db = sqlite3_context_db_handle(context); const char *zName; const char *zFile; char *zPath = 0; char *zErr = 0; unsigned int flags; Db *aNew; /* New array of Db pointers */ Db *pNew; /* Db object for the newly attached database */ char *zErrDyn = 0; sqlite3_vfs *pVfs; 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 = ""; #ifdef SQLITE_ENABLE_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 ** from sqlite3_deserialize() to close database db->init.iDb and ** reopen it as a MemDB */ pVfs = sqlite3_vfs_find("memdb"); if( pVfs==0 ) return; pNew = &db->aDb[db->init.iDb]; if( pNew->pBt ) sqlite3BtreeClose(pNew->pBt); pNew->pBt = 0; pNew->pSchema = 0; rc = sqlite3BtreeOpen(pVfs, "x\0", db, &pNew->pBt, 0, SQLITE_OPEN_MAIN_DB); }else{ /* This is a real ATTACH ** ** Check for the following errors: ** ** * Too many attached databases, ** * Transaction currently open ** * Specified database name already being used. */ 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++){ char *z = db->aDb[i].zDbSName; assert( z && zName ); if( sqlite3StrICmp(z, zName)==0 ){ zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName); goto attach_error; } } /* Allocate the new entry in the db->aDb[] array and initialize the schema ** hash tables. |
︙ | ︙ | |||
206 207 208 209 210 211 212 | #endif sqlite3BtreeLeave(pNew->pBt); } pNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1; if( rc==SQLITE_OK && pNew->zDbSName==0 ){ rc = SQLITE_NOMEM_BKPT; } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 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 | #endif sqlite3BtreeLeave(pNew->pBt); } pNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1; if( rc==SQLITE_OK && pNew->zDbSName==0 ){ rc = SQLITE_NOMEM_BKPT; } #ifdef SQLITE_HAS_CODEC if( rc==SQLITE_OK ){ extern int sqlite3CodecAttach(sqlite3*, int, const void*, int); extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); int nKey; char *zKey; int t = sqlite3_value_type(argv[2]); switch( t ){ case SQLITE_INTEGER: case SQLITE_FLOAT: zErrDyn = sqlite3DbStrDup(db, "Invalid key value"); rc = SQLITE_ERROR; break; case SQLITE_TEXT: case SQLITE_BLOB: nKey = sqlite3_value_bytes(argv[2]); zKey = (char *)sqlite3_value_blob(argv[2]); rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); break; case SQLITE_NULL: /* No key specified. Use the key from URI filename, or if none, ** use the key from the main database. */ if( sqlite3CodecQueryParameters(db, zName, zPath)==0 ){ sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); if( nKey || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){ rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); } } break; } } #endif sqlite3_free( 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 ){ |
︙ | ︙ | |||
233 234 235 236 237 238 239 | rc = sqlite3UserAuthCheckLogin(db, zName, &newAuth); if( newAuth<db->auth.authLevel ){ rc = SQLITE_AUTH_USER; } } #endif if( rc ){ | | | 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 | rc = sqlite3UserAuthCheckLogin(db, zName, &newAuth); if( newAuth<db->auth.authLevel ){ rc = SQLITE_AUTH_USER; } } #endif if( rc ){ if( !REOPEN_AS_MEMDB(db) ){ int iDb = db->nDb - 1; assert( iDb>=2 ); if( db->aDb[iDb].pBt ){ sqlite3BtreeClose(db->aDb[iDb].pBt); db->aDb[iDb].pBt = 0; db->aDb[iDb].pSchema = 0; } |
︙ | ︙ | |||
282 283 284 285 286 287 288 | 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; | < | < | < < < < < < < < < < < < < | 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 | 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; if( sqlite3StrICmp(pDb->zDbSName, zName)==0 ) 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( sqlite3BtreeIsInReadTrans(pDb->pBt) || sqlite3BtreeIsInBackup(pDb->pBt) ){ sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked", zName); goto detach_error; } sqlite3BtreeClose(pDb->pBt); pDb->pBt = 0; pDb->pSchema = 0; sqlite3CollapseDatabaseArray(db); return; detach_error: |
︙ | ︙ | |||
350 351 352 353 354 355 356 | ){ int rc; NameContext sName; Vdbe *v; sqlite3* db = pParse->db; int regArgs; | < < | | | | < | > > | > | 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 | ){ int rc; NameContext sName; Vdbe *v; sqlite3* db = pParse->db; int regArgs; if( pParse->nErr ) goto attach_end; memset(&sName, 0, sizeof(NameContext)); sName.pParse = pParse; if( SQLITE_OK!=(rc = resolveAttachExpr(&sName, pFilename)) || SQLITE_OK!=(rc = resolveAttachExpr(&sName, pDbname)) || SQLITE_OK!=(rc = resolveAttachExpr(&sName, pKey)) ){ goto attach_end; } #ifndef SQLITE_OMIT_AUTHORIZATION if( pAuthArg ){ char *zAuthArg; if( pAuthArg->op==TK_STRING ){ 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 ){ sqlite3VdbeAddOp4(v, OP_Function0, 0, regArgs+3-pFunc->nArg, regArgs+3, (char *)pFunc, P4_FUNCDEF); assert( pFunc->nArg==-1 || (pFunc->nArg&0xff)==pFunc->nArg ); sqlite3VdbeChangeP5(v, (u8)(pFunc->nArg)); /* 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)); } |
︙ | ︙ | |||
445 446 447 448 449 450 451 | "sqlite_attach", /* zName */ {0} }; codeAttach(pParse, SQLITE_ATTACH, &attach_func, p, p, pDbname, pKey); } #endif /* SQLITE_OMIT_ATTACH */ | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > > | < < < < < < < | | | | > | > > > | > > > | > > > > > > > > > | | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | < > > | < < > | < | | | | | | < < | 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 | "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 */ ){ sqlite3 *db; 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->bVarOnly = (iDb==1); } /* ** 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 i; const char *zDb; struct SrcList_item *pItem; if( NEVER(pList==0) ) return 0; zDb = pFix->zDb; for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){ if( pFix->bVarOnly==0 ){ if( pItem->zDatabase && sqlite3StrICmp(pItem->zDatabase, zDb) ){ sqlite3ErrorMsg(pFix->pParse, "%s %T cannot reference objects in database %s", pFix->zType, pFix->pName, pItem->zDatabase); return 1; } sqlite3DbFree(pFix->pParse->db, pItem->zDatabase); pItem->zDatabase = 0; pItem->pSchema = pFix->pSchema; } #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1; if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1; #endif if( pItem->fg.isTabFunc && sqlite3FixExprList(pFix, pItem->u1.pFuncArg) ){ return 1; } } return 0; } #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 */ ){ while( pSelect ){ if( sqlite3FixExprList(pFix, pSelect->pEList) ){ return 1; } if( sqlite3FixSrcList(pFix, pSelect->pSrc) ){ return 1; } if( sqlite3FixExpr(pFix, pSelect->pWhere) ){ return 1; } if( sqlite3FixExprList(pFix, pSelect->pGroupBy) ){ return 1; } if( sqlite3FixExpr(pFix, pSelect->pHaving) ){ return 1; } if( sqlite3FixExprList(pFix, pSelect->pOrderBy) ){ return 1; } if( sqlite3FixExpr(pFix, pSelect->pLimit) ){ return 1; } if( pSelect->pWith ){ int i; for(i=0; i<pSelect->pWith->nCte; i++){ if( sqlite3FixSelect(pFix, pSelect->pWith->a[i].pSelect) ){ return 1; } } } pSelect = pSelect->pPrior; } return 0; } int sqlite3FixExpr( DbFixer *pFix, /* Context of the fixation */ Expr *pExpr /* The expression to be fixed to one database */ ){ while( pExpr ){ 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 1; } } if( ExprHasProperty(pExpr, EP_TokenOnly|EP_Leaf) ) break; if( ExprHasProperty(pExpr, EP_xIsSelect) ){ if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1; }else{ if( sqlite3FixExprList(pFix, pExpr->x.pList) ) return 1; } if( sqlite3FixExpr(pFix, pExpr->pRight) ){ return 1; } pExpr = pExpr->pLeft; } return 0; } int sqlite3FixExprList( DbFixer *pFix, /* Context of the fixation */ ExprList *pList /* The expression to be fixed to one database */ ){ int i; struct ExprList_item *pItem; if( pList==0 ) return 0; for(i=0, pItem=pList->a; i<pList->nExpr; i++, pItem++){ if( sqlite3FixExpr(pFix, pItem->pExpr) ){ return 1; } } return 0; } #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( sqlite3FixSelect(pFix, pStep->pSelect) ){ return 1; } if( sqlite3FixExpr(pFix, pStep->pWhere) ){ return 1; } if( sqlite3FixExprList(pFix, pStep->pExprList) ){ return 1; } #ifndef SQLITE_OMIT_UPSERT if( pStep->pUpsert ){ Upsert *pUp = pStep->pUpsert; if( sqlite3FixExprList(pFix, pUp->pUpsertTarget) || sqlite3FixExpr(pFix, pUp->pUpsertTargetWhere) || sqlite3FixExprList(pFix, pUp->pUpsertSet) || sqlite3FixExpr(pFix, 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; sqlite3ExpirePreparedStatements(db, 0); 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 146 147 148 149 150 151 152 | */ 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 ); | > | | | | | | | | 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 | */ 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 */ ){ sqlite3 *db = pParse->db; 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 || db->xAuth==0 ); if( db->xAuth==0 ) return; 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; ALWAYS(iSrc<pTabList->nSrc); iSrc++){ if( pExpr->iTable==pTabList->a[iSrc].iCursor ){ pTab = pTabList->a[iSrc].pTab; break; } } } iCol = pExpr->iColumn; if( NEVER(pTab==0) ) return; if( iCol>=0 ){ assert( iCol<pTab->nCol ); zCol = pTab->aCol[iCol].zName; }else if( pTab->iPKey>=0 ){ assert( pTab->iPKey<pTab->nCol ); zCol = pTab->aCol[pTab->iPKey].zName; }else{ zCol = "ROWID"; } assert( iDb>=0 && iDb<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 |
︙ | ︙ | |||
204 205 206 207 208 209 210 | 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 ); | | > > > > | 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | 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->init.busy || IN_SPECIAL_PARSE ){ return SQLITE_OK; } if( db->xAuth==0 ){ 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.
︙ | ︙ | |||
81 82 83 84 85 86 87 | */ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){ int i = sqlite3FindDbName(pDb, zDb); if( i==1 ){ Parse sParse; int rc = 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 | */ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){ int i = sqlite3FindDbName(pDb, zDb); if( i==1 ){ Parse sParse; int rc = 0; memset(&sParse, 0, sizeof(sParse)); sParse.db = pDb; if( sqlite3OpenTempDatabase(&sParse) ){ sqlite3ErrorWithMsg(pErrorDb, sParse.rc, "%s", sParse.zErrMsg); rc = SQLITE_ERROR; } sqlite3DbFree(pErrorDb, sParse.zErrMsg); sqlite3ParserReset(&sParse); if( rc ){ return 0; } } if( i<0 ){ sqlite3ErrorWithMsg(pErrorDb, SQLITE_ERROR, "unknown database %s", zDb); return 0; } return pDb->aDb[i].pBt; } /* ** 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),-1,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( sqlite3BtreeIsInReadTrans(p) ){ sqlite3ErrorWithMsg(db, SQLITE_ERROR, "destination database is in use"); return SQLITE_ERROR; } return SQLITE_OK; } /* |
︙ | ︙ | |||
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 | 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; | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | 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; #ifdef SQLITE_HAS_CODEC /* Use BtreeGetReserveNoMutex() for the source b-tree, as although it is ** guaranteed that the shared-mutex is held by this thread, handle ** p->pSrc may not actually be the owner. */ int nSrcReserve = sqlite3BtreeGetReserveNoMutex(p->pSrc); int nDestReserve = sqlite3BtreeGetOptimalReserve(p->pDest); #endif 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; } #ifdef SQLITE_HAS_CODEC /* Backup is not possible if the page size of the destination is changing ** and a codec is in use. */ if( nSrcPgsz!=nDestPgsz && sqlite3PagerGetCodec(pDestPager)!=0 ){ rc = SQLITE_READONLY; } /* Backup is not possible if the number of bytes of reserve space differ ** between source and destination. If there is a difference, try to ** fix the destination to agree with the source. If that is not possible, ** then the backup cannot proceed. */ if( nSrcReserve!=nDestReserve ){ u32 newPgsz = nSrcPgsz; rc = sqlite3PagerSetPagesize(pDestPager, &newPgsz, nSrcReserve); if( rc==SQLITE_OK && newPgsz!=nSrcPgsz ) rc = SQLITE_READONLY; } #endif /* 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; |
︙ | ︙ | |||
349 350 351 352 353 354 355 | 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. */ | | | 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 | 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 && 0==sqlite3BtreeIsInReadTrans(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 |
︙ | ︙ | |||
587 588 589 590 591 592 593 | /* Detach this backup from the source pager. */ if( p->pDestDb ){ p->pSrc->nBackup--; } if( p->isAttached ){ pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p->pSrc)); | < < | 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); |
︙ | ︙ | |||
721 722 723 724 725 726 727 | int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ int rc; sqlite3_file *pFd; /* File descriptor for database pTo */ sqlite3_backup b; sqlite3BtreeEnter(pTo); sqlite3BtreeEnter(pFrom); | | > > > > | | 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 | int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ int rc; sqlite3_file *pFd; /* File descriptor for database pTo */ sqlite3_backup b; sqlite3BtreeEnter(pTo); sqlite3BtreeEnter(pFrom); assert( sqlite3BtreeIsInTrans(pTo) ); 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; #ifdef SQLITE_HAS_CODEC sqlite3PagerAlignReserve(sqlite3BtreePager(pTo), sqlite3BtreePager(pFrom)); #endif /* 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( sqlite3BtreeIsInTrans(pTo)==0 ); copy_finished: sqlite3BtreeLeave(pFrom); sqlite3BtreeLeave(pTo); return rc; } #endif /* SQLITE_OMIT_VACUUM */ |
Changes to src/bitvec.c.
︙ | ︙ | |||
349 350 351 352 353 354 355 | if( pBitvec==0 || pV==0 || pTmpSpace==0 ) goto bitvec_end; /* NULL pBitvec tests */ sqlite3BitvecSet(0, 1); sqlite3BitvecClear(0, 1, pTmpSpace); /* Run the program */ | | | 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 | if( pBitvec==0 || pV==0 || pTmpSpace==0 ) goto bitvec_end; /* NULL pBitvec tests */ sqlite3BitvecSet(0, 1); sqlite3BitvecClear(0, 1, pTmpSpace); /* Run the program */ pc = 0; while( (op = aOp[pc])!=0 ){ switch( op ){ case 1: case 2: case 5: { nx = 4; i = aOp[pc+2] - 1; |
︙ | ︙ |
Changes to src/btmutex.c.
︙ | ︙ | |||
248 249 250 251 252 253 254 | ** ** If pSchema is not NULL, then iDb is computed from pSchema and ** db using sqlite3SchemaToIndex(). */ int sqlite3SchemaMutexHeld(sqlite3 *db, int iDb, Schema *pSchema){ Btree *p; assert( db!=0 ); | < | 248 249 250 251 252 253 254 255 256 257 258 259 260 261 | ** ** If pSchema is not NULL, then iDb is computed from pSchema and ** db using sqlite3SchemaToIndex(). */ int sqlite3SchemaMutexHeld(sqlite3 *db, int iDb, Schema *pSchema){ Btree *p; assert( db!=0 ); if( pSchema ) iDb = sqlite3SchemaToIndex(db, pSchema); assert( iDb>=0 && iDb<db->nDb ); if( !sqlite3_mutex_held(db->mutex) ) return 0; if( iDb==1 ) return 1; p = db->aDb[iDb].pBt; assert( p!=0 ); return p->sharable==0 || p->locked==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_MASTER. */ #ifdef SQLITE_TEST BtShared *SQLITE_WSD sqlite3SharedCacheList = 0; #else static BtShared *SQLITE_WSD sqlite3SharedCacheList = 0; #endif #endif /* SQLITE_OMIT_SHARED_CACHE */ |
︙ | ︙ | |||
106 107 108 109 110 111 112 | */ #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 | < < < < < < < < < < < | 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | */ #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 |
︙ | ︙ | |||
207 208 209 210 211 212 213 | /* 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; | < | | < | 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 | /* 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 ){ if( iTab ){ /* 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; } } }else{ iTab = iRoot; } /* Search for the required lock. Either a write-lock on root-page iTab, a |
︙ | ︙ | |||
364 365 366 367 368 369 370 | 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 | | | 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 | 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_master ** 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) ); |
︙ | ︙ | |||
543 544 545 546 547 548 549 | 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; | | | 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 | 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; if( pBtree->hasIncrblobCur==0 ) return; 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; |
︙ | ︙ | |||
620 621 622 623 624 625 626 | ** ** 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; | | | 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 | ** ** 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) || sqlite3BitvecTest(p, pgno))); } /* ** Clear (destroy) the BtShared.pHasContent bitvec. This should be ** invoked at the conclusion of each write-transaction. */ static void btreeClearHasContent(BtShared *pBt){ |
︙ | ︙ | |||
708 709 710 711 712 713 714 | static int saveCursorPosition(BtCursor *pCur){ int rc; assert( CURSOR_VALID==pCur->eState || CURSOR_SKIPNEXT==pCur->eState ); assert( 0==pCur->pKey ); assert( cursorHoldsMutex(pCur) ); | < < < | 695 696 697 698 699 700 701 702 703 704 705 706 707 708 | 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); |
︙ | ︙ | |||
803 804 805 806 807 808 809 | pCur->pKey = 0; pCur->eState = CURSOR_INVALID; } /* ** In this version of BtreeMoveto, pKey is a packed index record ** such as is generated by the OP_MakeRecord opcode. Unpack the | | < | < > | > > > | 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 | pCur->pKey = 0; pCur->eState = CURSOR_INVALID; } /* ** In this version of BtreeMoveto, pKey is a packed index record ** such as is generated by the OP_MakeRecord opcode. Unpack the ** record and then call BtreeMovetoUnpacked() to do the work. */ static int btreeMoveto( BtCursor *pCur, /* Cursor open on the btree to be searched */ const void *pKey, /* Packed key if the btree is an index */ i64 nKey, /* Integer key for tables. Size of pKey for indices */ 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; goto moveto_done; } }else{ pIdxKey = 0; } rc = sqlite3BtreeMovetoUnpacked(pCur, pIdxKey, nKey, bias, pRes); moveto_done: if( pIdxKey ){ sqlite3DbFree(pCur->pKeyInfo->db, pIdxKey); } 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 |
︙ | ︙ | |||
998 999 1000 1001 1002 1003 1004 | 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) ); | | | 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 | 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 master-journal page number must never be used as a pointer map page */ assert( 0==PTRMAP_ISPAGE(pBt, PENDING_BYTE_PAGE(pBt)) ); assert( pBt->autoVacuum ); if( key==0 ){ *pRC = SQLITE_CORRUPT_BKPT; return; } |
︙ | ︙ | |||
1137 1138 1139 1140 1141 1142 1143 | pInfo->nLocal = (u16)surplus; }else{ pInfo->nLocal = (u16)minLocal; } pInfo->nSize = (u16)(&pInfo->pPayload[pInfo->nLocal] - pCell) + 4; } | < < < < < < < < < < < < < < < < < < | 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 | 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. ** ** btreeParseCellPtr() => table btree leaf nodes |
︙ | ︙ | |||
1221 1222 1223 1224 1225 1226 1227 | } pIter++; /* The next block of code is equivalent to: ** ** pIter += getVarint(pIter, (u64*)&pInfo->nKey); ** | | < | | < > | | < | < < < < < < < < | < < < < < > | | 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 | } pIter++; /* The next block of code is equivalent to: ** ** pIter += getVarint(pIter, (u64*)&pInfo->nKey); ** ** The code is inlined to avoid a function call. */ iKey = *pIter; if( iKey>=0x80 ){ u8 *pEnd = &pIter[7]; iKey &= 0x7f; while(1){ iKey = (iKey<<7) | (*++pIter & 0x7f); if( (*pIter)<0x80 ) break; if( pIter>=pEnd ){ iKey = (iKey<<8) | *++pIter; break; } } } pIter++; pInfo->nKey = *(i64*)&iKey; pInfo->nPayload = nPayload; pInfo->pPayload = pIter; testcase( nPayload==pPage->maxLocal ); testcase( nPayload==pPage->maxLocal+1 ); if( nPayload<=pPage->maxLocal ){ /* This is the (easy) common case where the entire payload fits ** on the local page. No overflow is required. */ pInfo->nSize = nPayload + (u16)(pIter - pCell); if( pInfo->nSize<4 ) pInfo->nSize = 4; pInfo->nLocal = (u16)nPayload; |
︙ | ︙ | |||
1293 1294 1295 1296 1297 1298 1299 | }while( *(pIter)>=0x80 && pIter<pEnd ); } pIter++; pInfo->nKey = nPayload; pInfo->nPayload = nPayload; pInfo->pPayload = pIter; testcase( nPayload==pPage->maxLocal ); | | | 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 | }while( *(pIter)>=0x80 && pIter<pEnd ); } pIter++; pInfo->nKey = nPayload; pInfo->nPayload = nPayload; pInfo->pPayload = pIter; testcase( nPayload==pPage->maxLocal ); testcase( nPayload==pPage->maxLocal+1 ); if( nPayload<=pPage->maxLocal ){ /* This is the (easy) common case where the entire payload fits ** on the local page. No overflow is required. */ pInfo->nSize = nPayload + (u16)(pIter - pCell); if( pInfo->nSize<4 ) pInfo->nSize = 4; pInfo->nLocal = (u16)nPayload; |
︙ | ︙ | |||
1323 1324 1325 1326 1327 1328 1329 | ** ** Compute the total number of bytes that a Cell needs in the cell ** data area of the btree-page. The return number includes the cell ** data header and the local payload, but not any overflow page or ** the space used by the cell pointer. ** ** cellSizePtrNoPayload() => table internal nodes | < | 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 | ** ** Compute the total number of bytes that a Cell needs in the cell ** data area of the btree-page. The return number includes the cell ** data header and the local payload, but not any overflow page or ** the space used by the cell pointer. ** ** cellSizePtrNoPayload() => table internal nodes ** cellSizePtr() => all index nodes & table leaf nodes */ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){ u8 *pIter = pCell + pPage->childPtrSize; /* For looping over bytes of pCell */ u8 *pEnd; /* End mark for a varint */ u32 nSize; /* Size value to return */ |
︙ | ︙ | |||
1349 1350 1351 1352 1353 1354 1355 1356 | pEnd = &pIter[8]; nSize &= 0x7f; do{ nSize = (nSize<<7) | (*++pIter & 0x7f); }while( *(pIter)>=0x80 && pIter<pEnd ); } pIter++; testcase( nSize==pPage->maxLocal ); | > > > > > > > | | | 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 | pEnd = &pIter[8]; nSize &= 0x7f; do{ nSize = (nSize<<7) | (*++pIter & 0x7f); }while( *(pIter)>=0x80 && pIter<pEnd ); } pIter++; if( pPage->intKey ){ /* pIter now points at the 64-bit integer key value, a variable length ** integer. The following block moves pIter to point at the first byte ** past the end of the key value. */ pEnd = &pIter[9]; while( (*pIter++)&0x80 && pIter<pEnd ); } testcase( nSize==pPage->maxLocal ); testcase( nSize==pPage->maxLocal+1 ); if( nSize<=pPage->maxLocal ){ nSize += (u32)(pIter - pCell); if( nSize<4 ) nSize = 4; }else{ int minLocal = pPage->minLocal; nSize = minLocal + (nSize - minLocal) % (pPage->pBt->usableSize - 4); testcase( nSize==pPage->maxLocal ); testcase( nSize==pPage->maxLocal+1 ); if( nSize>pPage->maxLocal ){ nSize = minLocal; } nSize += 4 + (u16)(pIter - pCell); } assert( nSize==debuginfo.nSize || CORRUPT_DB ); return (u16)nSize; |
︙ | ︙ | |||
1388 1389 1390 1391 1392 1393 1394 | assert( pPage->childPtrSize==4 ); pEnd = pIter + 9; while( (*pIter++)&0x80 && pIter<pEnd ); assert( debuginfo.nSize==(u16)(pIter - pCell) || CORRUPT_DB ); return (u16)(pIter - pCell); } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 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 | assert( pPage->childPtrSize==4 ); pEnd = pIter + 9; while( (*pIter++)&0x80 && pIter<pEnd ); assert( debuginfo.nSize==(u16)(pIter - pCell) || CORRUPT_DB ); return (u16)(pIter - pCell); } #ifdef SQLITE_DEBUG /* This variation on cellSizePtr() is used inside of assert() statements ** only. */ 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 ); |
︙ | ︙ | |||
1502 1503 1504 1505 1506 1507 1508 | 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 */ | < > | | 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 | 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; assert( nCell==get2byte(&data[hdr+3]) || CORRUPT_DB ); iCellFirst = cellOffset + 2*nCell; usableSize = pPage->pBt->usableSize; |
︙ | ︙ | |||
1562 1563 1564 1565 1566 1567 1568 | goto defragment_out; } } } cbrk = usableSize; iCellLast = usableSize - 4; | < < < < < | | | | | | | | | | | | | | | | | | | | | | > > > > | > > > | | 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 | goto defragment_out; } } } cbrk = usableSize; iCellLast = usableSize - 4; 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<iCellFirst || pc>iCellLast ){ return SQLITE_CORRUPT_PAGE(pPage); } assert( pc>=iCellFirst && pc<=iCellLast ); size = pPage->xCellSize(pPage, &src[pc]); cbrk -= size; if( cbrk<iCellFirst || pc+size>usableSize ){ return SQLITE_CORRUPT_PAGE(pPage); } assert( cbrk+size<=usableSize && cbrk>=iCellFirst ); testcase( cbrk+size==usableSize ); testcase( pc+size==usableSize ); put2byte(pAddr, cbrk); if( temp==0 ){ int x; if( cbrk==pc ) continue; temp = sqlite3PagerTempSpace(pPage->pBt->pPager); x = get2byte(&data[hdr+5]); memcpy(&temp[x], &data[x], (cbrk+size) - x); 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; |
︙ | ︙ | |||
1626 1627 1628 1629 1630 1631 1632 | ** 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 */ | < | < | < < | | | | 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 | ** 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 */ |
︙ | ︙ | |||
1699 1700 1701 1702 1703 1704 1705 | ** also end up needing a new cell pointer. */ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ const int hdr = pPage->hdrOffset; /* Local cache of pPage->hdrOffset */ u8 * const data = pPage->aData; /* Local cache of pPage->aData */ int top; /* First byte of cell content area */ int rc = SQLITE_OK; /* Integer return code */ | < < | | < | | < < < | < | 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 | ** also end up needing a new cell pointer. */ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ const int hdr = pPage->hdrOffset; /* Local cache of pPage->hdrOffset */ u8 * const data = pPage->aData; /* Local cache of pPage->aData */ int top; /* First byte of cell content area */ int rc = SQLITE_OK; /* Integer return code */ int gap; /* First byte of gap between cell pointers and cell content */ assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( pPage->pBt ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( nByte>=0 ); /* Minimum cell size is 4 */ assert( pPage->nFree>=nByte ); assert( pPage->nOverflow==0 ); assert( nByte < (int)(pPage->pBt->usableSize-8) ); assert( pPage->cellOffset == hdr + 12 - 4*pPage->leaf ); gap = pPage->cellOffset + 2*pPage->nCell; 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 ); /* Prevent by getAndInitPage() */ 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 ){ assert( pSpace>=data && (pSpace - data)<65536 ); *pIdx = (int)(pSpace - data); 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. |
︙ | ︙ | |||
1801 1802 1803 1804 1805 1806 1807 | u16 iFreeBlk; /* Address of the next freeblock */ u8 hdr; /* Page header size. 0 or 100 */ u8 nFrag = 0; /* Reduction in fragmentation */ u16 iOrigSize = iSize; /* Original value of iSize */ u16 x; /* Offset to cell content area */ u32 iEnd = iStart + iSize; /* First byte past the iStart buffer */ unsigned char *data = pPage->aData; /* Page content */ | < | | | | | 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 | u16 iFreeBlk; /* Address of the next freeblock */ u8 hdr; /* Page header size. 0 or 100 */ u8 nFrag = 0; /* Reduction in fragmentation */ u16 iOrigSize = iSize; /* Original value of iSize */ u16 x; /* Offset to cell content area */ u32 iEnd = iStart + iSize; /* First byte past the iStart buffer */ unsigned char *data = pPage->aData; /* Page content */ assert( pPage->pBt!=0 ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( CORRUPT_DB || iStart>=pPage->hdrOffset+6+pPage->childPtrSize ); assert( CORRUPT_DB || iEnd <= pPage->pBt->usableSize ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( iSize>=4 ); /* Minimum cell size is 4 */ assert( iStart<=pPage->pBt->usableSize-4 ); /* The list of freeblocks must be in ascending order. Find the ** spot on the list where iStart should be inserted. */ 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; return SQLITE_CORRUPT_PAGE(pPage); } iPtr = iFreeBlk; } if( iFreeBlk>pPage->pBt->usableSize-4 ){ 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 ** ** Check to see if iFreeBlk should be coalesced onto the end of iStart. */ |
︙ | ︙ | |||
1864 1865 1866 1867 1868 1869 1870 | iSize = iEnd - iPtr; iStart = iPtr; } } if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PAGE(pPage); data[hdr+7] -= nFrag; } | < | < | | 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 | iSize = iEnd - iPtr; iStart = iPtr; } } if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PAGE(pPage); 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 || 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 ){ |
︙ | ︙ | |||
1896 1897 1898 1899 1900 1901 1902 | /* ** Decode the flags byte (the first byte of the header) for a page ** and initialize fields of the MemPage structure accordingly. ** ** Only the following combinations are supported. Anything different ** indicates a corrupt database files: ** | | < | | > | < | | > | | | | | | | < | < | < < < < < | | < | < < | < < < < < < < < < < < > | | | > > > > > > | | < | > > > > > | | < > | 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 | /* ** Decode the flags byte (the first byte of the header) for a page ** and initialize fields of the MemPage structure accordingly. ** ** Only the following combinations are supported. Anything different ** indicates a corrupt database files: ** ** PTF_ZERODATA ** PTF_ZERODATA | PTF_LEAF ** PTF_LEAFDATA | PTF_INTKEY ** PTF_LEAFDATA | PTF_INTKEY | PTF_LEAF */ static int decodeFlags(MemPage *pPage, int flagByte){ BtShared *pBt; /* A copy of pPage->pBt */ assert( pPage->hdrOffset==(pPage->pgno==1 ? 100 : 0) ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); pPage->leaf = (u8)(flagByte>>3); assert( PTF_LEAF == 1<<3 ); flagByte &= ~PTF_LEAF; pPage->childPtrSize = 4-4*pPage->leaf; pPage->xCellSize = cellSizePtr; pBt = pPage->pBt; if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){ /* EVIDENCE-OF: R-07291-35328 A value of 5 (0x05) means the page is an ** interior table b-tree page. */ assert( (PTF_LEAFDATA|PTF_INTKEY)==5 ); /* EVIDENCE-OF: R-26900-09176 A value of 13 (0x0d) means the page is a ** leaf table b-tree page. */ assert( (PTF_LEAFDATA|PTF_INTKEY|PTF_LEAF)==13 ); pPage->intKey = 1; if( pPage->leaf ){ pPage->intKeyLeaf = 1; pPage->xParseCell = btreeParseCellPtr; }else{ pPage->intKeyLeaf = 0; pPage->xCellSize = cellSizePtrNoPayload; pPage->xParseCell = btreeParseCellPtrNoPayload; } pPage->maxLocal = pBt->maxLeaf; pPage->minLocal = pBt->minLeaf; }else if( flagByte==PTF_ZERODATA ){ /* EVIDENCE-OF: R-43316-37308 A value of 2 (0x02) means the page is an ** interior index b-tree page. */ assert( (PTF_ZERODATA)==2 ); /* EVIDENCE-OF: R-59615-42828 A value of 10 (0x0a) means the page is a ** leaf index b-tree page. */ assert( (PTF_ZERODATA|PTF_LEAF)==10 ); pPage->intKey = 0; pPage->intKeyLeaf = 0; pPage->xParseCell = btreeParseCellPtrIndex; pPage->maxLocal = pBt->maxLocal; pPage->minLocal = pBt->minLocal; }else{ /* EVIDENCE-OF: R-47608-56469 Any other value for the b-tree page type is ** an error. */ 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. */ |
︙ | ︙ | |||
2001 2002 2003 2004 2005 2006 2007 | ** 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; | | | 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 | ** 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<iCellFirst ){ /* 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 ){ |
︙ | ︙ | |||
2035 2036 2037 2038 2039 2040 2041 | /* 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. */ | | | 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 | /* 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 ){ return SQLITE_CORRUPT_PAGE(pPage); } pPage->nFree = (u16)(nFree - iCellFirst); return SQLITE_OK; } /* |
︙ | ︙ | |||
2111 2112 2113 2114 2115 2116 2117 | 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; | | | 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 | 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); |
︙ | ︙ | |||
2146 2147 2148 2149 2150 2151 2152 | */ static void zeroPage(MemPage *pPage, int flags){ unsigned char *data = pPage->aData; BtShared *pBt = pPage->pBt; u8 hdr = pPage->hdrOffset; u16 first; | | | | 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 | */ static void zeroPage(MemPage *pPage, int flags){ unsigned char *data = pPage->aData; BtShared *pBt = pPage->pBt; u8 hdr = pPage->hdrOffset; u16 first; assert( sqlite3PagerPagenumber(pPage->pDbPage)==pPage->pgno ); assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage ); assert( sqlite3PagerGetData(pPage->pDbPage) == data ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( sqlite3_mutex_held(pBt->mutex) ); if( pBt->btsFlags & BTS_FAST_SECURE ){ memset(&data[hdr], 0, pBt->usableSize - hdr); } data[hdr] = (char)flags; first = hdr + ((flags&PTF_LEAF)==0 ? 12 : 8); memset(&data[hdr+1], 0, 4); data[hdr+7] = 0; put2byte(&data[hdr+5], pBt->usableSize); pPage->nFree = (u16)(pBt->usableSize - first); decodeFlags(pPage, flags); pPage->cellOffset = first; pPage->aDataEnd = &data[pBt->usableSize]; pPage->aCellIdx = &data[first]; pPage->aDataOfst = &data[pPage->childPtrSize]; pPage->nOverflow = 0; assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); pPage->maskPage = (u16)(pBt->pageSize - 1); pPage->nCell = 0; pPage->isInit = 1; |
︙ | ︙ | |||
2240 2241 2242 2243 2244 2245 2246 | /* ** 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; } | | > | 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 | /* ** 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; } u32 sqlite3BtreeLastPage(Btree *p){ assert( sqlite3BtreeHoldsMutex(p) ); assert( ((p->pBt->nPage)&0x80000000)==0 ); 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() |
︙ | ︙ | |||
2288 2289 2290 2291 2292 2293 2294 | if( (*ppPage)->isInit==0 ){ btreePageFromDbPage(pDbPage, pgno, pBt); rc = btreeInitPage(*ppPage); if( rc!=SQLITE_OK ){ goto getAndInitPage_error2; } } | | | | 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 | 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; } /* ** Release a MemPage. This should be called once for each prior ** call to btreeGetPage. ** |
︙ | ︙ | |||
2404 2405 2406 2407 2408 2409 2410 | /* ** 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) ); | | > | 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 | /* ** 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, sqlite3PagerFile(pBt->pPager)); } /* ** 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 |
︙ | ︙ | |||
2508 2509 2510 2511 2512 2513 2514 | } if( isMemdb ){ memcpy(zFullPathname, zFilename, nFilename); }else{ rc = sqlite3OsFullPathname(pVfs, zFilename, nFullPathname, zFullPathname); if( rc ){ | < < < | | | < | | 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 | } if( isMemdb ){ memcpy(zFullPathname, zFilename, nFilename); }else{ rc = sqlite3OsFullPathname(pVfs, zFilename, nFullPathname, zFullPathname); if( rc ){ 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_MASTER); 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; |
︙ | ︙ | |||
2639 2640 2641 2642 2643 2644 2645 | #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; ) | | | 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 | #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_MASTER);) if( SQLITE_THREADSAFE && sqlite3GlobalConfig.bCoreMutex ){ pBt->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_FAST); if( pBt->mutex==0 ){ rc = SQLITE_NOMEM_BKPT; goto btree_open_out; } } |
︙ | ︙ | |||
2704 2705 2706 2707 2708 2709 2710 | 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 ){ | | | 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 | 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 ){ sqlite3PagerSetCachesize(p->pBt->pPager, SQLITE_DEFAULT_CACHE_SIZE); } pFile = sqlite3PagerFile(pBt->pPager); if( pFile->pMethods ){ sqlite3OsFileControlHint(pFile, SQLITE_FCNTL_PDB, (void*)&pBt->db); } } |
︙ | ︙ | |||
2728 2729 2730 2731 2732 2733 2734 | ** 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 | | | | | | < | < < < | < < < < < | < | | | | | | | | | | | | | | | > | | < > > > < < < < | | | | | | < | 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 | ** 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 *pMaster; ) BtShared *pList; int removed = 0; assert( sqlite3_mutex_notheld(pBt->mutex) ); MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); ) sqlite3_mutex_enter(pMaster); 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(pMaster); return removed; #else return 1; #endif } /* ** Make sure pBt->pTmpSpace points to an allocation of ** MX_CELL_SIZE(pBt) bytes with a 4-byte prefix for a left-child ** pointer. */ static void allocateTempSpace(BtShared *pBt){ if( !pBt->pTmpSpace ){ pBt->pTmpSpace = sqlite3PageMalloc( pBt->pageSize ); /* One of the uses of pBt->pTmpSpace is to format cells before ** inserting them into a leaf page (function fillInCell()). If ** a cell is less than 4 bytes in size, it is rounded up to 4 bytes ** by the various routines that manipulate binary cells. Which ** can mean that fillInCell() only initializes the first 2 or 3 ** bytes of pTmpSpace, but that the first 4 bytes are copied from ** it into a database page. This is not actually a problem, but it ** does cause a valgrind error when the 1 or 2 bytes of unitialized ** data is passed to system call write(). So to avoid this error, ** zero the first 4 bytes of temp space here. ** ** Also: Provide four bytes of initialized space before the ** beginning of pTmpSpace as an area available to prepend the ** left-child pointer to the beginning of a cell. */ if( pBt->pTmpSpace ){ memset(pBt->pTmpSpace, 0, 8); pBt->pTmpSpace += 4; } } } /* ** Free the pBt->pTmpSpace allocation */ static void freeTempSpace(BtShared *pBt){ if( pBt->pTmpSpace ){ pBt->pTmpSpace -= 4; sqlite3PageFree(pBt->pTmpSpace); pBt->pTmpSpace = 0; } } /* ** Close an open database and invalidate all cursors. */ int sqlite3BtreeClose(Btree *p){ BtShared *pBt = p->pBt; BtCursor *pCur; /* Close all cursors opened via this handle. */ assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3BtreeEnter(p); pCur = pBt->pCursor; while( pCur ){ BtCursor *pTmp = pCur; pCur = pCur->pNext; if( pTmp->pBtree==p ){ sqlite3BtreeCloseCursor(pTmp); } } /* 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); |
︙ | ︙ | |||
2967 2968 2969 2970 2971 2972 2973 | ** 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; | < | > | < | > > > < | 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 | ** 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; assert( nReserve>=-1 && nReserve<=255 ); sqlite3BtreeEnter(p); #if SQLITE_HAS_CODEC if( nReserve>pBt->optimalReserve ) pBt->optimalReserve = (u8)nReserve; #endif if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){ sqlite3BtreeLeave(p); return SQLITE_READONLY; } if( nReserve<0 ){ nReserve = pBt->pageSize - pBt->usableSize; } assert( nReserve>=0 && nReserve<=255 ); if( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE && ((pageSize-1)&pageSize)==0 ){ assert( (pageSize & 7)==0 ); assert( !pBt->pCursor ); 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); |
︙ | ︙ | |||
3024 3025 3026 3027 3028 3029 3030 | } /* ** 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. ** | > | < | | | < | > > > | | | | 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 | } /* ** 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. ** ** If SQLITE_HAS_MUTEX is defined then the number returned is the ** greater of the current reserved space and the maximum requested ** reserve space. */ int sqlite3BtreeGetOptimalReserve(Btree *p){ int n; sqlite3BtreeEnter(p); n = sqlite3BtreeGetReserveNoMutex(p); #ifdef SQLITE_HAS_CODEC if( n<p->pBt->optimalReserve ) n = p->pBt->optimalReserve; #endif sqlite3BtreeLeave(p); return n; } /* ** 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. */ int sqlite3BtreeMaxPageCount(Btree *p, int mxPage){ int n; sqlite3BtreeEnter(p); n = sqlite3PagerMaxPageCount(p->pBt->pPager, mxPage); sqlite3BtreeLeave(p); return n; } /* |
︙ | ︙ | |||
3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 | ** 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. */ | > | | 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 | ** 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 */ u32 nPageHeader; /* Number of pages in the database according to hdr */ assert( sqlite3_mutex_held(pBt->mutex) ); assert( pBt->pPage1==0 ); rc = sqlite3PagerSharedLock(pBt->pPager); if( rc!=SQLITE_OK ) return rc; rc = btreeGetPage(pBt, 1, &pPage1, 0); if( rc!=SQLITE_OK ) return rc; /* Do some checking to help insure the file we opened really is ** a valid database file. */ nPage = nPageHeader = get4byte(28+(u8*)pPage1->aData); sqlite3PagerPagecount(pBt->pPager, (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; } |
︙ | ︙ | |||
3221 3222 3223 3224 3225 3226 3227 | if( page1[18]>2 ){ pBt->btsFlags |= BTS_READ_ONLY; } if( page1[19]>2 ){ goto page1_init_failed; } | | | 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 | if( page1[18]>2 ){ pBt->btsFlags |= BTS_READ_ONLY; } if( page1[19]>2 ){ goto page1_init_failed; } /* If the write 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. */ |
︙ | ︙ | |||
3293 3294 3295 3296 3297 3298 3299 | pBt->usableSize = usableSize; pBt->pageSize = pageSize; freeTempSpace(pBt); rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize, pageSize-usableSize); return rc; } | < | | | < < < | 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 | pBt->usableSize = usableSize; pBt->pageSize = pageSize; freeTempSpace(pBt); rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize, pageSize-usableSize); return rc; } if( sqlite3WritableSchema(pBt->db)==0 && nPage>nPageFile ){ rc = SQLITE_CORRUPT_BKPT; goto page1_init_failed; } /* EVIDENCE-OF: R-28312-64704 However, the usable size is not allowed to ** be less than 480. In other words, if the page size is 512, then the ** reserved space size cannot exceed 32. */ if( usableSize<480 ){ goto page1_init_failed; } |
︙ | ︙ | |||
3487 3488 3489 3490 3491 3492 3493 | ** 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; | < | | 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 | ** 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; 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(pBt->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; |
︙ | ︙ | |||
3545 3546 3547 3548 3549 3550 3551 | } } #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. */ | | < < < < < < < < < < < < | < | < < < | 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 | } } #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, MASTER_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 { /* 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{ rc = sqlite3PagerBegin(pBt->pPager,wrflag>1,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 ){ unlockBtreeIfUnused(pBt); } }while( (rc&0xFF)==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE && btreeInvokeBusyHandler(pBt) ); sqlite3PagerResetLockTimeout(pBt->pPager); 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 ); |
︙ | ︙ | |||
3649 3650 3651 3652 3653 3654 3655 | *pSchemaVersion = get4byte(&pBt->pPage1->aData[40]); } 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. */ | | | 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 | *pSchemaVersion = get4byte(&pBt->pPage1->aData[40]); } 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. */ rc = sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint); } } btreeIntegrity(p); sqlite3BtreeLeave(p); return rc; } |
︙ | ︙ | |||
3743 3744 3745 3746 3747 3748 3749 | } if( iFrom==get4byte(pCell+info.nSize-4) ){ put4byte(pCell+info.nSize-4, iTo); break; } } }else{ | < < < | 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 | } if( iFrom==get4byte(pCell+info.nSize-4) ){ put4byte(pCell+info.nSize-4, iTo); break; } } }else{ if( get4byte(pCell)==iFrom ){ put4byte(pCell, iTo); break; } } } |
︙ | ︙ | |||
3932 3933 3934 3935 3936 3937 3938 | */ if( bCommit==0 ){ eMode = BTALLOC_LE; iNear = nFin; } do { MemPage *pFreePg; | < < < < < | 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 | */ if( bCommit==0 ){ eMode = BTALLOC_LE; iNear = nFin; } do { MemPage *pFreePg; rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iNear, eMode); if( rc!=SQLITE_OK ){ releasePage(pLastPg); return rc; } releasePage(pFreePg); }while( bCommit && iFreePg>nFin ); assert( iFreePg<iLastPg ); rc = relocatePage(pBt, pLastPg, eType, iPtrPage, iFreePg, bCommit); releasePage(pLastPg); if( rc!=SQLITE_OK ){ return rc; |
︙ | ︙ | |||
4008 4009 4010 4011 4012 4013 4014 | if( !pBt->autoVacuum ){ rc = SQLITE_DONE; }else{ Pgno nOrig = btreePagecount(pBt); Pgno nFree = get4byte(&pBt->pPage1->aData[36]); Pgno nFin = finalDbSize(pBt, nOrig, nFree); | | | 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 | 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 ){ 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); } |
︙ | ︙ | |||
4031 4032 4033 4034 4035 4036 4037 4038 | sqlite3BtreeLeave(p); return rc; } /* ** This routine is called prior to sqlite3PagerCommit when a transaction ** is committed for an auto-vacuum database. */ | > > > > > | | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | | < | 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 | sqlite3BtreeLeave(p); return rc; } /* ** This routine is called prior to sqlite3PagerCommit when a transaction ** is committed for an auto-vacuum database. ** ** If SQLITE_OK is returned, then *pnTrunc is set to the number of pages ** the database file should be truncated to during the commit process. ** i.e. the database has been reorganized so that only the first *pnTrunc ** pages are in use. */ static int autoVacuumCommit(BtShared *pBt){ int rc = SQLITE_OK; Pager *pPager = pBt->pPager; VVA_ONLY( int 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 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]); nFin = finalDbSize(pBt, nOrig, nFree); if( nFin>nOrig ) return SQLITE_CORRUPT_BKPT; if( nFin<nOrig ){ rc = saveAllCursors(pBt, 0, 0); } for(iFree=nOrig; iFree>nFin && rc==SQLITE_OK; iFree--){ rc = incrVacuumStep(pBt, nFin, iFree, 1); } if( (rc==SQLITE_DONE || rc==SQLITE_OK) && nFree>0 ){ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); put4byte(&pBt->pPage1->aData[32], 0); put4byte(&pBt->pPage1->aData[36], 0); put4byte(&pBt->pPage1->aData[28], nFin); pBt->bDoTruncate = 1; pBt->nPage = nFin; } if( rc!=SQLITE_OK ){ sqlite3PagerRollback(pPager); } |
︙ | ︙ | |||
4132 4133 4134 4135 4136 4137 4138 | ** 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. ** | | | | | | | | | 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 | ** 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. zMaster points to ** the name of a master journal file that should be written into the ** individual journal file, or is NULL, indicating no master journal file ** (single database transaction). ** ** When this is called, the master 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 *zMaster){ int rc = SQLITE_OK; if( p->inTrans==TRANS_WRITE ){ BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum ){ rc = autoVacuumCommit(pBt); if( rc!=SQLITE_OK ){ sqlite3BtreeLeave(p); return rc; } } if( pBt->bDoTruncate ){ sqlite3PagerTruncateImage(pBt->pPager, pBt->nPage); } #endif rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zMaster, 0); sqlite3BtreeLeave(p); } return rc; } /* ** This function is called from both BtreeCommitPhaseTwo() and BtreeRollback() |
︙ | ︙ | |||
4223 4224 4225 4226 4227 4228 4229 | ** 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 | | | 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 | ** 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 master 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. |
︙ | ︙ | |||
4251 4252 4253 4254 4255 4256 4257 | assert( pBt->inTransaction==TRANS_WRITE ); assert( pBt->nTransaction>0 ); rc = sqlite3PagerCommitPhaseTwo(pBt->pPager); if( rc!=SQLITE_OK && bCleanup==0 ){ sqlite3BtreeLeave(p); return rc; } | | | 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 | assert( pBt->inTransaction==TRANS_WRITE ); assert( pBt->nTransaction>0 ); rc = sqlite3PagerCommitPhaseTwo(pBt->pPager); if( rc!=SQLITE_OK && bCleanup==0 ){ sqlite3BtreeLeave(p); return rc; } p->iDataVersion--; /* Compensate for pPager->iDataVersion++; */ pBt->inTransaction = TRANS_READ; btreeClearHasContent(pBt); } btreeEndTransaction(p); sqlite3BtreeLeave(p); return SQLITE_OK; |
︙ | ︙ | |||
4329 4330 4331 4332 4333 4334 4335 | btreeReleaseAllCursorPages(p); } sqlite3BtreeLeave(pBtree); } return rc; } | < < < < < < < < < < < < | 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 | 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 ** a tripped cursor will result in an error. |
︙ | ︙ | |||
4386 4387 4388 4389 4390 4391 4392 | 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 ){ | | > > > > | 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 | 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 ){ int nPage = get4byte(28+(u8*)pPage1->aData); testcase( nPage==0 ); if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage); testcase( pBt->nPage!=nPage ); pBt->nPage = nPage; releasePageOne(pPage1); } assert( countValidCursors(pBt, 1)==0 ); pBt->inTransaction = TRANS_READ; btreeClearHasContent(pBt); } |
︙ | ︙ | |||
4466 4467 4468 4469 4470 4471 4472 | 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); | | | | > | | 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 | 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); pBt->nPage = get4byte(28 + pBt->pPage1->aData); /* The database size was written into the offset 28 of the header ** when the transaction started, so we know that the value at offset ** 28 is nonzero. */ assert( pBt->nPage>0 ); } sqlite3BtreeLeave(p); } return rc; } /* |
︙ | ︙ | |||
4521 4522 4523 4524 4525 4526 4527 | ** 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 */ | | | | < | | | > | | | < | | > | | < < < | < < < < < < < < < < < < < < < < < | | | > > | > > | 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 | ** 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 */ int 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. */ assert( hasSharedCacheTableLock(p, iTable, pKeyInfo!=0, (wrFlag?2: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 && 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 = (Pgno)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==(Pgno)iTable ){ pX->curFlags |= BTCF_Multiple; pCur->curFlags |= BTCF_Multiple; } } pCur->pNext = pBt->pCursor; pBt->pCursor = pCur; pCur->eState = CURSOR_INVALID; return SQLITE_OK; } int sqlite3BtreeCursor( Btree *p, /* The btree */ int 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 */ ){ int rc; if( iTable<1 ){ rc = SQLITE_CORRUPT_BKPT; }else{ sqlite3BtreeEnter(p); rc = btreeCursor(p, iTable, wrFlag, pKeyInfo, pCur); sqlite3BtreeLeave(p); } return rc; } /* ** 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 |
︙ | ︙ | |||
4663 4664 4665 4666 4667 4668 4669 | pPrev = pPrev->pNext; }while( ALWAYS(pPrev) ); } btreeReleaseAllCursorPages(pCur); unlockBtreeIfUnused(pBt); sqlite3_free(pCur->aOverflow); sqlite3_free(pCur->pKey); | < < < < < < | < | 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 | pPrev = pPrev->pNext; }while( ALWAYS(pPrev) ); } btreeReleaseAllCursorPages(pCur); unlockBtreeIfUnused(pBt); sqlite3_free(pCur->aOverflow); sqlite3_free(pCur->pKey); sqlite3BtreeLeave(pBtree); pCur->pBtree = 0; } return SQLITE_OK; } /* ** Make sure the BtCursor* given in the argument has a valid |
︙ | ︙ | |||
4740 4741 4742 4743 4744 4745 4746 | assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->curIntKey ); getCellInfo(pCur); return pCur->info.nKey; } | < < < < < < < < < < < < | 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 | 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){ assert( cursorHoldsMutex(pCur) ); |
︙ | ︙ | |||
4957 4958 4959 4960 4961 4962 4963 | #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 ); | | < < | 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 | #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 ); assert( pCur->ix<pPage->nCell ); assert( cursorHoldsMutex(pCur) ); getCellInfo(pCur); aPayload = pCur->info.pPayload; assert( offset+amt <= pCur->info.nPayload ); assert( aPayload > pPage->aData ); |
︙ | ︙ | |||
4996 4997 4998 4999 5000 5001 5002 | 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]); | | | 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 | 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). */ |
︙ | ︙ | |||
5035 5036 5037 5038 5039 5040 5041 | offset = (offset%ovflSize); } } assert( rc==SQLITE_OK && amt>0 ); while( nextPage ){ /* If required, populate the overflow page-list cache. */ | < | 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 | 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 |
︙ | ︙ | |||
5090 5091 5092 5093 5094 5095 5096 | ){ 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)); | < | 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 | ){ 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; |
︙ | ︙ | |||
5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 | ** 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. | > | 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 | ** 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 ); assert( pCur->ix<pCur->pPage->nCell ); 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. |
︙ | ︙ | |||
5207 5208 5209 5210 5211 5212 5213 | 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) ); | | | 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 | 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 ); 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. */ |
︙ | ︙ | |||
5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 | ** ** This function returns SQLITE_CORRUPT if the page-header flags field of ** the new child page does not match the flags field of the parent (i.e. ** if an intkey page appears to be the parent of a non-intkey page, or ** vice-versa). */ static int moveToChild(BtCursor *pCur, u32 newPgno){ assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->iPage<BTCURSOR_MAX_DEPTH ); assert( pCur->iPage>=0 ); if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){ return SQLITE_CORRUPT_BKPT; } pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); pCur->aiIdx[pCur->iPage] = pCur->ix; pCur->apPage[pCur->iPage] = pCur->pPage; pCur->ix = 0; pCur->iPage++; | > > | < | 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 | ** ** This function returns SQLITE_CORRUPT if the page-header flags field of ** the new child page does not match the flags field of the parent (i.e. ** if an intkey page appears to be the parent of a non-intkey page, or ** vice-versa). */ static int moveToChild(BtCursor *pCur, u32 newPgno){ BtShared *pBt = pCur->pBt; assert( cursorOwnsBtShared(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->iPage<BTCURSOR_MAX_DEPTH ); assert( pCur->iPage>=0 ); if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){ return SQLITE_CORRUPT_BKPT; } pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl); pCur->aiIdx[pCur->iPage] = pCur->ix; pCur->apPage[pCur->iPage] = pCur->pPage; pCur->ix = 0; pCur->iPage++; return getAndInitPage(pBt, newPgno, &pCur->pPage, pCur, pCur->curPagerFlags); } #ifdef SQLITE_DEBUG /* ** Page pParent is an internal (non-leaf) tree page. This function ** asserts that page number iChild is the left-child if the iIdx'th ** cell in page pParent. Or, if iIdx is equal to the total number of |
︙ | ︙ | |||
5357 5358 5359 5360 5361 5362 5363 | if( pCur->iPage>=0 ){ if( pCur->iPage ){ releasePageNotNull(pCur->pPage); while( --pCur->iPage ){ releasePageNotNull(pCur->apPage[pCur->iPage]); } | | | | | 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 | if( pCur->iPage>=0 ){ if( pCur->iPage ){ releasePageNotNull(pCur->pPage); while( --pCur->iPage ){ releasePageNotNull(pCur->apPage[pCur->iPage]); } pCur->pPage = pCur->apPage[0]; goto skip_init; } }else if( pCur->pgnoRoot==0 ){ pCur->eState = CURSOR_INVALID; return SQLITE_EMPTY; }else{ assert( pCur->iPage==(-1) ); if( pCur->eState>=CURSOR_REQUIRESEEK ){ if( pCur->eState==CURSOR_FAULT ){ assert( pCur->skipNext!=SQLITE_OK ); return pCur->skipNext; } sqlite3BtreeClearCursor(pCur); } rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->pPage, 0, pCur->curPagerFlags); if( rc!=SQLITE_OK ){ pCur->eState = CURSOR_INVALID; return rc; } pCur->iPage = 0; pCur->curIntKey = pCur->pPage->intKey; } pRoot = pCur->pPage; assert( pRoot->pgno==pCur->pgnoRoot ); /* If pCur->pKeyInfo is not NULL, then the caller that opened this cursor ** expected to open it on an index b-tree. Otherwise, if pKeyInfo is ** NULL, the caller expects a table b-tree. If this is not the case, ** return an SQLITE_CORRUPT error. ** ** Earlier versions of SQLite assumed that this test could not fail |
︙ | ︙ | |||
5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 | } skip_init: pCur->ix = 0; pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl); if( pRoot->nCell>0 ){ pCur->eState = CURSOR_VALID; }else if( !pRoot->leaf ){ Pgno subpage; if( pRoot->pgno!=1 ) return SQLITE_CORRUPT_BKPT; subpage = get4byte(&pRoot->aData[pRoot->hdrOffset+8]); pCur->eState = CURSOR_VALID; | > | 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 | } skip_init: pCur->ix = 0; pCur->info.nSize = 0; pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl); pRoot = pCur->pPage; if( pRoot->nCell>0 ){ pCur->eState = CURSOR_VALID; }else if( !pRoot->leaf ){ Pgno subpage; if( pRoot->pgno!=1 ) return SQLITE_CORRUPT_BKPT; subpage = get4byte(&pRoot->aData[pRoot->hdrOffset+8]); pCur->eState = CURSOR_VALID; |
︙ | ︙ | |||
5496 5497 5498 5499 5500 5501 5502 | 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. */ | | > > > > > > > > > > > > > > > > > > > > | < < < < < < < < < < < < < < < < < < < < < < < | | > > > > | | | > > > | > > | | > | > | 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 | 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 ); assert( pCur->pPage->leaf ); #endif return SQLITE_OK; } rc = moveToRoot(pCur); if( rc==SQLITE_OK ){ assert( pCur->eState==CURSOR_VALID ); *pRes = 0; rc = moveToRightmost(pCur); if( rc==SQLITE_OK ){ pCur->curFlags |= BTCF_AtLast; }else{ pCur->curFlags &= ~BTCF_AtLast; } }else if( rc==SQLITE_EMPTY ){ 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 near the key ** specified by pIdxKey or intKey. Return a success code. ** ** For INTKEY tables, the intKey parameter is used. pIdxKey ** must be NULL. For index tables, pIdxKey is used and intKey ** is ignored. ** ** 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/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 intKey/pIdxKey. ** ** *pRes>0 The cursor is left pointing at an entry that ** is larger than intKey/pIdxKey. ** ** For index tables, the pIdxKey->eqSeen field is set to 1 if there ** exists an entry in the table that exactly matches pIdxKey. */ int sqlite3BtreeMovetoUnpacked( BtCursor *pCur, /* The cursor to be moved */ UnpackedRecord *pIdxKey, /* Unpacked index key */ i64 intKey, /* The table key */ int biasRight, /* If true, bias the search to the high end */ int *pRes /* Write search results here */ ){ int rc; RecordCompare xRecordCompare; assert( cursorOwnsBtShared(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( pRes ); assert( (pIdxKey==0)==(pCur->pKeyInfo==0) ); assert( pCur->eState!=CURSOR_VALID || (pIdxKey==0)==(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( pIdxKey==0 && 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; |
︙ | ︙ | |||
5599 5600 5601 5602 5603 5604 5605 | *pRes = 0; rc = sqlite3BtreeNext(pCur, 0); if( rc==SQLITE_OK ){ getCellInfo(pCur); if( pCur->info.nKey==intKey ){ return SQLITE_OK; } | | > > | | > > > > > | > > | < | > > | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > < > | | | > | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | *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 ){ rc = SQLITE_OK; }else{ return rc; } } } } if( pIdxKey ){ xRecordCompare = sqlite3VdbeFindCompare(pIdxKey); pIdxKey->errCode = 0; assert( pIdxKey->default_rc==1 || pIdxKey->default_rc==0 || pIdxKey->default_rc==-1 ); }else{ xRecordCompare = 0; /* All keys are integers */ } 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 || pIdxKey ); 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==(pIdxKey==0) ); 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; if( xRecordCompare==0 ){ 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_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; */ } }else{ 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; 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_finish; } pCellKey = sqlite3Malloc( nCell+18 ); if( pCellKey==0 ){ rc = SQLITE_NOMEM_BKPT; goto moveto_finish; } pCur->ix = (u16)idx; rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0); pCur->curFlags &= ~BTCF_ValidOvfl; if( rc ){ sqlite3_free(pCellKey); goto moveto_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_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_finish; } moveto_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_finish: pCur->info.nSize = 0; assert( (pCur->curFlags & BTCF_ValidOvfl)==0 ); return rc; } /* |
︙ | ︙ | |||
6080 6081 6082 6083 6084 6085 6086 | pCur->eState = CURSOR_VALID; if( pCur->skipNext>0 ) return SQLITE_OK; } } pPage = pCur->pPage; idx = ++pCur->ix; | | > > > > > > > > > > > > > > | 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 | 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 the database file is corrupt, it is possible for the value of idx ** to be invalid here. This can only occur if a second cursor modifies ** the page while cursor pCur is holding a reference to it. Which can ** only happen if the database is corrupt in such a way as to link the ** page into more than one b-tree structure. */ testcase( idx>pPage->nCell ); if( idx>=pPage->nCell ){ if( !pPage->leaf ){ rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8])); if( rc ) return rc; return moveToLeftmost(pCur); } |
︙ | ︙ | |||
6256 6257 6258 6259 6260 6261 6262 | MemPage *pPrevTrunk = 0; Pgno mxPage; /* Total size of the database file */ assert( sqlite3_mutex_held(pBt->mutex) ); assert( eMode==BTALLOC_ANY || (nearby>0 && IfNotOmitAV(pBt->autoVacuum)) ); pPage1 = pBt->pPage1; mxPage = btreePagecount(pBt); | | | | 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 | MemPage *pPrevTrunk = 0; Pgno mxPage; /* Total size of the database file */ assert( sqlite3_mutex_held(pBt->mutex) ); assert( eMode==BTALLOC_ANY || (nearby>0 && IfNotOmitAV(pBt->autoVacuum)) ); pPage1 = pBt->pPage1; mxPage = btreePagecount(pBt); /* EVIDENCE-OF: R-05119-02637 The 4-byte big-endian integer at offset 36 ** stores stores the total number of pages on the freelist. */ n = get4byte(&pPage1->aData[36]); testcase( n==mxPage-1 ); if( n>=mxPage ){ return SQLITE_CORRUPT_BKPT; } if( n>0 ){ /* There are pages on the freelist. Reuse one of those pages. */ |
︙ | ︙ | |||
6444 6445 6446 6447 6448 6449 6450 | } }else{ closest = 0; } iPage = get4byte(&aData[8+closest*4]); testcase( iPage==mxPage ); | | | 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 | } }else{ closest = 0; } iPage = get4byte(&aData[8+closest*4]); testcase( iPage==mxPage ); if( iPage>mxPage ){ rc = SQLITE_CORRUPT_PGNO(iTrunk); goto end_allocate_page; } testcase( iPage==mxPage ); if( !searchList || (iPage==nearby || (iPage<nearby && eMode==BTALLOC_LE)) ){ |
︙ | ︙ | |||
6602 6603 6604 6605 6606 6607 6608 | } memset(pPage->aData, 0, pPage->pBt->pageSize); } /* If the database supports auto-vacuum, write an entry in the pointer-map ** to indicate that the page is free. */ | | < < < < | 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 | } memset(pPage->aData, 0, pPage->pBt->pageSize); } /* If the database supports auto-vacuum, write an entry in the pointer-map ** to indicate that the page is free. */ if( ISAUTOVACUUM ){ ptrmapPut(pBt, iPage, PTRMAP_FREEPAGE, 0, &rc); if( rc ) goto freepage_out; } /* Now manipulate the actual database free-list structure. There are two ** possibilities. If the free-list is currently empty, or if the first ** trunk page in the free-list is full, then this page will become a ** new free-list trunk page. Otherwise, it will become a leaf of the ** 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 ); |
︙ | ︙ | |||
6700 6701 6702 6703 6704 6705 6706 | static void freePage(MemPage *pPage, int *pRC){ if( (*pRC)==SQLITE_OK ){ *pRC = freePage2(pPage->pBt, pPage, pPage->pgno); } } /* | | > | > | > > | 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 | static void freePage(MemPage *pPage, int *pRC){ if( (*pRC)==SQLITE_OK ){ *pRC = freePage2(pPage->pBt, pPage, pPage->pgno); } } /* ** Free any overflow pages associated with the given Cell. Store ** size information about the cell in pInfo. */ static int clearCell( MemPage *pPage, /* The page that contains the Cell */ unsigned char *pCell, /* First byte of the Cell */ CellInfo *pInfo /* Size information about the cell */ ){ BtShared *pBt; Pgno ovflPgno; int rc; int nOvfl; u32 ovflPageSize; assert( sqlite3_mutex_held(pPage->pBt->mutex) ); pPage->xParseCell(pPage, pCell, pInfo); if( pInfo->nLocal==pInfo->nPayload ){ return SQLITE_OK; /* No overflow pages. Return without doing anything */ } 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); |
︙ | ︙ | |||
6769 6770 6771 6772 6773 6774 6775 | sqlite3PagerUnref(pOvfl->pDbPage); } if( rc ) return rc; ovflPgno = iNext; } return SQLITE_OK; } | < < < < < < < < < < < < < < < | 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 | 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[]. |
︙ | ︙ | |||
6995 6996 6997 6998 6999 7000 7001 | u32 pc; /* Offset to cell content of cell being deleted */ u8 *data; /* pPage->aData */ u8 *ptr; /* Used to move bytes around within data[] */ int rc; /* The return code */ int hdr; /* Beginning of the header. 0 most pages. 100 page 1 */ if( *pRC ) return; | | < < | | 6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 | u32 pc; /* Offset to cell content of cell being deleted */ u8 *data; /* pPage->aData */ u8 *ptr; /* Used to move bytes around within data[] */ int rc; /* The return code */ 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 ){ *pRC = SQLITE_CORRUPT_BKPT; return; } rc = freeSpace(pPage, pc, sz); if( rc ){ |
︙ | ︙ | |||
7042 7043 7044 7045 7046 7047 7048 7049 | ** If the cell content will fit on the page, then put it there. If it ** will not fit, then make a copy of the cell content into pTemp if ** pTemp is not null. Regardless of pTemp, allocate a new entry ** in pPage->apOvfl[] and make it point to the cell content (either ** in pTemp or the original pCell) and also record its index. ** Allocating a new entry in pPage->aCell[] implies that ** pPage->nOverflow is incremented. */ | > > | | > > > > > > > | | 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 | ** If the cell content will fit on the page, then put it there. If it ** will not fit, then make a copy of the cell content into pTemp if ** pTemp is not null. Regardless of pTemp, allocate a new entry ** in pPage->apOvfl[] and make it point to the cell content (either ** in pTemp or the original pCell) and also record its index. ** Allocating a new entry in pPage->aCell[] implies that ** pPage->nOverflow is incremented. ** ** *pRC must be SQLITE_OK when this routine is called. */ static void insertCell( MemPage *pPage, /* Page into which we are copying */ int i, /* New cell becomes the i-th cell of the page */ u8 *pCell, /* Content of the new cell */ int sz, /* Bytes of content in pCell */ u8 *pTemp, /* Temp storage space for pCell, if needed */ Pgno iChild, /* If non-zero, replace first 4 bytes with this value */ int *pRC /* Read and write return code from here */ ){ int idx = 0; /* Where to write new cell content in data[] */ int j; /* Loop counter */ u8 *data; /* The content of the whole page */ u8 *pIns; /* The point in pPage->aCellIdx[] where no cell inserted */ 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) ); /* The cell should normally be sized correctly. However, when moving a ** malformed cell from a leaf page to an interior page, if the cell size ** wanted to be less than 4 but got rounded up to 4 on the leaf, then size ** might be less than 8 (leaf-size + pointer) on the interior node. Hence ** the term after the || in the following assert(). */ assert( sz==pPage->xCellSize(pPage, pCell) || (sz==8 && iChild>0) ); assert( pPage->nFree>=0 ); if( pPage->nOverflow || sz+2>pPage->nFree ){ if( pTemp ){ memcpy(pTemp, pCell, sz); pCell = pTemp; } if( iChild ){ |
︙ | ︙ | |||
7090 7091 7092 7093 7094 7095 7096 | ** balancing, and the dividers are adjacent and sorted. */ assert( j==0 || pPage->aiOvfl[j-1]<(u16)i ); /* Overflows in sorted order */ assert( j==0 || i==pPage->aiOvfl[j-1]+1 ); /* Overflows are sequential */ }else{ int rc = sqlite3PagerWrite(pPage->pDbPage); if( rc!=SQLITE_OK ){ | > | | | 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 | ** balancing, and the dividers are adjacent and sorted. */ assert( j==0 || pPage->aiOvfl[j-1]<(u16)i ); /* Overflows in sorted order */ assert( j==0 || i==pPage->aiOvfl[j-1]+1 ); /* Overflows are sequential */ }else{ int rc = sqlite3PagerWrite(pPage->pDbPage); if( rc!=SQLITE_OK ){ *pRC = rc; return; } assert( sqlite3PagerIswriteable(pPage->pDbPage) ); data = pPage->aData; assert( &data[pPage->cellOffset]==pPage->aCellIdx ); rc = allocateSpace(pPage, sz, &idx); 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)pPage->pBt->usableSize ); pPage->nFree -= (u16)(2 + sz); if( iChild ){ |
︙ | ︙ | |||
7123 7124 7125 7126 7127 7128 7129 | 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 ); #ifndef SQLITE_OMIT_AUTOVACUUM if( pPage->pBt->autoVacuum ){ | < | < < | 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 | 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 ); #ifndef SQLITE_OMIT_AUTOVACUUM if( pPage->pBt->autoVacuum ){ /* 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); } #endif } } /* ** 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 |
︙ | ︙ | |||
7233 7234 7235 7236 7237 7238 7239 | }; /* ** Make sure the cell sizes at idx, idx+1, ..., idx+N-1 have been ** computed. */ static void populateCellCache(CellArray *p, int idx, int N){ | < < | | | | 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 | }; /* ** Make sure the cell sizes at idx, idx+1, ..., idx+N-1 have been ** computed. */ static void populateCellCache(CellArray *p, int idx, int N){ assert( idx>=0 && idx+N<=p->nCell ); while( N>0 ){ assert( p->apCell[idx]!=0 ); if( p->szCell[idx]==0 ){ p->szCell[idx] = p->pRef->xCellSize(p->pRef, p->apCell[idx]); }else{ assert( CORRUPT_DB || p->szCell[idx]==p->pRef->xCellSize(p->pRef, p->apCell[idx]) ); } idx++; N--; } } /* |
︙ | ︙ | |||
7298 7299 7300 7301 7302 7303 7304 | 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]); | | | | > | 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 | 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,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; memcpy(pData, pCell, sz); assert( sz==pPg->xCellSize(pPg, pCell) || CORRUPT_DB ); testcase( sz!=pPg->xCellSize(pPg,pCell) ); i++; if( i>=iEnd ) break; if( pCArray->ixNx[k]<=i ){ k++; pSrcEnd = pCArray->apEnd[k]; } } |
︙ | ︙ | |||
7389 7390 7391 7392 7393 7394 7395 | 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; | < | | 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 | 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; sz = cachedCellSize(pCArray, 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() |
︙ | ︙ | |||
7444 7445 7446 7447 7448 7449 7450 | ){ u8 * const aData = pPg->aData; u8 * const pEnd = &aData[pPg->pBt->usableSize]; u8 * const pStart = &aData[pPg->hdrOffset + 8 + pPg->childPtrSize]; int nRet = 0; int i; int iEnd = iFirst + nCell; | | | | < < < < < | 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 | ){ u8 * const aData = pPg->aData; u8 * const pEnd = &aData[pPg->pBt->usableSize]; u8 * const pStart = &aData[pPg->hdrOffset + 8 + pPg->childPtrSize]; int nRet = 0; int i; int iEnd = iFirst + nCell; u8 *pFree = 0; int szFree = 0; for(i=iFirst; i<iEnd; i++){ u8 *pCell = pCArray->apCell[i]; if( SQLITE_WITHIN(pCell, pStart, pEnd) ){ int sz; /* No need to use cachedCellSize() here. The sizes of all cells that ** are to be freed have already been computing while deciding which ** cells need freeing */ sz = pCArray->szCell[i]; assert( sz>0 ); 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 ){ |
︙ | ︙ | |||
7520 7521 7522 7523 7524 7525 7526 | 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); | | < | 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 | 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( 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; /* 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; |
︙ | ︙ | |||
7557 7558 7559 7560 7561 7562 7563 | 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++; | < | 7140 7141 7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 | 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++; if( pageInsertArray( pPg, pBegin, &pData, pCellptr, iCell+iNew, 1, pCArray ) ) goto editpage_fail; } } |
︙ | ︙ | |||
7676 7677 7678 7679 7680 7681 7682 | ** 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. */ | | | 7258 7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 | ** 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( ISAUTOVACUUM ){ 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 |
︙ | ︙ | |||
7704 7705 7706 7707 7708 7709 7710 | pStop = &pCell[9]; while( (*(pCell++)&0x80) && pCell<pStop ); pStop = &pCell[9]; while( ((*(pOut++) = *(pCell++))&0x80) && pCell<pStop ); /* Insert the new divider cell into pParent. */ if( rc==SQLITE_OK ){ | | | | 7286 7287 7288 7289 7290 7291 7292 7293 7294 7295 7296 7297 7298 7299 7300 7301 | pStop = &pCell[9]; while( (*(pCell++)&0x80) && pCell<pStop ); pStop = &pCell[9]; while( ((*(pOut++) = *(pCell++))&0x80) && pCell<pStop ); /* Insert the new divider cell into pParent. */ if( rc==SQLITE_OK ){ insertCell(pParent, pParent->nCell, pSpace, (int)(pOut-pSpace), 0, pPage->pgno, &rc); } /* Set the right-child pointer of pParent to point to the new page. */ put4byte(&pParent->aData[pParent->hdrOffset+8], pgnoNew); /* Release the reference to the new page. */ releasePage(pNew); |
︙ | ︙ | |||
7814 7815 7816 7817 7818 7819 7820 | *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. */ | | | 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 | *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. */ if( ISAUTOVACUUM ){ *pRC = setChildPtrmaps(pTo); } } } /* ** This routine redistributes cells on the iParentIdx'th child of pParent |
︙ | ︙ | |||
7892 7893 7894 7895 7896 7897 7898 | int cntNew[NB+2]; /* Index in b.paCell[] of cell after i-th page */ int cntOld[NB+2]; /* Old index in b.apCell[] */ 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 */ | > > | | > | 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484 7485 7486 7487 7488 7489 7490 7491 7492 7493 7494 | int cntNew[NB+2]; /* Index in b.paCell[] of cell after i-th page */ int cntOld[NB+2]; /* Old index in b.apCell[] */ 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)); b.nCell = 0; b.apCell = 0; 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 |
︙ | ︙ | |||
7946 7947 7948 7949 7950 7951 7952 | 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 ){ | < | < < | 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 | if( (i+nxDiv-pParent->nOverflow)==pParent->nCell ){ pRight = &pParent->aData[pParent->hdrOffset+8]; }else{ pRight = findCell(pParent, i+nxDiv-pParent->nOverflow); } pgno = get4byte(pRight); while( 1 ){ rc = getAndInitPage(pBt, pgno, &apOld[i], 0, 0); if( rc ){ memset(apOld, 0, (i+1)*sizeof(MemPage*)); goto balance_cleanup; } if( apOld[i]->nFree<0 ){ rc = btreeComputeFreeSpace(apOld[i]); if( rc ){ memset(apOld, 0, (i)*sizeof(MemPage*)); goto balance_cleanup; } } 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; |
︙ | ︙ | |||
7988 7989 7990 7991 7992 7993 7994 | ** 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; | < < | > > > > > | 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 | ** 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); if( (iOff+szNew[i])>(int)pBt->usableSize ){ rc = SQLITE_CORRUPT_BKPT; memset(apOld, 0, (i+1)*sizeof(MemPage*)); goto balance_cleanup; }else{ 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 = nOld*(MX_CELL(pBt) + ArraySize(pParent->apOvfl)); nMaxCells = (nMaxCells + 3)&~3; /* ** Allocate space for memory structures */ szScratch = nMaxCells*sizeof(u8*) /* b.apCell */ |
︙ | ︙ | |||
8048 8049 8050 8051 8052 8053 8054 | 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; | < | 7633 7634 7635 7636 7637 7638 7639 7640 7641 7642 7643 7644 7645 7646 | 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; |
︙ | ︙ | |||
8077 8078 8079 8080 8081 8082 8083 | ** 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 ){ | < < < < < | | 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 | ** 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 ); assert( pOld->hdrOffset==0 ); /* 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 |
︙ | ︙ | |||
8238 8239 8240 8241 8242 8243 8244 | int r; /* Index of right-most cell in left sibling */ int d; /* Index of first cell to the left of right sibling */ r = cntNew[i-1] - 1; d = r + 1 - leafData; (void)cachedCellSize(&b, d); do{ | < | < | | | | 7817 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835 7836 7837 7838 7839 | int r; /* Index of right-most cell in left sibling */ int d; /* Index of first cell to the left of right sibling */ r = cntNew[i-1] - 1; d = r + 1 - leafData; (void)cachedCellSize(&b, d); do{ assert( d<nMaxCells ); assert( r<nMaxCells ); (void)cachedCellSize(&b, r); if( szRight!=0 && (bBulk || szRight+b.szCell[d]+2 > szLeft-(b.szCell[r]+(i==k-1?0:2)))){ break; } szRight += b.szCell[d] + 2; szLeft -= b.szCell[r] + 2; cntNew[i-1] = r; r--; d--; }while( r>=0 ); szNew[i] = szRight; szNew[i-1] = szLeft; if( cntNew[i-1] <= (i>1 ? cntNew[i-2] : 0) ){ |
︙ | ︙ | |||
8286 8287 8288 8289 8290 8291 8292 | for(i=0; i<k; i++){ MemPage *pNew; if( i<nOld ){ pNew = apNew[i] = apOld[i]; apOld[i] = 0; rc = sqlite3PagerWrite(pNew->pDbPage); nNew++; | < < < < < | | | | | > > > > > > > > | > > | > > | | | | | < < < | < | < | < < < < | > | | < < < | 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 | 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; nNew++; cntOld[i] = b.nCell; /* Set the pointer-map entry for the new sibling page. */ if( ISAUTOVACUUM ){ ptrmapPut(pBt, pNew->pgno, PTRMAP_BTREE, pParent->pgno, &rc); if( rc!=SQLITE_OK ){ goto balance_cleanup; } } } } /* ** Reassign page numbers so that the new pages are in ascending order. ** This helps to keep entries in the disk file in order so that a scan ** of the table is closer to a linear scan through the file. That in turn ** helps the operating system to deliver pages from the disk more rapidly. ** ** An O(n^2) insertion sort algorithm is used, but since n is never more ** than (NB+2) (a small constant), that should not be a problem. ** ** 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( 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 ); rc = SQLITE_CORRUPT_BKPT; goto balance_cleanup; } } } for(i=0; i<nNew; i++){ int iBest = 0; /* aPgno[] index of page number to use */ for(j=1; j<nNew; j++){ if( aPgOrder[j]<aPgOrder[iBest] ) iBest = j; } pgno = aPgOrder[iBest]; aPgOrder[iBest] = 0xffffffff; if( iBest!=i ){ if( iBest>i ){ sqlite3PagerRekey(apNew[iBest]->pDbPage, pBt->nPage+iBest+1, 0); } sqlite3PagerRekey(apNew[i]->pDbPage, pgno, aPgFlags[iBest]); apNew[i]->pgno = pgno; } } TRACE(("BALANCE: new: %d(%d nc=%d) %d(%d nc=%d) %d(%d nc=%d) " "%d(%d nc=%d) %d(%d nc=%d)\n", apNew[0]->pgno, szNew[0], cntNew[0], nNew>=2 ? apNew[1]->pgno : 0, nNew>=2 ? szNew[1] : 0, nNew>=2 ? cntNew[1] - cntNew[0] - !leafData : 0, nNew>=3 ? apNew[2]->pgno : 0, nNew>=3 ? szNew[2] : 0, nNew>=3 ? cntNew[2] - cntNew[1] - !leafData : 0, 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]; |
︙ | ︙ | |||
8395 8396 8397 8398 8399 8400 8401 | ** with the cell. ** ** 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. */ | | < | 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 | ** with the cell. ** ** 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( ISAUTOVACUUM ){ 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 ); pOld = iOld<nNew ? apNew[iOld] : apOld[iOld]; cntOldNext += pOld->nCell + pOld->nOverflow + !leafData; } if( i==cntNew[iNew] ){ pNew = apNew[++iNew]; if( !leafData ) continue; } |
︙ | ︙ | |||
8442 8443 8444 8445 8446 8447 8448 | } /* Insert new divider cells into pParent. */ for(i=0; i<nNew-1; i++){ u8 *pCell; u8 *pTemp; int sz; | < | 8014 8015 8016 8017 8018 8019 8020 8021 8022 8023 8024 8025 8026 8027 | } /* Insert new divider cells into pParent. */ for(i=0; i<nNew-1; i++){ u8 *pCell; u8 *pTemp; int sz; MemPage *pNew = apNew[i]; j = cntNew[i]; assert( j<nMaxCells ); assert( b.apCell[j]!=0 ); pCell = b.apCell[j]; sz = b.szCell[j] + leafCorrection; |
︙ | ︙ | |||
8486 8487 8488 8489 8490 8491 8492 | assert(leafCorrection==4); sz = pParent->xCellSize(pParent, pCell); } } iOvflSpace += sz; assert( sz<=pBt->maxLocal+23 ); assert( iOvflSpace <= (int)pBt->pageSize ); | < < < < < < | | 8057 8058 8059 8060 8061 8062 8063 8064 8065 8066 8067 8068 8069 8070 8071 | 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 ** cells may still to be read. In practice, this means: |
︙ | ︙ | |||
8588 8589 8590 8591 8592 8593 8594 | 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); | | | | 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 | 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( ISAUTOVACUUM && !leafCorrection ){ /* Fix the pointer map entries associated with the right-child of each ** sibling page. All other pointer map entries have already been taken ** care of. */ for(i=0; i<nNew; i++){ u32 key = get4byte(&apNew[i]->aData[8]); ptrmapPut(pBt, key, PTRMAP_BTREE, apNew[i]->pgno, &rc); } } assert( pParent->isInit ); TRACE(("BALANCE: finished: old=%d new=%d cells=%d\n", nOld, nNew, b.nCell)); /* Free any old pages that were not reused as new pages. */ for(i=nNew; i<nOld; i++){ freePage(apOld[i], &rc); } #if 0 if( ISAUTOVACUUM && rc==SQLITE_OK && apNew[0]->isInit ){ /* The ptrmapCheckPages() contains assert() statements that verify that ** all pointer map pages are set correctly. This is helpful while ** debugging. This is usually disabled because a corrupt database may ** cause an assert() statement to fail. */ ptrmapCheckPages(apNew, nNew); ptrmapCheckPages(&pParent, 1); } |
︙ | ︙ | |||
8671 8672 8673 8674 8675 8676 8677 | ** page that will become the new right-child of pPage. Copy the contents ** of the node stored on pRoot into the new child page. */ rc = sqlite3PagerWrite(pRoot->pDbPage); if( rc==SQLITE_OK ){ rc = allocateBtreePage(pBt,&pChild,&pgnoChild,pRoot->pgno,0); copyNodeContent(pRoot, pChild, &rc); | | | 8236 8237 8238 8239 8240 8241 8242 8243 8244 8245 8246 8247 8248 8249 8250 | ** page that will become the new right-child of pPage. Copy the contents ** of the node stored on pRoot into the new child page. */ rc = sqlite3PagerWrite(pRoot->pDbPage); if( rc==SQLITE_OK ){ rc = allocateBtreePage(pBt,&pChild,&pgnoChild,pRoot->pgno,0); copyNodeContent(pRoot, pChild, &rc); if( ISAUTOVACUUM ){ ptrmapPut(pBt, pgnoChild, PTRMAP_BTREE, pRoot->pgno, &rc); } } if( rc ){ *ppChild = 0; releasePage(pChild); return rc; |
︙ | ︙ | |||
8701 8702 8703 8704 8705 8706 8707 | zeroPage(pRoot, pChild->aData[0] & ~PTF_LEAF); put4byte(&pRoot->aData[pRoot->hdrOffset+8], pgnoChild); *ppChild = pChild; return SQLITE_OK; } | < < < < < < < < < < < < < < < < < < < < < < < < > | < < < < < < | | | | < < < | 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 | zeroPage(pRoot, pChild->aData[0] & ~PTF_LEAF); put4byte(&pRoot->aData[pRoot->hdrOffset+8], pgnoChild); *ppChild = pChild; 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: ** ** balance_quick() ** balance_deeper() ** balance_nonroot() */ static int balance(BtCursor *pCur){ int rc = SQLITE_OK; const int nMin = pCur->pBt->usableSize * 2 / 3; u8 aBalanceQuickSpace[13]; u8 *pFree = 0; VVA_ONLY( int balance_quick_called = 0 ); VVA_ONLY( int balance_deeper_called = 0 ); do { int iPage = pCur->iPage; MemPage *pPage = pCur->pPage; if( NEVER(pPage->nFree<0) && btreeComputeFreeSpace(pPage) ) break; if( iPage==0 ){ if( pPage->nOverflow ){ /* 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 if( pPage->nOverflow==0 && pPage->nFree<=nMin ){ 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); |
︙ | ︙ | |||
8910 8911 8912 8913 8914 8915 8916 | } } return SQLITE_OK; } /* ** Overwrite the cell that cursor pCur is pointing to with fresh content | | < | < < < | > | > | < < < < < < < < < < < < < < < < < < < < < < < | | > | | > > > > > > > > > > > > > > > > > | < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < | < > | 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 8554 8555 8556 8557 8558 8559 8560 8561 8562 8563 8564 8565 8566 8567 8568 8569 8570 8571 8572 8573 8574 8575 8576 8577 8578 8579 8580 8581 8582 8583 8584 8585 8586 8587 8588 8589 8590 8591 8592 8593 8594 8595 8596 8597 8598 8599 8600 8601 | } } 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 ){ 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 ){ rc = SQLITE_CORRUPT_BKPT; }else{ if( iOffset+ovflPageSize<(u32)nTotal ){ ovflPgno = get4byte(pPage->aData); }else{ ovflPageSize = nTotal - iOffset; } rc = btreeOverwriteContent(pPage, pPage->aData+4, pX, iOffset, ovflPageSize); } sqlite3PagerUnref(pPage->pDbPage); if( rc ) return rc; iOffset += ovflPageSize; }while( iOffset<nTotal ); return SQLITE_OK; } /* ** Insert a new record into the BTree. The content of the new record ** is described by the pX object. The pCur cursor is used only to ** define what table the record should be inserted into, and is left ** pointing at a random location. ** ** For a table btree (used for rowid tables), only the pX.nKey value of ** the key is used. The pX.pKey value must be NULL. The pX.nKey is the ** rowid or INTEGER PRIMARY KEY of the row. The pX.nData,pData,nZero fields ** hold the content of the row. ** ** For an index btree (used for indexes and WITHOUT ROWID tables), the ** key is an arbitrary byte sequence stored in pX.pKey,nKey. The ** pX.pData,nData,nZero fields must be zero. ** ** If the seekResult parameter is non-zero, then a successful call to ** MovetoUnpacked() to seek cursor pCur to (pKey,nKey) has already ** been performed. In other words, if seekResult!=0 then the cursor ** is currently pointing to a cell that will be adjacent to the cell ** to be inserted. If seekResult<0 then pCur points to a cell that is ** smaller then (pKey,nKey). If seekResult>0 then pCur points to a cell ** that is larger than (pKey,nKey). ** ** If seekResult==0, that means pCur is pointing at some unknown location. ** In that case, this routine must seek the cursor to the correct insertion ** point for (pKey,nKey) before doing the insertion. For index btrees, ** if pX->nMem is non-zero, then pX->aMem contains pointers to the unpacked ** key values and pX->aMem can be used instead of pX->pKey to avoid having ** to decode the key. */ int sqlite3BtreeInsert( BtCursor *pCur, /* Insert data into the table of this cursor */ const BtreePayload *pX, /* Content of the row to be inserted */ int flags, /* True if this is likely an append */ int seekResult /* Result of prior MovetoUnpacked() call */ ){ int rc; int loc = seekResult; /* -1: before desired location +1: after */ int szNew = 0; 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))==flags ); 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( (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( 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 */ 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( pCur->info.nSize!=0 ); 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. |
︙ | ︙ | |||
9118 9119 9120 9121 9122 9123 9124 | } 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. */ | | < | 8612 8613 8614 8615 8616 8617 8618 8619 8620 8621 8622 8623 8624 8625 8626 | } 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 = sqlite3BtreeMovetoUnpacked(pCur, 0, pX->nKey, flags!=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. |
︙ | ︙ | |||
9142 9143 9144 9145 9146 9147 9148 9149 | 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; | > > > | | < | > | < | < < < < | < | | < < < < < < < < < < < < < < < | | < | | < < < | < < | < < < | < < | | 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 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 8734 8735 | 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.errCode = 0; r.r1 = 0; r.r2 = 0; r.eqSeen = 0; rc = sqlite3BtreeMovetoUnpacked(pCur, &r, 0, flags!=0, &loc); }else{ rc = btreeMoveto(pCur, pX->pKey, pX->nKey, flags!=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) ); pPage = pCur->pPage; assert( pPage->intKey || pX->nKey>=0 ); assert( pPage->leaf || !pPage->intKey ); if( pPage->nFree<0 ){ 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 ); 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<pPage->nCell ); rc = sqlite3PagerWrite(pPage->pDbPage); if( rc ){ goto end_insert; } oldCell = findCell(pPage, idx); if( !pPage->leaf ){ memcpy(newCell, oldCell, 4); } rc = clearCell(pPage, oldCell, &info); if( info.nSize==szNew && info.nLocal==info.nPayload && (!ISAUTOVACUUM || 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+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 ); idx = ++pCur->ix; pCur->curFlags &= ~BTCF_ValidNKey; }else{ assert( pPage->leaf ); } insertCell(pPage, idx, newCell, szNew, 0, 0, &rc); assert( pPage->nOverflow==0 || rc==SQLITE_OK ); assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 ); /* If no error has occurred and pPage has an overflow cell, call balance() ** to redistribute the cells within the tree. Since balance() may move ** the cursor, zero the BtCursor.info.nSize and BTCF_ValidNKey ** variables. |
︙ | ︙ | |||
9314 9315 9316 9317 9318 9319 9320 | } assert( pCur->iPage<0 || pCur->pPage->nOverflow==0 ); end_insert: return rc; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | > | < | | < | < < < < < < | < | < | | | < < < < < < < < < | | | 8778 8779 8780 8781 8782 8783 8784 8785 8786 8787 8788 8789 8790 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 8847 8848 8849 8850 8851 8852 8853 8854 8855 8856 8857 8858 8859 | } 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 ** the next call to BtreeNext() or BtreePrev() moves it to the same row ** as it would have been on if the call to BtreeDelete() had been omitted. ** ** The BTREE_AUXDELETE bit of flags indicates that is one of several deletes ** associated with a single table entry and its indexes. Only one of those ** deletes is considered the "primary" delete. The primary delete occurs ** on a cursor that is not a BTREE_FORDELETE cursor. All but one delete ** operation on non-FORDELETE cursors is tagged with the AUXDELETE flag. ** The BTREE_AUXDELETE bit is a hint that is not used by this implementation, ** but which might be used by alternative storage engines. */ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ Btree *p = pCur->pBtree; BtShared *pBt = p->pBt; int rc; /* Return code */ MemPage *pPage; /* Page to delete cell from */ unsigned char *pCell; /* Pointer to cell to delete */ int iCellIdx; /* Index of cell to delete */ int iCellDepth; /* Depth of node containing pCell */ CellInfo info; /* Size of the cell being deleted */ int bSkipnext = 0; /* Leaf cursor in SKIPNEXT state */ u8 bPreserve = flags & BTREE_SAVEPOSITION; /* Keep cursor valid */ 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); if( rc ) return rc; } assert( 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. ** ** Or, if the current delete will not cause a rebalance, then the cursor ** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately ** before or after the deleted entry. In this case set bSkipnext to true. */ if( bPreserve ){ if( !pPage->leaf || (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3) || pPage->nCell==1 /* See dbfuzz001.test for a test case */ ){ /* A b-tree rebalance will be required after deleting this entry. ** Save the cursor key. */ rc = saveCursorKey(pCur); if( rc ) return rc; }else{ bSkipnext = 1; } } /* If the page containing the entry to delete is not a leaf page, move ** the cursor to the largest entry in the tree that is smaller than ** the entry being deleted. This cell will replace the cell being deleted ** from the internal node. The 'previous' entry is used for this instead |
︙ | ︙ | |||
9537 9538 9539 9540 9541 9542 9543 | 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. */ | | | | 8871 8872 8873 8874 8875 8876 8877 8878 8879 8880 8881 8882 8883 8884 8885 8886 8887 8888 8889 8890 8891 8892 8893 8894 | 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 ){ 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; rc = clearCell(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 |
︙ | ︙ | |||
9578 9579 9580 9581 9582 9583 9584 | if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT; nCell = pLeaf->xCellSize(pLeaf, pCell); assert( MX_CELL_SIZE(pBt) >= nCell ); pTmp = pBt->pTmpSpace; assert( pTmp!=0 ); rc = sqlite3PagerWrite(pLeaf->pDbPage); if( rc==SQLITE_OK ){ | | < < < < < < < | < | | | 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 | if( pCell<&pLeaf->aData[4] ) return SQLITE_CORRUPT_BKPT; nCell = pLeaf->xCellSize(pLeaf, pCell); assert( MX_CELL_SIZE(pBt) >= nCell ); pTmp = pBt->pTmpSpace; assert( pTmp!=0 ); rc = sqlite3PagerWrite(pLeaf->pDbPage); if( rc==SQLITE_OK ){ insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc); } dropCell(pLeaf, pLeaf->nCell-1, nCell, &rc); if( rc ) return rc; } /* Balance the tree. If the entry deleted was located on a leaf page, ** then the cursor still points to that page. In this case the first ** call to balance() repairs the tree, and the if(...) condition is ** never true. ** ** Otherwise, if the entry deleted was on an internal node page, then ** pCur is pointing to the leaf page from which a cell was removed to ** replace the cell deleted from the internal node. This is slightly ** tricky as the leaf node may be underfull, and the internal node may ** be either under or overfull. In this case run the balancing algorithm ** on the leaf node first. If the balance proceeds far enough up the ** tree that we can be sure that any problem in the internal node has ** been corrected, so be it. Otherwise, after balancing the leaf node, ** walk the cursor up the tree to the internal node and balance it as ** well. */ rc = balance(pCur); if( rc==SQLITE_OK && pCur->iPage>iCellDepth ){ releasePageNotNull(pCur->pPage); pCur->iPage--; while( pCur->iPage>iCellDepth ){ releasePage(pCur->apPage[pCur->iPage--]); } pCur->pPage = pCur->apPage[pCur->iPage]; rc = balance(pCur); } if( rc==SQLITE_OK ){ if( bSkipnext ){ assert( bPreserve && (pCur->iPage==iCellDepth || CORRUPT_DB) ); assert( pPage==pCur->pPage || CORRUPT_DB ); assert( (pPage->nCell>0 || CORRUPT_DB) && iCellIdx<=pPage->nCell ); pCur->eState = CURSOR_SKIPNEXT; if( iCellIdx>=pPage->nCell ){ pCur->skipNext = -1; pCur->ix = pPage->nCell-1; }else{ |
︙ | ︙ | |||
9653 9654 9655 9656 9657 9658 9659 | ** 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 */ | | | 8979 8980 8981 8982 8983 8984 8985 8986 8987 8988 8989 8990 8991 8992 8993 | ** 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, int *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) ); |
︙ | ︙ | |||
9686 9687 9688 9689 9690 9691 9692 | 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); | < < < | > | 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 | 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++; } assert( pgnoRoot>=3 || CORRUPT_DB ); testcase( 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 ){ |
︙ | ︙ | |||
9795 9796 9797 9798 9799 9800 9801 | 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 ); | | | | < < | > | < < | > > > | | | < | < | 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 | 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 = (int)pgnoRoot; return SQLITE_OK; } int sqlite3BtreeCreateTable(Btree *p, int *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 */ int *pnChange /* Add number of Cells freed to this counter */ ){ 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; if( pPage->bBusy ){ rc = SQLITE_CORRUPT_BKPT; goto cleardatabasepage_out; } pPage->bBusy = 1; hdr = pPage->hdrOffset; for(i=0; i<pPage->nCell; i++){ pCell = findCell(pPage, i); if( !pPage->leaf ){ rc = clearDatabasePage(pBt, get4byte(pCell), 1, pnChange); if( rc ) goto cleardatabasepage_out; } rc = clearCell(pPage, pCell, &info); if( rc ) goto cleardatabasepage_out; } if( !pPage->leaf ){ rc = clearDatabasePage(pBt, get4byte(&pPage->aData[hdr+8]), 1, pnChange); if( rc ) goto cleardatabasepage_out; }else if( pnChange ){ assert( pPage->intKey || CORRUPT_DB ); 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: pPage->bBusy = 0; 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 table iTable must be an intkey table. The ** integer value pointed to by pnChange is incremented by the number of ** entries in the table. */ int sqlite3BtreeClearTable(Btree *p, int iTable, int *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). */ invalidateIncrblobCursors(p, (Pgno)iTable, 0, 1); rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange); } sqlite3BtreeLeave(p); return rc; } /* |
︙ | ︙ | |||
9939 9940 9941 9942 9943 9944 9945 9946 | assert( sqlite3BtreeHoldsMutex(p) ); assert( p->inTrans==TRANS_WRITE ); assert( iTable>=2 ); if( iTable>btreePagecount(pBt) ){ return SQLITE_CORRUPT_BKPT; } rc = sqlite3BtreeClearTable(p, iTable, 0); | > > | < < | 9261 9262 9263 9264 9265 9266 9267 9268 9269 9270 9271 9272 9273 9274 9275 9276 9277 9278 | assert( sqlite3BtreeHoldsMutex(p) ); assert( p->inTrans==TRANS_WRITE ); assert( iTable>=2 ); if( iTable>btreePagecount(pBt) ){ return SQLITE_CORRUPT_BKPT; } rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0); if( rc ) return rc; rc = sqlite3BtreeClearTable(p, iTable, 0); if( rc ){ releasePage(pPage); return rc; } *piMoved = 0; #ifdef SQLITE_OMIT_AUTOVACUUM |
︙ | ︙ | |||
10046 10047 10048 10049 10050 10051 10052 | ** read it from this routine. */ void sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){ BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); assert( p->inTrans>TRANS_NONE ); | | | | 9368 9369 9370 9371 9372 9373 9374 9375 9376 9377 9378 9379 9380 9381 9382 9383 9384 9385 9386 9387 | ** 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, MASTER_ROOT, READ_LOCK) ); assert( pBt->pPage1 ); assert( idx>=0 && idx<=15 ); if( idx==BTREE_DATA_VERSION ){ *pMeta = sqlite3PagerDataVersion(pBt->pPager) + p->iDataVersion; }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 |
︙ | ︙ | |||
10095 10096 10097 10098 10099 10100 10101 10102 10103 10104 10105 10106 10107 10108 10109 | } #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. */ | > | | | 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 | } #endif } sqlite3BtreeLeave(p); return rc; } #ifndef SQLITE_OMIT_BTREECOUNT /* ** 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(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 ){ 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. */ |
︙ | ︙ | |||
10167 10168 10169 10170 10171 10172 10173 10174 10175 10176 10177 10178 10179 10180 10181 10182 10183 | 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; } #ifndef SQLITE_OMIT_INTEGRITY_CHECK | > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 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 | rc = moveToChild(pCur, get4byte(findCell(pPage, iIdx))); } } /* An error has occurred. Return an error code. */ return rc; } #endif /* ** Return the pager associated with a BTree. This routine is used for ** testing and debugging only. */ Pager *sqlite3BtreePager(Btree *p){ return p->pBt->pPager; } #ifndef SQLITE_OMIT_INTEGRITY_CHECK /* ** Append a message to the error message string. */ static void checkAppendMsg( IntegrityCk *pCheck, const char *zFormat, ... ){ va_list ap; if( !pCheck->mxErr ) return; pCheck->mxErr--; pCheck->nErr++; va_start(ap, zFormat); if( pCheck->errMsg.nChar ){ sqlite3_str_append(&pCheck->errMsg, "\n", 1); } 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->mallocFailed = 1; } } #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ #ifndef SQLITE_OMIT_INTEGRITY_CHECK /* |
︙ | ︙ | |||
10299 10300 10301 10302 10303 10304 10305 | ){ int rc; u8 ePtrmapType; Pgno iPtrmapParent; rc = ptrmapGet(pCheck->pBt, iChild, &ePtrmapType, &iPtrmapParent); if( rc!=SQLITE_OK ){ | | | | 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 | ){ 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->mallocFailed = 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 */ int 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; |
︙ | ︙ | |||
10406 10407 10408 10409 10410 10411 10412 | ** ** This heap is used for cell overlap and coverage testing. Each u32 ** entry represents the span of a cell or freeblock on a btree page. ** The upper 16 bits are the index of the first byte of a range and the ** lower 16 bits are the index of the last byte of that range. */ static void btreeHeapInsert(u32 *aHeap, u32 x){ | < < | | 9694 9695 9696 9697 9698 9699 9700 9701 9702 9703 9704 9705 9706 9707 9708 | ** ** This heap is used for cell overlap and coverage testing. Each u32 ** entry represents the span of a cell or freeblock on a btree page. ** The upper 16 bits are the index of the first byte of a range and the ** lower 16 bits are the index of the last byte of that range. */ static void btreeHeapInsert(u32 *aHeap, u32 x){ u32 j, i = ++aHeap[0]; aHeap[i] = x; while( (j = i/2)>0 && aHeap[j]>aHeap[i] ){ x = aHeap[j]; aHeap[j] = aHeap[i]; aHeap[i] = x; i = j; } |
︙ | ︙ | |||
10453 10454 10455 10456 10457 10458 10459 | ** 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 */ | | | 9739 9740 9741 9742 9743 9744 9745 9746 9747 9748 9749 9750 9751 9752 9753 | ** 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 */ int 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 */ |
︙ | ︙ | |||
10485 10486 10487 10488 10489 10490 10491 | const char *saved_zPfx = pCheck->zPfx; int saved_v1 = pCheck->v1; int saved_v2 = pCheck->v2; u8 savedIsInit = 0; /* Check that the page exists */ | < < | | | 9771 9772 9773 9774 9775 9776 9777 9778 9779 9780 9781 9782 9783 9784 9785 9786 9787 9788 9789 9790 9791 | const char *saved_zPfx = pCheck->zPfx; int saved_v1 = pCheck->v1; int saved_v2 = pCheck->v2; u8 savedIsInit = 0; /* 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 %d: "; pCheck->v1 = iPage; if( (rc = btreeGetPage(pBt, (Pgno)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. */ |
︙ | ︙ | |||
10518 10519 10520 10521 10522 10523 10524 | checkAppendMsg(pCheck, "free space corruption", rc); goto end_of_check; } data = pPage->aData; hdr = pPage->hdrOffset; /* Set up for cell analysis */ | | | | 9802 9803 9804 9805 9806 9807 9808 9809 9810 9811 9812 9813 9814 9815 9816 9817 9818 9819 9820 9821 9822 9823 9824 9825 9826 9827 9828 9829 9830 9831 9832 9833 9834 9835 9836 | 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 %d 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 %d 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 |
︙ | ︙ | |||
10679 10680 10681 10682 10683 10684 10685 | ** 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, | | | | 9963 9964 9965 9966 9967 9968 9969 9970 9971 9972 9973 9974 9975 9976 9977 9978 9979 9980 9981 9982 9983 9984 9985 9986 9987 9988 9989 9990 9991 9992 | ** 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 %d", 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 %d", nFrag, data[hdr+7], iPage); } } end_of_check: if( !doCoverageCheck ) pPage->isInit = savedIsInit; releasePage(pPage); |
︙ | ︙ | |||
10722 10723 10724 10725 10726 10727 10728 | ** 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. | < < < < < < < < < | < | | < < < < < < < < < < < < < > > > > > > > | | < | | | | | < < | | | | | | | | | | | | | | | < | < | | | | | | | | | | | | | | | < < | < < | > > | | 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 10121 10122 10123 10124 10125 10126 10127 10128 10129 10130 10131 10132 10133 10134 10135 10136 10137 10138 10139 10140 10141 10142 10143 10144 10145 10146 10147 | ** 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 */ int *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]; VVA_ONLY( int nRef ); sqlite3BtreeEnter(p); assert( p->inTrans>TRANS_NONE && pBt->inTransaction>TRANS_NONE ); VVA_ONLY( nRef = sqlite3PagerRefcount(pBt->pPager) ); assert( nRef>=0 ); sCheck.pBt = pBt; sCheck.pPager = pBt->pPager; sCheck.nPage = btreePagecount(sCheck.pBt); sCheck.mxErr = mxErr; sCheck.nErr = 0; sCheck.mallocFailed = 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.mallocFailed = 1; goto integrity_ck_cleanup; } sCheck.heap = (u32*)sqlite3PageMalloc( pBt->pageSize ); if( sCheck.heap==0 ){ sCheck.mallocFailed = 1; goto integrity_ck_cleanup; } i = PENDING_BYTE_PAGE(pBt); if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i); /* Check the integrity of the freelist */ 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( pBt->autoVacuum ){ int mx = 0; int 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 ){ checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0); } #endif checkTreePage(&sCheck, aRoot[i], ¬Used, LARGEST_INT64); } pBt->db->flags = savedDbFlags; /* Make sure every page in the file is referenced */ for(i=1; 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.mallocFailed ){ 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) ); sqlite3BtreeLeave(p); return sqlite3StrAccumFinish(&sCheck.errMsg); } #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ /* ** Return the full pathname of the underlying database file. Return ** an empty string if the database is in-memory or a TEMP database. ** |
︙ | ︙ | |||
10902 10903 10904 10905 10906 10907 10908 | */ const char *sqlite3BtreeGetJournalname(Btree *p){ assert( p->pBt->pPager!=0 ); return sqlite3PagerJournalname(p->pBt->pPager); } /* | | < | | | 10163 10164 10165 10166 10167 10168 10169 10170 10171 10172 10173 10174 10175 10176 10177 10178 10179 10180 10181 | */ const char *sqlite3BtreeGetJournalname(Btree *p){ assert( p->pBt->pPager!=0 ); return sqlite3PagerJournalname(p->pBt->pPager); } /* ** Return non-zero if a transaction is active. */ int sqlite3BtreeIsInTrans(Btree *p){ assert( p==0 || sqlite3_mutex_held(p->db->mutex) ); return (p && (p->inTrans==TRANS_WRITE)); } #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 |
︙ | ︙ | |||
10936 10937 10938 10939 10940 10941 10942 | sqlite3BtreeLeave(p); } return rc; } #endif /* | | > > > > > > | 10196 10197 10198 10199 10200 10201 10202 10203 10204 10205 10206 10207 10208 10209 10210 10211 10212 10213 10214 10215 10216 10217 | sqlite3BtreeLeave(p); } return rc; } #endif /* ** Return non-zero if a read (or write) transaction is active. */ int sqlite3BtreeIsInReadTrans(Btree *p){ assert( p ); assert( sqlite3_mutex_held(p->db->mutex) ); return p->inTrans!=TRANS_NONE; } int sqlite3BtreeIsInBackup(Btree *p){ assert( p ); assert( sqlite3_mutex_held(p->db->mutex) ); return p->nBackup!=0; } /* |
︙ | ︙ | |||
10978 10979 10980 10981 10982 10983 10984 | 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 | | | | 10244 10245 10246 10247 10248 10249 10250 10251 10252 10253 10254 10255 10256 10257 10258 10259 10260 10261 10262 10263 10264 | 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_master table. Otherwise SQLITE_OK. */ int sqlite3BtreeSchemaLocked(Btree *p){ int rc; assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3BtreeEnter(p); rc = querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK); assert( rc==SQLITE_OK || rc==SQLITE_LOCKED_SHAREDCACHE ); sqlite3BtreeLeave(p); return rc; } #ifndef SQLITE_OMIT_SHARED_CACHE |
︙ | ︙ | |||
11137 11138 11139 11140 11141 11142 11143 | } /* ** Return the size of the header added to each page by this module. */ int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); } | < < < < < < < < < < < | 10403 10404 10405 10406 10407 10408 10409 10410 10411 10412 10413 10414 10415 10416 | } /* ** Return the size of the header added to each page by this module. */ int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); } #if !defined(SQLITE_OMIT_SHARED_CACHE) /* ** Return true if the Btree passed as the only argument is sharable. */ int sqlite3BtreeSharable(Btree *p){ return p->sharable; } |
︙ | ︙ |
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 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | 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*); int sqlite3BtreeMaxPageCount(Btree*,int); u32 sqlite3BtreeLastPage(Btree*); int sqlite3BtreeSecureDelete(Btree*,int); int sqlite3BtreeGetOptimalReserve(Btree*); int sqlite3BtreeGetReserveNoMutex(Btree *p); int sqlite3BtreeSetAutoVacuum(Btree *, int); int sqlite3BtreeGetAutoVacuum(Btree *); int sqlite3BtreeBeginTrans(Btree*,int,int*); int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster); int sqlite3BtreeCommitPhaseTwo(Btree*, int); int sqlite3BtreeCommit(Btree*); int sqlite3BtreeRollback(Btree*,int,int); int sqlite3BtreeBeginStmt(Btree*,int); int sqlite3BtreeCreateTable(Btree*, int*, int flags); int sqlite3BtreeIsInTrans(Btree*); int sqlite3BtreeIsInReadTrans(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 int sqlite3BtreeSavepoint(Btree *, int, int); const char *sqlite3BtreeGetFilename(Btree *); const char *sqlite3BtreeGetJournalname(Btree *); int sqlite3BtreeCopyFile(Btree *, Btree *); int sqlite3BtreeIncrVacuum(Btree *); /* The flags parameter to sqlite3BtreeCreateTable can be the bitwise OR ** of the flags shown below. ** ** Every SQLite table must have either BTREE_INTKEY or BTREE_BLOBKEY set. ** With BTREE_INTKEY, the table key is a 64-bit integer and arbitrary data ** is stored in the leaves. (BTREE_INTKEY is used for SQL tables.) With ** BTREE_BLOBKEY, the key is an arbitrary BLOB and no content is stored ** 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, int*); 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); |
︙ | ︙ | |||
179 180 181 182 183 184 185 | ** ** The design of the _RANGE hint is aid b-tree implementations that try ** to prefetch content from remote machines - to provide those ** implementations with limits on what needs to be prefetched and thereby ** reduce network bandwidth. ** ** Note that BTREE_HINT_FLAGS with BTREE_BULKLOAD is the only hint used by | | | 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | ** ** The design of the _RANGE hint is aid b-tree implementations that try ** to prefetch content from remote machines - to provide those ** implementations with limits on what needs to be prefetched and thereby ** reduce network bandwidth. ** ** Note that BTREE_HINT_FLAGS with BTREE_BULKLOAD is the only hint used by ** standard SQLite. The other hints are provided for extentions that use ** the SQLite parser and code generator but substitute their own storage ** engine. */ #define BTREE_HINT_RANGE 0 /* Range constraints on queries */ /* ** Values that may be OR'd together to form the argument to the |
︙ | ︙ | |||
229 230 231 232 233 234 235 | ** 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 */ | | | > < < < < < < | 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 | ** 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 */ int 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 sqlite3BtreeMovetoUnpacked( BtCursor*, UnpackedRecord *pUnKey, i64 intKey, int bias, 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 */ /* 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 |
︙ | ︙ | |||
315 316 317 318 319 320 321 | 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*); | < < | < < < < < < < < < < < < < < > | > < < < < | 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 | 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*); #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(Btree*, int *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); #ifndef NDEBUG int sqlite3BtreeCursorIsValid(BtCursor*); #endif int sqlite3BtreeCursorIsValidNN(BtCursor*); #ifndef SQLITE_OMIT_BTREECOUNT int sqlite3BtreeCount(BtCursor *, i64 *); #endif #ifdef SQLITE_TEST int sqlite3BtreeCursorInfo(BtCursor*, int*, int); void sqlite3BtreeCursorList(Btree*); #endif #ifndef SQLITE_OMIT_WAL int sqlite3BtreeCheckpoint(Btree*, int, int *, int *); #endif /* ** 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 void sqlite3BtreeEnter(Btree*); |
︙ | ︙ |
Changes to src/btreeInt.h.
︙ | ︙ | |||
268 269 270 271 272 273 274 275 276 277 278 279 280 281 | ** "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 */ /* 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 */ | > | 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 | ** "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 bBusy; /* Prevent endless loops on corrupt database files */ 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 */ /* 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 */ |
︙ | ︙ | |||
289 290 291 292 293 294 295 | 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 */ | | < < | 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 | 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 */ u8 *aDataEnd; /* One byte past the end of usable data */ u8 *aCellIdx; /* The cell index area */ u8 *aDataOfst; /* Same as aData for leaves. aData+4 for interior */ DbPage *pDbPage; /* Pager page handle */ u16 (*xCellSize)(MemPage*,u8*); /* cellSizePtr method */ void (*xParseCell)(MemPage*,u8*,CellInfo*); /* btreeParseCell method */ }; |
︙ | ︙ | |||
347 348 349 350 351 352 353 | 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 */ | | < < < < < < < < < < < < < < < < < | | 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 | 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 iDataVersion; /* Combines with pBt->pPager->iDataVersion */ Btree *pNext; /* List of other sharable Btrees from the same db */ Btree *pPrev; /* Back pointer of the same list */ #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. */ #define TRANS_NONE 0 #define TRANS_READ 1 #define TRANS_WRITE 2 /* ** 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_MASTER 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 |
︙ | ︙ | |||
431 432 433 434 435 436 437 | #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 */ | > | > < | 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 | #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 */ #ifdef SQLITE_HAS_CODEC u8 optimalReserve; /* Desired amount of reserved space per page */ #endif 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 */ int nTransaction; /* Number of open transactions (read + write) */ u32 nPage; /* Number of pages in the database */ void *pSchema; /* Pointer to space allocated by sqlite3BtreeSchema() */ void (*xFreeSchema)(void*); /* Destructor for BtShared.pSchema */ sqlite3_mutex *mutex; /* Non-recursive mutex required to access this object */ Bitvec *pHasContent; /* Set of pages moved to free-list this transaction */ #ifndef SQLITE_OMIT_SHARED_CACHE int nRef; /* Number of references to this structure */ BtShared *pNext; /* Next on a list of sharable BtShared structs */ 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 */ }; /* ** 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 */ |
︙ | ︙ | |||
555 556 557 558 559 560 561 | */ #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 */ | < | 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 |
︙ | ︙ | |||
596 597 598 599 600 601 602 | #define CURSOR_SKIPNEXT 2 #define CURSOR_REQUIRESEEK 3 #define CURSOR_FAULT 4 /* ** The database page the PENDING_BYTE occupies. This page is never used. */ | | | 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 | #define CURSOR_SKIPNEXT 2 #define CURSOR_REQUIRESEEK 3 #define CURSOR_FAULT 4 /* ** The database page the PENDING_BYTE occupies. This page is never used. */ # define PENDING_BYTE_PAGE(pBt) PAGER_MJ_PGNO(pBt) /* ** These macros define the location of the pointer-map entry for a ** database page. The first argument to each is the number of usable ** bytes on each page of the database (often 1024). The second is the ** page number to look up in the pointer map. ** |
︙ | ︙ | |||
670 671 672 673 674 675 676 | ** The ISAUTOVACUUM macro is used within balance_nonroot() to determine ** if the database supports auto-vacuum or not. Because it is used ** within an expression that is an argument to another macro ** (sqliteMallocRaw), it is not possible to use conditional compilation. ** So, this macro is defined instead. */ #ifndef SQLITE_OMIT_AUTOVACUUM | | | | | | < < | < | 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 | ** The ISAUTOVACUUM macro is used within balance_nonroot() to determine ** if the database supports auto-vacuum or not. Because it is used ** within an expression that is an argument to another macro ** (sqliteMallocRaw), it is not possible to use conditional compilation. ** So, this macro is defined instead. */ #ifndef SQLITE_OMIT_AUTOVACUUM #define ISAUTOVACUUM (pBt->autoVacuum) #else #define ISAUTOVACUUM 0 #endif /* ** This structure is passed around through all the sanity checking routines ** in order to keep track of some global state information. ** ** The aRef[] array is allocated so that there is 1 bit for each page in ** the database. As the integrity-check proceeds, for each page used in ** the database the corresponding bit is set. This allows integrity-check to ** detect pages that are used twice and orphaned pages (both of which ** indicate corruption). */ typedef struct IntegrityCk IntegrityCk; 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 mallocFailed; /* A memory allocation error has occurred */ const char *zPfx; /* Error message prefix */ int v1, v2; /* Values for up to two %d fields in zPfx */ StrAccum errMsg; /* Accumulate the error message text here */ u32 *heap; /* Min-heap used for analyzing cell coverage */ }; /* ** 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 70 | #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 */ int 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(). */ void sqlite3TableLock( Parse *pParse, /* Parsing context */ int iDb, /* Index of the database containing the table to lock */ int 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 = sqlite3ParseToplevel(pParse); int i; int nBytes; TableLock *p; assert( iDb>=0 ); if( iDb==1 ) return; if( !sqlite3BtreeSharable(pParse->db->aDb[iDb].pBt) ) return; for(i=0; i<pToplevel->nTableLock; i++){ p = &pToplevel->aTableLock[i]; if( p->iDb==iDb && p->iTab==iTab ){ p->isWriteLock = (p->isWriteLock || isWriteLock); return; } } |
︙ | ︙ | |||
78 79 80 81 82 83 84 | p->isWriteLock = isWriteLock; p->zLockName = zName; }else{ pToplevel->nTableLock = 0; sqlite3OomFault(pToplevel->db); } } | < < < < < < < < < < < | > > | | 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 | 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; Vdbe *pVdbe; pVdbe = sqlite3GetVdbe(pParse); assert( pVdbe!=0 ); /* sqlite3GetVdbe cannot fail: VDBE already allocated */ 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); } |
︙ | ︙ | |||
136 137 138 139 140 141 142 | ** ** Note that if an error occurred, it might be the case that ** no VDBE code was generated. */ void sqlite3FinishCoding(Parse *pParse){ sqlite3 *db; Vdbe *v; | < < | | < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < > > > > | | | < < | | | | | | | | | | | | | | < > | | | | | | | | | | | | | | < < < < < < | | | | < | | | | < < | | | < < | < < < | | < | | | > | | < > < < < | | | 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 | ** ** Note that if an error occurred, it might be the case that ** no VDBE code was generated. */ void sqlite3FinishCoding(Parse *pParse){ sqlite3 *db; Vdbe *v; assert( pParse->pToplevel==0 ); db = pParse->db; if( pParse->nested ) return; if( db->mallocFailed || pParse->nErr ){ if( pParse->rc==SQLITE_OK ) pParse->rc = SQLITE_ERROR; return; } /* Begin by generating some termination code at the end of the ** vdbe program */ v = sqlite3GetVdbe(pParse); assert( !pParse->isMultiWrite || sqlite3VdbeAssertMayAbort(v, pParse->mayAbort)); if( v ){ 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"); pParse->rc = SQLITE_AUTH_USER; return; } } #endif /* The cookie mask contains one bit for each database file open. ** (Bit 0 is for main, bit 1 is for temp, and so forth.) Bits are ** set for each database that is used. Generate code to start a ** transaction on each used database and to verify the schema cookie ** on each used database. */ if( db->mallocFailed==0 && (DbMaskNonZero(pParse->cookieMask) || pParse->pConstExpr) ){ int iDb, i; assert( sqlite3VdbeGetOp(v, 0)->opcode==OP_Init ); sqlite3VdbeJumpHere(v, 0); for(iDb=0; iDb<db->nDb; iDb++){ Schema *pSchema; if( DbMaskTest(pParse->cookieMask, iDb)==0 ) continue; sqlite3VdbeUsesBtree(v, iDb); pSchema = db->aDb[iDb].pSchema; sqlite3VdbeAddOp4Int(v, OP_Transaction, /* Opcode */ iDb, /* P1 */ DbMaskTest(pParse->writeMask,iDb), /* P2 */ pSchema->schema_cookie, /* P3 */ pSchema->iGeneration /* P4 */ ); if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1); VdbeComment((v, "usesStmtJournal=%d", pParse->mayAbort && pParse->isMultiWrite)); } #ifndef SQLITE_OMIT_VIRTUALTABLE for(i=0; i<pParse->nVtabLock; i++){ char *vtab = (char *)sqlite3GetVTable(db, pParse->apVtabLock[i]); sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB); } pParse->nVtabLock = 0; #endif /* Once all the cookies have been verified and transactions opened, ** obtain the required table-locks. This is a no-op unless the ** shared-cache feature is enabled. */ codeTableLocks(pParse); /* Initialize any AUTOINCREMENT data structures required. */ sqlite3AutoincrementBegin(pParse); /* Code constant expressions that where factored out of inner loops */ if( pParse->pConstExpr ){ ExprList *pEL = pParse->pConstExpr; pParse->okConstFactor = 0; for(i=0; i<pEL->nExpr; i++){ sqlite3ExprCode(pParse, pEL->a[i].pExpr, pEL->a[i].u.iConstExprReg); } } /* 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. When the parser is run recursively ** this way, the final OP_Halt is not appended and other initialization ** and finalization steps are omitted because those are handling by the ** outermost parser. ** ** Not everything is nestable. This facility is designed to permit ** INSERT, UPDATE, and DELETE operations against SQLITE_MASTER. Use ** care if you decide to try to use this routine for some other purposes. */ void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ va_list ap; char *zSql; char *zErrMsg = 0; sqlite3 *db = pParse->db; 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); sqlite3RunParser(pParse, zSql, &zErrMsg); sqlite3DbFree(db, zErrMsg); sqlite3DbFree(db, zSql); memcpy(PARSE_TAIL(pParse), saveBuf, PARSE_TAIL_SZ); pParse->nested--; } #if SQLITE_USER_AUTHENTICATION /* |
︙ | ︙ | |||
362 363 364 365 366 367 368 | #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 | | | > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | < < < < < < | > > > > > | < | | 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 | #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 while(1){ for(i=OMIT_TEMPDB; i<db->nDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ if( zDatabase==0 || sqlite3StrICmp(zDatabase, db->aDb[j].zDbSName)==0 ){ assert( sqlite3SchemaMutexHeld(db, j, 0) ); p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName); if( p ) return p; } } /* Not found. If the name we were looking for was temp.sqlite_master ** then change the name to sqlite_temp_master and try again. */ if( sqlite3StrICmp(zName, MASTER_NAME)!=0 ) break; if( sqlite3_stricmp(zDatabase, db->aDb[1].zDbSName)!=0 ) break; zName = TEMP_MASTER_NAME; } return 0; } /* ** 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. |
︙ | ︙ | |||
450 451 452 453 454 455 456 | 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. */ | | < | < < | < < < < < < < < < < < < < < < < | 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 | 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 ){ 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) ){ 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); } } 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, struct SrcList_item *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); } /* ** 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. ** ** If zDatabase is 0, all databases are searched for the |
︙ | ︙ | |||
543 544 545 546 547 548 549 | 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 ); | | | | 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 | 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 && sqlite3StrICmp(zDb, db->aDb[j].zDbSName) ) 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_STAT3_OR_STAT4 sqlite3_free(p->aiRowEst); #endif sqlite3DbFree(db, p); } /* ** For the index called zIdxName which is found in the database iDb, |
︙ | ︙ | |||
686 687 688 689 690 691 692 693 | /* ** This routine is called when a commit occurs. */ void sqlite3CommitInternalChanges(sqlite3 *db){ db->mDbFlags &= ~DBFLAG_SchemaChange; } /* | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < | < | < < < < < | 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 | /* ** 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++){ sqlite3DbFree(db, pCol->zName); sqlite3ExprDelete(db, pCol->pDflt); sqlite3DbFree(db, pCol->zColl); } sqlite3DbFree(db, pTable->aCol); } } /* ** Remove the memory data structures associated with the given ** Table. No changes are made to disk by this routine. ** |
︙ | ︙ | |||
812 813 814 815 816 817 818 | ** 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 | | | < < < < < | | | | < < < < < < < < < < > > > > < | | 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 | ** 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. */ int nLookaside = 0; if( db && (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); } /* Delete any foreign keys attached to this table. */ sqlite3FkDelete(db, pTable); /* Delete the Table structure itself. */ sqlite3DeleteColumnNames(db, pTable); sqlite3DbFree(db, pTable->zName); sqlite3DbFree(db, pTable->zColAff); sqlite3SelectDelete(db, pTable->pSelect); sqlite3ExprListDelete(db, pTable->pCheck); #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3VtabClear(db, pTable); #endif 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. */ if( !pTable ) return; if( ((!db || db->pnBytesFreed==0) && (--pTable->nTabRef)>0) ) return; deleteTable(db, pTable); } /* ** Unlink the given table from the hash tables and the delete the ** table structure with all its indices and foreign keys. |
︙ | ︙ | |||
906 907 908 909 910 911 912 | ** 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. */ | | | | | | | | 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 | ** 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, Token *pName){ char *zName; if( pName ){ zName = sqlite3DbStrNDup(db, (char*)pName->z, pName->n); sqlite3Dequote(zName); }else{ zName = 0; } return zName; } /* ** Open the sqlite_master table stored in database number iDb for ** writing. The table is opened using cursor 0. */ void sqlite3OpenMasterTable(Parse *p, int iDb){ Vdbe *v = sqlite3GetVdbe(p); sqlite3TableLock(p, iDb, MASTER_ROOT, 1, MASTER_NAME); sqlite3VdbeAddOp4Int(v, OP_OpenWrite, 0, MASTER_ROOT, iDb, 5); if( p->nTab==0 ){ p->nTab = 1; } } /* ** Parameter zName points to a nul-terminated buffer containing the name |
︙ | ︙ | |||
1003 1004 1005 1006 1007 1008 1009 | *pUnqual = pName2; iDb = sqlite3FindDb(db, pName1); if( iDb<0 ){ sqlite3ErrorMsg(pParse, "unknown database %T", pName1); return -1; } }else{ | | | 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 | *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_RENAME_OBJECT || (db->mDbFlags & DBFLAG_Vacuum)!=0); iDb = db->init.iDb; *pUnqual = pName1; } return iDb; } |
︙ | ︙ | |||
1032 1033 1034 1035 1036 1037 1038 | /* ** 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. ** | | | < < < | 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 | /* ** 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_master 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 ){ /* 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]) |
︙ | ︙ | |||
1081 1082 1083 1084 1085 1086 1087 | Index *sqlite3PrimaryKeyIndex(Table *pTab){ Index *p; for(p=pTab->pIndex; p && !IsPrimaryKeyIndex(p); p=p->pNext){} return p; } /* | < < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | Index *sqlite3PrimaryKeyIndex(Table *pTab){ Index *p; for(p=pTab->pIndex; p && !IsPrimaryKeyIndex(p); p=p->pNext){} return p; } /* ** Return the column of index pIdx that corresponds to table ** column iCol. Return -1 if not found. */ i16 sqlite3ColumnOfIndex(Index *pIdx, i16 iCol){ int i; for(i=0; i<pIdx->nColumn; i++){ if( iCol==pIdx->aiColumn[i] ) return i; } return -1; } /* ** 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 ** file instead of in the main database file. This is normally the case |
︙ | ︙ | |||
1222 1223 1224 1225 1226 1227 1228 | 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 ){ | | | 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 | 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_master or sqlite_temp_master 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; |
︙ | ︙ | |||
1284 1285 1286 1287 1288 1289 1290 | char *zDb = db->aDb[iDb].zDbSName; if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto begin_table_error; } pTable = sqlite3FindTable(db, zName, zDb); if( pTable ){ if( !noErr ){ | | < < | 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 | char *zDb = db->aDb[iDb].zDbSName; if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto begin_table_error; } 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; } |
︙ | ︙ | |||
1317 1318 1319 1320 1321 1322 1323 1324 1325 | #ifdef SQLITE_DEFAULT_ROWEST 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 | > > > > > > > > > > > | | 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 | #ifdef SQLITE_DEFAULT_ROWEST pTable->nRowLogEst = sqlite3LogEst(SQLITE_DEFAULT_ROWEST); #else pTable->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); #endif assert( pParse->pNewTable==0 ); pParse->pNewTable = pTable; /* 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. */ #ifndef SQLITE_OMIT_AUTOINCREMENT if( !pParse->nested && strcmp(zName, "sqlite_sequence")==0 ){ assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); pTable->pSchema->pSeqTab = pTable; } #endif /* Begin generating the code that will insert the table record into ** the SQLITE_MASTER 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 ){ |
︙ | ︙ | |||
1355 1356 1357 1358 1359 1360 1361 | 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); | | < | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | < | > > | | | | | | > | < | | < | < | | < | | < | 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 | 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_master 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 { pParse->addrCrTab = sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, reg2, BTREE_INTKEY); } sqlite3OpenMasterTable(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: 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->zName, "__hidden__", 10)==0 ){ pCol->colFlags |= COLFLAG_HIDDEN; }else if( pTab && pCol!=pTab->aCol && (pCol[-1].colFlags & COLFLAG_HIDDEN) ){ pTab->tabFlags |= TF_OOOHidden; } } #endif /* ** 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 *pName, Token *pType){ Table *p; int i; char *z; char *zType; Column *pCol; sqlite3 *db = pParse->db; 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; } z = sqlite3DbMallocRaw(db, pName->n + pType->n + 2); if( z==0 ) return; if( IN_RENAME_OBJECT ) sqlite3RenameTokenMap(pParse, (void*)z, pName); memcpy(z, pName->z, pName->n); z[pName->n] = 0; sqlite3Dequote(z); for(i=0; i<p->nCol; i++){ if( sqlite3_stricmp(z, p->aCol[i].zName)==0 ){ sqlite3ErrorMsg(pParse, "duplicate column name: %s", z); sqlite3DbFree(db, z); return; } } if( (p->nCol & 0x7)==0 ){ Column *aNew; aNew = sqlite3DbRealloc(db,p->aCol,(p->nCol+8)*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->zName = z; sqlite3ColumnPropertiesFromName(p, pCol); if( pType->n==0 ){ /* If there is no type specified, columns have the default affinity ** 'BLOB' with a default size of 4 bytes. */ pCol->affinity = SQLITE_AFF_BLOB; pCol->szEst = 1; #ifdef SQLITE_ENABLE_SORTER_REFERENCES if( 4>=sqlite3GlobalConfig.szSorterRef ){ pCol->colFlags |= COLFLAG_SORTERREF; } #endif }else{ zType = z + sqlite3Strlen30(z) + 1; memcpy(zType, pType->z, pType->n); zType[pType->n] = 0; sqlite3Dequote(zType); pCol->affinity = sqlite3AffinityType(zType, pCol); pCol->colFlags |= COLFLAG_HASTYPE; } p->nCol++; 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 |
︙ | ︙ | |||
1736 1737 1738 1739 1740 1741 1742 | 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 ){ | < | | < < < < < < | > | < | 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 | 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]); if( !sqlite3ExprIsConstantOrFunction(pExpr, db->init.busy) ){ sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant", pCol->zName); }else{ /* A copy of pExpr is used instead of the original, as pExpr contains ** tokens that point to volatile memory. */ Expr x; sqlite3ExprDelete(db, pCol->pDflt); memset(&x, 0, sizeof(x)); x.op = TK_SPAN; x.u.zToken = sqlite3DbSpanDup(db, zStart, zEnd); x.pLeft = pExpr; x.flags = EP_Skip; pCol->pDflt = sqlite3ExprDup(db, &x, EXPRDUP_REDUCE); sqlite3DbFree(db, x.u.zToken); } } if( IN_RENAME_OBJECT ){ sqlite3RenameExprUnmap(pParse, pExpr); } sqlite3ExprDelete(db, pExpr); } |
︙ | ︙ | |||
1781 1782 1783 1784 1785 1786 1787 | ** 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. | | < < < < < < < < < < < < < < < | 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 | ** 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 epxression 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; } } /* ** 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 ** a primary key (and this is the second primary key) then create an |
︙ | ︙ | |||
1846 1847 1848 1849 1850 1851 1852 | "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]; | | | < < | | | | < | | < < < < < < < < < | > | | | | | | | > > > | > > > > > > > > > > > > > > > | < < | > > | < < < < < < < < < < < < < < < < < | < < | < < < | | < < < < < < | | < < | < < < < < < < < < < < | | 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 | "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]; pCol->colFlags |= COLFLAG_PRIMKEY; 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 = pCExpr->u.zToken; for(iCol=0; iCol<pTab->nCol; iCol++){ if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){ pCol = &pTab->aCol[iCol]; pCol->colFlags |= COLFLAG_PRIMKEY; break; } } } } } if( nTerm==1 && pCol && sqlite3StrICmp(sqlite3ColumnType(pCol,""), "INTEGER")==0 && 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].sortOrder; }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 */ ){ #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 #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 ) return; i = p->nCol-1; db = pParse->db; zColl = sqlite3NameFromToken(db, pToken); if( !zColl ) return; if( sqlite3LocateCollSeq(pParse, zColl) ){ Index *pIdx; sqlite3DbFree(db, p->aCol[i].zColl); p->aCol[i].zColl = 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] = p->aCol[i].zColl; } } }else{ sqlite3DbFree(db, zColl); } } /* ** This function returns the collation sequence for database native text ** encoding identified by the string zName, length nName. ** ** 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; } /* ** 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 |
︙ | ︙ | |||
2116 2117 2118 2119 2120 2121 2122 | 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++){ | | | 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 | 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->zName) + 5; } n += identLength(p->zName); if( n<50 ){ zSep = ""; zSep2 = ","; zEnd = ")"; }else{ |
︙ | ︙ | |||
2144 2145 2146 2147 2148 2149 2150 | zStmt[k++] = '('; for(pCol=p->aCol, i=0; i<p->nCol; i++, pCol++){ static const char * const azType[] = { /* SQLITE_AFF_BLOB */ "", /* SQLITE_AFF_TEXT */ " TEXT", /* SQLITE_AFF_NUMERIC */ " NUM", /* SQLITE_AFF_INTEGER */ " INT", | | < | < | < | < < < | 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 | zStmt[k++] = '('; for(pCol=p->aCol, i=0; i<p->nCol; i++, pCol++){ static const char * const azType[] = { /* SQLITE_AFF_BLOB */ "", /* SQLITE_AFF_TEXT */ " TEXT", /* SQLITE_AFF_NUMERIC */ " NUM", /* SQLITE_AFF_INTEGER */ " INT", /* SQLITE_AFF_REAL */ " REAL" }; int len; const char *zType; sqlite3_snprintf(n-k, &zStmt[k], zSep); k += sqlite3Strlen30(&zStmt[k]); zSep = zSep2; identPut(zStmt, &k, pCol->zName); 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 ); zType = azType[pCol->affinity - SQLITE_AFF_BLOB]; len = sqlite3Strlen30(zType); assert( pCol->affinity==SQLITE_AFF_BLOB || pCol->affinity==sqlite3AffinityType(zType, 0) ); memcpy(&zStmt[k], zType, len); k += len; assert( k<=n ); } sqlite3_snprintf(n-k, &zStmt[k], "%s", zEnd); return zStmt; } /* ** Resize an Index object to hold N columns total. Return SQLITE_OK ** 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(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->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; |
︙ | ︙ | |||
2233 2234 2235 2236 2237 2238 2239 | i16 x = pIdx->aiColumn[i]; assert( x<pIdx->pTable->nCol ); wIndex += x<0 ? 1 : aCol[pIdx->aiColumn[i]].szEst; } pIdx->szIdxRow = sqlite3LogEst(wIndex*4); } | | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < | | | | < | < < < < | | | | < < < < < < | < < < < < | | | < < < | | | < | < < < | < < < < < | < < < | | | < < | | | | | | | | > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > > | < < | | < < < < < < < < < < | < < < < < < < < < < < < < | | | | | | > | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | > > < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | 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 | 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 value x is found any of the first nCol entries of aiCol[] */ static int hasColumn(const i16 *aiCol, int nCol, int x){ while( nCol-- > 0 ) if( x==*(aiCol++) ) 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. ** ** 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; for(j=pIdx->nColumn-1; j>=0; j--){ int x = pIdx->aiColumn[j]; if( x>=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_master table entry ** for the PRIMARY KEY as the primary key index is now ** identified by the sqlite_master 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 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_Abort; } } } /* Convert the P3 operand of the OP_CreateBtree opcode from BTREE_INTKEY ** into BTREE_BLOBKEY. */ if( pParse->addrCrTab ){ assert( v ); sqlite3VdbeChangeP3(v, pParse->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].zName); pList = sqlite3ExprListAppend(pParse, 0, sqlite3ExprAlloc(db, TK_ID, &ipkToken, 0)); if( pList==0 ) return; pList->a[0].sortOrder = pParse->iPkSortOrder; assert( pParse->pNewTable==pTab ); sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0, SQLITE_IDXTYPE_PRIMARYKEY); if( db->mallocFailed || pParse->nErr ) return; pPk = sqlite3PrimaryKeyIndex(pTab); pTab->iPKey = -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( hasColumn(pPk->aiColumn, j, pPk->aiColumn[i]) ){ pPk->nColumn--; }else{ pPk->aiColumn[j++] = pPk->aiColumn[i]; } } pPk->nKeyCol = j; } assert( pPk!=0 ); pPk->isCovering = 1; if( !db->init.imposterTable ) pPk->uniqNotNull = 1; nPk = pPk->nKeyCol; /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master ** 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, 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( !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( !hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ){ pIdx->aiColumn[j] = pPk->aiColumn[i]; pIdx->azColl[j] = pPk->azColl[i]; j++; } } assert( pIdx->nColumn>=pIdx->nKeyCol+n ); assert( pIdx->nColumn>=j ); } /* Add all table columns to the PRIMARY KEY index */ if( nPk<pTab->nCol ){ if( resizeIndexObject(db, pPk, pTab->nCol) ) return; for(i=0, j=nPk; i<pTab->nCol; i++){ if( !hasColumn(pPk->aiColumn, j, i) ){ assert( j<pPk->nColumn ); pPk->aiColumn[j] = i; pPk->azColl[j] = sqlite3StrBINARY; j++; } } assert( pPk->nColumn==j ); assert( pTab->nCol==j ); }else{ pPk->nColumn = pTab->nCol; } recomputeColumnsNotIndexed(pPk); } #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 */ Module *pMod; /* Module for the virtual table */ 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; pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->azModuleArg[0]); if( pMod==0 ) return 0; if( pMod->pModule->iVersion<3 ) return 0; if( pMod->pModule->xShadowName==0 ) return 0; return pMod->pModule->xShadowName(zTail+1); } #endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */ /* ** 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 master 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_master table because we just ** connected to the database or because the sqlite_master table has ** recently changed, so the entry for this table already exists in ** the sqlite_master 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 */ u8 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; } assert( !db->mallocFailed ); 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_master" or "sqlite_temp_master" 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_master ** table itself. So mark it read-only. */ if( db->init.busy ){ if( pSelect ){ sqlite3ErrorMsg(pParse, ""); return; } p->tnum = db->init.newTnum; if( p->tnum==1 ) p->tabFlags |= TF_Readonly; } 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); }else{ 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); } #endif /* !defined(SQLITE_OMIT_CHECK) */ /* 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 SQLITE_MASTER 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( p->pSelect==0 ){ /* A regular table */ zType = "table"; zType2 = "TABLE"; #ifndef SQLITE_OMIT_VIEW }else{ /* A view */ zType = "view"; |
︙ | ︙ | |||
2827 2828 2829 2830 2831 2832 2833 | int regYield; /* Register holding co-routine entry-point */ int addrTop; /* Top of the co-routine */ int regRec; /* A record to be insert into the new table */ int regRowid; /* Rowid of the next row to insert */ int addrInsLoop; /* Top of the loop for inserting rows */ Table *pSelTab; /* A table that describes the SELECT results */ | < < < < < | | | 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 | int regYield; /* Register holding co-routine entry-point */ int addrTop; /* Top of the co-routine */ int regRec; /* A record to be insert into the new table */ int regRowid; /* Rowid of the next row to insert */ int addrInsLoop; /* Top of the loop for inserting rows */ Table *pSelTab; /* A table that describes the SELECT results */ regYield = ++pParse->nMem; regRec = ++pParse->nMem; regRowid = ++pParse->nMem; assert(pParse->nTab==1); 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); if( pSelTab==0 ) return; assert( p->aCol==0 ); p->nCol = 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; |
︙ | ︙ | |||
2880 2881 2882 2883 2884 2885 2886 | 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 | | | | | | | | > < < < < < | < < | < < < | < < > | | | | > | | > | 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 | 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 ** SQLITE_MASTER table. We just need to update that slot with all ** the information we've collected. */ sqlite3NestedParse(pParse, "UPDATE %Q.%s " "SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q " "WHERE rowid=#%d", db->aDb[iDb].zDbSName, MASTER_NAME, 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 ){ 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)); } /* 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) ); 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; #ifndef SQLITE_OMIT_ALTERTABLE if( !p->pSelect ){ const char *zName = (const char *)pParse->sNameToken.z; int nName; assert( !pSelect && pCons && pEnd ); if( pCons->z==0 ){ pCons = pEnd; } nName = (int)((const char *)pCons->z - zName); p->addColOffset = 13 + sqlite3Utf8CharLen(zName, nName); } #endif } } #ifndef SQLITE_OMIT_VIEW /* ** The parser calls this routine in order to create a new VIEW */ void sqlite3CreateView( |
︙ | ︙ | |||
2988 2989 2990 2991 2992 2993 2994 | 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; | < < < < < < < < < < < | | < | | > < | | | > | > | < | | 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 | 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 ){ p->pSelect = pSelect; pSelect = 0; }else{ p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); } p->pCheck = sqlite3ExprListDup(db, pCNames, EXPRDUP_REDUCE); if( db->mallocFailed ) goto create_view_fail; /* Locate the end of the CREATE VIEW statement. Make sEnd point to ** the end. */ sEnd = pParse->sLastToken; assert( sEnd.z[0]!=0 || sEnd.n==0 ); if( sEnd.z[0]!=';' ){ sEnd.z += sEnd.n; } sEnd.n = 0; n = (int)(sEnd.z - pBegin->z); assert( n>0 ); z = pBegin->z; while( sqlite3Isspace(z[n-1]) ){ n--; } sEnd.z = &z[n-1]; sEnd.n = 1; /* Use sqlite3EndTable() to add the view to the SQLITE_MASTER table */ sqlite3EndTable(pParse, 0, &sEnd, 0, 0); create_view_fail: sqlite3SelectDelete(db, pSelect); if( IN_RENAME_OBJECT ){ sqlite3RenameExprlistUnmap(pParse, pCNames); } sqlite3ExprListDelete(db, pCNames); return; } #endif /* SQLITE_OMIT_VIEW */ #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) /* ** The Table structure pTable is really a VIEW. Fill in the names of ** the columns of the view in the pTable structure. Return the number ** of errors. If an error is seen leave an error message in pParse->zErrMsg. */ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ Table *pSelTab; /* A fake table from which we get the result set */ Select *pSel; /* Copy of the SELECT that implements the view */ int nErr = 0; /* Number of errors encountered */ int n; /* Temporarily holds the number of cursors assigned */ sqlite3 *db = pParse->db; /* Database connection for malloc errors */ #ifndef SQLITE_OMIT_VIRTUALTABLE int rc; #endif #ifndef SQLITE_OMIT_AUTHORIZATION sqlite3_xauth xAuth; /* Saved xAuth pointer */ #endif assert( pTable ); #ifndef SQLITE_OMIT_VIRTUALTABLE db->nSchemaLock++; rc = sqlite3VtabCallConnect(pParse, pTable); db->nSchemaLock--; if( rc ){ return 1; } if( IsVirtual(pTable) ) return 0; #endif #ifndef SQLITE_OMIT_VIEW /* A positive nCol means the columns names for this view are ** already known. */ if( pTable->nCol>0 ) return 0; /* A negative nCol is a special marker meaning that we are currently ** trying to compute the column names. If we enter this routine with ** a negative nCol, it means two or more views form a loop, like this: ** ** CREATE VIEW one AS SELECT * FROM two; ** CREATE VIEW two AS SELECT * FROM one; |
︙ | ︙ | |||
3112 3113 3114 3115 3116 3117 3118 | /* 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. */ | | | > < < > > | | | | < < < < | > | < | | < > > > < | > > > > < < < < < | > > | 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 | /* 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( pTable->pSelect ); pSel = sqlite3SelectDup(db, pTable->pSelect, 0); if( pSel ){ #ifndef SQLITE_OMIT_ALTERTABLE u8 eParseMode = pParse->eParseMode; pParse->eParseMode = PARSE_MODE_NORMAL; #endif n = pParse->nTab; sqlite3SrcListAssignCursors(pParse, pSel->pSrc); pTable->nCol = -1; db->lookaside.bDisable++; #ifndef SQLITE_OMIT_AUTHORIZATION xAuth = db->xAuth; db->xAuth = 0; pSelTab = sqlite3ResultSetOfSelect(pParse, pSel); db->xAuth = xAuth; #else pSelTab = sqlite3ResultSetOfSelect(pParse, pSel); #endif pParse->nTab = n; 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); } }else if( pSelTab ){ /* 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; pSelTab->nCol = 0; pSelTab->aCol = 0; assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) ); }else{ pTable->nCol = 0; nErr++; } sqlite3DeleteTable(db, pSelTab); sqlite3SelectDelete(db, pSel); db->lookaside.bDisable--; #ifndef SQLITE_OMIT_ALTERTABLE pParse->eParseMode = eParseMode; #endif } else { nErr++; } pTable->pSchema->schemaFlags |= DB_UnresetViews; if( db->mallocFailed ){ sqlite3DeleteColumnNames(db, pTable); pTable->aCol = 0; pTable->nCol = 0; } #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( pTab->pSelect ){ sqlite3DeleteColumnNames(db, pTab); pTab->aCol = 0; pTab->nCol = 0; } } DbClearProperty(db, idx, DB_UnresetViews); } #else # define sqliteViewResetAll(A,B) #endif /* SQLITE_OMIT_VIEW */ |
︙ | ︙ | |||
3222 3223 3224 3225 3226 3227 3228 | ** 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 | | | 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 | ** 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, int iFrom, int iTo){ HashElem *pElem; Hash *pHash; Db *pDb; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); pDb = &db->aDb[iDb]; pHash = &pDb->pSchema->tblHash; |
︙ | ︙ | |||
3248 3249 3250 3251 3252 3253 3254 | } } } #endif /* ** Write code to erase the table with root-page iTable from database iDb. | | | < | | | | | | | | 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 | } } } #endif /* ** Write code to erase the table with root-page iTable from database iDb. ** Also write code to modify the sqlite_master 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_master 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.%s SET rootpage=%d WHERE #%d AND rootpage=#%d", pParse->db->aDb[iDb].zDbSName, MASTER_NAME, 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_master 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. */ int iTab = pTab->tnum; int iDestroyed = 0; while( 1 ){ Index *pIdx; int iLargest = 0; if( iDestroyed==0 || iTab<iDestroyed ){ iLargest = iTab; } for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int iIdx = pIdx->tnum; assert( pIdx->pSchema==pTab->pSchema ); if( (iDestroyed==0 || (iIdx<iDestroyed)) && iIdx>iLargest ){ iLargest = iIdx; } } if( iLargest==0 ){ return; |
︙ | ︙ | |||
3371 3372 3373 3374 3375 3376 3377 | #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ sqlite3VdbeAddOp0(v, OP_VBegin); } #endif /* Drop all triggers associated with the table being dropped. Code | | | | 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 | #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_master and/or ** sqlite_temp_master 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; |
︙ | ︙ | |||
3396 3397 3398 3399 3400 3401 3402 | sqlite3NestedParse(pParse, "DELETE FROM %Q.sqlite_sequence WHERE name=%Q", pDb->zDbSName, pTab->zName ); } #endif | | | < | | | 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 | sqlite3NestedParse(pParse, "DELETE FROM %Q.sqlite_sequence WHERE name=%Q", pDb->zDbSName, pTab->zName ); } #endif /* Drop all SQLITE_MASTER table and index entries that refer to the ** table. The program name loops through the master table and deletes ** every row that refers to a table of the same name as the one being ** dropped. Triggers are handled separately because a trigger can be ** created in the temp database that refers to a table in another ** database. */ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'", pDb->zDbSName, MASTER_NAME, pTab->zName); if( !isView && !IsVirtual(pTab) ){ destroyTable(pParse, pTab); } /* Remove the table entry from SQLite's internal schema and modify ** the schema cookie. */ |
︙ | ︙ | |||
3432 3433 3434 3435 3436 3437 3438 | ** context. */ int sqlite3ReadOnlyShadowTables(sqlite3 *db){ #ifndef SQLITE_OMIT_VIRTUALTABLE if( (db->flags & SQLITE_Defensive)!=0 && db->pVtabCtx==0 && db->nVdbeExec==0 | < < < < | 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 | ** context. */ int sqlite3ReadOnlyShadowTables(sqlite3 *db){ #ifndef SQLITE_OMIT_VIRTUALTABLE if( (db->flags & SQLITE_Defensive)!=0 && db->pVtabCtx==0 && db->nVdbeExec==0 ){ 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; } 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. */ |
︙ | ︙ | |||
3480 3481 3482 3483 3484 3485 3486 | 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 ){ | < | < < | 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 | 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); 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. |
︙ | ︙ | |||
3539 3540 3541 3542 3543 3544 3545 | 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. */ | | | | | 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 | 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 && pTab->pSelect==0 ){ sqlite3ErrorMsg(pParse, "use DROP TABLE to delete table %s", pTab->zName); goto exit_drop_table; } if( !isView && pTab->pSelect ){ sqlite3ErrorMsg(pParse, "use DROP VIEW to delete view %s", pTab->zName); goto exit_drop_table; } #endif /* Generate code to remove the table from the master table ** on disk. */ v = sqlite3GetVdbe(pParse); if( v ){ sqlite3BeginWriteOperation(pParse, 1, iDb); if( !isView ){ sqlite3ClearStatTables(pParse, iDb, "tbl", pTab->zName); |
︙ | ︙ | |||
3594 3595 3596 3597 3598 3599 3600 | int flags /* Conflict resolution algorithms. */ ){ sqlite3 *db = pParse->db; #ifndef SQLITE_OMIT_FOREIGN_KEY FKey *pFKey = 0; FKey *pNextTo; Table *p = pParse->pNewTable; | | | | < | | | | | | | | 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 | int flags /* Conflict resolution algorithms. */ ){ sqlite3 *db = pParse->db; #ifndef SQLITE_OMIT_FOREIGN_KEY FKey *pFKey = 0; FKey *pNextTo; Table *p = pParse->pNewTable; int 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].zName, 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].zName) + 1; } } pFKey = sqlite3DbMallocZero(db, nByte ); if( pFKey==0 ){ goto fk_end; } pFKey->pFrom = p; pFKey->pNextFrom = p->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].zName, pFromCol->a[i].zName)==0 ){ pFKey->aCol[i].iFrom = j; break; } } if( j>=p->nCol ){ sqlite3ErrorMsg(pParse, "unknown column \"%s\" in foreign key definition", pFromCol->a[i].zName); goto fk_end; } if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, &pFKey->aCol[i], pFromCol->a[i].zName); } } } if( pToCol ){ for(i=0; i<nCol; i++){ int n = sqlite3Strlen30(pToCol->a[i].zName); pFKey->aCol[i].zCol = z; if( IN_RENAME_OBJECT ){ sqlite3RenameTokenRemap(pParse, z, pToCol->a[i].zName); } memcpy(z, pToCol->a[i].zName, 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 */ |
︙ | ︙ | |||
3696 3697 3698 3699 3700 3701 3702 | assert( pNextTo->pPrevTo==0 ); pFKey->pNextTo = pNextTo; pNextTo->pPrevTo = pFKey; } /* Link the foreign key to the table as the last step. */ | < | | < < | 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 | assert( pNextTo->pPrevTo==0 ); pFKey->pNextTo = pNextTo; pNextTo->pPrevTo = pFKey; } /* Link the foreign key to the table as the last step. */ p->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 || (pFKey = pTab->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 |
︙ | ︙ | |||
3744 3745 3746 3747 3748 3749 3750 | 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 */ | | | | | < < < < < < < < < < < < < < < < | < | 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 | 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 */ int 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 = 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. */ iSorter = pParse->nTab++; sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, pIndex->nKeyCol, (char*) sqlite3KeyInfoRef(pKey), P4_KEYINFO); /* Open the table. Loop through all rows of the table, inserting index ** records into the sorter. */ sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); VdbeCoverage(v); regRecord = sqlite3GetTempReg(pParse); sqlite3MultiWrite(pParse); 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, 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{ addr2 = sqlite3VdbeCurrentAddr(v); } sqlite3VdbeAddOp3(v, OP_SorterData, iSorter, regRecord, iIdx); 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); |
︙ | ︙ | |||
3871 3872 3873 3874 3875 3876 3877 | p->nColumn = nCol; p->nKeyCol = nCol - 1; *ppExtra = ((char*)p) + nByte; } return p; } | < < < < < < < < < < < < < < < < < < < < < | 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 | 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 ** currently being constructed by a CREATE TABLE statement. |
︙ | ︙ | |||
3934 3935 3936 3937 3938 3939 3940 | Token *pName = 0; /* Unqualified name of the index to create */ struct ExprList_item *pListItem; /* For looping over pList */ int nExtra = 0; /* Space allocated for zExtra[] */ int nExtraCol; /* Number of extra columns needed */ char *zExtra = 0; /* Extra space after the Index object */ Index *pPk = 0; /* PRIMARY KEY index for WITHOUT ROWID tables */ | < | < < < < | 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 | Token *pName = 0; /* Unqualified name of the index to create */ struct ExprList_item *pListItem; /* For looping over pList */ int nExtra = 0; /* Space allocated for zExtra[] */ int nExtraCol; /* Number of extra columns needed */ char *zExtra = 0; /* Extra space after the Index object */ Index *pPk = 0; /* PRIMARY KEY index for WITHOUT ROWID tables */ if( db->mallocFailed || pParse->nErr>0 ){ 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 ){ /* Use the two-part index name to determine the database |
︙ | ︙ | |||
4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 | pTab = pParse->pNewTable; if( !pTab ) goto exit_create_index; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); } pDb = &db->aDb[iDb]; assert( pTab!=0 ); if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 && db->init.busy==0 && pTblName!=0 #if SQLITE_USER_AUTHENTICATION && sqlite3UserAuthTable(pTab->zName)==0 #endif | > > > > | | | | < | 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 | pTab = pParse->pNewTable; if( !pTab ) goto exit_create_index; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); } 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 #ifdef SQLITE_ALLOW_SQLITE_MASTER_INDEX && sqlite3StrICmp(&pTab->zName[7],"master")!=0 #endif ){ sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName); goto exit_create_index; } #ifndef SQLITE_OMIT_VIEW if( pTab->pSelect ){ 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_master 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); } goto exit_create_index; } } }else{ int n; Index *pLoop; |
︙ | ︙ | |||
4104 4105 4106 4107 4108 4109 4110 | ** 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; | | | < | 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 | ** 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->zName); pList = sqlite3ExprListAppend(pParse, 0, sqlite3ExprAlloc(db, TK_ID, &prevCol, 0)); if( pList==0 ) goto exit_create_index; assert( pList->nExpr==1 ); sqlite3ExprListSetSortOrder(pList, sortOrder); }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 ){ nExtra += (1 + sqlite3Strlen30(pExpr->u.zToken)); } } /* ** Allocate the index structure. */ |
︙ | ︙ | |||
4206 4207 4208 4209 4210 4211 4212 | pIndex->uniqNotNull = 0; pIndex->bHasExpr = 1; }else{ j = pCExpr->iColumn; assert( j<=0x7fff ); if( j<0 ){ j = pTab->iPKey; | < | | < < < < < < | | | < | | | 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 | pIndex->uniqNotNull = 0; pIndex->bHasExpr = 1; }else{ j = pCExpr->iColumn; assert( j<=0x7fff ); if( j<0 ){ j = pTab->iPKey; }else if( pTab->aCol[j].notNull==0 ){ pIndex->uniqNotNull = 0; } pIndex->aiColumn[i] = (i16)j; } zColl = 0; if( pListItem->pExpr->op==TK_COLLATE ){ int nColl; 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 = pTab->aCol[j].zColl; } if( !zColl ) zColl = sqlite3StrBINARY; if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){ goto exit_create_index; } pIndex->azColl[i] = zColl; requestedSortOrder = pListItem->sortOrder & 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( hasColumn(pIndex->aiColumn, pIndex->nKeyCol, x) ){ pIndex->nColumn--; }else{ 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 || sqlite3ColumnOfIndex(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( sqlite3ColumnOfIndex(pIndex,j)>=0 ) continue; pIndex->isCovering = 0; break; } } if( pTab==pParse->pNewTable ){ /* This routine has been called to create an automatic index as a |
︙ | ︙ | |||
4379 4380 4381 4382 4383 4384 4385 | } 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 | | | | 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 | } 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_master table and populate the index with ** content. But, do not do this if we are simply reading the sqlite_master ** 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. |
︙ | ︙ | |||
4405 4406 4407 4408 4409 4410 4411 | /* 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. */ | | < | | | | | | | | | | > > > > > > > > > | | > > > > > > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | /* 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 = 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 */ 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_master for this index */ sqlite3NestedParse(pParse, "INSERT INTO %Q.%s VALUES('index',%Q,%Q,#%d,%Q);", db->aDb[iDb].zDbSName, MASTER_NAME, 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)); sqlite3VdbeAddOp2(v, OP_Expire, 0, 1); } sqlite3VdbeJumpHere(v, pIndex->tnum); } } /* When adding an index to the list of indices for a table, make ** sure all indices labeled OE_Replace come after all those labeled ** OE_Ignore. This is necessary for the correct constraint check ** processing (in sqlite3GenerateConstraintChecks()) as part of ** UPDATE and INSERT statements. */ if( db->init.busy || pTblName==0 ){ if( onError!=OE_Replace || pTab->pIndex==0 || pTab->pIndex->onError==OE_Replace){ pIndex->pNext = pTab->pIndex; pTab->pIndex = pIndex; }else{ Index *pOther = pTab->pIndex; while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){ pOther = pOther->pNext; } pIndex->pNext = pOther->pNext; pOther->pNext = 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); sqlite3ExprDelete(db, pPIWhere); sqlite3ExprListDelete(db, pList); sqlite3SrcListDelete(db, pTblName); sqlite3DbFree(db, zName); } /* |
︙ | ︙ | |||
4518 4519 4520 4521 4522 4523 4524 | ** 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){ | | | < | < < < < < < < | < < < < | | | 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 | ** 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 */ LogEst aVal[] = { 33, 32, 30, 28, 26 }; LogEst *a = pIdx->aiRowLogEst; 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. But do not let the estimate drop below 10. */ a[0] = pIdx->pTable->nRowLogEst; if( pIdx->pPartIdxWhere!=0 ) a[0] -= 10; assert( 10==sqlite3LogEst(2) ); if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) ); /* 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) ); } |
︙ | ︙ | |||
4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 | */ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){ Index *pIndex; Vdbe *v; sqlite3 *db = pParse->db; int iDb; if( db->mallocFailed ){ goto exit_drop_index; } | > < | < | | | | | 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 | */ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){ Index *pIndex; Vdbe *v; sqlite3 *db = pParse->db; int iDb; assert( pParse->nErr==0 ); /* Never called with prior errors */ if( db->mallocFailed ){ goto exit_drop_index; } 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, 0); }else{ sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); } 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 ) 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 master table */ v = sqlite3GetVdbe(pParse); if( v ){ sqlite3BeginWriteOperation(pParse, 1, iDb); sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE name=%Q AND type='index'", db->aDb[iDb].zDbSName, MASTER_NAME, 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); } |
︙ | ︙ | |||
4679 4680 4681 4682 4683 4684 4685 | */ IdList *sqlite3IdListAppend(Parse *pParse, IdList *pList, Token *pToken){ sqlite3 *db = pParse->db; int i; if( pList==0 ){ pList = sqlite3DbMallocZero(db, sizeof(IdList) ); if( pList==0 ) return 0; | < > > > | | | > > | | | | < < < < < > | | | 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 | */ IdList *sqlite3IdListAppend(Parse *pParse, IdList *pList, Token *pToken){ sqlite3 *db = pParse->db; int i; if( pList==0 ){ pList = sqlite3DbMallocZero(db, sizeof(IdList) ); if( pList==0 ) return 0; } pList->a = sqlite3ArrayAllocate( db, pList->a, sizeof(pList->a[0]), &pList->nId, &i ); if( i<0 ){ sqlite3IdListDelete(db, pList); return 0; } pList->a[i].zName = sqlite3NameFromToken(db, pToken); if( IN_RENAME_OBJECT && pList->a[i].zName ){ sqlite3RenameTokenMap(pParse, (void*)pList->a[i].zName, pToken); } return pList; } /* ** Delete an IdList. */ void sqlite3IdListDelete(sqlite3 *db, IdList *pList){ int i; if( pList==0 ) return; for(i=0; i<pList->nId; i++){ sqlite3DbFree(db, pList->a[i].zName); } sqlite3DbFree(db, pList->a); sqlite3DbFreeNN(db, pList); } /* ** Return the index in pList of the identifier named zId. Return -1 ** if not found. */ int sqlite3IdListIndex(IdList *pList, const char *zName){ int i; if( pList==0 ) return -1; for(i=0; i<pList->nId; i++){ if( sqlite3StrICmp(pList->a[i].zName, zName)==0 ) return i; } return -1; } /* |
︙ | ︙ | |||
4851 4852 4853 4854 4855 4856 4857 | */ 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 */ ){ | | | 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 | */ 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 */ ){ struct SrcList_item *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) ); |
︙ | ︙ | |||
4892 4893 4894 4895 4896 4897 4898 | } /* ** Assign VdbeCursor index numbers to all tables in a SrcList */ void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){ int i; | | | | | | < | | | | | | < < | < | | 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 | } /* ** Assign VdbeCursor index numbers to all tables in a SrcList */ void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){ int i; struct SrcList_item *pItem; assert(pList || pParse->db->mallocFailed ); if( pList ){ for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){ if( pItem->iCursor>=0 ) break; 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; struct SrcList_item *pItem; if( pList==0 ) return; for(pItem=pList->a, i=0; i<pList->nSrc; i++, pItem++){ sqlite3DbFree(db, pItem->zDatabase); sqlite3DbFree(db, pItem->zName); sqlite3DbFree(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); sqlite3SelectDelete(db, pItem->pSelect); sqlite3ExprDelete(db, pItem->pOn); 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 ** the FROM clause that has already been constructed. "p" is NULL ** if this is the first term of the FROM clause. pTable and pDatabase |
︙ | ︙ | |||
4953 4954 4955 4956 4957 4958 4959 | SrcList *sqlite3SrcListAppendFromTerm( Parse *pParse, /* Parsing context */ SrcList *p, /* The left part of the FROM clause already seen */ 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 */ | > | | | | < | < < < < < < < | < | < < < < | | > | < < < < < < < < < < < < < < < < < < < < < < | | 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 | SrcList *sqlite3SrcListAppendFromTerm( Parse *pParse, /* Parsing context */ SrcList *p, /* The left part of the FROM clause already seen */ 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 */ ){ struct SrcList_item *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 ); if( IN_RENAME_OBJECT && pItem->zName ){ Token *pToken = (ALWAYS(pDatabase) && pDatabase->z) ? pDatabase : pTable; sqlite3RenameTokenMap(pParse, pItem->zName, pToken); } assert( pAlias!=0 ); if( pAlias->n ){ pItem->zAlias = sqlite3NameFromToken(db, pAlias); } pItem->pSelect = pSubquery; pItem->pOn = pOn; pItem->pUsing = pUsing; return p; append_from_error: assert( p==0 ); sqlite3ExprDelete(db, pOn); sqlite3IdListDelete(db, pUsing); sqlite3SelectDelete(db, pSubquery); return 0; } /* ** 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 ){ struct SrcList_item *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; } } } /* ** 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 ){ struct SrcList_item *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); |
︙ | ︙ | |||
5081 5082 5083 5084 5085 5086 5087 | ** Example: Suppose the join is like this: ** ** A natural cross join B ** ** The operator is "natural cross join". The A and B operands are stored ** in p->a[0] and p->a[1], respectively. The parser initially stores the ** operator with A. This routine shifts that operator over to B. | < < < < < < < | < | | | < | < < | < < < < < < < | < < | 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 | ** Example: Suppose the join is like this: ** ** A natural cross join B ** ** The operator is "natural cross join". The A and B operands are stored ** in p->a[0] and p->a[1], respectively. The parser initially stores the ** operator with A. This routine shifts that operator over to B. */ void sqlite3SrcListShiftJoinType(SrcList *p){ if( p ){ int i; for(i=p->nSrc-1; i>0; i--){ p->a[i].fg.jointype = p->a[i-1].fg.jointype; } p->a[0].fg.jointype = 0; } } /* ** Generate VDBE code for a BEGIN statement. */ void sqlite3BeginTransaction(Parse *pParse, int type){ |
︙ | ︙ | |||
5130 5131 5132 5133 5134 5135 5136 | if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ){ return; } v = sqlite3GetVdbe(pParse); if( !v ) return; if( type!=TK_DEFERRED ){ for(i=0; i<db->nDb; i++){ | < < < < < < < < < | | 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 | if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ){ return; } v = sqlite3GetVdbe(pParse); if( !v ) return; if( type!=TK_DEFERRED ){ for(i=0; i<db->nDb; i++){ sqlite3VdbeAddOp2(v, OP_Transaction, i, (type==TK_EXCLUSIVE)+1); sqlite3VdbeUsesBtree(v, i); } } sqlite3VdbeAddOp0(v, OP_AutoCommit); } /* |
︙ | ︙ | |||
5214 5215 5216 5217 5218 5219 5220 | 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 ); | | | > > | | | | < < < < | 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 | 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, -1, 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(). */ void sqlite3CodeVerifySchema(Parse *pParse, int iDb){ Parse *pToplevel = sqlite3ParseToplevel(pParse); assert( iDb>=0 && iDb<pParse->db->nDb ); assert( pParse->db->aDb[iDb].pBt!=0 || iDb==1 ); assert( iDb<SQLITE_MAX_ATTACHED+2 ); assert( sqlite3SchemaMutexHeld(pParse->db, iDb, 0) ); if( DbMaskTest(pToplevel->cookieMask, iDb)==0 ){ DbMaskSet(pToplevel->cookieMask, iDb); if( !OMIT_TEMPDB && iDb==1 ){ sqlite3OpenTempDatabase(pToplevel); } } } /* ** 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; |
︙ | ︙ | |||
5275 5276 5277 5278 5279 5280 5281 | ** 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); | | | 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 | ** 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); sqlite3CodeVerifySchema(pParse, 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, |
︙ | ︙ | |||
5326 5327 5328 5329 5330 5331 5332 | 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 */ ){ | < < | | | 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 | 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 = sqlite3GetVdbe(pParse); assert( (errCode&0xff)==SQLITE_CONSTRAINT ); if( onError==OE_Abort ){ sqlite3MayAbort(pParse); } sqlite3VdbeAddOp4(v, OP_Halt, errCode, onError, 0, p4, p4type); sqlite3VdbeChangeP5(v, p5Errmsg); } |
︙ | ︙ | |||
5358 5359 5360 5361 5362 5363 5364 | 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 ); | | | 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 | 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]].zName; 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); |
︙ | ︙ | |||
5385 5386 5387 5388 5389 5390 5391 | 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, | | | 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 | 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].zName); 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); |
︙ | ︙ | |||
5549 5550 5551 5552 5553 5554 5555 | } 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); | | < | 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 | } 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->aSortOrder[i] = pIdx->aSortOrder[i]; } 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 |
︙ | ︙ | |||
5573 5574 5575 5576 5577 5578 5579 | pKey = 0; } } return pKey; } #ifndef SQLITE_OMIT_CTE | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | > > < < < < | > | > > > > | | | > > > | 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 | pKey = 0; } } return pKey; } #ifndef SQLITE_OMIT_CTE /* ** This routine is invoked once per CTE by the parser while parsing a ** WITH clause. */ With *sqlite3WithAdd( Parse *pParse, /* Parsing context */ With *pWith, /* Existing WITH clause, or NULL */ Token *pName, /* Name of the common-table */ ExprList *pArglist, /* Optional column name list for the table */ Select *pQuery /* Query used to initialize the table */ ){ sqlite3 *db = pParse->db; With *pNew; char *zName; /* Check that the CTE name is unique within this WITH clause. If ** not, store an error in the Parse structure. */ zName = sqlite3NameFromToken(pParse->db, pName); 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 ){ sqlite3ExprListDelete(db, pArglist); sqlite3SelectDelete(db, pQuery); sqlite3DbFree(db, zName); pNew = pWith; }else{ pNew->a[pNew->nCte].pSelect = pQuery; pNew->a[pNew->nCte].pCols = pArglist; pNew->a[pNew->nCte].zName = zName; pNew->a[pNew->nCte].zCteErr = 0; pNew->nCte++; } 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++){ struct Cte *pCte = &pWith->a[i]; sqlite3ExprListDelete(db, pCte->pCols); sqlite3SelectDelete(db, pCte->pSelect); sqlite3DbFree(db, pCte->zName); } sqlite3DbFree(db, pWith); } } #endif /* !defined(SQLITE_OMIT_CTE) */ |
Changes to src/callback.c.
︙ | ︙ | |||
60 61 62 63 64 65 66 67 68 69 70 71 72 73 | memcpy(pColl, pColl2, sizeof(CollSeq)); 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. ** | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | memcpy(pColl, pColl2, sizeof(CollSeq)); pColl->xDel = 0; /* Do not copy the destructor */ return SQLITE_OK; } } return SQLITE_ERROR; } /* ** 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 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. ** |
︙ | ︙ | |||
153 154 155 156 157 158 159 | ** 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( | | | | | < < < < < | < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | ** 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, u8 enc, const char *zName, int create ){ CollSeq *pColl; if( zName ){ pColl = findCollSeqEntry(db, zName, create); }else{ pColl = db->pDfltColl; } assert( SQLITE_UTF8==1 && SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); assert( enc>=SQLITE_UTF8 && enc<=SQLITE_UTF16BE ); if( pColl ) pColl += enc-1; 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 |
︙ | ︙ | |||
297 298 299 300 301 302 303 | #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; | < < | | < | > > | 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 | #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; /* nArg of -2 is a special case */ if( nArg==(-2) ) return (p->xSFunc==0) ? 0 : FUNC_PERFECT_MATCH; /* Wrong number of arguments means "no match" */ if( p->nArg!=nArg && 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; |
︙ | ︙ | |||
333 334 335 336 337 338 339 | */ 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){ | < | | 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 | */ 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; } /* ** Insert a new FuncDef into a FuncDefHash hash table. */ void sqlite3InsertBuiltinFuncs( FuncDef *aDef, /* List of global functions to be inserted */ int nDef /* Length of the apDef[] list */ ){ 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; |
︙ | ︙ | |||
486 487 488 489 490 491 492 | ** The Schema.cache_size variable is not cleared. */ void sqlite3SchemaClear(void *p){ Hash temp1; Hash temp2; HashElem *pElem; Schema *pSchema = (Schema *)p; | < < | | | 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 | ** The Schema.cache_size variable is not cleared. */ void sqlite3SchemaClear(void *p){ Hash temp1; Hash temp2; HashElem *pElem; Schema *pSchema = (Schema *)p; temp1 = pSchema->tblHash; temp2 = pSchema->trigHash; sqlite3HashInit(&pSchema->trigHash); sqlite3HashClear(&pSchema->idxHash); for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){ sqlite3DeleteTrigger(0, (Trigger*)sqliteHashData(pElem)); } sqlite3HashClear(&temp2); sqlite3HashInit(&pSchema->tblHash); for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){ Table *pTab = sqliteHashData(pElem); sqlite3DeleteTable(0, pTab); } sqlite3HashClear(&temp1); sqlite3HashClear(&pSchema->fkeyHash); pSchema->pSeqTab = 0; if( pSchema->schemaFlags & DB_SchemaLoaded ){ pSchema->iGeneration++; } |
︙ | ︙ |
Changes to src/ctime.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 | /* ** 2010 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 routines used to report what compile-time options ** SQLite was built with. */ #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS /* ** 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) /* ** 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 */ #if SQLITE_32BIT_ROWID "32BIT_ROWID", #endif #if SQLITE_4_BYTE_ALIGNED_MALLOC "4_BYTE_ALIGNED_MALLOC", #endif #if SQLITE_64BIT_STATS "64BIT_STATS", #endif #if SQLITE_ALLOW_COVERING_INDEX_SCAN "ALLOW_COVERING_INDEX_SCAN", #endif #if SQLITE_ALLOW_URI_AUTHORITY "ALLOW_URI_AUTHORITY", #endif #ifdef SQLITE_BITMASK_TYPE "BITMASK_TYPE=" CTIMEOPT_VAL(SQLITE_BITMASK_TYPE), #endif #if SQLITE_BUG_COMPATIBLE_20160819 "BUG_COMPATIBLE_20160819", #endif #if SQLITE_CASE_SENSITIVE_LIKE "CASE_SENSITIVE_LIKE", #endif #if 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 #if SQLITE_COVERAGE_TEST "COVERAGE_TEST", #endif #if SQLITE_DEBUG "DEBUG", #endif #if SQLITE_DEFAULT_AUTOMATIC_INDEX "DEFAULT_AUTOMATIC_INDEX", #endif #if SQLITE_DEFAULT_AUTOVACUUM "DEFAULT_AUTOVACUUM", #endif #ifdef SQLITE_DEFAULT_CACHE_SIZE "DEFAULT_CACHE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_CACHE_SIZE), #endif #if 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 #if 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 #if SQLITE_DEFAULT_MEMSTATUS "DEFAULT_MEMSTATUS", #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 #if 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 #if SQLITE_DIRECT_OVERFLOW_READ "DIRECT_OVERFLOW_READ", #endif #if SQLITE_DISABLE_DIRSYNC "DISABLE_DIRSYNC", #endif #if SQLITE_DISABLE_FTS3_UNICODE "DISABLE_FTS3_UNICODE", #endif #if SQLITE_DISABLE_FTS4_DEFERRED "DISABLE_FTS4_DEFERRED", #endif #if SQLITE_DISABLE_INTRINSIC "DISABLE_INTRINSIC", #endif #if SQLITE_DISABLE_LFS "DISABLE_LFS", #endif #if SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS "DISABLE_PAGECACHE_OVERFLOW_STATS", #endif #if 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 #if SQLITE_ENABLE_API_ARMOR "ENABLE_API_ARMOR", #endif #if SQLITE_ENABLE_ATOMIC_WRITE "ENABLE_ATOMIC_WRITE", #endif #if SQLITE_ENABLE_BATCH_ATOMIC_WRITE "ENABLE_BATCH_ATOMIC_WRITE", #endif #if SQLITE_ENABLE_CEROD "ENABLE_CEROD=" CTIMEOPT_VAL(SQLITE_ENABLE_CEROD), #endif #if SQLITE_ENABLE_COLUMN_METADATA "ENABLE_COLUMN_METADATA", #endif #if SQLITE_ENABLE_COLUMN_USED_MASK "ENABLE_COLUMN_USED_MASK", #endif #if SQLITE_ENABLE_COSTMULT "ENABLE_COSTMULT", #endif #if SQLITE_ENABLE_CURSOR_HINTS "ENABLE_CURSOR_HINTS", #endif #if SQLITE_ENABLE_DBSTAT_VTAB "ENABLE_DBSTAT_VTAB", #endif #if SQLITE_ENABLE_EXPENSIVE_ASSERT "ENABLE_EXPENSIVE_ASSERT", #endif #if SQLITE_ENABLE_FTS1 "ENABLE_FTS1", #endif #if SQLITE_ENABLE_FTS2 "ENABLE_FTS2", #endif #if SQLITE_ENABLE_FTS3 "ENABLE_FTS3", #endif #if SQLITE_ENABLE_FTS3_PARENTHESIS "ENABLE_FTS3_PARENTHESIS", #endif #if SQLITE_ENABLE_FTS3_TOKENIZER "ENABLE_FTS3_TOKENIZER", #endif #if SQLITE_ENABLE_FTS4 "ENABLE_FTS4", #endif #if SQLITE_ENABLE_FTS5 "ENABLE_FTS5", #endif #if SQLITE_ENABLE_GEOPOLY "ENABLE_GEOPOLY", #endif #if SQLITE_ENABLE_HIDDEN_COLUMNS "ENABLE_HIDDEN_COLUMNS", #endif #if SQLITE_ENABLE_ICU "ENABLE_ICU", #endif #if SQLITE_ENABLE_IOTRACE "ENABLE_IOTRACE", #endif #if SQLITE_ENABLE_JSON1 "ENABLE_JSON1", #endif #if SQLITE_ENABLE_LOAD_EXTENSION "ENABLE_LOAD_EXTENSION", #endif #ifdef SQLITE_ENABLE_LOCKING_STYLE "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE), #endif #if SQLITE_ENABLE_MEMORY_MANAGEMENT "ENABLE_MEMORY_MANAGEMENT", #endif #if SQLITE_ENABLE_MEMSYS3 "ENABLE_MEMSYS3", #endif #if SQLITE_ENABLE_MEMSYS5 "ENABLE_MEMSYS5", #endif #if SQLITE_ENABLE_MULTIPLEX "ENABLE_MULTIPLEX", #endif #if SQLITE_ENABLE_NORMALIZE "ENABLE_NORMALIZE", #endif #if SQLITE_ENABLE_NULL_TRIM "ENABLE_NULL_TRIM", #endif #if SQLITE_ENABLE_OVERSIZE_CELL_CHECK "ENABLE_OVERSIZE_CELL_CHECK", #endif #if SQLITE_ENABLE_PREUPDATE_HOOK "ENABLE_PREUPDATE_HOOK", #endif #if SQLITE_ENABLE_QPSG "ENABLE_QPSG", #endif #if SQLITE_ENABLE_RBU "ENABLE_RBU", #endif #if SQLITE_ENABLE_RTREE "ENABLE_RTREE", #endif #if SQLITE_ENABLE_SELECTTRACE "ENABLE_SELECTTRACE", #endif #if SQLITE_ENABLE_SESSION "ENABLE_SESSION", #endif #if SQLITE_ENABLE_SNAPSHOT "ENABLE_SNAPSHOT", #endif #if SQLITE_ENABLE_SORTER_REFERENCES "ENABLE_SORTER_REFERENCES", #endif #if SQLITE_ENABLE_SQLLOG "ENABLE_SQLLOG", #endif #if defined(SQLITE_ENABLE_STAT4) "ENABLE_STAT4", #elif defined(SQLITE_ENABLE_STAT3) "ENABLE_STAT3", #endif #if SQLITE_ENABLE_STMTVTAB "ENABLE_STMTVTAB", #endif #if SQLITE_ENABLE_STMT_SCANSTATUS "ENABLE_STMT_SCANSTATUS", #endif #if SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION "ENABLE_UNKNOWN_SQL_FUNCTION", #endif #if SQLITE_ENABLE_UNLOCK_NOTIFY "ENABLE_UNLOCK_NOTIFY", #endif #if SQLITE_ENABLE_UPDATE_DELETE_LIMIT "ENABLE_UPDATE_DELETE_LIMIT", #endif #if SQLITE_ENABLE_URI_00_ERROR "ENABLE_URI_00_ERROR", #endif #if SQLITE_ENABLE_VFSTRACE "ENABLE_VFSTRACE", #endif #if SQLITE_ENABLE_WHERETRACE "ENABLE_WHERETRACE", #endif #if SQLITE_ENABLE_ZIPVFS "ENABLE_ZIPVFS", #endif #if SQLITE_EXPLAIN_ESTIMATED_ROWS "EXPLAIN_ESTIMATED_ROWS", #endif #if 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 #if SQLITE_FTS5_ENABLE_TEST_MI "FTS5_ENABLE_TEST_MI", #endif #if SQLITE_FTS5_NO_WITHOUT_ROWID "FTS5_NO_WITHOUT_ROWID", #endif #if SQLITE_HAS_CODEC "HAS_CODEC", #endif #if HAVE_ISNAN || SQLITE_HAVE_ISNAN "HAVE_ISNAN", #endif #if SQLITE_HOMEGROWN_RECURSIVE_MUTEX "HOMEGROWN_RECURSIVE_MUTEX", #endif #if SQLITE_IGNORE_AFP_LOCK_ERRORS "IGNORE_AFP_LOCK_ERRORS", #endif #if SQLITE_IGNORE_FLOCK_LOCK_ERRORS "IGNORE_FLOCK_LOCK_ERRORS", #endif #if SQLITE_INLINE_MEMCPY "INLINE_MEMCPY", #endif #if SQLITE_INT64_TYPE "INT64_TYPE", #endif #ifdef SQLITE_INTEGRITY_CHECK_ERROR_MAX "INTEGRITY_CHECK_ERROR_MAX=" CTIMEOPT_VAL(SQLITE_INTEGRITY_CHECK_ERROR_MAX), #endif #if SQLITE_LIKE_DOESNT_MATCH_BLOBS "LIKE_DOESNT_MATCH_BLOBS", #endif #if SQLITE_LOCK_TRACE "LOCK_TRACE", #endif #if 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), |
︙ | ︙ | |||
464 465 466 467 468 469 470 | #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 | | | | | > > > | | | | > > > | | | | | | | | | | | | > > > | | | | | | | | | < < < | | | | | | | | | < < < < < < | | | | | | | | | | | | | | | | | | | | | | < | < | | | | | | | | | > > > | | < | < | | | | | | | | < < < | | | | | | | | | | | | | > > | | 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 | #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 #if SQLITE_MEMDEBUG "MEMDEBUG", #endif #if SQLITE_MIXED_ENDIAN_64BIT_FLOAT "MIXED_ENDIAN_64BIT_FLOAT", #endif #if SQLITE_MMAP_READWRITE "MMAP_READWRITE", #endif #if SQLITE_MUTEX_NOOP "MUTEX_NOOP", #endif #if SQLITE_MUTEX_NREF "MUTEX_NREF", #endif #if SQLITE_MUTEX_OMIT "MUTEX_OMIT", #endif #if SQLITE_MUTEX_PTHREADS "MUTEX_PTHREADS", #endif #if SQLITE_MUTEX_W32 "MUTEX_W32", #endif #if SQLITE_NEED_ERR_NAME "NEED_ERR_NAME", #endif #if SQLITE_NOINLINE "NOINLINE", #endif #if SQLITE_NO_SYNC "NO_SYNC", #endif #if SQLITE_OMIT_ALTERTABLE "OMIT_ALTERTABLE", #endif #if SQLITE_OMIT_ANALYZE "OMIT_ANALYZE", #endif #if SQLITE_OMIT_ATTACH "OMIT_ATTACH", #endif #if SQLITE_OMIT_AUTHORIZATION "OMIT_AUTHORIZATION", #endif #if SQLITE_OMIT_AUTOINCREMENT "OMIT_AUTOINCREMENT", #endif #if SQLITE_OMIT_AUTOINIT "OMIT_AUTOINIT", #endif #if SQLITE_OMIT_AUTOMATIC_INDEX "OMIT_AUTOMATIC_INDEX", #endif #if SQLITE_OMIT_AUTORESET "OMIT_AUTORESET", #endif #if SQLITE_OMIT_AUTOVACUUM "OMIT_AUTOVACUUM", #endif #if SQLITE_OMIT_BETWEEN_OPTIMIZATION "OMIT_BETWEEN_OPTIMIZATION", #endif #if SQLITE_OMIT_BLOB_LITERAL "OMIT_BLOB_LITERAL", #endif #if SQLITE_OMIT_BTREECOUNT "OMIT_BTREECOUNT", #endif #if SQLITE_OMIT_CAST "OMIT_CAST", #endif #if SQLITE_OMIT_CHECK "OMIT_CHECK", #endif #if SQLITE_OMIT_COMPLETE "OMIT_COMPLETE", #endif #if SQLITE_OMIT_COMPOUND_SELECT "OMIT_COMPOUND_SELECT", #endif #if SQLITE_OMIT_CONFLICT_CLAUSE "OMIT_CONFLICT_CLAUSE", #endif #if SQLITE_OMIT_CTE "OMIT_CTE", #endif #if SQLITE_OMIT_DATETIME_FUNCS "OMIT_DATETIME_FUNCS", #endif #if SQLITE_OMIT_DECLTYPE "OMIT_DECLTYPE", #endif #if SQLITE_OMIT_DEPRECATED "OMIT_DEPRECATED", #endif #if SQLITE_OMIT_DISKIO "OMIT_DISKIO", #endif #if SQLITE_OMIT_EXPLAIN "OMIT_EXPLAIN", #endif #if SQLITE_OMIT_FLAG_PRAGMAS "OMIT_FLAG_PRAGMAS", #endif #if SQLITE_OMIT_FLOATING_POINT "OMIT_FLOATING_POINT", #endif #if SQLITE_OMIT_FOREIGN_KEY "OMIT_FOREIGN_KEY", #endif #if SQLITE_OMIT_GET_TABLE "OMIT_GET_TABLE", #endif #if SQLITE_OMIT_HEX_INTEGER "OMIT_HEX_INTEGER", #endif #if SQLITE_OMIT_INCRBLOB "OMIT_INCRBLOB", #endif #if SQLITE_OMIT_INTEGRITY_CHECK "OMIT_INTEGRITY_CHECK", #endif #if SQLITE_OMIT_LIKE_OPTIMIZATION "OMIT_LIKE_OPTIMIZATION", #endif #if SQLITE_OMIT_LOAD_EXTENSION "OMIT_LOAD_EXTENSION", #endif #if SQLITE_OMIT_LOCALTIME "OMIT_LOCALTIME", #endif #if SQLITE_OMIT_LOOKASIDE "OMIT_LOOKASIDE", #endif #if SQLITE_OMIT_MEMORYDB "OMIT_MEMORYDB", #endif #if SQLITE_OMIT_OR_OPTIMIZATION "OMIT_OR_OPTIMIZATION", #endif #if SQLITE_OMIT_PAGER_PRAGMAS "OMIT_PAGER_PRAGMAS", #endif #if SQLITE_OMIT_PARSER_TRACE "OMIT_PARSER_TRACE", #endif #if SQLITE_OMIT_POPEN "OMIT_POPEN", #endif #if SQLITE_OMIT_PRAGMA "OMIT_PRAGMA", #endif #if SQLITE_OMIT_PROGRESS_CALLBACK "OMIT_PROGRESS_CALLBACK", #endif #if SQLITE_OMIT_QUICKBALANCE "OMIT_QUICKBALANCE", #endif #if SQLITE_OMIT_REINDEX "OMIT_REINDEX", #endif #if SQLITE_OMIT_SCHEMA_PRAGMAS "OMIT_SCHEMA_PRAGMAS", #endif #if SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS "OMIT_SCHEMA_VERSION_PRAGMAS", #endif #if SQLITE_OMIT_SHARED_CACHE "OMIT_SHARED_CACHE", #endif #if SQLITE_OMIT_SHUTDOWN_DIRECTORIES "OMIT_SHUTDOWN_DIRECTORIES", #endif #if SQLITE_OMIT_SUBQUERY "OMIT_SUBQUERY", #endif #if SQLITE_OMIT_TCL_VARIABLE "OMIT_TCL_VARIABLE", #endif #if SQLITE_OMIT_TEMPDB "OMIT_TEMPDB", #endif #if SQLITE_OMIT_TEST_CONTROL "OMIT_TEST_CONTROL", #endif #if SQLITE_OMIT_TRACE "OMIT_TRACE", #endif #if SQLITE_OMIT_TRIGGER "OMIT_TRIGGER", #endif #if SQLITE_OMIT_TRUNCATE_OPTIMIZATION "OMIT_TRUNCATE_OPTIMIZATION", #endif #if SQLITE_OMIT_UTF16 "OMIT_UTF16", #endif #if SQLITE_OMIT_VACUUM "OMIT_VACUUM", #endif #if SQLITE_OMIT_VIEW "OMIT_VIEW", #endif #if SQLITE_OMIT_VIRTUALTABLE "OMIT_VIRTUALTABLE", #endif #if SQLITE_OMIT_WAL "OMIT_WAL", #endif #if SQLITE_OMIT_WSD "OMIT_WSD", #endif #if SQLITE_OMIT_XFER_OPT "OMIT_XFER_OPT", #endif #if SQLITE_PCACHE_SEPARATE_HEADER "PCACHE_SEPARATE_HEADER", #endif #if SQLITE_PERFORMANCE_TRACE "PERFORMANCE_TRACE", #endif #if SQLITE_POWERSAFE_OVERWRITE "POWERSAFE_OVERWRITE", #endif #if SQLITE_PREFER_PROXY_LOCKING "PREFER_PROXY_LOCKING", #endif #if SQLITE_PROXY_DEBUG "PROXY_DEBUG", #endif #if SQLITE_REVERSE_UNORDERED_SELECTS "REVERSE_UNORDERED_SELECTS", #endif #if SQLITE_RTREE_INT_ONLY "RTREE_INT_ONLY", #endif #if SQLITE_SECURE_DELETE "SECURE_DELETE", #endif #if SQLITE_SMALL_STACK "SMALL_STACK", #endif #ifdef SQLITE_SORTER_PMASZ "SORTER_PMASZ=" CTIMEOPT_VAL(SQLITE_SORTER_PMASZ), #endif #if 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 #if SQLITE_SUBSTR_COMPATIBILITY "SUBSTR_COMPATIBILITY", #endif #if SQLITE_SYSTEM_MALLOC "SYSTEM_MALLOC", #endif #if SQLITE_TCL "TCL", #endif #ifdef SQLITE_TEMP_STORE "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE), #endif #if SQLITE_TEST "TEST", #endif #if defined(SQLITE_THREADSAFE) "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE), #elif defined(THREADSAFE) "THREADSAFE=" CTIMEOPT_VAL(THREADSAFE), #else "THREADSAFE=1", #endif #if SQLITE_UNLINK_AFTER_CLOSE "UNLINK_AFTER_CLOSE", #endif #if SQLITE_UNTESTABLE "UNTESTABLE", #endif #if SQLITE_USER_AUTHENTICATION "USER_AUTHENTICATION", #endif #if SQLITE_USE_ALLOCA "USE_ALLOCA", #endif #if SQLITE_USE_FCNTL_TRACE "USE_FCNTL_TRACE", #endif #if SQLITE_USE_URI "USE_URI", #endif #if SQLITE_VDBE_COVERAGE "VDBE_COVERAGE", #endif #if SQLITE_WIN32_MALLOC "WIN32_MALLOC", #endif #if 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.
︙ | ︙ | |||
272 273 274 275 276 277 278 | A = Y/100; B = 2 - A + (A/4); X1 = 36525*(Y+4716)/100; X2 = 306001*(M+1)/10000; p->iJD = (sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000); p->validJD = 1; if( p->validHMS ){ | | | 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | A = Y/100; B = 2 - A + (A/4); X1 = 36525*(Y+4716)/100; X2 = 306001*(M+1)/10000; p->iJD = (sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000); p->validJD = 1; if( p->validHMS ){ p->iJD += p->h*3600000 + p->m*60000 + (sqlite3_int64)(p->s*1000); if( p->validTZ ){ p->iJD -= p->tz*60000; p->validYMD = 0; p->validHMS = 0; p->validTZ = 0; } } |
︙ | ︙ | |||
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) ){ setRawDateNumber(p, r); return 0; } return 1; } /* The julian day number for 9999-12-31 23:59:59.999 is 5373484.4999999. |
︙ | ︙ | |||
499 500 501 502 503 504 505 | /* ** The following routine implements the rough equivalent of localtime_r() ** using whatever operating-system specific localtime facility that ** is available. This routine returns 0 on success and ** non-zero on any kind of error. ** | | | < < | | < < < < < < < < < < | < < < < < < | > > > > > | | | > > < > | < < | | | | | > > > > > > > | | | < < < < > | | | | | | | | | | | | | > | > > | | | | | | | | | | | 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 | /* ** The following routine implements the rough equivalent of localtime_r() ** using whatever operating-system specific localtime facility that ** is available. This routine returns 0 on success and ** non-zero on any kind of error. ** ** If the sqlite3GlobalConfig.bLocaltimeFault variable is true then this ** routine will always fail. ** ** EVIDENCE-OF: R-62172-00036 In this implementation, the standard C ** library function localtime_r() is used to assist in the calculation of ** 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_MASTER); #endif sqlite3_mutex_enter(mutex); pX = localtime(t); #ifndef SQLITE_UNTESTABLE if( sqlite3GlobalConfig.bLocaltimeFault ) pX = 0; #endif if( pX ) *pTm = *pX; sqlite3_mutex_leave(mutex); rc = pX==0; #else #ifndef SQLITE_UNTESTABLE if( sqlite3GlobalConfig.bLocaltimeFault ) return 1; #endif #if HAVE_LOCALTIME_R rc = localtime_r(t, pTm)==0; #else rc = localtime_s(pTm, t); #endif /* HAVE_LOCALTIME_R */ #endif /* HAVE_LOCALTIME_R || HAVE_LOCALTIME_S */ return rc; } #endif /* SQLITE_OMIT_LOCALTIME */ #ifndef SQLITE_OMIT_LOCALTIME /* ** Compute the difference (in milliseconds) between localtime and UTC ** (a.k.a. GMT) for the time value p where p is in UTC. If no error occurs, ** return this value and set *pRc to SQLITE_OK. ** ** Or, if an error does occur, set *pRc to SQLITE_ERROR. The returned value ** is undefined in this case. */ static sqlite3_int64 localtimeOffset( DateTime *p, /* Date at which to calculate offset */ sqlite3_context *pCtx, /* Write error here if one occurs */ int *pRc /* OUT: Error code. SQLITE_OK or ERROR */ ){ DateTime x, y; time_t t; struct tm sLocal; /* Initialize the contents of sLocal to avoid a compiler warning. */ memset(&sLocal, 0, sizeof(sLocal)); x = *p; computeYMD_HMS(&x); if( x.Y<1971 || x.Y>=2038 ){ /* EVIDENCE-OF: R-55269-29598 The localtime_r() C function normally only ** works for years between 1970 and 2037. For dates outside this range, ** SQLite attempts to map the year into an equivalent year within this ** range, do the calculation, then map the year back. */ x.Y = 2000; x.M = 1; x.D = 1; x.h = 0; x.m = 0; x.s = 0.0; } else { int s = (int)(x.s + 0.5); x.s = s; } x.tz = 0; x.validJD = 0; computeJD(&x); t = (time_t)(x.iJD/1000 - 21086676*(i64)10000); if( osLocaltime(&t, &sLocal) ){ sqlite3_result_error(pCtx, "local time unavailable", -1); *pRc = SQLITE_ERROR; return 0; } y.Y = sLocal.tm_year + 1900; y.M = sLocal.tm_mon + 1; y.D = sLocal.tm_mday; y.h = sLocal.tm_hour; y.m = sLocal.tm_min; y.s = sLocal.tm_sec; y.validYMD = 1; y.validHMS = 1; y.validJD = 0; y.rawS = 0; y.validTZ = 0; y.isError = 0; computeJD(&y); *pRc = SQLITE_OK; return y.iJD - x.iJD; } #endif /* SQLITE_OMIT_LOCALTIME */ /* ** The following table defines various date transformations of the form ** ** 'NNN days' ** ** Where NNN is an arbitrary floating-point number and "days" can be one ** of several units of time. */ 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, 86400000.0/(24.0*60.0*60.0) }, { 0, 6, "minute", 7737817680.0, 86400000.0/(24.0*60.0) }, { 0, 4, "hour", 128963628.0, 86400000.0/24.0 }, { 0, 3, "day", 5373485.0, 86400000.0 }, { 1, 5, "month", 176546.0, 30.0*86400000.0 }, { 2, 4, "year", 14713.0, 365.0*86400000.0 }, }; /* ** Process a modifier to a date-time stamp. The modifiers are ** as follows: ** ** NNN days |
︙ | ︙ | |||
659 660 661 662 663 664 665 | ** to context pCtx. If the error is an unrecognized modifier, no error is ** written to pCtx. */ static int parseModifier( sqlite3_context *pCtx, /* Function context */ const char *z, /* The text of the modifier */ int n, /* Length of zMod in bytes */ | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | > < | < < < < | < < < < < < < < | | < < < < | > | > | | > | | | 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 | ** to context pCtx. If the error is an unrecognized modifier, no error is ** written to pCtx. */ static int parseModifier( sqlite3_context *pCtx, /* Function context */ const char *z, /* The text of the modifier */ int n, /* Length of zMod in bytes */ DateTime *p /* The date/time value to be modified */ ){ int rc = 1; double r; switch(sqlite3UpperToLower[(u8)z[0]] ){ #ifndef SQLITE_OMIT_LOCALTIME case 'l': { /* localtime ** ** Assuming the current time value is UTC (a.k.a. GMT), shift it to ** show local time. */ if( sqlite3_stricmp(z, "localtime")==0 && sqlite3NotPureFunc(pCtx) ){ computeJD(p); p->iJD += localtimeOffset(p, pCtx, &rc); clearYMD_HMS_TZ(p); } break; } #endif case 'u': { /* ** unixepoch ** ** 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; p->validJD = 1; p->rawS = 0; rc = 0; } } #ifndef SQLITE_OMIT_LOCALTIME else if( sqlite3_stricmp(z, "utc")==0 && sqlite3NotPureFunc(pCtx) ){ if( p->tzSet==0 ){ sqlite3_int64 c1; computeJD(p); c1 = localtimeOffset(p, pCtx, &rc); if( rc==SQLITE_OK ){ p->iJD -= c1; clearYMD_HMS_TZ(p); p->iJD += c1 - localtimeOffset(p, pCtx, &rc); } p->tzSet = 1; }else{ rc = SQLITE_OK; } } #endif break; } case 'w': { /* ** 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) && (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; if( Z>n ) Z -= 7; |
︙ | ︙ | |||
839 840 841 842 843 844 845 | 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) ){ 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 |
︙ | ︙ | |||
882 883 884 885 886 887 888 | rc = 1; rRounder = r<0 ? -0.5 : +0.5; for(i=0; i<ArraySize(aXformType); i++){ if( aXformType[i].nName==n && sqlite3_strnicmp(aXformType[i].zName, z, n)==0 && r>-aXformType[i].rLimit && r<aXformType[i].rLimit ){ | | | < | < | | 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 | rc = 1; rRounder = r<0 ? -0.5 : +0.5; for(i=0; i<ArraySize(aXformType); i++){ if( aXformType[i].nName==n && sqlite3_strnicmp(aXformType[i].zName, z, n)==0 && r>-aXformType[i].rLimit && r<aXformType[i].rLimit ){ switch( aXformType[i].eType ){ case 1: { /* Special processing to add months */ int x; computeYMD_HMS(p); p->M += (int)r; x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12; p->Y += x; p->M -= x*12; p->validJD = 0; r -= (int)r; break; } case 2: { /* Special processing to add years */ int y = (int)r; computeYMD_HMS(p); p->Y += y; p->validJD = 0; r -= (int)r; break; } } computeJD(p); p->iJD += (sqlite3_int64)(r*aXformType[i].rXform + rRounder); rc = 0; break; } } clearYMD_HMS_TZ(p); break; } |
︙ | ︙ | |||
941 942 943 944 945 946 947 | DateTime *p ){ int i, n; const unsigned char *z; int eType; memset(p, 0, sizeof(*p)); if( argc==0 ){ | < | | 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 | 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]); if( !z || parseDateOrTime(context, (char*)z, p) ){ return 1; } } for(i=1; i<argc; i++){ z = sqlite3_value_text(argv[i]); n = sqlite3_value_bytes(argv[i]); if( z==0 || parseModifier(context, (char*)z, n, p) ) return 1; } computeJD(p); if( p->isError || !validJulianDay(p->iJD) ) return 1; return 0; } |
︙ | ︙ | |||
986 987 988 989 990 991 992 | DateTime x; if( isDate(context, argc, argv, &x)==0 ){ computeJD(&x); sqlite3_result_double(context, x.iJD/86400000.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 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 | DateTime x; if( isDate(context, argc, argv, &x)==0 ){ computeJD(&x); sqlite3_result_double(context, x.iJD/86400000.0); } } /* ** datetime( TIMESTRING, MOD, MOD, ...) ** ** Return YYYY-MM-DD HH:MM:SS */ static void datetimeFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ DateTime x; if( isDate(context, argc, argv, &x)==0 ){ char zBuf[100]; computeYMD_HMS(&x); sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d %02d:%02d:%02d", x.Y, x.M, x.D, x.h, x.m, (int)(x.s)); sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); } } /* ** time( TIMESTRING, MOD, MOD, ...) ** ** Return HH:MM:SS */ static void timeFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ DateTime x; if( isDate(context, argc, argv, &x)==0 ){ char zBuf[100]; computeHMS(&x); sqlite3_snprintf(sizeof(zBuf), zBuf, "%02d:%02d:%02d", x.h, x.m, (int)x.s); sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); } } /* ** date( TIMESTRING, MOD, MOD, ...) ** ** Return YYYY-MM-DD */ static void dateFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ DateTime x; if( isDate(context, argc, argv, &x)==0 ){ char zBuf[100]; computeYMD(&x); sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d", x.Y, x.M, x.D); sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); } } /* ** strftime( FORMAT, TIMESTRING, MOD, MOD, ...) ** ** Return a string described by FORMAT. Conversions as follows: |
︙ | ︙ | |||
1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 | */ static void strftimeFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ DateTime x; size_t i,j; sqlite3 *db; const char *zFmt; | > > < | < < < < < | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > | < < > > > > > > > > > > > | > > | | | > > > > > > > > > > | | | | > | | | < < < | | | | | | | | | | | | | > | | > | | | | | > | | | < < < | < < < | > | | | | < | < < | < | | | | | | | < < < < | < < < > | > | 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 | */ static void strftimeFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ DateTime x; u64 n; size_t i,j; char *z; sqlite3 *db; const char *zFmt; char zBuf[100]; 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); for(i=0, n=1; zFmt[i]; i++, n++){ if( zFmt[i]=='%' ){ switch( zFmt[i+1] ){ case 'd': case 'H': case 'm': case 'M': case 'S': case 'W': n++; /* fall thru */ case 'w': case '%': break; case 'f': n += 8; break; case 'j': n += 3; break; case 'Y': n += 8; break; case 's': case 'J': n += 50; break; default: return; /* ERROR. return a NULL */ } i++; } } testcase( n==sizeof(zBuf)-1 ); testcase( n==sizeof(zBuf) ); testcase( n==(u64)db->aLimit[SQLITE_LIMIT_LENGTH]+1 ); testcase( n==(u64)db->aLimit[SQLITE_LIMIT_LENGTH] ); if( n<sizeof(zBuf) ){ z = zBuf; }else if( n>(u64)db->aLimit[SQLITE_LIMIT_LENGTH] ){ sqlite3_result_error_toobig(context); return; }else{ z = sqlite3DbMallocRawNN(db, (int)n); if( z==0 ){ sqlite3_result_error_nomem(context); return; } } computeJD(&x); computeYMD_HMS(&x); for(i=j=0; zFmt[i]; i++){ if( zFmt[i]!='%' ){ z[j++] = zFmt[i]; }else{ i++; switch( zFmt[i] ){ case 'd': sqlite3_snprintf(3, &z[j],"%02d",x.D); j+=2; break; case 'f': { double s = x.s; if( s>59.999 ) s = 59.999; sqlite3_snprintf(7, &z[j],"%06.3f", s); j += sqlite3Strlen30(&z[j]); break; } case 'H': sqlite3_snprintf(3, &z[j],"%02d",x.h); j+=2; 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_snprintf(3, &z[j],"%02d",(nDay+7-wd)/7); j += 2; }else{ sqlite3_snprintf(4, &z[j],"%03d",nDay+1); j += 3; } break; } case 'J': { sqlite3_snprintf(20, &z[j],"%.16g",x.iJD/86400000.0); j+=sqlite3Strlen30(&z[j]); break; } case 'm': sqlite3_snprintf(3, &z[j],"%02d",x.M); j+=2; break; case 'M': sqlite3_snprintf(3, &z[j],"%02d",x.m); j+=2; break; case 's': { sqlite3_snprintf(30,&z[j],"%lld", (i64)(x.iJD/1000 - 21086676*(i64)10000)); j += sqlite3Strlen30(&z[j]); break; } case 'S': sqlite3_snprintf(3,&z[j],"%02d",(int)x.s); j+=2; break; case 'w': { z[j++] = (char)(((x.iJD+129600000)/86400000) % 7) + '0'; break; } case 'Y': { sqlite3_snprintf(5,&z[j],"%04d",x.Y); j+=sqlite3Strlen30(&z[j]); break; } default: z[j++] = '%'; break; } } } z[j] = 0; sqlite3_result_text(context, z, -1, z==zBuf ? SQLITE_TRANSIENT : SQLITE_DYNAMIC); } /* ** current_time() ** ** This function returns the same value as time('now'). */ |
︙ | ︙ | |||
1314 1315 1316 1317 1318 1319 1320 | iT = sqlite3StmtCurrentTime(context); if( iT<=0 ) return; t = iT/1000 - 10000*(sqlite3_int64)21086676; #if HAVE_GMTIME_R pTm = gmtime_r(&t, &sNow); #else | | | < | 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 | 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_MASTER)); pTm = gmtime(&t); if( pTm ) memcpy(&sNow, pTm, sizeof(sNow)); sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); #endif if( pTm ){ strftime(zBuf, 20, zFormat, &sNow); sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); } } #endif /* ** This function registered all of the above C functions as SQL ** functions. This should be the only routine in this file with ** external linkage. */ void sqlite3RegisterDateTimeFunctions(void){ static FuncDef aDateTimeFuncs[] = { #ifndef SQLITE_OMIT_DATETIME_FUNCS PURE_DATE(julianday, -1, 0, 0, juliandayFunc ), PURE_DATE(date, -1, 0, 0, dateFunc ), PURE_DATE(time, -1, 0, 0, timeFunc ), PURE_DATE(datetime, -1, 0, 0, datetimeFunc ), PURE_DATE(strftime, -1, 0, 0, strftimeFunc ), DFUNCTION(current_time, 0, 0, 0, ctimeFunc ), DFUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc), DFUNCTION(current_date, 0, 0, 0, cdateFunc ), |
︙ | ︙ |
Changes to src/dbpage.c.
︙ | ︙ | |||
68 69 70 71 72 73 74 | void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ DbpageTable *pTab = 0; int rc = SQLITE_OK; | < < < < < | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | void *pAux, 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; } |
︙ | ︙ | |||
110 111 112 113 114 115 116 | ** 1 schema=main, pgno=?1 ** 2 schema=?1, full table scan ** 3 schema=?1, pgno=?2 */ static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ int i; int iPlan = 0; | < | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | ** 1 schema=main, pgno=?1 ** 2 schema=?1, full table scan ** 3 schema=?1, pgno=?2 */ static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ int i; int iPlan = 0; /* If there is a schema= constraint, it must be honored. Report a ** ridiculously large estimated cost if the schema= constraint is ** unavailable */ for(i=0; i<pIdxInfo->nConstraint; i++){ struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[i]; |
︙ | ︙ | |||
157 158 159 160 161 162 163 | if( pIdxInfo->nOrderBy>=1 && pIdxInfo->aOrderBy[0].iColumn<=0 && pIdxInfo->aOrderBy[0].desc==0 ){ pIdxInfo->orderByConsumed = 1; } | < | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | if( pIdxInfo->nOrderBy>=1 && pIdxInfo->aOrderBy[0].iColumn<=0 && pIdxInfo->aOrderBy[0].desc==0 ){ pIdxInfo->orderByConsumed = 1; } return SQLITE_OK; } /* ** Open a new dbpagevfs cursor. */ static int dbpageOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ |
︙ | ︙ | |||
226 227 228 229 230 231 232 | ){ DbpageCursor *pCsr = (DbpageCursor *)pCursor; DbpageTable *pTab = (DbpageTable *)pCursor->pVtab; int rc; sqlite3 *db = pTab->db; Btree *pBt; | < < | | 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 | ){ DbpageCursor *pCsr = (DbpageCursor *)pCursor; DbpageTable *pTab = (DbpageTable *)pCursor->pVtab; int rc; sqlite3 *db = pTab->db; Btree *pBt; /* Default setting is no rows of result */ pCsr->pgno = 1; pCsr->mxPgno = 0; if( idxNum & 2 ){ const char *zSchema; assert( argc>=1 ); zSchema = (const char*)sqlite3_value_text(argv[0]); pCsr->iDb = sqlite3FindDbName(db, zSchema); if( pCsr->iDb<0 ) return SQLITE_OK; }else{ pCsr->iDb = 0; } pBt = db->aDb[pCsr->iDb].pBt; if( pBt==0 ) return SQLITE_OK; pCsr->pPager = sqlite3BtreePager(pBt); pCsr->szPage = sqlite3BtreeGetPageSize(pBt); pCsr->mxPgno = sqlite3BtreeLastPage(pBt); if( idxNum & 1 ){ assert( argc>(idxNum>>1) ); pCsr->pgno = sqlite3_value_int(argv[idxNum>>1]); if( pCsr->pgno<1 || pCsr->pgno>pCsr->mxPgno ){ |
︙ | ︙ | |||
277 278 279 280 281 282 283 | switch( i ){ case 0: { /* pgno */ sqlite3_result_int(ctx, pCsr->pgno); break; } case 1: { /* data */ DbPage *pDbPage = 0; | < < < < < | | | | | | < | | 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 | switch( i ){ case 0: { /* pgno */ sqlite3_result_int(ctx, pCsr->pgno); break; } case 1: { /* data */ DbPage *pDbPage = 0; rc = sqlite3PagerGet(pCsr->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0); if( rc==SQLITE_OK ){ sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pCsr->szPage, SQLITE_TRANSIENT); } sqlite3PagerUnref(pDbPage); break; } default: { /* schema */ sqlite3 *db = sqlite3_context_db_handle(ctx); sqlite3_result_text(ctx, db->aDb[pCsr->iDb].zDbSName, -1, SQLITE_STATIC); break; } } return SQLITE_OK; } static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ DbpageCursor *pCsr = (DbpageCursor *)pCursor; *pRowid = pCsr->pgno; return SQLITE_OK; } |
︙ | ︙ | |||
323 324 325 326 327 328 329 | char *zErr = 0; const char *zSchema; int iDb; Btree *pBt; Pager *pPager; int szPage; | < < | < | | | < < < | | | > > | 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 | char *zErr = 0; const char *zSchema; int iDb; Btree *pBt; Pager *pPager; int szPage; if( pTab->db->flags & SQLITE_Defensive ){ zErr = "read-only"; goto update_fail; } if( argc==1 ){ zErr = "cannot delete"; goto update_fail; } pgno = sqlite3_value_int(argv[0]); if( (Pgno)sqlite3_value_int(argv[1])!=pgno ){ zErr = "cannot insert"; goto update_fail; } zSchema = (const char*)sqlite3_value_text(argv[4]); iDb = zSchema ? sqlite3FindDbName(pTab->db, zSchema) : -1; if( iDb<0 ){ zErr = "no such schema"; goto update_fail; } pBt = pTab->db->aDb[iDb].pBt; if( pgno<1 || pBt==0 || pgno>(int)sqlite3BtreeLastPage(pBt) ){ zErr = "bad page number"; goto update_fail; } szPage = sqlite3BtreeGetPageSize(pBt); if( sqlite3_value_type(argv[3])!=SQLITE_BLOB || sqlite3_value_bytes(argv[3])!=szPage ){ zErr = "bad page value"; goto update_fail; } pPager = sqlite3BtreePager(pBt); rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0); if( rc==SQLITE_OK ){ rc = sqlite3PagerWrite(pDbPage); if( rc==SQLITE_OK ){ memcpy(sqlite3PagerGetData(pDbPage), sqlite3_value_blob(argv[3]), szPage); } } sqlite3PagerUnref(pDbPage); return rc; update_fail: sqlite3_free(pVtab->zErrMsg); |
︙ | ︙ | |||
387 388 389 390 391 392 393 | */ static int dbpageBegin(sqlite3_vtab *pVtab){ DbpageTable *pTab = (DbpageTable *)pVtab; sqlite3 *db = pTab->db; int i; for(i=0; i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; | | | 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 | */ static int dbpageBegin(sqlite3_vtab *pVtab){ DbpageTable *pTab = (DbpageTable *)pVtab; sqlite3 *db = pTab->db; int i; for(i=0; i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt ) sqlite3BtreeBeginTrans(pBt, 1, 0); } return SQLITE_OK; } /* ** Invoke this routine to register the "dbpage" virtual table module |
︙ | ︙ |
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 | ** 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 formatting ** 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) /* ** 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 '/'. ** |
︙ | ︙ | |||
61 62 63 64 65 66 67 | ** ** 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 */ | | | | | | | | | | | | | | < | | < < < | | | > | < | | < | < > < | | | | < | | | < < | | | > > | < < < < < < < < < | | < < < | < < < < < < < < < < < < < < | < | | < < < | < > < < < | < < | | 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 | ** ** 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 */ #define VTAB_SCHEMA \ "CREATE TABLE xx( " \ " name TEXT, /* Name of table or index */" \ " path TEXT, /* Path to page from root */" \ " pageno INTEGER, /* Page number */" \ " pagetype TEXT, /* 'internal', 'leaf' or 'overflow' */" \ " ncell INTEGER, /* Cells on page (0 for overflow) */" \ " payload INTEGER, /* Bytes of payload on this page */" \ " unused INTEGER, /* Bytes of unused space on this page */" \ " mx_payload INTEGER, /* Largest payload size of all cells */" \ " pgoffset INTEGER, /* Offset of page in file */" \ " pgsize INTEGER, /* Size of the page */" \ " schema TEXT HIDDEN /* Database schema being analyzed */" \ ");" typedef struct StatTable StatTable; typedef struct StatCursor StatCursor; typedef struct StatPage StatPage; typedef struct StatCell StatCell; 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[] */ }; struct StatPage { u32 iPgno; DbPage *pPg; int iCell; 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 this page */ }; struct StatCursor { sqlite3_vtab_cursor base; sqlite3_stmt *pStmt; /* Iterates through set of root pages */ int isEof; /* After pStmt has returned SQLITE_DONE */ int iDb; /* Schema used for this query */ StatPage aPage[32]; int iPage; /* Current entry in aPage[] */ /* Values to return. */ char *zName; /* Value of 'name' column */ char *zPath; /* Value of 'path' column */ u32 iPageno; /* Value of 'pageno' column */ char *zPagetype; /* Value of 'pagetype' column */ int nCell; /* Value of 'ncell' column */ int nPayload; /* Value of 'payload' column */ int nUnused; /* Value of 'unused' column */ int nMxPayload; /* Value of 'mx_payload' column */ i64 iOffset; /* Value of 'pgOffset' column */ int szPage; /* Value of 'pgSize' column */ }; struct StatTable { sqlite3_vtab base; sqlite3 *db; int iDb; /* Index of database to analyze */ }; #ifndef get2byte # define get2byte(x) ((x)[0]<<8 | (x)[1]) #endif /* ** Connect to or create a statvfs virtual table. */ static int statConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ StatTable *pTab = 0; int rc = SQLITE_OK; int iDb; if( argc>=4 ){ Token nm; sqlite3TokenInit(&nm, (char*)argv[3]); iDb = sqlite3FindDb(db, &nm); if( iDb<0 ){ *pzErr = sqlite3_mprintf("no such database: %s", argv[3]); return SQLITE_ERROR; } }else{ iDb = 0; } rc = sqlite3_declare_vtab(db, VTAB_SCHEMA); 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 a statvfs virtual table. */ static int statDisconnect(sqlite3_vtab *pVtab){ sqlite3_free(pVtab); return SQLITE_OK; } /* ** There is no "best-index". This virtual table always does a linear ** scan. However, a schema=? constraint should cause this table to ** operate on a different database schema, so check for it. ** ** idxNum is normally 0, but will be 1 if a schema=? constraint exists. */ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ int i; /* 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].iColumn!=10 ) continue; if( pIdxInfo->aConstraint[i].usable==0 ) return SQLITE_CONSTRAINT; if( pIdxInfo->aConstraint[i].op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; pIdxInfo->idxNum = 1; pIdxInfo->estimatedCost = 1.0; pIdxInfo->aConstraintUsage[i].argvIndex = 1; pIdxInfo->aConstraintUsage[i].omit = 1; break; } /* 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; } return SQLITE_OK; } /* ** Open a new statvfs 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 ){ |
︙ | ︙ | |||
312 313 314 315 316 317 318 | sqlite3_free(p->aCell); } p->nCell = 0; p->aCell = 0; } static void statClearPage(StatPage *p){ | < > < < | < < < < < < < < < < < < < < < | < < < < < | | > | < < < | | 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 | sqlite3_free(p->aCell); } p->nCell = 0; p->aCell = 0; } static void statClearPage(StatPage *p){ statClearCells(p); sqlite3PagerUnref(p->pPg); sqlite3_free(p->zPath); memset(p, 0, sizeof(StatPage)); } static void statResetCsr(StatCursor *pCsr){ int i; sqlite3_reset(pCsr->pStmt); for(i=0; i<ArraySize(pCsr->aPage); i++){ statClearPage(&pCsr->aPage[i]); } pCsr->iPage = 0; sqlite3_free(pCsr->zPath); pCsr->zPath = 0; pCsr->isEof = 0; } /* ** Close a statvfs cursor. */ static int statClose(sqlite3_vtab_cursor *pCursor){ StatCursor *pCsr = (StatCursor *)pCursor; statResetCsr(pCsr); sqlite3_finalize(pCsr->pStmt); sqlite3_free(pCsr); return SQLITE_OK; } static void getLocalPayload( int nUsable, /* Usable bytes per page */ u8 flags, /* Page flags */ int nTotal, /* Total record (payload) size */ int *pnLocal /* OUT: Bytes stored locally */ ){ 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; *pnLocal = nLocal; } static int statDecodePage(Btree *pBt, StatPage *p){ int nUnused; int iOff; int nHdr; int isLeaf; int szPage; u8 *aData = sqlite3PagerGetData(p->pPg); 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 ){ |
︙ | ︙ | |||
458 459 460 461 462 463 464 | 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; | | < | < | 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 | 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; getLocalPayload(nUsable, p->flags, nPayload, &nLocal); 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>nUsable ) 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; |
︙ | ︙ | |||
510 511 512 513 514 515 516 | 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]; | > > > > | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | < < | < | < < | | > | | | > > > | | > > > > | | | < | < < < < < < | < > < < < < < | < < | < < > | 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 | 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]; /* The default page size and offset */ pCsr->szPage = sqlite3BtreeGetPageSize(pBt); pCsr->iOffset = (i64)pCsr->szPage * (pCsr->iPageno - 1); /* If connected to a ZIPVFS backend, override the page size and ** offset with actual values obtained from ZIPVFS. */ fd = sqlite3PagerFile(pPager); x[0] = pCsr->iPageno; if( sqlite3OsFileControl(fd, 230440, &x)==SQLITE_OK ){ pCsr->iOffset = x[0]; pCsr->szPage = (int)x[1]; } } /* ** Move a statvfs cursor to the next entry in the file. */ 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->aPage[0].pPg==0 ){ 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 = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg, 0); pCsr->aPage[0].iPgno = iRoot; pCsr->aPage[0].iCell = 0; pCsr->aPage[0].zPath = z = sqlite3_mprintf("/"); pCsr->iPage = 0; if( z==0 ) rc = SQLITE_NOMEM_BKPT; }else{ pCsr->isEof = 1; return sqlite3_reset(pCsr->pStmt); } }else{ /* Page p itself has already been visited. */ StatPage *p = &pCsr->aPage[pCsr->iPage]; while( p->iCell<p->nCell ){ StatCell *pCell = &p->aCell[p->iCell]; if( pCell->iOvfl<pCell->nOvfl ){ int nUsable; sqlite3BtreeEnter(pBt); nUsable = sqlite3BtreeGetPageSize(pBt) - sqlite3BtreeGetReserveNoMutex(pBt); sqlite3BtreeLeave(pBt); pCsr->zName = (char *)sqlite3_column_text(pCsr->pStmt, 0); pCsr->iPageno = pCell->aOvfl[pCell->iOvfl]; pCsr->zPagetype = "overflow"; pCsr->nCell = 0; pCsr->nMxPayload = 0; pCsr->zPath = z = sqlite3_mprintf( "%s%.3x+%.6x", p->zPath, p->iCell, pCell->iOvfl ); if( pCell->iOvfl<pCell->nOvfl-1 ){ pCsr->nUnused = 0; pCsr->nPayload = nUsable - 4; }else{ pCsr->nPayload = pCell->nLastOvfl; pCsr->nUnused = nUsable - 4 - pCsr->nPayload; } pCell->iOvfl++; statSizeAndOffset(pCsr); return z==0 ? SQLITE_NOMEM_BKPT : SQLITE_OK; } if( p->iRightChildPg ) break; p->iCell++; } if( !p->iRightChildPg || p->iCell>p->nCell ){ statClearPage(p); if( pCsr->iPage==0 ) return statNext(pCursor); pCsr->iPage--; 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 = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg, 0); p[1].iCell = 0; p[1].zPath = z = sqlite3_mprintf("%s%.3x/", p->zPath, p->iCell); p->iCell++; if( z==0 ) rc = SQLITE_NOMEM_BKPT; } /* Populate the StatCursor fields with the values to be returned ** by the xColumn() and xRowid() methods. */ if( rc==SQLITE_OK ){ |
︙ | ︙ | |||
695 696 697 698 699 700 701 | case 0x0A: /* index leaf */ pCsr->zPagetype = "leaf"; break; default: pCsr->zPagetype = "corrupted"; break; } | | | | < | | < | < < < < < < < < < < | < | < < < < < < | < | < < > > | < | | < < < < < | < | < < | | | | | < < < < < < < < < | < < < < | < < | < | | | | < | < | | < < < < | 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 | case 0x0A: /* index leaf */ pCsr->zPagetype = "leaf"; break; default: pCsr->zPagetype = "corrupted"; break; } pCsr->nCell = p->nCell; pCsr->nUnused = p->nUnused; pCsr->nMxPayload = p->nMxPayload; 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; } } return rc; } static int statEof(sqlite3_vtab_cursor *pCursor){ StatCursor *pCsr = (StatCursor *)pCursor; return pCsr->isEof; } 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); char *zSql; int rc = SQLITE_OK; if( idxNum==1 ){ const char *zDbase = (const char*)sqlite3_value_text(argv[0]); pCsr->iDb = sqlite3FindDbName(pTab->db, zDbase); if( pCsr->iDb<0 ){ sqlite3_free(pCursor->pVtab->zErrMsg); pCursor->pVtab->zErrMsg = sqlite3_mprintf("no such schema: %s", zDbase); return pCursor->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM_BKPT; } }else{ pCsr->iDb = pTab->iDb; } statResetCsr(pCsr); sqlite3_finalize(pCsr->pStmt); pCsr->pStmt = 0; zSql = sqlite3_mprintf( "SELECT 'sqlite_master' AS name, 1 AS rootpage, 'table' AS type" " UNION ALL " "SELECT name, rootpage, type" " FROM \"%w\".sqlite_master WHERE rootpage!=0" " ORDER BY name", pTab->db->aDb[pCsr->iDb].zDbSName); 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 ){ 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 */ sqlite3_result_text(ctx, pCsr->zPath, -1, SQLITE_TRANSIENT); break; case 2: /* pageno */ sqlite3_result_int64(ctx, pCsr->iPageno); break; case 3: /* pagetype */ 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 */ sqlite3_result_int64(ctx, pCsr->iOffset); break; case 9: /* pgsize */ sqlite3_result_int(ctx, pCsr->szPage); break; default: { /* schema */ sqlite3 *db = sqlite3_context_db_handle(ctx); int iDb = pCsr->iDb; sqlite3_result_text(ctx, db->aDb[iDb].zDbSName, -1, SQLITE_STATIC); break; } } return SQLITE_OK; } static int statRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ StatCursor *pCsr = (StatCursor *)pCursor; *pRowid = pCsr->iPageno; |
︙ | ︙ |
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){ struct SrcList_item *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( 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_master), 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 && pTab->pSelect ){ sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName); return 1; } #endif return 0; } |
︙ | ︙ | |||
150 151 152 153 154 155 156 | 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); | | | | 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | 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 ); } pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, pOrderBy, SF_IncludeHidden, pLimit); sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur); sqlite3Select(pParse, pSel, &dest); sqlite3SelectDelete(db, pSel); } |
︙ | ︙ | |||
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 ){ | | | | < < | < < < < < | 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 | 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]].zName; 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]].zName); 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(pParse->db, pSrc, 0); pSrc->a[0].pTab = pTab; pSrc->a[0].pIBIndex = 0; /* 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 */ |
︙ | ︙ | |||
315 316 317 318 319 320 321 | #ifndef SQLITE_OMIT_TRIGGER int isView; /* True if attempting to delete from a view */ Trigger *pTrigger; /* List of table triggers, if required */ #endif memset(&sContext, 0, sizeof(sContext)); db = pParse->db; | < | < > | < < < < < < < < | 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 | #ifndef SQLITE_OMIT_TRIGGER int isView; /* True if attempting to delete from a view */ Trigger *pTrigger; /* List of table triggers, if required */ #endif memset(&sContext, 0, sizeof(sContext)); db = pParse->db; if( pParse->nErr || db->mallocFailed ){ goto delete_from_cleanup; } assert( pTabList->nSrc==1 ); /* Locate the table which we want to delete. This table has to be ** put in an SrcList structure because some of the subroutines we ** will be calling are designed to work with multiple tables and expect ** an SrcList* parameter instead of just a Table* parameter. */ pTab = sqlite3SrcListLookup(pParse, pTabList); 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 = pTab->pSelect!=0; #else # define pTrigger 0 # define isView 0 #endif bComplex = pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0); #ifdef SQLITE_OMIT_VIEW # undef isView # define isView 0 #endif #ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT if( !isView ){ pWhere = sqlite3LimitWhere( pParse, pTabList, pWhere, pOrderBy, pLimit, "DELETE" ); |
︙ | ︙ | |||
435 436 437 438 439 440 441 | /* Initialize the counter of the number of rows deleted, if ** we are counting rows. */ if( (db->flags & SQLITE_CountRows)!=0 && !pParse->nested && !pParse->pTriggerTab | < | 383 384 385 386 387 388 389 390 391 392 393 394 395 396 | /* 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. |
︙ | ︙ | |||
469 470 471 472 473 474 475 | sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName); 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 ); | < < < | < | 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 | sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName); 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 */ { u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK; if( sNC.ncFlags & NC_VarSelect ) bComplex = 1; wcf |= (bComplex ? 0 : WHERE_ONEPASS_MULTIROW); |
︙ | ︙ | |||
508 509 510 511 512 513 514 | ** to be deleted, based on the WHERE clause. Set variable eOnePass ** to indicate the strategy used to implement this delete: ** ** ONEPASS_OFF: Two-pass approach - use a FIFO for rowids/PK values. ** ONEPASS_SINGLE: One-pass approach - at most one row deleted. ** ONEPASS_MULTI: One-pass approach - any number of rows may be deleted. */ | | | 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 | ** to be deleted, based on the WHERE clause. Set variable eOnePass ** to indicate the strategy used to implement this delete: ** ** ONEPASS_OFF: Two-pass approach - use a FIFO for rowids/PK values. ** ONEPASS_SINGLE: One-pass approach - at most one row deleted. ** ONEPASS_MULTI: One-pass approach - any number of rows may be deleted. */ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0,0,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); |
︙ | ︙ | |||
583 584 585 586 587 588 589 | 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 ); | | < < | | 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 | 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 ) sqlite3VdbeJumpHere(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 || pTab->pSelect!=0 ); 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); |
︙ | ︙ | |||
661 662 663 664 665 666 667 | } /* 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 ){ | > > | | | 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 | } /* 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_ResultRow, memCnt, 1); sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", SQLITE_STATIC); } delete_from_cleanup: sqlite3AuthContextPop(&sContext); sqlite3SrcListDelete(db, pTabList); sqlite3ExprDelete(db, pWhere); #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) sqlite3ExprListDelete(db, pOrderBy); sqlite3ExprDelete(db, pLimit); #endif sqlite3DbFree(db, aToOpen); return; } /* Make sure "isView" and other macros defined above are undefined. Otherwise ** they may interfere with compilation of other functions in this file ** (or in another file, if this file becomes part of the amalgamation). */ #ifdef isView #undef isView |
︙ | ︙ | |||
783 784 785 786 787 788 789 | /* 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) ){ | < | | 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 | /* 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) ){ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, iCol, iOld+iCol+1); } } /* Invoke BEFORE DELETE trigger programs. */ addrStart = sqlite3VdbeCurrentAddr(v); sqlite3CodeRowTrigger(pParse, pTrigger, TK_DELETE, 0, TRIGGER_BEFORE, pTab, iOld, onconf, iLabel |
︙ | ︙ | |||
826 827 828 829 830 831 832 | ** ** 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. */ | | | 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 | ** ** 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( pTab->pSelect==0 ){ u8 p5 = 0; sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek); sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0)); if( pParse->nested==0 || 0==sqlite3_stricmp(pTab->zName, "sqlite_stat1") ){ sqlite3VdbeAppendP4(v, (char*)pTab, P4_TABLE); } if( eMode!=ONEPASS_OFF ){ |
︙ | ︙ | |||
906 907 908 909 910 911 912 | 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); | < | 848 849 850 851 852 853 854 855 856 857 858 859 860 861 | 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 |
︙ | ︙ | |||
965 966 967 968 969 970 971 | if( piPartIdxLabel ){ if( pIdx->pPartIdxWhere ){ *piPartIdxLabel = sqlite3VdbeMakeLabel(pParse); pParse->iSelfTab = iDataCur + 1; sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, SQLITE_JUMPIFNULL); pParse->iSelfTab = 0; | < < < | | | | | | | < > > > > | 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 | if( piPartIdxLabel ){ if( pIdx->pPartIdxWhere ){ *piPartIdxLabel = sqlite3VdbeMakeLabel(pParse); pParse->iSelfTab = iDataCur + 1; sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, SQLITE_JUMPIFNULL); pParse->iSelfTab = 0; }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 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); if( pIdx->pTable->pSelect ){ const char *zAff = sqlite3IndexAffinityStr(pParse->db, pIdx); sqlite3VdbeChangeP4(v, -1, zAff, P4_TRANSIENT); } } 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 | /* 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(Table *pTab, int iCol){ assert( iCol<pTab->nCol ); return iCol>=0 ? pTab->aCol[iCol].affinity : SQLITE_AFF_INTEGER; } /* ** 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(Expr *pExpr){ int op; pExpr = sqlite3ExprSkipCollate(pExpr); if( pExpr->flags & EP_Generic ) return 0; op = pExpr->op; if( op==TK_SELECT ){ assert( pExpr->flags&EP_xIsSelect ); return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr); } if( op==TK_REGISTER ) op = pExpr->op2; #ifndef SQLITE_OMIT_CAST if( op==TK_CAST ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); return sqlite3AffinityType(pExpr->u.zToken, 0); } #endif if( (op==TK_AGG_COLUMN || op==TK_COLUMN) && pExpr->y.pTab ){ return sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn); } if( op==TK_SELECT_COLUMN ){ assert( pExpr->pLeft->flags&EP_xIsSelect ); return sqlite3ExprAffinity( pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr ); } return pExpr->affinity; } /* ** 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( 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(Parse *pParse, Expr *pExpr, const char *zC){ Token s; assert( zC!=0 ); sqlite3TokenInit(&s, (char*)zC); return sqlite3ExprAddCollateToken(pParse, pExpr, &s, 0); } /* ** Skip over any TK_COLLATE operators and any unlikely() ** or likelihood() function at the root of an expression. */ Expr *sqlite3ExprSkipCollate(Expr *pExpr){ while( pExpr && ExprHasProperty(pExpr, EP_Skip) ){ if( ExprHasProperty(pExpr, EP_Unlikely) ){ assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); 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; } |
︙ | ︙ | |||
235 236 237 238 239 240 241 | ** 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. */ | | | > < | > < < | > | > | < < < < < < < > > > | | 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 | ** 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, Expr *pExpr){ sqlite3 *db = pParse->db; CollSeq *pColl = 0; Expr *p = pExpr; while( p ){ int op = p->op; if( p->flags & EP_Generic ) break; if( op==TK_REGISTER ) op = p->op2; if( (op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_TRIGGER) && 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 = p->y.pTab->aCol[j].zColl; pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0); } break; } if( op==TK_CAST || op==TK_UPLUS ){ p = p->pLeft; continue; } if( op==TK_COLLATE ){ 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( p->x.pList==0 || p->pRight==0 ); /* p->flags holds EP_Collate and p->pLeft->flags does not. And ** p->x.pSelect cannot. So if p->x.pLeft exists, it must hold at ** least one EP_Collate. Thus the following two ALWAYS. */ if( p->x.pList!=0 && ALWAYS(!ExprHasProperty(p, EP_xIsSelect)) ){ 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; } } |
︙ | ︙ | |||
307 308 309 310 311 312 313 | ** defautl collation sequence. ** ** See also: sqlite3ExprCollSeq() ** ** The sqlite3ExprCollSeq() routine works the same except that it ** returns NULL if there is no defined collation. */ | | | | | > > > > > | | | | | > | | < | | < > | > | < < < < | | < < < < < < < < < < < < < < < < | < < < < < | < | | < < | 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 | ** 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, 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, Expr *pE1, 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(Expr *pExpr, char aff2){ char aff1 = sqlite3ExprAffinity(pExpr); if( aff1 && aff2 ){ /* 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 if( !aff1 && !aff2 ){ /* Neither side of the comparison is a column. Compare the ** results directly. */ return SQLITE_AFF_BLOB; }else{ /* One side is a column, the other is not. Use the columns affinity. */ assert( aff1==0 || aff2==0 ); return (aff1 + aff2); } } /* ** pExpr is a comparison operator. Return the type affinity that should ** be applied to both operands prior to doing the comparison. */ static char comparisonAffinity(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( ExprHasProperty(pExpr, EP_xIsSelect) ){ 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(Expr *pExpr, char idx_affinity){ char aff = comparisonAffinity(pExpr); switch( aff ){ case SQLITE_AFF_BLOB: return 1; case SQLITE_AFF_TEXT: return idx_affinity==SQLITE_AFF_TEXT; default: 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(Expr *pExpr1, Expr *pExpr2, int jumpIfNull){ 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, Expr *pLeft, 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; } /* ** 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 p5; int addr; CollSeq *p4; 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(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(Expr *pExpr){ u8 op = pExpr->op; if( op==TK_REGISTER ) op = pExpr->op2; if( op==TK_VECTOR ){ return pExpr->x.pList->nExpr; }else if( op==TK_SELECT ){ return pExpr->x.pSelect->pEList->nExpr; }else{ return 1; } } /* |
︙ | ︙ | |||
525 526 527 528 529 530 531 | ** ** 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){ | | < < | 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 | ** ** 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) ); if( sqlite3ExprIsVector(pVector) ){ assert( pVector->op2==0 || pVector->op==TK_REGISTER ); if( pVector->op==TK_SELECT || pVector->op2==TK_SELECT ){ return pVector->x.pSelect->pEList->a[i].pExpr; }else{ return pVector->x.pList->a[i].pExpr; } } return pVector; } /* |
︙ | ︙ | |||
563 564 565 566 567 568 569 | ** 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 */ | | < | < > | < < < < < < < < < < > | 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 | ** 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 */ ){ Expr *pRet; if( pVector->op==TK_SELECT ){ assert( pVector->flags & EP_xIsSelect ); /* 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->iColumn = iField; pRet->pLeft = pVector; } assert( pRet==0 || pRet->iTable==0 ); }else{ if( pVector->op==TK_VECTOR ) pVector = pVector->x.pList->a[iField].pExpr; pRet = sqlite3ExprDup(pParse->db, pVector, 0); sqlite3RenameTokenRemap(pParse, pRet, pVector); } 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 |
︙ | ︙ | |||
653 654 655 656 657 658 659 | 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; | | < < < | | < < | 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 | 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 ); if( op==TK_REGISTER ){ *ppExpr = sqlite3VectorFieldSubexpr(pVector, iField); return pVector->iTable+iField; } if( op==TK_SELECT ){ *ppExpr = pVector->x.pSelect->pEList->a[iField].pExpr; return regSelect+iField; } *ppExpr = pVector->x.pList->a[iField].pExpr; return sqlite3ExprCodeTemp(pParse, *ppExpr, pRegFree); } /* ** 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. ** |
︙ | ︙ | |||
697 698 699 700 701 702 703 | Expr *pLeft = pExpr->pLeft; Expr *pRight = pExpr->pRight; int nLeft = sqlite3ExprVectorSize(pLeft); int i; int regLeft = 0; int regRight = 0; u8 opx = op; | < < < < > | | < < | < < | < < < < < < < < < < > > > | > | > > > > < < < < | 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 | Expr *pLeft = pExpr->pLeft; Expr *pRight = pExpr->pRight; int nLeft = sqlite3ExprVectorSize(pLeft); int i; int regLeft = 0; int regRight = 0; u8 opx = op; int addrDone = sqlite3VdbeMakeLabel(pParse); 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 ); p5 |= SQLITE_STOREP2; if( opx==TK_LE ) opx = TK_LT; if( opx==TK_GE ) opx = TK_GT; regLeft = exprCodeSubselect(pParse, pLeft); regRight = exprCodeSubselect(pParse, pRight); for(i=0; 1 /*Loop exits by "break"*/; i++){ int regFree1 = 0, regFree2 = 0; Expr *pL, *pR; int r1, r2; assert( i>=0 && i<nLeft ); r1 = exprVectorRegister(pParse, pLeft, i, regLeft, &pL, ®Free1); r2 = exprVectorRegister(pParse, pRight, i, regRight, &pR, ®Free2); codeCompare(pParse, pL, pR, opx, r1, r2, dest, p5); 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( i==nLeft-1 ){ break; } if( opx==TK_EQ ){ sqlite3VdbeAddOp2(v, OP_IfNot, dest, addrDone); VdbeCoverage(v); p5 |= SQLITE_KEEPNULL; }else if( opx==TK_NE ){ sqlite3VdbeAddOp2(v, OP_If, dest, addrDone); VdbeCoverage(v); p5 |= SQLITE_KEEPNULL; }else{ assert( op==TK_LT || op==TK_GT || op==TK_LE || op==TK_GE ); sqlite3VdbeAddOp2(v, OP_ElseNotEq, 0, addrDone); VdbeCoverageIf(v, op==TK_LT); VdbeCoverageIf(v, op==TK_GT); VdbeCoverageIf(v, op==TK_LE); VdbeCoverageIf(v, op==TK_GE); if( i==nLeft-2 ) opx = op; } } sqlite3VdbeResolveLabel(v, addrDone); } #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. |
︙ | ︙ | |||
798 799 800 801 802 803 804 | ** 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. */ | | | | | | 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 | ** 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(Expr *p, int *pnHeight){ if( p ){ if( p->nHeight>*pnHeight ){ *pnHeight = p->nHeight; } } } static void heightOfExprList(ExprList *p, int *pnHeight){ if( p ){ int i; for(i=0; i<p->nExpr; i++){ heightOfExpr(p->a[i].pExpr, pnHeight); } } } static void heightOfSelect(Select *pSelect, int *pnHeight){ Select *p; for(p=pSelect; p; p=p->pPrior){ heightOfExpr(p->pWhere, pnHeight); heightOfExpr(p->pHaving, pnHeight); heightOfExpr(p->pLimit, pnHeight); heightOfExprList(p->pEList, pnHeight); heightOfExprList(p->pGroupBy, pnHeight); heightOfExprList(p->pOrderBy, pnHeight); |
︙ | ︙ | |||
836 837 838 839 840 841 842 | ** has a height equal to the maximum height of any other ** referenced Expr plus one. ** ** Also propagate EP_Propagate flags up from Expr.x.pList to Expr.flags, ** if appropriate. */ static void exprSetHeight(Expr *p){ | | | | < | | 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 | ** has a height equal to the maximum height of any other ** referenced Expr plus one. ** ** 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( ExprHasProperty(p, EP_xIsSelect) ){ 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; } |
︙ | ︙ | |||
867 868 869 870 871 872 873 | sqlite3ExprCheckHeight(pParse, p->nHeight); } /* ** Return the maximum height of any expression tree referenced ** by the select statement passed as an argument. */ | | < | | 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 | sqlite3ExprCheckHeight(pParse, p->nHeight); } /* ** Return the maximum height of any expression tree referenced ** by the select statement passed as an argument. */ int sqlite3SelectExprHeight(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( p && p->x.pList && !ExprHasProperty(p, EP_xIsSelect) ){ p->flags |= EP_Propagate & sqlite3ExprListFlags(p->x.pList); } } #define exprSetHeight(y) #endif /* SQLITE_MAX_EXPR_DEPTH>0 */ /* |
︙ | ︙ | |||
931 932 933 934 935 936 937 | 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 ){ | | | 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 | 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; 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]) ){ |
︙ | ︙ | |||
982 983 984 985 986 987 988 | Expr *pRight ){ if( pRoot==0 ){ assert( db->mallocFailed ); sqlite3ExprDelete(db, pLeft); sqlite3ExprDelete(db, pRight); }else{ | < < < < < < < < < < | < < > > > > > | | | | | > > > < < < > | | < | > | | | | | < < | < < < < < < < < < < < < | < < | < | | < < | | | < | < < < < < < < < | < < < | | | < | | < < | | | > > | | < < < | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | Expr *pRight ){ if( pRoot==0 ){ assert( db->mallocFailed ); sqlite3ExprDelete(db, pLeft); sqlite3ExprDelete(db, pRight); }else{ if( pRight ){ pRoot->pRight = pRight; pRoot->flags |= EP_Propagate & pRight->flags; } if( pLeft ){ pRoot->pLeft = pLeft; pRoot->flags |= EP_Propagate & pLeft->flags; } exprSetHeight(pRoot); } } /* ** Allocate an Expr node which joins as many as two subtrees. ** ** One or both of the subtrees can be NULL. Return a pointer to the new ** Expr node. Or, if an OOM error occurs, set pParse->db->mallocFailed, ** free the subtrees and return NULL. */ Expr *sqlite3PExpr( Parse *pParse, /* Parsing context */ int op, /* Expression opcode */ Expr *pLeft, /* Left operand */ Expr *pRight /* Right operand */ ){ Expr *p; if( op==TK_AND && pParse->nErr==0 && !IN_RENAME_OBJECT ){ /* Take advantage of short-circuit false optimization for AND */ p = sqlite3ExprAnd(pParse->db, pLeft, pRight); }else{ 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); } if( p ) { sqlite3ExprCheckHeight(pParse, p->nHeight); } 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); } } /* ** If the expression is always either TRUE or FALSE (respectively), ** then return 1. If one cannot determine the truth value of the ** expression at compile-time return 0. ** ** This is an optimization. If is OK to return 0 here even if ** the expression really is always false or false (a false negative). ** But it is a bug to return 1 if the expression might have different ** boolean values in different circumstances (a false positive.) ** ** Note that if the expression is part of conditional for a ** LEFT JOIN, then we cannot determine at compile-time whether or not ** is it true or false, so always return 0. */ static int exprAlwaysTrue(Expr *p){ int v = 0; if( ExprHasProperty(p, EP_FromJoin) ) return 0; if( !sqlite3ExprIsInteger(p, &v) ) return 0; return v!=0; } static int exprAlwaysFalse(Expr *p){ int v = 0; if( ExprHasProperty(p, EP_FromJoin) ) return 0; if( !sqlite3ExprIsInteger(p, &v) ) return 0; return v==0; } /* ** 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(sqlite3 *db, Expr *pLeft, Expr *pRight){ if( pLeft==0 ){ return pRight; }else if( pRight==0 ){ return pLeft; }else if( exprAlwaysFalse(pLeft) || exprAlwaysFalse(pRight) ){ sqlite3ExprDelete(db, pLeft); sqlite3ExprDelete(db, pRight); return sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[0], 0); }else{ Expr *pNew = sqlite3ExprAlloc(db, TK_AND, 0, 0); sqlite3ExprAttachSubtrees(db, pNew, pLeft, pRight); return pNew; } } /* ** Construct a new expression node for a function with multiple ** arguments. */ Expr *sqlite3ExprFunction( Parse *pParse, /* Parsing context */ ExprList *pList, /* Argument list */ 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] ){ sqlite3ErrorMsg(pParse, "too many arguments on function %T", pToken); } pNew->x.pList = pList; ExprSetProperty(pNew, EP_HasFunc); assert( !ExprHasProperty(pNew, EP_xIsSelect) ); sqlite3ExprSetHeightAndFlags(pParse, pNew); if( eDistinct==SF_Distinct ) ExprSetProperty(pNew, EP_Distinct); return pNew; } /* ** 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. ** |
︙ | ︙ | |||
1250 1251 1252 1253 1254 1255 1256 | testcase( i==0 ); testcase( i==1 ); testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]-1 ); testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ); if( bOk==0 || i<1 || i>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){ sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d", db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]); | < | 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 | testcase( i==0 ); testcase( i==1 ); testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]-1 ); testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ); if( bOk==0 || i<1 || i>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){ sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d", db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]); return; } x = (ynVar)i; if( x>pParse->nVar ){ pParse->nVar = (int)x; doAdd = 1; }else if( sqlite3VListNumToName(pParse->pVList, x)==0 ){ |
︙ | ︙ | |||
1278 1279 1280 1281 1282 1283 1284 | if( doAdd ){ pParse->pVList = sqlite3VListAdd(db, pParse->pVList, z, n, x); } } pExpr->iColumn = x; if( x>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){ sqlite3ErrorMsg(pParse, "too many SQL variables"); | < | | | | | > | < | < < | < > | > | | < | < > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > > > > > > > > > > | 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 | if( doAdd ){ pParse->pVList = sqlite3VListAdd(db, pParse->pVList, z, n, x); } } pExpr->iColumn = x; if( x>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){ sqlite3ErrorMsg(pParse, "too many SQL variables"); } } /* ** Recursively delete an expression tree. */ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){ assert( p!=0 ); /* Sanity check: Assert that the IntValue is non-negative if it exists */ assert( !ExprHasProperty(p, EP_IntValue) || p->u.iValue>=0 ); assert( !ExprHasProperty(p, EP_WinFunc) || p->y.pWin!=0 || db->mallocFailed ); assert( p->op!=TK_FUNCTION || ExprHasProperty(p, EP_TokenOnly|EP_Reduced) || p->y.pWin==0 || ExprHasProperty(p, EP_WinFunc) ); #ifdef SQLITE_DEBUG if( ExprHasProperty(p, EP_Leaf) && !ExprHasProperty(p, EP_TokenOnly) ){ assert( p->pLeft==0 ); assert( p->pRight==0 ); assert( p->x.pSelect==0 ); } #endif if( !ExprHasProperty(p, (EP_TokenOnly|EP_Leaf)) ){ /* The Expr.x union is never used at the same time as Expr.pRight */ assert( p->x.pList==0 || p->pRight==0 ); if( p->pLeft && p->op!=TK_SELECT_COLUMN ) sqlite3ExprDeleteNN(db, p->pLeft); if( p->pRight ){ sqlite3ExprDeleteNN(db, p->pRight); }else if( ExprHasProperty(p, EP_xIsSelect) ){ sqlite3SelectDelete(db, p->x.pSelect); }else{ sqlite3ExprListDelete(db, p->x.pList); } if( ExprHasProperty(p, EP_WinFunc) ){ assert( p->op==TK_FUNCTION ); sqlite3WindowDelete(db, p->y.pWin); } } if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken); if( !ExprHasProperty(p, EP_Static) ){ sqlite3DbFreeNN(db, p); } } void sqlite3ExprDelete(sqlite3 *db, Expr *p){ if( p ) sqlite3ExprDeleteNN(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(Expr *p){ if( ExprHasProperty(p, EP_TokenOnly) ) return EXPR_TOKENONLYSIZE; if( ExprHasProperty(p, EP_Reduced) ) return EXPR_REDUCEDSIZE; return EXPR_FULLSIZE; } /* ** Copy the complete content of an Expr node, taking care not to read ** past the end of the structure for a reduced-size version of the source ** Expr. */ static void exprNodeCopy(Expr *pDest, Expr *pSrc){ memset(pDest, 0, sizeof(Expr)); memcpy(pDest, pSrc, exprStructSize(pSrc)); } /* ** The dupedExpr*Size() routines each return the number of bytes required ** to store a copy of an expression or expression tree. They differ in ** how much of the tree is measured. ** ** dupedExprStructSize() Size of only the Expr structure |
︙ | ︙ | |||
1413 1414 1415 1416 1417 1418 1419 | ** 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. */ | | | > | | | | < | 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 | ** 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(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( !ExprHasProperty(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(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(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, 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; }else{ zAlloc = sqlite3DbMallocRawNN(db, dupedExprSize(p, dupFlags)); staticFlag = 0; } pNew = (Expr *)zAlloc; if( pNew ){ |
︙ | ︙ | |||
1530 1531 1532 1533 1534 1535 1536 | memcpy(zAlloc, p, nSize); if( nSize<EXPR_FULLSIZE ){ memset(&zAlloc[nSize], 0, EXPR_FULLSIZE-nSize); } } /* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */ | | < < < < | | 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 | memcpy(zAlloc, p, nSize); if( nSize<EXPR_FULLSIZE ){ memset(&zAlloc[nSize], 0, EXPR_FULLSIZE-nSize); } } /* 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. */ if( ExprHasProperty(p, EP_xIsSelect) ){ 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. */ |
︙ | ︙ | |||
1575 1576 1577 1578 1579 1580 1581 | if( pzBuffer ){ *pzBuffer = zAlloc; } }else{ if( !ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){ if( pNew->op==TK_SELECT_COLUMN ){ pNew->pLeft = p->pLeft; | > | < | < | < | > > > > > | 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 | if( pzBuffer ){ *pzBuffer = zAlloc; } }else{ if( !ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){ if( pNew->op==TK_SELECT_COLUMN ){ pNew->pLeft = p->pLeft; assert( p->iColumn==0 || p->pRight==0 ); assert( p->pRight==0 || p->pRight==p->pLeft ); }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 static With *withDup(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 withDup(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( pWin->ppThis==0 ); if( pSelect->pWin ){ pSelect->pWin->ppThis = &pWin->pNextWin; } pWin->pNextWin = pSelect->pWin; pWin->ppThis = &pSelect->pWin; pSelect->pWin = 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){ |
︙ | ︙ | |||
1665 1666 1667 1668 1669 1670 1671 | ** 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. */ | | | | < | < < > | | < | | | | | < | | > | | > > | | | | < < < | < | < < < | < | > | > > > > > > | | | | | 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 | ** 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, Expr *p, int flags){ assert( flags==0 || flags==EXPRDUP_REDUCE ); return p ? exprDup(db, p, flags, 0) : 0; } ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){ ExprList *pNew; struct ExprList_item *pItem, *pOldItem; int i; Expr *pPriorSelectCol = 0; assert( db!=0 ); if( p==0 ) return 0; pNew = sqlite3DbMallocRawNN(db, sqlite3DbMallocSize(db, p)); if( pNew==0 ) return 0; pNew->nExpr = p->nExpr; 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 ){ assert( pNewExpr->iColumn==0 || i>0 ); if( pNewExpr->iColumn==0 ){ assert( pOldExpr->pLeft==pOldExpr->pRight ); pPriorSelectCol = pNewExpr->pLeft = pNewExpr->pRight; }else{ assert( i>0 ); assert( pItem[-1].pExpr!=0 ); assert( pNewExpr->iColumn==pItem[-1].pExpr->iColumn+1 ); assert( pPriorSelectCol==pItem[-1].pExpr->pLeft ); pNewExpr->pLeft = pPriorSelectCol; } } pItem->zName = sqlite3DbStrDup(db, pOldItem->zName); pItem->zSpan = sqlite3DbStrDup(db, pOldItem->zSpan); pItem->sortOrder = pOldItem->sortOrder; pItem->done = 0; pItem->bSpanIsTab = pOldItem->bSpanIsTab; 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, 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++){ struct SrcList_item *pNewItem = &pNew->a[i]; struct SrcList_item *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->pIBIndex = pOldItem->pIBIndex; 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, 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; pNew->a = sqlite3DbMallocRawNN(db, p->nId*sizeof(p->a[0]) ); if( pNew->a==0 ){ sqlite3DbFreeNN(db, pNew); return 0; } /* Note that because the size of the allocation for p->a[] is not ** necessarily a power of two, sqlite3IdListAppend() may not be called ** on the duplicate created by this function. */ for(i=0; i<p->nId; i++){ 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, Select *pDup, int flags){ Select *pRet = 0; Select *pNext = 0; Select **pp = &pRet; 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); |
︙ | ︙ | |||
1813 1814 1815 1816 1817 1818 1819 | 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; | | | < < < < < < < < | | 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 | 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 = withDup(db, p->pWith); #ifndef SQLITE_OMIT_WINDOWFUNC pNew->pWin = 0; pNew->pWinDefn = sqlite3WindowListDup(db, p->pWinDefn); if( p->pWin ) gatherSelectWindows(pNew); #endif pNew->selId = p->selId; *pp = pNew; pp = &pNew->pPrior; pNext = pNew; } return pRet; } #else Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){ assert( p==0 ); return 0; } #endif /* |
︙ | ︙ | |||
1858 1859 1860 1861 1862 1863 1864 | ** 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. */ | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > | > > | | > | > > > > | > > > > | > > > > > > | 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 | ** 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. */ 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; sqlite3 *db = pParse->db; assert( db!=0 ); if( pList==0 ){ pList = sqlite3DbMallocRawNN(db, sizeof(ExprList) ); if( pList==0 ){ goto no_mem; } pList->nExpr = 0; }else if( (pList->nExpr & (pList->nExpr-1))==0 ){ ExprList *pNew; pNew = sqlite3DbRealloc(db, pList, sizeof(*pList)+(2*(sqlite3_int64)pList->nExpr-1)*sizeof(pList->a[0])); if( pNew==0 ){ goto no_mem; } pList = pNew; } pItem = &pList->a[pList->nExpr++]; assert( offsetof(struct ExprList_item,zName)==sizeof(pItem->pExpr) ); assert( offsetof(struct ExprList_item,pExpr)==0 ); memset(&pItem->zName,0,sizeof(*pItem)-offsetof(struct ExprList_item,zName)); pItem->pExpr = pExpr; return pList; no_mem: /* Avoid leaking memory if malloc has failed. */ sqlite3ExprDelete(db, pExpr); sqlite3ExprListDelete(db, pList); return 0; } /* ** 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) |
︙ | ︙ | |||
1956 1957 1958 1959 1960 1961 1962 | 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++){ | | < < | > | > > | < < < | | | | < < < < < | < < < < | | < < < < | < < < | | < | < | | < < < < | | < | 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 | 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); pList = sqlite3ExprListAppend(pParse, pList, pSubExpr); if( pList ){ assert( pList->nExpr==iFirst+i+1 ); pList->a[pList->nExpr-1].zName = 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: if( IN_RENAME_OBJECT ){ sqlite3RenameExprUnmap(pParse, pExpr); } sqlite3ExprDelete(db, pExpr); sqlite3IdListDelete(db, pColumns); return pList; } /* ** Set the sort order for the last element on the given ExprList. */ void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder){ if( p==0 ) return; assert( SQLITE_SO_UNDEFINED<0 && SQLITE_SO_ASC>=0 && SQLITE_SO_DESC>0 ); assert( p->nExpr>0 ); if( iSortOrder<0 ){ assert( p->a[p->nExpr-1].sortOrder==SQLITE_SO_ASC ); return; } p->a[p->nExpr-1].sortOrder = (u8)iSortOrder; } /* ** Set the ExprList.a[].zName 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. */ Token *pName, /* Name to be added */ int dequote /* True to cause the name to be dequoted */ ){ assert( pList!=0 || pParse->db->mallocFailed!=0 ); if( pList ){ struct ExprList_item *pItem; assert( pList->nExpr>0 ); pItem = &pList->a[pList->nExpr-1]; assert( pItem->zName==0 ); pItem->zName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n); if( dequote ) sqlite3Dequote(pItem->zName); if( IN_RENAME_OBJECT ){ sqlite3RenameTokenMap(pParse, (void*)pItem->zName, pName); } } } /* ** Set the ExprList.a[].zSpan element of the most recently added item ** on the expression list. |
︙ | ︙ | |||
2075 2076 2077 2078 2079 2080 2081 | 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 ); | | | < < | 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 | 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 ); sqlite3DbFree(db, pItem->zSpan); pItem->zSpan = sqlite3DbSpanDup(db, zStart, zEnd); } } /* ** If the expression list pEList contains more than iLimit elements, ** leave an error message in pParse. */ |
︙ | ︙ | |||
2106 2107 2108 2109 2110 2111 2112 | /* ** Delete an entire expression list. */ static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){ int i = pList->nExpr; struct ExprList_item *pItem = pList->a; assert( pList->nExpr>0 ); | < | > | | 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 | /* ** Delete an entire expression list. */ 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->zName); sqlite3DbFree(db, pItem->zSpan); pItem++; }while( --i>0 ); sqlite3DbFreeNN(db, pList); } void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){ if( pList ) exprListDeleteNN(db, pList); } /* ** Return the bitwise-OR of all Expr.flags fields in the given |
︙ | ︙ | |||
2146 2147 2148 2149 2150 2151 2152 | ** This callback is used by multiple expression walkers. */ int sqlite3SelectWalkFail(Walker *pWalker, Select *NotUsed){ UNUSED_PARAMETER(NotUsed); pWalker->eCode = 0; return WRC_Abort; } | < < < < < < < < < < < < < < < < | > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | | | | | | < < < | | < < | | | 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 | ** 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 ); if( !ExprHasProperty(pExpr, EP_Quoted) && (sqlite3StrICmp(pExpr->u.zToken, "true")==0 || sqlite3StrICmp(pExpr->u.zToken, "false")==0) ){ pExpr->op = TK_TRUEFALSE; 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){ assert( pExpr->op==TK_TRUEFALSE ); assert( sqlite3StrICmp(pExpr->u.zToken,"true")==0 || sqlite3StrICmp(pExpr->u.zToken,"false")==0 ); return pExpr->u.zToken[4]==0; } /* ** 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 expressions ** in a CREATE TABLE statement. The Walker.eCode value is 5 when parsing ** an existing schema and 4 when processing a new statement. A bound ** parameter raises an error for new statements, but is silently converted ** to NULL for existing schemas. This allows sqlite_master 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) ){ 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; } /* Fall thru */ 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; } /* Fall through */ case TK_IF_NULL_ROW: case TK_REGISTER: testcase( pExpr->op==TK_REGISTER ); testcase( pExpr->op==TK_IF_NULL_ROW ); 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_master 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; } /* 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){ |
︙ | ︙ | |||
2355 2356 2357 2358 2359 2360 2361 | ** (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 | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | ** (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 sqlite3ExprCodeAtInit(). */ int sqlite3ExprIsConstantNotJoin(Expr *p){ return exprIsConst(p, 2, 0); } /* ** Walk an expression tree. Return non-zero if the expression is constant ** for any single row of the table with cursor iCur. In other words, the ** expression must not refer to any non-deterministic function nor any ** table other than iCur. */ int sqlite3ExprIsTableConstant(Expr *p, int iCur){ return exprIsConst(p, 3, iCur); } /* ** sqlite3WalkExpr() callback used by sqlite3ExprIsConstantOrGroupBy(). */ static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){ ExprList *pGroupBy = pWalker->u.pGroupBy; int i; |
︙ | ︙ | |||
2428 2429 2430 2431 2432 2433 2434 | if( sqlite3IsBinary(pColl) ){ return WRC_Prune; } } } /* Check if pExpr is a sub-select. If so, consider it variable. */ | | | 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 | if( sqlite3IsBinary(pColl) ){ return WRC_Prune; } } } /* Check if pExpr is a sub-select. If so, consider it variable. */ if( ExprHasProperty(pExpr, EP_xIsSelect) ){ pWalker->eCode = 0; return WRC_Abort; } return exprNodeIsConstant(pWalker, pExpr); } |
︙ | ︙ | |||
2467 2468 2469 2470 2471 2472 2473 | w.u.pGroupBy = pGroupBy; w.pParse = pParse; sqlite3WalkExpr(&w, p); return w.eCode; } /* | < | < | | < < < < < < < < < < | 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 | w.u.pGroupBy = pGroupBy; w.pParse = pParse; sqlite3WalkExpr(&w, p); return w.eCode; } /* ** Walk an expression tree. Return non-zero if the expression is constant ** or a function call with constant arguments. Return and 0 if there ** are any variables. ** ** 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 ); |
︙ | ︙ | |||
2516 2517 2518 2519 2520 2521 2522 | /* ** 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. */ | | | | | | 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 | /* ** 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(Expr *p, int *pValue){ int rc = 0; if( p==0 ) return 0; /* Can 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; if( sqlite3ExprIsInteger(p->pLeft, &v) ){ assert( v!=(-2147483647-1) ); *pValue = -v; rc = 1; } break; } default: break; } |
︙ | ︙ | |||
2564 2565 2566 2567 2568 2569 2570 | ** 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; | < < < < < | < | < < < | | | | | > | 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 | ** 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; while( p->op==TK_UPLUS || p->op==TK_UMINUS ){ p = p->pLeft; } 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: return ExprHasProperty(p, EP_CanBeNull) || p->y.pTab==0 || /* Reference to column of index on expression */ (p->iColumn>=0 && 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; if( aff==SQLITE_AFF_BLOB ) return 1; while( p->op==TK_UPLUS || p->op==TK_UMINUS ){ p = p->pLeft; } op = p->op; if( op==TK_REGISTER ) op = p->op2; switch( op ){ case TK_INTEGER: { return aff==SQLITE_AFF_INTEGER || aff==SQLITE_AFF_NUMERIC; } case TK_FLOAT: { return aff==SQLITE_AFF_REAL || aff==SQLITE_AFF_NUMERIC; } case TK_STRING: { return aff==SQLITE_AFF_TEXT; } case TK_BLOB: { return 1; } case TK_COLUMN: { assert( p->iTable>=0 ); /* p cannot be part of a CHECK constraint */ return p->iColumn<0 && (aff==SQLITE_AFF_INTEGER || aff==SQLITE_AFF_NUMERIC); } default: { return 0; } } } |
︙ | ︙ | |||
2650 2651 2652 2653 2654 2655 2656 | ** 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 | | | | | 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 | ** 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(Expr *pX){ Select *p; SrcList *pSrc; ExprList *pEList; Table *pTab; int i; if( !ExprHasProperty(pX, EP_xIsSelect) ) 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( pTab->pSelect==0 ); /* 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; |
︙ | ︙ | |||
2734 2735 2736 2737 2738 2739 2740 | ** might be either a list of expressions or a subquery. ** ** The job of this routine is to find or create a b-tree object that can ** be used either to test for membership in the RHS set or to iterate through ** all members of the RHS set, skipping duplicates. ** ** A cursor is opened on the b-tree object that is the RHS of the IN operator | | | < < < | 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 | ** might be either a list of expressions or a subquery. ** ** The job of this routine is to find or create a b-tree object that can ** be used either to test for membership in the RHS set or to iterate through ** all members of the RHS set, skipping duplicates. ** ** A cursor is opened on the b-tree object that is the RHS of the IN operator ** and pX->iTable is set to the index of that cursor. ** ** The returned value of this function indicates the b-tree type, as follows: ** ** IN_INDEX_ROWID - The cursor was opened on a database table. ** IN_INDEX_INDEX_ASC - The cursor was opened on an ascending index. ** IN_INDEX_INDEX_DESC - The cursor was opened on a descending index. ** IN_INDEX_EPH - The cursor was opened on a specially created and ** populated epheremal table. ** IN_INDEX_NOOP - No cursor was allocated. The IN operator must be ** implemented as a sequence of comparisons. ** ** An existing b-tree might be used if the RHS expression pX is a simple ** subquery such as: ** ** SELECT <column1>, <column2>... FROM <table> ** ** If the RHS of the IN operator is a list or a more complex subquery, then ** an ephemeral table might need to be generated from the RHS and then ** pX->iTable made to point to the ephemeral table instead of an ** existing table. ** ** The inFlags parameter must contain, at a minimum, one of the bits ** IN_INDEX_MEMBERSHIP or IN_INDEX_LOOP but not both. If inFlags contains ** IN_INDEX_MEMBERSHIP, then the generated table will be used for a fast ** membership test. When the IN_INDEX_LOOP bit is set, the IN index will ** be used to loop over all values of the RHS of the IN operator. ** |
︙ | ︙ | |||
2810 2811 2812 2813 2814 2815 2816 | ** 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 */ | | | < | | < | 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 | ** 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 right-hand side (RHS) of the IN operator */ 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 && (pX->flags & EP_xIsSelect) ){ 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>. */ i16 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); 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); |
︙ | ︙ | |||
2987 2988 2989 2990 2991 2992 2993 | ** 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) | | < < | 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 | ** 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) && !ExprHasProperty(pX, EP_xIsSelect) && (!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. */ |
︙ | ︙ | |||
3034 3035 3036 3037 3038 3039 3040 | ** 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(). */ | | | | 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 | ** 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, Expr *pExpr){ Expr *pLeft = pExpr->pLeft; int nVal = sqlite3ExprVectorSize(pLeft); Select *pSelect = (pExpr->flags & EP_xIsSelect) ? 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++){ |
︙ | ︙ | |||
3067 3068 3069 3070 3071 3072 3073 | /* ** 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){ | < | | < | | 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 | /* ** 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){ 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( pExpr->flags & EP_xIsSelect ){ sqlite3SubselectError(pParse, pExpr->x.pSelect->pEList->nExpr, 1); }else #endif { sqlite3ErrorMsg(pParse, "row value misused"); } } |
︙ | ︙ | |||
3151 3152 3153 3154 3155 3156 3157 | 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); | | < < < < | > | | < < < | < | < | > | 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 | 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( ExprHasProperty(pExpr, EP_xIsSelect) ){ ExplainQueryPlan((pParse, 0, "REUSE LIST SUBQUERY %d", pExpr->x.pSelect->selId)); } 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 */ 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")); 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( ExprHasProperty(pExpr, EP_xIsSelect) ){ 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( ExprHasProperty(pExpr, EP_xIsSelect) ){ /* 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) ){ SelectDest dest; int i; 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() */ if( sqlite3Select(pParse, pSelect, &dest) ){ sqlite3DbFree(pParse->db, dest.zAffSdst); sqlite3KeyInfoUnref(pKeyInfo); return; } sqlite3DbFree(pParse->db, dest.zAffSdst); 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( |
︙ | ︙ | |||
3248 3249 3250 3251 3252 3253 3254 | ** 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; | | | < < < < | | | < < < < | | < < | < < < < | < < < < < < < < < < < < < < < < < < > > > > > > > > > > > > > > > > | < > < < < < < < < | < < < < < < | < < | < < < | | > | < | | 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 | ** 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, r3; affinity = sqlite3ExprAffinity(pLeft); if( !affinity ){ affinity = SQLITE_AFF_BLOB; } 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); addrOnce = 0; } /* Evaluate the expression and insert it into the temp table */ r3 = sqlite3ExprCodeTarget(pParse, pE2, r1); sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r2, r3, 1); } sqlite3ReleaseTempReg(pParse, r1); sqlite3ReleaseTempReg(pParse, r2); } if( pKeyInfo ){ sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO); } if( addrOnce ){ sqlite3VdbeJumpHere(v, addrOnce); /* Subroutine return */ sqlite3VdbeAddOp1(v, OP_Return, pExpr->y.sub.regReturn); sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1); } } #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. ** ** 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 ); testcase( pExpr->op==TK_EXISTS ); testcase( pExpr->op==TK_SELECT ); assert( pExpr->op==TK_EXISTS || pExpr->op==TK_SELECT ); assert( ExprHasProperty(pExpr, EP_xIsSelect) ); pSel = pExpr->x.pSelect; /* 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) ){ /* 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)); sqlite3VdbeAddOp2(v, OP_Gosub, pExpr->y.sub.regReturn, pExpr->y.sub.iAddr); return pExpr->iTable; } /* Begin coding the subroutine */ 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")); 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")); } pLimit = sqlite3ExprAlloc(pParse->db, TK_INTEGER,&sqlite3IntTokens[1], 0); if( pSel->pLimit ){ sqlite3ExprDelete(pParse->db, pSel->pLimit->pLeft); pSel->pLimit->pLeft = pLimit; }else{ pSel->pLimit = sqlite3PExpr(pParse, TK_LIMIT, pLimit, 0); } pSel->iLimit = 0; if( sqlite3Select(pParse, pSel, &dest) ){ return 0; } pExpr->iTable = rReg = dest.iSDParm; ExprSetVVAProperty(pExpr, EP_NoReduce); if( addrOnce ){ sqlite3VdbeJumpHere(v, addrOnce); /* Subroutine return */ sqlite3VdbeAddOp1(v, OP_Return, pExpr->y.sub.regReturn); sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1); } 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( (pIn->flags & EP_xIsSelect) ){ 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; |
︙ | ︙ | |||
3511 3512 3513 3514 3515 3516 3517 | 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 */ | < < | 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 | 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 */ 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 ); |
︙ | ︙ | |||
3556 3557 3558 3559 3560 3561 3562 | ** 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. | | < < < < < < | | | < < < < | | | < < < | | < < > | 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 | ** 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. */ rLhsOrig = exprCodeVector(pParse, pLeft, &iDummy); 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 = pExpr->x.pList; CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft); int labelOk = sqlite3VdbeMakeLabel(pParse); int r2, regToFree; int regCkNull = 0; int ii; assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); 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); } if( ii<pList->nExpr-1 || destIfNull!=destIfFalse ){ sqlite3VdbeAddOp4(v, OP_Eq, rLhs, labelOk, r2, (void*)pColl, P4_COLLSEQ); VdbeCoverageIf(v, ii<pList->nExpr-1); VdbeCoverageIf(v, ii==pList->nExpr-1); sqlite3VdbeChangeP5(v, zAff[0]); }else{ assert( destIfNull==destIfFalse ); sqlite3VdbeAddOp4(v, OP_Ne, rLhs, destIfFalse, r2, (void*)pColl, P4_COLLSEQ); VdbeCoverage(v); sqlite3VdbeChangeP5(v, zAff[0] | SQLITE_JUMPIFNULL); } sqlite3ReleaseTempReg(pParse, regToFree); } if( regCkNull ){ sqlite3VdbeAddOp2(v, OP_IsNull, regCkNull, destIfNull); VdbeCoverage(v); sqlite3VdbeGoto(v, destIfFalse); } sqlite3VdbeResolveLabel(v, labelOk); sqlite3ReleaseTempReg(pParse, regCkNull); |
︙ | ︙ | |||
3641 3642 3643 3644 3645 3646 3647 | if( destIfNull==destIfFalse ){ destStep2 = destIfFalse; }else{ destStep2 = destStep6 = sqlite3VdbeMakeLabel(pParse); } for(i=0; i<nVector; i++){ Expr *p = sqlite3VectorFieldSubexpr(pExpr->pLeft, i); | < | 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 | if( destIfNull==destIfFalse ){ destStep2 = destIfFalse; }else{ destStep2 = destStep6 = sqlite3VdbeMakeLabel(pParse); } for(i=0; i<nVector; i++){ Expr *p = sqlite3VectorFieldSubexpr(pExpr->pLeft, i); 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 |
︙ | ︙ | |||
3779 3780 3781 3782 3783 3784 3785 | int c; i64 value; const char *z = pExpr->u.zToken; assert( z!=0 ); c = sqlite3DecOrHexToI64(z, &value); if( (c==3 && !negFlag) || (c==2) || (negFlag && value==SMALLEST_INT64)){ #ifdef SQLITE_OMIT_FLOATING_POINT | | | < | 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 | int c; i64 value; const char *z = pExpr->u.zToken; assert( z!=0 ); c = sqlite3DecOrHexToI64(z, &value); if( (c==3 && !negFlag) || (c==2) || (negFlag && value==SMALLEST_INT64)){ #ifdef SQLITE_OMIT_FLOATING_POINT sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z); #else #ifndef SQLITE_OMIT_HEX_INTEGER if( sqlite3_strnicmp(z,"0x",2)==0 ){ sqlite3ErrorMsg(pParse, "hex literal too big: %s%s", negFlag?"-":"",z); }else #endif { codeReal(v, z, negFlag, iMem); } #endif }else{ |
︙ | ︙ | |||
3822 3823 3824 3825 3826 3827 3828 | pParse->iSelfTab = 0; }else{ sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pIdx->pTable, iTabCur, iTabCol, regOut); } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | > > > < < < | < | < < < < < < < < < < < < < < < < | < | < < < < < > > > | | | < > | < < | 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 | 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( Vdbe *v, /* The VDBE under construction */ 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 */ ){ 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 = IsVirtual(pTab) ? OP_VColumn : OP_Column; int x = iCol; if( !HasRowid(pTab) && !IsVirtual(pTab) ){ x = sqlite3ColumnOfIndex(sqlite3PrimaryKeyIndex(pTab), iCol); } sqlite3VdbeAddOp3(v, op, iTabCur, x, regOut); } if( iCol>=0 ){ 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 */ ){ Vdbe *v = pParse->pVdbe; assert( v!=0 ); sqlite3ExprCodeGetColumnOfTable(v, pTab, iTable, iColumn, iReg); if( p5 ){ sqlite3VdbeChangeP5(v, 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){ assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo ); 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 *p, int iReg){ p->op2 = p->op; p->op = TK_REGISTER; p->iTable = iReg; ExprClearProperty(p, EP_Skip); } /* |
︙ | ︙ | |||
3975 3976 3977 3978 3979 3980 3981 | #else iResult = sqlite3CodeSubselect(pParse, p); #endif }else{ int i; iResult = pParse->nMem+1; pParse->nMem += nResult; | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | 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 | #else iResult = sqlite3CodeSubselect(pParse, p); #endif }else{ int i; iResult = pParse->nMem+1; pParse->nMem += nResult; for(i=0; i<nResult; i++){ sqlite3ExprCodeFactorable(pParse, p->x.pList->a[i].pExpr, i+iResult); } } } return iResult; } /* ** Check to see if pExpr is one of the indexed expressions on pParse->pIdxExpr. ** If it is, then resolve the expression by reading from the index and ** return the register into which the value has been read. If pExpr is ** not an indexed expression, then return negative. */ static SQLITE_NOINLINE int sqlite3IndexedExprLookup( Parse *pParse, /* The parsing context */ Expr *pExpr, /* The expression to potentially bypass */ int target /* Where to store the result of the expression */ ){ IndexedExpr *p; Vdbe *v; for(p=pParse->pIdxExpr; p; p=p->pIENext){ int iDataCur = p->iDataCur; if( iDataCur<0 ) continue; if( pParse->iSelfTab ){ if( p->iDataCur!=pParse->iSelfTab-1 ) continue; iDataCur = -1; } if( sqlite3ExprCompare(0, pExpr, p->pExpr, iDataCur)!=0 ) continue; v = pParse->pVdbe; assert( v!=0 ); if( p->bMaybeNullRow ){ /* If the index is on a NULL row due to an outer join, then we ** cannot extract the value from the index. The value must be ** computed using the original expression. */ int addr = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp3(v, OP_IfNullRow, p->iIdxCur, addr+3, target); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_Column, p->iIdxCur, p->iIdxCol, target); VdbeComment((v, "%s expr-column %d", p->zIdxName, p->iIdxCol)); sqlite3VdbeGoto(v, 0); p = pParse->pIdxExpr; pParse->pIdxExpr = 0; sqlite3ExprCode(pParse, pExpr, target); pParse->pIdxExpr = p; sqlite3VdbeJumpHere(v, addr+2); }else{ sqlite3VdbeAddOp3(v, OP_Column, p->iIdxCur, p->iIdxCol, target); VdbeComment((v, "%s expr-column %d", p->zIdxName, p->iIdxCol)); } return target; } |
︙ | ︙ | |||
4185 4186 4187 4188 4189 4190 4191 | 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 ); | > | > > | < | < < < > | < < < < < < < < < < < < < < < < < < < < | < < | | | > > > > | < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < | < < < < < | < | 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 | 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 ); if( v==0 ){ assert( pParse->db->mallocFailed ); return 0; } expr_code_doover: if( pExpr==0 ){ op = TK_NULL; }else if( pParse->pIdxExpr!=0 && !ExprHasProperty(pExpr, EP_Leaf) && (r1 = sqlite3IndexedExprLookup(pParse, pExpr, target))>=0 ){ return r1; }else{ op = pExpr->op; } switch( op ){ case TK_AGG_COLUMN: { AggInfo *pAggInfo = pExpr->pAggInfo; struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg]; if( !pAggInfo->directMode ){ assert( pCol->iMem>0 ); return pCol->iMem; }else if( pAggInfo->useSortingIdx ){ sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab, pCol->iSorterColumn, target); return target; } /* Otherwise, fall thru into the TK_COLUMN case */ } case TK_COLUMN: { int iTab = pExpr->iTable; 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 iReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft,target); int aff = sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn); if( aff!=SQLITE_AFF_BLOB ){ static const char zAff[] = "B\000C\000D\000E"; assert( SQLITE_AFF_BLOB=='A' ); assert( SQLITE_AFF_TEXT=='B' ); if( iReg!=target ){ sqlite3VdbeAddOp2(v, OP_SCopy, iReg, target); iReg = target; } sqlite3VdbeAddOp4(v, OP_Affinity, iReg, 1, 0, &zAff[(aff-'B')*2], P4_STATIC); } return iReg; } if( iTab<0 ){ if( pParse->iSelfTab<0 ){ /* Generating CHECK constraints or inserting into partial index */ return pExpr->iColumn - pParse->iSelfTab; }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; } } return sqlite3ExprCodeGetColumn(pParse, pExpr->y.pTab, pExpr->iColumn, iTab, target, pExpr->op2); } case TK_INTEGER: { codeInteger(pParse, pExpr, 0, target); return target; } case TK_TRUEFALSE: { sqlite3VdbeAddOp2(v, OP_Integer, sqlite3ExprTruthValue(pExpr), target); |
︙ | ︙ | |||
4335 4336 4337 4338 4339 4340 4341 | } #endif case TK_STRING: { assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3VdbeLoadString(v, target, pExpr->u.zToken); return target; } | | < < < < < | 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 | } #endif case TK_STRING: { assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3VdbeLoadString(v, target, pExpr->u.zToken); return target; } case TK_NULL: { sqlite3VdbeAddOp2(v, OP_Null, 0, target); return target; } #ifndef SQLITE_OMIT_BLOB_LITERAL case TK_BLOB: { int n; const char *z; |
︙ | ︙ | |||
4367 4368 4369 4370 4371 4372 4373 | 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); | | < | 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 | 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]=='?' || strcmp(pExpr->u.zToken, z)==0 ); 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; } sqlite3VdbeAddOp2(v, OP_Cast, target, sqlite3AffinityType(pExpr->u.zToken, 0)); return inReg; } #endif /* SQLITE_OMIT_CAST */ case TK_IS: case TK_ISNOT: |
︙ | ︙ | |||
4407 4408 4409 4410 4411 4412 4413 | 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); | < | < < > < < < < < | 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 | 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); codeCompare(pParse, pLeft, pExpr->pRight, op, r1, r2, inReg, SQLITE_STOREP2 | p5); 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); testcase( regFree1==0 ); testcase( regFree2==0 ); } break; } case TK_AND: case TK_OR: |
︙ | ︙ | |||
4473 4474 4475 4476 4477 4478 4479 | 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; | < | 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 | 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; } |
︙ | ︙ | |||
4519 4520 4521 4522 4523 4524 4525 | VdbeCoverageIf(v, op==TK_NOTNULL); sqlite3VdbeAddOp2(v, OP_Integer, 0, target); sqlite3VdbeJumpHere(v, addr); break; } case TK_AGG_FUNCTION: { AggInfo *pInfo = pExpr->pAggInfo; | | < < < | | | 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 | 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 ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); sqlite3ErrorMsg(pParse, "misuse of aggregate: %s()", pExpr->u.zToken); }else{ return pInfo->aFunc[pExpr->iAgg].iMem; } break; } case TK_FUNCTION: { ExprList *pFarg; /* List of function arguments */ int nFarg; /* Number of function arguments */ FuncDef *pDef; /* The function definition object */ |
︙ | ︙ | |||
4548 4549 4550 4551 4552 4553 4554 | #ifndef SQLITE_OMIT_WINDOWFUNC if( ExprHasProperty(pExpr, EP_WinFunc) ){ return pExpr->y.pWin->regResult; } #endif if( ConstFactorOk(pParse) && sqlite3ExprIsConstantNotJoin(pExpr) ){ | | | | | | > > | > | > > > > > | > > > > > > > > > > > | > > > | > | > | > > > > > | > > > | > > > > | 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 | #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 move constant functions ** out of the inner loop, even if that means an extra OP_Copy. */ return sqlite3ExprCodeAtInit(pParse, pExpr, -1); } assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); if( ExprHasProperty(pExpr, EP_TokenOnly) ){ pFarg = 0; }else{ 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; } /* Attempt a direct implementation of the built-in COALESCE() and ** IFNULL() functions. This avoids unnecessary evaluation of ** arguments past the first non-NULL argument. */ if( pDef->funcFlags & SQLITE_FUNC_COALESCE ){ int endCoalesce = sqlite3VdbeMakeLabel(pParse); 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); } sqlite3VdbeResolveLabel(v, endCoalesce); break; } /* The UNLIKELY() function is a no-op. The result is the value ** of the first argument. */ if( pDef->funcFlags & SQLITE_FUNC_UNLIKELY ){ assert( nFarg>=1 ); return sqlite3ExprCodeTarget(pParse, pFarg->a[0].pExpr, target); } #ifdef SQLITE_DEBUG /* 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. */ if( pDef->funcFlags & SQLITE_FUNC_AFFINITY ){ const char *azAff[] = { "blob", "text", "numeric", "integer", "real" }; char aff; assert( nFarg==1 ); aff = sqlite3ExprAffinity(pFarg->a[0].pExpr); sqlite3VdbeLoadString(v, target, aff ? azAff[aff-SQLITE_AFF_BLOB] : "none"); return target; } #endif 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 ){ |
︙ | ︙ | |||
4641 4642 4643 4644 4645 4646 4647 | pDef = sqlite3VtabOverloadFunction(db, pDef, nFarg, pFarg->a[0].pExpr); } #endif if( pDef->funcFlags & SQLITE_FUNC_NEEDCOLL ){ if( !pColl ) pColl = db->pDfltColl; sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ); } | | | | | | > > > > > > > | | > > < < < < | < | < | < | < | > > | | 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 | pDef = sqlite3VtabOverloadFunction(db, pDef, nFarg, pFarg->a[0].pExpr); } #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 ){ 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 { sqlite3VdbeAddOp4(v, pParse->iSelfTab ? OP_PureFunc0 : OP_Function0, constMask, r1, target, (char*)pDef, P4_FUNCDEF); sqlite3VdbeChangeP5(v, (u8)nFarg); } if( nFarg && constMask==0 ){ sqlite3ReleaseTempRange(pParse, r1, nFarg); } return target; } #ifndef SQLITE_OMIT_SUBQUERY case TK_EXISTS: case TK_SELECT: { int nCol; testcase( op==TK_EXISTS ); testcase( op==TK_SELECT ); if( op==TK_SELECT && (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->iTable==0 || pExpr->pLeft->op==TK_SELECT ); if( pExpr->iTable && pExpr->iTable!=(n = sqlite3ExprVectorSize(pExpr->pLeft)) ){ 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); |
︙ | ︙ | |||
4714 4715 4716 4717 4718 4719 4720 | ** Y is stored in pExpr->pList->a[0].pExpr. ** Z is stored in pExpr->pList->a[1].pExpr. */ case TK_BETWEEN: { exprCodeBetween(pParse, pExpr, target, 0, 0); return target; } | | < < < < < < < < < < < < < < < < | | 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 | ** Y is stored in pExpr->pList->a[0].pExpr. ** Z is stored in pExpr->pList->a[1].pExpr. */ case TK_BETWEEN: { exprCodeBetween(pParse, pExpr, target, 0, 0); return target; } case TK_SPAN: case TK_COLLATE: case TK_UPLUS: { pExpr = pExpr->pLeft; goto expr_code_doover; /* 2018-04-28: Prevent deep recursion. OSSFuzz. */ } case TK_TRIGGER: { /* If the opcode is TK_TRIGGER, then the expression is a reference |
︙ | ︙ | |||
4763 4764 4765 4766 4767 4768 4769 | ** ** 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 */ | < < < < < | < | < | | | > | > < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | ** ** 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 = pExpr->y.pTab; int p1 = pExpr->iTable * (pTab->nCol+1) + 1 + pExpr->iColumn; assert( pExpr->iTable==0 || pExpr->iTable==1 ); assert( pExpr->iColumn>=-1 && pExpr->iColumn<pTab->nCol ); assert( pTab->iPKey<0 || pExpr->iColumn!=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[pExpr->iColumn].zName) )); #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( pExpr->iColumn>=0 && pTab->aCol[pExpr->iColumn].affinity==SQLITE_AFF_REAL ){ sqlite3VdbeAddOp1(v, OP_RealAffinity, target); } #endif break; } case TK_VECTOR: { sqlite3ErrorMsg(pParse, "row value misused"); break; } case TK_IF_NULL_ROW: { int addrINR; addrINR = sqlite3VdbeAddOp1(v, OP_IfNullRow, pExpr->iTable); inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); sqlite3VdbeJumpHere(v, addrINR); sqlite3VdbeChangeP3(v, addrINR, inReg); break; } /* ** Form A: |
︙ | ︙ | |||
4860 4861 4862 4863 4864 4865 4866 | ** 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. */ | | < < | | < < < < | | | 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 | ** 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. */ default: assert( op==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) */ assert( !ExprHasProperty(pExpr, EP_xIsSelect) && pExpr->x.pList ); assert(pExpr->x.pList->nExpr > 0); pEList = pExpr->x.pList; aListelem = pEList->a; nExpr = pEList->nExpr; endLabel = sqlite3VdbeMakeLabel(pParse); if( (pX = pExpr->pLeft)!=0 ){ exprNodeCopy(&tempX, pX); testcase( pX->op==TK_COLUMN ); exprToRegister(&tempX, exprCodeVector(pParse, &tempX, ®Free1)); testcase( regFree1==0 ); memset(&opCompare, 0, sizeof(opCompare)); opCompare.op = TK_EQ; opCompare.pLeft = &tempX; 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; } |
︙ | ︙ | |||
4918 4919 4920 4921 4922 4923 4924 | sqlite3VdbeResolveLabel(v, nextCase); } if( (nExpr&1)!=0 ){ sqlite3ExprCode(pParse, pEList->a[nExpr-1].pExpr, target); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, target); } | < < | | | | | | | | < | | < < < < < < | | < < | < | < < < < < < < < < < < < < < < | | | | | | | | < | < | | 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 | sqlite3VdbeResolveLabel(v, nextCase); } if( (nExpr&1)!=0 ){ sqlite3ExprCode(pParse, pEList->a[nExpr-1].pExpr, target); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, target); } sqlite3VdbeResolveLabel(v, endLabel); break; } #ifndef SQLITE_OMIT_TRIGGER case TK_RAISE: { assert( pExpr->affinity==OE_Rollback || pExpr->affinity==OE_Abort || pExpr->affinity==OE_Fail || pExpr->affinity==OE_Ignore ); if( !pParse->pTriggerTab ){ sqlite3ErrorMsg(pParse, "RAISE() may only be used within a trigger-program"); return 0; } if( pExpr->affinity==OE_Abort ){ sqlite3MayAbort(pParse); } assert( !ExprHasProperty(pExpr, EP_IntValue) ); if( pExpr->affinity==OE_Ignore ){ sqlite3VdbeAddOp4( v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0); VdbeCoverage(v); }else{ sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_TRIGGER, pExpr->affinity, pExpr->u.zToken, 0, 0); } break; } #endif } sqlite3ReleaseTempReg(pParse, regFree1); sqlite3ReleaseTempReg(pParse, regFree2); return inReg; } /* ** Factor out the code of the given expression to initialization time. ** ** 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 will ** code to the same register. */ int sqlite3ExprCodeAtInit( 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); 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 = sqlite3ExprSkipCollate(pExpr); if( ConstFactorOk(pParse) && pExpr->op!=TK_REGISTER && sqlite3ExprIsConstantNotJoin(pExpr) ){ *pReg = 0; r2 = sqlite3ExprCodeAtInit(pParse, pExpr, -1); }else{ int r1 = sqlite3GetTempReg(pParse); r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1); if( r2==r1 ){ *pReg = r1; }else{ sqlite3ReleaseTempReg(pParse, r1); |
︙ | ︙ | |||
5065 5066 5067 5068 5069 5070 5071 | ** 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; | < > | | | > | < < < < | < | 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 | ** 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 ); if( pExpr && pExpr->op==TK_REGISTER ){ sqlite3VdbeAddOp2(pParse->pVdbe, OP_Copy, pExpr->iTable, target); }else{ inReg = sqlite3ExprCodeTarget(pParse, pExpr, target); assert( pParse->pVdbe!=0 || pParse->db->mallocFailed ); if( inReg!=target && pParse->pVdbe ){ sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, 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. |
︙ | ︙ | |||
5101 5102 5103 5104 5105 5106 5107 | ** 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) ){ | | | > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ** 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) ){ sqlite3ExprCodeAtInit(pParse, pExpr, target); }else{ sqlite3ExprCode(pParse, pExpr, target); } } /* ** Generate code that evaluates the given expression and puts the result ** in register target. ** ** Also make a copy of the expression results into another "cache" register ** and modify the expression so that the next time it is evaluated, ** the result is a copy of the cache register. ** ** This routine is used for expressions that are used multiple ** times. They are evaluated once and the results of the expression ** are reused. */ void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){ Vdbe *v = pParse->pVdbe; int iMem; assert( target>0 ); assert( pExpr->op!=TK_REGISTER ); sqlite3ExprCode(pParse, pExpr, target); iMem = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Copy, target, iMem); exprToRegister(pExpr, iMem); } /* ** 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 ** usually be pList->nExpr but might be reduced if SQLITE_ECEL_OMITREF |
︙ | ︙ | |||
5146 5147 5148 5149 5150 5151 5152 | assert( target>0 ); assert( pParse->pVdbe!=0 ); /* Never gets this far otherwise */ n = pList->nExpr; if( !ConstFactorOk(pParse) ) flags &= ~SQLITE_ECEL_FACTOR; for(pItem=pList->a, i=0; i<n; i++, pItem++){ Expr *pExpr = pItem->pExpr; #ifdef SQLITE_ENABLE_SORTER_REFERENCES | | | | < | 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 | assert( target>0 ); assert( pParse->pVdbe!=0 ); /* Never gets this far otherwise */ n = pList->nExpr; if( !ConstFactorOk(pParse) ) flags &= ~SQLITE_ECEL_FACTOR; for(pItem=pList->a, i=0; i<n; i++, pItem++){ Expr *pExpr = pItem->pExpr; #ifdef SQLITE_ENABLE_SORTER_REFERENCES if( pItem->bSorterRef ){ i--; n--; }else #endif if( (flags & SQLITE_ECEL_REF)!=0 && (j = pItem->u.x.iOrderByCol)>0 ){ if( flags & SQLITE_ECEL_OMITREF ){ i--; n--; }else{ sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i); } }else if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstantNotJoin(pExpr) ){ sqlite3ExprCodeAtInit(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->p3++; }else{ sqlite3VdbeAddOp2(v, copyOp, inReg, target+i); } } } |
︙ | ︙ | |||
5209 5210 5211 5212 5213 5214 5215 | 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 */ ){ | | > < < | | < | | | | | | | | | | | | | | | | | | | | | | < < | 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 | 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 */ Expr exprX; /* The x subexpression */ int regFree1 = 0; /* Temporary use register */ memset(&compLeft, 0, sizeof(Expr)); memset(&compRight, 0, sizeof(Expr)); memset(&exprAnd, 0, sizeof(Expr)); assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); exprNodeCopy(&exprX, pExpr->pLeft); exprAnd.op = TK_AND; exprAnd.pLeft = &compLeft; exprAnd.pRight = &compRight; compLeft.op = TK_GE; compLeft.pLeft = &exprX; compLeft.pRight = pExpr->x.pList->a[0].pExpr; compRight.op = TK_LE; compRight.pLeft = &exprX; compRight.pRight = pExpr->x.pList->a[1].pExpr; exprToRegister(&exprX, exprCodeVector(pParse, &exprX, ®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. */ exprX.flags |= EP_FromJoin; sqlite3ExprCodeTarget(pParse, &exprAnd, dest); } sqlite3ReleaseTempReg(pParse, regFree1); /* 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 ); |
︙ | ︙ | |||
5284 5285 5286 5287 5288 5289 5290 | 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 */ | < | < < < < < | | | < | | > > | | | | < | 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 | int regFree1 = 0; int regFree2 = 0; int r1, r2; assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 ); if( NEVER(v==0) ) return; /* Existence of VDBE checked by caller */ if( NEVER(pExpr==0) ) return; /* No way this can happen */ op = pExpr->op; switch( op ){ case TK_AND: { int d2 = sqlite3VdbeMakeLabel(pParse); testcase( jumpIfNull==0 ); sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2,jumpIfNull^SQLITE_JUMPIFNULL); sqlite3ExprIfTrue(pParse, pExpr->pRight, dest, jumpIfNull); sqlite3VdbeResolveLabel(v, d2); break; } case TK_OR: { 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; } |
︙ | ︙ | |||
5334 5335 5336 5337 5338 5339 5340 | } 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; | | | < | 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 | } 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; /* Fall thru */ 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); 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); assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v, op==OP_Ne && jumpIfNull==SQLITE_NULLEQ); VdbeCoverageIf(v, op==OP_Ne && jumpIfNull!=SQLITE_NULLEQ); testcase( regFree1==0 ); testcase( regFree2==0 ); break; } case TK_ISNULL: case TK_NOTNULL: { assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL ); assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); sqlite3VdbeAddOp2(v, op, r1, dest); VdbeCoverageIf(v, op==TK_ISNULL); VdbeCoverageIf(v, op==TK_NOTNULL); testcase( regFree1==0 ); break; } case TK_BETWEEN: { |
︙ | ︙ | |||
5390 5391 5392 5393 5394 5395 5396 | sqlite3VdbeGoto(v, dest); sqlite3VdbeResolveLabel(v, destIfFalse); break; } #endif default: { default_expr: | | | | 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 | 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 ); |
︙ | ︙ | |||
5427 5428 5429 5430 5431 5432 5433 | 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; | < | 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 | 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 |
︙ | ︙ | |||
5461 5462 5463 5464 5465 5466 5467 | 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 ){ | | < < < < < | | | > > | | | | < | | < | 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 | 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: { testcase( jumpIfNull==0 ); sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); sqlite3ExprIfFalse(pParse, pExpr->pRight, dest, jumpIfNull); break; } case TK_OR: { 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; } |
︙ | ︙ | |||
5511 5512 5513 5514 5515 5516 5517 | } 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; | | | < | 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 | } 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; /* Fall thru */ 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); 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); assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v, op==OP_Ne && jumpIfNull!=SQLITE_NULLEQ); VdbeCoverageIf(v, op==OP_Ne && jumpIfNull==SQLITE_NULLEQ); testcase( regFree1==0 ); testcase( regFree2==0 ); break; } case TK_ISNULL: case TK_NOTNULL: { r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); sqlite3VdbeAddOp2(v, op, r1, dest); testcase( op==TK_ISNULL ); VdbeCoverageIf(v, op==TK_ISNULL); testcase( op==TK_NOTNULL ); VdbeCoverageIf(v, op==TK_NOTNULL); testcase( regFree1==0 ); break; } case TK_BETWEEN: { |
︙ | ︙ | |||
5567 5568 5569 5570 5571 5572 5573 | sqlite3VdbeResolveLabel(v, destIfNull); } break; } #endif default: { default_expr: | | | | 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 | 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 ); |
︙ | ︙ | |||
5612 5613 5614 5615 5616 5617 5618 | ** 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. */ | | < < < < | 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 | ** 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(Parse *pParse, Expr *pVar, 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; |
︙ | ︙ | |||
5668 5669 5670 5671 5672 5673 5674 | ** 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. */ | | < < < < < | 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 | ** 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(Parse *pParse, Expr *pA, 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; } |
︙ | ︙ | |||
5703 5704 5705 5706 5707 5708 5709 | && pB->iTable<0 && pA->iTable==iTab ){ /* fall through */ }else{ return 2; } } | < < | | | > > > > > > > | < < | < < < < < < | < | < | | < | | < | < | | < | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | && pB->iTable<0 && pA->iTable==iTab ){ /* fall through */ }else{ return 2; } } if( pA->op!=TK_COLUMN && pA->op!=TK_AGG_COLUMN && pA->u.zToken ){ if( pA->op==TK_FUNCTION ){ if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2; #ifndef SQLITE_OMIT_WINDOWFUNC /* Justification for the assert(): ** window functions have p->op==TK_FUNCTION but aggregate functions ** have p->op==TK_AGG_FUNCTION. So any comparison between an aggregate ** function and a window function should have failed before reaching ** this point. And, it is not possible to have a window function and ** a scalar function with the same name and number of arguments. So ** if we reach this point, either A and B both window functions or ** neither are a window functions. */ assert( ExprHasProperty(pA,EP_WinFunc)==ExprHasProperty(pB,EP_WinFunc) ); if( ExprHasProperty(pA,EP_WinFunc) ){ if( sqlite3WindowCompare(pParse,pA->y.pWin,pB->y.pWin)!=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( ALWAYS(pB->u.zToken!=0) && strcmp(pA->u.zToken,pB->u.zToken)!=0 ){ return 2; } } if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2; if( (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 && (combinedFlags & EP_Reduced)==0 ){ if( pA->iColumn!=pB->iColumn ) return 2; if( pA->iTable!=pB->iTable && (pA->iTable!=iTab || NEVER(pB->iTable>=0)) ) return 2; } } return 0; } /* ** Compare two ExprList objects. Return 0 if they are identical and ** non-zero if they differ in any way. ** ** 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(ExprList *pA, 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++){ Expr *pExprA = pA->a[i].pExpr; Expr *pExprB = pB->a[i].pExpr; if( pA->a[i].sortOrder!=pB->a[i].sortOrder ) return 1; if( sqlite3ExprCompare(0, pExprA, pExprB, iTab) ) return 1; } return 0; } /* ** Like sqlite3ExprCompare() except COLLATE operators at the top-level ** are ignored. */ int sqlite3ExprCompareSkip(Expr *pA, Expr *pB, int iTab){ return sqlite3ExprCompare(0, sqlite3ExprSkipCollate(pA), sqlite3ExprSkipCollate(pB), iTab); } /* ** 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 ** pE1: x>0 pE2: x==5 Result: false |
︙ | ︙ | |||
5899 5900 5901 5902 5903 5904 5905 | ** 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. */ | | < < < < < | | | | | | > < | | < < < < < < < < < < < < < < < < < < < | < < < < < < | < < | < < | < < | | | | | | < | > > | 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 | ** 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(Parse *pParse, Expr *pE1, 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 && pE1->op!=TK_ISNULL && pE1->op!=TK_IS ){ Expr *pX = sqlite3ExprSkipCollate(pE1->pLeft); testcase( pX!=pE1->pLeft ); if( sqlite3ExprCompare(pParse, pX, pE2->pLeft, iTab)==0 ) return 1; } return 0; } /* ** This is the Expr node callback for sqlite3ExprImpliesNotNullRow(). ** 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_NOT: case TK_ISNULL: case TK_NOTNULL: case TK_IS: case TK_OR: case TK_CASE: case TK_IN: case TK_FUNCTION: testcase( pExpr->op==TK_ISNOT ); testcase( pExpr->op==TK_NOT ); testcase( pExpr->op==TK_ISNULL ); testcase( pExpr->op==TK_NOTNULL ); testcase( pExpr->op==TK_IS ); testcase( pExpr->op==TK_OR ); testcase( pExpr->op==TK_CASE ); testcase( pExpr->op==TK_IN ); testcase( pExpr->op==TK_FUNCTION ); return WRC_Prune; case TK_COLUMN: if( pWalker->u.iCur==pExpr->iTable ){ pWalker->eCode = 1; 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: 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 ); if( (pExpr->pLeft->op==TK_COLUMN && IsVirtual(pExpr->pLeft->y.pTab)) || (pExpr->pRight->op==TK_COLUMN && IsVirtual(pExpr->pRight->y.pTab)) ){ return WRC_Prune; } default: return WRC_Continue; } } /* ** Return true (non-zero) if expression p can only be true if at least ** one column of table iTab is non-null. In other words, return true ** if expression p will always be NULL or false if every column of iTab ** is NULL. ** ** False negatives are acceptable. In other words, it is ok to return ** zero even if expression p will never be true of every column of iTab ** is NULL. A false negative is merely a missed optimization opportunity. ** ** False positives are not allowed, however. A false positive may result ** in an incorrect answer. ** ** Terms of p that are marked with EP_FromJoin (and hence that come from ** the ON or USING clauses of LEFT JOINS) are excluded from the analysis. ** ** This routine is used to check if a LEFT JOIN can be converted into ** 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 = sqlite3ExprSkipCollate(p); while( p ){ if( p->op==TK_NOTNULL ){ p = p->pLeft; }else if( p->op==TK_AND ){ if( sqlite3ExprImpliesNonNullRow(p->pLeft, iTab) ) return 1; p = p->pRight; }else{ break; } } w.xExprCallback = impliesNotNullRow; w.xSelectCallback = 0; w.xSelectCallback2 = 0; w.eCode = 0; w.u.iCur = iTab; |
︙ | ︙ | |||
6081 6082 6083 6084 6085 6086 6087 | ** 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 | | | 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 | ** 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 && sqlite3ColumnOfIndex(pWalker->u.pIdxCover->pIdx, pExpr->iColumn)<0 ){ pWalker->eCode = 1; return WRC_Abort; } return WRC_Continue; } |
︙ | ︙ | |||
6116 6117 6118 6119 6120 6121 6122 | w.xExprCallback = exprIdxCover; w.u.pIdxCover = &xcov; sqlite3WalkExpr(&w, pExpr); return !w.eCode; } | > | > | > | < | | | | < < < < < | < < < < < < < > | < < < < < < < < < < < < < < < < < < < | | | < < < < < < < | < < | | | < < | > > | < | < | | | | < < < < < < < < < | | | < < | | < | < | < < > > < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | w.xExprCallback = exprIdxCover; w.u.pIdxCover = &xcov; sqlite3WalkExpr(&w, pExpr); return !w.eCode; } /* ** An instance of the following structure is used by the tree walker ** to count references to table columns in the arguments of an ** aggregate function, in order to implement the ** sqlite3FunctionThisSrc() routine. */ struct SrcCount { SrcList *pSrc; /* One particular FROM clause in a nested query */ int nThis; /* Number of references to columns in pSrcList */ int nOther; /* Number of references to columns in other FROM clauses */ }; /* ** Count the number of references to columns. */ static int exprSrcCount(Walker *pWalker, Expr *pExpr){ /* The NEVER() on the second term is because sqlite3FunctionUsesThisSrc() ** is always called before sqlite3ExprAnalyzeAggregates() and so the ** TK_COLUMNs have not yet been converted into TK_AGG_COLUMN. If ** sqlite3FunctionUsesThisSrc() is used differently in the future, the ** NEVER() will need to be removed. */ if( pExpr->op==TK_COLUMN || NEVER(pExpr->op==TK_AGG_COLUMN) ){ int i; struct SrcCount *p = pWalker->u.pSrcCount; SrcList *pSrc = p->pSrc; int nSrc = pSrc ? pSrc->nSrc : 0; for(i=0; i<nSrc; i++){ if( pExpr->iTable==pSrc->a[i].iCursor ) break; } if( i<nSrc ){ p->nThis++; }else{ p->nOther++; } } return WRC_Continue; } /* ** Determine if any of the arguments to the pExpr Function reference ** pSrcList. Return true if they do. Also return true if the function ** has no arguments or has only constant arguments. Return false if pExpr ** references columns but not columns of tables found in pSrcList. */ int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){ Walker w; struct SrcCount cnt; assert( pExpr->op==TK_AGG_FUNCTION ); w.xExprCallback = exprSrcCount; w.xSelectCallback = 0; w.u.pSrcCount = &cnt; cnt.pSrc = pSrcList; cnt.nThis = 0; cnt.nOther = 0; sqlite3WalkExprList(&w, pExpr->x.pList); return cnt.nThis>0 || cnt.nOther==0; } /* ** 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){ |
︙ | ︙ | |||
6322 6323 6324 6325 6326 6327 6328 | db, pInfo->aFunc, sizeof(pInfo->aFunc[0]), &pInfo->nFunc, &i ); return i; | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < | | > | | 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 | 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){ int i; NameContext *pNC = pWalker->u.pNC; Parse *pParse = pNC->pParse; SrcList *pSrcList = pNC->pSrcList; AggInfo *pAggInfo = pNC->uNC.pAggInfo; assert( pNC->ncFlags & NC_UAggInfo ); switch( pExpr->op ){ 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) ){ struct SrcList_item *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. ** ** Make an entry for the column in pAggInfo->aCol[] if there ** is not an entry there already. */ int k; pCol = pAggInfo->aCol; for(k=0; k<pAggInfo->nColumn; k++, pCol++){ if( pCol->iTable==pExpr->iTable && pCol->iColumn==pExpr->iColumn ){ 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; pCol->pExpr = 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; if( pE->op==TK_COLUMN && pE->iTable==pExpr->iTable && pE->iColumn==pExpr->iColumn ){ pCol->iSorterColumn = j; break; } } } if( pCol->iSorterColumn<0 ){ pCol->iSorterColumn = pAggInfo->nSortingColumn++; } } /* There is now an entry for pExpr in pAggInfo->aCol[] (either ** because it was there before or because we just created it). ** Convert the pExpr to be a TK_AGG_COLUMN referring to that ** pAggInfo->aCol[] entry. */ ExprSetVVAProperty(pExpr, EP_NoReduce); pExpr->pAggInfo = pAggInfo; pExpr->op = TK_AGG_COLUMN; pExpr->iAgg = (i16)k; break; } /* endif pExpr->iTable==pItem->iCursor */ } /* end loop over pSrcList */ } return WRC_Prune; } case TK_AGG_FUNCTION: { if( (pNC->ncFlags & NC_InAggFunc)==0 && 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( sqlite3ExprCompare(0, pItem->pExpr, 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->pExpr = pExpr; pItem->iMem = ++pParse->nMem; assert( !ExprHasProperty(pExpr, EP_IntValue) ); 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; |
︙ | ︙ | |||
6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 | }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; | > > > > > > > > > | | | 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 | }else{ return WRC_Continue; } } } return WRC_Continue; } static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){ UNUSED_PARAMETER(pSelect); pWalker->walkerDepth++; return WRC_Continue; } static void analyzeAggregatesInSelectEnd(Walker *pWalker, Select *pSelect){ UNUSED_PARAMETER(pSelect); pWalker->walkerDepth--; } /* ** 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 = analyzeAggregatesInSelect; w.xSelectCallback2 = analyzeAggregatesInSelectEnd; w.walkerDepth = 0; w.u.pNC = pNC; w.pParse = 0; assert( pNC->pSrcList!=0 ); sqlite3WalkExpr(&w, pExpr); } |
︙ | ︙ | |||
6556 6557 6558 6559 6560 6561 6562 | } /* ** Deallocate a register, making available for reuse for some other ** purpose. */ void sqlite3ReleaseTempReg(Parse *pParse, int iReg){ | < < | | < | 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 | } /* ** Deallocate a register, making available for reuse for some other ** purpose. */ void sqlite3ReleaseTempReg(Parse *pParse, int iReg){ if( iReg && 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){ |
︙ | ︙ | |||
6586 6587 6588 6589 6590 6591 6592 | return i; } void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){ if( nReg==1 ){ sqlite3ReleaseTempReg(pParse, iReg); return; } | < < < < < < | 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 | 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; } /* |
︙ | ︙ |
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 | ** 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].zName, zKey) ) return 0; } }else if( paiCol ){ assert( nCol>1 ); aiCol = (int *)sqlite3DbMallocRawNN(pParse->db, nCol*sizeof(int)); if( !aiCol ) return 1; *paiCol = aiCol; } |
︙ | ︙ | |||
255 256 257 258 259 260 261 | 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. */ | | | | 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 | char *zIdxCol; /* Name of indexed column */ if( iCol<0 ) break; /* No foreign keys against expression indexes */ /* If the index uses a collation sequence that is different from ** the default collation sequence for the column, this index is ** unusable. Bail out early in this case. */ zDfltColl = pParent->aCol[iCol].zColl; if( !zDfltColl ) zDfltColl = sqlite3StrBINARY; if( sqlite3StrICmp(pIdx->azColl[i], zDfltColl) ) break; zIdxCol = pParent->aCol[iCol].zName; 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; |
︙ | ︙ | |||
347 348 349 350 351 352 353 | ** 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++){ | | | < | 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 | ** 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 = 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, 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. */ |
︙ | ︙ | |||
386 387 388 389 390 391 392 393 394 395 396 | sqlite3VdbeGoto(v, iOk); sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2); sqlite3VdbeJumpHere(v, iMustBeInt); sqlite3ReleaseTempReg(pParse, regTemp); }else{ int nCol = pFKey->nCol; int regTemp = sqlite3GetTempRange(pParse, nCol); sqlite3VdbeAddOp3(v, OP_OpenRead, iCur, pIdx->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); for(i=0; i<nCol; i++){ | > | < < < | | < < | | | | > | 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 | sqlite3VdbeGoto(v, iOk); sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2); sqlite3VdbeJumpHere(v, iMustBeInt); sqlite3ReleaseTempReg(pParse, regTemp); }else{ 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, 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 = aiCol[i]+1+regData; int iParent = pIdx->aiColumn[i]+1+regData; assert( pIdx->aiColumn[i]>=0 ); assert( aiCol[i]!=pTab->iPKey ); if( pIdx->aiColumn[i]==pTab->iPKey ){ /* The parent key is a composite key that includes the IPK column */ iParent = regData; } sqlite3VdbeAddOp3(v, OP_Ne, iChild, iJump, iParent); VdbeCoverage(v); sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL); } sqlite3VdbeGoto(v, iOk); } sqlite3VdbeAddOp4(v, OP_MakeRecord, regTemp, nCol, regRec, sqlite3IndexAffinityStr(pParse->db,pIdx), nCol); sqlite3VdbeAddOp4Int(v, OP_Found, iCur, iOk, regRec, 0); VdbeCoverage(v); sqlite3ReleaseTempReg(pParse, regRec); sqlite3ReleaseTempRange(pParse, regTemp, nCol); } } if( !pFKey->isDeferred && !(pParse->db->flags & SQLITE_DeferFKs) && !pParse->pToplevel && !pParse->isMultiWrite |
︙ | ︙ | |||
479 480 481 482 483 484 485 | 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]; | | | | | < | 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 | 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 + iCol + 1; pExpr->affinity = pCol->affinity; zColl = pCol->zColl; if( zColl==0 ) zColl = db->pDfltColl->zName; pExpr = sqlite3ExprAddCollateString(pParse, pExpr, zColl); }else{ pExpr->iTable = regBase; pExpr->affinity = 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 ){ pExpr->y.pTab = pTab; pExpr->iTable = iCursor; pExpr->iColumn = iCol; } return pExpr; } |
︙ | ︙ | |||
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 | ** The code generated by this function scans through the rows in the child ** table that correspond to the parent table row being deleted or inserted. ** For each child row found, one of the following actions is taken: ** ** Operation | FK type | Action taken ** -------------------------------------------------------------------------- ** DELETE immediate Increment the "immediate constraint counter". ** ** INSERT immediate Decrement the "immediate constraint counter". ** ** DELETE deferred Increment the "deferred constraint counter". ** ** INSERT deferred Decrement the "deferred constraint counter". ** ** These operations are identified in the comment at the top of this file ** (fkey.c) as "I.2" and "D.2". */ static void fkScanChildren( | > > > > | 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 | ** The code generated by this function scans through the rows in the child ** table that correspond to the parent table row being deleted or inserted. ** For each child row found, one of the following actions is taken: ** ** Operation | FK type | Action taken ** -------------------------------------------------------------------------- ** DELETE immediate Increment the "immediate constraint counter". ** Or, if the ON (UPDATE|DELETE) action is RESTRICT, ** throw a "FOREIGN KEY constraint failed" exception. ** ** INSERT immediate Decrement the "immediate constraint counter". ** ** DELETE deferred Increment the "deferred constraint counter". ** Or, if the ON (UPDATE|DELETE) action is RESTRICT, ** throw a "FOREIGN KEY constraint failed" exception. ** ** INSERT deferred Decrement the "deferred constraint counter". ** ** These operations are identified in the comment at the top of this file ** (fkey.c) as "I.2" and "D.2". */ static void fkScanChildren( |
︙ | ︙ | |||
587 588 589 590 591 592 593 | 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 ); | | | | 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 | 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].zName; pRight = sqlite3Expr(db, TK_ID, zCol); pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight); pWhere = sqlite3ExprAnd(db, 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 |
︙ | ︙ | |||
622 623 624 625 626 627 628 | }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); | | | | | 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 | }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].zName); pEq = sqlite3PExpr(pParse, TK_IS, pLeft, pRight); pAll = sqlite3ExprAnd(db, pAll, pEq); } pNe = sqlite3PExpr(pParse, TK_NOT, pAll, 0); } pWhere = sqlite3ExprAnd(db, pWhere, pNe); } /* Resolve the references in the WHERE clause. */ memset(&sNameContext, 0, sizeof(NameContext)); sNameContext.pSrcList = pSrc; sNameContext.pParse = pParse; sqlite3ResolveExprNames(&sNameContext, pWhere); |
︙ | ︙ | |||
651 652 653 654 655 656 657 | sqlite3WhereEnd(pWInfo); } } /* Clean up the WHERE clause constructed above. */ sqlite3ExprDelete(db, pWhere); if( iFkIfZero ){ | | | 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 | sqlite3WhereEnd(pWInfo); } } /* Clean up the WHERE clause constructed above. */ sqlite3ExprDelete(db, pWhere); if( iFkIfZero ){ sqlite3VdbeJumpHere(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: |
︙ | ︙ | |||
692 693 694 695 696 697 698 | sqlite3ExprListDelete(dbMem, pStep->pExprList); sqlite3SelectDelete(dbMem, pStep->pSelect); sqlite3ExprDelete(dbMem, p->pWhen); sqlite3DbFree(dbMem, p); } } | < < < < < < < < < < < < < < < < < < < | | | | 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 | sqlite3ExprListDelete(dbMem, pStep->pExprList); sqlite3SelectDelete(dbMem, pStep->pSelect); sqlite3ExprDelete(dbMem, p->pWhen); sqlite3DbFree(dbMem, p); } } /* ** This function is called to generate code that runs when table pTab is ** being dropped from the database. The SrcList passed as the second argument ** to this function contains a single entry guaranteed to resolve to ** table pTab. ** ** Normally, no code is required. However, if either ** ** (a) The table is the parent table of a FK constraint, or ** (b) The table is the child table of a deferred FK constraint and it is ** determined at runtime that there are outstanding deferred FK ** constraint violations in the database, ** ** 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) && !IsVirtual(pTab) ){ int iSkip = 0; Vdbe *v = sqlite3GetVdbe(pParse); assert( v ); /* VDBE has already been allocated */ assert( pTab->pSelect==0 ); /* Not a view */ 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->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); } |
︙ | ︙ | |||
832 833 834 835 836 837 838 | 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 ){ | | | 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 | 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->zName, zKey) ) return 1; }else if( pCol->colFlags & COLFLAG_PRIMKEY ){ return 1; } } } } return 0; |
︙ | ︙ | |||
899 900 901 902 903 904 905 | 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; | < | | 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 | 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). */ for(pFKey=pTab->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; |
︙ | ︙ | |||
945 946 947 948 949 950 951 | ** 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++){ | < | < | 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 | ** 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 iReg = pFKey->aCol[i].iFrom + regOld + 1; sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iJump); VdbeCoverage(v); } sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, -1); } continue; } assert( pFKey->nCol==1 || (aiFree && pIdx) ); |
︙ | ︙ | |||
973 974 975 976 977 978 979 | 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; | | | 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 | assert( pIdx==0 || pIdx->aiColumn[i]>=0 ); #ifndef SQLITE_OMIT_AUTHORIZATION /* Request permission to read the parent key columns. If the ** authorization callback returns SQLITE_IGNORE, behave as if any ** values read from the parent table are NULL. */ if( db->xAuth ){ int rcauth; char *zCol = pTo->aCol[pIdx ? pIdx->aiColumn[i] : pTo->iPKey].zName; rcauth = sqlite3AuthReadCol(pParse, pTo->zName, zCol, iDb); bIgnore = (rcauth==SQLITE_IGNORE); } #endif } /* Take a shared-cache advisory read-lock on the parent table. Allocate |
︙ | ︙ | |||
1037 1038 1039 1040 1041 1042 1043 | } 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 ){ | | | 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 | } 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 ){ struct SrcList_item *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); |
︙ | ︙ | |||
1088 1089 1090 1091 1092 1093 1094 | ** row contained in table pTab. */ u32 sqlite3FkOldmask( Parse *pParse, /* Parse context */ Table *pTab /* Table being modified */ ){ u32 mask = 0; | | | | 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 | ** 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 ){ FKey *p; int i; for(p=pTab->pFKey; p; p=p->pNextFrom){ for(i=0; i<p->nCol; i++) mask |= COLUMN_MASK(p->aCol[i].iFrom); } for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ Index *pIdx = 0; sqlite3FkLocateIndex(pParse, pTab, p, &pIdx, 0); if( pIdx ){ for(i=0; i<pIdx->nKeyCol; i++){ |
︙ | ︙ | |||
1125 1126 1127 1128 1129 1130 1131 | ** ** 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: ** | | < < | < | | | > < | | | | | | | 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 | ** ** 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, 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 = 0; if( pParse->db->flags&SQLITE_ForeignKeys ){ 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. */ eRet = (sqlite3FkReferences(pTab) || pTab->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->pFKey; p; p=p->pNextFrom){ if( 0==sqlite3_stricmp(pTab->zName, p->zTo) ) return 2; if( fkChildIsModified(pTab, p, aChange, chngRowid) ){ eRet = 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; eRet = 1; } } } } return eRet; } /* ** 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 ** DELETE, pChanges is passed a NULL pointer. ** ** It returns a pointer to a Trigger structure containing a trigger ** equivalent to the ON UPDATE or ON DELETE action specified by pFKey. ** If the action is "NO ACTION" or "RESTRICT", then a NULL pointer is ** returned (these actions require no special handling by the triggers ** sub-system, code for them is created by fkScanChildren()). ** ** For example, if pFKey is the foreign key and pTab is table "p" in ** the following schema: ** ** CREATE TABLE p(pk PRIMARY KEY); ** CREATE TABLE c(ck REFERENCES p ON DELETE CASCADE); ** |
︙ | ︙ | |||
1246 1247 1248 1249 1250 1251 1252 | 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, | | | | | < | < < < < < < < < < < < < | | | | 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 | 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].zName); sqlite3TokenInit(&tFromCol, pFKey->pFrom->aCol[iFromCol].zName); /* 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(db, 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(db, 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 ){ Expr *pDflt = pFKey->pFrom->aCol[iFromCol].pDflt; if( pDflt ){ pNew = sqlite3ExprDup(db, pDflt, 0); }else{ pNew = sqlite3ExprAlloc(db, TK_NULL, 0, 0); } }else{ pNew = sqlite3ExprAlloc(db, TK_NULL, 0, 0); } pList = sqlite3ExprListAppend(pParse, pList, pNew); sqlite3ExprListSetName(pParse, pList, &tFromCol, 0); } } sqlite3DbFree(db, aiCol); zFrom = pFKey->pFrom->zName; nFrom = sqlite3Strlen30(zFrom); if( action==OE_Restrict ){ Token tFrom; Expr *pRaise; tFrom.z = zFrom; tFrom.n = nFrom; pRaise = sqlite3Expr(db, TK_RAISE, "FOREIGN KEY constraint failed"); if( pRaise ){ pRaise->affinity = 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 */ db->lookaside.bDisable++; pTrigger = (Trigger *)sqlite3DbMallocZero(db, sizeof(Trigger) + /* struct Trigger */ sizeof(TriggerStep) + /* Single step in trigger program */ nFrom + 1 /* Space for pStep->zTarget */ ); if( pTrigger ){ |
︙ | ︙ | |||
1358 1359 1360 1361 1362 1363 1364 | 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. */ | | < | < | 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 | 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. */ db->lookaside.bDisable--; sqlite3ExprDelete(db, pWhere); sqlite3ExprDelete(db, pWhen); sqlite3ExprListDelete(db, pList); sqlite3SelectDelete(db, pSelect); if( db->mallocFailed==1 ){ fkTriggerDelete(db, pTrigger); return 0; } assert( pStep!=0 ); switch( action ){ case OE_Restrict: pStep->op = TK_SELECT; break; case OE_Cascade: if( !pChanges ){ pStep->op = TK_DELETE; break; } default: pStep->op = TK_UPDATE; } pStep->pTrig = pTrigger; pTrigger->pSchema = pTab->pSchema; pTrigger->pTabSchema = pTab->pSchema; pFKey->apTrigger[iAction] = pTrigger; |
︙ | ︙ | |||
1434 1435 1436 1437 1438 1439 1440 | ** 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 */ | < | < | > | | 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 | ** 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( db==0 || IsVirtual(pTab) || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) ); for(pFKey=pTab->pFKey; pFKey; pFKey=pNext){ /* 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; const char *z = (p ? pFKey->pNextTo->zTo : pFKey->zTo); sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, p); } |
︙ | ︙ |
Changes to src/func.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 | ** 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> | < < < | 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; |
︙ | ︙ | |||
93 94 95 96 97 98 99 | /* EVIDENCE-OF: R-01470-60482 The sqlite3_value_type(V) interface returns ** the datatype code for the initial datatype of the sqlite3_value object ** V. The returned value is one of SQLITE_INTEGER, SQLITE_FLOAT, ** SQLITE_TEXT, SQLITE_BLOB, or SQLITE_NULL. */ sqlite3_result_text(context, azType[i], -1, SQLITE_STATIC); } | < < < < < < < < < < < < | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | /* EVIDENCE-OF: R-01470-60482 The sqlite3_value_type(V) interface returns ** the datatype code for the initial datatype of the sqlite3_value object ** V. The returned value is one of SQLITE_INTEGER, SQLITE_FLOAT, ** SQLITE_TEXT, SQLITE_BLOB, or SQLITE_NULL. */ sqlite3_result_text(context, azType[i], -1, SQLITE_STATIC); } /* ** Implementation of the length() function */ static void lengthFunc( sqlite3_context *context, int argc, |
︙ | ︙ | |||
213 214 215 216 217 218 219 | const unsigned char *zNeedle; int nHaystack; int nNeedle; int typeHaystack, typeNeedle; int N = 1; int isText; unsigned char firstChar; | < < | < < < < < < < < < < | < < < < < < < | | 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 | const unsigned char *zNeedle; int nHaystack; int nNeedle; int typeHaystack, typeNeedle; int N = 1; int isText; unsigned char firstChar; 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{ zHaystack = sqlite3_value_text(argv[0]); zNeedle = sqlite3_value_text(argv[1]); isText = 1; } if( zNeedle==0 || (nHaystack && zHaystack==0) ) return; 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); } /* ** Implementation of the printf() function. */ static void printfFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ PrintfArguments x; |
︙ | ︙ | |||
416 417 418 419 420 421 422 | } 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. */ | | | | | | 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 | } 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( n==0 && r>=0 && r<LARGEST_INT64-1 ){ r = (double)((sqlite_int64)(r+0.5)); }else if( n==0 && r<0 && (-r)<LARGEST_INT64-1 ){ r = -(double)((sqlite_int64)((-r)+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); |
︙ | ︙ | |||
579 580 581 582 583 584 585 | ** function. */ sqlite3_result_int64(context, sqlite3_last_insert_rowid(db)); } /* ** Implementation of the changes() SQL function. ** | | | | | | | | | | 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 | ** function. */ sqlite3_result_int64(context, sqlite3_last_insert_rowid(db)); } /* ** Implementation of the changes() SQL function. ** ** IMP: R-62073-11209 The changes() SQL function is a wrapper ** around the sqlite3_changes() 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_int(context, sqlite3_changes(db)); } /* ** Implementation of the total_changes() SQL function. The return value is ** the same as the sqlite3_total_changes() 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-52756-41993 This function is a wrapper around the ** sqlite3_total_changes() C/C++ interface. */ sqlite3_result_int(context, sqlite3_total_changes(db)); } /* ** A structure defining how to do GLOB-style comparisons. */ struct compareInfo { u8 matchAll; /* "*" or "%" */ |
︙ | ︙ | |||
702 703 704 705 706 707 708 | 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 */ | | < | 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 | 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 ){ 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 ){ |
︙ | ︙ | |||
736 737 738 739 740 741 742 | ** first matching character and recursively continue the match from ** that point. ** ** For a case-insensitive search, set variable cx to be the same as ** c but in the other case and search the input string for either ** c or cx. */ | | | 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 | ** first matching character and recursively continue the match from ** that point. ** ** For a case-insensitive search, set variable cx to be the same as ** c but in the other case and search the input string for either ** c or cx. */ if( c<=0x80 ){ char zStop[3]; int bMatch; if( noCase ){ zStop[0] = sqlite3Toupper(c); zStop[1] = sqlite3Tolower(c); zStop[2] = 0; }else{ |
︙ | ︙ | |||
819 820 821 822 823 824 825 | } /* ** The sqlite3_strglob() interface. Return 0 on a match (like strcmp()) and ** non-zero if there is no match. */ int sqlite3_strglob(const char *zGlobPattern, const char *zString){ | < < < < < | < < < < < < | < | 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 | } /* ** The sqlite3_strglob() interface. Return 0 on a match (like strcmp()) and ** non-zero if there is no match. */ int sqlite3_strglob(const char *zGlobPattern, const char *zString){ return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '['); } /* ** The sqlite3_strlike() interface. Return 0 on a match and non-zero for ** a miss - like strcmp(). */ int sqlite3_strlike(const char *zPattern, const char *zStr, unsigned int esc){ return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc); } /* ** Count the number of times that the LIKE operator (or GLOB which is ** just a variation of LIKE) gets called. This is used for testing ** only. */ |
︙ | ︙ | |||
874 875 876 877 878 879 880 | 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); | < > > > > < < < < < < < < | 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 | 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 zB = sqlite3_value_text(argv[0]); zA = sqlite3_value_text(argv[1]); /* 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; } assert( zB==sqlite3_value_text(argv[0]) ); /* Encoding did not change */ 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); }else{ escape = pInfo->matchSet; } if( zA && zB ){ #ifdef SQLITE_TEST sqlite3_like_count++; #endif sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape)==SQLITE_MATCH); } |
︙ | ︙ | |||
1047 1048 1049 1050 1051 1052 1053 | ** digits. */ static const char hexdigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; /* | | | > > > | < < < | | | | | | < < | | < | | < > | > | | | < | | | > > > | > | > > > > > > > > > > > > > > > | | < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | ** digits. */ static const char hexdigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; /* ** Implementation of the QUOTE() function. This function takes a single ** argument. If the argument is numeric, the return value is the same as ** the argument. If the argument is NULL, the return value is the string ** "NULL". Otherwise, the argument is enclosed in single quotes with ** single-quote escapes. */ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ assert( argc==1 ); UNUSED_PARAMETER(argc); switch( sqlite3_value_type(argv[0]) ){ case SQLITE_FLOAT: { double r1, r2; char zBuf[50]; r1 = sqlite3_value_double(argv[0]); sqlite3_snprintf(sizeof(zBuf), zBuf, "%!.15g", r1); sqlite3AtoF(zBuf, &r2, 20, SQLITE_UTF8); if( r1!=r2 ){ sqlite3_snprintf(sizeof(zBuf), zBuf, "%!.20e", r1); } sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); break; } case SQLITE_INTEGER: { sqlite3_result_value(context, argv[0]); break; } case SQLITE_BLOB: { char *zText = 0; char const *zBlob = sqlite3_value_blob(argv[0]); int nBlob = sqlite3_value_bytes(argv[0]); assert( zBlob==sqlite3_value_blob(argv[0]) ); /* No encoding change */ zText = (char *)contextMalloc(context, (2*(i64)nBlob)+4); if( zText ){ int i; for(i=0; i<nBlob; i++){ zText[(i*2)+2] = hexdigits[(zBlob[i]>>4)&0x0F]; zText[(i*2)+3] = hexdigits[(zBlob[i])&0x0F]; } zText[(nBlob*2)+2] = '\''; zText[(nBlob*2)+3] = '\0'; zText[0] = 'X'; zText[1] = '\''; sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT); sqlite3_free(zText); } break; } case SQLITE_TEXT: { int i,j; u64 n; const unsigned char *zArg = sqlite3_value_text(argv[0]); char *z; if( zArg==0 ) return; for(i=0, n=0; zArg[i]; i++){ if( zArg[i]=='\'' ) n++; } z = contextMalloc(context, ((i64)i)+((i64)n)+3); if( z ){ z[0] = '\''; for(i=0, j=1; zArg[i]; i++){ z[j++] = zArg[i]; if( zArg[i]=='\'' ){ z[j++] = '\''; } } z[j++] = '\''; z[j] = 0; sqlite3_result_text(context, z, j, sqlite3_free); } break; } default: { assert( sqlite3_value_type(argv[0])==SQLITE_NULL ); sqlite3_result_text(context, "NULL", 4, SQLITE_STATIC); break; } } } /* ** The unicode() function. Return the integer unicode code-point value ** for the first character of the input string. */ static void unicodeFunc( sqlite3_context *context, int argc, |
︙ | ︙ | |||
1218 1219 1220 1221 1222 1223 1224 | *(z++) = hexdigits[(c>>4)&0xf]; *(z++) = hexdigits[c&0xf]; } *z = 0; sqlite3_result_text(context, zHex, n*2, sqlite3_free); } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 | *(z++) = hexdigits[(c>>4)&0xf]; *(z++) = hexdigits[c&0xf]; } *z = 0; sqlite3_result_text(context, zHex, n*2, sqlite3_free); } } /* ** The zeroblob(N) function returns a zero-filled blob of size N bytes. */ static void zeroblobFunc( sqlite3_context *context, int argc, |
︙ | ︙ | |||
1403 1404 1405 1406 1407 1408 1409 | } 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; | | | 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 | } 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 = sqlite3_realloc64(zOut, (int)nOut + (nOut - nStr - 1)); if( zOut==0 ){ sqlite3_result_error_nomem(context); sqlite3_free(zOld); return; } } } |
︙ | ︙ | |||
1435 1436 1437 1438 1439 1440 1441 | 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 */ | | | | | | | < | | | | | 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 | 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 */ int nIn; /* Number of bytes in input */ int flags; /* 1: trimleft 2: trimright 3: trim */ int i; /* Loop counter */ unsigned char *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 = sqlite3_value_bytes(argv[0]); assert( zIn==sqlite3_value_text(argv[0]) ); if( argc==1 ){ static const unsigned char lenOne[] = { 1 }; static unsigned char * const azOne[] = { (u8*)" " }; nChar = 1; aLen = (u8*)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*)+1)); if( azChar==0 ){ return; } aLen = (unsigned char*)&azChar[nChar]; for(z=zCharSet, nChar=0; *z; nChar++){ azChar[nChar] = (unsigned char *)z; SQLITE_SKIP_UTF8(z); aLen[nChar] = (u8)(z - azChar[nChar]); } } } if( nChar>0 ){ flags = SQLITE_PTR_TO_INT(sqlite3_user_data(context)); if( flags & 1 ){ while( nIn>0 ){ 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 ){ 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; } |
︙ | ︙ | |||
1526 1527 1528 1529 1530 1531 1532 | */ static void unknownFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ /* no-op */ | < < < | 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 | */ static void unknownFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ /* no-op */ } #endif /*SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION*/ /* IMP: R-25361-16150 This function is omitted from SQLite by default. It ** is only available if the SQLITE_SOUNDEX compile-time option is used ** when SQLite is built. |
︙ | ︙ | |||
1837 1838 1839 1840 1841 1842 1843 | #endif /* SQLITE_OMIT_WINDOWFUNC */ static void minMaxFinalize(sqlite3_context *context){ minMaxValueFinalize(context, 0); } /* ** group_concat(EXPR, ?SEPARATOR?) | < < < < < < < < < < < < < < < < < < < < | | > | | | < | < < < < < < < | | | < < < < | | < < < < < < < < < < < < < < < < < | < < | < < < < < | < < | < > | < | | | < < < < | < < < | | < < < < < > | | | | < | < < < | | | > | | > > > | < > | | | < | | 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 | #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; StrAccum *pAccum; const char *zSep; int nVal, nSep; assert( argc==1 || argc==2 ); if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; pAccum = (StrAccum*)sqlite3_aggregate_context(context, sizeof(*pAccum)); if( pAccum ){ sqlite3 *db = sqlite3_context_db_handle(context); int firstTerm = pAccum->mxAlloc==0; pAccum->mxAlloc = db->aLimit[SQLITE_LIMIT_LENGTH]; if( !firstTerm ){ if( argc==2 ){ zSep = (char*)sqlite3_value_text(argv[1]); nSep = sqlite3_value_bytes(argv[1]); }else{ zSep = ","; nSep = 1; } if( zSep ) sqlite3_str_append(pAccum, zSep, nSep); } zVal = (char*)sqlite3_value_text(argv[0]); nVal = sqlite3_value_bytes(argv[0]); if( zVal ) sqlite3_str_append(pAccum, zVal, nVal); } } #ifndef SQLITE_OMIT_WINDOWFUNC static void groupConcatInverse( sqlite3_context *context, int argc, sqlite3_value **argv ){ int n; StrAccum *pAccum; assert( argc==1 || argc==2 ); if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; pAccum = (StrAccum*)sqlite3_aggregate_context(context, sizeof(*pAccum)); /* pAccum is always non-NULL since groupConcatStep() will have always ** run frist to initialize it */ if( ALWAYS(pAccum) ){ n = sqlite3_value_bytes(argv[0]); if( argc==2 ){ n += sqlite3_value_bytes(argv[1]); }else{ n++; } if( n>=(int)pAccum->nChar ){ pAccum->nChar = 0; }else{ pAccum->nChar -= n; memmove(pAccum->zText, &pAccum->zText[n], pAccum->nChar); } if( pAccum->nChar==0 ) pAccum->mxAlloc = 0; } } #else # define groupConcatInverse 0 #endif /* SQLITE_OMIT_WINDOWFUNC */ static void groupConcatFinalize(sqlite3_context *context){ StrAccum *pAccum; pAccum = sqlite3_aggregate_context(context, 0); if( pAccum ){ if( pAccum->accError==SQLITE_TOOBIG ){ sqlite3_result_error_toobig(context); }else if( pAccum->accError==SQLITE_NOMEM ){ sqlite3_result_error_nomem(context); }else{ sqlite3_result_text(context, sqlite3StrAccumFinish(pAccum), -1, sqlite3_free); } } } #ifndef SQLITE_OMIT_WINDOWFUNC static void groupConcatValue(sqlite3_context *context){ sqlite3_str *pAccum; pAccum = (sqlite3_str*)sqlite3_aggregate_context(context, 0); if( pAccum ){ 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, -1, SQLITE_TRANSIENT); } } } #else # define groupConcatValue 0 #endif /* SQLITE_OMIT_WINDOWFUNC */ |
︙ | ︙ | |||
2019 2020 2021 2022 2023 2024 2025 | assert( rc==SQLITE_NOMEM || rc==SQLITE_OK ); if( rc==SQLITE_NOMEM ){ sqlite3OomFault(db); } } /* | > > > > > > > > > > > > > > > | | < < < | > > | > | 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 | assert( rc==SQLITE_NOMEM || rc==SQLITE_OK ); if( rc==SQLITE_NOMEM ){ sqlite3OomFault(db); } } /* ** Set the LIKEOPT flag on the 2-argument function with the given name. */ static void setLikeOptFlag(sqlite3 *db, const char *zName, u8 flagVal){ FuncDef *pDef; pDef = sqlite3FindFunction(db, zName, 2, SQLITE_UTF8, 0); if( ALWAYS(pDef) ){ pDef->funcFlags |= flagVal; } pDef = sqlite3FindFunction(db, zName, 3, SQLITE_UTF8, 0); if( pDef ){ pDef->funcFlags |= flagVal; } } /* ** Register the built-in LIKE and GLOB functions. The caseSensitive ** parameter determines whether or not the LIKE operator is case ** sensitive. GLOB is always case sensitive. */ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){ struct compareInfo *pInfo; if( caseSensitive ){ pInfo = (struct compareInfo*)&likeInfoAlt; }else{ pInfo = (struct compareInfo*)&likeInfoNorm; } 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); sqlite3CreateFunc(db, "glob", 2, SQLITE_UTF8, (struct compareInfo*)&globInfo, likeFunc, 0, 0, 0, 0, 0); setLikeOptFlag(db, "glob", SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE); setLikeOptFlag(db, "like", caseSensitive ? (SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE) : SQLITE_FUNC_LIKE); } /* ** 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 |
︙ | ︙ | |||
2059 2060 2061 2062 2063 2064 2065 | ** 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; | < | < < > < < < < > > > > > > > > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | > > > | > | | < < < | < < < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < > > > < < | 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 | ** 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; if( pExpr->op!=TK_FUNCTION || !pExpr->x.pList ){ return 0; } assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); nExpr = pExpr->x.pList->nExpr; pDef = sqlite3FindFunction(db, pExpr->u.zToken, nExpr, SQLITE_UTF8, 0); if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){ return 0; } if( nExpr<3 ){ aWc[3] = 0; }else{ Expr *pEscape = pExpr->x.pList->a[2].pExpr; char *zEscape; if( pEscape->op!=TK_STRING ) return 0; zEscape = pEscape->u.zToken; if( zEscape[0]==0 || zEscape[1]!=0 ) return 0; aWc[3] = zEscape[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 ); *pIsNocase = (pDef->funcFlags & SQLITE_FUNC_CASE)==0; return 1; } /* ** 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[] = { #ifdef SQLITE_SOUNDEX FUNCTION(soundex, 1, 0, 0, soundexFunc ), #endif #ifndef SQLITE_OMIT_LOAD_EXTENSION VFUNCTION(load_extension, 1, 0, 0, loadExt ), VFUNCTION(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 */ FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), FUNCTION2(likely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY), #ifdef SQLITE_DEBUG FUNCTION2(affinity, 1, 0, 0, noopFunc, SQLITE_FUNC_AFFINITY), #endif #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC FUNCTION2(sqlite_offset, 1, 0, 0, noopFunc, SQLITE_FUNC_OFFSET| SQLITE_FUNC_TYPEOF), #endif FUNCTION(ltrim, 1, 1, 0, trimFunc ), FUNCTION(ltrim, 2, 1, 0, trimFunc ), FUNCTION(rtrim, 1, 2, 0, trimFunc ), FUNCTION(rtrim, 2, 2, 0, trimFunc ), FUNCTION(trim, 1, 3, 0, trimFunc ), 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 ), FUNCTION(max, -1, 1, 1, minmaxFunc ), FUNCTION(max, 0, 1, 1, 0 ), WAGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize, minMaxValue, 0, SQLITE_FUNC_MINMAX ), 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 ), FUNCTION2(ifnull, 2, 0, 0, noopFunc, SQLITE_FUNC_COALESCE), 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 ), 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 ), WAGGREGATE(count, 1,0,0, countStep, countFinalize, countFinalize, countInverse, 0 ), 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 ), FUNCTION2(coalesce, -1, 0, 0, noopFunc, SQLITE_FUNC_COALESCE), }; #ifndef SQLITE_OMIT_ALTERTABLE sqlite3AlterFunctions(); #endif sqlite3WindowFunctions(); #if defined(SQLITE_ENABLE_STAT3) || defined(SQLITE_ENABLE_STAT4) sqlite3AnalyzeFunctions(); #endif 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; 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 | 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 }; /* ** The following 256 byte lookup table is used to support SQLites built-in ** equivalents to the following standard library functions: ** ** isspace() 0x01 ** isalpha() 0x02 |
︙ | ︙ | |||
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 ()*+,-./ */ | > | 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | ** 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. */ #ifdef SQLITE_ASCII 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 ()*+,-./ */ |
︙ | ︙ | |||
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | 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 | > > > > > > > | > | < < < < < < < | 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 | 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 ........ */ }; #endif /* 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. ** ** URI filenames are enabled by default if SQLITE_HAS_CODEC is ** enabled. */ #ifndef SQLITE_USE_URI # ifdef SQLITE_HAS_CODEC # define SQLITE_USE_URI 1 # else # define SQLITE_USE_URI 0 # endif #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. */ #ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN # define SQLITE_ALLOW_COVERING_INDEX_SCAN 1 #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 |
︙ | ︙ | |||
205 206 207 208 209 210 211 | /* ** 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); | < < < < < < | < < < | 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | /* ** 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 # define SQLITE_DEFAULT_LOOKASIDE 1200,100 #endif /* The default maximum size of an in-memory database created using ** sqlite3_deserialize() */ #ifndef SQLITE_MEMDB_DEFAULT_MAXSIZE |
︙ | ︙ | |||
238 239 240 241 242 243 244 | 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 */ | < | 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | 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 */ 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 */ |
︙ | ︙ | |||
275 276 277 278 279 280 281 | 0, /* xSqllog */ 0, /* pSqllogArg */ #endif #ifdef SQLITE_VDBE_COVERAGE 0, /* xVdbeBranch */ 0, /* pVbeBranchArg */ #endif | | | < < < < < < | < < < < | < > > > | 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 | 0, /* xSqllog */ 0, /* pSqllogArg */ #endif #ifdef SQLITE_VDBE_COVERAGE 0, /* xVdbeBranch */ 0, /* pVbeBranchArg */ #endif #ifdef SQLITE_ENABLE_DESERIALIZE SQLITE_MEMDB_DEFAULT_MAXSIZE, /* mxMemdbSize */ #endif #ifndef SQLITE_UNTESTABLE 0, /* xTestCallback */ #endif 0, /* bLocaltimeFault */ 0, /* bInternalFunctions */ 0x7ffffffe, /* iOnceResetThreshold */ SQLITE_DEFAULT_SORTERREF_SIZE, /* szSorterRef */ }; /* ** Hash table for global functions - functions common to all ** database connections. After initialization, this table is ** read-only. */ FuncDefHash sqlite3BuiltinFunctions; /* ** Constant tokens for values 0 and 1. */ const Token sqlite3IntTokens[] = { { "0", 1 }, { "1", 1 } }; #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; |
︙ | ︙ | |||
340 341 342 343 344 345 346 | ** Changing the pending byte during operation will result in undefined ** and incorrect behavior. */ #ifndef SQLITE_OMIT_WSD int sqlite3PendingByte = 0x40000000; #endif | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 | ** 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"; |
Changes to src/hash.c.
︙ | ︙ | |||
162 163 164 165 166 167 168 | count = pEntry->count; }else{ h = 0; elem = pH->first; count = pH->count; } if( pHash ) *pHash = h; | | < | 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | count = pEntry->count; }else{ h = 0; elem = pH->first; count = pH->count; } if( pHash ) *pHash = h; while( count-- ){ assert( elem!=0 ); if( sqlite3StrICmp(elem->pKey,pKey)==0 ){ return elem; } elem = elem->next; } return &nullElement; } /* Remove a single entry from the hash table given a pointer to that ** element and a hash on the element's key. */ |
︙ | ︙ |
Changes to src/hash.h.
︙ | ︙ | |||
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) // NOT USED */ #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 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(__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(__GNUC__) && defined(__x86_64__)) __inline__ sqlite_uint64 sqlite3Hwtime(void){ unsigned long val; __asm__ __volatile__ ("rdtsc" : "=A" (val)); return val; } #elif (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 #error Need implementation of sqlite3Hwtime() for your platform. /* ** To compile without implementing sqlite3Hwtime() for your platform, ** you can remove the above #error and use the following ** stub function. You will lose timing support for many ** of the debugging and testing utilities, but it should at ** least compile and run. */ 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 49 50 51 52 | 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) ); v = sqlite3GetVdbe(pParse); 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->nCol); 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); VdbeComment((v, "%s", pTab->zName)); } } /* |
︙ | ︙ | |||
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]; | < | | > < | < | > < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | > | > > > > > > > < < | 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 | 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 ){ pIdx->zColAff[n] = pTab->aCol[x].affinity; }else if( x==XN_ROWID ){ pIdx->zColAff[n] = SQLITE_AFF_INTEGER; }else{ char aff; assert( x==XN_EXPR ); assert( pIdx->bHasExpr ); assert( pIdx->aColExpr!=0 ); aff = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr); if( aff==0 ) aff = SQLITE_AFF_BLOB; pIdx->zColAff[n] = aff; } } pIdx->zColAff[n] = 0; } return pIdx->zColAff; } /* ** 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 exists (if it is no entirely SQLITE_AFF_BLOB values) and ** if iReg>0 then code an OP_Affinity opcode that will set the affinities ** for register iReg and following. Or if affinities exists and 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 */ void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){ int i; char *zColAff = pTab->zColAff; if( zColAff==0 ){ sqlite3 *db = sqlite3VdbeDb(v); zColAff = (char *)sqlite3DbMallocRaw(0, pTab->nCol+1); if( !zColAff ){ sqlite3OomFault(db); return; } for(i=0; i<pTab->nCol; i++){ zColAff[i] = pTab->aCol[i].affinity; } do{ zColAff[i--] = 0; }while( i>=0 && zColAff[i]==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{ sqlite3VdbeChangeP4(v, -1, zColAff, i); } } } /* ** Return non-zero if the table pTab in database iDb or any of its indices |
︙ | ︙ | |||
231 232 233 234 235 236 237 | #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; | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | #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; int 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; } #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 |
︙ | ︙ | |||
414 415 416 417 418 419 420 | 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) | | < < | | 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 | 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) || 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)); if( pInfo==0 ) 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 */ |
︙ | ︙ | |||
680 681 682 683 684 685 686 | ** 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 */ | | | 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 | ** 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. */ 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 */ |
︙ | ︙ | |||
705 706 707 708 709 710 711 | 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 */ | < < | < | 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 | 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 */ int regData; /* register holding first column to insert */ int *aRegIdx = 0; /* One register allocated to each index */ #ifndef SQLITE_OMIT_TRIGGER int isView; /* True if attempting to insert into a view */ Trigger *pTrigger; /* List of triggers on pTab, if required */ int tmask; /* Mask of trigger times */ #endif db = pParse->db; if( pParse->nErr || db->mallocFailed ){ goto insert_cleanup; } dest.iSDParm = 0; /* Suppress a harmless compiler warning */ /* If the Select object is really just a simple VALUES() list with a ** single row (the common case) then keep that one row of values ** and discard the other (unused) parts of the pSelect object */ if( pSelect && (pSelect->selFlags & SF_Values)!=0 && pSelect->pPrior==0 ){ |
︙ | ︙ | |||
761 762 763 764 765 766 767 | 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); | | < < < < < < < < | 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 | 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 = pTab->pSelect!=0; #else # define pTrigger 0 # define tmask 0 # define isView 0 #endif #ifdef SQLITE_OMIT_VIEW # undef isView # define isView 0 #endif assert( (pTrigger && tmask) || (pTrigger==0 && tmask==0) ); /* If pTab is really a view, make sure it has been initialized. ** ViewGetColumnNames() is a no-op if pTab is not a view. */ if( sqlite3ViewGetColumnNames(pParse, pTab) ){ goto insert_cleanup; } |
︙ | ︙ | |||
811 812 813 814 815 816 817 | ** INSERT INTO <table1> SELECT * FROM <table2>; ** ** Then special optimizations can be applied that make the transfer ** very fast and which reduce fragmentation of indices. ** ** This is the 2nd template. */ | < < < | < | | | < < < < < < < < | < < | | | < < < < < < < < | | 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 | ** INSERT INTO <table1> SELECT * FROM <table2>; ** ** Then special optimizations can be applied that make the transfer ** very fast and which reduce fragmentation of indices. ** ** This is the 2nd template. */ if( pColumn==0 && xferOptimization(pParse, pTab, pSelect, onError, iDb) ){ assert( !pTrigger ); assert( pList==0 ); goto insert_end; } #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 registers for holding the rowid of the new row, ** the content of the new row, and the assembled row record. */ 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.) */ bIdListInOrder = (pTab->tabFlags & TF_OOOHidden)==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].zName)==0 ){ pColumn->a[i].idx = j; if( i!=j ) bIdListInOrder = 0; if( j==pTab->iPKey ){ ipkColumn = i; assert( !withoutRowid ); } 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, 0, pColumn->a[i].zName); pParse->checkSchema = 1; goto insert_cleanup; } } } } |
︙ | ︙ | |||
917 918 919 920 921 922 923 | addrTop = sqlite3VdbeCurrentAddr(v) + 1; sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop); sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield); dest.iSdst = bIdListInOrder ? regData : 0; dest.nSdst = pTab->nCol; rc = sqlite3Select(pParse, pSelect, &dest); regFromSelect = dest.iSdst; | < | < | 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 | addrTop = sqlite3VdbeCurrentAddr(v) + 1; sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop); sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield); dest.iSdst = bIdListInOrder ? regData : 0; dest.nSdst = pTab->nCol; rc = sqlite3Select(pParse, pSelect, &dest); regFromSelect = dest.iSdst; if( rc || db->mallocFailed || pParse->nErr ) goto insert_cleanup; sqlite3VdbeEndCoroutine(v, regYield); sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */ assert( pSelect->pEList ); nColumn = pSelect->pEList->nExpr; /* Set useTempTable to TRUE if the result of the SELECT statement ** should be written into a temporary table (template 4). Set to |
︙ | ︙ | |||
991 992 993 994 995 996 997 | /* 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; | < < < < < < < < < | | < < < | | | < < < < | | | < | | | | | < < | < < < < < < < < < < < | | | | | | < | < < < | 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 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; } /* Make sure the number of columns in the source data matches the number ** of columns to be inserted into the table. */ for(i=0; i<pTab->nCol; i++){ nHidden += (IsHiddenColumn(&pTab->aCol[i]) ? 1 : 0); } if( pColumn==0 && nColumn && nColumn!=(pTab->nCol-nHidden) ){ sqlite3ErrorMsg(pParse, "table %S has %d columns but %d values were supplied", pTabList, 0, 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 ){ 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+1)); 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; } } #ifndef SQLITE_OMIT_UPSERT if( pUpsert ){ if( IsVirtual(pTab) ){ sqlite3ErrorMsg(pParse, "UPSERT not implemented for virtual table \"%s\"", pTab->zName); goto insert_cleanup; } pTabList->a[0].iCursor = iDataCur; pUpsert->pUpsertSrc = pTabList; pUpsert->regData = regData; pUpsert->iDataCur = iDataCur; pUpsert->iIdxCur = iIdxCur; if( pUpsert->pUpsertTarget ){ sqlite3UpsertAnalyzeTarget(pParse, pTabList, pUpsert); } } #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 |
︙ | ︙ | |||
1110 1111 1112 1113 1114 1115 1116 | ** following pseudocode (template 3): ** ** C: yield X, at EOF goto D ** insert the select result into <table> from R..R+n ** goto C ** D: ... */ | < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 | ** 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); } /* 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); |
︙ | ︙ | |||
1236 1237 1238 1239 1240 1241 1242 | } addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regCols); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols); sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp1(v, OP_MustBeInt, regCols); VdbeCoverage(v); } | | > > | < < | > > | | < | > > > | | > > > > | | < > > > > > < | | 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 | } addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, regCols); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols); sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp1(v, OP_MustBeInt, regCols); VdbeCoverage(v); } /* Cannot have triggers on a virtual table. If it were possible, ** this block would have to account for hidden column. */ assert( !IsVirtual(pTab) ); /* Create the new column data */ for(i=j=0; i<pTab->nCol; i++){ if( pColumn ){ for(j=0; j<pColumn->nId; j++){ if( pColumn->a[j].idx==i ) break; } } if( (!useTempTable && !pList) || (pColumn && j>=pColumn->nId) || (pColumn==0 && IsOrdinaryHiddenColumn(&pTab->aCol[i])) ){ sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i+1); }else if( useTempTable ){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i+1); }else{ assert( pSelect==0 ); /* Otherwise useTempTable is true */ sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr, regCols+i+1); } if( pColumn==0 && !IsOrdinaryHiddenColumn(&pTab->aCol[i]) ) j++; } /* 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); } /* Compute the content of the next row to insert into a range of ** registers beginning at regIns. */ if( !isView ){ if( IsVirtual(pTab) ){ /* The row that the VUpdate opcode will delete: none */ sqlite3VdbeAddOp2(v, OP_Null, 0, regIns); } if( ipkColumn>=0 ){ if( useTempTable ){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, ipkColumn, regRowid); }else if( pSelect ){ sqlite3VdbeAddOp2(v, OP_Copy, regFromSelect+ipkColumn, regRowid); }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); |
︙ | ︙ | |||
1311 1312 1313 1314 1315 1316 1317 | sqlite3VdbeAddOp2(v, OP_Null, 0, regRowid); }else{ sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc); appendFlag = 1; } autoIncStep(pParse, regAutoinc, regRowid); | < | | > | > > > | > > > > > > > | > > > > > > > > > > > > | > > > > > | | > > > | < | < | > > < < < < < < < | 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 | sqlite3VdbeAddOp2(v, OP_Null, 0, regRowid); }else{ sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc); appendFlag = 1; } autoIncStep(pParse, regAutoinc, regRowid); /* Compute data for all columns of the new entry, beginning ** with the first column. */ nHidden = 0; for(i=0; i<pTab->nCol; i++){ int iRegStore = regRowid+1+i; if( i==pTab->iPKey ){ /* The value of the INTEGER PRIMARY KEY column is always a NULL. ** Whenever this column is read, the rowid will be substituted ** in its place. Hence, fill this column with a NULL to avoid ** taking up data space with information that will never be used. ** As there may be shallow copies of this value, make it a soft-NULL */ sqlite3VdbeAddOp1(v, OP_SoftNull, iRegStore); continue; } if( pColumn==0 ){ if( IsHiddenColumn(&pTab->aCol[i]) ){ j = -1; nHidden++; }else{ j = i - nHidden; } }else{ for(j=0; j<pColumn->nId; j++){ if( pColumn->a[j].idx==i ) break; } } if( j<0 || nColumn==0 || (pColumn && j>=pColumn->nId) ){ sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore); }else if( useTempTable ){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, iRegStore); }else if( pSelect ){ if( regFromSelect!=regData ){ sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+j, iRegStore); } }else{ sqlite3ExprCode(pParse, pList->a[j].pExpr, iRegStore); } } /* 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; /* 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 || (pTrigger==0 && ((db->flags & SQLITE_ForeignKeys)==0 || sqlite3FkReferences(pTab)==0) )); sqlite3CompleteInsertion(pParse, pTab, iDataCur, iIdxCur, regIns, aRegIdx, 0, appendFlag, bUseSeek ); } } /* Update the count of rows that are inserted */ if( regRowCount ){ sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1); } |
︙ | ︙ | |||
1387 1388 1389 1390 1391 1392 1393 | 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); | < < < < < < < < < < < | > > | | 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 | 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 ){ sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1); sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows inserted", SQLITE_STATIC); } insert_cleanup: sqlite3SrcListDelete(db, pTabList); sqlite3ExprListDelete(db, pList); sqlite3UpsertDelete(db, pUpsert); sqlite3SelectDelete(db, pSelect); sqlite3IdListDelete(db, pColumn); sqlite3DbFree(db, aRegIdx); } /* Make sure "isView" and other macros defined above are undefined. Otherwise ** they may interfere with compilation of other functions in this file ** (or in another file, if this file becomes part of the amalgamation). */ #ifdef isView #undef isView |
︙ | ︙ | |||
1504 1505 1506 1507 1508 1509 1510 | 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; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 | 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 |
︙ | ︙ | |||
1603 1604 1605 1606 1607 1608 1609 | ** ** 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. ** | < < < < < < < < | 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 | ** ** 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 ** are at iIdxCur+N for the N-th element of the pTab->pIndex list. |
︙ | ︙ | |||
1676 1677 1678 1679 1680 1681 1682 | 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 */ | | > < > | | | < < < < < < < < | | < < < < < | < < < < < | | | < < < < < | | | | > > | | | | | | < < < < < < | < < | < < < | | < < > | | > | > | < < | | | < > > > | | | | | | | | < | | | | | > | | | | | | | | < < < < < < < | < < < < < < < < < | < < < < < < < < < < | < < | | | | 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 | 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 */ sqlite3 *db; /* Database connection */ int i; /* loop counter */ int ix; /* Index loop counter */ int nCol; /* Number of columns */ int onError; /* Conflict resolution strategy */ int addr1; /* Address of jump instruction */ 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 */ Index *pUpIdx = 0; /* Index to which to apply the upsert */ u8 isUpdate; /* True if this is an UPDATE operation */ u8 bAffinityDone = 0; /* True if the OP_Affinity operation has been run */ int upsertBypass = 0; /* Address of Goto to bypass upsert subroutine */ int upsertJump = 0; /* Address of Goto that jumps into upsert subroutine */ int ipkTop = 0; /* Top of the IPK uniqueness check */ int ipkBottom = 0; /* OP_Goto at the end of the IPK uniqueness check */ isUpdate = regOldData!=0; db = pParse->db; v = sqlite3GetVdbe(pParse); assert( v!=0 ); assert( pTab->pSelect==0 ); /* 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. */ for(i=0; i<nCol; i++){ if( i==pTab->iPKey ){ continue; /* ROWID is never NULL */ } if( aiChng && aiChng[i]<0 ){ /* Don't bother checking for NOT NULL on columns that do not change */ continue; } onError = pTab->aCol[i].notNull; if( onError==OE_None ) continue; /* This column is allowed to be NULL */ if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ onError = OE_Abort; } if( onError==OE_Replace && pTab->aCol[i].pDflt==0 ){ onError = OE_Abort; } assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail || onError==OE_Ignore || onError==OE_Replace ); addr1 = 0; switch( onError ){ case OE_Replace: { assert( onError==OE_Replace ); addr1 = sqlite3VdbeMakeLabel(pParse); sqlite3VdbeAddOp2(v, OP_NotNull, regNewData+1+i, addr1); VdbeCoverage(v); sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regNewData+1+i); sqlite3VdbeAddOp2(v, OP_NotNull, regNewData+1+i, addr1); VdbeCoverage(v); onError = OE_Abort; /* Fall through into the OE_Abort case to generate code that runs ** if both the input and the default value are NULL */ } case OE_Abort: sqlite3MayAbort(pParse); /* Fall through */ case OE_Rollback: case OE_Fail: { char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName, pTab->aCol[i].zName); sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, onError, regNewData+1+i); sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC); sqlite3VdbeChangeP5(v, P5_ConstraintNotNull); VdbeCoverage(v); if( addr1 ) sqlite3VdbeResolveLabel(v, addr1); break; } default: { assert( onError==OE_Ignore ); sqlite3VdbeAddOp2(v, OP_IsNull, regNewData+1+i, ignoreDest); VdbeCoverage(v); break; } } } /* 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 *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; } allOk = sqlite3VdbeMakeLabel(pParse); sqlite3VdbeVerifyAbortable(v, onError); sqlite3ExprIfTrue(pParse, pExpr, allOk, SQLITE_JUMPIFNULL); if( onError==OE_Ignore ){ sqlite3VdbeGoto(v, ignoreDest); }else{ char *zName = pCheck->a[i].zName; if( zName==0 ) zName = pTab->zName; if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-15569-63625 */ sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_CHECK, onError, zName, P4_TRANSIENT, P5_ConstraintCheck); } sqlite3VdbeResolveLabel(v, allOk); } pParse->iSelfTab = 0; |
︙ | ︙ | |||
1898 1899 1900 1901 1902 1903 1904 | ** 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. */ | | < < < < < < | | > | | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < | < | < | | | < < < < < < < | < | 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 | ** 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. */ if( pUpsert ){ if( pUpsert->pUpsertTarget==0 ){ /* An ON CONFLICT DO NOTHING clause, without a constraint-target. ** Make all unique constraint resolution be OE_Ignore */ assert( pUpsert->pUpsertSet==0 ); overrideError = OE_Ignore; pUpsert = 0; }else if( (pUpIdx = pUpsert->pUpsertIdx)!=0 ){ /* If the constraint-target uniqueness check must be run first. ** Jump to that uniqueness check now */ upsertJump = sqlite3VdbeAddOp0(v, OP_Goto); VdbeComment((v, "UPSERT constraint goes first")); } } /* 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 && pUpsert->pUpsertIdx==0 ){ if( pUpsert->pUpsertSet==0 ){ onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */ }else{ onError = OE_Update; /* DO UPDATE */ } } /* 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 contraints are different */ && pTab->pIndex /* There exist other constraints */ ){ ipkTop = sqlite3VdbeAddOp0(v, OP_Goto)+1; VdbeComment((v, "defer IPK REPLACE until last")); } if( isUpdate ){ /* pkChng!=0 does not mean that the rowid has changed, only that |
︙ | ︙ | |||
2067 2068 2069 2070 2071 2072 2073 | sqlite3VdbeVerifyAbortable(v, onError); sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regNewData); VdbeCoverage(v); switch( onError ){ default: { onError = OE_Abort; | | | 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 | sqlite3VdbeVerifyAbortable(v, onError); sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regNewData); VdbeCoverage(v); switch( onError ){ default: { onError = OE_Abort; /* Fall thru into the next case */ } case OE_Rollback: case OE_Abort: case OE_Fail: { testcase( onError==OE_Rollback ); testcase( onError==OE_Abort ); testcase( onError==OE_Fail ); |
︙ | ︙ | |||
2101 2102 2103 2104 2105 2106 2107 | ** 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. */ | | > > > > < < | 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 | ** 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. */ Trigger *pTrigger = 0; if( db->flags&SQLITE_RecTriggers ){ pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0); } if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){ sqlite3MultiWrite(pParse); sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur, regNewData, 1, 0, OE_Replace, 1, -1); }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. */ |
︙ | ︙ | |||
2128 2129 2130 2131 2132 2133 2134 | } seenReplace = 1; break; } #ifndef SQLITE_OMIT_UPSERT case OE_Update: { sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, 0, iDataCur); | | < < | < | < < < | > | | | | < | > | | | 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 | } seenReplace = 1; break; } #ifndef SQLITE_OMIT_UPSERT case OE_Update: { sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, 0, iDataCur); /* Fall through */ } #endif case OE_Ignore: { testcase( onError==OE_Ignore ); sqlite3VdbeGoto(v, ignoreDest); break; } } sqlite3VdbeResolveLabel(v, addrRowidOk); 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(ix=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, 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 */ if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */ if( pUpIdx==pIdx ){ addrUniqueOk = upsertJump+1; upsertBypass = sqlite3VdbeGoto(v, 0); VdbeComment((v, "Skip upsert subroutine")); sqlite3VdbeJumpHere(v, upsertJump); }else{ addrUniqueOk = sqlite3VdbeMakeLabel(pParse); } if( bAffinityDone==0 && (pUpIdx==0 || pUpIdx==pIdx) ){ sqlite3TableAffinity(v, pTab, regNewData+1); bAffinityDone = 1; } VdbeNoopComment((v, "uniqueness check for %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); |
︙ | ︙ | |||
2200 2201 2202 2203 2204 2205 2206 | 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)); | > | | < < | < | > | | < | 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 | 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; }else{ x = iField + regNewData + 1; } sqlite3VdbeAddOp2(v, iField<0 ? OP_IntCopy : OP_SCopy, x, regIdx+i); VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName)); } } 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 /* 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); |
︙ | ︙ | |||
2242 2243 2244 2245 2246 2247 2248 | if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ onError = OE_Abort; } /* Figure out if the upsert clause applies to this index */ | | | | < | < | | | | | | < | 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 | 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( pUpIdx==pIdx ){ if( pUpsert->pUpsertSet==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. */ #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->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); 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 = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]); sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i); VdbeComment((v, "%s.%s", pTab->zName, pTab->aCol[pPk->aiColumn[i]].zName)); } } if( isUpdate ){ /* 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. ** ** For a UNIQUE index, only conflict if the PRIMARY KEY values ** of the matched index row are different from the original PRIMARY ** KEY values of this row before the update. */ int addrJump = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol; int op = OP_Ne; int regCmp = (IsPrimaryKeyIndex(pIdx) ? regIdx : regR); for(i=0; i<pPk->nKeyCol; i++){ char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]); x = pPk->aiColumn[i]; assert( x>=0 ); if( i==(pPk->nKeyCol-1) ){ addrJump = addrUniqueOk; op = OP_Eq; } sqlite3VdbeAddOp4(v, op, regOldData+1+x, addrJump, regCmp+i, p4, P4_COLLSEQ ); sqlite3VdbeChangeP5(v, SQLITE_NOTNULL); VdbeCoverageIf(v, op==OP_Eq); VdbeCoverageIf(v, op==OP_Ne); } |
︙ | ︙ | |||
2354 2355 2356 2357 2358 2359 2360 | testcase( onError==OE_Fail ); sqlite3UniqueConstraint(pParse, onError, pIdx); break; } #ifndef SQLITE_OMIT_UPSERT case OE_Update: { sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, pIdx, iIdxCur+ix); | | < | < < < < | | < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | | | > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | testcase( onError==OE_Fail ); sqlite3UniqueConstraint(pParse, onError, pIdx); break; } #ifndef SQLITE_OMIT_UPSERT case OE_Update: { sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, pIdx, iIdxCur+ix); /* Fall through */ } #endif case OE_Ignore: { testcase( onError==OE_Ignore ); sqlite3VdbeGoto(v, ignoreDest); break; } default: { Trigger *pTrigger = 0; assert( onError==OE_Replace ); if( db->flags&SQLITE_RecTriggers ){ pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0); } if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){ sqlite3MultiWrite(pParse); } sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur, regR, nPkField, 0, OE_Replace, (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), iThisCur); seenReplace = 1; break; } } if( pUpIdx==pIdx ){ sqlite3VdbeGoto(v, upsertJump+1); sqlite3VdbeJumpHere(v, upsertBypass); }else{ sqlite3VdbeResolveLabel(v, addrUniqueOk); } if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField); } /* If the IPK constraint is a REPLACE, run it last */ if( ipkTop ){ sqlite3VdbeGoto(v, ipkTop); VdbeComment((v, "Do IPK REPLACE")); sqlite3VdbeJumpHere(v, ipkBottom); } *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].pDflt!=0 ) break; if( pTab->aCol[i].colFlags & COLFLAG_PRIMKEY ) break; } sqlite3VdbeChangeP5(v, i+1); } #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 |
︙ | ︙ | |||
2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 | 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) ); | > > > | | < < < < > > > > > > | > > > > > > > > > > > | | 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 | 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 regData; /* Content registers (after the rowid) */ int regRec; /* Register holding assembled record for the table */ int i; /* Loop counter */ u8 bAffinityDone = 0; /* True if OP_Affinity has been run already */ assert( update_flags==0 || update_flags==OPFLAG_ISUPDATE || update_flags==(OPFLAG_ISUPDATE|OPFLAG_SAVEPOSITION) ); v = sqlite3GetVdbe(pParse); assert( v!=0 ); assert( pTab->pSelect==0 ); /* This table is not a VIEW */ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ if( aRegIdx[i]==0 ) continue; bAffinityDone = 1; 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); #ifdef SQLITE_ENABLE_PREUPDATE_HOOK if( update_flags==0 ){ int r = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_Integer, 0, r); sqlite3VdbeAddOp4(v, OP_Insert, iIdxCur+i, aRegIdx[i], r, (char*)pTab, P4_TABLE ); sqlite3VdbeChangeP5(v, OPFLAG_ISNOOP); sqlite3ReleaseTempReg(pParse, r); } #endif } 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; regData = regNewData + 1; regRec = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec); sqlite3SetMakeRecordP5(v, pTab); if( !bAffinityDone ){ sqlite3TableAffinity(v, pTab, 0); } 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, regRec, regNewData); if( !pParse->nested ){ sqlite3VdbeAppendP4(v, pTab, P4_TABLE); } sqlite3VdbeChangeP5(v, pik_flags); } /* |
︙ | ︙ | |||
2654 2655 2656 2657 2658 2659 2660 | 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 | | | < | | 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 | 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 uninitialized so that valgrind ** can detect if they are used by mistake in the caller. */ return 0; } iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); v = sqlite3GetVdbe(pParse); 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{ |
︙ | ︙ | |||
2717 2718 2719 2720 2721 2722 2723 | ** * 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 ); | | | 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 | ** * 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 ){ 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] ){ |
︙ | ︙ | |||
2785 2786 2787 2788 2789 2790 2791 | 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 */ | | | > > > > > | 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 | 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 */ struct SrcList_item *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 */ int regAutoinc; /* Memory register used by AUTOINC */ int destHasUniqueIdx = 0; /* True if pDest has a UNIQUE index */ int regData, regRowid; /* Registers holding data and rowid */ if( pSelect==0 ){ return 0; /* Must be of the form INSERT INTO ... SELECT ... */ } if( pParse->pWith || pSelect->pWith ){ /* Do not attempt to process this query if there are an WITH clauses ** attached to it. Proceeding may generate a false "no such table: xxx" ** error if pSelect reads from a CTE named "xxx". */ return 0; } if( sqlite3TriggerList(pParse, pDest) ){ return 0; /* tab1 must not have triggers */ } #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pDest) ){ return 0; /* tab1 must not be a virtual table */ } #endif if( onError==OE_Default ){ if( pDest->iPKey>=0 ) onError = pDest->keyConf; |
︙ | ︙ | |||
2860 2861 2862 2863 2864 2865 2866 | */ 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 ){ | | > | > > > > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < < | < | < | | | | 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 | */ 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_master.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 */ } #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pSrc) ){ return 0; /* tab2 must not be a virtual table */ } #endif if( pSrc->pSelect ){ return 0; /* tab2 may not be a view */ } 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 */ } 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 if( pDestCol->affinity!=pSrcCol->affinity ){ return 0; /* Affinity must be the same on all columns */ } if( sqlite3_stricmp(pDestCol->zColl, pSrcCol->zColl)!=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( i>0 ){ assert( pDestCol->pDflt==0 || pDestCol->pDflt->op==TK_SPAN ); assert( pSrcCol->pDflt==0 || pSrcCol->pDflt->op==TK_SPAN ); if( (pDestCol->pDflt==0)!=(pSrcCol->pDflt==0) || (pDestCol->pDflt && strcmp(pDestCol->pDflt->u.zToken, pSrcCol->pDflt->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) ){ |
︙ | ︙ | |||
2980 2981 2982 2983 2984 2985 2986 | /* 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] */ | < | | 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 | /* 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] */ if( (db->flags & SQLITE_ForeignKeys)!=0 && pDest->pFKey!=0 ){ return 0; } #endif if( (db->flags & SQLITE_CountRows)!=0 ){ return 0; /* xfer opt does not play well with PRAGMA count_changes */ } |
︙ | ︙ | |||
3003 3004 3005 3006 3007 3008 3009 | 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); | < | 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 | 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) */ |
︙ | ︙ | |||
3039 3040 3041 3042 3043 3044 3045 | } 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); | < | | | | | < | > | | < < < < < < < < < | < | < < | 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 | } 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); 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 ); } sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1); if( db->mDbFlags & DBFLAG_Vacuum ){ sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest); insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID| OPFLAG_APPEND|OPFLAG_USESEEKRESULT; }else{ insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND; } sqlite3VdbeAddOp4(v, OP_Insert, iDest, regData, regRowid, (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); } |
︙ | ︙ | |||
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 | 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 ){ | > | < > | < < < < < < < < < | 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 | 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); sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1); 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; sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest); } } if( !HasRowid(pSrc) && pDestIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY ){ idxInsFlags |= OPFLAG_NCHANGE; } 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); |
︙ | ︙ |
Deleted src/json.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/loadext.c.
︙ | ︙ | |||
457 458 459 460 461 462 463 | #ifdef SQLITE_ENABLE_NORMALIZE sqlite3_normalized_sql, #else 0, #endif /* Version 3.28.0 and later */ sqlite3_stmt_isexplain, | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 | #ifdef SQLITE_ENABLE_NORMALIZE sqlite3_normalized_sql, #else 0, #endif /* Version 3.28.0 and later */ sqlite3_stmt_isexplain, sqlite3_value_frombind }; /* ** 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. ** ** Return SQLITE_OK on success and SQLITE_ERROR if something goes wrong. |
︙ | ︙ | |||
544 545 546 547 548 549 550 | sqlite3_vfs *pVfs = db->pVfs; void *handle; sqlite3_loadext_entry xInit; char *zErrmsg = 0; const char *zEntry; char *zAltEntry = 0; void **aHandle; | | | 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 | sqlite3_vfs *pVfs = db->pVfs; void *handle; sqlite3_loadext_entry xInit; char *zErrmsg = 0; const char *zEntry; char *zAltEntry = 0; void **aHandle; u64 nMsg = 300 + sqlite3Strlen30(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" |
︙ | ︙ | |||
578 579 580 581 582 583 584 | *pzErrMsg = sqlite3_mprintf("not authorized"); } return SQLITE_ERROR; } zEntry = zProc ? zProc : "sqlite3_extension_init"; | < < < < < < | > > > > > > > > > > | 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 | *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 if( handle==0 ){ if( pzErrMsg ){ *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg); if( zErrmsg ){ sqlite3_snprintf(nMsg, zErrmsg, "unable to open shared library [%s]", zFile); sqlite3OsDlError(pVfs, nMsg-1, zErrmsg); } } return SQLITE_ERROR; } 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 ".", |
︙ | ︙ | |||
616 617 618 619 620 621 622 | int ncFile = sqlite3Strlen30(zFile); zAltEntry = sqlite3_malloc64(ncFile+30); if( zAltEntry==0 ){ sqlite3OsDlClose(pVfs, handle); return SQLITE_NOMEM_BKPT; } memcpy(zAltEntry, "sqlite3_", 8); | | | < | | 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 | 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 && 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 += sqlite3Strlen30(zEntry); *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg); if( zErrmsg ){ sqlite3_snprintf(nMsg, zErrmsg, "no entry point [%s] in shared library [%s]", zEntry, zFile); sqlite3OsDlError(pVfs, nMsg-1, zErrmsg); } } sqlite3OsDlClose(pVfs, handle); sqlite3_free(zAltEntry); return SQLITE_ERROR; |
︙ | ︙ | |||
668 669 670 671 672 673 674 | memcpy(aHandle, db->aExtension, sizeof(handle)*db->nExtension); } sqlite3DbFree(db, db->aExtension); db->aExtension = aHandle; db->aExtension[db->nExtension++] = handle; return SQLITE_OK; | < < < < < < < < < < < < < | 612 613 614 615 616 617 618 619 620 621 622 623 624 625 | 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 */ ){ |
︙ | ︙ | |||
730 731 732 733 734 735 736 | #endif /* !defined(SQLITE_OMIT_LOAD_EXTENSION) */ /* ** The following object holds the list of automatically loaded ** extensions. ** | | | 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 | #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_MASTER ** 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 }; |
︙ | ︙ | |||
772 773 774 775 776 777 778 | if( rc ){ return rc; }else #endif { u32 i; #if SQLITE_THREADSAFE | | | 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 | if( rc ){ return rc; }else #endif { u32 i; #if SQLITE_THREADSAFE sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); #endif wsdAutoextInit; sqlite3_mutex_enter(mutex); for(i=0; i<wsdAutoext.nExt; i++){ if( wsdAutoext.aExt[i]==xInit ) break; } if( i==wsdAutoext.nExt ){ |
︙ | ︙ | |||
810 811 812 813 814 815 816 | ** 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 | | | 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 | ** 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_MASTER); #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 ){ |
︙ | ︙ | |||
837 838 839 840 841 842 843 | */ void sqlite3_reset_auto_extension(void){ #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize()==SQLITE_OK ) #endif { #if SQLITE_THREADSAFE | | | 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 | */ 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_MASTER); #endif wsdAutoextInit; sqlite3_mutex_enter(mutex); sqlite3_free(wsdAutoext.aExt); wsdAutoext.aExt = 0; wsdAutoext.nExt = 0; sqlite3_mutex_leave(mutex); |
︙ | ︙ | |||
867 868 869 870 871 872 873 | 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 | | | 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 | 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_MASTER); #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 | #endif #ifdef SQLITE_ENABLE_RTREE # include "rtree.h" #endif #if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) # include "sqliteicu.h" #endif | < < < < < < < < < < < < < < < < | | < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < | | 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 | #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 int sqlite3Fts5Init(sqlite3*); #endif #ifndef SQLITE_AMALGAMATION /* IMPLEMENTATION-OF: R-46656-45156 The sqlite3_version[] string constant ** contains the text of SQLITE_VERSION macro. */ const char sqlite3_version[] = SQLITE_VERSION; #endif /* IMPLEMENTATION-OF: R-53536-42575 The sqlite3_libversion() function returns ** a pointer to the to the sqlite3_version[] string constant. */ |
︙ | ︙ | |||
194 195 196 197 198 199 200 | ** * 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){ | | | 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | ** * 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 *pMaster; ) /* 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); |
︙ | ︙ | |||
217 218 219 220 221 222 223 | 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. */ | | < < < | | | | | 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 | 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 ) 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_MASTER 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( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); ) sqlite3_mutex_enter(pMaster); 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(pMaster); /* 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; } |
︙ | ︙ | |||
298 299 300 301 302 303 304 | if( sqlite3GlobalConfig.isPCacheInit==0 ){ rc = sqlite3PcacheInitialize(); } if( rc==SQLITE_OK ){ sqlite3GlobalConfig.isPCacheInit = 1; rc = sqlite3OsInit(); } | | < | | | 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 | if( sqlite3GlobalConfig.isPCacheInit==0 ){ rc = sqlite3PcacheInitialize(); } if( rc==SQLITE_OK ){ sqlite3GlobalConfig.isPCacheInit = 1; rc = sqlite3OsInit(); } #ifdef SQLITE_ENABLE_DESERIALIZE if( rc==SQLITE_OK ){ rc = sqlite3MemdbInit(); } #endif if( rc==SQLITE_OK ){ sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage, sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage); 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(pMaster); sqlite3GlobalConfig.nRefInitMutex--; if( sqlite3GlobalConfig.nRefInitMutex<=0 ){ assert( sqlite3GlobalConfig.nRefInitMutex==0 ); sqlite3_mutex_free(sqlite3GlobalConfig.pInitMutex); sqlite3GlobalConfig.pInitMutex = 0; } sqlite3_mutex_leave(pMaster); /* 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 |
︙ | ︙ | |||
713 714 715 716 717 718 719 | iVal = SQLITE_DEFAULT_SORTERREF_SIZE; } sqlite3GlobalConfig.szSorterRef = (u32)iVal; break; } #endif /* SQLITE_ENABLE_SORTER_REFERENCES */ | | | | 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 | iVal = SQLITE_DEFAULT_SORTERREF_SIZE; } sqlite3GlobalConfig.szSorterRef = (u32)iVal; break; } #endif /* SQLITE_ENABLE_SORTER_REFERENCES */ #ifdef SQLITE_ENABLE_DESERIALIZE case SQLITE_CONFIG_MEMDB_MAXSIZE: { sqlite3GlobalConfig.mxMemdbSize = va_arg(ap, sqlite3_int64); break; } #endif /* SQLITE_ENABLE_DESERIALIZE */ default: { rc = SQLITE_ERROR; break; } } va_end(ap); |
︙ | ︙ | |||
743 744 745 746 747 748 749 | ** 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; | < < < | 679 680 681 682 683 684 685 686 687 688 689 690 691 692 | ** 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. |
︙ | ︙ | |||
768 769 770 771 772 773 774 | 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(); | | | < < < < < < < < < < < < < < < < > | < < < < < < < < < < < < | < < < < < | < < < | 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 | 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( sz*(sqlite3_int64)cnt ); /* IMP: R-61949-35727 */ sqlite3EndBenignMalloc(); if( pStart ) cnt = sqlite3MallocSize(pStart)/sz; }else{ pStart = pBuf; } db->lookaside.pStart = pStart; db->lookaside.pInit = 0; db->lookaside.pFree = 0; db->lookaside.sz = (u16)sz; if( pStart ){ int i; LookasideSlot *p; assert( sz > (int)sizeof(LookasideSlot*) ); db->lookaside.nSlot = cnt; p = (LookasideSlot*)pStart; for(i=cnt-1; i>=0; i--){ p->pNext = db->lookaside.pInit; db->lookaside.pInit = p; p = (LookasideSlot*)&((u8*)p)[sz]; } db->lookaside.pEnd = p; db->lookaside.bDisable = 0; db->lookaside.bMalloced = pBuf==0 ?1:0; }else{ db->lookaside.pStart = db; db->lookaside.pEnd = db; db->lookaside.bDisable = 1; db->lookaside.bMalloced = 0; db->lookaside.nSlot = 0; } #endif /* SQLITE_OMIT_LOOKASIDE */ return SQLITE_OK; } /* ** Return the mutex associated with a database connection. */ |
︙ | ︙ | |||
891 892 893 894 895 896 897 | #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; | | < | 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 | #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 && sqlite3BtreeIsInTrans(pBt) ){ Pager *pPager = sqlite3BtreePager(pBt); rc = sqlite3PagerFlush(pPager); if( rc==SQLITE_BUSY ){ bSeenBusy = 1; rc = SQLITE_OK; } } } sqlite3BtreeLeaveAll(db); sqlite3_mutex_leave(db->mutex); return ((rc==SQLITE_OK && bSeenBusy) ? SQLITE_BUSY : rc); } /* ** Configuration settings for an individual database connection */ int sqlite3_db_config(sqlite3 *db, int op, ...){ va_list ap; int rc; va_start(ap, op); switch( op ){ case SQLITE_DBCONFIG_MAINDBNAME: { /* IMP: R-06824-28531 */ /* IMP: R-36257-52125 */ db->aDb[0].zDbSName = va_arg(ap,char*); rc = SQLITE_OK; |
︙ | ︙ | |||
935 936 937 938 939 940 941 | 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 }, | < < < < < < | 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 | 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 }, { SQLITE_DBCONFIG_WRITABLE_SCHEMA, SQLITE_WriteSchema| SQLITE_NoSchemaError }, }; 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*); |
︙ | ︙ | |||
977 978 979 980 981 982 983 | break; } } break; } } va_end(ap); | < > > > > > > > > > > > > | < > > > > > > > > > > | > < < < < < < < < < < < < < < < < | > | | 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 | break; } } break; } } va_end(ap); return rc; } /* ** Return true if the buffer z[0..n-1] contains all spaces. */ static int allSpaces(const char *z, int n){ while( n>0 && z[n-1]==' ' ){ n--; } return n==0; } /* ** This is the default collating function named "BINARY" which is always ** available. ** ** If the padFlag argument is not NULL then space padding at the end ** of strings is ignored. This implements the RTRIM collation. */ static int binCollFunc( void *padFlag, int nKey1, const void *pKey1, int nKey2, const void *pKey2 ){ int rc, n; 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 ){ if( padFlag && allSpaces(((char*)pKey1)+n, nKey1-n) && allSpaces(((char*)pKey2)+n, nKey2-n) ){ /* EVIDENCE-OF: R-31624-24737 RTRIM is like BINARY except that extra ** spaces at the end of either string do not change the result. In other ** words, strings will compare equal to one another as long as they ** differ only in the number of spaces at the end. */ }else{ rc = nKey1 - nKey2; } } return rc; } /* ** Return true if CollSeq is the default built-in BINARY. */ int sqlite3IsBinary(const CollSeq *p){ assert( p==0 || p->xCmp!=binCollFunc || p->pUser!=0 || strcmp(p->zName,"BINARY")==0 ); return p==0 || (p->xCmp==binCollFunc && p->pUser==0); } /* ** 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 |
︙ | ︙ | |||
1082 1083 1084 1085 1086 1087 1088 | db->lastRowid = iRowid; sqlite3_mutex_leave(db->mutex); } /* ** Return the number of changes in the most recent call to sqlite3_exec(). */ | | < < < | < < < | 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 | db->lastRowid = iRowid; sqlite3_mutex_leave(db->mutex); } /* ** Return the number of changes in the most recent call to sqlite3_exec(). */ int sqlite3_changes(sqlite3 *db){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif return db->nChange; } /* ** Return the number of changes since the database handle was opened. */ int sqlite3_total_changes(sqlite3 *db){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif return db->nTotalChange; } /* ** 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. */ |
︙ | ︙ | |||
1134 1135 1136 1137 1138 1139 1140 | /* ** 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){ | | < < | 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 | /* ** 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 = p->u.pDestructor; if( pDestructor ){ pDestructor->nRef--; if( pDestructor->nRef==0 ){ pDestructor->xDestroy(pDestructor->pUserData); sqlite3DbFree(db, pDestructor); } } |
︙ | ︙ | |||
1206 1207 1208 1209 1210 1211 1212 | return SQLITE_OK; } if( !sqlite3SafetyCheckSickOrOk(db) ){ return SQLITE_MISUSE_BKPT; } sqlite3_mutex_enter(db->mutex); if( db->mTrace & SQLITE_TRACE_CLOSE ){ | | | 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 | return SQLITE_OK; } if( !sqlite3SafetyCheckSickOrOk(db) ){ return SQLITE_MISUSE_BKPT; } sqlite3_mutex_enter(db->mutex); if( db->mTrace & SQLITE_TRACE_CLOSE ){ db->xTrace(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 |
︙ | ︙ | |||
1240 1241 1242 1243 1244 1245 1246 | /* 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. */ | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 | /* 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->magic = SQLITE_MAGIC_ZOMBIE; sqlite3LeaveMutexAndCloseZombie(db); return SQLITE_OK; } /* ** Two variations on the public interface for closing a database ** connection. The sqlite3_close() version returns SQLITE_BUSY and ** leaves the connection option 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); } |
︙ | ︙ | |||
1304 1305 1306 1307 1308 1309 1310 | 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. */ | | | 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 | 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->magic!=SQLITE_MAGIC_ZOMBIE || connectionIsBusy(db) ){ sqlite3_mutex_leave(db->mutex); return; } /* If we reach this point, it means that the database connection has ** closed all sqlite3_stmt and sqlite3_backup objects and has been ** passed to sqlite3_close (meaning that it is a zombie). Therefore, |
︙ | ︙ | |||
1376 1377 1378 1379 1380 1381 1382 1383 | } 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); | > > > | | < < < | | 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 | } sqlite3DbFree(db, pColl); } sqlite3HashClear(&db->aCollSeq); #ifndef SQLITE_OMIT_VIRTUALTABLE for(i=sqliteHashFirst(&db->aModule); i; i=sqliteHashNext(i)){ Module *pMod = (Module *)sqliteHashData(i); if( pMod->xDestroy ){ pMod->xDestroy(pMod->pAux); } sqlite3VtabEponymousTableClear(db, pMod); sqlite3DbFree(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->magic = SQLITE_MAGIC_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); sqlite3_mutex_leave(db->mutex); db->magic = SQLITE_MAGIC_CLOSED; sqlite3_mutex_free(db->mutex); assert( sqlite3LookasideUsed(db,0)==0 ); if( db->lookaside.bMalloced ){ sqlite3_free(db->lookaside.pStart); } sqlite3_free(db); } |
︙ | ︙ | |||
1438 1439 1440 1441 1442 1443 1444 | ** 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 ){ | | | | 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 | ** 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( sqlite3BtreeIsInTrans(p) ){ 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; /* If one has been configured, invoke the rollback-hook callback */ if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){ db->xRollbackCallback(db->pRollbackArg); } } |
︙ | ︙ | |||
1530 1531 1532 1533 1534 1535 1536 | 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; | < | 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 | 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; |
︙ | ︙ | |||
1562 1563 1564 1565 1566 1567 1568 | case SQLITE_RANGE: zName = "SQLITE_RANGE"; break; case SQLITE_NOTADB: zName = "SQLITE_NOTADB"; break; case SQLITE_ROW: zName = "SQLITE_ROW"; break; case SQLITE_NOTICE: zName = "SQLITE_NOTICE"; break; case SQLITE_NOTICE_RECOVER_WAL: zName = "SQLITE_NOTICE_RECOVER_WAL";break; case SQLITE_NOTICE_RECOVER_ROLLBACK: zName = "SQLITE_NOTICE_RECOVER_ROLLBACK"; break; | < | 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 | case SQLITE_RANGE: zName = "SQLITE_RANGE"; break; case SQLITE_NOTADB: zName = "SQLITE_NOTADB"; break; case SQLITE_ROW: zName = "SQLITE_ROW"; break; case SQLITE_NOTICE: zName = "SQLITE_NOTICE"; break; case SQLITE_NOTICE_RECOVER_WAL: zName = "SQLITE_NOTICE_RECOVER_WAL";break; case SQLITE_NOTICE_RECOVER_ROLLBACK: zName = "SQLITE_NOTICE_RECOVER_ROLLBACK"; break; case SQLITE_WARNING: zName = "SQLITE_WARNING"; break; case SQLITE_WARNING_AUTOINDEX: zName = "SQLITE_WARNING_AUTOINDEX"; break; case SQLITE_DONE: zName = "SQLITE_DONE"; break; } } if( zName==0 ){ static char zBuf[50]; |
︙ | ︙ | |||
1653 1654 1655 1656 1657 1658 1659 | ** 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 */ | | > > > > > > > > > > > > > > > | > > > > > > > > | > | 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 | ** 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 */ sqlite3_file *pFile /* The file on which the lock occurred */ ){ #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; #ifdef SQLITE_ENABLE_SETLK_TIMEOUT if( sqlite3OsFileControl(pFile,SQLITE_FCNTL_LOCK_TIMEOUT,&tmout)==SQLITE_OK ){ if( count ){ tmout = 0; sqlite3OsFileControl(pFile, SQLITE_FCNTL_LOCK_TIMEOUT, &tmout); return 0; }else{ return 1; } } #else UNUSED_PARAMETER(pFile); #endif 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; UNUSED_PARAMETER(pFile); 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, sqlite3_file *pFile){ int rc; if( p->xBusyHandler==0 || p->nBusy<0 ) return 0; if( p->bExtraFileArg ){ /* Add an extra parameter with the pFile pointer to the end of the ** callback argument list */ int (*xTra)(void*,int,sqlite3_file*); xTra = (int(*)(void*,int,sqlite3_file*))p->xBusyHandler; rc = xTra(p->pBusyArg, p->nBusy, pFile); }else{ /* Legacy style busy handler callback */ rc = p->xBusyHandler(p->pBusyArg, p->nBusy); } if( rc==0 ){ p->nBusy = -1; }else{ p->nBusy++; } return rc; } |
︙ | ︙ | |||
1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 | #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 /* | > | 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 | #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->busyHandler.bExtraFileArg = 0; db->busyTimeout = 0; sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } #ifndef SQLITE_OMIT_PROGRESS_CALLBACK /* |
︙ | ︙ | |||
1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 | #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 | > | < < | < < < < < < < < < < < < < < < | 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 | #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; db->busyHandler.bExtraFileArg = 1; }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->magic!=SQLITE_MAGIC_ZOMBIE) ){ (void)SQLITE_MISUSE_BKPT; return; } #endif 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 ** is returned and the mallocFailed flag cleared. */ |
︙ | ︙ | |||
1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 | 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) | > | < | < < < < < < < < | | < | | | < | | | < | | | | | | < < < < < < < < < < < < < < | 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 | 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 nName; 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<(nName = sqlite3Strlen30( zFunctionName))) ){ return SQLITE_MISUSE_BKPT; } assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC ); extraFlags = enc & SQLITE_DETERMINISTIC; enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY); #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. */ if( enc==SQLITE_UTF16 ){ enc = SQLITE_UTF16NATIVE; }else if( enc==SQLITE_ANY ){ int rc; rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF8|extraFlags, pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor); if( rc==SQLITE_OK ){ rc = sqlite3CreateFunc(db, zFunctionName, nArg, SQLITE_UTF16LE|extraFlags, pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor); } if( rc!=SQLITE_OK ){ return rc; } enc = SQLITE_UTF16BE; } #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); } } 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 ); p->xSFunc = xSFunc ? xSFunc : xStep; p->xFinalize = xFinal; p->xValue = xValue; p->xInverse = xInverse; p->pUserData = pUserData; p->nArg = (u16)nArg; return SQLITE_OK; |
︙ | ︙ | |||
1995 1996 1997 1998 1999 2000 2001 | pArg->xDestroy = xDestroy; pArg->pUserData = p; } rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p, xSFunc, xStep, xFinal, xValue, xInverse, pArg ); if( pArg && pArg->nRef==0 ){ | | | 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 | 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 ); xDestroy(p); sqlite3_free(pArg); } out: rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); |
︙ | ︙ | |||
2132 2133 2134 2135 2136 2137 2138 | return SQLITE_MISUSE_BKPT; } #endif sqlite3_mutex_enter(db->mutex); rc = sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)!=0; sqlite3_mutex_leave(db->mutex); if( rc ) return SQLITE_OK; | | | 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 | return SQLITE_MISUSE_BKPT; } #endif sqlite3_mutex_enter(db->mutex); rc = sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)!=0; sqlite3_mutex_leave(db->mutex); if( rc ) return SQLITE_OK; zCopy = sqlite3_mprintf(zName); if( zCopy==0 ) return SQLITE_NOMEM; return sqlite3_create_function_v2(db, zName, nArg, SQLITE_UTF8, zCopy, sqlite3InvalidFunction, 0, 0, sqlite3_free); } #ifndef SQLITE_OMIT_TRACE /* |
︙ | ︙ | |||
2160 2161 2162 2163 2164 2165 2166 | (void)SQLITE_MISUSE_BKPT; return 0; } #endif sqlite3_mutex_enter(db->mutex); pOld = db->pTraceArg; db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0; | | | 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 | (void)SQLITE_MISUSE_BKPT; return 0; } #endif sqlite3_mutex_enter(db->mutex); pOld = db->pTraceArg; db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0; db->xTrace = (int(*)(u32,void*,void*,void*))xTrace; db->pTraceArg = pArg; sqlite3_mutex_leave(db->mutex); return pOld; } #endif /* SQLITE_OMIT_DEPRECATED */ /* Register a trace callback using the version-2 interface. |
︙ | ︙ | |||
2184 2185 2186 2187 2188 2189 2190 | return SQLITE_MISUSE_BKPT; } #endif sqlite3_mutex_enter(db->mutex); if( mTrace==0 ) xTrace = 0; if( xTrace==0 ) mTrace = 0; db->mTrace = mTrace; | | | 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 | return SQLITE_MISUSE_BKPT; } #endif sqlite3_mutex_enter(db->mutex); if( mTrace==0 ) xTrace = 0; if( xTrace==0 ) mTrace = 0; db->mTrace = mTrace; db->xTrace = xTrace; db->pTraceArg = pArg; sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } #ifndef SQLITE_OMIT_DEPRECATED /* |
︙ | ︙ | |||
2320 2321 2322 2323 2324 2325 2326 | pRet = db->pPreUpdateArg; db->xPreUpdateCallback = xCallback; db->pPreUpdateArg = pArg; sqlite3_mutex_leave(db->mutex); return pRet; } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 | 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()). |
︙ | ︙ | |||
2441 2442 2443 2444 2445 2446 2447 | 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 */ | | | 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 | 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 = SQLITE_MAX_ATTACHED; /* sqlite3.aDb[] index of db 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; |
︙ | ︙ | |||
2464 2465 2466 2467 2468 2469 2470 | ** mode: */ return SQLITE_MISUSE; } sqlite3_mutex_enter(db->mutex); if( zDb && zDb[0] ){ iDb = sqlite3FindDbName(db, zDb); | < < | | 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 | ** 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 ){ db->u1.isInterrupted = 0; } sqlite3_mutex_leave(db->mutex); return rc; #endif } |
︙ | ︙ | |||
2514 2515 2516 2517 2518 2519 2520 | ** 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. ** | | < < | | 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 | ** 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_ATTACHED, 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 ); for(i=0; i<db->nDb && rc==SQLITE_OK; i++){ if( i==iDb || iDb==SQLITE_MAX_ATTACHED ){ rc = sqlite3BtreeCheckpoint(db->aDb[i].pBt, eMode, pnLog, pnCkpt); pnLog = 0; pnCkpt = 0; if( rc==SQLITE_BUSY ){ bBusy = 1; rc = SQLITE_OK; } |
︙ | ︙ | |||
2611 2612 2613 2614 2615 2616 2617 | z = sqlite3ErrStr(db->errCode); } } sqlite3_mutex_leave(db->mutex); return z; } | < < < < < < < < < < < < < | 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 | z = sqlite3ErrStr(db->errCode); } } sqlite3_mutex_leave(db->mutex); return z; } #ifndef SQLITE_OMIT_UTF16 /* ** Return UTF-16 encoded English language explanation of the most recent ** error. */ const void *sqlite3_errmsg16(sqlite3 *db){ static const u16 outOfMem[] = { |
︙ | ︙ | |||
2884 2885 2886 2887 2888 2889 2890 | if( limitId<0 || limitId>=SQLITE_N_LIMIT ){ return -1; } oldLimit = db->aLimit[limitId]; if( newLimit>=0 ){ /* IMP: R-52476-28732 */ if( newLimit>aHardLimit[limitId] ){ newLimit = aHardLimit[limitId]; /* IMP: R-51463-25634 */ | < < | 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 | if( limitId<0 || limitId>=SQLITE_N_LIMIT ){ return -1; } oldLimit = db->aLimit[limitId]; if( newLimit>=0 ){ /* IMP: R-52476-28732 */ if( newLimit>aHardLimit[limitId] ){ newLimit = aHardLimit[limitId]; /* IMP: R-51463-25634 */ } db->aLimit[limitId] = newLimit; } return oldLimit; /* IMP: R-53341-35419 */ } /* |
︙ | ︙ | |||
2907 2908 2909 2910 2911 2912 2913 | ** 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 | | < < | | | 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 | ** 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. It is the ** responsibility of the caller to eventually call sqlite3_free() to release ** this buffer. ** ** 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( |
︙ | ︙ | |||
2943 2944 2945 2946 2947 2948 2949 | || 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 */ | | < < < | 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 | || 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+2; /* 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; 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. ** The correct URI for that UNC has only two or four leading / characters |
︙ | ︙ | |||
3045 3046 3047 3048 3049 3050 3051 | }else if( (eState==0 && c=='?') || (eState==2 && c=='&') ){ c = 0; eState = 1; } zFile[iOut++] = c; } if( eState==1 ) zFile[iOut++] = '\0'; | | > | 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 | }else if( (eState==0 && c=='?') || (eState==2 && c=='&') ){ c = 0; eState = 1; } zFile[iOut++] = c; } if( eState==1 ) zFile[iOut++] = '\0'; zFile[iOut++] = '\0'; zFile[iOut++] = '\0'; /* 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] ){ |
︙ | ︙ | |||
3125 3126 3127 3128 3129 3130 3131 | } } zOpt = &zVal[nVal+1]; } }else{ | | < < | > | > | | > > > | | > > | > | > > | | < | > > > > > > > > > | | | > < | 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 | } } zOpt = &zVal[nVal+1]; } }else{ zFile = sqlite3_malloc64(nUri+2); if( !zFile ) return SQLITE_NOMEM_BKPT; if( nUri ){ memcpy(zFile, zUri, nUri); } zFile[nUri] = '\0'; zFile[nUri+1] = '\0'; 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(zFile); zFile = 0; } *pFlags = flags; *pzFile = zFile; return rc; } #if defined(SQLITE_HAS_CODEC) /* ** Process URI filename query parameters relevant to the SQLite Encryption ** Extension. Return true if any of the relevant query parameters are ** seen and return false if not. */ int sqlite3CodecQueryParameters( sqlite3 *db, /* Database connection */ const char *zDb, /* Which schema is being created/attached */ const char *zUri /* URI filename */ ){ const char *zKey; if( (zKey = sqlite3_uri_parameter(zUri, "hexkey"))!=0 && zKey[0] ){ u8 iByte; int i; char zDecoded[40]; for(i=0, iByte=0; i<sizeof(zDecoded)*2 && sqlite3Isxdigit(zKey[i]); i++){ iByte = (iByte<<4) + sqlite3HexToInt(zKey[i]); if( (i&1)!=0 ) zDecoded[i/2] = iByte; } sqlite3_key_v2(db, zDb, zDecoded, i/2); return 1; }else if( (zKey = sqlite3_uri_parameter(zUri, "key"))!=0 ){ sqlite3_key_v2(db, zDb, zKey, sqlite3Strlen30(zKey)); return 1; }else if( (zKey = sqlite3_uri_parameter(zUri, "textkey"))!=0 ){ sqlite3_key_v2(db, zDb, zKey, -1); return 1; }else{ return 0; } } #endif /* ** 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() */ #ifdef SQLITE_ENABLE_API_ARMOR if( ppDb==0 ) return SQLITE_MISUSE_BKPT; #endif *ppDb = 0; #ifndef SQLITE_OMIT_AUTOINIT rc = sqlite3_initialize(); |
︙ | ︙ | |||
3217 3218 3219 3220 3221 3222 3223 | /* 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, | | | | | 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 | /* 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, 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_MASTER_JOURNAL | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_FULLMUTEX | SQLITE_OPEN_WAL ); /* Allocate the sqlite data structure */ db = sqlite3MallocZero( sizeof(sqlite3) ); |
︙ | ︙ | |||
3253 3254 3255 3256 3257 3258 3259 | goto opendb_out; } if( isThreadsafe==0 ){ sqlite3MutexWarnOnContention(db->mutex); } } sqlite3_mutex_enter(db->mutex); | | | < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | goto opendb_out; } if( isThreadsafe==0 ){ sqlite3MutexWarnOnContention(db->mutex); } } sqlite3_mutex_enter(db->mutex); db->errMask = 0xff; db->nDb = 2; db->magic = SQLITE_MAGIC_BUSY; db->aDb = db->aDbStatic; db->lookaside.bDisable = 1; 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->nMaxSorterMmap = 0x7FFFFFFF; db->flags |= SQLITE_ShortColNames | SQLITE_EnableTrigger | SQLITE_CacheSpill #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 |
︙ | ︙ | |||
3361 3362 3363 3364 3365 3366 3367 | ** 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); | | | < < < | < > | | < < < < < | 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 | ** 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, (void*)1, binCollFunc, 0); if( db->mallocFailed ){ goto opendb_out; } /* EVIDENCE-OF: R-08308-17224 The default collating function for all ** strings is BINARY. */ db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, sqlite3StrBINARY, 0); assert( db->pDfltColl!=0 ); /* 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 |
︙ | ︙ | |||
3399 3400 3401 3402 3403 3404 3405 | 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 ){ | | < < < < < < | < < | | > | > | | > | > > > > > | > > > > > > | > > > > > | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | 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-65497-44594 */ }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); goto opendb_out; } /* Open the backend database driver */ rc = sqlite3BtreeOpen(db->pVfs, zOpen, db, &db->aDb[0].pBt, 0, flags | SQLITE_OPEN_MAIN_DB); if( rc!=SQLITE_OK ){ if( rc==SQLITE_IOERR_NOMEM ){ 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 ) ENC(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->magic = SQLITE_MAGIC_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); #ifdef SQLITE_ENABLE_FTS5 /* Register any built-in FTS5 module before loading the automatic ** extensions. This allows automatic extensions to register FTS5 ** tokenizers and auxiliary functions. */ if( !db->mallocFailed && rc==SQLITE_OK ){ rc = sqlite3Fts5Init(db); } #endif /* 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_FTS1 if( !db->mallocFailed ){ extern int sqlite3Fts1Init(sqlite3*); rc = sqlite3Fts1Init(db); } #endif #ifdef SQLITE_ENABLE_FTS2 if( !db->mallocFailed && rc==SQLITE_OK ){ extern int sqlite3Fts2Init(sqlite3*); rc = sqlite3Fts2Init(db); } #endif #ifdef SQLITE_ENABLE_FTS3 /* automatically defined by SQLITE_ENABLE_FTS4 */ if( !db->mallocFailed && rc==SQLITE_OK ){ rc = sqlite3Fts3Init(db); } #endif #if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS) if( !db->mallocFailed && rc==SQLITE_OK ){ rc = sqlite3IcuInit(db); } #endif #ifdef SQLITE_ENABLE_RTREE if( !db->mallocFailed && rc==SQLITE_OK){ rc = sqlite3RtreeInit(db); } #endif #ifdef SQLITE_ENABLE_DBPAGE_VTAB if( !db->mallocFailed && rc==SQLITE_OK){ rc = sqlite3DbpageRegister(db); } #endif #ifdef SQLITE_ENABLE_DBSTAT_VTAB if( !db->mallocFailed && rc==SQLITE_OK){ rc = sqlite3DbstatRegister(db); } #endif #ifdef SQLITE_ENABLE_JSON1 if( !db->mallocFailed && rc==SQLITE_OK){ rc = sqlite3Json1Init(db); } #endif #ifdef SQLITE_ENABLE_STMTVTAB if( !db->mallocFailed && rc==SQLITE_OK){ rc = sqlite3StmtVtabInit(db); } #endif /* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking ** mode. -DSQLITE_DEFAULT_LOCKING_MODE=0 make NORMAL the default locking ** mode. Doing nothing at all also makes NORMAL the default. */ #ifdef SQLITE_DEFAULT_LOCKING_MODE |
︙ | ︙ | |||
3504 3505 3506 3507 3508 3509 3510 | opendb_out: if( db ){ assert( db->mutex!=0 || isThreadsafe==0 || sqlite3GlobalConfig.bFullMutex==0 ); sqlite3_mutex_leave(db->mutex); } rc = sqlite3_errcode(db); | | | | > > > | | | 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 | 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==SQLITE_NOMEM ); if( rc==SQLITE_NOMEM ){ sqlite3_close(db); db = 0; }else if( rc!=SQLITE_OK ){ db->magic = SQLITE_MAGIC_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 #if defined(SQLITE_HAS_CODEC) if( rc==SQLITE_OK ) sqlite3CodecQueryParameters(db, 0, zOpen); #endif sqlite3_free(zOpen); return rc & 0xff; } /* ** Open a new database handle. */ int sqlite3_open( |
︙ | ︙ | |||
3746 3747 3748 3749 3750 3751 3752 | 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"); } | | < < | 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 | 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"); } #ifdef SQLITE_DEBUG 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); } 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"); |
︙ | ︙ | |||
3820 3821 3822 3823 3824 3825 3826 | rc = sqlite3Init(db, &zErrMsg); if( SQLITE_OK!=rc ){ goto error_out; } /* Locate the table in question */ pTab = sqlite3FindTable(db, zTableName, zDbName); | | | | 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 | rc = sqlite3Init(db, &zErrMsg); if( SQLITE_OK!=rc ){ goto error_out; } /* Locate the table in question */ pTab = sqlite3FindTable(db, zTableName, zDbName); if( !pTab || pTab->pSelect ){ 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->zName, zColumnName) ){ break; } } if( iCol==pTab->nCol ){ if( HasRowid(pTab) && sqlite3IsRowid(zColumnName) ){ iCol = pTab->iPKey; pCol = iCol>=0 ? &pTab->aCol[iCol] : 0; |
︙ | ︙ | |||
3858 3859 3860 3861 3862 3863 3864 | ** 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); | | | 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 | ** 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 = pCol->zColl; notnull = pCol->notNull!=0; primarykey = (pCol->colFlags & COLFLAG_PRIMKEY)!=0; autoinc = pTab->iPKey==iCol && (pTab->tabFlags & TF_Autoincrement)!=0; }else{ zDataType = "INTEGER"; primarykey = 1; } |
︙ | ︙ | |||
3957 3958 3959 3960 3961 3962 3963 | 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; | < < < < < < < < < < < < | 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 | 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; } |
︙ | ︙ | |||
4008 4009 4010 4011 4012 4013 4014 | ** this verb acts like PRNG_RESET. */ case SQLITE_TESTCTRL_PRNG_RESTORE: { sqlite3PrngRestoreState(); break; } | | < < < < < < < < < | < | < < | < < < < | < < < < < < < | 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 | ** this verb acts like PRNG_RESET. */ case SQLITE_TESTCTRL_PRNG_RESTORE: { sqlite3PrngRestoreState(); break; } /* ** Reset the PRNG back to its uninitialized state. The next call ** to sqlite3_randomness() will reseed the PRNG using a single call ** to the xRandomness method of the default VFS. */ case SQLITE_TESTCTRL_PRNG_RESET: { sqlite3_randomness(0,0); break; } /* ** 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. |
︙ | ︙ | |||
4068 4069 4070 4071 4072 4073 4074 | ** ** As a test of the fault simulator mechanism itself, sqlite3FaultSim(0) ** is called immediately after installing the new callback and the return ** value from sqlite3FaultSim(0) becomes the return from ** sqlite3_test_control(). */ case SQLITE_TESTCTRL_FAULT_INSTALL: { | | < < | < < | | | 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 | ** ** As a test of the fault simulator mechanism itself, sqlite3FaultSim(0) ** is called immediately after installing the new callback and the return ** value from sqlite3FaultSim(0) becomes the return from ** sqlite3_test_control(). */ case SQLITE_TESTCTRL_FAULT_INSTALL: { /* MSVC is picky about pulling func ptrs from va lists. ** http://support.microsoft.com/kb/47961 ** sqlite3GlobalConfig.xTestCallback = va_arg(ap, int(*)(int)); */ typedef int(*TESTCALLBACKFUNC_t)(int); sqlite3GlobalConfig.xTestCallback = va_arg(ap, TESTCALLBACKFUNC_t); rc = sqlite3FaultSim(0); break; } /* ** sqlite3_test_control(BENIGN_MALLOC_HOOKS, xBegin, xEnd) ** |
︙ | ︙ | |||
4136 4137 4138 4139 4140 4141 4142 | ** process aborts. If X is false and assert() is disabled, then the ** return value is zero. */ case SQLITE_TESTCTRL_ASSERT: { volatile int x = 0; assert( /*side-effects-ok*/ (x = va_arg(ap,int))!=0 ); rc = x; | < < < < < < < < < < < < < < < < < < < < < < | 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 | ** process aborts. If X is false and assert() is disabled, then the ** return value is zero. */ case SQLITE_TESTCTRL_ASSERT: { volatile int x = 0; assert( /*side-effects-ok*/ (x = va_arg(ap,int))!=0 ); rc = x; break; } /* ** sqlite3_test_control(SQLITE_TESTCTRL_ALWAYS, int X) ** |
︙ | ︙ | |||
4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 | ** 432101 big-endian, determined at compile-time ** 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*); | > > > > > > > > > > > > > > | | | < < < < < < < < | < < < < < < | | | > > | < < < < < < < < < < < < < < < < < < | 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 | ** 432101 big-endian, determined at compile-time ** 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_RESERVE, sqlite3 *db, int N) ** ** Set the nReserve size to N for the main database on the database ** connection db. */ case SQLITE_TESTCTRL_RESERVE: { sqlite3 *db = va_arg(ap, sqlite3*); int x = va_arg(ap,int); sqlite3_mutex_enter(db->mutex); sqlite3BtreeSetPageSize(db->aDb[0].pBt, 0, x, 0); sqlite3_mutex_leave(db->mutex); 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 = (u16)(va_arg(ap, int) & 0xffff); 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_FUNCS, int onoff); ** ** If parameter onoff is non-zero, internal-use-only SQL functions ** are visible to ordinary SQL. This is useful for testing but is ** unsafe because invalid parameters to those internal-use-only functions ** can result in crashes or segfaults. */ case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS: { sqlite3GlobalConfig.bInternalFunctions = va_arg(ap, int); 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; } /* 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: { sqlite3GlobalConfig.iOnceResetThreshold = va_arg(ap, int); |
︙ | ︙ | |||
4351 4352 4353 4354 4355 4356 4357 | ** ** If onOff==0 and tnum>0 then reset the schema for all databases, causing ** the schema to be reparsed the next time it is needed. This has the ** effect of erasing all imposter tables. */ case SQLITE_TESTCTRL_IMPOSTER: { sqlite3 *db = va_arg(ap, sqlite3*); | < | < < | | | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > > | | 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 | ** ** If onOff==0 and tnum>0 then reset the schema for all databases, causing ** the schema to be reparsed the next time it is needed. This has the ** effect of erasing all imposter tables. */ case SQLITE_TESTCTRL_IMPOSTER: { sqlite3 *db = va_arg(ap, sqlite3*); sqlite3_mutex_enter(db->mutex); db->init.iDb = sqlite3FindDbName(db, va_arg(ap,const char*)); db->init.busy = db->init.imposterTable = va_arg(ap,int); db->init.newTnum = va_arg(ap,int); if( db->init.busy==0 && db->init.newTnum>0 ){ sqlite3ResetAllSchemasOfConnection(db); } sqlite3_mutex_leave(db->mutex); break; } #if defined(YYCOVERAGE) /* sqlite3_test_control(SQLITE_TESTCTRL_PARSER_COVERAGE, FILE *out) ** ** This test control (only available when SQLite is compiled with ** -DYYCOVERAGE) writes a report onto "out" that shows all ** state/lookahead combinations in the parser state machine ** which are never exercised. If any state is missed, make the ** return code SQLITE_ERROR. */ case SQLITE_TESTCTRL_PARSER_COVERAGE: { FILE *out = va_arg(ap, FILE*); if( sqlite3ParserCoverage(out) ) rc = SQLITE_ERROR; break; } #endif /* defined(YYCOVERAGE) */ } va_end(ap); #endif /* SQLITE_UNTESTABLE */ return rc; } /* ** 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 += sqlite3Strlen30(zFilename) + 1; while( zFilename[0] ){ int x = strcmp(zFilename, zParam); zFilename += sqlite3Strlen30(zFilename) + 1; if( x==0 ) return zFilename; zFilename += sqlite3Strlen30(zFilename) + 1; } return 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); |
︙ | ︙ | |||
4626 4627 4628 4629 4630 4631 4632 | sqlite3_int64 v; if( z && sqlite3DecOrHexToI64(z, &v)==0 ){ bDflt = v; } return bDflt; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 | 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; } /* ** Return the filename of the database associated with a database ** connection. */ const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName){ Btree *pBt; #ifdef SQLITE_ENABLE_API_ARMOR |
︙ | ︙ | |||
4742 4743 4744 4745 4746 4747 4748 | #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; | | | 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 | #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( 0==sqlite3BtreeIsInTrans(pBt) ){ rc = sqlite3BtreeBeginTrans(pBt, 0, 0); if( rc==SQLITE_OK ){ rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot); } } } } |
︙ | ︙ | |||
4778 4779 4780 4781 4782 4783 4784 | #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; | | | | 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 | #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( sqlite3BtreeIsInTrans(pBt)==0 ){ Pager *pPager = sqlite3BtreePager(pBt); int bUnlock = 0; if( sqlite3BtreeIsInReadTrans(pBt) ){ if( db->nVdbeActive==0 ){ rc = sqlite3PagerSnapshotCheck(pPager, pSnapshot); if( rc==SQLITE_OK ){ bUnlock = 1; rc = sqlite3BtreeCommit(pBt); } } |
︙ | ︙ | |||
4817 4818 4819 4820 4821 4822 4823 | /* ** Recover as many snapshots as possible from the wal file associated with ** schema zDb of database db. */ int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){ int rc = SQLITE_ERROR; | < > | | 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 | /* ** Recover as many snapshots as possible from the wal file associated with ** schema zDb of database db. */ int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){ int rc = SQLITE_ERROR; int iDb; #ifndef SQLITE_OMIT_WAL #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ return SQLITE_MISUSE_BKPT; } #endif sqlite3_mutex_enter(db->mutex); iDb = sqlite3FindDbName(db, zDb); if( iDb==0 || iDb>1 ){ Btree *pBt = db->aDb[iDb].pBt; if( 0==sqlite3BtreeIsInReadTrans(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 | ** is a no-op returning zero if SQLite is not compiled with ** SQLITE_ENABLE_MEMORY_MANAGEMENT. */ UNUSED_PARAMETER(n); return 0; #endif } | < < < < < < < < | | 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 | ** 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; } mem0 = { 0, 0, 0 }; #define mem0 GLOBAL(struct Mem0Global, mem0) /* ** Return the memory allocator mutex. sqlite3_status() needs it. */ sqlite3_mutex *sqlite3MallocMutex(void){ |
︙ | ︙ | |||
78 79 80 81 82 83 84 | (void)pArg; (void)iThreshold; return SQLITE_OK; } #endif /* | | | < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | | 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 | (void)pArg; (void)iThreshold; return SQLITE_OK; } #endif /* ** Set the soft heap-size limit for the library. Passing a zero or ** negative value indicates no 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; } mem0.alarmThreshold = n; nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); 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); } /* ** Initialize the memory allocation subsystem. */ int sqlite3MallocInit(void){ int rc; if( sqlite3GlobalConfig.m.xMalloc==0 ){ sqlite3MemSetDefault(); } memset(&mem0, 0, sizeof(mem0)); 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 mem0.nearlyFull; } /* ** Deinitialize the memory allocation subsystem. */ void sqlite3MallocEnd(void){ if( sqlite3GlobalConfig.m.xShutdown ){ |
︙ | ︙ | |||
233 234 235 236 237 238 239 240 241 242 243 244 | /* 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 ){ | > > > > > > > | < < < < < < < | < < < < < < < < < < < < < < < < < < < < < | > > > > > | 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 | /* 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); #ifdef SQLITE_MAX_MEMORY if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)+nFull>SQLITE_MAX_MEMORY ){ *pp = 0; return; } #endif sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, n); if( mem0.alarmThreshold>0 ){ sqlite3_int64 nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); if( nUsed >= mem0.alarmThreshold - nFull ){ mem0.nearlyFull = 1; sqlite3MallocAlarm(nFull); }else{ 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); } #endif if( p ){ nFull = sqlite3MallocSize(p); sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nFull); sqlite3StatusUp(SQLITE_STATUS_MALLOC_COUNT, 1); } *pp = p; } /* ** Allocate memory. This routine is like sqlite3_malloc() except that it ** assumes the memory subsystem has already been initialized. */ void *sqlite3Malloc(u64 n){ void *p; if( n==0 || n>=0x7fffff00 ){ /* A memory allocation of a number of bytes which is near the maximum ** signed integer value might cause an integer overflow inside of the ** xMalloc(). Hence we limit the maximum size to 0x7fffff00, giving ** 255 bytes of overhead. SQLite itself will never use anything near ** this amount. The only way to reach the limit is with sqlite3_malloc() */ p = 0; }else if( sqlite3GlobalConfig.bMemstat ){ sqlite3_mutex_enter(mem0.mutex); mallocWithAlarm((int)n, &p); sqlite3_mutex_leave(mem0.mutex); }else{ p = sqlite3GlobalConfig.m.xMalloc((int)n); |
︙ | ︙ | |||
328 329 330 331 332 333 334 | return sqlite3Malloc(n); } /* ** TRUE if p is a lookaside memory allocation from db */ #ifndef SQLITE_OMIT_LOOKASIDE | | | | | < < < < < < < | > | | | | | | | < < < < < | | < < | | | < < < | 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 | return sqlite3Malloc(n); } /* ** TRUE if p is a lookaside memory allocation from db */ #ifndef SQLITE_OMIT_LOOKASIDE static int isLookaside(sqlite3 *db, 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(void *p){ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); return sqlite3GlobalConfig.m.xSize(p); } int sqlite3DbMallocSize(sqlite3 *db, void *p){ assert( p!=0 ); if( db==0 || !isLookaside(db,p) ){ #ifdef SQLITE_DEBUG 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 return sqlite3GlobalConfig.m.xSize(p); }else{ assert( sqlite3_mutex_held(db->mutex) ); return db->lookaside.sz; } } sqlite3_uint64 sqlite3_msize(void *p){ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) ); assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) ); return p ? sqlite3GlobalConfig.m.xSize(p) : 0; } |
︙ | ︙ | |||
418 419 420 421 422 423 424 | ** connection. Calling sqlite3DbFree(D,X) for X==0 is a harmless no-op. ** The sqlite3DbFreeNN(D,X) version requires that X be non-NULL. */ void sqlite3DbFreeNN(sqlite3 *db, void *p){ assert( db==0 || sqlite3_mutex_held(db->mutex) ); assert( p!=0 ); if( db ){ | < < < < | < < < < < > | | < | | < > | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | ** connection. Calling sqlite3DbFree(D,X) for X==0 is a harmless no-op. ** The sqlite3DbFreeNN(D,X) version requires that X be non-NULL. */ void sqlite3DbFreeNN(sqlite3 *db, void *p){ assert( db==0 || sqlite3_mutex_held(db->mutex) ); assert( p!=0 ); if( db ){ if( db->pnBytesFreed ){ measureAllocationSize(db, p); return; } if( isLookaside(db, p) ){ LookasideSlot *pBuf = (LookasideSlot*)p; #ifdef SQLITE_DEBUG /* Trash all content in the buffer being freed */ memset(p, 0xaa, db->lookaside.sz); #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); } void sqlite3DbFree(sqlite3 *db, void *p){ assert( db==0 || sqlite3_mutex_held(db->mutex) ); if( p ) sqlite3DbFreeNN(db, p); } /* ** Change the size of an existing memory allocation |
︙ | ︙ | |||
522 523 524 525 526 527 528 | /* 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 ){ | < | < < < | < < < | 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 | /* 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; if( nDiff>0 && sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >= mem0.alarmThreshold-nDiff ){ sqlite3MallocAlarm(nDiff); } pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); if( pNew==0 && mem0.alarmThreshold>0 ){ sqlite3MallocAlarm((int)nBytes); pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); } if( pNew ){ nNew = sqlite3MallocSize(pNew); sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nNew-nOld); } sqlite3_mutex_leave(mem0.mutex); }else{ pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); |
︙ | ︙ | |||
644 645 646 647 648 649 650 | } 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 ); | < | < | < < < < < < < < | < < < | < < < < | | | | | | | | | | > > > | 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 | } 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( db->lookaside.bDisable==0 ){ assert( db->mallocFailed==0 ); if( n>db->lookaside.sz ){ db->lookaside.anStat[1]++; }else 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 if( db->mallocFailed ){ return 0; } #else assert( db!=0 ); assert( sqlite3_mutex_held(db->mutex) ); assert( db->pnBytesFreed==0 ); if( db->mallocFailed ){ return 0; |
︙ | ︙ | |||
698 699 700 701 702 703 704 | ** 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) ); | < < < < < < < | < < | | | 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 | ** 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( isLookaside(db,p) && n<=db->lookaside.sz ) 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, db->lookaside.sz); sqlite3DbFree(db, p); } }else{ assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) ); sqlite3MemdebugSetType(p, MEMTYPE_HEAP); pNew = sqlite3_realloc64(p, n); if( !pNew ){ sqlite3OomFault(db); } sqlite3MemdebugSetType(pNew, (db->lookaside.bDisable==0 ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP)); } } |
︙ | ︙ | |||
772 773 774 775 776 777 778 | memcpy(zNew, z, n); } return zNew; } char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){ char *zNew; assert( db!=0 ); | | > > | < < < < < | < | < < < < < < < | | | < < < < < | | < < | | | | < | | | < < | 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 | memcpy(zNew, z, n); } return zNew; } char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){ char *zNew; assert( db!=0 ); if( z==0 ){ return 0; } assert( (n&0x7fffffff)==n ); zNew = sqlite3DbMallocRawNN(db, n+1); if( zNew ){ memcpy(zNew, z, (size_t)n); zNew[n] = 0; } return zNew; } /* ** The text between zStart and zEnd represents a phrase within a larger ** SQL statement. Make a copy of this phrase in space obtained form ** sqlite3DbMalloc(). Omit leading and trailing whitespace. */ char *sqlite3DbSpanDup(sqlite3 *db, const char *zStart, const char *zEnd){ int n; while( sqlite3Isspace(zStart[0]) ) zStart++; n = (int)(zEnd - zStart); while( ALWAYS(n>0) && sqlite3Isspace(zStart[n-1]) ) n--; return sqlite3DbStrNDup(db, zStart, n); } /* ** Free any prior content in *pz and replace it with a copy of zNew. */ void sqlite3SetString(char **pz, sqlite3 *db, const char *zNew){ sqlite3DbFree(db, *pz); *pz = sqlite3DbStrDup(db, zNew); } /* ** Call this routine to record the fact that an OOM (out-of-memory) error ** has happened. This routine will set db->mallocFailed, and also ** 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 ){ db->u1.isInterrupted = 1; } db->lookaside.bDisable++; 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; db->u1.isInterrupted = 0; assert( db->lookaside.bDisable>0 ); db->lookaside.bDisable--; } } /* ** Take actions at the end of an API call to indicate an OOM error */ static SQLITE_NOINLINE int apiOomError(sqlite3 *db){ sqlite3OomClear(db); sqlite3Error(db, SQLITE_NOMEM); return SQLITE_NOMEM_BKPT; } /* ** 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. ** |
︙ | ︙ | |||
889 890 891 892 893 894 895 | 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) ); | | | | 707 708 709 710 711 712 713 714 715 716 717 718 | 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==SQLITE_IOERR_NOMEM ){ return apiOomError(db); } 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(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.xMalloc==sqlite3MemMalloc ){ 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(void *p, u8 eType){ int rc = 1; if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){ 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(void *p, u8 eType){ int rc = 1; if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){ 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 mnMaster; /* ** iMaster is the index of the master chunk. Most new allocations ** occur off of this chunk. szMaster is the size (in Mem3Blocks) ** of the current master. iMaster is 0 if there is not master chunk. ** The master chunk is not in either the aiHash[] or aiSmall[]. */ u32 iMaster; u32 szMaster; /* ** 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.iMaster free chunk. ** Return a pointer to the new allocation. Or, if the master chunk ** is not large enough, return 0. */ static void *memsys3FromMaster(u32 nBlock){ assert( sqlite3_mutex_held(mem3.mutex) ); assert( mem3.szMaster>=nBlock ); if( nBlock>=mem3.szMaster-1 ){ /* Use the entire master */ void *p = memsys3Checkout(mem3.iMaster, mem3.szMaster); mem3.iMaster = 0; mem3.szMaster = 0; mem3.mnMaster = 0; return p; }else{ /* Split the master block. Return the tail. */ u32 newi, x; newi = mem3.iMaster + mem3.szMaster - nBlock; assert( newi > mem3.iMaster+1 ); mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = nBlock; mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x |= 2; mem3.aPool[newi-1].u.hdr.size4x = nBlock*4 + 1; mem3.szMaster -= nBlock; mem3.aPool[newi-1].u.hdr.prevSize = mem3.szMaster; x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2; mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x; if( mem3.szMaster < mem3.mnMaster ){ mem3.mnMaster = mem3.szMaster; } 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.iMaster, it replaces ** the current mem3.iMaster with the new larger chunk. In order for ** this mem3.iMaster replacement to work, the master chunk must be ** linked into the hash tables. That is not the normal state of ** affairs, of course. The calling routine must link the master ** chunk before invoking this routine, then must unlink the (possibly ** changed) master 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.szMaster ){ mem3.iMaster = i; mem3.szMaster = 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 master chunk. This step usually works if step 1 fails. */ if( mem3.szMaster>=nBlock ){ return memsys3FromMaster(nBlock); } /* STEP 3: ** Loop through the entire memory pool. Coalesce adjacent free ** chunks. Recompute the master chunk as the largest free chunk. ** Then try again to satisfy the allocation by carving a piece off ** of the end of the master chunk. This step happens very ** rarely (we hope!) */ for(toFree=nBlock*16; toFree<(mem3.nPool*16); toFree *= 2){ memsys3OutOfMemory(toFree); if( mem3.iMaster ){ memsys3Link(mem3.iMaster); mem3.iMaster = 0; mem3.szMaster = 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.szMaster ){ memsys3Unlink(mem3.iMaster); if( mem3.szMaster>=nBlock ){ return memsys3FromMaster(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 master using the newly freed chunk */ if( mem3.iMaster ){ while( (mem3.aPool[mem3.iMaster-1].u.hdr.size4x&2)==0 ){ size = mem3.aPool[mem3.iMaster-1].u.hdr.prevSize; mem3.iMaster -= size; mem3.szMaster += size; memsys3Unlink(mem3.iMaster); x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2; mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x; mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = mem3.szMaster; } x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2; while( (mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x&1)==0 ){ memsys3Unlink(mem3.iMaster+mem3.szMaster); mem3.szMaster += mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x/4; mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x; mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = mem3.szMaster; } } } /* ** 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 master block. */ mem3.szMaster = mem3.nPool; mem3.mnMaster = mem3.szMaster; mem3.iMaster = 1; mem3.aPool[0].u.hdr.size4x = (mem3.szMaster<<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.iMaster ? " **master**" : ""); } } 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, "master=%d\n", mem3.iMaster); fprintf(out, "nowUsed=%d\n", mem3.nPool*8 - mem3.szMaster*8); fprintf(out, "mxUsed=%d\n", mem3.nPool*8 - mem3.mnMaster*8); sqlite3_mutex_leave(mem3.mutex); if( out==stdout ){ fflush(stdout); }else{ fclose(out); } #else |
︙ | ︙ |
Changes to src/mem5.c.
︙ | ︙ | |||
416 417 418 419 420 421 422 | ** ** All allocations must be a power of two and must be expressed by a ** 32-bit signed integer. Hence the largest allocation is 0x40000000 ** or 1073741824 bytes. */ static int memsys5Roundup(int n){ int iFullSz; | < < < < < | < < < | < | 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 | ** ** All allocations must be a power of two and must be expressed by a ** 32-bit signed integer. Hence the largest allocation is 0x40000000 ** or 1073741824 bytes. */ static int memsys5Roundup(int n){ int iFullSz; if( n > 0x40000000 ) return 0; for(iFullSz=mem5.szAtom; iFullSz<n; iFullSz *= 2); return iFullSz; } /* ** Return the ceiling of the logarithm base 2 of iValue. ** ** Examples: memsys5Log(1) -> 0 |
︙ | ︙ |
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 | ** 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" #ifdef SQLITE_ENABLE_DESERIALIZE /* ** Forward declaration of objects used by this utility */ typedef struct sqlite3_vfs MemVfs; typedef struct MemFile MemFile; /* Access to a lower-level VFS that (might) implement dynamic loading, ** access to randomness, etc. */ #define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData)) /* An open file */ struct MemFile { sqlite3_file base; /* IO methods */ 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 */ int nMmap; /* Number of memory mapped pages */ unsigned mFlags; /* Flags */ int eLock; /* Most recent lock against this file */ }; /* ** 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); static int memdbSync(sqlite3_file*, int flags); static int memdbFileSize(sqlite3_file*, sqlite3_int64 *pSize); static int memdbLock(sqlite3_file*, int); /* static int memdbCheckReservedLock(sqlite3_file*, int *pResOut);// not used */ static int memdbFileControl(sqlite3_file*, int op, void *pArg); /* static int memdbSectorSize(sqlite3_file*); // not used */ static int memdbDeviceCharacteristics(sqlite3_file*); static int memdbFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp); static int memdbUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p); |
︙ | ︙ | |||
149 150 151 152 153 154 155 | memdbDlError, /* xDlError */ memdbDlSym, /* xDlSym */ memdbDlClose, /* xDlClose */ memdbRandomness, /* xRandomness */ memdbSleep, /* xSleep */ 0, /* memdbCurrentTime, */ /* xCurrentTime */ memdbGetLastError, /* xGetLastError */ | | < < < | < < < < < < < < < < < < < < < < < < < < | > > | < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < | < < < | | | | | < | < < < < < < < | < < | < < < | < < | < < | < < < < < < < | < < < < | < < < < < < < < < < < < | < < < < < < < < < < < < | < < < < < < < < < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < | < | < < > < | < < < | < | < | < < < < | | < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < | < < < < < < < < < < < < | | < < < | | < | | | | 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 | memdbDlError, /* xDlError */ memdbDlSym, /* xDlSym */ memdbDlClose, /* xDlClose */ memdbRandomness, /* xRandomness */ memdbSleep, /* xSleep */ 0, /* memdbCurrentTime, */ /* xCurrentTime */ memdbGetLastError, /* xGetLastError */ memdbCurrentTimeInt64 /* xCurrentTimeInt64 */ }; static const sqlite3_io_methods memdb_io_methods = { 3, /* iVersion */ memdbClose, /* xClose */ memdbRead, /* xRead */ memdbWrite, /* xWrite */ memdbTruncate, /* xTruncate */ memdbSync, /* xSync */ memdbFileSize, /* xFileSize */ memdbLock, /* xLock */ memdbLock, /* xUnlock - same as xLock in this case */ 0, /* memdbCheckReservedLock, */ /* xCheckReservedLock */ memdbFileControl, /* xFileControl */ 0, /* memdbSectorSize,*/ /* xSectorSize */ memdbDeviceCharacteristics, /* xDeviceCharacteristics */ 0, /* xShmMap */ 0, /* xShmLock */ 0, /* xShmBarrier */ 0, /* xShmUnmap */ memdbFetch, /* xFetch */ memdbUnfetch /* xUnfetch */ }; /* ** Close an memdb-file. ** ** The pData pointer is owned by the application, so there is nothing ** to free. */ static int memdbClose(sqlite3_file *pFile){ MemFile *p = (MemFile *)pFile; if( p->mFlags & SQLITE_DESERIALIZE_FREEONCLOSE ) sqlite3_free(p->aData); return SQLITE_OK; } /* ** Read data from an memdb-file. */ static int memdbRead( sqlite3_file *pFile, void *zBuf, int iAmt, sqlite_int64 iOfst ){ MemFile *p = (MemFile *)pFile; if( iOfst+iAmt>p->sz ){ memset(zBuf, 0, iAmt); if( iOfst<p->sz ) memcpy(zBuf, p->aData+iOfst, p->sz - iOfst); return SQLITE_IOERR_SHORT_READ; } memcpy(zBuf, p->aData+iOfst, iAmt); return SQLITE_OK; } /* ** Try to enlarge the memory allocation to hold at least sz bytes */ static int memdbEnlarge(MemFile *p, sqlite3_int64 newSz){ unsigned char *pNew; if( (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)==0 || p->nMmap>0 ){ return SQLITE_FULL; } if( newSz>p->szMax ){ return SQLITE_FULL; } newSz *= 2; if( newSz>p->szMax ) newSz = p->szMax; pNew = sqlite3_realloc64(p->aData, newSz); if( pNew==0 ) return SQLITE_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 ){ MemFile *p = (MemFile *)pFile; if( NEVER(p->mFlags & SQLITE_DESERIALIZE_READONLY) ) return SQLITE_READONLY; if( iOfst+iAmt>p->sz ){ int rc; if( iOfst+iAmt>p->szAlloc && (rc = memdbEnlarge(p, iOfst+iAmt))!=SQLITE_OK ){ 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); 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){ MemFile *p = (MemFile *)pFile; if( NEVER(size>p->sz) ) return SQLITE_FULL; p->sz = size; return SQLITE_OK; } /* ** Sync an memdb-file. */ static int memdbSync(sqlite3_file *pFile, int flags){ return SQLITE_OK; } /* ** Return the current file-size of an memdb-file. */ static int memdbFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ MemFile *p = (MemFile *)pFile; *pSize = p->sz; return SQLITE_OK; } /* ** Lock an memdb-file. */ static int memdbLock(sqlite3_file *pFile, int eLock){ MemFile *p = (MemFile *)pFile; if( eLock>SQLITE_LOCK_SHARED && (p->mFlags & SQLITE_DESERIALIZE_READONLY)!=0 ){ return SQLITE_READONLY; } p->eLock = eLock; return SQLITE_OK; } #if 0 /* Never used because memdbAccess() always returns false */ /* ** Check if another file-handle holds a RESERVED lock on an memdb-file. */ 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){ MemFile *p = (MemFile *)pFile; int rc = SQLITE_NOTFOUND; 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; } 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){ 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 ){ MemFile *p = (MemFile *)pFile; if( iOfst+iAmt>p->sz ){ *pp = 0; }else{ p->nMmap++; *pp = (void*)(p->aData + iOfst); } return SQLITE_OK; } /* Release a memory-mapped page */ static int memdbUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){ MemFile *p = (MemFile *)pFile; p->nMmap--; return SQLITE_OK; } /* ** Open an mem file handle. */ static int memdbOpen( sqlite3_vfs *pVfs, const char *zName, sqlite3_file *pFile, int flags, int *pOutFlags ){ MemFile *p = (MemFile*)pFile; if( (flags & SQLITE_OPEN_MAIN_DB)==0 ){ return ORIGVFS(pVfs)->xOpen(ORIGVFS(pVfs), zName, pFile, flags, pOutFlags); } memset(p, 0, sizeof(*p)); p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE; assert( pOutFlags!=0 ); /* True because flags==SQLITE_OPEN_MAIN_DB */ *pOutFlags = flags | SQLITE_OPEN_MEMORY; p->base.pMethods = &memdb_io_methods; p->szMax = sqlite3GlobalConfig.mxMemdbSize; return SQLITE_OK; } #if 0 /* Only used to delete rollback journals, master 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){ |
︙ | ︙ | |||
638 639 640 641 642 643 644 | */ static int memdbAccess( sqlite3_vfs *pVfs, const char *zPath, int flags, int *pResOut ){ | < < < < | 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 | */ 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. */ |
︙ | ︙ | |||
729 730 731 732 733 734 735 | /* ** Translate a database connection pointer and schema name into a ** MemFile pointer. */ static MemFile *memdbFromDbSchema(sqlite3 *db, const char *zSchema){ MemFile *p = 0; | < < < < < | 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 | /* ** 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( |
︙ | ︙ | |||
772 773 774 775 776 777 778 | 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 ){ | < < | | | | | 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 | 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 ){ if( piSize ) *piSize = p->sz; if( mFlags & SQLITE_SERIALIZE_NOCOPY ){ pOut = p->aData; }else{ pOut = sqlite3_malloc64( p->sz ); if( pOut ) memcpy(pOut, p->aData, p->sz); } return pOut; } pBt = db->aDb[iDb].pBt; if( pBt==0 ) return 0; szPage = sqlite3BtreeGetPageSize(pBt); zSql = sqlite3_mprintf("PRAGMA \"%w\".page_count", zSchema); |
︙ | ︙ | |||
849 850 851 852 853 854 855 | 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); | < | | < < < | | < < | < | | | | | | < < < < < < < < < < < < | > > | < < < | | | 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 | 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); if( iDb<0 ){ rc = SQLITE_ERROR; goto end_deserialize; } zSql = sqlite3_mprintf("ATTACH x AS %Q", zSchema); 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{ p->aData = pData; p->sz = szDb; p->szAlloc = szBuf; p->szMax = szBuf; if( p->szMax<sqlite3GlobalConfig.mxMemdbSize ){ p->szMax = sqlite3GlobalConfig.mxMemdbSize; } p->mFlags = mFlags; rc = SQLITE_OK; } end_deserialize: sqlite3_finalize(pStmt); 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); int sz = pLower->szOsFile; memdb_vfs.pAppData = pLower; /* In all known configurations of SQLite, the size of a default ** sqlite3_file is greater than the size of a memdb sqlite3_file. ** Should that ever change, remove the following NEVER() */ if( NEVER(sz<sizeof(MemFile)) ) sz = sizeof(MemFile); memdb_vfs.szOsFile = sz; return sqlite3_vfs_register(&memdb_vfs, 0); } #endif /* SQLITE_ENABLE_DESERIALIZE */ |
Changes to src/memjournal.c.
︙ | ︙ | |||
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 */ | > | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | ** 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 */ int nSize; /* Bytes of data currently in memory */ 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 */ |
︙ | ︙ | |||
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 ){ | > > > > > | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | ){ MemJournal *p = (MemJournal *)pJfd; u8 *zOut = zBuf; int nRead = iAmt; int iChunkOffset; FileChunk *pChunk; #if defined(SQLITE_ENABLE_ATOMIC_WRITE) \ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) if( (iAmt+iOfst)>p->endpoint.iOffset ){ return SQLITE_IOERR_SHORT_READ; } #endif assert( (iAmt+iOfst)<=p->endpoint.iOffset ); 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 ){ |
︙ | ︙ | |||
126 127 128 129 130 131 132 | return SQLITE_OK; } /* ** Free the list of FileChunk structures headed at MemJournal.pFirst. */ | | | > | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | return SQLITE_OK; } /* ** Free the list of FileChunk structures headed at MemJournal.pFirst. */ static void memjrnlFreeChunks(MemJournal *p){ FileChunk *pIter; FileChunk *pNext; for(pIter=p->pFirst; pIter; pIter=pNext){ pNext = pIter->pNext; sqlite3_free(pIter); } p->pFirst = 0; } /* ** Flush the contents of memory to a real file on disk. */ static int memjrnlCreateFile(MemJournal *p){ int rc; |
︙ | ︙ | |||
159 160 161 162 163 164 165 | } 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. */ | | < < < | 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 | } 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(©); } } 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. */ sqlite3OsClose(pReal); *p = copy; } return rc; } /* ** Write data to the file. */ static int memjrnlWrite( sqlite3_file *pJfd, /* The journal file into which to write */ const void *zBuf, /* Take data to be written from here */ int iAmt, /* Number of bytes to write */ |
︙ | ︙ | |||
206 207 208 209 210 211 212 | /* If the contents of this write should be stored in memory */ else{ /* An in-memory journal file should only ever be appended to. Random ** access writes are not required. The only exception to this is when ** the in-memory journal is being used by a connection using the ** atomic-write optimization. In this case the first 28 bytes of the | | | | | < | > > > > < | < | > | > > > > < < < < < < < < < < < | | | < < < | | | | 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 | /* If the contents of this write should be stored in memory */ else{ /* An in-memory journal file should only ever be appended to. Random ** access writes are not required. The only exception to this is when ** the in-memory journal is being used by a connection using the ** atomic-write optimization. In this case the first 28 bytes of the ** journal file may be written as part of committing the transaction. */ assert( iOfst==p->endpoint.iOffset || iOfst==0 ); #if defined(SQLITE_ENABLE_ATOMIC_WRITE) \ || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) if( iOfst==0 && p->pFirst ){ assert( p->nChunkSize>iAmt ); memcpy((u8*)p->pFirst->zChunk, zBuf, iAmt); }else #else assert( iOfst>0 || p->pFirst==0 ); #endif { while( nWrite>0 ){ FileChunk *pChunk = p->endpoint.pChunk; int iChunkOffset = (int)(p->endpoint.iOffset%p->nChunkSize); int iSpace = MIN(nWrite, p->nChunkSize - iChunkOffset); if( iChunkOffset==0 ){ /* New chunk is required to extend the file. */ FileChunk *pNew = sqlite3_malloc(fileChunkSize(p->nChunkSize)); if( !pNew ){ return SQLITE_IOERR_NOMEM_BKPT; } pNew->pNext = 0; if( pChunk ){ assert( p->pFirst ); pChunk->pNext = pNew; }else{ assert( !p->pFirst ); p->pFirst = pNew; } p->endpoint.pChunk = pNew; } memcpy((u8*)p->endpoint.pChunk->zChunk + iChunkOffset, zWrite, iSpace); zWrite += iSpace; nWrite -= iSpace; p->endpoint.iOffset += iSpace; } p->nSize = iAmt + iOfst; } } return SQLITE_OK; } /* ** Truncate the file. ** ** If the journal file is already on disk, truncate it there. Or, if it ** is still in main memory but is being truncated to zero bytes in size, ** ignore */ static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){ MemJournal *p = (MemJournal *)pJfd; if( ALWAYS(size==0) ){ memjrnlFreeChunks(p); p->nSize = 0; p->endpoint.pChunk = 0; p->endpoint.iOffset = 0; 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); return SQLITE_OK; } /* ** Sync the file. ** ** If the real file has been created, call its xSync method. Otherwise, |
︙ | ︙ | |||
355 356 357 358 359 360 361 | const char *zName, /* Name of the journal file */ sqlite3_file *pJfd, /* Preallocated, blank file handle */ int flags, /* Opening flags */ int nSpill /* Bytes buffered before opening the file */ ){ MemJournal *p = (MemJournal*)pJfd; | < < | | 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 | const char *zName, /* Name of the journal file */ sqlite3_file *pJfd, /* Preallocated, blank file handle */ int flags, /* Opening flags */ int nSpill /* Bytes buffered before opening the file */ ){ MemJournal *p = (MemJournal*)pJfd; /* Zero the file-handle object. If nSpill was passed zero, initialize ** it using the sqlite3OsOpen() function of the underlying VFS. In this ** case none of the code in this module is executed as a result of calls ** made on the journal file-handle. */ memset(p, 0, sizeof(MemJournal)); if( nSpill==0 ){ return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0); } if( nSpill>0 ){ p->nChunkSize = nSpill; }else{ p->nChunkSize = 8 + MEMJOURNAL_DFLT_FILECHUNKSIZE - sizeof(FileChunk); assert( MEMJOURNAL_DFLT_FILECHUNKSIZE==fileChunkSize(p->nChunkSize) ); } p->pMethod = (const sqlite3_io_methods*)&MemJournalMethods; p->nSpill = nSpill; p->flags = flags; p->zJournal = zName; p->pVfs = pVfs; return SQLITE_OK; } |
︙ | ︙ | |||
399 400 401 402 403 404 405 | ** 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; | | | 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 | ** 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( p->pMethod==&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 | #pragma warning(disable : 4244) #pragma warning(disable : 4305) #pragma warning(disable : 4306) #pragma warning(disable : 4702) #pragma warning(disable : 4706) #endif /* defined(_MSC_VER) */ | < < < < < | 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 */ |
Changes to src/mutex.c.
︙ | ︙ | |||
250 251 252 253 254 255 256 | assert( sqlite3GlobalConfig.mutex.xMutexInit ); rc = sqlite3GlobalConfig.mutex.xMutexInit(); #ifdef SQLITE_DEBUG GLOBAL(int, mutexIsInit) = 1; #endif | < | 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(). */ |
︙ | ︙ |
Changes to src/mutex.h.
︙ | ︙ | |||
63 64 65 66 67 68 69 | #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 | < | 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) */ |
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_MASTER ** <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_MASTER ** <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_MASTER)) ) /* ** 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_MASTER ** 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_MASTER mutex. */ static void enterMutex(void){ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); checkListProperties(0); } /* ** Release the STATIC_MASTER mutex. */ static void leaveMutex(void){ assertMutexHeld(); checkListProperties(0); sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); } /* ** 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_MASTER 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_MASTER 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.
︙ | ︙ | |||
102 103 104 105 106 107 108 | } int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){ DO_OS_MALLOC_TEST(id); return id->pMethods->xFileSize(id, pSize); } int sqlite3OsLock(sqlite3_file *id, int lockType){ DO_OS_MALLOC_TEST(id); | < < < < | < < < < < < | 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 | } int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){ DO_OS_MALLOC_TEST(id); return id->pMethods->xFileSize(id, pSize); } int sqlite3OsLock(sqlite3_file *id, int lockType){ DO_OS_MALLOC_TEST(id); return id->pMethods->xLock(id, lockType); } int sqlite3OsUnlock(sqlite3_file *id, int lockType){ return id->pMethods->xUnlock(id, lockType); } int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut){ DO_OS_MALLOC_TEST(id); return id->pMethods->xCheckReservedLock(id, pResOut); } /* ** Use sqlite3OsFileControl() when we are doing something that might fail ** and we need to know about the failures. Use sqlite3OsFileControlHint() ** when simply tossing information over the wall to the VFS and we do not ** really care if the VFS receives and understands the information since it ** is only a hint and can be safely ignored. The sqlite3OsFileControlHint() ** 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 ** to the user. */ 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){ 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){ |
︙ | ︙ | |||
221 222 223 224 225 226 227 | ){ 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. */ | < | | | 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | ){ 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 & 0x87f7f, 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(pVfs, zPath, dirSync); } int sqlite3OsAccess( sqlite3_vfs *pVfs, const char *zPath, int flags, int *pResOut ){ |
︙ | ︙ | |||
252 253 254 255 256 257 258 | ){ 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){ | < < < < < < < < | < < | 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 | ){ 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){ 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; } |
︙ | ︙ | |||
315 316 317 318 319 320 321 | 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); | < < < | 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); } |
︙ | ︙ | |||
365 366 367 368 369 370 371 | sqlite3_mutex *mutex; #endif #ifndef SQLITE_OMIT_AUTOINIT int rc = sqlite3_initialize(); if( rc ) return 0; #endif #if SQLITE_THREADSAFE | | | | 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 | 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_MASTER); #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_MASTER)) ); 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 ){ |
︙ | ︙ | |||
411 412 413 414 415 416 417 | int rc = sqlite3_initialize(); if( rc ) return rc; #endif #ifdef SQLITE_ENABLE_API_ARMOR if( pVfs==0 ) return SQLITE_MISUSE_BKPT; #endif | | | 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 | 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_MASTER); ) sqlite3_mutex_enter(mutex); vfsUnlink(pVfs); if( makeDflt || vfsList==0 ){ pVfs->pNext = vfsList; vfsList = pVfs; }else{ pVfs->pNext = vfsList->pNext; |
︙ | ︙ | |||
435 436 437 438 439 440 441 | */ 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 | | | 411 412 413 414 415 416 417 418 419 420 421 422 423 | */ 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_MASTER); ) sqlite3_mutex_enter(mutex); vfsUnlink(pVfs); sqlite3_mutex_leave(mutex); return SQLITE_OK; } |
Changes to src/os.h.
︙ | ︙ | |||
29 30 31 32 33 34 35 | /* If the SET_FULLSYNC macro is not defined above, then make it ** a no-op */ #ifndef SET_FULLSYNC # define SET_FULLSYNC(x,y) #endif | < < < < < < < < < < < < < | 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | /* 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 |
︙ | ︙ |
Changes to src/os_common.h.
︙ | ︙ | |||
31 32 33 34 35 36 37 38 39 40 41 42 43 44 | /* ** Macros for performance tracing. Normally turned off. Only works ** on i486 hardware. */ #ifdef SQLITE_PERFORMANCE_TRACE static sqlite_uint64 g_start; static sqlite_uint64 g_elapsed; #define TIMER_START g_start=sqlite3Hwtime() #define TIMER_END g_elapsed=sqlite3Hwtime()-g_start #define TIMER_ELAPSED g_elapsed #else #define TIMER_START | > > > > > > | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | /* ** Macros for performance tracing. Normally turned off. Only works ** on i486 hardware. */ #ifdef SQLITE_PERFORMANCE_TRACE /* ** hwtime.h contains inline assembler code for implementing ** high-performance timing routines. */ #include "hwtime.h" static sqlite_uint64 g_start; static sqlite_uint64 g_elapsed; #define TIMER_START g_start=sqlite3Hwtime() #define TIMER_END g_elapsed=sqlite3Hwtime()-g_start #define TIMER_ELAPSED g_elapsed #else #define TIMER_START |
︙ | ︙ |
Deleted src/os_kv.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/os_setup.h.
︙ | ︙ | |||
16 17 18 19 20 21 22 | #ifndef SQLITE_OS_SETUP_H #define SQLITE_OS_SETUP_H /* ** Figure out if we are dealing with Unix, Windows, or some other operating ** system. ** | | > > | | | | > | < < < | < > | | | < | > | | | | | > > > > | > > > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | #ifndef SQLITE_OS_SETUP_H #define SQLITE_OS_SETUP_H /* ** Figure out if we are dealing with Unix, Windows, or some other operating ** system. ** ** After the following block of preprocess macros, all of SQLITE_OS_UNIX, ** SQLITE_OS_WIN, and SQLITE_OS_OTHER will defined to either 1 or 0. One of ** the three will be 1. The other two will be 0. */ #if defined(SQLITE_OS_OTHER) # if SQLITE_OS_OTHER==1 # undef SQLITE_OS_UNIX # define SQLITE_OS_UNIX 0 # undef SQLITE_OS_WIN # define SQLITE_OS_WIN 0 # else # undef SQLITE_OS_OTHER # endif #endif #if !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_OTHER) # define SQLITE_OS_OTHER 0 # ifndef SQLITE_OS_WIN # if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || \ defined(__MINGW32__) || defined(__BORLANDC__) # define SQLITE_OS_WIN 1 # define SQLITE_OS_UNIX 0 # else # define SQLITE_OS_WIN 0 # define SQLITE_OS_UNIX 1 # endif # else # define SQLITE_OS_UNIX 0 # endif #else # ifndef SQLITE_OS_WIN # define SQLITE_OS_WIN 0 # endif #endif #endif /* SQLITE_OS_SETUP_H */ |
Changes to src/os_unix.c.
︙ | ︙ | |||
83 84 85 86 87 88 89 | # undef USE_PREAD64 # define USE_PREAD 1 #endif /* ** standard include files. */ | | | | | | < < < < < < < < < < < < < < < | | | | < < | | | < | 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 | # undef USE_PREAD64 # define USE_PREAD 1 #endif /* ** standard include files. */ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <unistd.h> #include <time.h> #include <sys/time.h> #include <errno.h> #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 # include <sys/mman.h> #endif #if SQLITE_ENABLE_LOCKING_STYLE # include <sys/ioctl.h> # include <sys/file.h> # include <sys/param.h> #endif /* SQLITE_ENABLE_LOCKING_STYLE */ #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)) # define HAVE_GETHOSTUUID 1 # else # warning "gethostuuid() is disabled." # endif #endif #if OS_VXWORKS # include <sys/ioctl.h> # include <semaphore.h> |
︙ | ︙ | |||
180 181 182 183 184 185 186 | #define MAX_PATHNAME 512 /* ** Maximum supported symbolic links */ #define SQLITE_MAX_SYMLINKS 100 | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | #define MAX_PATHNAME 512 /* ** Maximum supported symbolic links */ #define SQLITE_MAX_SYMLINKS 100 /* Always cast the getpid() return type for compatibility with ** kernel modules in VxWorks. */ #define osGetpid(X) (pid_t)getpid() /* ** Only set the lastErrno if the error code is a real error and not ** a normal expected return code of SQLITE_BUSY or SQLITE_OK */ #define IS_LOCK_ERROR(x) ((x != SQLITE_OK) && (x != SQLITE_BUSY)) |
︙ | ︙ | |||
491 492 493 494 495 496 497 | { "pwrite64", (sqlite3_syscall_ptr)pwrite64, 0 }, #else { "pwrite64", (sqlite3_syscall_ptr)0, 0 }, #endif #define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off64_t))\ aSyscall[13].pCurrent) | < < < < | 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 | { "pwrite64", (sqlite3_syscall_ptr)pwrite64, 0 }, #else { "pwrite64", (sqlite3_syscall_ptr)0, 0 }, #endif #define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off64_t))\ aSyscall[13].pCurrent) { "fchmod", (sqlite3_syscall_ptr)fchmod, 0 }, #define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent) #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE { "fallocate", (sqlite3_syscall_ptr)posix_fallocate, 0 }, #else { "fallocate", (sqlite3_syscall_ptr)0, 0 }, #endif |
︙ | ︙ | |||
531 532 533 534 535 536 537 | #if defined(HAVE_FCHOWN) { "geteuid", (sqlite3_syscall_ptr)geteuid, 0 }, #else { "geteuid", (sqlite3_syscall_ptr)0, 0 }, #endif #define osGeteuid ((uid_t(*)(void))aSyscall[21].pCurrent) | | < | < | 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 | #if defined(HAVE_FCHOWN) { "geteuid", (sqlite3_syscall_ptr)geteuid, 0 }, #else { "geteuid", (sqlite3_syscall_ptr)0, 0 }, #endif #define osGeteuid ((uid_t(*)(void))aSyscall[21].pCurrent) #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 { "mmap", (sqlite3_syscall_ptr)mmap, 0 }, #else { "mmap", (sqlite3_syscall_ptr)0, 0 }, #endif #define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[22].pCurrent) #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0 { "munmap", (sqlite3_syscall_ptr)munmap, 0 }, #else { "munmap", (sqlite3_syscall_ptr)0, 0 }, #endif #define osMunmap ((int(*)(void*,size_t))aSyscall[23].pCurrent) #if HAVE_MREMAP && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) |
︙ | ︙ | |||
578 579 580 581 582 583 584 | { "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 }, | < < > | 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 | { "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 #define osIoctl ((int(*)(int,int,...))aSyscall[28].pCurrent) }; /* 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 |
︙ | ︙ | |||
726 727 728 729 730 731 732 | fd = osOpen(z,f,m2); #endif if( fd<0 ){ if( errno==EINTR ) continue; break; } if( fd>=SQLITE_MINIMUM_FILE_DESCRIPTOR ) break; | < < < | | 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 | fd = osOpen(z,f,m2); #endif if( fd<0 ){ if( errno==EINTR ) continue; 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", f, 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 |
︙ | ︙ | |||
1588 1589 1590 1591 1592 1593 1594 | sqlite3_mutex_leave(pFile->pInode->pLockMutex); OSTRACE(("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved)); *pResOut = reserved; return rc; } | < < < | 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 | 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 |
︙ | ︙ | |||
1612 1613 1614 1615 1616 1617 1618 | # 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 */ ){ | < | | | | 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 | # 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); while( rc<0 && pFile->iBusyTimeout>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. */ usleep(1000); rc = osFcntl(h,F_SETLK,pLock); pFile->iBusyTimeout--; } return rc; } #endif /* SQLITE_ENABLE_SETLK_TIMEOUT */ /* |
︙ | ︙ | |||
1691 1692 1693 1694 1695 1696 1697 | ** are inserted in between. The locking might fail on one of the later ** transitions leaving the lock state different from what it started but ** still short of its goal. The following chart shows the allowed ** transitions and the inserted intermediate states: ** ** UNLOCKED -> SHARED ** SHARED -> RESERVED | | | 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 | ** are inserted in between. The locking might fail on one of the later ** transitions leaving the lock state different from what it started but ** still short of its goal. The following chart shows the allowed ** transitions and the inserted intermediate states: ** ** UNLOCKED -> SHARED ** SHARED -> RESERVED ** SHARED -> (PENDING) -> EXCLUSIVE ** RESERVED -> (PENDING) -> EXCLUSIVE ** PENDING -> EXCLUSIVE ** ** This routine will only increase a lock. Use the sqlite3OsUnlock() ** routine to lower a locking level. */ static int unixLock(sqlite3_file *id, int eFileLock){ |
︙ | ︙ | |||
1724 1725 1726 1727 1728 1729 1730 | ** lack of shared-locks on Windows95 lives on, for backwards ** compatibility.) ** ** A process may only obtain a RESERVED lock after it has a SHARED lock. ** A RESERVED lock is implemented by grabbing a write-lock on the ** 'reserved byte'. ** | | | < | | > > > < | | < | | < | | 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 | ** lack of shared-locks on Windows95 lives on, for backwards ** compatibility.) ** ** A process may only obtain a RESERVED lock after it has a SHARED lock. ** A RESERVED lock is implemented by grabbing a write-lock on the ** 'reserved byte'. ** ** A process may only obtain a PENDING lock after it has obtained a ** SHARED lock. A PENDING lock is implemented by obtaining a write-lock ** on the 'pending byte'. This ensures that no new SHARED locks can be ** obtained, but existing SHARED locks are allowed to persist. A process ** does not have to obtain a RESERVED lock on the way to a PENDING lock. ** This property is used by the algorithm for rolling back a journal file ** after a crash. ** ** An EXCLUSIVE lock, obtained after a PENDING lock is held, is ** implemented by obtaining a write-lock on the entire 'shared byte ** range'. Since all other locks require a read-lock on one of the bytes ** within this range, this ensures that no other locks are held on the ** database. */ int rc = SQLITE_OK; unixFile *pFile = (unixFile*)id; unixInodeInfo *pInode; struct flock lock; int tErrno = 0; |
︙ | ︙ | |||
1808 1809 1810 1811 1812 1813 1814 | /* A PENDING lock is needed before acquiring a SHARED lock and before ** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will ** be released. */ lock.l_len = 1L; lock.l_whence = SEEK_SET; if( eFileLock==SHARED_LOCK | | < < < | 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 | /* A PENDING lock is needed before acquiring a SHARED lock and before ** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will ** be released. */ lock.l_len = 1L; lock.l_whence = SEEK_SET; if( eFileLock==SHARED_LOCK || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK) ){ lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK); lock.l_start = PENDING_BYTE; if( unixFileLock(pFile, &lock) ){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); if( rc!=SQLITE_BUSY ){ storeLastErrno(pFile, tErrno); } goto end_lock; } } /* If control gets to this point, then actually go ahead and make ** operating system calls for the specified lock. */ |
︙ | ︙ | |||
1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 | && eFileLock==RESERVED_LOCK ){ pFile->transCntrChng = 0; pFile->dbUpdate = 0; pFile->inNormalWrite = 1; } #endif if( rc==SQLITE_OK ){ pFile->eFileLock = eFileLock; pInode->eFileLock = eFileLock; } end_lock: sqlite3_mutex_leave(pInode->pLockMutex); OSTRACE(("LOCK %d %s %s (unix)\n", pFile->h, azFileLock(eFileLock), rc==SQLITE_OK ? "ok" : "failed")); return rc; | > > > > | 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 | && eFileLock==RESERVED_LOCK ){ pFile->transCntrChng = 0; pFile->dbUpdate = 0; pFile->inNormalWrite = 1; } #endif if( rc==SQLITE_OK ){ pFile->eFileLock = eFileLock; pInode->eFileLock = eFileLock; }else if( eFileLock==EXCLUSIVE_LOCK ){ pFile->eFileLock = PENDING_LOCK; pInode->eFileLock = PENDING_LOCK; } end_lock: sqlite3_mutex_leave(pInode->pLockMutex); OSTRACE(("LOCK %d %s %s (unix)\n", pFile->h, azFileLock(eFileLock), rc==SQLITE_OK ? "ok" : "failed")); return rc; |
︙ | ︙ | |||
2191 2192 2193 2194 2195 2196 2197 | ** 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); | < | 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 | ** 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 ***************** ******************************************************************************/ |
︙ | ︙ | |||
3388 3389 3390 3391 3392 3393 3394 | ){ unixFile *pFile = (unixFile *)id; int got; assert( id ); assert( offset>=0 ); assert( amt>0 ); | | | 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 | ){ unixFile *pFile = (unixFile *)id; int got; assert( id ); assert( offset>=0 ); assert( amt>0 ); /* If this is a database file (not a journal, master-journal or temp ** file), the bytes in the locking range should never be read or written. */ #if 0 assert( pFile->pPreallocatedUnused==0 || offset>=PENDING_BYTE+512 || offset+amt<=PENDING_BYTE ); #endif |
︙ | ︙ | |||
3418 3419 3420 3421 3422 3423 3424 | } #endif got = seekAndRead(pFile, offset, pBuf, amt); if( got==amt ){ return SQLITE_OK; }else if( got<0 ){ | | < < < < < < < < < < < < < < < < < | 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 | } #endif got = seekAndRead(pFile, offset, pBuf, amt); if( got==amt ){ return SQLITE_OK; }else if( got<0 ){ /* lastErrno set by seekAndRead */ return SQLITE_IOERR_READ; }else{ 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; } |
︙ | ︙ | |||
3518 3519 3520 3521 3522 3523 3524 | sqlite3_int64 offset ){ unixFile *pFile = (unixFile*)id; int wrote = 0; assert( id ); assert( amt>0 ); | | | 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 | sqlite3_int64 offset ){ unixFile *pFile = (unixFile*)id; int wrote = 0; assert( id ); assert( amt>0 ); /* If this is a database file (not a journal, master-journal or temp ** file), the bytes in the locking range should never be read or written. */ #if 0 assert( pFile->pPreallocatedUnused==0 || offset>=PENDING_BYTE+512 || offset+amt<=PENDING_BYTE ); #endif |
︙ | ︙ | |||
3994 3995 3996 3997 3998 3999 4000 | }else{ pFile->ctrlFlags |= mask; } } /* Forward declaration */ static int unixGetTempname(int nBuf, char *zBuf); | < < < | 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 | }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 ){ |
︙ | ︙ | |||
4064 4065 4066 4067 4068 4069 4070 | } case SQLITE_FCNTL_HAS_MOVED: { *(int*)pArg = fileHasMoved(pFile); return SQLITE_OK; } #ifdef SQLITE_ENABLE_SETLK_TIMEOUT case SQLITE_FCNTL_LOCK_TIMEOUT: { | < < | 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 | } 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; |
︙ | ︙ | |||
4113 4114 4115 4116 4117 4118 4119 | #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__) */ | < < < < < < < < < | 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 | #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 |
︙ | ︙ | |||
4331 4332 4333 4334 4335 4336 4337 | 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 */ | < | 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 | 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 }; |
︙ | ︙ | |||
4366 4367 4368 4369 4370 4371 4372 | }; /* ** 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 */ | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 | }; /* ** 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. */ |
︙ | ︙ | |||
4429 4430 4431 4432 4433 4434 4435 | /* 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 ){ | < | < < < < | < < | 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 | /* 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; rc = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile); rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY; } /* 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); |
︙ | ︙ | |||
4698 4699 4700 4701 4702 4703 4704 | rc = SQLITE_NOMEM_BKPT; goto shm_open_err; } } if( pInode->bProcessLock==0 ){ if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){ | | < | < | 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 | 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,(sStat.st_mode&0777)); } if( pShmNode->hShm<0 ){ pShmNode->hShm = robust_open(zShm, O_RDONLY, (sStat.st_mode&0777)); if( pShmNode->hShm<0 ){ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShm); goto shm_open_err; } pShmNode->isReadonly = 1; } |
︙ | ︙ | |||
4906 4907 4908 4909 4910 4911 4912 | *pp = 0; } if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY; sqlite3_mutex_leave(pShmNode->pShmMutex); return rc; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > | > | | | | | | | > | < | < < < | < | | | | | > > | > > | > | < | < > > > > | > > > > > | > | | | < < | < > | | < | | | > < < < < | 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 | *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 */ unixShm *pX; /* For looping over all siblings */ unixShmNode *pShmNode = p->pShmNode; /* The underlying file iNode */ int rc = SQLITE_OK; /* Result code */ u16 mask; /* Mask of locks to take or release */ 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 ); mask = (1<<(ofst+n)) - (1<<ofst); assert( n>1 || mask==(1<<ofst) ); sqlite3_mutex_enter(pShmNode->pShmMutex); if( flags & SQLITE_SHM_UNLOCK ){ u16 allMask = 0; /* Mask of locks held by siblings */ /* See if any siblings hold this same lock */ for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ if( pX==p ) continue; assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 ); allMask |= pX->sharedMask; } /* Unlock the system-level locks */ if( (mask & allMask)==0 ){ rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n); }else{ rc = SQLITE_OK; } /* Undo the local locks */ if( rc==SQLITE_OK ){ p->exclMask &= ~mask; p->sharedMask &= ~mask; } }else if( flags & SQLITE_SHM_SHARED ){ u16 allShared = 0; /* Union of locks held by connections other than "p" */ /* Find out which shared locks are already held by sibling connections. ** If any sibling already holds an exclusive lock, go ahead and return ** SQLITE_BUSY. */ for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ if( (pX->exclMask & mask)!=0 ){ rc = SQLITE_BUSY; break; } allShared |= pX->sharedMask; } /* Get shared locks at the system level, if necessary */ if( rc==SQLITE_OK ){ if( (allShared & mask)==0 ){ rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n); }else{ rc = SQLITE_OK; } } /* Get the local shared locks */ if( rc==SQLITE_OK ){ p->sharedMask |= mask; } }else{ /* Make sure no sibling connections hold locks that will block this ** lock. If any do, return SQLITE_BUSY right away. */ for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){ rc = SQLITE_BUSY; break; } } /* Get the exclusive locks at the system level. Then if successful ** also mark the local connection as being locked. */ 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; } } } 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; } /* |
︙ | ︙ | |||
5840 5841 5842 5843 5844 5845 5846 | osUnlink(zFilename); pNew->ctrlFlags |= UNIXFILE_DELETE; } #endif if( rc!=SQLITE_OK ){ if( h>=0 ) robust_close(pNew, h, __LINE__); }else{ | | < < < < < < < < < < < < < < < < < < < < > > > > > > > > > > | | < < < | < | | | | | | | | < < < | < < | | | 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 | osUnlink(zFilename); pNew->ctrlFlags |= UNIXFILE_DELETE; } #endif if( rc!=SQLITE_OK ){ if( h>=0 ) robust_close(pNew, h, __LINE__); }else{ pNew->pMethod = pLockingStyle; OpenCounter(+1); verifyDbFile(pNew); } return rc; } /* ** Return the name of a directory in which to put temporary files. ** If no suitable temporary file directory can be found, return NULL. */ static const char *unixTempFileDir(void){ static const char *azDirs[] = { 0, 0, "/var/tmp", "/usr/tmp", "/tmp", "." }; unsigned int i = 0; struct stat buf; const char *zDir = sqlite3_temp_directory; if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR"); if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR"); while(1){ if( zDir!=0 && osStat(zDir, &buf)==0 && S_ISDIR(buf.st_mode) && osAccess(zDir, 03)==0 ){ return zDir; } if( i>=sizeof(azDirs)/sizeof(azDirs[0]) ) break; zDir = azDirs[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 ** pVfs->mxPathname bytes. */ static int unixGetTempname(int nBuf, char *zBuf){ const char *zDir; int iLimit = 0; /* It's odd to simulate an io-error here, but really this is just ** using the io-error infrastructure to test that SQLite handles this ** function failing. */ zBuf[0] = 0; SimulateIOError( return SQLITE_IOERR ); zDir = unixTempFileDir(); if( zDir==0 ) return SQLITE_IOERR_GETTEMPPATH; do{ u64 r; sqlite3_randomness(sizeof(r), &r); assert( nBuf>2 ); zBuf[nBuf-2] = 0; sqlite3_snprintf(nBuf, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX"%llx%c", zDir, r, 0); if( zBuf[nBuf-2]!=0 || (iLimit++)>10 ) return SQLITE_ERROR; }while( osAccess(zBuf,0)==0 ); return SQLITE_OK; } #if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) /* ** Routine to transform a unixFile into a proxy-locking unixFile. ** Implementation in the proxy-lock division, but used by unixOpen() ** 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 master-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 |
︙ | ︙ | |||
5987 5988 5989 5990 5991 5992 5993 | || 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); | < | 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 | || 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); } |
︙ | ︙ | |||
6041 6042 6043 6044 6045 6046 6047 | ** 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 | | | 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 | ** 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. */ 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 */ |
︙ | ︙ | |||
6069 6070 6071 6072 6073 6074 6075 | ** "<path to db>-journal" ** "<path to db>-wal" ** "<path to db>-journalNN" ** "<path to db>-walNN" ** ** where NN is a decimal number. The NN naming schemes are ** used by the test_multiplex.c module. | | > > | | | | | < < < | > | | < < | < < > | 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 | ** "<path to db>-journal" ** "<path to db>-wal" ** "<path to db>-journalNN" ** "<path to db>-walNN" ** ** 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 master 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'; rc = getFileMode(zDb, pMode, pUid, pGid); }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){ *pMode = 0600; }else if( flags & SQLITE_OPEN_URI ){ /* If this is a main database file and the file was opened using a URI ** filename, check for the "modeof" parameter. If present, interpret ** its value as a filename and try to copy the mode, uid and gid from ** that file. */ |
︙ | ︙ | |||
6133 6134 6135 6136 6137 6138 6139 | 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() */ | | | | | 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 | 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&0xFFFFFF00; /* 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 master 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_MASTER_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. */ |
︙ | ︙ | |||
6178 6179 6180 6181 6182 6183 6184 | ** (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); | | | | < < < < < | 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 | ** (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 master 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_MASTER_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_MASTER_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)); if( eType==SQLITE_OPEN_MAIN_DB ){ UnixUnusedFd *pUnused; pUnused = findReusableFd(zName, flags); if( pUnused ){ fd = pUnused->fd; }else{ pUnused = sqlite3_malloc64(sizeof(*pUnused)); |
︙ | ︙ | |||
6248 6249 6250 6251 6252 6253 6254 | ** 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); | | | 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 | ** 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); 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 ){ |
︙ | ︙ | |||
6284 6285 6286 6287 6288 6289 6290 | } if( fd<0 ){ int rc2 = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName); if( rc==SQLITE_OK ) rc = rc2; goto open_finished; } | > | | < < < < < < < < < | | < | 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 | } if( fd<0 ){ int rc2 = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName); if( rc==SQLITE_OK ) rc = rc2; goto open_finished; } /* If this process is running as root and if creating a new rollback ** journal or WAL file, set the ownership of the journal or WAL to be ** the same as the original database. */ if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){ robustFchown(fd, uid, gid); } } assert( fd>=0 ); if( pOutFlags ){ *pOutFlags = flags; } if( p->pPreallocatedUnused ){ p->pPreallocatedUnused->fd = fd; p->pPreallocatedUnused->flags = flags; } if( isDelete ){ #if OS_VXWORKS zPath = zName; #elif defined(SQLITE_UNLINK_AFTER_CLOSE) zPath = sqlite3_mprintf("%s", zName); |
︙ | ︙ | |||
6386 6387 6388 6389 6390 6391 6392 | } goto open_finished; } } #endif assert( zPath==0 || zPath[0]=='/' | | | 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 | } goto open_finished; } } #endif assert( zPath==0 || zPath[0]=='/' || eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL ); rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags); open_finished: if( rc!=SQLITE_OK ){ sqlite3_free(p->pPreallocatedUnused); } |
︙ | ︙ | |||
6466 6467 6468 6469 6470 6471 6472 | /* 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; | | < | < | < < | < < < | < < | < < < < < < < < < < < < | < > | < | < < < < | | | < < < < < < < | < < < | | < < < > > > | < | < < < > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > > > > > > > | > | > > > > > > | > > > > | > > > > > > | > | > | > > | > > | > > > | > > > > > > > > > > | > > > > | > | | > > > > > | | | > | > > | 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 | /* 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) && buf.st_size>0); }else{ *pResOut = osAccess(zPath, W_OK|R_OK)==0; } return SQLITE_OK; } /* ** */ 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; 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); 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. ** ** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes ** (in this case, MAX_PATHNAME bytes). The full-path is written to ** this buffer before returning. */ static int unixFullPathname( sqlite3_vfs *pVfs, /* Pointer to vfs object */ const char *zPath, /* Possibly relative input path */ int nOut, /* Size of output buffer in bytes */ 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 = 1; /* 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 ** using the io-error infrastructure to test that SQLite handles this ** function failing. This function could fail if, for example, the ** current working directory has been unlinked. */ SimulateIOError( return SQLITE_ERROR ); do { /* Call stat() on path zIn. Set bLink to true if the path is a symbolic ** link, or false otherwise. */ int bLink = 0; struct stat buf; if( osLstat(zIn, &buf)!=0 ){ if( errno!=ENOENT ){ 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; }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); }else{ if( zDel[0]!='/' ){ int n; for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--); if( nByte+n+1>nOut ){ rc = SQLITE_CANTOPEN_BKPT; }else{ memmove(&zDel[n], zDel, nByte+1); memcpy(zDel, zIn, n); nByte += n; } } zDel[nByte] = '\0'; } } zIn = zDel; } assert( rc!=SQLITE_OK || zIn!=zOut || zIn[0]=='/' ); if( rc==SQLITE_OK && zIn!=zOut ){ 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 /* ** Interfaces for opening a shared library, finding entry points ** within the shared library, and closing the shared library. */ #include <dlfcn.h> |
︙ | ︙ | |||
6717 6718 6719 6720 6721 6722 6723 | ** The argument is the number of microseconds we want to sleep. ** The return value is the number of microseconds of sleep actually ** requested from the underlying operating system, a number which ** might be greater than or equal to the argument, but not less ** than the argument. */ static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){ | | < | | 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 argument is the number of microseconds we want to sleep. ** The return value is the number of microseconds of sleep actually ** requested from the underlying operating system, a number which ** might be greater than or equal to the argument, but not less ** than the argument. */ static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){ #if OS_VXWORKS struct timespec sp; 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 usleep(microseconds); UNUSED_PARAMETER(NotUsed); return microseconds; #else int seconds = (microseconds+999999)/1000000; sleep(seconds); UNUSED_PARAMETER(NotUsed); return seconds*1000000; |
︙ | ︙ | |||
7085 7086 7087 7088 7089 7090 7091 | 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; | | | 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 | 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; 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. |
︙ | ︙ | |||
7115 7116 7117 7118 7119 7120 7121 | if( fd<0 && errno==ENOENT && islockfile ){ if( proxyCreateLockPath(path) == SQLITE_OK ){ fd = robust_open(path, openFlags, 0); } } } if( fd<0 ){ | | | 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 | if( fd<0 && errno==ENOENT && islockfile ){ if( proxyCreateLockPath(path) == SQLITE_OK ){ fd = robust_open(path, openFlags, 0); } } } if( fd<0 ){ openFlags = O_RDONLY; fd = robust_open(path, openFlags, 0); terrno = errno; } if( fd<0 ){ if( islockfile ){ return SQLITE_BUSY; } |
︙ | ︙ | |||
7166 7167 7168 7169 7170 7171 7172 | #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 */ | | | | 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 | #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 */ #ifdef 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); #ifdef HAVE_GETHOSTUUID { struct timespec timeout = {1, 0}; /* 1 sec timeout */ if( gethostuuid(pHostID, &timeout) ){ int err = errno; if( pError ){ *pError = err; } |
︙ | ︙ | |||
7241 7242 7243 7244 7245 7246 7247 | /* 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 */ | | | 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 | /* 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), 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; |
︙ | ︙ | |||
7300 7301 7302 7303 7304 7305 7306 | if( osFstat(conchFile->h, &buf) ){ storeLastErrno(pFile, errno); return SQLITE_IOERR_LOCK; } if( nTries==1 ){ conchModTime = buf.st_mtimespec; | | | 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 | if( osFstat(conchFile->h, &buf) ){ storeLastErrno(pFile, errno); return SQLITE_IOERR_LOCK; } if( nTries==1 ){ conchModTime = buf.st_mtimespec; usleep(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; |
︙ | ︙ | |||
7326 7327 7328 7329 7330 7331 7332 | 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; } | | | 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 | 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; } usleep(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 ){ |
︙ | ︙ | |||
7851 7852 7853 7854 7855 7856 7857 | } return rc; } default: { assert( 0 ); /* The call assures that only valid opcodes are sent */ } } | | | 7599 7600 7601 7602 7603 7604 7605 7606 7607 7608 7609 7610 7611 7612 7613 | } return rc; } default: { assert( 0 ); /* The call assures that only valid opcodes are sent */ } } /*NOTREACHED*/ 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. |
︙ | ︙ | |||
8099 8100 8101 8102 8103 8104 8105 | /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ assert( ArraySize(aSyscall)==29 ); /* Register all VFSes defined in the aVfs[] array */ for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){ | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 7847 7848 7849 7850 7851 7852 7853 7854 7855 7856 7857 7858 7859 7860 7861 7862 7863 | /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ 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, |
︙ | ︙ |
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 *pMaster; ) /* The main static mutex */ MUTEX_LOGIC( sqlite3_mutex *pMem; ) /* The memsys static mutex */ MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); ) MUTEX_LOGIC( pMem = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); ) sqlite3_mutex_enter(pMaster); 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 master 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(pMaster); return rc; } #endif /* SQLITE_WIN32_MALLOC */ /* ** This function outputs the specified (ANSI) string to the Win32 debugger ** (if available). |
︙ | ︙ | |||
1914 1915 1916 1917 1918 1919 1920 | ** it accepts a UTF-8 string. */ int sqlite3_win32_set_directory8( unsigned long type, /* Identifier for directory being set or reset */ const char *zValue /* New value for directory being set or reset */ ){ char **ppDirectory = 0; | < | < | < | < < < < | | 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 | ** it accepts a UTF-8 string. */ int sqlite3_win32_set_directory8( unsigned long type, /* Identifier for directory being set or reset */ const char *zValue /* New value for directory being set or reset */ ){ char **ppDirectory = 0; #ifndef SQLITE_OMIT_AUTOINIT int rc = sqlite3_initialize(); if( rc ) return rc; #endif if( type==SQLITE_WIN32_DATA_DIRECTORY_TYPE ){ ppDirectory = &sqlite3_data_directory; }else if( type==SQLITE_WIN32_TEMP_DIRECTORY_TYPE ){ ppDirectory = &sqlite3_temp_directory; } assert( !ppDirectory || type==SQLITE_WIN32_DATA_DIRECTORY_TYPE || type==SQLITE_WIN32_TEMP_DIRECTORY_TYPE ); assert( !ppDirectory || sqlite3MemdebugHasType(*ppDirectory, MEMTYPE_HEAP) ); if( ppDirectory ){ char *zCopy = 0; if( zValue && zValue[0] ){ zCopy = sqlite3_mprintf("%s", zValue); if ( zCopy==0 ){ return SQLITE_NOMEM_BKPT; } } sqlite3_free(*ppDirectory); *ppDirectory = zCopy; return SQLITE_OK; } return SQLITE_ERROR; } /* ** This function is the same as sqlite3_win32_set_directory (below); however, ** it accepts a UTF-16 string. */ int sqlite3_win32_set_directory16( |
︙ | ︙ | |||
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 *); | < | 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; |
︙ | ︙ | |||
4073 4074 4075 4076 4077 4078 4079 | 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 */ ){ winFile *pDbFd = (winFile*)fd; /* Connection holding shared memory */ winShm *p = pDbFd->pShm; /* The shared memory being locked */ winShm *pX; /* For looping over all siblings */ | | < < < < | 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 | 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 */ ){ winFile *pDbFd = (winFile*)fd; /* Connection holding shared memory */ winShm *p = pDbFd->pShm; /* The shared memory being locked */ winShm *pX; /* For looping over all siblings */ winShmNode *pShmNode = p->pShmNode; int rc = SQLITE_OK; /* Result code */ u16 mask; /* Mask of locks to take or release */ 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 ); |
︙ | ︙ | |||
4223 4224 4225 4226 4227 4228 4229 | 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; | < | 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; |
︙ | ︙ | |||
4526 4527 4528 4529 4530 4531 4532 | if( rc!=SQLITE_OK ){ OSTRACE(("FETCH pid=%lu, pFile=%p, rc=%s\n", osGetCurrentProcessId(), pFd, sqlite3ErrName(rc))); return rc; } } if( pFd->mmapSize >= iOff+nAmt ){ | < | 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", |
︙ | ︙ | |||
4720 4721 4722 4723 4724 4725 4726 | return 1; } } } return 0; } | < < < < < < < < < < < < < | 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 | return 1; } } } return 0; } /* ** Create a temporary file name and store the resulting pointer into pzBuf. ** The pointer returned in pzBuf must be freed via sqlite3_free(). */ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){ static char zChars[] = "abcdefghijklmnopqrstuvwxyz" |
︙ | ︙ | |||
4769 4770 4771 4772 4773 4774 4775 | /* Figure out the effective temporary directory. First, check if one ** has been explicitly set by the application; otherwise, use the one ** configured by the operating system. */ nDir = nMax - (nPre + 15); assert( nDir>0 ); | | < < < | 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 | /* Figure out the effective temporary directory. First, check if one ** has been explicitly set by the application; otherwise, use the one ** configured by the operating system. */ nDir = nMax - (nPre + 15); assert( nDir>0 ); if( sqlite3_temp_directory ){ int nDirLen = sqlite3Strlen30(sqlite3_temp_directory); if( nDirLen>0 ){ if( !winIsDirSep(sqlite3_temp_directory[nDirLen-1]) ){ nDirLen++; } if( nDirLen>nDir ){ sqlite3_free(zBuf); OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n")); return winLogError(SQLITE_ERROR, 0, "winGetTempname1", 0); } sqlite3_snprintf(nMax, zBuf, "%s", sqlite3_temp_directory); } } #if defined(__CYGWIN__) else{ static const char *azDirs[] = { 0, /* getenv("SQLITE_TMPDIR") */ 0, /* getenv("TMPDIR") */ 0, /* getenv("TMP") */ 0, /* getenv("TEMP") */ |
︙ | ︙ | |||
5046 5047 5048 5049 5050 5051 5052 | 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 && ( | | | | | | 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 | int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE); int isCreate = (flags & SQLITE_OPEN_CREATE); int isReadonly = (flags & SQLITE_OPEN_READONLY); int isReadWrite = (flags & SQLITE_OPEN_READWRITE); #ifndef NDEBUG int isOpenJournal = (isCreate && ( eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_WAL )); #endif OSTRACE(("OPEN name=%s, pFile=%p, flags=%x, pOutFlags=%p\n", zUtf8Name, id, flags, pOutFlags)); /* Check the following statements are true: ** ** (a) Exactly one of the READWRITE and READONLY flags must be set, and ** (b) if CREATE is set, then READWRITE must also be set, and ** (c) if EXCLUSIVE is set, then CREATE must also be set. ** (d) if DELETEONCLOSE is set, then CREATE must also be set. */ 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 master 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_MASTER_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_MASTER_JOURNAL || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL ); assert( pFile!=0 ); memset(pFile, 0, sizeof(winFile)); pFile->h = INVALID_HANDLE_VALUE; |
︙ | ︙ | |||
5149 5150 5151 5152 5153 5154 5155 | /* Open existing file, or create if it doesn't exist */ dwCreationDisposition = OPEN_ALWAYS; }else{ /* Opens a file, only if it exists. */ dwCreationDisposition = OPEN_EXISTING; } | < | < < < | 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 | /* Open existing file, or create if it doesn't exist */ dwCreationDisposition = OPEN_ALWAYS; }else{ /* Opens a file, only if it exists. */ dwCreationDisposition = OPEN_EXISTING; } dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; if( isDelete ){ #if SQLITE_OS_WINCE dwFlagsAndAttributes = FILE_ATTRIBUTE_HIDDEN; isTemp = 1; #else dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY |
︙ | ︙ | |||
5293 5294 5295 5296 5297 5298 5299 | }else #endif { sqlite3_free(zConverted); } sqlite3_free(zTmpname); | | < | < | 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 | }else #endif { sqlite3_free(zConverted); } sqlite3_free(zTmpname); pFile->pMethod = pAppData ? pAppData->pMethod : &winIoMethod; pFile->pVfs = pVfs; pFile->h = h; if( isReadonly ){ pFile->ctrlFlags |= WINFILE_RDONLY; } if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){ pFile->ctrlFlags |= WINFILE_PSOW; } pFile->lastErrno = NO_ERROR; pFile->zPath = zName; #if SQLITE_MAX_MMAP_SIZE>0 pFile->hMap = NULL; pFile->pMapRegion = 0; |
︙ | ︙ | |||
5511 5512 5513 5514 5515 5516 5517 | } *pResOut = rc; OSTRACE(("ACCESS name=%s, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n", zFilename, pResOut, *pResOut)); return SQLITE_OK; } | < < < < < < < < < < < | 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 | } *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 ){ |
︙ | ︙ | |||
5574 5575 5576 5577 5578 5579 5580 | } /* ** Turn a relative pathname into a full pathname. Write the full ** pathname into zOut[]. zOut[] will be at least pVfs->mxPathname ** bytes in size. */ | | | | | < | 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 | } /* ** Turn a relative pathname into a full pathname. Write the full ** pathname into zOut[]. zOut[] will be at least pVfs->mxPathname ** bytes in size. */ static int winFullPathname( sqlite3_vfs *pVfs, /* Pointer to vfs object */ const char *zRelative, /* Possibly relative input path */ int nFull, /* Size of output buffer in bytes */ char *zFull /* Output buffer */ ){ #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && !defined(__CYGWIN__) DWORD nByte; void *zConverted; char *zOut; #endif /* If this path name begins with "/X:", where "X" is any alphabetic ** character, discard the initial "/" from the pathname. */ if( zRelative[0]=='/' && winIsDriveLetterAndColon(zRelative+1) ){ zRelative++; } #if defined(__CYGWIN__) SimulateIOError( return SQLITE_ERROR ); UNUSED_PARAMETER(nFull); assert( nFull>=pVfs->mxPathname ); |
︙ | ︙ | |||
5753 5754 5755 5756 5757 5758 5759 | sqlite3_free(zOut); return SQLITE_OK; }else{ return SQLITE_IOERR_NOMEM_BKPT; } #endif } | < < < < < < < < < < < < < < | 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 | sqlite3_free(zOut); return SQLITE_OK; }else{ return SQLITE_IOERR_NOMEM_BKPT; } #endif } #ifndef SQLITE_OMIT_LOAD_EXTENSION /* ** Interfaces for opening a shared library, finding entry points ** within the shared library, and closing the shared library. */ static void *winDlOpen(sqlite3_vfs *pVfs, const char *zFilename){ |
︙ | ︙ |
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 master journal file is used, then all writes to the database file ** are synced prior to the master 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 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 | > > > > > > > > > > > > > > | 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 | ** 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) /* ** A macro used for invoking the codec if there is one */ #ifdef SQLITE_HAS_CODEC # define CODEC1(P,D,N,X,E) \ if( P->xCodec && P->xCodec(P->pCodec,D,N,X)==0 ){ E; } # define CODEC2(P,D,N,X,E,O) \ if( P->xCodec==0 ){ O=(char*)D; }else \ if( (O=(char*)(P->xCodec(P->pCodec,D,N,X)))==0 ){ E; } #else # define CODEC1(P,D,N,X,E) /* NO-OP */ # define CODEC2(P,D,N,X,E,O) O=(char*)D #endif /* ** 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 |
︙ | ︙ | |||
431 432 433 434 435 436 437 | 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 */ | < | 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. |
︙ | ︙ | |||
485 486 487 488 489 490 491 | ** 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. ** | | | | | | | | | | 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 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. ** ** setMaster ** ** When PagerCommitPhaseOne() is called to commit a transaction, it may ** (or may not) specify a master-journal name to be written into the ** journal file before it is synced to disk. ** ** Whether or not a journal file contains a master-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 master-journal pointer, it is ** finalized by overwriting the first journal header with zeroes. If ** it does contain a master-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 master journal pointers cannot be finalized ** simply by overwriting the first journal-header with zeroes, as the ** master 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 setMaster 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). |
︙ | ︙ | |||
626 627 628 629 630 631 632 | 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 */ | < | | 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 | 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 */ u8 setMaster; /* True if a m-j name has been written to 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 */ |
︙ | ︙ | |||
676 677 678 679 680 681 682 683 | ** 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 */ | > < < > > > > > > | 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 | ** 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 */ int pageSize; /* Number of bytes in a page */ Pgno mxPgno; /* Maximum allowed size of the database */ 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 */ #ifdef SQLITE_HAS_CODEC void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */ void (*xCodecSizeChng)(void*,int,int); /* Notify of page size changes */ void (*xCodecFree)(void*); /* Destructor for the codec */ void *pCodec; /* First argument to xCodec... methods */ #endif 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 }; |
︙ | ︙ | |||
785 786 787 788 789 790 791 792 793 794 795 796 797 798 | */ #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) ){ ... | > > > > > | 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 | */ #if SQLITE_MAX_MMAP_SIZE>0 # define USEFETCH(x) ((x)->bUseFetch) #else # define USEFETCH(x) 0 #endif /* ** The maximum legal page number is (2^31 - 1). */ #define PAGER_MAX_PGNO 2147483647 /* ** The argument to this macro is a file descriptor (type sqlite3_file*). ** 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) ){ ... |
︙ | ︙ | |||
811 812 813 814 815 816 817 818 819 820 821 822 823 824 | ** * the database file is open, ** * there are no dirty pages in the cache, and ** * the desired page is not currently in the wal file. */ int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){ if( pPager->fd->pMethods==0 ) return 0; if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0; #ifndef SQLITE_OMIT_WAL if( pPager->pWal ){ u32 iRead = 0; int rc; rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iRead); return (rc==SQLITE_OK && iRead==0); } | > > > | 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 | ** * the database file is open, ** * there are no dirty pages in the cache, and ** * the desired page is not currently in the wal file. */ int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){ if( pPager->fd->pMethods==0 ) return 0; if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0; #ifdef SQLITE_HAS_CODEC if( pPager->xCodec!=0 ) return 0; #endif #ifndef SQLITE_OMIT_WAL if( pPager->pWal ){ u32 iRead = 0; int rc; rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iRead); return (rc==SQLITE_OK && iRead==0); } |
︙ | ︙ | |||
914 915 916 917 918 919 920 | assert( pPager->errCode==SQLITE_OK ); if( !pagerUseWal(pPager) ){ assert( p->eLock>=RESERVED_LOCK ); } assert( pPager->dbSize==pPager->dbOrigSize ); assert( pPager->dbOrigSize==pPager->dbFileSize ); assert( pPager->dbOrigSize==pPager->dbHintSize ); | | | 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 | assert( pPager->errCode==SQLITE_OK ); if( !pagerUseWal(pPager) ){ assert( p->eLock>=RESERVED_LOCK ); } assert( pPager->dbSize==pPager->dbOrigSize ); assert( pPager->dbOrigSize==pPager->dbFileSize ); assert( pPager->dbOrigSize==pPager->dbHintSize ); assert( pPager->setMaster==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 |
︙ | ︙ | |||
1044 1045 1046 1047 1048 1049 1050 | ** 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 | | > > > > | 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 | ** 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) #ifdef SQLITE_HAS_CODEC && pPager->xCodec==0 #endif ){ pPager->xGet = getPageMMap; #endif /* SQLITE_MAX_MMAP_SIZE>0 */ }else{ pPager->xGet = getPageNormal; } } |
︙ | ︙ | |||
1069 1070 1071 1072 1073 1074 1075 | 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) ){ | < < < | 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 | 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 |
︙ | ︙ | |||
1142 1143 1144 1145 1146 1147 1148 | 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)) } | < | 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 | 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. |
︙ | ︙ | |||
1271 1272 1273 1274 1275 1276 1277 | #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. | | | | | | | | | | | | | | | | | | | | | | | | < | 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 | #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 master journal file name from the ** end of the file and, if successful, copies it into memory supplied ** by the caller. See comments above writeMasterJournal() for the format ** used to store a master journal file name at the end of a journal file. ** ** zMaster must point to a buffer of at least nMaster bytes allocated by ** the caller. This should be sqlite3_vfs.mxPathname+1 (to ensure there is ** enough space to write the master journal name). If the master journal ** name in the journal is longer than nMaster bytes (including a ** nul-terminator), then this is handled as if no master journal name ** were present in the journal. ** ** If a master journal file name is present at the end of the journal ** file, then it is copied into the buffer pointed to by zMaster. A ** nul-terminator byte is appended to the buffer following the master ** journal file name. ** ** If it is determined that no master journal file name is present ** zMaster[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 readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){ int rc; /* Return code */ u32 len; /* Length in bytes of master 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 */ zMaster[0] = '\0'; if( SQLITE_OK!=(rc = sqlite3OsFileSize(pJrnl, &szJ)) || szJ<16 || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len)) || len>=nMaster || 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, zMaster, len, szJ-16-len)) ){ return rc; } /* See if the checksum matches the master journal name */ for(u=0; u<len; u++){ cksum -= zMaster[u]; } if( cksum ){ /* If the checksum doesn't add up, then one or more of the disk sectors ** containing the master journal filename is corrupted. This means ** definitely roll back, so just return SQLITE_OK and report a (nul) ** master-journal filename. */ len = 0; } zMaster[len] = '\0'; return SQLITE_OK; } /* ** Return the offset of the sector boundary at or immediately ** following the value in pPager->journalOff, assuming a sector |
︙ | ︙ | |||
1658 1659 1660 1661 1662 1663 1664 | pPager->journalOff += JOURNAL_HDR_SZ(pPager); return rc; } /* | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 | pPager->journalOff += JOURNAL_HDR_SZ(pPager); return rc; } /* ** Write the supplied master journal name into the journal file for pager ** pPager at the current location. The master 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: Master journal filename in utf-8. ** + 4 bytes: N (length of master journal name in bytes, no nul-terminator). ** + 4 bytes: Master journal name checksum. ** + 8 bytes: aJournalMagic[]. ** ** The master journal page checksum is the sum of the bytes in the master ** journal name, where each byte is interpreted as a signed 8-bit integer. ** ** If zMaster is a NULL pointer (occurs for a single database transaction), ** this call is a no-op. */ static int writeMasterJournal(Pager *pPager, const char *zMaster){ int rc; /* Return code */ int nMaster; /* Length of string zMaster */ i64 iHdrOff; /* Offset of header in journal file */ i64 jrnlSize; /* Size of journal file on disk */ u32 cksum = 0; /* Checksum of string zMaster */ assert( pPager->setMaster==0 ); assert( !pagerUseWal(pPager) ); if( !zMaster || pPager->journalMode==PAGER_JOURNALMODE_MEMORY || !isOpen(pPager->jfd) ){ return SQLITE_OK; } pPager->setMaster = 1; assert( pPager->journalHdr <= pPager->journalOff ); /* Calculate the length in bytes and the checksum of zMaster */ for(nMaster=0; zMaster[nMaster]; nMaster++){ cksum += zMaster[nMaster]; } /* If in full-sync mode, advance to the next disk sector before writing ** the master 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 master 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, zMaster, nMaster, iHdrOff+4))) || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nMaster, nMaster))) || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nMaster+4, cksum))) || (0 != (rc = sqlite3OsWrite(pPager->jfd, aJournalMagic, 8, iHdrOff+4+nMaster+8))) ){ return rc; } pPager->journalOff += (nMaster+20); /* If the pager is in peristent-journal mode, then the physical ** journal-file may extend past the end of the master-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 master-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 |
︙ | ︙ | |||
1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 | } /* 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. | > | 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 | } /* 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->changeCountDone = 0; 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. |
︙ | ︙ | |||
1888 1889 1890 1891 1892 1893 1894 | if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0); pPager->errCode = SQLITE_OK; setGetterMethod(pPager); } pPager->journalOff = 0; pPager->journalHdr = 0; | | | 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 | if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0); pPager->errCode = SQLITE_OK; setGetterMethod(pPager); } pPager->journalOff = 0; pPager->journalHdr = 0; pPager->setMaster = 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 |
︙ | ︙ | |||
2004 2005 2006 2007 2008 2009 2010 | ** 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. */ | | | 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 | ** 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 hasMaster, 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: |
︙ | ︙ | |||
2056 2057 2058 2059 2060 2061 2062 | rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags); } } pPager->journalOff = 0; }else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST || (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL) ){ | | | 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 | 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, hasMaster||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. */ |
︙ | ︙ | |||
2127 2128 2129 2130 2131 2132 2133 2134 2135 | 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; | > | | 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 | if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK; } if( !pPager->exclusiveMode && (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0)) ){ rc2 = pagerUnlockDb(pPager, SHARED_LOCK); pPager->changeCountDone = 0; } pPager->eState = PAGER_READER; pPager->setMaster = 0; return (rc==SQLITE_OK?rc2:rc); } /* ** Execute a rollback if a transaction is active and unlock the ** database file. |
︙ | ︙ | |||
2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 | 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 | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | while( i>0 ){ cksum += aData[i]; i -= 200; } return cksum; } /* ** Report the current page size and number of reserved bytes back ** to the codec. */ #ifdef SQLITE_HAS_CODEC static void pagerReportSize(Pager *pPager){ if( pPager->xCodecSizeChng ){ pPager->xCodecSizeChng(pPager->pCodec, pPager->pageSize, (int)pPager->nReserve); } } #else # define pagerReportSize(X) /* No-op if we do not support a codec */ #endif #ifdef SQLITE_HAS_CODEC /* ** Make sure the number of reserved bits is the same in the destination ** pager as it is in the source. This comes up when a VACUUM changes the ** number of reserved bits to the "optimal" amount. */ void sqlite3PagerAlignReserve(Pager *pDest, Pager *pSrc){ if( pDest->nReserve!=pSrc->nReserve ){ pDest->nReserve = pSrc->nReserve; pagerReportSize(pDest); } } #endif /* ** 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 |
︙ | ︙ | |||
2222 2223 2224 2225 2226 2227 2228 | ** and played back, then SQLITE_OK is returned. If an IO error occurs ** while reading the record from the (sub-)journal file or while writing ** to the database file, then the IO error code is returned. If data ** is successfully read from the (sub-)journal file but appears to be ** corrupted, SQLITE_DONE is returned. Data is considered corrupted in ** two circumstances: ** | | | 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 | ** and played back, then SQLITE_OK is returned. If an IO error occurs ** while reading the record from the (sub-)journal file or while writing ** to the database file, then the IO error code is returned. If data ** is successfully read from the (sub-)journal file but appears to be ** corrupted, SQLITE_DONE is returned. Data is considered corrupted in ** two circumstances: ** ** * If the record page-number is illegal (0 or PAGER_MJ_PGNO), or ** * If the record is being rolled back from the main journal file ** and the checksum field does not match the record content. ** ** Neither of these two scenarios are possible during a savepoint rollback. ** ** If this is a savepoint rollback, then memory may have to be dynamically ** allocated by this function. If this is the case and an allocation fails, |
︙ | ︙ | |||
2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 | 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; | > > > > > | 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 | 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 */ #ifdef SQLITE_HAS_CODEC /* The jrnlEnc flag is true if Journal pages should be passed through ** the codec. It is false for pure in-memory journals. */ const int jrnlEnc = (isMainJrnl || pPager->subjInMemory==0); #endif 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; |
︙ | ︙ | |||
2282 2283 2284 2285 2286 2287 2288 | *pOffset += pPager->pageSize + 4 + isMainJrnl*4; /* Sanity checking on the page. This is more important that I originally ** thought. If a power failure occurs while the journal is being written, ** it could cause invalid data to be written into the journal. We need to ** detect this invalid data (with high probability) and ignore it. */ | | | 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 | *pOffset += pPager->pageSize + 4 + isMainJrnl*4; /* Sanity checking on the page. This is more important that I originally ** thought. If a power failure occurs while the journal is being written, ** it could cause invalid data to be written into the journal. We need to ** detect this invalid data (with high probability) and ignore it. */ if( pgno==0 || pgno==PAGER_MJ_PGNO(pPager) ){ assert( !isSavepnt ); return SQLITE_DONE; } if( pgno>(Pgno)pPager->dbSize || sqlite3BitvecTest(pDone, pgno) ){ return SQLITE_OK; } if( isMainJrnl ){ |
︙ | ︙ | |||
2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 | 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 | > | 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 | return rc; } /* When playing back page 1, restore the nReserve setting */ if( pgno==1 && pPager->nReserve!=((u8*)aData)[20] ){ pPager->nReserve = ((u8*)aData)[20]; pagerReportSize(pPager); } /* 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 |
︙ | ︙ | |||
2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 | /* 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 | > > > > > > > > > > > > > > | 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 | /* 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. */ #ifdef SQLITE_HAS_CODEC if( !jrnlEnc ){ CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData); rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst); CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT); }else #endif rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst); if( pgno>pPager->dbFileSize ){ pPager->dbFileSize = pgno; } if( pPager->pBackup ){ #ifdef SQLITE_HAS_CODEC if( jrnlEnc ){ CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT); sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData); CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT,aData); }else #endif 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 |
︙ | ︙ | |||
2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 | 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; } /* | > > > > > | | | | | | | | | | | | | | | | | < | | | | > | < | | < | | | | | | | | | | | < | < | | | < | | | | | | < < < | | | | | | | | | | | | | | | 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 | 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)); } /* Decode the page just read from disk */ #if SQLITE_HAS_CODEC if( jrnlEnc ){ CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT); } #endif sqlite3PcacheRelease(pPg); } return rc; } /* ** Parameter zMaster is the name of a master journal file. A single journal ** file that referred to the master journal file has just been rolled back. ** This routine checks if it is possible to delete the master journal file, ** and does so if it is. ** ** Argument zMaster may point to Pager.pTmpSpace. So that buffer is not ** available for use within this function. ** ** When a master 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 master journal ** file for a transaction involving two databases might be: ** ** "/home/bill/a.db-journal\x00/home/bill/b.db-journal\x00" ** ** A master journal file may only be deleted once all of its child ** journals have been rolled back. ** ** This function reads the contents of the master-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 master journal ** file zMaster ** ** 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 zMaster 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 master journal file. This could be ** a couple of kilobytes or so - potentially larger than the page ** size. */ static int pager_delmaster(Pager *pPager, const char *zMaster){ sqlite3_vfs *pVfs = pPager->pVfs; int rc; /* Return code */ sqlite3_file *pMaster; /* Malloc'd master-journal file descriptor */ sqlite3_file *pJournal; /* Malloc'd child-journal file descriptor */ char *zMasterJournal = 0; /* Contents of master journal file */ i64 nMasterJournal; /* Size of master journal file */ char *zJournal; /* Pointer to one journal within MJ file */ char *zMasterPtr; /* Space to hold MJ filename from a journal file */ int nMasterPtr; /* Amount of space allocated to zMasterPtr[] */ /* Allocate space for both the pJournal and pMaster file descriptors. ** If successful, open the master journal file for reading. */ pMaster = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2); pJournal = (sqlite3_file *)(((u8 *)pMaster) + pVfs->szOsFile); if( !pMaster ){ rc = SQLITE_NOMEM_BKPT; }else{ const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL); rc = sqlite3OsOpen(pVfs, zMaster, pMaster, flags, 0); } if( rc!=SQLITE_OK ) goto delmaster_out; /* Load the entire master journal file into space obtained from ** sqlite3_malloc() and pointed to by zMasterJournal. Also obtain ** sufficient space (in zMasterPtr) to hold the names of master ** journal files extracted from regular rollback-journals. */ rc = sqlite3OsFileSize(pMaster, &nMasterJournal); if( rc!=SQLITE_OK ) goto delmaster_out; nMasterPtr = pVfs->mxPathname+1; zMasterJournal = sqlite3Malloc(nMasterJournal + nMasterPtr + 1); if( !zMasterJournal ){ rc = SQLITE_NOMEM_BKPT; goto delmaster_out; } zMasterPtr = &zMasterJournal[nMasterJournal+1]; rc = sqlite3OsRead(pMaster, zMasterJournal, (int)nMasterJournal, 0); if( rc!=SQLITE_OK ) goto delmaster_out; zMasterJournal[nMasterJournal] = 0; zJournal = zMasterJournal; while( (zJournal-zMasterJournal)<nMasterJournal ){ int exists; rc = sqlite3OsAccess(pVfs, zJournal, SQLITE_ACCESS_EXISTS, &exists); if( rc!=SQLITE_OK ){ goto delmaster_out; } if( exists ){ /* One of the journals pointed to by the master journal exists. ** Open it and check if it points at the master journal. If ** so, return without deleting the master journal file. */ int c; int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL); rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0); if( rc!=SQLITE_OK ){ goto delmaster_out; } rc = readMasterJournal(pJournal, zMasterPtr, nMasterPtr); sqlite3OsClose(pJournal); if( rc!=SQLITE_OK ){ goto delmaster_out; } c = zMasterPtr[0]!=0 && strcmp(zMasterPtr, zMaster)==0; if( c ){ /* We have a match. Do not delete the master journal file. */ goto delmaster_out; } } zJournal += (sqlite3Strlen30(zJournal)+1); } sqlite3OsClose(pMaster); rc = sqlite3OsDelete(pVfs, zMaster, 0); delmaster_out: sqlite3_free(zMasterJournal); if( pMaster ){ sqlite3OsClose(pMaster); assert( !isOpen(pJournal) ); sqlite3_free(pMaster); } return rc; } /* ** This function is used to change the actual size of the database |
︙ | ︙ | |||
2619 2620 2621 2622 2623 2624 2625 | if( currentSize>newSize ){ rc = sqlite3OsTruncate(pPager->fd, newSize); }else if( (currentSize+szPage)<=newSize ){ char *pTmp = pPager->pTmpSpace; memset(pTmp, 0, szPage); testcase( (newSize-szPage) == currentSize ); testcase( (newSize-szPage) > currentSize ); | < | 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 | if( currentSize>newSize ){ rc = sqlite3OsTruncate(pPager->fd, newSize); }else if( (currentSize+szPage)<=newSize ){ char *pTmp = pPager->pTmpSpace; memset(pTmp, 0, szPage); testcase( (newSize-szPage) == currentSize ); testcase( (newSize-szPage) > currentSize ); rc = sqlite3OsWrite(pPager->fd, pTmp, szPage, newSize-szPage); } if( rc==SQLITE_OK ){ pPager->dbFileSize = nPage; } } } |
︙ | ︙ | |||
2650 2651 2652 2653 2654 2655 2656 | } /* ** 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 | | | 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 | } /* ** 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 ** master 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. |
︙ | ︙ | |||
2749 2750 2751 2752 2753 2754 2755 | 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() */ | | | | | | | | | | 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 | 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 *zMaster = 0; /* Name of master journal file if any */ int needPagerReset; /* True to reset page prior to first page rollback */ int nPlayback = 0; /* Total number of pages restored from journal */ 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 master journal name from the journal, if it is present. ** If a master 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. */ zMaster = pPager->pTmpSpace; rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1); if( rc==SQLITE_OK && zMaster[0] ){ rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res); } zMaster = 0; if( rc!=SQLITE_OK || !res ){ goto end_playback; } pPager->journalOff = 0; needPagerReset = isHot; /* This loop terminates either when a readJournalHdr() or |
︙ | ︙ | |||
2842 2843 2844 2845 2846 2847 2848 | */ if( pPager->journalOff==JOURNAL_HDR_SZ(pPager) ){ rc = pager_truncate(pPager, mxPg); if( rc!=SQLITE_OK ){ goto end_playback; } pPager->dbSize = mxPg; | < < < | 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 | */ if( pPager->journalOff==JOURNAL_HDR_SZ(pPager) ){ rc = pager_truncate(pPager, mxPg); if( rc!=SQLITE_OK ){ goto end_playback; } pPager->dbSize = mxPg; } /* Copy original pages out of the journal and back into the ** database file and/or page cache. */ for(u=0; u<nRec; u++){ if( needPagerReset ){ |
︙ | ︙ | |||
2909 2910 2911 2912 2913 2914 2915 | ** 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 ){ | < < < < | | | | | | < < | | 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 | ** 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 ){ zMaster = pPager->pTmpSpace; rc = readMasterJournal(pPager->jfd, zMaster, 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, zMaster[0]!='\0', 0); testcase( rc!=SQLITE_OK ); } if( rc==SQLITE_OK && zMaster[0] && res ){ /* If there was a master journal and this routine will return success, ** see if it is possible to delete the master journal. */ rc = pager_delmaster(pPager, zMaster); testcase( rc!=SQLITE_OK ); } if( isHot && nPlayback ){ sqlite3_log(SQLITE_NOTICE_RECOVER_ROLLBACK, "recovered %d pages from %s", nPlayback, pPager->zJournal); } |
︙ | ︙ | |||
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 | */ 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; | > > < | 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 | */ memset(pPager->dbFileVers, 0xff, sizeof(pPager->dbFileVers)); }else{ u8 *dbFileVers = &((u8*)pPg->pData)[24]; memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers)); } } CODEC1(pPager, pPg->pData, pPg->pgno, 3, rc = SQLITE_NOMEM_BKPT); 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; /* 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 |
︙ | ︙ | |||
3312 3313 3314 3315 3316 3317 3318 | } 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 master 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: ** |
︙ | ︙ | |||
3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 | ** and SQLITE_SYNC_NORMAL on platforms other than MacOSX. But the ** synchronous=FULL versus synchronous=NORMAL setting determines when ** the xSync primitive is called and is relevant to all platforms. ** ** Numeric values associated with these states are OFF==1, NORMAL=2, ** and FULL=3. */ void sqlite3PagerSetFlags( Pager *pPager, /* The pager to set safety level for */ unsigned pgFlags /* Various flags */ ){ unsigned level = pgFlags & PAGER_SYNCHRONOUS_MASK; if( pPager->tempFile ){ pPager->noSync = 1; | > | 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 | ** and SQLITE_SYNC_NORMAL on platforms other than MacOSX. But the ** synchronous=FULL versus synchronous=NORMAL setting determines when ** the xSync primitive is called and is relevant to all platforms. ** ** Numeric values associated with these states are OFF==1, NORMAL=2, ** and FULL=3. */ #ifndef SQLITE_OMIT_PAGER_PRAGMAS void sqlite3PagerSetFlags( Pager *pPager, /* The pager to set safety level for */ unsigned pgFlags /* Various flags */ ){ unsigned level = pgFlags & PAGER_SYNCHRONOUS_MASK; if( pPager->tempFile ){ pPager->noSync = 1; |
︙ | ︙ | |||
3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 | } if( pgFlags & PAGER_CACHESPILL ){ pPager->doNotSpill &= ~SPILLFLAG_OFF; }else{ pPager->doNotSpill |= SPILLFLAG_OFF; } } /* ** The following global variable is incremented whenever the library ** attempts to open a temporary file. This information is used for ** testing and analysis only. */ #ifdef SQLITE_TEST | > | 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 | } if( pgFlags & PAGER_CACHESPILL ){ pPager->doNotSpill &= ~SPILLFLAG_OFF; }else{ pPager->doNotSpill |= SPILLFLAG_OFF; } } #endif /* ** The following global variable is incremented whenever the library ** attempts to open a temporary file. This information is used for ** testing and analysis only. */ #ifdef SQLITE_TEST |
︙ | ︙ | |||
3739 3740 3741 3742 3743 3744 3745 | rc = sqlite3PcacheSetPageSize(pPager->pPCache, pageSize); } if( rc==SQLITE_OK ){ sqlite3PageFree(pPager->pTmpSpace); pPager->pTmpSpace = pNew; pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize); pPager->pageSize = pageSize; | < > | 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 | rc = sqlite3PcacheSetPageSize(pPager->pPCache, pageSize); } if( rc==SQLITE_OK ){ sqlite3PageFree(pPager->pTmpSpace); pPager->pTmpSpace = pNew; pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize); pPager->pageSize = pageSize; }else{ sqlite3PageFree(pNew); } } *pPageSize = pPager->pageSize; if( rc==SQLITE_OK ){ if( nReserve<0 ) nReserve = pPager->nReserve; assert( nReserve>=0 && nReserve<1000 ); pPager->nReserve = (i16)nReserve; pagerReportSize(pPager); pagerFixMaplimit(pPager); } return rc; } /* ** Return a pointer to the "temporary page" buffer held internally |
︙ | ︙ | |||
3774 3775 3776 3777 3778 3779 3780 | /* ** 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. */ | | | 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 | /* ** 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. */ int sqlite3PagerMaxPageCount(Pager *pPager, int 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 |
︙ | ︙ | |||
3900 3901 3902 3903 3904 3905 3906 | ** Function assertTruncateConstraint(pPager) checks that one of the ** following is true for all dirty pages currently in the page-cache: ** ** a) The page number is less than or equal to the size of the ** current database image, in pages, OR ** ** b) if the page content were written at this time, it would not | | > < < | < < < < < < | | 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 | ** Function assertTruncateConstraint(pPager) checks that one of the ** following is true for all dirty pages currently in the page-cache: ** ** a) The page number is less than or equal to the size of the ** current database image, in pages, OR ** ** b) if the page content were written at this time, it would not ** be necessary to write the current content out to the sub-journal ** (as determined by function subjRequiresPage()). ** ** If the condition asserted by this function were not true, and the ** dirty page were to be discarded from the cache via the pagerStress() ** routine, pagerStress() would not write the current page content to ** the database file. If a savepoint transaction were rolled back after ** this happened, the correct behavior would be to restore the current ** content of the page. However, since this content is not present in either ** the database file or the portion of the rollback journal and ** sub-journal rolled back the content could not be restored and the ** database image would become corrupt. It is therefore fortunate that ** this circumstance cannot arise. */ #if defined(SQLITE_DEBUG) static void assertTruncateConstraintCb(PgHdr *pPg){ assert( pPg->flags&PGHDR_DIRTY ); assert( !subjRequiresPage(pPg) || pPg->pgno<=pPg->pPager->dbSize ); } static void assertTruncateConstraint(Pager *pPager){ sqlite3PcacheIterateDirty(pPager->pPCache, assertTruncateConstraintCb); } #else # define assertTruncateConstraint(pPager) #endif /* ** Truncate the in-memory database file image to nPage pages. This ** function does not actually modify the database file on disk. It ** just sets the internal state of the pager object so that the ** truncation will be done when the current transaction is committed. ** ** 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 ); 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 |
︙ | ︙ | |||
4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 | 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; } | > > > > > | 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 | 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); #ifdef SQLITE_HAS_CODEC if( pPager->xCodecFree ) pPager->xCodecFree(pPager->pCodec); #endif assert( !pPager->aSavepoint && !pPager->pInJournal ); assert( !isOpen(pPager->jfd) && !isOpen(pPager->sjfd) ); sqlite3_free(pPager); return SQLITE_OK; } |
︙ | ︙ | |||
4402 4403 4404 4405 4406 4407 4408 | 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); | > | | 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 | 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); /* Encode the database */ CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM_BKPT, 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. |
︙ | ︙ | |||
4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 | /* 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); } } | > > > > > > | 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 | /* 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; #if SQLITE_HAS_CODEC if( !pPager->subjInMemory ){ CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2); }else #endif 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); } } |
︙ | ︙ | |||
4673 4674 4675 4676 4677 4678 4679 | 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 */ | | | | 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 | 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 */ #ifdef SQLITE_ENABLE_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 nUri = 0; /* Number of bytes of URI args at *zUri */ /* 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; |
︙ | ︙ | |||
4720 4721 4722 4723 4724 4725 4726 | 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); | < < < < < < < < < | | | | | 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 | 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 ){ z += sqlite3Strlen30(z)+1; z += sqlite3Strlen30(z)+1; } nUri = (int)(&z[1] - zUri); assert( nUri>=0 ); 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. */ |
︙ | ︙ | |||
4761 4762 4763 4764 4765 4766 4767 | ** 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) | < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | < < | < | | < > | | < | | > < | < < | < < < < < < < < < < | | | < < | | < < | < | < < | | | < | < < < > < < < < | | | 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 | ** 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) ** Journal file name (nPathname+8+1 bytes) */ 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 */ nPathname + 1 + nUri + /* zFilename */ nPathname + 8 + 2 /* zJournal */ #ifndef SQLITE_OMIT_WAL + nPathname + 4 + 2 /* zWal */ #endif ); assert( EIGHT_BYTE_ALIGNMENT(SQLITE_INT_TO_PTR(journalFileSize)) ); if( !pPtr ){ sqlite3DbFree(0, zPathname); return SQLITE_NOMEM_BKPT; } pPager = (Pager*)(pPtr); pPager->pPCache = (PCache*)(pPtr += ROUND8(sizeof(*pPager))); pPager->fd = (sqlite3_file*)(pPtr += ROUND8(pcacheSize)); pPager->sjfd = (sqlite3_file*)(pPtr += ROUND8(pVfs->szOsFile)); pPager->jfd = (sqlite3_file*)(pPtr += journalFileSize); pPager->zFilename = (char*)(pPtr += journalFileSize); assert( EIGHT_BYTE_ALIGNMENT(pPager->jfd) ); /* Fill in the Pager.zFilename and Pager.zJournal buffers, if required. */ if( zPathname ){ assert( nPathname>0 ); pPager->zJournal = (char*)(pPtr += nPathname + 1 + nUri); memcpy(pPager->zFilename, zPathname, nPathname); if( nUri ) memcpy(&pPager->zFilename[nPathname+1], zUri, nUri); memcpy(pPager->zJournal, zPathname, nPathname); memcpy(&pPager->zJournal[nPathname], "-journal\000", 8+2); sqlite3FileSuffix3(pPager->zFilename, pPager->zJournal); #ifndef SQLITE_OMIT_WAL pPager->zWal = &pPager->zJournal[nPathname+8+1]; memcpy(pPager->zWal, zPathname, nPathname); memcpy(&pPager->zWal[nPathname], "-wal\000", 4+1); sqlite3FileSuffix3(pPager->zFilename, pPager->zWal); #endif 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 ); #ifdef SQLITE_ENABLE_DESERIALIZE 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: ** |
︙ | ︙ | |||
4915 4916 4917 4918 4919 4920 4921 | if( iDc&(SQLITE_IOCAP_ATOMIC|(ii>>8)) ){ szPageDflt = ii; } } } #endif } | | | | 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 | if( iDc&(SQLITE_IOCAP_ATOMIC|(ii>>8)) ){ szPageDflt = ii; } } } #endif } pPager->noLock = sqlite3_uri_boolean(zFilename, "nolock", 0); if( (iDc & SQLITE_IOCAP_IMMUTABLE)!=0 || sqlite3_uri_boolean(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 |
︙ | ︙ | |||
4989 4990 4991 4992 4993 4994 4995 | || tempFile==PAGER_LOCKINGMODE_EXCLUSIVE ); assert( PAGER_LOCKINGMODE_EXCLUSIVE==1 ); pPager->exclusiveMode = (u8)tempFile; pPager->changeCountDone = pPager->tempFile; pPager->memDb = (u8)memDb; pPager->readOnly = (u8)readOnly; assert( useJournal || pPager->tempFile ); | > | > > > > > > > > > > | 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 | || tempFile==PAGER_LOCKINGMODE_EXCLUSIVE ); assert( PAGER_LOCKINGMODE_EXCLUSIVE==1 ); pPager->exclusiveMode = (u8)tempFile; pPager->changeCountDone = pPager->tempFile; pPager->memDb = (u8)memDb; pPager->readOnly = (u8)readOnly; assert( useJournal || pPager->tempFile ); pPager->noSync = pPager->tempFile; if( pPager->noSync ){ assert( pPager->fullSync==0 ); assert( pPager->extraSync==0 ); assert( pPager->syncFlags==0 ); assert( pPager->walSyncFlags==0 ); }else{ pPager->fullSync = 1; pPager->extraSync = 0; pPager->syncFlags = SQLITE_SYNC_NORMAL; pPager->walSyncFlags = SQLITE_SYNC_NORMAL | (SQLITE_SYNC_NORMAL<<2); } /* pPager->pFirst = 0; */ /* pPager->pFirstSynced = 0; */ /* pPager->pLast = 0; */ pPager->nExtra = (u16)nExtra; pPager->journalSizeLimit = SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT; assert( isOpen(pPager->fd) || tempFile ); setSectorSize(pPager); |
︙ | ︙ | |||
5013 5014 5015 5016 5017 5018 5019 | /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */ /* pPager->szMmap = SQLITE_DEFAULT_MMAP_SIZE // will be set by btree.c */ *ppPager = pPager; return SQLITE_OK; } | < < < < < < < < < < < < < | | | 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 | /* 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. ** ** This routine does not check if there is a master journal filename ** at the end of the file. If there is, and that master 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 |
︙ | ︙ | |||
5251 5252 5253 5254 5255 5256 5257 | ** ** If the journal does not exist, it usually means that some ** other connection managed to get in and roll it back before ** this connection obtained the exclusive lock above. Or, it ** may mean that the pager was in the error-state when this ** function was called and the journal file does not exist. */ | | | 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 | ** ** If the journal does not exist, it usually means that some ** other connection managed to get in and roll it back before ** this connection obtained the exclusive lock above. Or, it ** may mean that the pager was in the error-state when this ** function was called and the journal file does not exist. */ if( !isOpen(pPager->jfd) ){ sqlite3_vfs * const pVfs = pPager->pVfs; int bExists; /* True if journal file exists */ rc = sqlite3OsAccess( pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &bExists); if( rc==SQLITE_OK && bExists ){ int fout = 0; int f = SQLITE_OPEN_READWRITE|SQLITE_OPEN_MAIN_JOURNAL; |
︙ | ︙ | |||
5496 5497 5498 5499 5500 5501 5502 | 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. */ | | | | | 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 | 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_MAX_PGNO && 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: ** ** (1) The maximum page number is 2^31 ** (2) Never try to fetch the locking page */ if( pgno>PAGER_MAX_PGNO || pgno==PAGER_MJ_PGNO(pPager) ){ rc = SQLITE_CORRUPT_BKPT; goto pager_acquire_err; } pPg->pPager = pPager; assert( !isOpen(pPager->fd) || !MEMDB ); |
︙ | ︙ | |||
5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 | ** 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; | > > > | 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 | ** 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) ); #ifdef SQLITE_HAS_CODEC assert( pPager->xCodec==0 ); #endif /* 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; |
︙ | ︙ | |||
5653 5654 5655 5656 5657 5658 5659 | */ int sqlite3PagerGet( Pager *pPager, /* The pager open on the database file */ Pgno pgno, /* Page number to fetch */ DbPage **ppPage, /* Write a pointer to the page here */ int flags /* PAGER_GET_XXX flags */ ){ | < | 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 | */ int sqlite3PagerGet( Pager *pPager, /* The pager open on the database file */ Pgno pgno, /* Page number to fetch */ DbPage **ppPage, /* Write a pointer to the page here */ int flags /* PAGER_GET_XXX flags */ ){ return pPager->xGet(pPager, pgno, ppPage, flags); } /* ** Acquire a page if it is already in the in-memory cache. Do ** not read the page from disk. Return a pointer to the page, ** or 0 if the page is not in cache. |
︙ | ︙ | |||
5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 | } 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 | > | 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 | } 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; sqlite3PagerResetLockTimeout(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 |
︙ | ︙ | |||
5767 5768 5769 5770 5771 5772 5773 | sqlite3MemJournalOpen(pPager->jfd); }else{ int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE; int nSpill; if( pPager->tempFile ){ flags |= (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL); | < | 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 | sqlite3MemJournalOpen(pPager->jfd); }else{ int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE; int nSpill; if( pPager->tempFile ){ flags |= (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL); nSpill = sqlite3Config.nStmtSpill; }else{ flags |= SQLITE_OPEN_MAIN_JOURNAL; nSpill = jrnlBufferSize(pPager); } /* Verify that the database still has the same name as it did when |
︙ | ︙ | |||
5794 5795 5796 5797 5798 5799 5800 | /* 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; | | < | 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 | /* 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->setMaster = 0; pPager->journalHdr = 0; rc = writeJournalHdr(pPager); } } if( rc!=SQLITE_OK ){ sqlite3BitvecDestroy(pPager->pInJournal); pPager->pInJournal = 0; }else{ assert( pPager->eState==PAGER_WRITER_LOCKED ); pPager->eState = PAGER_WRITER_CACHEMOD; } return rc; } |
︙ | ︙ | |||
5836 5837 5838 5839 5840 5841 5842 | 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; | | | 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 | 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( ALWAYS(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) ){ |
︙ | ︙ | |||
5908 5909 5910 5911 5912 5913 5914 | u32 cksum; char *pData2; i64 iOff = pPager->journalOff; /* We should never write to the journal file the page that ** contains the database locks. The following assert verifies ** that we do not. */ | | | | 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 | u32 cksum; char *pData2; i64 iOff = pPager->journalOff; /* 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 ); CODEC2(pPager, pPg->pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2); 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, |
︙ | ︙ | |||
6087 6088 6089 6090 6091 6092 6093 | assert(pg1<=pPg->pgno); assert((pg1+nPage)>pPg->pgno); for(ii=0; ii<nPage && rc==SQLITE_OK; ii++){ Pgno pg = pg1+ii; PgHdr *pPage; if( pg==pPg->pgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){ | | | 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 | assert(pg1<=pPg->pgno); assert((pg1+nPage)>pPg->pgno); for(ii=0; ii<nPage && rc==SQLITE_OK; ii++){ Pgno pg = pg1+ii; PgHdr *pPage; if( pg==pPg->pgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){ if( pg!=PAGER_MJ_PGNO(pPager) ){ rc = sqlite3PagerGet(pPager, pg, &pPage, 0); if( rc==SQLITE_OK ){ rc = pager_write(pPage); if( pPage->flags&PGHDR_NEED_SYNC ){ needSync = 1; } sqlite3PagerUnrefNotNull(pPage); |
︙ | ︙ | |||
6250 6251 6252 6253 6254 6255 6256 | # define DIRECT_MODE 0 assert( isDirectMode==0 ); UNUSED_PARAMETER(isDirectMode); #else # define DIRECT_MODE isDirectMode #endif | | | 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 | # define DIRECT_MODE 0 assert( isDirectMode==0 ); UNUSED_PARAMETER(isDirectMode); #else # define DIRECT_MODE isDirectMode #endif if( !pPager->changeCountDone && ALWAYS(pPager->dbSize>0) ){ PgHdr *pPgHdr; /* Reference to page 1 */ assert( !pPager->tempFile && isOpen(pPager->fd) ); /* Open page 1 of the file for writing. */ rc = sqlite3PagerGet(pPager, 1, &pPgHdr, 0); assert( pPgHdr==0 || rc==SQLITE_OK ); |
︙ | ︙ | |||
6276 6277 6278 6279 6280 6281 6282 | /* 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 ); | | | 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 | /* 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 ); CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM_BKPT, zBuf); if( rc==SQLITE_OK ){ rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0); pPager->aStat[PAGER_STAT_WRITE]++; } if( rc==SQLITE_OK ){ /* Update the pager's copy of the change-counter. Otherwise, the ** next time a read transaction is opened the cache will be |
︙ | ︙ | |||
6307 6308 6309 6310 6311 6312 6313 | /* ** 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. */ | | | | 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 | /* ** 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 *zMaster){ int rc = SQLITE_OK; void *pArg = (void*)zMaster; 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; |
︙ | ︙ | |||
6347 6348 6349 6350 6351 6352 6353 | rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); } } return rc; } /* | | | | | | | | | | | 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 | rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); } } return rc; } /* ** Sync the database file for the pager pPager. zMaster points to the name ** of a master journal file that should be written into the individual ** journal file. zMaster may be NULL, which is interpreted as no master ** 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 master journal file if specified). ** ** Note that if zMaster==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 *zMaster, /* If not NULL, the master 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 zMaster=%s nSize=%d\n", pPager->zFilename, zMaster, 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) ){ |
︙ | ︙ | |||
6432 6433 6434 6435 6436 6437 6438 | }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; | | | 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 | }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 = zMaster==0 /* An SQLITE_IOCAP_BATCH_ATOMIC commit */ && (sqlite3OsDeviceCharacteristics(fd) & SQLITE_IOCAP_BATCH_ATOMIC) && !pPager->noSync && sqlite3JournalIsInMemory(pPager->jfd); #else # define bBatch 0 #endif |
︙ | ︙ | |||
6470 6471 6472 6473 6474 6475 6476 | */ if( bBatch==0 ){ PgHdr *pPg; assert( isOpen(pPager->jfd) || pPager->journalMode==PAGER_JOURNALMODE_OFF || pPager->journalMode==PAGER_JOURNALMODE_WAL ); | | | | | | | | 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 | */ if( bBatch==0 ){ PgHdr *pPg; assert( isOpen(pPager->jfd) || pPager->journalMode==PAGER_JOURNALMODE_OFF || pPager->journalMode==PAGER_JOURNALMODE_WAL ); if( !zMaster && 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( zMaster ){ 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 master journal name into the journal file. If a master ** journal file name has already been written to the journal file, ** or if zMaster is NULL (no master journal), then this call is a no-op. */ rc = writeMasterJournal(pPager, zMaster); 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 |
︙ | ︙ | |||
6565 6566 6567 6568 6569 6570 6571 | /* If the file on disk is smaller than the database image, use ** pager_truncate to grow the file here. This can happen if the database ** image was extended as part of the current transaction and then the ** last page in the db image moved to the free-list. In this case the ** last page is never written out to disk, leaving the database file ** undersized. Fix this now if it is the case. */ if( pPager->dbSize>pPager->dbFileSize ){ | | | | 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 | /* If the file on disk is smaller than the database image, use ** pager_truncate to grow the file here. This can happen if the database ** image was extended as part of the current transaction and then the ** last page in the db image moved to the free-list. In this case the ** last page is never written out to disk, leaving the database file ** undersized. Fix this now if it is the case. */ if( pPager->dbSize>pPager->dbFileSize ){ Pgno nNew = pPager->dbSize - (pPager->dbSize==PAGER_MJ_PGNO(pPager)); 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, zMaster); } IOTRACE(("DBSYNC %p\n", pPager)) } } commit_phase_one_exit: if( rc==SQLITE_OK && !pagerUseWal(pPager) ){ |
︙ | ︙ | |||
6609 6610 6611 6612 6613 6614 6615 | 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; | < | 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 | 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) ); |
︙ | ︙ | |||
6638 6639 6640 6641 6642 6643 6644 | ){ assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) || !pPager->journalOff ); pPager->eState = PAGER_READER; return SQLITE_OK; } PAGERTRACE(("COMMIT %d\n", PAGERID(pPager))); | > | | 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 | ){ assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) || !pPager->journalOff ); pPager->eState = PAGER_READER; return SQLITE_OK; } PAGERTRACE(("COMMIT %d\n", PAGERID(pPager))); pPager->iDataVersion++; rc = pager_end_transaction(pPager, pPager->setMaster, 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 |
︙ | ︙ | |||
6683 6684 6685 6686 6687 6688 6689 | 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); | | | 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 | 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->setMaster, 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. |
︙ | ︙ | |||
6736 6737 6738 6739 6740 6741 6742 | #endif /* ** Return the approximate number of bytes of memory currently ** used by the pager and its associated cache. */ int sqlite3PagerMemUsed(Pager *pPager){ | | | | 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 | #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 + sizeof(PgHdr) + 5*sizeof(void*); return perPageSize*sqlite3PcachePagecount(pPager->pPCache) + sqlite3MallocSize(pPager) + pPager->pageSize; } /* ** Return the number of references to the specified page. |
︙ | ︙ | |||
6806 6807 6808 6809 6810 6811 6812 | } } /* ** Return true if this is an in-memory or temp-file backed pager. */ int sqlite3PagerIsMemdb(Pager *pPager){ | | | 6804 6805 6806 6807 6808 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818 | } } /* ** Return true if this is an in-memory or temp-file backed pager. */ int sqlite3PagerIsMemdb(Pager *pPager){ return pPager->tempFile; } /* ** 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. |
︙ | ︙ | |||
6852 6853 6854 6855 6856 6857 6858 | 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); | < | 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 | 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; |
︙ | ︙ | |||
6931 6932 6933 6934 6935 6936 6937 | */ nNew = iSavepoint + (( op==SAVEPOINT_RELEASE ) ? 0 : 1); for(ii=nNew; ii<pPager->nSavepoint; ii++){ sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint); } pPager->nSavepoint = nNew; | > | < < | < | | | 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 | */ nNew = iSavepoint + (( op==SAVEPOINT_RELEASE ) ? 0 : 1); for(ii=nNew; ii<pPager->nSavepoint; ii++){ sqlite3BitvecDestroy(pPager->aSavepoint[ii].pInSavepoint); } pPager->nSavepoint = nNew; /* If this is a release of the outermost savepoint, truncate ** the sub-journal to zero bytes in size. */ if( op==SAVEPOINT_RELEASE ){ if( nNew==0 && isOpen(pPager->sjfd) ){ /* Only truncate if it is an in-memory sub-journal. */ if( sqlite3JournalIsInMemory(pPager->sjfd) ){ rc = sqlite3OsTruncate(pPager->sjfd, 0); assert( rc==SQLITE_OK ); } pPager->nSubRec = 0; } } /* 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. */ |
︙ | ︙ | |||
6984 6985 6986 6987 6988 6989 6990 | ** ** 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. | < < < | < < < < | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ** ** 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. */ const char *sqlite3PagerFilename(Pager *pPager, int nullIfMemDb){ return (nullIfMemDb && pPager->memDb) ? "" : 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; } #ifdef SQLITE_ENABLE_SETLK_TIMEOUT /* ** Reset the lock timeout for pager. */ void sqlite3PagerResetLockTimeout(Pager *pPager){ int x = 0; sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_LOCK_TIMEOUT, &x); } #endif /* ** 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; } #ifdef SQLITE_HAS_CODEC /* ** Set or retrieve the codec for this pager */ void sqlite3PagerSetCodec( Pager *pPager, void *(*xCodec)(void*,void*,Pgno,int), void (*xCodecSizeChng)(void*,int,int), void (*xCodecFree)(void*), void *pCodec ){ if( pPager->xCodecFree ){ pPager->xCodecFree(pPager->pCodec); }else{ pager_reset(pPager); } pPager->xCodec = pPager->memDb ? 0 : xCodec; pPager->xCodecSizeChng = xCodecSizeChng; pPager->xCodecFree = xCodecFree; pPager->pCodec = pCodec; setGetterMethod(pPager); pagerReportSize(pPager); } void *sqlite3PagerGetCodec(Pager *pPager){ return pPager->pCodec; } /* ** This function is called by the wal module when writing page content ** into the log file. ** ** This function returns a pointer to a buffer containing the encrypted ** page content. If a malloc fails, this function may return NULL. */ void *sqlite3PagerCodec(PgHdr *pPg){ void *aData = 0; CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData); return aData; } /* ** Return the current pager state */ int sqlite3PagerState(Pager *pPager){ return pPager->eState; } #endif /* SQLITE_HAS_CODEC */ #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 |
︙ | ︙ | |||
7130 7131 7132 7133 7134 7135 7136 | ** 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 ){ | | | 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 | ** 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( 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. */ |
︙ | ︙ | |||
7265 7266 7267 7268 7269 7270 7271 | ** ** The returned indicate the current (possibly updated) journal-mode. */ int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){ u8 eOld = pPager->journalMode; /* Prior journalmode */ /* The eMode parameter is always valid */ | | | | | | | | 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329 | ** ** The returned indicate the current (possibly updated) journal-mode. */ int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){ u8 eOld = pPager->journalMode; /* Prior journalmode */ /* The eMode parameter is always valid */ assert( eMode==PAGER_JOURNALMODE_DELETE || eMode==PAGER_JOURNALMODE_TRUNCATE || eMode==PAGER_JOURNALMODE_PERSIST || eMode==PAGER_JOURNALMODE_OFF || eMode==PAGER_JOURNALMODE_WAL || eMode==PAGER_JOURNALMODE_MEMORY ); /* This routine is only called from the OP_JournalMode opcode, and ** the logic there will never allow a temporary file to be changed ** to WAL mode. */ assert( pPager->tempFile==0 || eMode!=PAGER_JOURNALMODE_WAL ); |
︙ | ︙ | |||
7307 7308 7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 | assert( (PAGER_JOURNALMODE_DELETE & 5)==0 ); assert( (PAGER_JOURNALMODE_MEMORY & 5)==4 ); assert( (PAGER_JOURNALMODE_OFF & 5)==0 ); assert( (PAGER_JOURNALMODE_WAL & 5)==5 ); assert( isOpen(pPager->fd) || pPager->exclusiveMode ); if( !pPager->exclusiveMode && (eOld & 5)==1 && (eMode & 1)==0 ){ /* In this case we would like to delete the journal file. If it is ** not possible, then that is not a problem. Deleting the journal file ** here is an optimization only. ** ** Before deleting the journal file, obtain a RESERVED lock on the ** database file. This ensures that the journal file is not deleted ** while it is in use by some other client. | > | 7352 7353 7354 7355 7356 7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 | assert( (PAGER_JOURNALMODE_DELETE & 5)==0 ); assert( (PAGER_JOURNALMODE_MEMORY & 5)==4 ); assert( (PAGER_JOURNALMODE_OFF & 5)==0 ); assert( (PAGER_JOURNALMODE_WAL & 5)==5 ); assert( isOpen(pPager->fd) || pPager->exclusiveMode ); if( !pPager->exclusiveMode && (eOld & 5)==1 && (eMode & 1)==0 ){ /* In this case we would like to delete the journal file. If it is ** not possible, then that is not a problem. Deleting the journal file ** here is an optimization only. ** ** Before deleting the journal file, obtain a RESERVED lock on the ** database file. This ensures that the journal file is not deleted ** while it is in use by some other client. |
︙ | ︙ | |||
7418 7419 7420 7421 7422 7423 7424 | Pager *pPager, /* Checkpoint on this pager */ sqlite3 *db, /* Db handle used to check for interrupts */ int eMode, /* Type of checkpoint */ int *pnLog, /* OUT: Final number of frames in log */ int *pnCkpt /* OUT: Final number of checkpointed frames */ ){ int rc = SQLITE_OK; | < < < < < < < < < < < < > | 7464 7465 7466 7467 7468 7469 7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484 7485 | Pager *pPager, /* Checkpoint on this pager */ sqlite3 *db, /* Db handle used to check for interrupts */ int eMode, /* Type of checkpoint */ int *pnLog, /* OUT: Final number of frames in log */ int *pnCkpt /* OUT: Final number of checkpointed frames */ ){ int rc = SQLITE_OK; 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 ); sqlite3PagerResetLockTimeout(pPager); } return rc; } int sqlite3PagerWalCallback(Pager *pPager){ return sqlite3WalCallback(pPager->pWal); } |
︙ | ︙ | |||
7601 7602 7603 7604 7605 7606 7607 | pagerFixMaplimit(pPager); if( rc && !pPager->exclusiveMode ) pagerUnlockDb(pPager, SHARED_LOCK); } } return rc; } | < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | 7636 7637 7638 7639 7640 7641 7642 7643 7644 7645 7646 7647 7648 7649 7650 7651 7652 7653 7654 7655 7656 7657 7658 7659 7660 7661 7662 7663 7664 7665 7666 7667 7668 | 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. */ int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot){ int rc = SQLITE_OK; if( pPager->pWal ){ sqlite3WalSnapshotOpen(pPager->pWal, pSnapshot); }else{ rc = SQLITE_ERROR; } return rc; |
︙ | ︙ |
Changes to src/pager.h.
︙ | ︙ | |||
39 40 41 42 43 44 45 | /* ** Handle type for pages. */ typedef struct PgHdr DbPage; /* | | | | | < | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | /* ** Handle type for pages. */ 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 master journal name - there are no more pages to ** roll back. See comments for function writeMasterJournal() in pager.c ** for details. */ #define PAGER_MJ_PGNO(x) ((Pgno)((PENDING_BYTE/((x)->pageSize))+1)) /* ** Allowed values for the flags parameter to sqlite3PagerOpen(). ** ** NOTE: These values must match the corresponding BTREE_ values in btree.h. */ #define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */ |
︙ | ︙ | |||
125 126 127 128 129 130 131 | ); 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 139 140 141 | ); 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); #ifdef SQLITE_HAS_CODEC void sqlite3PagerAlignReserve(Pager*,Pager*); #endif int sqlite3PagerMaxPageCount(Pager*, int); 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); |
︙ | ︙ | |||
158 159 160 161 162 163 164 | 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); | | | | | < < < < < < < < | > > > > > > > > > | 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 | 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 *zMaster, int); int sqlite3PagerExclusiveLock(Pager*); int sqlite3PagerSync(Pager *pPager, const char *zMaster); 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 *pPager, sqlite3_snapshot **ppSnapshot); int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot); int sqlite3PagerSnapshotRecover(Pager *pPager); int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot); void sqlite3PagerSnapshotUnlock(Pager *pPager); # endif #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(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 *); #ifdef SQLITE_ENABLE_SETLK_TIMEOUT void sqlite3PagerResetLockTimeout(Pager *pPager); #else # define sqlite3PagerResetLockTimeout(X) #endif /* Functions used to truncate the database file. */ void sqlite3PagerTruncateImage(Pager*,Pgno); void sqlite3PagerRekey(DbPage*, Pgno, u16); #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL) void *sqlite3PagerCodec(DbPage *); #endif /* Functions to support testing and debugging. */ #if !defined(NDEBUG) || defined(SQLITE_TEST) Pgno sqlite3PagerPagenumber(DbPage*); int sqlite3PagerIswriteable(DbPage*); #endif #ifdef SQLITE_TEST |
︙ | ︙ |
Changes to src/parse.y.
|
| < | | | < < | < < | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | /* ** 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 contains SQLite's grammar for SQL. Process this file ** using the lemon parser generator to generate C code that runs ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. */ // 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. // |
︙ | ︙ | |||
108 109 110 111 112 113 114 | struct FrameBound { int eType; Expr *pExpr; }; /* ** Disable lookaside memory allocation for objects that might be ** shared across database connections. */ static void disableLookaside(Parse *pParse){ | < < < | < < < < < < < < < < < < < < < | < < < < | | 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 | 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++; pParse->db->lookaside.bDisable++; } } // 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. explain ::= EXPLAIN. { pParse->explain = 1; } explain ::= EXPLAIN QUERY PLAN. { pParse->explain = 2; } %endif SQLITE_OMIT_EXPLAIN cmdx ::= cmd. { sqlite3FinishCoding(pParse); } ///////////////////// Begin and end transactions. //////////////////////////// // |
︙ | ︙ | |||
189 190 191 192 193 194 195 | 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 | | | | < | < < | < < < < < < < < | | 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 | 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 = 1;} %endif SQLITE_OMIT_TEMPDB temp(A) ::= . {A = 0;} create_table_args ::= LP columnlist conslist_opt(X) RP(E) table_options(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_options {int} table_options(A) ::= . {A = 0;} table_options(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); } } 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. // |
︙ | ︙ | |||
246 247 248 249 250 251 252 | %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 | < < < < < | 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | %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 %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 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, |
︙ | ︙ | |||
282 283 284 285 286 287 288 | %right NOT. %left IS MATCH LIKE_KW BETWEEN IN ISNULL NOTNULL NE EQ. %left GT LE LT GE. %right ESCAPE. %left BITAND BITOR LSHIFT RSHIFT. %left PLUS MINUS. %left STAR SLASH REM. | | | 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | %right NOT. %left IS MATCH LIKE_KW BETWEEN IN ISNULL NOTNULL NE EQ. %left GT LE LT GE. %right ESCAPE. %left BITAND BITOR LSHIFT RSHIFT. %left PLUS MINUS. %left STAR SLASH REM. %left CONCAT. %left COLLATE. %right BITNOT. %nonassoc ON. // An IDENTIFIER can be a generic identifier, or one of several // keywords. Any non-standard keyword can also be an identifier. // |
︙ | ︙ | |||
341 342 343 344 345 346 347 | // post-processing, if needed. // %type scanpt {const char*} scanpt(A) ::= . { assert( yyLookahead!=YYNOCODE ); A = yyLookaheadToken.z; } | < < < < | | | | | | | | < < < < | 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 | // 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;} ccons ::= DEFAULT scanpt(A) term(X) scanpt(Z). {sqlite3AddDefaultValue(pParse,X,A,Z);} ccons ::= DEFAULT LP(A) expr(X) RP(Z). {sqlite3AddDefaultValue(pParse,X,A.z+1,Z.z);} ccons ::= DEFAULT PLUS(A) term(X) scanpt(Z). {sqlite3AddDefaultValue(pParse,X,A.z,Z);} ccons ::= DEFAULT MINUS(A) term(X) scanpt(Z). { Expr *p = sqlite3PExpr(pParse, TK_UMINUS, X, 0); sqlite3AddDefaultValue(pParse,p,A.z,Z); } ccons ::= DEFAULT scanpt 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 expr(X) RP. {sqlite3AddCheckConstraint(pParse,X);} 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);} // 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 |
︙ | ︙ | |||
434 435 436 437 438 439 440 | 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);} | | | | 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 | 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 expr(E) RP onconf. {sqlite3AddCheckConstraint(pParse,E);} 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;} |
︙ | ︙ | |||
483 484 485 486 487 488 489 | sqlite3DropTable(pParse, X, 1, E); } %endif SQLITE_OMIT_VIEW //////////////////////// The SELECT statement ///////////////////////////////// // cmd ::= select(X). { | | < | | < > < < < < < < < < < < | | | < > | | | | | | | | | > > > > > > > | > | < < < < | | 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 | sqlite3DropTable(pParse, X, 1, E); } %endif SQLITE_OMIT_VIEW //////////////////////// The SELECT statement ///////////////////////////////// // cmd ::= select(X). { SelectDest dest = {SRT_Output, 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){ if( p->pPrior ){ Select *pNext = 0, *pLoop; int mxSelect, cnt = 0; for(pLoop=p; pLoop; pNext=pLoop, pLoop=pLoop->pPrior, cnt++){ pLoop->pNext = pNext; pLoop->selFlags |= SF_Compound; } 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"); } } } } %ifndef SQLITE_OMIT_CTE select(A) ::= WITH wqlist(W) selectnowith(X). { Select *p = X; if( p ){ p->pWith = W; parserDoubleLinkSelect(pParse, p); }else{ sqlite3WithDelete(pParse->db, W); } A = p; } select(A) ::= WITH RECURSIVE wqlist(W) selectnowith(X). { Select *p = X; if( p ){ p->pWith = W; parserDoubleLinkSelect(pParse, p); }else{ sqlite3WithDelete(pParse->db, W); } A = p; } %endif /* SQLITE_OMIT_CTE */ select(A) ::= selectnowith(X). { Select *p = X; if( p ){ parserDoubleLinkSelect(pParse, p); } A = p; /*A-overwrites-X*/ } selectnowith(A) ::= oneselect(A). %ifndef SQLITE_OMIT_COMPOUND_SELECT selectnowith(A) ::= selectnowith(A) multiselect_op(Y) oneselect(Z). { Select *pRhs = Z; Select *pLhs = A; if( pRhs && pRhs->pPrior ){ SrcList *pFrom; Token x; x.n = 0; parserDoubleLinkSelect(pParse, pRhs); pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0,0); pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0); } if( pRhs ){ pRhs->op = (u8)Y; pRhs->pPrior = pLhs; if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue; pRhs->selFlags &= ~SF_MultiValue; |
︙ | ︙ | |||
655 656 657 658 659 660 661 | } selcollist(A) ::= sclp(A) scanpt STAR. { Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0); A = sqlite3ExprListAppend(pParse, A, p); } selcollist(A) ::= sclp(A) scanpt nm(X) DOT STAR. { Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0); | | | 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 | } selcollist(A) ::= sclp(A) scanpt STAR. { Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0); A = sqlite3ExprListAppend(pParse, A, p); } selcollist(A) ::= sclp(A) scanpt nm(X) DOT STAR. { Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0); Expr *pLeft = sqlite3ExprAlloc(pParse->db, TK_ID, &X, 1); Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight); A = sqlite3ExprListAppend(pParse,A, pDot); } // An option "AS <id>" phrase that can follow one of the expressions that // define the result set, or one of the tables in the FROM clause. // |
︙ | ︙ | |||
678 679 680 681 682 683 684 | %type stl_prefix {SrcList*} %destructor stl_prefix {sqlite3SrcListDelete(pParse->db, $$);} %type from {SrcList*} %destructor from {sqlite3SrcListDelete(pParse->db, $$);} // A complete FROM clause. // | | | | < < | | | > | | > | | > | | | | < < < | | | 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 | %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 = sqlite3DbMallocZero(pParse->db, sizeof(*A));} 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. // stl_prefix(A) ::= seltablist(A) joinop(Y). { if( ALWAYS(A && A->nSrc>0) ) A->a[A->nSrc-1].fg.jointype = (u8)Y; } stl_prefix(A) ::= . {A = 0;} seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) as(Z) indexed_opt(I) on_opt(N) using_opt(U). { A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,N,U); sqlite3SrcListIndexedBy(pParse, A, &I); } seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) LP exprlist(E) RP as(Z) on_opt(N) using_opt(U). { A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,N,U); sqlite3SrcListFuncArgs(pParse, A, E); } %ifndef SQLITE_OMIT_SUBQUERY seltablist(A) ::= stl_prefix(A) LP select(S) RP as(Z) on_opt(N) using_opt(U). { A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,S,N,U); } 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 ){ struct SrcList_item *pNew = &A->a[A->nSrc-1]; struct SrcList_item *pOld = F->a; pNew->zName = pOld->zName; pNew->zDatabase = pOld->zDatabase; pNew->pSelect = pOld->pSelect; if( pOld->fg.isTabFunc ){ pNew->u1.pFuncArg = pOld->u1.pFuncArg; pOld->u1.pFuncArg = 0; pOld->fg.isTabFunc = 0; pNew->fg.isTabFunc = 1; } pOld->zName = pOld->zDatabase = 0; pOld->pSelect = 0; } sqlite3SrcListDelete(pParse->db, F); }else{ Select *pSubquery; sqlite3SrcListShiftJoinType(F); pSubquery = sqlite3SelectNew(pParse,0,F,0,0,0,0,SF_NestedFrom,0); A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,pSubquery,N,U); } } %endif SQLITE_OMIT_SUBQUERY %type dbnm {Token} dbnm(A) ::= . {A.z=0; A.n=0;} dbnm(A) ::= DOT nm(X). {A = X;} |
︙ | ︙ | |||
792 793 794 795 796 797 798 | // the beginning of an ON CONFLICT clause, or the beginning of an ON // clause associated with the JOIN. The conflict is resolved in favor // of the JOIN. If an ON CONFLICT clause is intended, insert a dummy // WHERE clause in between, like this: // // INSERT INTO tab SELECT * FROM aaa JOIN bbb WHERE true ON CONFLICT ... // | | | | | < | < | < | > > > > > > | | | | < < < < < | 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 | // the beginning of an ON CONFLICT clause, or the beginning of an ON // clause associated with the JOIN. The conflict is resolved in favor // of the JOIN. If an ON CONFLICT clause is intended, insert a dummy // WHERE clause in between, like this: // // INSERT INTO tab SELECT * FROM aaa JOIN bbb WHERE true ON CONFLICT ... // // The [AND] and [OR] precedence marks in the rules for on_opt cause the // ON in this context to always be interpreted as belonging to the JOIN. // %type on_opt {Expr*} %destructor on_opt {sqlite3ExprDelete(pParse->db, $$);} on_opt(N) ::= ON expr(E). {N = E;} on_opt(N) ::= . [OR] {N = 0;} // Note that this block abuses the Token type just a little. If there is // no "INDEXED BY" clause, the returned token is empty (z==0 && n==0). If // there is an INDEXED BY clause, then the token is populated as per normal, // with z pointing to the token data and n containing the number of bytes // in the token. // // If there is a "NOT INDEXED" clause, then (z==0 && n==1), which is // normally illegal. The sqlite3SrcListIndexedBy() function // recognizes and interprets this as a special case. // %type indexed_opt {Token} indexed_opt(A) ::= . {A.z=0; A.n=0;} indexed_opt(A) ::= INDEXED BY nm(X). {A = X;} indexed_opt(A) ::= NOT INDEXED. {A.z=0; A.n=1;} %type using_opt {IdList*} %destructor using_opt {sqlite3IdListDelete(pParse->db, $$);} using_opt(U) ::= USING LP idlist(L) RP. {U = L;} using_opt(U) ::= . {U = 0;} %type orderby_opt {ExprList*} %destructor orderby_opt {sqlite3ExprListDelete(pParse->db, $$);} // the sortlist non-terminal stores a list of expression where each // expression is optionally followed by ASC or DESC to indicate the // 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). { A = sqlite3ExprListAppend(pParse,A,Y); sqlite3ExprListSetSortOrder(A,Z); } sortlist(A) ::= expr(Y) sortorder(Z). { A = sqlite3ExprListAppend(pParse,0,Y); /*A-overwrites-Y*/ sqlite3ExprListSetSortOrder(A,Z); } %type sortorder {int} sortorder(A) ::= ASC. {A = SQLITE_SO_ASC;} sortorder(A) ::= DESC. {A = SQLITE_SO_DESC;} sortorder(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, $$);} |
︙ | ︙ | |||
880 881 882 883 884 885 886 | 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 ///////////////////////////// // | | | < < | | < | > | < < < < < < < < | | | < < < < < < < < < < < < < < < < < < < | > | | < < < < < < < < < < < < < < | 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 | 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 ///////////////////////////// // %ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT cmd ::= with DELETE FROM xfullname(X) indexed_opt(I) where_opt(W) orderby_opt(O) limit_opt(L). { sqlite3SrcListIndexedBy(pParse, X, &I); #ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT sqlite3ExprListDelete(pParse->db, O); O = 0; sqlite3ExprDelete(pParse->db, L); L = 0; #endif sqlite3DeleteFrom(pParse,X,W,O,L); } %endif %ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT cmd ::= with DELETE FROM xfullname(X) indexed_opt(I) where_opt(W). { sqlite3SrcListIndexedBy(pParse, X, &I); sqlite3DeleteFrom(pParse,X,W,0,0); } %endif %type where_opt {Expr*} %destructor where_opt {sqlite3ExprDelete(pParse->db, $$);} where_opt(A) ::= . {A = 0;} where_opt(A) ::= WHERE expr(X). {A = X;} ////////////////////////// The UPDATE command //////////////////////////////// // %ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y) where_opt(W) orderby_opt(O) limit_opt(L). { sqlite3SrcListIndexedBy(pParse, X, &I); sqlite3ExprListCheckLength(pParse,Y,"set list"); sqlite3Update(pParse,X,Y,W,R,O,L,0); } %endif %ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y) where_opt(W). { sqlite3SrcListIndexedBy(pParse, X, &I); sqlite3ExprListCheckLength(pParse,Y,"set list"); 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); |
︙ | ︙ | |||
989 990 991 992 993 994 995 | ////////////////////////// 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); } | | < | | | | | | < < < < < | 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 | ////////////////////////// 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. { 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) ::= ON CONFLICT LP sortlist(T) RP where_opt(TW) DO UPDATE SET setlist(Z) where_opt(W). { A = sqlite3UpsertNew(pParse->db,T,TW,Z,W);} upsert(A) ::= ON CONFLICT LP sortlist(T) RP where_opt(TW) DO NOTHING. { A = sqlite3UpsertNew(pParse->db,T,TW,0,0); } upsert(A) ::= ON CONFLICT DO NOTHING. { A = sqlite3UpsertNew(pParse->db,0,0,0,0); } %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, $$);} |
︙ | ︙ | |||
1042 1043 1044 1045 1046 1047 1048 | %type expr {Expr*} %destructor expr {sqlite3ExprDelete(pParse->db, $$);} %type term {Expr*} %destructor term {sqlite3ExprDelete(pParse->db, $$);} %include { | | > > > | < | > < | < | | > > > > | | | | > < | 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 | %type expr {Expr*} %destructor expr {sqlite3ExprDelete(pParse->db, $$);} %type term {Expr*} %destructor term {sqlite3ExprDelete(pParse->db, $$);} %include { /* Construct a new Expr object from a single identifier. Use the ** new Expr to populate pOut. Set the span of pOut to be the identifier ** 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->affinity = 0; p->flags = EP_Leaf; p->iAgg = -1; p->pLeft = p->pRight = 0; p->x.pList = 0; p->pAggInfo = 0; p->y.pTab = 0; 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); } } return p; } } expr(A) ::= term(A). expr(A) ::= LP expr(X) RP. {A = X;} expr(A) ::= id(X). {A=tokenExpr(pParse,TK_ID,X); /*A-overwrites-X*/} expr(A) ::= JOIN_KW(X). {A=tokenExpr(pParse,TK_ID,X); /*A-overwrites-X*/} expr(A) ::= nm(X) DOT nm(Y). { Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &X, 1); Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &Y, 1); if( IN_RENAME_OBJECT ){ sqlite3RenameTokenMap(pParse, (void*)temp2, &Y); sqlite3RenameTokenMap(pParse, (void*)temp1, &X); } A = sqlite3PExpr(pParse, TK_DOT, temp1, temp2); } expr(A) ::= nm(X) DOT nm(Y) DOT nm(Z). { Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &X, 1); Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &Y, 1); Expr *temp3 = sqlite3ExprAlloc(pParse->db, TK_ID, &Z, 1); Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3); if( IN_RENAME_OBJECT ){ sqlite3RenameTokenMap(pParse, (void*)temp3, &Z); sqlite3RenameTokenMap(pParse, (void*)temp2, &Y); } A = sqlite3PExpr(pParse, TK_DOT, temp1, temp4); } term(A) ::= NULL|FLOAT|BLOB(X). {A=tokenExpr(pParse,@X,X); /*A-overwrites-X*/} term(A) ::= STRING(X). {A=tokenExpr(pParse,@X,X); /*A-overwrites-X*/} term(A) ::= INTEGER(X). { A = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &X, 1); } expr(A) ::= VARIABLE(X). { if( !(X.z[0]=='#' && sqlite3Isdigit(X.z[1])) ){ u32 n = X.n; A = tokenExpr(pParse, TK_VARIABLE, X); sqlite3ExprAssignVarNumber(pParse, A, n); }else{ |
︙ | ︙ | |||
1142 1143 1144 1145 1146 1147 1148 | A = sqlite3ExprFunction(pParse, Y, &X, D); } expr(A) ::= id(X) LP STAR RP. { A = sqlite3ExprFunction(pParse, 0, &X, 0); } %ifndef SQLITE_OMIT_WINDOWFUNC | | | < < < | | 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 | 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 over_clause(Z). { A = sqlite3ExprFunction(pParse, Y, &X, D); sqlite3WindowAttach(pParse, A, Z); } expr(A) ::= id(X) LP STAR RP over_clause(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; }else{ sqlite3ExprListDelete(pParse->db, pList); } } expr(A) ::= expr(A) AND(OP) expr(Y). {A=sqlite3PExpr(pParse,@OP,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). |
︙ | ︙ | |||
1236 1237 1238 1239 1240 1241 1242 | A = sqlite3PExpr(pParse,TK_IS,A,Y); binaryToUnaryIfNull(pParse, Y, A, TK_ISNULL); } expr(A) ::= expr(A) IS NOT expr(Y). { A = sqlite3PExpr(pParse,TK_ISNOT,A,Y); binaryToUnaryIfNull(pParse, Y, A, TK_NOTNULL); } | < < < < < < < < < < < < < < | 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 | A = sqlite3PExpr(pParse,TK_IS,A,Y); binaryToUnaryIfNull(pParse, Y, A, TK_ISNULL); } expr(A) ::= expr(A) IS NOT expr(Y). { A = sqlite3PExpr(pParse,TK_ISNOT,A,Y); binaryToUnaryIfNull(pParse, Y, A, TK_NOTNULL); } expr(A) ::= NOT(B) expr(X). {A = sqlite3PExpr(pParse, @B, X, 0);/*A-overwrites-B*/} expr(A) ::= BITNOT(B) expr(X). {A = sqlite3PExpr(pParse, @B, X, 0);/*A-overwrites-B*/} expr(A) ::= PLUS|MINUS(B) expr(X). [BITNOT] { A = sqlite3PExpr(pParse, @B==TK_PLUS ? TK_UPLUS : TK_UMINUS, X, 0); /*A-overwrites-B*/ } %type between_op {int} between_op(A) ::= BETWEEN. {A = 0;} between_op(A) ::= NOT BETWEEN. {A = 1;} expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] { ExprList *pList = sqlite3ExprListAppend(pParse,0, X); pList = sqlite3ExprListAppend(pParse,pList, Y); A = sqlite3PExpr(pParse, TK_BETWEEN, A, 0); |
︙ | ︙ | |||
1288 1289 1290 1291 1292 1293 1294 | ** ** expr1 IN () ** expr1 NOT IN () ** ** simplify to constants 0 (false) and 1 (true), respectively, ** regardless of the value of expr1. */ | > | | < > | > > > > > > > > > > > > > > > > < | | > > | | | > | < < < | | | < < < < < < < < < | | | > | 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 | ** ** expr1 IN () ** expr1 NOT IN () ** ** simplify to constants 0 (false) and 1 (true), respectively, ** regardless of the value of expr1. */ if( IN_RENAME_OBJECT==0 ){ sqlite3ExprDelete(pParse->db, A); A = sqlite3ExprAlloc(pParse->db, TK_INTEGER,&sqlite3IntTokens[N],1); } }else if( Y->nExpr==1 ){ /* Expressions of the form: ** ** expr1 IN (?1) ** expr1 NOT IN (?2) ** ** with exactly one value on the RHS can be simplified to something ** like this: ** ** expr1 == ?1 ** expr1 <> ?2 ** ** But, the RHS of the == or <> is marked with the EP_Generic flag ** so that it may not contribute to the computation of comparison ** affinity or the collating sequence to use for comparison. Otherwise, ** the semantics would be subtly different from IN or NOT IN. */ Expr *pRHS = Y->a[0].pExpr; Y->a[0].pExpr = 0; sqlite3ExprListDelete(pParse->db, Y); /* pRHS cannot be NULL because a malloc error would have been detected ** before now and control would have never reached this point */ if( ALWAYS(pRHS) ){ pRHS->flags &= ~EP_Collate; pRHS->flags |= EP_Generic; } A = sqlite3PExpr(pParse, N ? TK_NE : TK_EQ, A, pRHS); }else{ A = sqlite3PExpr(pParse, TK_IN, A, 0); if( A ){ A->x.pList = Y; sqlite3ExprSetHeightAndFlags(pParse, A); }else{ sqlite3ExprListDelete(pParse->db, Y); } 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); |
︙ | ︙ | |||
1425 1426 1427 1428 1429 1430 1431 | // 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 | | | 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 | // 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_master schema. // 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*} |
︙ | ︙ | |||
1480 1481 1482 1483 1484 1485 1486 | ///////////////////////////// The DROP INDEX command ///////////////////////// // cmd ::= DROP INDEX ifexists(E) fullname(X). {sqlite3DropIndex(pParse, X, E);} ///////////////////////////// The VACUUM command ///////////////////////////// // | | > | > | 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 | ///////////////////////////// The DROP INDEX command ///////////////////////// // cmd ::= DROP INDEX ifexists(E) fullname(X). {sqlite3DropIndex(pParse, X, E);} ///////////////////////////// The VACUUM command ///////////////////////////// // %ifndef SQLITE_OMIT_VACUUM %ifndef 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 SQLITE_OMIT_ATTACH %endif SQLITE_OMIT_VACUUM ///////////////////////////// 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);} |
︙ | ︙ | |||
1594 1595 1596 1597 1598 1599 1600 | %type trigger_cmd {TriggerStep*} %destructor trigger_cmd {sqlite3DeleteTriggerStep(pParse->db, $$);} // UPDATE trigger_cmd(A) ::= | | | | | | | 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 | %type trigger_cmd {TriggerStep*} %destructor trigger_cmd {sqlite3DeleteTriggerStep(pParse->db, $$);} // UPDATE trigger_cmd(A) ::= UPDATE(B) orconf(R) trnm(X) tridxby SET setlist(Y) where_opt(Z) scanpt(E). {A = sqlite3TriggerUpdateStep(pParse, &X, 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->affinity = OE_Ignore; } } expr(A) ::= RAISE LP raisetype(T) COMMA nm(Z) RP. { A = sqlite3ExprAlloc(pParse->db, TK_RAISE, &Z, 1); if( A ) { A->affinity = (char)T; } } %endif !SQLITE_OMIT_TRIGGER %type raisetype {int} raisetype(A) ::= ROLLBACK. {A = OE_Rollback;} raisetype(A) ::= ABORT. {A = OE_Abort;} |
︙ | ︙ | |||
1669 1670 1671 1672 1673 1674 1675 | /////////////////////////////////// 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 ... //////////////////////////////// | | < < < < < < | | 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 | /////////////////////////////////// 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 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); } 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_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). { |
︙ | ︙ | |||
1721 1722 1723 1724 1725 1726 1727 | anylist ::= anylist ANY. %endif SQLITE_OMIT_VIRTUALTABLE //////////////////////// COMMON TABLE EXPRESSIONS //////////////////////////// %type wqlist {With*} %destructor wqlist {sqlite3WithDelete(pParse->db, $$);} | < < < < < < < < < | | | | | 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 | 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); } wqlist(A) ::= nm(X) eidlist_opt(Y) AS LP select(Z) RP. { A = sqlite3WithAdd(pParse, 0, &X, Y, Z); /*A-overwrites-X*/ } wqlist(A) ::= wqlist(A) COMMA nm(X) eidlist_opt(Y) AS LP select(Z) RP. { A = sqlite3WithAdd(pParse, A, &X, Y, Z); } %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 |
︙ | ︙ | |||
1779 1780 1781 1782 1783 1784 1785 | %type frame_opt {Window*} %destructor frame_opt {sqlite3WindowDelete(pParse->db, $$);} %type part_opt {ExprList*} %destructor part_opt {sqlite3ExprListDelete(pParse->db, $$);} | | | < < < < < < | 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 | %type frame_opt {Window*} %destructor frame_opt {sqlite3WindowDelete(pParse->db, $$);} %type part_opt {ExprList*} %destructor part_opt {sqlite3ExprListDelete(pParse->db, $$);} %type filter_opt {Expr*} %destructor filter_opt {sqlite3ExprDelete(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);} |
︙ | ︙ | |||
1852 1853 1854 1855 1856 1857 1858 | 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; } | | < < < | < > | < < > | | | | | < < < < < < < < < < | | < < < > > > < | 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 | 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; } %type over_clause {Window*} %destructor over_clause {sqlite3WindowDelete(pParse->db, $$);} over_clause(A) ::= filter_opt(W) OVER LP window(Z) RP. { A = Z; assert( A!=0 ); A->pFilter = W; } over_clause(A) ::= filter_opt(W) OVER nm(Z). { A = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); if( A ){ A->zName = sqlite3DbStrNDup(pParse->db, Z.z, Z.n); A->pFilter = W; }else{ sqlite3ExprDelete(pParse->db, W); } } filter_opt(A) ::= . { A = 0; } filter_opt(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 TRUEFALSE /* True or false keyword */ ISNOT /* Combination of IS and NOT */ FUNCTION /* A function invocation */ COLUMN /* Reference to a table column */ AGG_FUNCTION /* An aggregate function */ AGG_COLUMN /* An aggregated column */ 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 */ 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 */ . /* 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 { |
︙ | ︙ |
Changes to src/pcache.c.
︙ | ︙ | |||
62 63 64 65 66 67 68 | ** When sqlite3PcacheTrace is 2, a dump of the pcache showing all cache entries ** is displayed for many operations, resulting in a lot of output. */ #if defined(SQLITE_DEBUG) && 0 int sqlite3PcacheTrace = 2; /* 0: off 1: simple 2: cache dumps */ int sqlite3PcacheMxDump = 9999; /* Max cache entries for pcacheDump() */ # define pcacheTrace(X) if(sqlite3PcacheTrace){sqlite3DebugPrintf X;} | < < < < < < < < < < | | > > > > | > > | | < < < < < < < < < < < < < < < | < < < < | < | 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 | ** When sqlite3PcacheTrace is 2, a dump of the pcache showing all cache entries ** is displayed for many operations, resulting in a lot of output. */ #if defined(SQLITE_DEBUG) && 0 int sqlite3PcacheTrace = 2; /* 0: off 1: simple 2: cache dumps */ int sqlite3PcacheMxDump = 9999; /* Max cache entries for pcacheDump() */ # define pcacheTrace(X) if(sqlite3PcacheTrace){sqlite3DebugPrintf X;} void pcacheDump(PCache *pCache){ int N; int i, j; sqlite3_pcache_page *pLower; PgHdr *pPg; unsigned char *a; if( sqlite3PcacheTrace<2 ) return; if( pCache->pCache==0 ) return; N = sqlite3PcachePagecount(pCache); if( N>sqlite3PcacheMxDump ) N = sqlite3PcacheMxDump; for(i=1; i<=N; i++){ pLower = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, i, 0); if( pLower==0 ) continue; pPg = (PgHdr*)pLower->pExtra; printf("%3d: nRef %2d flgs %02x data ", i, pPg->nRef, pPg->flags); a = (unsigned char *)pLower->pBuf; for(j=0; j<12; j++) printf("%02x", a[j]); printf("\n"); if( pPg->pPage==0 ){ sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, pLower, 0); } } } #else # define pcacheTrace(X) # define pcacheDump(X) #endif /* ** Check invariants on a PgHdr entry. Return true if everything is OK. ** Return false if any invariant is violated. ** ** This routine is for use inside of assert() statements only. For ** example: ** ** assert( sqlite3PcachePageSanity(pPg) ); */ #ifdef SQLITE_DEBUG int sqlite3PcachePageSanity(PgHdr *pPg){ PCache *pCache; assert( pPg!=0 ); assert( pPg->pgno>0 || pPg->pPager==0 ); /* Page number is 1 or more */ pCache = pPg->pCache; assert( pCache!=0 ); /* Every page has an associated PCache */ if( pPg->flags & PGHDR_CLEAN ){ assert( (pPg->flags & PGHDR_DIRTY)==0 );/* Cannot be both CLEAN and DIRTY */ assert( pCache->pDirty!=pPg ); /* CLEAN pages not on dirty list */ assert( pCache->pDirtyTail!=pPg ); } /* WRITEABLE pages must also be DIRTY */ if( pPg->flags & PGHDR_WRITEABLE ){ assert( pPg->flags & PGHDR_DIRTY ); /* WRITEABLE implies DIRTY */ } /* NEED_SYNC can be set independently of WRITEABLE. This can happen, ** for example, when using the sqlite3PagerDontWrite() optimization: |
︙ | ︙ | |||
263 264 265 266 267 268 269 | */ 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 | */ 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{ /* IMPLEMENTATION-OF: R-61436-13639 If the argument N is negative, then ** the number of cache pages is adjusted to use approximately abs(N*1024) ** bytes of memory. */ return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra)); } } /*************************************************** 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(); } 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); |
︙ | ︙ | |||
408 409 410 411 412 413 414 | ** (createFlag==1 AND !(bPurgeable AND pDirty) */ eCreate = createFlag & pCache->eCreate; assert( eCreate==0 || eCreate==1 || eCreate==2 ); assert( createFlag==0 || pCache->eCreate==eCreate ); assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) ); pRes = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate); | | < | 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 | ** (createFlag==1 AND !(bPurgeable AND pDirty) */ eCreate = createFlag & pCache->eCreate; assert( eCreate==0 || eCreate==1 || eCreate==2 ); assert( createFlag==0 || pCache->eCreate==eCreate ); assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) ); pRes = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate); pcacheTrace(("%p.FETCH %d%s (result: %p)\n",pCache,pgno, createFlag?" create":"",pRes)); return pRes; } /* ** If the sqlite3PcacheFetch() routine is unable to allocate a new ** page because no clean pages are available for reuse and the cache ** size limit has been reached, then this routine can be invoked to |
︙ | ︙ | |||
538 539 540 541 542 543 544 | assert( p->nRef>0 ); p->pCache->nRefSum--; if( (--p->nRef)==0 ){ if( p->flags&PGHDR_CLEAN ){ pcacheUnpin(p); }else{ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT); | < | 508 509 510 511 512 513 514 515 516 517 518 519 520 521 | assert( p->nRef>0 ); p->pCache->nRefSum--; if( (--p->nRef)==0 ){ if( p->flags&PGHDR_CLEAN ){ pcacheUnpin(p); }else{ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT); } } } /* ** Increase the reference count of a supplied page by 1. */ |
︙ | ︙ | |||
582 583 584 585 586 587 588 | if( p->flags & (PGHDR_CLEAN|PGHDR_DONT_WRITE) ){ /*OPTIMIZATION-IF-FALSE*/ p->flags &= ~PGHDR_DONT_WRITE; if( p->flags & PGHDR_CLEAN ){ p->flags ^= (PGHDR_DIRTY|PGHDR_CLEAN); pcacheTrace(("%p.DIRTY %d\n",p->pCache,p->pgno)); assert( (p->flags & (PGHDR_DIRTY|PGHDR_CLEAN))==PGHDR_DIRTY ); pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD); | < | 551 552 553 554 555 556 557 558 559 560 561 562 563 564 | if( p->flags & (PGHDR_CLEAN|PGHDR_DONT_WRITE) ){ /*OPTIMIZATION-IF-FALSE*/ p->flags &= ~PGHDR_DONT_WRITE; if( p->flags & PGHDR_CLEAN ){ p->flags ^= (PGHDR_DIRTY|PGHDR_CLEAN); pcacheTrace(("%p.DIRTY %d\n",p->pCache,p->pgno)); assert( (p->flags & (PGHDR_DIRTY|PGHDR_CLEAN))==PGHDR_DIRTY ); pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD); } assert( sqlite3PcachePageSanity(p) ); } } /* ** Make sure the page is marked as clean. If it isn't clean already, |
︙ | ︙ | |||
645 646 647 648 649 650 651 | } /* ** Change the page number of page p to newPgno. */ void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){ PCache *pCache = p->pCache; | < < < < < < < < < < | 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 | } /* ** Change the page number of page p to newPgno. */ void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){ PCache *pCache = p->pCache; assert( p->nRef>0 ); assert( newPgno>0 ); assert( sqlite3PcachePageSanity(p) ); pcacheTrace(("%p.MOVE %d -> %d\n",pCache,p->pgno,newPgno)); sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno); p->pgno = newPgno; if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){ pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT); } } /* ** Drop every cache entry whose page number is greater than "pgno". The ** caller must ensure that there are no outstanding references to any pages ** other than page 1 with a page number greater than pgno. |
︙ | ︙ |
Changes to src/pcache1.c.
︙ | ︙ | |||
35 36 37 38 39 40 41 | ** ** The size of the extension (MemPage+PgHdr+PgHdr1) can be determined at ** runtime using sqlite3_config(SQLITE_CONFIG_PCACHE_HDRSZ, &size). The ** sizes of the extensions sum to 272 bytes on x64 for 3.8.10, but this ** size can vary according to architecture, compile-time options, and ** SQLite library version number. ** | | | | | < < | > | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | ** ** The size of the extension (MemPage+PgHdr+PgHdr1) can be determined at ** runtime using sqlite3_config(SQLITE_CONFIG_PCACHE_HDRSZ, &size). The ** sizes of the extensions sum to 272 bytes on x64 for 3.8.10, but this ** size can vary according to architecture, compile-time options, and ** SQLite library version number. ** ** If SQLITE_PCACHE_SEPARATE_HEADER is defined, then the extension is obtained ** using a separate memory allocation from the database page content. This ** seeks to overcome the "clownshoe" problem (also called "internal ** fragmentation" in academic literature) of allocating a few bytes more ** than a power of two with the memory allocator rounding up to the next ** power of two, and leaving the rounded-up space unused. ** ** This module tracks pointers to PgHdr1 objects. Only pcache.c communicates ** with this module. Information is passed back and forth as PgHdr1 pointers. ** ** The pcache.c and pager.c modules deal pointers to PgHdr objects. ** The btree.c module deals with pointers to MemPage objects. ** |
︙ | ︙ | |||
86 87 88 89 90 91 92 | typedef struct PCache1 PCache1; typedef struct PgHdr1 PgHdr1; typedef struct PgFreeslot PgFreeslot; typedef struct PGroup PGroup; /* ** Each cache entry is represented by an instance of the following | > | < | < < < < < | | | < < < < < | | | | | | | | | | 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 | typedef struct PCache1 PCache1; typedef struct PgHdr1 PgHdr1; typedef struct PgFreeslot PgFreeslot; 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 */ }; /* ** A page is pinned if it is not on the LRU list. To be "pinned" means ** that the page is in active use and must not be deallocated. */ #define PAGE_IS_PINNED(p) ((p)->pLruNext==0) |
︙ | ︙ | |||
431 432 433 434 435 436 437 | */ 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)) ){ | < > > > > > > > > > > > < < > > > | 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 | */ 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 ** this mutex is not held. */ assert( pcache1.separateCache==0 ); assert( pCache->pGroup==&pcache1.grp ); pcache1LeaveMutex(pCache->pGroup); #endif if( benignMalloc ){ sqlite3BeginBenignMalloc(); } #ifdef SQLITE_PCACHE_SEPARATE_HEADER pPg = pcache1Alloc(pCache->szPage); p = sqlite3Malloc(sizeof(PgHdr1) + pCache->szExtra); if( !pPg || !p ){ pcache1Free(pPg); sqlite3_free(p); pPg = 0; } #else pPg = pcache1Alloc(pCache->szAlloc); p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage]; #endif if( benignMalloc ){ sqlite3EndBenignMalloc(); } #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT pcache1EnterMutex(pCache->pGroup); #endif if( pPg==0 ) return 0; p->page.pBuf = pPg; p->page.pExtra = &p[1]; p->isBulkLocal = 0; p->isAnchor = 0; } (*pCache->pnPurgeable)++; return p; } /* ** Free a page object allocated by pcache1AllocPage(). */ static void pcache1FreePage(PgHdr1 *p){ PCache1 *pCache; assert( p!=0 ); pCache = p->pCache; assert( sqlite3_mutex_held(p->pCache->pGroup->mutex) ); if( p->isBulkLocal ){ p->pNext = pCache->pFree; pCache->pFree = p; }else{ pcache1Free(p->page.pBuf); #ifdef SQLITE_PCACHE_SEPARATE_HEADER sqlite3_free(p); #endif } (*pCache->pnPurgeable)--; } /* ** Malloc function used by SQLite to obtain space from the buffer configured ** using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no such buffer |
︙ | ︙ | |||
774 775 776 777 778 779 780 | if( pCache ){ if( pcache1.separateCache ){ pGroup = (PGroup*)&pCache[1]; pGroup->mxPinned = 10; }else{ pGroup = &pcache1.grp; } | < > | 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 | 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); pcache1EnterMutex(pGroup); pcache1ResizeHash(pCache); if( bPurgeable ){ pCache->nMin = 10; pGroup->nMinPage += pCache->nMin; pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage; pCache->pnPurgeable = &pGroup->nPurgeable; }else{ |
︙ | ︙ | |||
809 810 811 812 813 814 815 | /* ** 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; | < < < < < < | | | | 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 | /* ** 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; if( pCache->bPurgeable ){ PGroup *pGroup = pCache->pGroup; pcache1EnterMutex(pGroup); pGroup->nMaxPage += (nMax - pCache->nMax); pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage; pCache->nMax = nMax; 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; int savedMaxPage; pcache1EnterMutex(pGroup); savedMaxPage = pGroup->nMaxPage; pGroup->nMaxPage = 0; pcache1EnforceMaxPage(pCache); pGroup->nMaxPage = savedMaxPage; pcache1LeaveMutex(pGroup); } |
︙ | ︙ | |||
1115 1116 1117 1118 1119 1120 1121 | sqlite3_pcache_page *pPg, unsigned int iOld, unsigned int iNew ){ PCache1 *pCache = (PCache1 *)p; PgHdr1 *pPage = (PgHdr1 *)pPg; PgHdr1 **pp; | | < < | | < | | | | 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 | sqlite3_pcache_page *pPg, unsigned int iOld, unsigned int iNew ){ PCache1 *pCache = (PCache1 *)p; PgHdr1 *pPage = (PgHdr1 *)pPg; PgHdr1 **pp; unsigned int h; assert( pPage->iKey==iOld ); assert( pPage->pCache==pCache ); pcache1EnterMutex(pCache->pGroup); h = iOld%pCache->nHash; pp = &pCache->apHash[h]; while( (*pp)!=pPage ){ pp = &(*pp)->pNext; } *pp = pPage->pNext; h = iNew%pCache->nHash; pPage->iKey = iNew; pPage->pNext = pCache->apHash[h]; pCache->apHash[h] = pPage; if( iNew>pCache->iMaxKey ){ pCache->iMaxKey = iNew; } pcache1LeaveMutex(pCache->pGroup); } |
︙ | ︙ | |||
1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 | PgHdr1 *p; pcache1EnterMutex(&pcache1.grp); while( (nReq<0 || nFree<nReq) && (p=pcache1.grp.lru.pLruPrev)!=0 && p->isAnchor==0 ){ nFree += pcache1MemSize(p->page.pBuf); assert( PAGE_IS_UNPINNED(p) ); pcache1PinPage(p); pcache1RemoveFromHash(p, 1); } pcache1LeaveMutex(&pcache1.grp); } return nFree; | > > > | 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 | PgHdr1 *p; pcache1EnterMutex(&pcache1.grp); while( (nReq<0 || nFree<nReq) && (p=pcache1.grp.lru.pLruPrev)!=0 && p->isAnchor==0 ){ nFree += pcache1MemSize(p->page.pBuf); #ifdef SQLITE_PCACHE_SEPARATE_HEADER nFree += sqlite3MemSize(p); #endif assert( PAGE_IS_UNPINNED(p) ); pcache1PinPage(p); pcache1RemoveFromHash(p, 1); } pcache1LeaveMutex(&pcache1.grp); } return nFree; |
︙ | ︙ |
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 | /* ** 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 || sqlite3BtreeIsInReadTrans(db->aDb[1].pBt) ){ 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); |
︙ | ︙ | |||
292 293 294 295 296 297 298 | upr = mid - 1; }else{ lwr = mid + 1; } } return lwr>upr ? 0 : &aPragmaName[mid]; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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. |
︙ | ︙ | |||
464 465 466 467 468 469 470 | pParse->nErr++; pParse->rc = rc; goto pragma_out; } /* Locate the pragma in the lookup table */ pPragma = pragmaLocate(zLeft); | | < < < < | 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 | pParse->nErr++; pParse->rc = rc; goto pragma_out; } /* Locate the pragma in the lookup table */ pPragma = pragmaLocate(zLeft); if( pPragma==0 ) 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 */ |
︙ | ︙ | |||
558 559 560 561 562 563 564 | 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); | | | 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 | 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,-1,0) ){ sqlite3OomFault(db); } } break; } /* |
︙ | ︙ | |||
614 615 616 617 618 619 620 | ** ** PRAGMA [schema.]page_count ** ** Return the number of pages in the specified database. */ case PragTyp_PAGE_COUNT: { int iReg; | < < < < < < < | > | 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 | ** ** 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{ sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg, sqlite3AbsInt32(sqlite3Atoi(zRight))); } sqlite3VdbeAddOp2(v, OP_ResultRow, iReg, 1); break; } /* ** PRAGMA [schema.]locking_mode |
︙ | ︙ | |||
702 703 704 705 706 707 708 | 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; } | < < < < < | 640 641 642 643 644 645 646 647 648 649 650 651 652 653 | 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; } for(ii=db->nDb-1; ii>=0; ii--){ |
︙ | ︙ | |||
804 805 806 807 808 809 810 | /* ** PRAGMA [schema.]incremental_vacuum(N) ** ** Do N steps of incremental vacuuming on a database. */ #ifndef SQLITE_OMIT_AUTOVACUUM case PragTyp_INCREMENTAL_VACUUM: { | | | 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 | /* ** PRAGMA [schema.]incremental_vacuum(N) ** ** Do N steps of incremental vacuuming on a database. */ #ifndef SQLITE_OMIT_AUTOVACUUM case PragTyp_INCREMENTAL_VACUUM: { int iLimit, addr; if( zRight==0 || !sqlite3GetInt32(zRight, &iLimit) || iLimit<=0 ){ iLimit = 0x7fffffff; } sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3VdbeAddOp2(v, OP_Integer, iLimit, 1); addr = sqlite3VdbeAddOp1(v, OP_IncrVacuum, iDb); VdbeCoverage(v); sqlite3VdbeAddOp1(v, OP_ResultRow, 1); |
︙ | ︙ | |||
961 962 963 964 965 966 967 | ** Return or set the local value of the temp_store_directory flag. Changing ** the value sets a specific directory to be used for temporary files. ** Setting to a null string reverts to the default temporary directory search. ** If temporary directory is changed, then invalidateTempStorage. ** */ case PragTyp_TEMP_STORE_DIRECTORY: { | < < < < < < | 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 | ** Return or set the local value of the temp_store_directory flag. Changing ** the value sets a specific directory to be used for temporary files. ** Setting to a null string reverts to the default temporary directory search. ** If temporary directory is changed, then invalidateTempStorage. ** */ case PragTyp_TEMP_STORE_DIRECTORY: { if( !zRight ){ returnSingleText(v, sqlite3_temp_directory); }else{ #ifndef SQLITE_OMIT_WSD if( zRight[0] ){ int res; rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res); if( rc!=SQLITE_OK || res==0 ){ sqlite3ErrorMsg(pParse, "not a writable directory"); goto pragma_out; } } if( SQLITE_TEMP_STORE==0 || (SQLITE_TEMP_STORE==1 && db->temp_store<=1) || (SQLITE_TEMP_STORE==2 && db->temp_store==1) ){ invalidateTempStorage(pParse); } sqlite3_free(sqlite3_temp_directory); if( zRight[0] ){ sqlite3_temp_directory = sqlite3_mprintf("%s", zRight); }else{ sqlite3_temp_directory = 0; } #endif /* SQLITE_OMIT_WSD */ } break; } #if SQLITE_OS_WIN /* ** PRAGMA data_store_directory ** PRAGMA data_store_directory = ""|"directory_name" ** ** Return or set the local value of the data_store_directory flag. Changing ** the value sets a specific directory to be used for database files that ** were specified with a relative pathname. Setting to a null string reverts ** to the default database directory, which for database files specified with ** a relative path will probably be based on the current directory for the ** process. Database file specified with an absolute path are not impacted ** by this setting, regardless of its value. ** */ case PragTyp_DATA_STORE_DIRECTORY: { if( !zRight ){ returnSingleText(v, sqlite3_data_directory); }else{ #ifndef SQLITE_OMIT_WSD if( zRight[0] ){ int res; rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res); if( rc!=SQLITE_OK || res==0 ){ sqlite3ErrorMsg(pParse, "not a writable directory"); goto pragma_out; } } sqlite3_free(sqlite3_data_directory); if( zRight[0] ){ sqlite3_data_directory = sqlite3_mprintf("%s", zRight); }else{ sqlite3_data_directory = 0; } #endif /* SQLITE_OMIT_WSD */ } break; } #endif #if SQLITE_ENABLE_LOCKING_STYLE /* ** PRAGMA [schema.]lock_proxy_file |
︙ | ︙ | |||
1124 1125 1126 1127 1128 1129 1130 | #endif if( sqlite3GetBoolean(zRight, 0) ){ db->flags |= mask; }else{ db->flags &= ~mask; if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0; | < < < < < < < < | 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); |
︙ | ︙ | |||
1161 1162 1163 1164 1165 1166 1167 | ** 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; | < > > | < < | | | < < < < < < < < < | < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 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 | ** 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 ){ int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); int i, k; int nHidden = 0; Column *pCol; Index *pPk = sqlite3PrimaryKeyIndex(pTab); pParse->nMem = 7; sqlite3CodeVerifySchema(pParse, iTabDb); sqlite3ViewGetColumnNames(pParse, pTab); for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){ int isHidden = IsHiddenColumn(pCol); if( isHidden && pPragma->iArg==0 ){ nHidden++; continue; } 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++){} } assert( pCol->pDflt==0 || pCol->pDflt->op==TK_SPAN ); sqlite3VdbeMultiLoad(v, 1, pPragma->iArg ? "issisii" : "issisi", i-nHidden, pCol->zName, sqlite3ColumnType(pCol,""), pCol->notNull ? 1 : 0, pCol->pDflt ? pCol->pDflt->u.zToken : 0, k, isHidden); } } } 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", pTab->zName, 0, pTab->szTabRow, pTab->nRowLogEst, pTab->tabFlags); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ sqlite3VdbeMultiLoad(v, 2, "siiiX", pIdx->zName, |
︙ | ︙ | |||
1320 1321 1322 1323 1324 1325 1326 | break; #endif case PragTyp_INDEX_INFO: if( zRight ){ Index *pIdx; Table *pTab; pIdx = sqlite3FindIndex(db, zRight, zDb); | < < < < < < < < < | | 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 | 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, cnum<0 ? 0 : pTab->aCol[cnum].zName); if( pPragma->iArg ){ sqlite3VdbeMultiLoad(v, 4, "isiX", pIdx->aSortOrder[i], pIdx->azColl[i], i<pIdx->nKeyCol); } sqlite3VdbeAddOp2(v, OP_ResultRow, 1, pParse->nMem); |
︙ | ︙ | |||
1408 1409 1410 1411 1412 1413 1414 | for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){ CollSeq *pColl = (CollSeq *)sqliteHashData(p); sqlite3VdbeMultiLoad(v, 1, "is", i++, pColl->zName); } } break; | | < | | | | < | 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 | for(p=sqliteHashFirst(&db->aCollSeq); p; p=sqliteHashNext(p)){ CollSeq *pColl = (CollSeq *)sqliteHashData(p); sqlite3VdbeMultiLoad(v, 1, "is", i++, pColl->zName); } } break; #ifdef SQLITE_INTROSPECTION_PRAGMAS case PragTyp_FUNCTION_LIST: { int i; HashElem *j; FuncDef *p; pParse->nMem = 2; for(i=0; i<SQLITE_FUNC_HASH_SZ; i++){ for(p=sqlite3BuiltinFunctions.a[i]; p; p=p->u.pHash ){ if( p->funcFlags & SQLITE_FUNC_INTERNAL ) continue; sqlite3VdbeMultiLoad(v, 1, "si", p->zName, 1); } } for(j=sqliteHashFirst(&db->aFunc); j; j=sqliteHashNext(j)){ p = (FuncDef*)sqliteHashData(j); sqlite3VdbeMultiLoad(v, 1, "si", p->zName, 0); } } break; #ifndef SQLITE_OMIT_VIRTUALTABLE case PragTyp_MODULE_LIST: { HashElem *j; |
︙ | ︙ | |||
1457 1458 1459 1460 1461 1462 1463 | #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); | | | | | 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 | #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 ){ pFK = pTab->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].zName, pFK->aCol[j].zCol, actionName(pFK->aAction[1]), /* ON UPDATE */ actionName(pFK->aAction[0]), /* ON DELETE */ "NONE"); } ++i; pFK = pFK->pNextFrom; |
︙ | ︙ | |||
1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 | Table *pParent; /* Parent table that child points to */ Index *pIdx; /* Index in the parent table */ int i; /* Loop counter: Foreign key number for pTab */ int j; /* Loop counter: Field of the foreign key */ HashElem *k; /* Loop counter: Next table in schema */ int x; /* result variable */ int regResult; /* 3 registers to hold a result row */ int regRow; /* Registers to hold a row from pTab */ int addrTop; /* Top of a loop checking foreign keys */ int addrOk; /* Jump here if the key is OK */ int *aiCols; /* child to parent column mapping */ regResult = pParse->nMem+1; pParse->nMem += 4; 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); } | > > > | | < | | | < | | | | < | | < | | | | 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 | Table *pParent; /* Parent table that child points to */ Index *pIdx; /* Index in the parent table */ int i; /* Loop counter: Foreign key number for pTab */ int j; /* Loop counter: Field of the foreign key */ HashElem *k; /* Loop counter: Next table in schema */ int x; /* result variable */ int regResult; /* 3 registers to hold a result row */ int regKey; /* Register to hold key for checking the FK */ int regRow; /* Registers to hold a row from pTab */ int addrTop; /* Top of a loop checking foreign keys */ int addrOk; /* Jump here if the key is OK */ int *aiCols; /* child to parent column mapping */ regResult = pParse->nMem+1; pParse->nMem += 4; regKey = ++pParse->nMem; regRow = ++pParse->nMem; k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash); while( k ){ int iTabDb; if( zRight ){ pTab = sqlite3LocateTable(pParse, 0, zRight, zDb); k = 0; }else{ pTab = (Table*)sqliteHashData(k); k = sqliteHashNext(k); } if( pTab==0 || pTab->pFKey==0 ) continue; iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); sqlite3CodeVerifySchema(pParse, iTabDb); sqlite3TableLock(pParse, iTabDb, pTab->tnum, 0, pTab->zName); if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow; sqlite3OpenTable(pParse, 0, iTabDb, pTab, OP_OpenRead); sqlite3VdbeLoadString(v, regResult, pTab->zName); for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){ pParent = sqlite3FindTable(db, pFK->zTo, zDb); if( pParent==0 ) continue; pIdx = 0; sqlite3TableLock(pParse, iTabDb, pParent->tnum, 0, pParent->zName); x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, 0); if( x==0 ){ if( pIdx==0 ){ sqlite3OpenTable(pParse, i, iTabDb, pParent, OP_OpenRead); }else{ sqlite3VdbeAddOp3(v, OP_OpenRead, i, pIdx->tnum, iTabDb); 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); for(i=1, pFK=pTab->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 ); } 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. */ 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 ); } /* 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); |
︙ | ︙ | |||
1601 1602 1603 1604 1605 1606 1607 | sqlite3VdbeJumpHere(v, addrTop); } } break; #endif /* !defined(SQLITE_OMIT_TRIGGER) */ #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ | < < < < < < < < < < < < < < < | 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 | sqlite3VdbeJumpHere(v, addrTop); } } break; #endif /* !defined(SQLITE_OMIT_TRIGGER) */ #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ /* 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; #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). */ case PragTyp_INTEGRITY_CHECK: { int i, j, addr, mxErr; 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. |
︙ | ︙ | |||
1667 1668 1669 1670 1671 1672 1673 | /* Initialize the VDBE program */ pParse->nMem = 6; /* Set the maximum error count */ mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX; if( zRight ){ | | | | < < < < | 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 | /* Initialize the VDBE program */ pParse->nMem = 6; /* Set the maximum error count */ mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX; if( zRight ){ sqlite3GetInt32(zRight, &mxErr); if( mxErr<=0 ){ mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX; } } 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 */ |
︙ | ︙ | |||
1702 1703 1704 1705 1706 1707 1708 | */ 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 */ | < < < < < | < | 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 | */ 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; for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ Table *pTab = sqliteHashData(x); Index *pIdx; if( HasRowid(pTab) ) aRoot[++cnt] = pTab->tnum; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ aRoot[++cnt] = pIdx->tnum; } } aRoot[0] = cnt; |
︙ | ︙ | |||
1744 1745 1746 1747 1748 1749 1750 | sqlite3VdbeJumpHere(v, addr); /* Make sure all the indices are constructed correctly. */ for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ Table *pTab = sqliteHashData(x); Index *pIdx, *pPk; | | < < < | < < < < < | < < < | < | < < < < < < < < < < < < < < < < < | < < | < < < < < < < < < < < < < < < < < | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < | < < < < < < < < | < < < | | | | | < < | | 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 | sqlite3VdbeJumpHere(v, addr); /* Make sure all the indices are constructed correctly. */ 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; if( pTab->tnum<1 ) continue; /* Skip VIEWs or VIRTUAL TABLEs */ 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->nCol-1, 3); sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); } /* Verify that all NOT NULL columns really are NOT NULL */ for(j=0; j<pTab->nCol; j++){ char *zErr; int jmp2; if( j==pTab->iPKey ) continue; if( pTab->aCol[j].notNull==0 ) continue; sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3); sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v); zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName, pTab->aCol[j].zName); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC); 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); |
︙ | ︙ | |||
1963 1964 1965 1966 1967 1968 1969 | sqlite3VdbeResolveLabel(v, addrCkOk); } 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++){ | | < < < < < < < < < < < < < < < < < < < < < > | 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 | sqlite3VdbeResolveLabel(v, addrCkOk); } 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); VdbeCoverage(v); } |
︙ | ︙ | |||
2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 | } 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); } | > < < | < > | 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 | } sqlite3VdbeJumpHere(v, jmp4); sqlite3ResolvePartIdxLabel(pParse, jmp3); } } sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v); sqlite3VdbeJumpHere(v, loopTop-1); #ifndef SQLITE_OMIT_BTREECOUNT 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); } } #endif /* SQLITE_OMIT_BTREECOUNT */ } } { static const int iLn = VDBE_OFFSET_LINENO(2); static const VdbeOpList endCode[] = { { OP_AddImm, 1, 0, 0}, /* 0 */ { OP_IfNotZero, 1, 4, 0}, /* 1 */ |
︙ | ︙ | |||
2126 2127 2128 2129 2130 2131 2132 | 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. */ | | > > > < | < > | 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 | 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( !(DbHasProperty(db, 0, DB_SchemaLoaded)) || DbHasProperty(db, 0, DB_Empty) ){ for(pEnc=&encnames[0]; pEnc->zName; pEnc++){ if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){ SCHEMA_ENC(db) = ENC(db) = pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE; break; } } if( !pEnc->zName ){ sqlite3ErrorMsg(pParse, "unsupported encoding: %s", zRight); } } |
︙ | ︙ | |||
2194 2195 2196 2197 2198 2199 2200 | 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); | < < < < < < | 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 | 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} }; |
︙ | ︙ | |||
2247 2248 2249 2250 2251 2252 2253 | #ifndef SQLITE_OMIT_WAL /* ** PRAGMA [schema.]wal_checkpoint = passive|full|restart|truncate ** ** Checkpoint the database. */ case PragTyp_WAL_CHECKPOINT: { | | | 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 | #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_ATTACHED); 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 ){ |
︙ | ︙ | |||
2446 2447 2448 2449 2450 2451 2452 | if( zRight && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK ){ sqlite3_soft_heap_limit64(N); } returnSingleInt(v, sqlite3_soft_heap_limit64(-1)); break; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | 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[] = { "unlocked", "shared", "reserved", "pending", "exclusive" |
︙ | ︙ | |||
2533 2534 2535 2536 2537 2538 2539 | } sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zDbSName, zState); } break; } #endif | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > | 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 | } sqlite3VdbeMultiLoad(v, 1, "ss", db->aDb[i].zDbSName, zState); } break; } #endif #ifdef SQLITE_HAS_CODEC /* Pragma iArg ** ---------- ------ ** key 0 ** rekey 1 ** hexkey 2 ** hexrekey 3 ** textkey 4 ** textrekey 5 */ case PragTyp_KEY: { if( zRight ){ int n = pPragma->iArg<4 ? sqlite3Strlen30(zRight) : -1; if( (pPragma->iArg & 1)==0 ){ sqlite3_key_v2(db, zDb, zRight, n); }else{ sqlite3_rekey_v2(db, zDb, zRight, n); } } break; } case PragTyp_HEXKEY: { if( zRight ){ u8 iByte; int i; char zKey[40]; for(i=0, iByte=0; i<sizeof(zKey)*2 && sqlite3Isxdigit(zRight[i]); i++){ iByte = (iByte<<4) + sqlite3HexToInt(zRight[i]); if( (i&1)!=0 ) zKey[i/2] = iByte; } if( (pPragma->iArg & 1)==0 ){ sqlite3_key_v2(db, zDb, zKey, i/2); }else{ sqlite3_rekey_v2(db, zDb, zKey, i/2); } } break; } #endif #if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD) case PragTyp_ACTIVATE_EXTENSIONS: if( zRight ){ #ifdef SQLITE_HAS_CODEC if( sqlite3StrNICmp(zRight, "see-", 4)==0 ){ sqlite3_activate_see(&zRight[4]); } #endif #ifdef SQLITE_ENABLE_CEROD if( sqlite3StrNICmp(zRight, "cerod-", 6)==0 ){ sqlite3_activate_cerod(&zRight[6]); } #endif } 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_HEADER_VALUE 0 #define PragTyp_AUTO_VACUUM 1 #define PragTyp_FLAG 2 #define PragTyp_BUSY_TIMEOUT 3 #define PragTyp_CACHE_SIZE 4 #define PragTyp_CACHE_SPILL 5 #define PragTyp_CASE_SENSITIVE_LIKE 6 #define PragTyp_COLLATION_LIST 7 #define PragTyp_COMPILE_OPTIONS 8 #define PragTyp_DATA_STORE_DIRECTORY 9 #define PragTyp_DATABASE_LIST 10 #define PragTyp_DEFAULT_CACHE_SIZE 11 #define PragTyp_ENCODING 12 #define PragTyp_FOREIGN_KEY_CHECK 13 #define PragTyp_FOREIGN_KEY_LIST 14 #define PragTyp_FUNCTION_LIST 15 #define PragTyp_INCREMENTAL_VACUUM 16 #define PragTyp_INDEX_INFO 17 #define PragTyp_INDEX_LIST 18 #define PragTyp_INTEGRITY_CHECK 19 #define PragTyp_JOURNAL_MODE 20 #define PragTyp_JOURNAL_SIZE_LIMIT 21 #define PragTyp_LOCK_PROXY_FILE 22 #define PragTyp_LOCKING_MODE 23 #define PragTyp_PAGE_COUNT 24 #define PragTyp_MMAP_SIZE 25 #define PragTyp_MODULE_LIST 26 #define PragTyp_OPTIMIZE 27 #define PragTyp_PAGE_SIZE 28 #define PragTyp_PRAGMA_LIST 29 #define PragTyp_SECURE_DELETE 30 #define PragTyp_SHRINK_MEMORY 31 #define PragTyp_SOFT_HEAP_LIMIT 32 #define PragTyp_SYNCHRONOUS 33 #define PragTyp_TABLE_INFO 34 #define PragTyp_TEMP_STORE 35 #define PragTyp_TEMP_STORE_DIRECTORY 36 #define PragTyp_THREADS 37 #define PragTyp_WAL_AUTOCHECKPOINT 38 #define PragTyp_WAL_CHECKPOINT 39 #define PragTyp_ACTIVATE_EXTENSIONS 40 #define PragTyp_HEXKEY 41 #define PragTyp_KEY 42 #define PragTyp_LOCK_STATUS 43 #define PragTyp_STATS 44 /* 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 */ #define PragFlg_Result0 0x10 /* Acts as query when no argument */ |
︙ | ︙ | |||
79 80 81 82 83 84 85 | /* 9 */ "name", /* 10 */ "type", /* 11 */ "notnull", /* 12 */ "dflt_value", /* 13 */ "pk", /* 14 */ "hidden", /* table_info reuses 8 */ | | | | | | | | | | | | | | | | | | | | | > | | | | | | | | < < < < < < < < < < < | | | | | | < < < < < | 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 | /* 9 */ "name", /* 10 */ "type", /* 11 */ "notnull", /* 12 */ "dflt_value", /* 13 */ "pk", /* 14 */ "hidden", /* table_info reuses 8 */ /* 15 */ "seqno", /* Used by: index_xinfo */ /* 16 */ "cid", /* 17 */ "name", /* 18 */ "desc", /* 19 */ "coll", /* 20 */ "key", /* 21 */ "tbl", /* Used by: stats */ /* 22 */ "idx", /* 23 */ "wdth", /* 24 */ "hght", /* 25 */ "flgs", /* 26 */ "seq", /* Used by: index_list */ /* 27 */ "name", /* 28 */ "unique", /* 29 */ "origin", /* 30 */ "partial", /* 31 */ "table", /* Used by: foreign_key_check */ /* 32 */ "rowid", /* 33 */ "parent", /* 34 */ "fkid", /* index_info reuses 15 */ /* 35 */ "seq", /* Used by: database_list */ /* 36 */ "name", /* 37 */ "file", /* 38 */ "busy", /* Used by: wal_checkpoint */ /* 39 */ "log", /* 40 */ "checkpointed", /* 41 */ "name", /* Used by: function_list */ /* 42 */ "builtin", /* collation_list reuses 26 */ /* 43 */ "database", /* Used by: lock_status */ /* 44 */ "status", /* 45 */ "cache_size", /* Used by: default_cache_size */ /* module_list pragma_list reuses 9 */ /* 46 */ "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_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD) {/* zName: */ "activate_extensions", /* ePragTyp: */ PragTyp_ACTIVATE_EXTENSIONS, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #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 |
︙ | ︙ | |||
174 175 176 177 178 179 180 | /* ColNames: */ 0, 0, /* iArg: */ SQLITE_AutoIndex }, #endif #endif {/* zName: */ "busy_timeout", /* ePragTyp: */ PragTyp_BUSY_TIMEOUT, /* ePragFlg: */ PragFlg_Result0, | | < < | | 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 | /* ColNames: */ 0, 0, /* iArg: */ SQLITE_AutoIndex }, #endif #endif {/* zName: */ "busy_timeout", /* ePragTyp: */ PragTyp_BUSY_TIMEOUT, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 46, 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 {/* zName: */ "case_sensitive_like", /* ePragTyp: */ PragTyp_CASE_SENSITIVE_LIKE, /* ePragFlg: */ PragFlg_NoColumns, /* ColNames: */ 0, 0, /* iArg: */ 0 }, {/* 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: */ 26, 2, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS) {/* zName: */ "compile_options", /* ePragTyp: */ PragTyp_COMPILE_OPTIONS, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 0, 0, |
︙ | ︙ | |||
247 248 249 250 251 252 253 | /* ePragFlg: */ PragFlg_ReadOnly|PragFlg_Result0, /* ColNames: */ 0, 0, /* iArg: */ BTREE_DATA_VERSION }, #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) {/* zName: */ "database_list", /* ePragTyp: */ PragTyp_DATABASE_LIST, | | | | | 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 | /* ePragFlg: */ PragFlg_ReadOnly|PragFlg_Result0, /* 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: */ 35, 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: */ 45, 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, |
︙ | ︙ | |||
284 285 286 287 288 289 290 | /* 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, | | | | 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 | /* 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, /* ColNames: */ 31, 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, |
︙ | ︙ | |||
324 325 326 327 328 329 330 | {/* zName: */ "fullfsync", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_FullFSync }, #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) | | | > > > > > > | | | | > | | | | > > > > > > > > > > > > | | 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 | {/* 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_INTROSPECTION_PRAGMAS) {/* zName: */ "function_list", /* ePragTyp: */ PragTyp_FUNCTION_LIST, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 41, 2, /* iArg: */ 0 }, #endif #endif #if defined(SQLITE_HAS_CODEC) {/* zName: */ "hexkey", /* ePragTyp: */ PragTyp_HEXKEY, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, /* iArg: */ 2 }, {/* zName: */ "hexrekey", /* ePragTyp: */ PragTyp_HEXKEY, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, /* iArg: */ 3 }, #endif #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: */ 15, 3, /* iArg: */ 0 }, {/* zName: */ "index_list", /* ePragTyp: */ PragTyp_INDEX_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 26, 5, /* iArg: */ 0 }, {/* zName: */ "index_xinfo", /* ePragTyp: */ PragTyp_INDEX_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 15, 6, /* iArg: */ 1 }, #endif #if !defined(SQLITE_OMIT_INTEGRITY_CHECK) {/* zName: */ "integrity_check", /* ePragTyp: */ PragTyp_INTEGRITY_CHECK, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1, /* 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_HAS_CODEC) {/* zName: */ "key", /* ePragTyp: */ PragTyp_KEY, /* ePragFlg: */ 0, /* 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 }, {/* zName: */ "legacy_file_format", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_LegacyFileFmt }, #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: */ 43, 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, |
︙ | ︙ | |||
429 430 431 432 433 434 435 | /* ePragTyp: */ PragTyp_MMAP_SIZE, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) #if !defined(SQLITE_OMIT_VIRTUALTABLE) | | | 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 | /* 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_INTROSPECTION_PRAGMAS) {/* zName: */ "module_list", /* ePragTyp: */ PragTyp_MODULE_LIST, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 9, 1, /* iArg: */ 0 }, #endif #endif |
︙ | ︙ | |||
464 465 466 467 468 469 470 | {/* zName: */ "parser_trace", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_ParserTrace }, #endif #endif | | | > > > > > > > > > | 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 | {/* zName: */ "parser_trace", /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ SQLITE_ParserTrace }, #endif #endif #if defined(SQLITE_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, /* 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 }, #endif #if defined(SQLITE_HAS_CODEC) {/* zName: */ "rekey", /* ePragTyp: */ PragTyp_KEY, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, /* iArg: */ 1 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* 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) |
︙ | ︙ | |||
546 547 548 549 550 551 552 | /* 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, | | < < < < < > > > > > > > > > > > > < < < < < < < | 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 | /* 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: */ 21, 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_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 #if defined(SQLITE_HAS_CODEC) {/* zName: */ "textkey", /* ePragTyp: */ PragTyp_KEY, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, /* iArg: */ 4 }, {/* zName: */ "textrekey", /* ePragTyp: */ PragTyp_KEY, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, /* iArg: */ 5 }, #endif {/* zName: */ "threads", /* ePragTyp: */ PragTyp_THREADS, /* ePragFlg: */ PragFlg_Result0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, #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 |
︙ | ︙ | |||
642 643 644 645 646 647 648 | /* ePragTyp: */ PragTyp_WAL_AUTOCHECKPOINT, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, {/* zName: */ "wal_checkpoint", /* ePragTyp: */ PragTyp_WAL_CHECKPOINT, /* ePragFlg: */ PragFlg_NeedSchema, | | | | 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 | /* ePragTyp: */ PragTyp_WAL_AUTOCHECKPOINT, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, /* iArg: */ 0 }, {/* zName: */ "wal_checkpoint", /* ePragTyp: */ PragTyp_WAL_CHECKPOINT, /* ePragFlg: */ PragFlg_NeedSchema, /* ColNames: */ 38, 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: 62 on by default, 81 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 | /* ** Fill the InitData structure with an error message that indicates ** that the database is corrupt. */ static void corruptSchema( InitData *pData, /* Initialization context */ const char *zObj, /* Object being parsed at the point of error */ 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_AlterTable ){ *pData->pzErrMsg = sqlite3DbStrDup(db, zExtra); pData->rc = SQLITE_ERROR; }else if( db->flags & SQLITE_WriteSchema ){ pData->rc = SQLITE_CORRUPT_BKPT; }else{ char *z; if( zObj==0 ) zObj = "?"; 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; } /* ** 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: |
︙ | ︙ | |||
96 97 98 99 100 101 102 | 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) ); | | < | > | | < < < < < < < | < < < < < < | < | | | < | | < < | < < | < | 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 | 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) ); DbClearProperty(db, iDb, DB_Empty); pData->nInitRow++; if( db->mallocFailed ){ corruptSchema(pData, argv[1], 0); return 1; } assert( iDb>=0 && iDb<db->nDb ); if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */ if( argv[3]==0 ){ corruptSchema(pData, argv[1], 0); }else if( sqlite3_strnicmp(argv[4],"create ",7)==0 ){ /* 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. */ 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; db->init.newTnum = sqlite3Atoi(argv[3]); db->init.orphanTrigger = 0; db->init.azInit = argv; TESTONLY(rcp = ) sqlite3_prepare(db, argv[4], -1, &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{ pData->rc = rc; if( rc==SQLITE_NOMEM ){ sqlite3OomFault(db); }else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){ corruptSchema(pData, argv[1], sqlite3_errmsg(db)); } } } sqlite3_finalize(pStmt); }else if( argv[1]==0 || (argv[4]!=0 && argv[4][0]!=0) ){ corruptSchema(pData, argv[1], 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 || sqlite3GetInt32(argv[3],&pIndex->tnum)==0 || pIndex->tnum<2 || sqlite3IndexHasDuplicateRootPage(pIndex) ){ corruptSchema(pData, argv[1], pIndex?"invalid rootpage":"orphan index"); } } return 0; } /* ** Attempt to read the database schema and initialize internal |
︙ | ︙ | |||
201 202 203 204 205 206 207 | #ifndef SQLITE_OMIT_DEPRECATED int size; #endif Db *pDb; char const *azArg[6]; int meta[5]; InitData initData; | | < | | | < < | | 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 | #ifndef SQLITE_OMIT_DEPRECATED int size; #endif Db *pDb; char const *azArg[6]; int meta[5]; InitData initData; const char *zMasterName; int openedTransaction = 0; 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_master or ** sqlite_temp_master) 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] = zMasterName = 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; sqlite3InitCallback(&initData, 5, (char **)azArg, 0); 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( !sqlite3BtreeIsInReadTrans(pDb->pBt) ){ rc = sqlite3BtreeBeginTrans(pDb->pBt, 0, 0); if( rc!=SQLITE_OK ){ sqlite3SetString(pzErrMsg, db, sqlite3ErrStr(rc)); goto initone_error_out; } openedTransaction = 1; } |
︙ | ︙ | |||
293 294 295 296 297 298 299 | /* 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 */ | | < > > | < < < | < < < | > > | 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 | /* 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 ){ #ifndef SQLITE_OMIT_UTF16 u8 encoding; /* If opening the main database, set ENC(db). */ encoding = (u8)meta[BTREE_TEXT_ENCODING-1] & 3; if( encoding==0 ) encoding = SQLITE_UTF8; ENC(db) = encoding; #else ENC(db) = SQLITE_UTF8; #endif }else{ /* If opening an attached database, the encoding much match ENC(db) */ if( meta[BTREE_TEXT_ENCODING-1]!=ENC(db) ){ sqlite3SetString(pzErrMsg, db, "attached databases must use the same" " text encoding as main database"); rc = SQLITE_ERROR; goto initone_error_out; } } }else{ DbSetProperty(db, iDb, DB_Empty); } 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; } |
︙ | ︙ | |||
359 360 361 362 363 364 365 | 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 ); | < | < < < > | | | | | | < < | | | 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 | 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, "SELECT*FROM\"%w\".%s ORDER BY rowid", db->aDb[iDb].zDbSName, zMasterName); #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 } if( db->mallocFailed ){ rc = SQLITE_NOMEM_BKPT; sqlite3ResetAllSchemasOfConnection(db); } if( rc==SQLITE_OK || (db->flags&SQLITE_NoSchemaError)){ /* Black magic: If the SQLITE_NoSchemaError flag is set, then consider ** the schema loaded, even if errors 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_master 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 |
︙ | ︙ | |||
433 434 435 436 437 438 439 | /* ** 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 | | > | 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 | /* ** 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. If the database ** file was of zero-length, then the DB_Empty flag is also set. */ 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) ); |
︙ | ︙ | |||
505 506 507 508 509 510 511 | 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. */ | | < < > | | | | | < | < < | < | < | | | | | < | < < | | < < < < > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > < | < < < | | | | 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 | 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( !sqlite3BtreeIsInReadTrans(pBt) ){ rc = sqlite3BtreeBeginTrans(pBt, 0, 0); if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ sqlite3OomFault(db); } 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, ** set Parse.rc to SQLITE_SCHEMA. */ sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&cookie); assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( cookie!=db->aDb[iDb].pSchema->schema_cookie ){ sqlite3ResetOneSchema(db, iDb); pParse->rc = SQLITE_SCHEMA; } /* Close the transaction, if one was opened. */ if( openedTransaction ){ sqlite3BtreeCommit(pBt); } } } /* ** 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 = -1000000; /* If pSchema is NULL, then return -1000000. 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 -1000000 instead of the more usual -1 simply because using ** -1000000 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). */ 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; sqlite3DbFree(db, pParse->aLabel); sqlite3ExprListDelete(db, pParse->pConstExpr); while( pParse->pIdxExpr!=0 ){ IndexedExpr *p = pParse->pIdxExpr; pParse->pIdxExpr = p->pIENext; sqlite3ExprDelete(db, p->pExpr); sqlite3DbFreeNN(db, p); } if( db ){ assert( db->lookaside.bDisable >= pParse->disableLookaside ); db->lookaside.bDisable -= pParse->disableLookaside; } pParse->disableLookaside = 0; } /* ** 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. */ 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 */ ){ char *zErrMsg = 0; /* Error message */ int rc = SQLITE_OK; /* Result code */ int i; /* Loop counter */ Parse sParse; /* Parsing context */ memset(&sParse, 0, PARSE_HDR_SZ); memset(PARSE_TAIL(&sParse), 0, PARSE_TAIL_SZ); sParse.pReprepare = pReprepare; assert( ppStmt && *ppStmt==0 ); /* assert( !db->mallocFailed ); // not true with SQLITE_USE_ALLOCA */ 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++; db->lookaside.bDisable++; } 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. ** |
︙ | ︙ | |||
731 732 733 734 735 736 737 | ** 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. */ | < | | | | | | | | | | < < | < > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | < | < | < < | < < | | | | | | < < < < < < < | | 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 | ** 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. */ 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; if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){ char *zSqlCopy; int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH]; testcase( nBytes==mxLen ); testcase( nBytes==mxLen+1 ); if( nBytes>mxLen ){ sqlite3ErrorWithMsg(db, SQLITE_TOOBIG, "statement too long"); rc = sqlite3ApiExit(db, SQLITE_TOOBIG); goto end_prepare; } zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes); if( zSqlCopy ){ sqlite3RunParser(&sParse, zSqlCopy, &zErrMsg); sParse.zTail = &zSql[sParse.zTail-zSqlCopy]; sqlite3DbFree(db, zSqlCopy); }else{ sParse.zTail = &zSql[nBytes]; } }else{ sqlite3RunParser(&sParse, zSql, &zErrMsg); } assert( 0==sParse.nQueryLoop ); if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK; if( sParse.checkSchema ){ schemaIsValid(&sParse); } if( db->mallocFailed ){ sParse.rc = SQLITE_NOMEM_BKPT; } if( pzTail ){ *pzTail = sParse.zTail; } rc = sParse.rc; #ifndef SQLITE_OMIT_EXPLAIN if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){ static const char * const azColName[] = { "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment", "id", "parent", "notused", "detail" }; int iFirst, mx; if( sParse.explain==2 ){ sqlite3VdbeSetNumCols(sParse.pVdbe, 4); iFirst = 8; mx = 12; }else{ sqlite3VdbeSetNumCols(sParse.pVdbe, 8); iFirst = 0; mx = 8; } for(i=iFirst; i<mx; i++){ sqlite3VdbeSetColName(sParse.pVdbe, i-iFirst, COLNAME_NAME, azColName[i], SQLITE_STATIC); } } #endif if( db->init.busy==0 ){ sqlite3VdbeSetSql(sParse.pVdbe, zSql, (int)(sParse.zTail-zSql), prepFlags); } if( sParse.pVdbe && (rc!=SQLITE_OK || db->mallocFailed) ){ sqlite3VdbeFinalize(sParse.pVdbe); assert(!(*ppStmt)); }else{ *ppStmt = (sqlite3_stmt*)sParse.pVdbe; } if( zErrMsg ){ sqlite3ErrorWithMsg(db, rc, "%s", zErrMsg); sqlite3DbFree(db, zErrMsg); }else{ sqlite3Error(db, rc); } /* Delete any TriggerPrg structures allocated while parsing this statement. */ while( sParse.pTriggerPrg ){ TriggerPrg *pT = sParse.pTriggerPrg; sParse.pTriggerPrg = pT->pNext; sqlite3DbFree(db, pT); } end_prepare: sqlite3ParserReset(&sParse); return rc; } static int sqlite3LockAndPrepare( 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 */ |
︙ | ︙ | |||
847 848 849 850 851 852 853 | sqlite3BtreeEnterAll(db); do{ /* Make multiple attempts to compile the SQL, until it either succeeds ** or encounters a permanent error. A schema problem after one schema ** reset is considered a permanent error. */ rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail); assert( rc==SQLITE_OK || *ppStmt==0 ); | < | < | | 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 | sqlite3BtreeEnterAll(db); do{ /* Make multiple attempts to compile the SQL, until it either succeeds ** or encounters a permanent error. A schema problem after one schema ** reset is considered a permanent error. */ 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 ** locked the sqlite3_master 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 etSRCLIST 12 /* a pointer to a SrcList */ #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 | { '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, etSRCLIST, 0, 0 }, { 'r', 10, 1, etORDINAL, 0, 0 }, }; /* ** If SQLITE_OMIT_FLOATING_POINT is defined, then none of the floating point ** conversions will work. */ #ifndef SQLITE_OMIT_FLOATING_POINT /* ** "*val" is a double such that 0.1 <= *val < 10.0 |
︙ | ︙ | |||
141 142 143 144 145 146 147 | return (char)digit; } #endif /* SQLITE_OMIT_FLOATING_POINT */ /* ** Set the StrAccum object to an error mode. */ | | | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | return (char)digit; } #endif /* SQLITE_OMIT_FLOATING_POINT */ /* ** Set the StrAccum object to an error mode. */ static void setStrAccumError(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); } /* |
︙ | ︙ | |||
177 178 179 180 181 182 183 | ** 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 ){ | | | < < < < < < < | 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 | ** 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 ){ setStrAccumError(pAccum, SQLITE_TOOBIG); return 0; } z = sqlite3DbMallocRaw(pAccum->db, n); if( z==0 ){ setStrAccumError(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 */ /* ** 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 */ |
︙ | ︙ | |||
403 404 405 406 407 408 409 | ** 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. */ | < < | | | < | > | > | 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 | ** 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; /* Fall through into the next case */ case etORDINAL: case etRADIX: cThousand = 0; /* Fall through into the next case */ 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 ){ if( v==SMALLEST_INT64 ){ longvalue = ((u64)1)<<63; }else{ longvalue = -v; } prefix = '-'; }else{ longvalue = v; prefix = flag_prefix; } }else{ if( bArgList ){ |
︙ | ︙ | |||
525 526 527 528 529 530 531 | }else{ realvalue = va_arg(ap,double); } #ifdef SQLITE_OMIT_FLOATING_POINT length = 0; #else if( precision<0 ) precision = 6; /* Set default precision */ | < < < < < | < < | < < < < < < < < | 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 | }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 ); for(idx=precision&0xfff, rounder=0.5; idx>0; idx--, rounder*=0.1){} if( xtype==etFLOAT ) realvalue += rounder; /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ exp = 0; if( sqlite3IsNaN((double)realvalue) ){ bufpt = "NaN"; length = 3; break; } |
︙ | ︙ | |||
732 733 734 735 736 737 738 | buf[1] = 0x80 + (u8)((ch>>12) & 0x3f); buf[2] = 0x80 + (u8)((ch>>6) & 0x3f); buf[3] = 0x80 + (u8)(ch & 0x3f); length = 4; } } if( precision>1 ){ | < < < | < < < < < < < | < < < | 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 | buf[1] = 0x80 + (u8)((ch>>12) & 0x3f); buf[2] = 0x80 + (u8)((ch>>6) & 0x3f); buf[3] = 0x80 + (u8)(ch & 0x3f); length = 4; } } if( precision>1 ){ width -= precision-1; if( width>1 && !flag_leftjustify ){ sqlite3_str_appendchar(pAccum, width-1, ' '); width = 0; } while( precision-- > 1 ){ sqlite3_str_append(pAccum, buf, length); } } bufpt = buf; flag_altform2 = 1; goto adjust_width_for_utf8; case etSTRING: case etDYNSTRING: |
︙ | ︙ | |||
812 813 814 815 816 817 818 | int ii = length - 1; while( ii>=0 ) if( (bufpt[ii--] & 0xc0)==0x80 ) width++; } break; case etSQLESCAPE: /* %q: Escape ' characters */ case etSQLESCAPE2: /* %Q: Escape ' and enclose in '...' */ case etSQLESCAPE3: { /* %w: Escape " characters */ | | | | | 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 | int ii = length - 1; while( ii>=0 ) if( (bufpt[ii--] & 0xc0)==0x80 ) width++; } break; case etSQLESCAPE: /* %q: Escape ' characters */ case etSQLESCAPE2: /* %Q: Escape ' and enclose in '...' */ case etSQLESCAPE3: { /* %w: Escape " characters */ int i, j, k, n, isnull; int needQuote; char ch; char q = ((xtype==etSQLESCAPE3)?'"':'\''); /* Quote character */ char *escarg; 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 byte (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++; |
︙ | ︙ | |||
858 859 860 861 862 863 864 865 | } if( needQuote ) bufpt[j++] = q; bufpt[j] = 0; length = j; goto adjust_width_for_utf8; } case etTOKEN: { if( (pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return; | > < < < < < < < < < | | | | < < | > > | | > > < < < > | | | | | < < < < < < < < < < < | 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 | } if( needQuote ) bufpt[j++] = q; bufpt[j] = 0; length = j; goto adjust_width_for_utf8; } case etTOKEN: { Token *pToken; if( (pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return; pToken = va_arg(ap, Token*); assert( bArgList==0 ); if( pToken && pToken->n ){ sqlite3_str_append(pAccum, (const char*)pToken->z, pToken->n); } length = width = 0; break; } case etSRCLIST: { SrcList *pSrc; int k; struct SrcList_item *pItem; if( (pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return; pSrc = va_arg(ap, SrcList*); k = va_arg(ap, int); pItem = &pSrc->a[k]; assert( bArgList==0 ); assert( k>=0 && k<pSrc->nSrc ); if( pItem->zDatabase ){ sqlite3_str_appendall(pAccum, pItem->zDatabase); sqlite3_str_append(pAccum, ".", 1); } sqlite3_str_appendall(pAccum, pItem->zName); length = width = 0; break; } default: { assert( xtype==etINVALID ); return; } |
︙ | ︙ | |||
934 935 936 937 938 939 940 | if( zExtra ){ sqlite3DbFree(pAccum->db, zExtra); zExtra = 0; } }/* End for loop over the format string */ } /* End of function */ | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | > | | | < | | 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 | if( zExtra ){ sqlite3DbFree(pAccum->db, zExtra); zExtra = 0; } }/* End for loop over the format string */ } /* End of function */ /* ** Enlarge the memory allocation on a StrAccum object so that it is ** able to accept at least N more bytes of text. ** ** Return the number of bytes of text that StrAccum is able to accept ** after the attempted enlargement. The value returned might be zero. */ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){ char *zNew; 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 ){ setStrAccumError(p, SQLITE_TOOBIG); return p->nAlloc - p->nChar - 1; }else{ char *zOld = isMalloced(p) ? p->zText : 0; i64 szNew = p->nChar; szNew += 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); setStrAccumError(p, SQLITE_TOOBIG); return 0; }else{ p->nAlloc = (int)szNew; } if( p->db ){ zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc); }else{ zNew = sqlite3_realloc64(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); setStrAccumError(p, SQLITE_NOMEM); return 0; } } return N; } /* ** Append N copies of character c to the given string buffer. */ void sqlite3_str_appendchar(sqlite3_str *p, int N, char c){ testcase( p->nChar + (i64)N > 0x7fffffff ); |
︙ | ︙ | |||
1092 1093 1094 1095 1096 1097 1098 | 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{ | | < < < < < < < < < < < < < < < < | 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 | 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{ setStrAccumError(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; } /* ** 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. */ static sqlite3_str sqlite3OomStr = { |
︙ | ︙ | |||
1367 1368 1369 1370 1371 1372 1373 | ** 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; | | | 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 | ** 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[500]; 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.
︙ | ︙ | |||
18 19 20 21 22 23 24 | #include "sqliteInt.h" /* All threads share a single random number generator. ** This structure is the current state of the generator. */ static SQLITE_WSD struct sqlite3PrngType { | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < > | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | #include "sqliteInt.h" /* All threads share a single random number generator. ** This structure is the current state of the generator. */ static SQLITE_WSD struct sqlite3PrngType { unsigned char isInit; /* True if initialized */ unsigned char i, j; /* State variables */ unsigned char s[256]; /* State variables */ } sqlite3Prng; /* ** Return N random bytes. */ void sqlite3_randomness(int N, void *pBuf){ unsigned char t; unsigned char *zBuf = pBuf; /* The "wsdPrng" macro will resolve to the pseudo-random number generator ** state vector. If writable static data is unsupported on the target, ** we have to locate the state vector at run-time. In the more common ** case where writable static data is supported, wsdPrng can refer directly ** to the "sqlite3Prng" state vector declared above. |
︙ | ︙ | |||
82 83 84 85 86 87 88 | #if SQLITE_THREADSAFE mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG); #endif sqlite3_mutex_enter(mutex); if( N<=0 || pBuf==0 ){ | | | > > > > > > | < > | < < | < | < | > > > > | > | > | < < < > | < < | < | | < | | | | | 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 | #if SQLITE_THREADSAFE mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG); #endif sqlite3_mutex_enter(mutex); if( N<=0 || pBuf==0 ){ wsdPrng.isInit = 0; sqlite3_mutex_leave(mutex); return; } /* Initialize the state of the random number generator once, ** the first time this routine is called. The seed value does ** not need to contain a lot of randomness since we are not ** 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; sqlite3OsRandomness(sqlite3_vfs_find(0), 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]; wsdPrng.s[i] = t; } wsdPrng.isInit = 1; } assert( N>0 ); do{ wsdPrng.i++; t = wsdPrng.s[wsdPrng.i]; wsdPrng.j += t; 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 |
︙ | ︙ |
Changes to src/resolve.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 | ** ** 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" | < < < < < < < | 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 ){ |
︙ | ︙ | |||
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | ** 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); | > < < | < < | < | > > > > > > > > | | | | > | | > | > > | | > > > > > > > > > > > > > > | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | ** 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 */ const char *zType, /* "GROUP" or "ORDER" or "" */ 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( pDup!=0 ){ if( zType[0]!='G' ) incrAggFunctionDepth(pDup, nSubquery); if( pExpr->op==TK_COLLATE ){ 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; } sqlite3DbFree(db, pDup); } ExprSetProperty(pExpr, EP_Alias); } /* ** 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 ** zCol. */ static int nameInUsingClause(IdList *pUsing, const char *zCol){ if( pUsing ){ int k; for(k=0; k<pUsing->nId; k++){ if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ) return 1; } } return 0; } /* ** 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 sqlite3MatchSpanName( const char *zSpan, const char *zCol, const char *zTab, const char *zDb ){ int n; 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; } /* ** 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: ** ** pExpr->iDb Set the index in db->aDb[] of the database X |
︙ | ︙ | |||
264 265 266 267 268 269 270 | 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 */ | | | | < < | 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 | 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 */ struct SrcList_item *pItem; /* Use for looping over pSrcList items */ struct SrcList_item *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. */ assert( zCol ); /* The Z in X.Y.Z cannot be NULL */ assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) ); /* Initialize the node to no-match */ pExpr->iTable = -1; ExprSetVVAProperty(pExpr, EP_NoReduce); /* Translate the schema name in zDb into a pointer to the corresponding |
︙ | ︙ | |||
303 304 305 306 307 308 309 | 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; } } | < < < < < < < | < | < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | < | < | > | > > < | < < | | | | < < < < < > | > < | < > > > > | | < < < < < < < < < < | < < < < < < < < < < < < < < < < < < > > | | < | < < < < < < < | | | | < < | < < | < | < > < < < < < < < < < < < | | | | | | | | | | | > > > < | | | < | > | < | < | | | < < | | 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 | 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 ); assert( pTab->nCol>0 ); if( pItem->pSelect && (pItem->pSelect->selFlags & SF_NestedFrom)!=0 ){ int hit = 0; pEList = pItem->pSelect->pEList; for(j=0; j<pEList->nExpr; j++){ if( sqlite3MatchSpanName(pEList->a[j].zSpan, 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; } if( IN_RENAME_OBJECT && pItem->zAlias ){ sqlite3RenameTokenRemap(pParse, 0, (void*)&pExpr->y.pTab); } } if( 0==(cntTab++) ){ pMatch = pItem; } for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){ if( sqlite3StrICmp(pCol->zName, 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( pMatch ){ pExpr->iTable = pMatch->iCursor; 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. */ if( zDb==0 && zTab!=0 && cntTab==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( op!=TK_DELETE && sqlite3StrICmp("new",zTab) == 0 ){ pExpr->iTable = 1; pTab = pParse->pTriggerTab; }else if( op!=TK_INSERT && sqlite3StrICmp("old",zTab)==0 ){ pExpr->iTable = 0; pTab = pParse->pTriggerTab; } } #endif /* SQLITE_OMIT_TRIGGER */ #ifndef SQLITE_OMIT_UPSERT if( (pNC->ncFlags & NC_UUpsert)!=0 ){ Upsert *pUpsert = pNC->uNC.pUpsert; if( pUpsert && sqlite3StrICmp("excluded",zTab)==0 ){ pTab = pUpsert->pUpsertSrc->a[0].pTab; pExpr->iTable = 2; } } #endif /* SQLITE_OMIT_UPSERT */ if( pTab ){ int iCol; pSchema = pTab->pSchema; cntTab++; for(iCol=0, pCol=pTab->aCol; iCol<pTab->nCol; iCol++, pCol++){ if( sqlite3StrICmp(pCol->zName, 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++; #ifndef SQLITE_OMIT_UPSERT if( pExpr->iTable==2 ){ testcase( iCol==(-1) ); if( IN_RENAME_OBJECT ){ pExpr->iColumn = iCol; pExpr->y.pTab = pTab; eNewExprOp = TK_COLUMN; }else{ pExpr->iTable = pNC->uNC.pUpsert->regData + iCol; eNewExprOp = TK_REGISTER; ExprSetProperty(pExpr, EP_Alias); } }else #endif /* SQLITE_OMIT_UPSERT */ { #ifndef SQLITE_OMIT_TRIGGER if( iCol<0 ){ pExpr->affinity = 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)); } pExpr->y.pTab = pTab; pExpr->iColumn = (i16)iCol; eNewExprOp = TK_TRIGGER; #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)==0 && sqlite3IsRowid(zCol) && VisibleRowid(pMatch->pTab) ){ cnt = 1; pExpr->iColumn = -1; pExpr->affinity = 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( (pNC->ncFlags & NC_UEList)!=0 && cnt==0 && zTab==0 ){ pEList = pNC->uNC.pEList; assert( pEList!=0 ); for(j=0; j<pEList->nExpr; j++){ char *zAs = pEList->a[j].zName; if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){ Expr *pOrig; assert( pExpr->pLeft==0 && pExpr->pRight==0 ); assert( pExpr->x.pList==0 ); assert( pExpr->x.pSelect==0 ); 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( (pNC->ncFlags&NC_AllowWin)==0 && ExprHasProperty(pOrig, EP_Win) ){ 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; |
︙ | ︙ | |||
652 653 654 655 656 657 658 | ** 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 ); | | < < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < | < < < < < | < < < | > > > > > > | > > > > > > > < | < < < | 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 | ** 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) ){ /* 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; pExpr->y.pTab = 0; return WRC_Prune; } if( sqlite3ExprIdToTrueFalse(pExpr) ){ return WRC_Prune; } } /* ** cnt==0 means there was not match. cnt>1 means there were two or ** more matches. Either way, we have an error. */ if( cnt!=1 ){ const char *zErr; zErr = cnt==0 ? "no such column" : "ambiguous column name"; if( zDb ){ 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->nErr++; } /* 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. If the ** column number is greater than the number of bits in the bitmask ** then set the high-order bit of the bitmask. */ if( pExpr->iColumn>=0 && pMatch!=0 ){ int n = pExpr->iColumn; testcase( n==BMS-1 ); if( n>=BMS ){ n = BMS-1; } assert( pMatch->iCursor==pExpr->iTable ); pMatch->colUsed |= ((Bitmask)1)<<n; } /* Clean up and return */ 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 ); if( !ExprHasProperty(pExpr, EP_Alias) ){ sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList); } /* Increment the nRef value on all name contexts from TopNC up to ** the point where the name matched. */ for(;;){ assert( pTopNC!=0 ); pTopNC->nRef++; if( pTopNC==pNC ) break; pTopNC = pTopNC->pNext; |
︙ | ︙ | |||
788 789 790 791 792 793 794 | /* ** 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 ){ | | < < | < < < < < < < | | | < < < < < < < < < < < < < | | | | < < > > > | | | < < < | < < | < < < > < | 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 | /* ** 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 ){ struct SrcList_item *pItem = &pSrc->a[iSrc]; p->y.pTab = pItem->pTab; p->iTable = pItem->iCursor; if( p->y.pTab->iPKey==iCol ){ p->iColumn = -1; }else{ p->iColumn = (ynVar)iCol; 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 */ ){ assert( (validMask&~(NC_IsCheck|NC_PartIdx|NC_IdxExpr))==0 ); if( (pNC->ncFlags & validMask)!=0 ){ 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 sqlite3ErrorMsg(pParse, "%s prohibited in %s", zMsg, zIn); } } /* ** 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; 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); } /* |
︙ | ︙ | |||
898 899 900 901 902 903 904 905 906 | 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 | > | < | | > < | | | < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < > | < < | > | | | | | | | | < < | | < < | | < < < < | | < < < < < < < | | | | | | | | | | | | | < < < < < < < < | | < | < < < < < | | | < > | > > > > > > > > | < < < < < < | < < | | < < | | < | < < < < < | < | < < < < < | < | | | < < < | | 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 | for(i=0; i<pNC->pSrcList->nSrc; i++){ assert( pSrcList->a[i].iCursor>=0 && pSrcList->a[i].iCursor<pParse->nTab); } } #endif switch( pExpr->op ){ #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) /* 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. */ case TK_ROW: { SrcList *pSrcList = pNC->pSrcList; struct SrcList_item *pItem; assert( pSrcList && pSrcList->nSrc==1 ); pItem = pSrcList->a; assert( HasRowid(pItem->pTab) && pItem->pTab->pSelect==0 ); pExpr->op = TK_COLUMN; pExpr->y.pTab = pItem->pTab; pExpr->iTable = pItem->iCursor; pExpr->iColumn = -1; pExpr->affinity = SQLITE_AFF_INTEGER; break; } #endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) */ /* 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; zColumn = pExpr->u.zToken; }else{ Expr *pLeft = pExpr->pLeft; notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr); pRight = pExpr->pRight; if( pRight->op==TK_ID ){ zDb = 0; }else{ assert( pRight->op==TK_DOT ); zDb = pLeft->u.zToken; pLeft = pRight->pLeft; pRight = pRight->pRight; } zTable = pLeft->u.zToken; zColumn = pRight->u.zToken; 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)); assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); 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|EP_Skip); 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->nErr++; } }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 ** for likelihood(X,0.9375). ** EVIDENCE-OF: R-53436-40973 The likely(X) function is equivalent ** to likelihood(X,0.9375). */ /* TUNING: unlikely() probability is 0.0625. likely() is 0.9375 */ pExpr->iTable = pDef->zName[0]=='u' ? 8388608 : 125829120; } } #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->nErr++; } 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 */ ExprSetProperty(pExpr,EP_ConstFunc); } if( (pDef->funcFlags & SQLITE_FUNC_CONSTANT)==0 ){ /* Date/time functions that use 'now', and other functions like ** sqlite_version() that might change over time cannot be used ** in an index. */ notValid(pParse, pNC, "non-deterministic functions", NC_IdxExpr|NC_PartIdx); } if( (pDef->funcFlags & SQLITE_FUNC_INTERNAL)!=0 && pParse->nested==0 && sqlite3Config.bInternalFunctions==0 ){ /* Internal-use-only functions are disallowed unless the ** SQL is being compiled using sqlite3NestedParse() */ no_such_func = 1; pDef = 0; } } 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 && ExprHasProperty(pExpr, EP_WinFunc) ){ sqlite3ErrorMsg(pParse, "%.*s() may not be used as a window function", nId, zId ); pNC->nErr++; }else if( (is_agg && (pNC->ncFlags & NC_AllowAgg)==0) || (is_agg && (pDef->funcFlags&SQLITE_FUNC_WINDOW) && !pExpr->y.pWin) || (is_agg && pExpr->y.pWin && (pNC->ncFlags & NC_AllowWin)==0) ){ const char *zType; if( (pDef->funcFlags & SQLITE_FUNC_WINDOW) || pExpr->y.pWin ){ zType = "window"; }else{ zType = "aggregate"; } sqlite3ErrorMsg(pParse, "misuse of %s function %.*s()",zType,nId,zId); pNC->nErr++; is_agg = 0; } #else if( (is_agg && (pNC->ncFlags & NC_AllowAgg)==0) ){ sqlite3ErrorMsg(pParse,"misuse of aggregate function %.*s()",nId,zId); pNC->nErr++; 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->nErr++; }else if( wrong_num_args ){ sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()", nId, zId); pNC->nErr++; } 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 | (!pExpr->y.pWin ? NC_AllowAgg : 0)); #else pNC->ncFlags &= ~NC_AllowAgg; #endif } } sqlite3WalkExprList(pWalker, pList); if( is_agg ){ #ifndef SQLITE_OMIT_WINDOWFUNC if( pExpr->y.pWin ){ Select *pSel = pNC->pWinSelect; Window *pWin = pExpr->y.pWin; if( IN_RENAME_OBJECT==0 ){ sqlite3WindowUpdate(pParse, pSel->pWinDefn, pWin, pDef); } sqlite3WalkExprList(pWalker, pWin->pPartition); sqlite3WalkExprList(pWalker, pWin->pOrderBy); sqlite3WalkExpr(pWalker, pWin->pFilter); if( 0==pSel->pWin || 0==sqlite3WindowCompare(pParse, pSel->pWin, pExpr->y.pWin) ){ pWin->pNextWin = pSel->pWin; if( pSel->pWin ){ pSel->pWin->ppThis = &pWin->pNextWin; } pSel->pWin = pWin; pWin->ppThis = &pSel->pWin; } pNC->ncFlags |= NC_HasWin; }else #endif /* SQLITE_OMIT_WINDOWFUNC */ { NameContext *pNC2 = pNC; pExpr->op = TK_AGG_FUNCTION; pExpr->op2 = 0; while( pNC2 && !sqlite3FunctionUsesThisSrc(pExpr, pNC2->pSrcList) ){ pExpr->op2++; pNC2 = pNC2->pNext; } assert( pDef!=0 ); if( pNC2 ){ assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg ); testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 ); pNC2->ncFlags |= NC_HasAgg | (pDef->funcFlags & SQLITE_FUNC_MINMAX); } } 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( ExprHasProperty(pExpr, EP_xIsSelect) ){ int nRef = pNC->nRef; notValid(pParse, pNC, "subqueries", NC_IsCheck|NC_PartIdx|NC_IdxExpr); 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: { notValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr); break; } case TK_IS: case TK_ISNOT: { Expr *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( (pRight = pExpr->pRight)->op==TK_ID ){ 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; } } /* Fall thru */ } 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 ){ 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); } if( nLeft!=nRight ){ 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 ); testcase( pExpr->op==TK_IS ); testcase( pExpr->op==TK_ISNOT ); testcase( pExpr->op==TK_BETWEEN ); sqlite3ErrorMsg(pParse, "row value misused"); } break; } } return (pParse->nErr || pParse->db->mallocFailed) ? WRC_Abort : WRC_Continue; } /* ** pEList is a list of expressions which are really the result set of the ** a SELECT statement. pE is a term in an ORDER BY or GROUP BY clause. ** This routine checks to see if pE is a simple identifier which corresponds ** to the AS-name of one of the terms of the expression list. If it is, |
︙ | ︙ | |||
1346 1347 1348 1349 1350 1351 1352 | Expr *pE /* Expression we are trying to match */ ){ int i; /* Loop counter */ UNUSED_PARAMETER(pParse); if( pE->op==TK_ID ){ | < < | | | < | 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 | Expr *pE /* Expression we are trying to match */ ){ int i; /* Loop counter */ UNUSED_PARAMETER(pParse); if( pE->op==TK_ID ){ char *zCol = pE->u.zToken; for(i=0; i<pEList->nExpr; i++){ char *zAs = pEList->a[i].zName; if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){ return i+1; } } } return 0; } |
︙ | ︙ | |||
1399 1400 1401 1402 1403 1404 1405 | /* 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; | | | | 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 | /* 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.nErr = 0; db = pParse->db; savedSuppErr = db->suppressErr; db->suppressErr = 1; rc = sqlite3ResolveExprNames(&nc, pE); db->suppressErr = savedSuppErr; if( rc ) return 0; |
︙ | ︙ | |||
1429 1430 1431 1432 1433 1434 1435 | /* ** Generate an ORDER BY or GROUP BY term out-of-range error. */ static void resolveOutOfRangeError( Parse *pParse, /* The error context into which to write the error */ const char *zType, /* "ORDER" or "GROUP" */ int i, /* The index (1-based) of the term out of range */ | | < < | 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 | /* ** Generate an ORDER BY or GROUP BY term out-of-range error. */ static void resolveOutOfRangeError( Parse *pParse, /* The error context into which to write the error */ const char *zType, /* "ORDER" or "GROUP" */ int i, /* The index (1-based) of the term out of range */ int mx /* Largest permissible value of i */ ){ sqlite3ErrorMsg(pParse, "%r %s BY term out of range - should be " "between 1 and %d", i, zType, mx); } /* ** Analyze the ORDER BY clause in a compound SELECT statement. Modify ** each term of the ORDER BY clause is a constant integer between 1 ** and N where N is the number of columns in the compound SELECT. ** |
︙ | ︙ | |||
1471 1472 1473 1474 1475 1476 1477 | if( pOrderBy==0 ) return 0; db = pParse->db; if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){ sqlite3ErrorMsg(pParse, "too many terms in ORDER BY clause"); return 1; } for(i=0; i<pOrderBy->nExpr; i++){ | | | | < | | | > > | | > > > | > < < | < > | > | | | | 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 | if( pOrderBy==0 ) return 0; db = pParse->db; if( pOrderBy->nExpr>db->aLimit[SQLITE_LIMIT_COLUMN] ){ sqlite3ErrorMsg(pParse, "too many terms in ORDER BY clause"); return 1; } for(i=0; i<pOrderBy->nExpr; i++){ pOrderBy->a[i].done = 0; } pSelect->pNext = 0; while( pSelect->pPrior ){ pSelect->pPrior->pNext = pSelect; pSelect = pSelect->pPrior; } while( pSelect && moreToDo ){ struct ExprList_item *pItem; 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 = sqlite3ExprSkipCollate(pItem->pExpr); 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. ** ** Or, if this is running as part of an ALTER TABLE operation, ** resolve the symbols in the actual expression, not a duplicate. ** And, if one of the comparisons is successful, leave the expression ** as is instead of transforming it to an integer as in the usual ** case. This allows the code in alter.c to modify column ** refererences within the ORDER BY expression as required. */ if( IN_RENAME_OBJECT ){ pDup = pE; }else{ pDup = sqlite3ExprDup(db, pE, 0); } if( !db->mallocFailed ){ assert(pDup); iCol = resolveOrderByTermToExprList(pParse, pSelect, pDup); } if( !IN_RENAME_OBJECT ){ 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; } for(i=0; i<pOrderBy->nExpr; i++){ if( pOrderBy->a[i].done==0 ){ sqlite3ErrorMsg(pParse, "%r ORDER BY term does not match any " "column in the result set", i+1); return 1; } } return 0; } |
︙ | ︙ | |||
1577 1578 1579 1580 1581 1582 1583 | const char *zType /* "ORDER" or "GROUP" */ ){ int i; sqlite3 *db = pParse->db; ExprList *pEList; struct ExprList_item *pItem; | | | | > < | > > > > | 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 | const char *zType /* "ORDER" or "GROUP" */ ){ int i; sqlite3 *db = pParse->db; ExprList *pEList; struct ExprList_item *pItem; if( pOrderBy==0 || pParse->db->mallocFailed ) 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, zType,0); } } return 0; } #ifndef SQLITE_OMIT_WINDOWFUNC /* ** Walker callback for windowRemoveExprFromSelect(). */ static int resolveRemoveWindowsCb(Walker *pWalker, Expr *pExpr){ if( ExprHasProperty(pExpr, EP_WinFunc) ){ Window *pWin = pExpr->y.pWin; if( pWin->ppThis ){ *pWin->ppThis = pWin->pNextWin; if( pWin->pNextWin ) pWin->pNextWin->ppThis = pWin->ppThis; pWin->ppThis = 0; } } return WRC_Continue; } /* ** Remove any Window objects owned by the expression pExpr from the ** Select.pWin list of Select object pSelect. |
︙ | ︙ | |||
1656 1657 1658 1659 1660 1661 1662 | ){ 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 */ | | | < | | 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 | ){ 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 */ if( pOrderBy==0 ) return 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 = sqlite3ExprSkipCollate(pE); 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. */ pItem->u.x.iOrderByCol = (u16)iCol; continue; } } if( sqlite3ExprIsInteger(pE2, &iCol) ){ /* The ORDER BY term is an integer constant. Again, set the column ** number so that sqlite3ResolveOrderGroupBy() will convert the ** order-by term to a copy of the result-set expression */ if( iCol<1 || iCol>0xffff ){ resolveOutOfRangeError(pParse, zType, i+1, nResult); return 1; } pItem->u.x.iOrderByCol = (u16)iCol; continue; } /* Otherwise, treat the ORDER BY term as an ordinary expression */ |
︙ | ︙ | |||
1737 1738 1739 1740 1741 1742 1743 | ** prior call to sqlite3SelectExpand(). When that happens, let ** sqlite3SelectPrep() do all of the processing for this SELECT. ** sqlite3SelectPrep() will invoke both sqlite3SelectExpand() and ** this routine in the correct order. */ if( (p->selFlags & SF_Expanded)==0 ){ sqlite3SelectPrep(pParse, p, pOuterNC); | | < < | 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 | ** prior call to sqlite3SelectExpand(). When that happens, let ** sqlite3SelectPrep() do all of the processing for this SELECT. ** sqlite3SelectPrep() will invoke both sqlite3SelectExpand() and ** this routine in the correct order. */ if( (p->selFlags & SF_Expanded)==0 ){ sqlite3SelectPrep(pParse, p, pOuterNC); return (pParse->nErr || db->mallocFailed) ? WRC_Abort : WRC_Prune; } 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; |
︙ | ︙ | |||
1774 1775 1776 1777 1778 1779 1780 | 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; } | | | > | > > > > > > > | < < < < < < < | | | < | 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 | 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 */ for(i=0; i<p->pSrc->nSrc; i++){ struct SrcList_item *pItem = &p->pSrc->a[i]; if( pItem->pSelect && (pItem->pSelect->selFlags & SF_Resolved)==0 ){ NameContext *pNC; /* Used to iterate name contexts */ int nRef = 0; /* Refcount for pOuterNC and outer contexts */ const char *zSavedContext = pParse->zAuthContext; /* Count the total number of references to pOuterNC and all of its ** parent contexts. After resolving references to expressions in ** pItem->pSelect, check if this value has changed. If so, then ** SELECT statement pItem->pSelect must be correlated. Set the ** pItem->fg.isCorrelated flag if this is the case. */ for(pNC=pOuterNC; pNC; pNC=pNC->pNext) nRef += pNC->nRef; if( pItem->zName ) pParse->zAuthContext = pItem->zName; sqlite3ResolveSelectNames(pParse, pItem->pSelect, pOuterNC); pParse->zAuthContext = zSavedContext; if( pParse->nErr || db->mallocFailed ) return WRC_Abort; for(pNC=pOuterNC; pNC; pNC=pNC->pNext) nRef -= pNC->nRef; assert( pItem->fg.isCorrelated==0 && nRef<=0 ); pItem->fg.isCorrelated = (nRef!=0); } } /* Set up the local name-context to pass to sqlite3ResolveExprNames() to ** resolve the result-set expression list. */ sNC.ncFlags = NC_AllowAgg|NC_AllowWin; |
︙ | ︙ | |||
1819 1820 1821 1822 1823 1824 1825 | /* 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 ); | < | > > > > > > > | < < < < < | < | < < < < < < < < < < < < < | 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 | /* 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 ); p->selFlags |= SF_Aggregate | (sNC.ncFlags&NC_MinMaxAgg); }else{ sNC.ncFlags &= ~NC_AllowAgg; } /* If a HAVING clause is present, then there must be a GROUP BY clause. */ if( p->pHaving && !pGroupBy ){ sqlite3ErrorMsg(pParse, "a GROUP BY clause is required before HAVING"); return WRC_Abort; } /* 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))==0 ); sNC.uNC.pEList = p->pEList; sNC.ncFlags |= NC_UEList; 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++){ struct SrcList_item *pItem = &p->pSrc->a[i]; if( pItem->fg.isTabFunc && sqlite3ResolveExprListNames(&sNC, pItem->u1.pFuncArg) ){ return WRC_Abort; } } /* The ORDER BY and GROUP BY clauses may not refer to terms in ** outer queries */ sNC.pNext = 0; sNC.ncFlags |= NC_AllowAgg|NC_AllowWin; /* If this is a converted compound query, move the ORDER BY clause from |
︙ | ︙ | |||
1895 1896 1897 1898 1899 1900 1901 | ** 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. */ | < | | 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 | ** 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( 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; } |
︙ | ︙ | |||
1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 | if( ExprHasProperty(pItem->pExpr, EP_Agg) ){ sqlite3ErrorMsg(pParse, "aggregate functions are not allowed in " "the GROUP BY clause"); return WRC_Abort; } } } /* If this is part of a compound SELECT, check that it has the right ** number of expressions in the select list. */ if( p->pNext && p->pEList->nExpr!=p->pNext->pEList->nExpr ){ sqlite3SelectWrongNumTermsError(pParse, p->pNext); return WRC_Abort; } | > > > > > > > > > > > > > | 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 | if( ExprHasProperty(pItem->pExpr, EP_Agg) ){ sqlite3ErrorMsg(pParse, "aggregate functions are not allowed in " "the GROUP BY clause"); 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 /* If this is part of a compound SELECT, check that it has the right ** number of expressions in the select list. */ if( p->pNext && p->pEList->nExpr!=p->pNext->pEList->nExpr ){ sqlite3SelectWrongNumTermsError(pParse, p->pNext); return WRC_Abort; } |
︙ | ︙ | |||
1999 2000 2001 2002 2003 2004 2005 | ** 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. */ ){ | | | | | | < < | < < < < < < < | < < < < < | < < < < < < < < < < < < < < | < < < | 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 | ** 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. */ ){ u16 savedHasAgg; Walker w; if( pExpr==0 ) return SQLITE_OK; savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin); pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin); w.pParse = pNC->pParse; w.xExprCallback = resolveExprStep; w.xSelectCallback = 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->nErr>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; if( pList ){ for(i=0; i<pList->nExpr; i++){ if( sqlite3ResolveExprNames(pNC, pList->a[i].pExpr) ) return WRC_Abort; } } 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 |
︙ | ︙ | |||
2110 2111 2112 2113 2114 2115 2116 | sqlite3WalkSelect(&w, p); } /* ** Resolve names in expressions that can only reference a single table ** or which cannot reference any tables at all. Examples: ** | < < | | | | < | | | | | | < < < < < < | | 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 | sqlite3WalkSelect(&w, p); } /* ** Resolve names in expressions that can only reference a single table ** or which cannot reference any tables at all. Examples: ** ** (1) CHECK constraints ** (2) WHERE clauses on partial indices ** (3) Expressions in indexes on expressions ** (4) Expression arguments to VACUUM INTO. ** ** 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 or NC_PartIdx or NC_IdxExpr, 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 || 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; } sNC.pParse = pParse; sNC.pSrcList = &sSrc; sNC.ncFlags = type; 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 ** objected. ** ** 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 entiries 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 16 17 18 19 20 21 22 23 | ** 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; struct DistinctCtx { | > > > > > > > > > > > > > > | | 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 | ** 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" /* ** Trace output macros */ #if SELECTTRACE_ENABLED /***/ int sqlite3SelectTrace = 0; # 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) #endif /* ** 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; struct DistinctCtx { u8 isTnct; /* True if the DISTINCT keyword is present */ u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */ int tabTnct; /* Ephemeral table used for DISTINCT processing */ int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */ }; /* ** An instance of the following object is used to record information about |
︙ | ︙ | |||
61 62 63 64 65 66 67 | struct DeferredCsr { Table *pTab; /* Table definition */ int iCsr; /* Cursor number for table */ int nKey; /* Number of PK columns for table pTab (>=1) */ } aDefer[4]; #endif struct RowLoadInfo *pDeferredRowLoad; /* Deferred row loading info or NULL */ | < < < < | < < < < < < < < < > > | < | 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 | struct DeferredCsr { Table *pTab; /* Table definition */ int iCsr; /* Cursor number for table */ int nKey; /* Number of PK columns for table pTab (>=1) */ } aDefer[4]; #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 only if bFree is true. */ 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); #ifndef SQLITE_OMIT_WINDOWFUNC if( OK_IF_ALWAYS_TRUE(p->pWinDefn) ){ sqlite3WindowListDelete(db, p->pWinDefn); } #endif if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith); assert( p->pWin==0 ); 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->zAffSdst = 0; pDest->iSdst = 0; pDest->nSdst = 0; } /* |
︙ | ︙ | |||
130 131 132 133 134 135 136 | 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 */ ){ | | | | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | 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; Select standin; 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)); |
︙ | ︙ | |||
166 167 168 169 170 171 172 | pNew->pWith = 0; #ifndef SQLITE_OMIT_WINDOWFUNC pNew->pWin = 0; pNew->pWinDefn = 0; #endif if( pParse->db->mallocFailed ) { clearSelect(pParse->db, pNew, pNew!=&standin); | | > | | 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | pNew->pWith = 0; #ifndef SQLITE_OMIT_WINDOWFUNC pNew->pWin = 0; pNew->pWinDefn = 0; #endif if( pParse->db->mallocFailed ) { clearSelect(pParse->db, pNew, pNew!=&standin); pNew = 0; }else{ assert( pNew->pSrc!=0 || pParse->nErr>0 ); } assert( pNew!=&standin ); return pNew; } /* ** Delete the given Select structure and all of its substructures. */ void sqlite3SelectDelete(sqlite3 *db, Select *p){ |
︙ | ︙ | |||
205 206 207 208 209 210 211 | ** JT_LEFT ** JT_RIGHT ** ** A full outer join is the combination of JT_LEFT and JT_RIGHT. ** ** If an illegal or unsupported join type is seen, then still return ** a join type, but put an error in the pParse structure. | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | 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 | ** JT_LEFT ** JT_RIGHT ** ** A full outer join is the combination of JT_LEFT and JT_RIGHT. ** ** If an illegal or unsupported join type is seen, then still return ** a join type, but put an error in the pParse structure. */ int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){ int jointype = 0; Token *apAll[3]; Token *p; /* 0123456789 123456789 123456789 123 */ static const char zKeyText[] = "naturaleftouterightfullinnercross"; static const struct { u8 i; /* Beginning of keyword text in zKeyText[] */ u8 nChar; /* Length of the keyword in characters */ u8 code; /* Join type mask */ } aKeyword[] = { /* natural */ { 0, 7, JT_NATURAL }, /* left */ { 6, 4, JT_LEFT|JT_OUTER }, /* outer */ { 10, 5, JT_OUTER }, /* right */ { 14, 5, JT_RIGHT|JT_OUTER }, /* full */ { 19, 4, JT_LEFT|JT_RIGHT|JT_OUTER }, /* inner */ { 23, 5, JT_INNER }, /* cross */ { 28, 5, JT_INNER|JT_CROSS }, }; int i, j; apAll[0] = pA; apAll[1] = pB; apAll[2] = pC; for(i=0; i<3 && apAll[i]; i++){ p = apAll[i]; |
︙ | ︙ | |||
292 293 294 295 296 297 298 | if( j>=ArraySize(aKeyword) ){ jointype |= JT_ERROR; break; } } if( (jointype & (JT_INNER|JT_OUTER))==(JT_INNER|JT_OUTER) || | | < | < | | | | > > > > > | < < | | < < < < < < < < < < < < < < | < < | < | < | < < < | < | | < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | < | | | < < | | | | | < | | < < < | | < < < < < < > | | < < < | | | < < | | | | | < | < < < < < | < | < | | | | | | | | | < | > > < | | | < | < < | | | | > > | > > | < | | > > > > > > > | | < < < < < | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < | 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 | if( j>=ArraySize(aKeyword) ){ jointype |= JT_ERROR; break; } } if( (jointype & (JT_INNER|JT_OUTER))==(JT_INNER|JT_OUTER) || (jointype & JT_ERROR)!=0 ){ const char *zSp = " "; assert( pB!=0 ); if( pC==0 ){ zSp++; } sqlite3ErrorMsg(pParse, "unknown or unsupported join type: " "%T %T%s%T", pA, pB, zSp, pC); jointype = JT_INNER; }else if( (jointype & JT_OUTER)!=0 && (jointype & (JT_LEFT|JT_RIGHT))!=JT_LEFT ){ sqlite3ErrorMsg(pParse, "RIGHT and FULL OUTER JOINs are not currently supported"); jointype = JT_INNER; } return jointype; } /* ** Return the index of a column in a table. Return -1 if the column ** is not contained in the table. */ static int columnIndex(Table *pTab, const char *zCol){ int i; for(i=0; i<pTab->nCol; i++){ if( sqlite3StrICmp(pTab->aCol[i].zName, 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 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 = columnIndex(pSrc->a[i].pTab, zCol); if( iCol>=0 ){ if( piTab ){ *piTab = i; *piCol = iCol; } return 1; } } return 0; } /* ** This function is used to add terms implied by JOIN syntax to the ** WHERE clause expression of a SELECT statement. The new term, which ** is ANDed with the existing WHERE clause, is of the form: ** ** (tab1.col1 = tab2.col2) ** ** where tab1 is the iSrc'th table in SrcList pSrc and tab2 is the ** (iSrc+1)'th. Column col1 is column iColLeft of tab1, and col2 is ** column iColRight of tab2. */ static void addWhereTerm( Parse *pParse, /* Parsing context */ SrcList *pSrc, /* List of tables in FROM clause */ int iLeft, /* Index of first table to join in pSrc */ int iColLeft, /* Index of column in first table */ int iRight, /* Index of second table in pSrc */ int iColRight, /* Index of column in second table */ int isOuterJoin, /* True if this is an OUTER join */ Expr **ppWhere /* IN/OUT: The WHERE clause to add to */ ){ sqlite3 *db = pParse->db; Expr *pE1; Expr *pE2; Expr *pEq; assert( iLeft<iRight ); assert( pSrc->nSrc>iRight ); 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); pEq->iRightJoinTable = (i16)pE2->iTable; } *ppWhere = sqlite3ExprAnd(db, *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. ** ** The EP_FromJoin property is used on terms of an expression to tell ** the LEFT OUTER JOIN processing logic that this term is part of the ** join restriction specified in the ON or USING clause and not a part ** of the more general WHERE clause. These terms are moved over to the ** WHERE clause during join processing but we need to remember that they ** originated in the ON or USING clause. ** ** The Expr.iRightJoinTable tells the WHERE clause processing that the ** expression depends on table iRightJoinTable even if that table is not ** explicitly mentioned in the expression. That information is needed ** for cases like this: ** ** SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.b AND t1.x=5 ** ** 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 = (i16)iTable; if( p->op==TK_FUNCTION && 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_FUNCTION && 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; } } /* ** This routine processes the join information for a SELECT statement. ** ON and USING clauses are converted into extra terms of the WHERE clause. ** NATURAL joins also create extra WHERE clause terms. ** ** The terms of a FROM clause are contained in the Select.pSrc structure. ** The left most table is the first entry in Select.pSrc. The right-most ** table is the last entry. The join operator is held in the entry to ** the left. Thus entry 0 contains the join operator for the join between ** entries 0 and 1. Any ON or USING clauses associated with the join are ** 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 */ struct SrcList_item *pLeft; /* Left table being joined */ struct SrcList_item *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; if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue; isOuter = (pRight->fg.jointype & JT_OUTER)!=0; /* When the NATURAL keyword is present, add WHERE clause terms for ** every column that the two tables have in common. */ if( pRight->fg.jointype & JT_NATURAL ){ if( pRight->pOn || pRight->pUsing ){ sqlite3ErrorMsg(pParse, "a NATURAL join may not have " "an ON or USING clause", 0); 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 */ zName = pRightTab->aCol[j].zName; if( tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol) ){ 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->db, 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 = columnIndex(pRightTab, zName); if( iRightCol<0 || !tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol) ){ 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); } } } return 0; } /* ** An instance of this object holds information (beyond pParse and pSelect) |
︙ | ︙ | |||
721 722 723 724 725 726 727 | ** SQLITE_ECEL_OMITREF optimization, or due to the ** SortCtx.pDeferredRowLoad optimiation. In any of these cases ** regOrigData is 0 to prevent this routine from trying to copy ** values that might not yet exist. */ assert( nData==1 || regData==regOrigData || regOrigData==0 ); | < < < < | 619 620 621 622 623 624 625 626 627 628 629 630 631 632 | ** SQLITE_ECEL_OMITREF optimization, or due to the ** SortCtx.pDeferredRowLoad optimiation. In any of these cases ** regOrigData is 0 to prevent this routine from trying to copy ** values that might not yet exist. */ assert( nData==1 || regData==regOrigData || regOrigData==0 ); if( nPrefixReg ){ assert( nPrefixReg==nExpr+bSeq ); regBase = regData - nPrefixReg; }else{ regBase = pParse->nMem + 1; pParse->nMem += nBase; } |
︙ | ︙ | |||
766 767 768 769 770 771 772 | } 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; | | < | 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 | } 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->aSortOrder, 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); 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 ){ |
︙ | ︙ | |||
825 826 827 828 829 830 831 | } sqlite3VdbeAddOp4Int(v, op, pSort->iECursor, regRecord, regBase+nOBSat, nBase-nOBSat); if( iSkip ){ sqlite3VdbeChangeP2(v, iSkip, pSort->labelOBLopt ? pSort->labelOBLopt : sqlite3VdbeCurrentAddr(v)); } | < < < | | < < < < < < | < < < < | < < < < < < < < | < < < < < < < < < | < < < < < < < | < | | < < | < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > > | | | < < < < < < | < < < < < | | | < < < < | < | | 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 | } sqlite3VdbeAddOp4Int(v, op, pSort->iECursor, regRecord, regBase+nOBSat, nBase-nOBSat); if( iSkip ){ sqlite3VdbeChangeP2(v, iSkip, pSort->labelOBLopt ? pSort->labelOBLopt : sqlite3VdbeCurrentAddr(v)); } } /* ** Add code to implement the OFFSET */ static void codeOffset( Vdbe *v, /* Generate code into this VM */ int iOffset, /* Register holding the offset counter */ int iContinue /* Jump here to skip the current record */ ){ if( iOffset>0 ){ sqlite3VdbeAddOp3(v, OP_IfPos, iOffset, iContinue, 1); VdbeCoverage(v); VdbeComment((v, "OFFSET")); } } /* ** Add code that will check to make sure the N registers starting at iMem ** form a distinct entry. iTab is a sorting index that holds previously ** seen combinations of the N values. A new entry is made in iTab ** if the current N values are new. ** ** A jump to addrRepeat is made and the N+1 values are popped from the ** stack if the top N elements are not distinct. */ static void codeDistinct( Parse *pParse, /* Parsing and code generating context */ int iTab, /* A sorting index used to test for distinctness */ int addrRepeat, /* Jump to here if not distinct */ int N, /* Number of elements */ int iMem /* First element */ ){ Vdbe *v; int r1; v = pParse->pVdbe; r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp4Int(v, OP_Found, iTab, addrRepeat, iMem, N); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_MakeRecord, iMem, N, r1); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r1, iMem, N); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); sqlite3ReleaseTempReg(pParse, r1); } #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 ** optimization should be used for. The sorter-reference optimization ** is used for SELECT queries like: ** ** SELECT a, bigblob FROM t1 ORDER BY a LIMIT 10 ** ** If the optimization is used for expression "bigblob", then instead of ** storing values read from that column in the sorter records, the PK of ** the row from table t1 is stored instead. Then, as records are extracted from ** the sorter to return to the user, the required value of bigblob is ** retrieved directly from table t1. If the values are very large, this ** can be more efficient than storing them directly in the sorter records. ** ** The ExprList_item.bSorterRef flag is set for each expression in pEList ** for which the sorter-reference optimization should be enabled. ** Additionally, the pSort->aDefer[] array is populated with entries ** for all cursors required to evaluate all selected expressions. Finally. ** output variable (*ppExtra) is set to an expression list containing ** expressions for all extra PK values that should be stored in the ** sorter records. */ static void selectExprDefer( Parse *pParse, /* Leave any error here */ SortCtx *pSort, /* Sorter context */ ExprList *pEList, /* Expressions destined for sorter */ ExprList **ppExtra /* Expressions to append to sorter record */ ){ 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 = pExpr->y.pTab; if( pExpr->op==TK_COLUMN && pExpr->iColumn>=0 && pTab && !IsVirtual(pTab) && (pTab->aCol[pExpr->iColumn].colFlags & COLFLAG_SORTERREF) ){ 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; 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; pSort->aDefer[nDefer].nKey = nKey; nDefer++; } } pItem->bSorterRef = 1; } } } pSort->nDefer = (u8)nDefer; *ppExtra = pExtra; } #endif |
︙ | ︙ | |||
1154 1155 1156 1157 1158 1159 1160 | 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); | | | 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 | 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].zName)); } }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. |
︙ | ︙ | |||
1206 1207 1208 1209 1210 1211 1212 | /* Adjust nResultCol to account for columns that are omitted ** from the sorter by the optimizations in this branch */ pEList = p->pEList; for(i=0; i<pEList->nExpr; i++){ if( pEList->a[i].u.x.iOrderByCol>0 #ifdef SQLITE_ENABLE_SORTER_REFERENCES | | | < | 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 | /* Adjust nResultCol to account for columns that are omitted ** from the sorter by the optimizations in this branch */ pEList = p->pEList; for(i=0; i<pEList->nExpr; i++){ if( pEList->a[i].u.x.iOrderByCol>0 #ifdef SQLITE_ENABLE_SORTER_REFERENCES || pEList->a[i].bSorterRef #endif ){ nResultCol--; regOrig = 0; } } 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 ); } sRowLoadInfo.regResult = regResult; sRowLoadInfo.ecelFlags = ecelFlags; #ifdef SQLITE_ENABLE_SORTER_REFERENCES sRowLoadInfo.pExtra = pExtra; sRowLoadInfo.regExtraResult = regResult + nResultCol; if( pExtra ) nResultCol += pExtra->nExpr; |
︙ | ︙ | |||
1248 1249 1250 1251 1252 1253 1254 | } /* 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 ){ | | > > > > | > > > | > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > | 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 | } /* 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 ){ switch( pDistinct->eTnctType ){ case WHERE_DISTINCT_ORDERED: { VdbeOp *pOp; /* No longer required OpenEphemeral instr. */ int iJump; /* Jump destination */ int regPrev; /* Previous row content */ /* Allocate space for the previous row */ regPrev = pParse->nMem+1; pParse->nMem += nResultCol; /* Change the OP_OpenEphemeral coded earlier to an OP_Null ** sets the MEM_Cleared bit on the first register of the ** previous value. This will cause the OP_Ne below to always ** fail on the first iteration of the loop even if the first ** row is all NULLs. */ sqlite3VdbeChangeToNoop(v, pDistinct->addrTnct); pOp = sqlite3VdbeGetOp(v, pDistinct->addrTnct); pOp->opcode = OP_Null; pOp->p1 = 1; pOp->p2 = regPrev; iJump = sqlite3VdbeCurrentAddr(v) + nResultCol; for(i=0; i<nResultCol; i++){ CollSeq *pColl = sqlite3ExprCollSeq(pParse, p->pEList->a[i].pExpr); if( i<nResultCol-1 ){ sqlite3VdbeAddOp3(v, OP_Ne, regResult+i, iJump, regPrev+i); VdbeCoverage(v); }else{ sqlite3VdbeAddOp3(v, OP_Eq, regResult+i, iContinue, 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, regResult, regPrev, nResultCol-1); break; } case WHERE_DISTINCT_UNIQUE: { sqlite3VdbeChangeToNoop(v, pDistinct->addrTnct); break; } default: { assert( pDistinct->eTnctType==WHERE_DISTINCT_UNORDERED ); codeDistinct(pParse, pDistinct->tabTnct, iContinue, nResultCol, regResult); break; } } if( pSort==0 ){ codeOffset(v, p->iOffset, iContinue); } } switch( eDest ){ /* In this mode, write each query result to the key of the temporary |
︙ | ︙ | |||
1322 1323 1324 1325 1326 1327 1328 | sqlite3VdbeChangeP5(v, OPFLAG_APPEND); sqlite3ReleaseTempReg(pParse, r2); } sqlite3ReleaseTempRange(pParse, r1, nPrefixReg+1); break; } | < < < < < < < < < < < < < < < < < < < < < < < < | 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 | 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: { if( pSort ){ |
︙ | ︙ | |||
1369 1370 1371 1372 1373 1374 1375 | sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, nResultCol, r1, pDest->zAffSdst, nResultCol); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol); sqlite3ReleaseTempReg(pParse, r1); } break; } | < | 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 | 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; |
︙ | ︙ | |||
1491 1492 1493 1494 1495 1496 1497 | ** 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 ){ | | | < | | 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 | ** 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->aSortOrder = (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{ sqlite3OomFault(db); } return p; } /* ** Deallocate a KeyInfo object */ void sqlite3KeyInfoUnref(KeyInfo *p){ if( p ){ assert( p->nRef>0 ); p->nRef--; if( p->nRef==0 ) sqlite3DbFreeNN(p->db, p); } } /* ** Make a new pointer to a KeyInfo object */ KeyInfo *sqlite3KeyInfoRef(KeyInfo *p){ |
︙ | ︙ | |||
1569 1570 1571 1572 1573 1574 1575 | 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); | | | | 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 | 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->aSortOrder[i-iStart] = pItem->sortOrder; } } return pInfo; } /* ** Name of the connection operator, used for error messages. */ static const char *selectOpName(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; } |
︙ | ︙ | |||
1651 1652 1653 1654 1655 1656 1657 | int iCol; int nKey; /* Number of key columns in sorter record */ int iSortTab; /* Sorter cursor to read from */ int i; int bSeq; /* True if sorter record includes seq. no. */ int nRefKey = 0; struct ExprList_item *aOutEx = p->pEList->a; | < < < < < < < < < < < < < | 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 | int iCol; int nKey; /* Number of key columns in sorter record */ int iSortTab; /* Sorter cursor to read from */ int i; int bSeq; /* True if sorter record includes seq. no. */ int nRefKey = 0; struct ExprList_item *aOutEx = p->pEList->a; assert( addrBreak<0 ); if( pSort->labelBkOut ){ sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut); sqlite3VdbeGoto(v, addrBreak); sqlite3VdbeResolveLabel(v, pSort->labelBkOut); } #ifdef SQLITE_ENABLE_SORTER_REFERENCES /* Open any cursors needed for sorter-reference expressions */ for(i=0; i<pSort->nDefer; i++){ Table *pTab = pSort->aDefer[i].pTab; int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); sqlite3OpenTable(pParse, pSort->aDefer[i].iCsr, iDb, pTab, OP_OpenRead); nRefKey = MAX(nRefKey, pSort->aDefer[i].nKey); } #endif 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; |
︙ | ︙ | |||
1707 1708 1709 1710 1711 1712 1713 | addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); } sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut, nKey+1+nColumn+nRefKey); if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce); addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak); VdbeCoverage(v); | | < < < | | 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 | addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); } sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut, nKey+1+nColumn+nRefKey); if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce); addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak); VdbeCoverage(v); codeOffset(v, p->iOffset, addrContinue); sqlite3VdbeAddOp3(v, OP_SorterData, iTab, regSortOut, iSortTab); bSeq = 0; }else{ addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v); codeOffset(v, p->iOffset, addrContinue); iSortTab = iTab; bSeq = 1; } for(i=0, iCol=nKey+bSeq-1; i<nColumn; i++){ #ifdef SQLITE_ENABLE_SORTER_REFERENCES if( aOutEx[i].bSorterRef ) continue; #endif if( aOutEx[i].u.x.iOrderByCol==0 ) iCol++; } #ifdef SQLITE_ENABLE_SORTER_REFERENCES if( pSort->nDefer ){ int iKey = iCol+1; int regKey = sqlite3GetTempRange(pParse, nRefKey); |
︙ | ︙ | |||
1758 1759 1760 1761 1762 1763 1764 | } } sqlite3ReleaseTempRange(pParse, regKey, nRefKey); } #endif for(i=nColumn-1; i>=0; i--){ #ifdef SQLITE_ENABLE_SORTER_REFERENCES | | | < | 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 | } } sqlite3ReleaseTempRange(pParse, regKey, nRefKey); } #endif for(i=nColumn-1; i>=0; i--){ #ifdef SQLITE_ENABLE_SORTER_REFERENCES if( aOutEx[i].bSorterRef ){ sqlite3ExprCode(pParse, aOutEx[i].pExpr, regRow+i); }else #endif { 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].zName?aOutEx[i].zName : aOutEx[i].zSpan)); } } 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); |
︙ | ︙ | |||
1796 1797 1798 1799 1800 1801 1802 | break; } case SRT_Mem: { /* The LIMIT clause will terminate the loop for us */ break; } #endif | < < < < < < < < < < < | 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 | break; } case SRT_Mem: { /* The LIMIT clause will terminate the loop for us */ break; } #endif 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{ |
︙ | ︙ | |||
1835 1836 1837 1838 1839 1840 1841 | */ sqlite3VdbeResolveLabel(v, addrContinue); if( pSort->sortFlags & SORTFLAG_UseSorter ){ sqlite3VdbeAddOp2(v, OP_SorterNext, iTab, addr); VdbeCoverage(v); }else{ sqlite3VdbeAddOp2(v, OP_Next, iTab, addr); VdbeCoverage(v); } | < > > > | 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 | */ sqlite3VdbeResolveLabel(v, addrContinue); if( pSort->sortFlags & SORTFLAG_UseSorter ){ sqlite3VdbeAddOp2(v, OP_SorterNext, iTab, addr); VdbeCoverage(v); }else{ sqlite3VdbeAddOp2(v, OP_Next, iTab, addr); VdbeCoverage(v); } if( pSort->regReturn ) sqlite3VdbeAddOp1(v, OP_Return, pSort->regReturn); sqlite3VdbeResolveLabel(v, addrBreak); } /* ** Return a pointer to a string containing the 'declaration type' of the ** expression pExpr. The string may be treated as static by the caller. ** ** Also try to estimate the size of the returned value and return that ** result in *pEstWidth. ** ** The declaration type is the exact datatype definition extracted from the ** original CREATE TABLE statement if the expression is a column. The ** declaration type for a ROWID field is INTEGER. Exactly when an expression ** is considered a column can be complex in the presence of subqueries. The ** result-set expression in all of the following SELECT statements is ** considered a column by this function. |
︙ | ︙ | |||
1928 1929 1930 1931 1932 1933 1934 | ** 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; } | | | < < < < < < | 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 | ** 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 && 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>=0 && iCol<pS->pEList->nExpr ){ /* 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; |
︙ | ︙ | |||
1962 1963 1964 1965 1966 1967 1968 | #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{ | | | 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 | #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].zName; 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; } |
︙ | ︙ | |||
1988 1989 1990 1991 1992 1993 1994 | #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; | < < < | | > | 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 | #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 = pExpr->x.pSelect; Expr *p = pS->pEList->a[0].pExpr; assert( ExprHasProperty(pExpr, EP_xIsSelect) ); sNC.pSrcList = pS->pSrc; sNC.pNext = pNC; sNC.pParse = pNC->pParse; zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol); break; } #endif |
︙ | ︙ | |||
2084 2085 2086 2087 2088 2089 2090 | ** 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. */ | | | 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 | ** 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. */ static void generateColumnNames( Parse *pParse, /* Parser context */ Select *pSelect /* Generate column names for this SELECT statement */ ){ Vdbe *v = pParse->pVdbe; int i; Table *pTab; SrcList *pTabList; |
︙ | ︙ | |||
2107 2108 2109 2110 2111 2112 2113 | return; } #endif if( pParse->colNamesSet ) return; /* Column names are determined by the left-most term of a compound select */ while( pSelect->pPrior ) pSelect = pSelect->pPrior; | | | < | | | | | 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 | return; } #endif if( pParse->colNamesSet ) return; /* Column names are determined by the left-most term of a compound select */ while( pSelect->pPrior ) pSelect = pSelect->pPrior; SELECTTRACE(1,pParse,pSelect,("generating column names\n")); pTabList = pSelect->pSrc; pEList = pSelect->pEList; assert( v!=0 ); assert( pTabList!=0 ); pParse->colNamesSet = 1; fullName = (db->flags & SQLITE_FullColNames)!=0; 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 || p->y.pTab!=0 ); /* Covering idx not yet coded */ if( pEList->a[i].zName ){ /* An AS clause always takes first priority */ char *zName = pEList->a[i].zName; 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].zName; } 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].zSpan; z = z==0 ? sqlite3MPrintf(db, "column%d", i+1) : sqlite3DbStrDup(db, z); sqlite3VdbeSetColName(v, i, COLNAME_NAME, z, SQLITE_DYNAMIC); } } generateColumnTypes(pParse, pTabList, pEList); } |
︙ | ︙ | |||
2175 2176 2177 2178 2179 2180 2181 | ** 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. ** | | < | | < < | | | | < < < | > | | | | < < < < < | | < | < < < < | | | | < < | | < | < | | > > > > | | | | < > | < | < < < > | < > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | < < < > | < | | > > > | | 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 | ** 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: generateColumnNames() */ 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 */ sqlite3HashInit(&ht); if( pEList ){ nCol = pEList->nExpr; aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol); testcase( aCol==0 ); if( 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].zName)!=0 ){ /* If the column contains an "AS <name>" phrase, use <name> as the name */ }else{ Expr *pColExpr = sqlite3ExprSkipCollate(pEList->a[i].pExpr); while( pColExpr->op==TK_DOT ){ pColExpr = pColExpr->pRight; assert( pColExpr!=0 ); } if( pColExpr->op==TK_COLUMN ){ /* For columns use the column name name */ int iCol = pColExpr->iColumn; Table *pTab = pColExpr->y.pTab; assert( pTab!=0 ); if( iCol<0 ) iCol = pTab->iPKey; zName = iCol>=0 ? pTab->aCol[iCol].zName : "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].zSpan; } } if( 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 ) sqlite3_randomness(sizeof(cnt), &cnt); } pCol->zName = 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].zName); } sqlite3DbFree(db, aCol); *paCol = 0; *pnCol = 0; return SQLITE_NOMEM_BKPT; } return SQLITE_OK; } /* ** Add type and collation information to a column list based on ** a SELECT statement. ** ** The column list presumably came from selectColumnNamesFromExprList(). ** The column list has only names, not types or collations. This ** routine goes through and adds the types and collations. ** ** 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 */ ){ 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; int n, m; 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->zName); pCol->zName = sqlite3DbReallocOrFree(db, pCol->zName, n+m+2); if( pCol->zName ){ memcpy(&pCol->zName[n+1], zType, m+1); pCol->colFlags |= COLFLAG_HASTYPE; } } if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_BLOB; pColl = sqlite3ExprCollSeq(pParse, p); if( pColl && pCol->zColl==0 ){ pCol->zColl = sqlite3DbStrDup(db, 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){ 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; } /* The sqlite3ResultSetOfSelect() is only used n contexts where lookaside ** is disabled */ assert( db->lookaside.bDisable ); 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); pTab->iPKey = -1; if( db->mallocFailed ){ sqlite3DeleteTable(db, pTab); return 0; } return pTab; } |
︙ | ︙ | |||
2539 2540 2541 2542 2543 2544 2545 | ** ** 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; | | | | 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 | ** ** 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 = p->pOrderBy->nExpr; 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->aSortOrder[i] = pOrderBy->a[i].sortOrder; } } return pRet; } #ifndef SQLITE_OMIT_CTE |
︙ | ︙ | |||
2611 2612 2613 2614 2615 2616 2617 | 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 */ | | < | 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 | 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 = p->pPrior; /* The setup query */ 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 */ |
︙ | ︙ | |||
2688 2689 2690 2691 2692 2693 2694 | 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; | < < < < < < < < < < < < < < < < < | 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 | 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 */ |
︙ | ︙ | |||
2738 2739 2740 2741 2742 2743 2744 | 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. */ | > > > | | | | | > | 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 | 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. */ if( p->selFlags & SF_Aggregate ){ sqlite3ErrorMsg(pParse, "recursive aggregate queries not supported"); }else{ p->pPrior = 0; ExplainQueryPlan((pParse, 1, "RECURSIVE STEP")); sqlite3Select(pParse, p, &destQueue); assert( p->pPrior==0 ); p->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); |
︙ | ︙ | |||
2777 2778 2779 2780 2781 2782 2783 | ** (1) There is no LIMIT or OFFSET or else there is a LIMIT of exactly 1 ** (2) All terms are UNION ALL ** (3) There is no ORDER BY clause ** ** The "LIMIT of exactly 1" case of condition (1) comes about when a VALUES ** clause occurs within scalar expression (ex: "SELECT (VALUES(1),(2),(3))"). ** The sqlite3CodeSubselect will have added the LIMIT 1 clause in tht case. | | < < < < < < < < < < < < < | 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 | ** (1) There is no LIMIT or OFFSET or else there is a LIMIT of exactly 1 ** (2) All terms are UNION ALL ** (3) There is no ORDER BY clause ** ** The "LIMIT of exactly 1" case of condition (1) comes about when a VALUES ** clause occurs within scalar expression (ex: "SELECT (VALUES(1),(2),(3))"). ** The sqlite3CodeSubselect will have added the LIMIT 1 clause in tht case. ** Since the limit is exactly 1, we only need to evalutes the left-most VALUES. */ static int multiSelectValues( Parse *pParse, /* Parsing context */ Select *p, /* The right-most of SELECTs to be coded */ SelectDest *pDest /* What to do with query results */ ){ int nRow = 1; 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 ** left is p->pPrior. The left query could also be a compound query |
︙ | ︙ | |||
2869 2870 2871 2872 2873 2874 2875 | 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 ); | < | > | > > > | < | | 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 | 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; if( pPrior->pOrderBy || pPrior->pLimit ){ sqlite3ErrorMsg(pParse,"%s clause should come after %s not before", pPrior->pOrderBy!=0 ? "ORDER BY" : "LIMIT", selectOpName(p->op)); rc = 1; goto multi_select_end; } 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); goto multi_select_end; } /* 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 ){ generateWithRecursiveQuery(pParse, p, &dest); }else #endif /* Compound SELECTs that have an ORDER BY clause are handled separately. */ if( p->pOrderBy ){ |
︙ | ︙ | |||
2925 2926 2927 2928 2929 2930 2931 | #endif /* Generate code for the left and right SELECT statements. */ switch( p->op ){ case TK_ALL: { int addr = 0; | | < | < | | | 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 | #endif /* Generate code for the left and right SELECT statements. */ switch( p->op ){ case TK_ALL: { int addr = 0; int nLimit; assert( !pPrior->pLimit ); pPrior->iLimit = p->iLimit; pPrior->iOffset = p->iOffset; pPrior->pLimit = p->pLimit; rc = sqlite3Select(pParse, pPrior, &dest); p->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")); rc = sqlite3Select(pParse, p, &dest); testcase( rc!=SQLITE_OK ); pDelete = p->pPrior; p->pPrior = pPrior; p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); if( pPrior->pLimit && sqlite3ExprIsInteger(pPrior->pLimit->pLeft, &nLimit) && nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit) ){ p->nSelectRow = sqlite3LogEst((u64)nLimit); } if( addr ){ sqlite3VdbeJumpHere(v, addr); } |
︙ | ︙ | |||
2995 2996 2997 2998 2999 3000 3001 | 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 ); } | < < | < < | > | 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 | 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", selectOpName(p->op))); 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 ); if( dest.eDest!=priorOp ){ int iCont, iBreak, iStart; assert( p->pEList ); 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); |
︙ | ︙ | |||
3082 3083 3084 3085 3086 3087 3088 | 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); | < | < < | 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 | 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", selectOpName(p->op))); 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. */ 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); |
︙ | ︙ | |||
3141 3142 3143 3144 3145 3146 3147 | #ifndef SQLITE_OMIT_EXPLAIN if( p->pNext==0 ){ ExplainQueryPlanPop(pParse); } #endif } | < < | 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 | #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++){ |
︙ | ︙ | |||
3195 3196 3197 3198 3199 3200 3201 | } sqlite3KeyInfoUnref(pKeyInfo); } multi_select_end: pDest->iSdst = dest.iSdst; pDest->nSdst = dest.nSdst; | < < | < < | < | 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 | } sqlite3KeyInfoUnref(pKeyInfo); } multi_select_end: pDest->iSdst = dest.iSdst; pDest->nSdst = dest.nSdst; sqlite3SelectDelete(db, 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", selectOpName(p->op)); } } /* ** Code an output subroutine for a coroutine implementation of a ** SELECT statment. ** |
︙ | ︙ | |||
3307 3308 3309 3310 3311 3312 3313 | 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 | | < | | | 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 | 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. */ case SRT_Mem: { assert( pIn->nSdst==1 || pParse->nErr>0 ); testcase( pIn->nSdst!=1 ); sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSDParm, 1); /* 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. |
︙ | ︙ | |||
3453 3454 3455 3456 3457 3458 3459 | static int multiSelectOrderBy( Parse *pParse, /* Parsing context */ Select *p, /* The right-most of SELECTs to be coded */ SelectDest *pDest /* What to do with query results */ ){ int i, j; /* Loop counters */ Select *pPrior; /* Another SELECT immediately to our left */ | < < | 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 | static int multiSelectOrderBy( Parse *pParse, /* Parsing context */ Select *p, /* The right-most of SELECTs to be coded */ SelectDest *pDest /* What to do with query results */ ){ int i, j; /* Loop counters */ Select *pPrior; /* Another SELECT immediately to our left */ Vdbe *v; /* Generate code to this VDBE */ SelectDest destA; /* Destination for coroutine A */ SelectDest destB; /* Destination for coroutine B */ int regAddrA; /* Address register for select-A coroutine */ int regAddrB; /* Address register for select-B coroutine */ int addrSelectA; /* Address of the select-A coroutine */ int addrSelectB; /* Address of the select-B coroutine */ |
︙ | ︙ | |||
3486 3487 3488 3489 3490 3491 3492 | 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 */ | | > | < | 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 | 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 */ int *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->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; |
︙ | ︙ | |||
3535 3536 3537 3538 3539 3540 3541 | /* 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. */ | | < > > > > > | < < < < < < < < < < < < < < < < < | < < < > | > | 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 | /* 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(int)*(nOrderBy + 1)); if( aPermute ){ struct ExprList_item *pItem; aPermute[0] = nOrderBy; for(i=1, pItem=pOrderBy->a; i<=nOrderBy; i++, pItem++){ 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; } /* Reattach the ORDER BY clause to the query. */ p->pOrderBy = pOrderBy; pPrior->pOrderBy = sqlite3ExprListDup(pParse->db, pOrderBy, 0); /* Allocate a range of temporary registers and the KeyInfo needed ** for the logic that removes duplicate result rows when the ** operator is UNION, EXCEPT, or INTERSECT (but not UNION ALL). */ if( op==TK_ALL ){ regPrev = 0; }else{ int nExpr = p->pEList->nExpr; assert( nOrderBy>=nExpr || db->mallocFailed ); regPrev = pParse->nMem+1; 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->aSortOrder[i] = 0; } } } /* Separate the left and the right query from one another */ p->pPrior = 0; pPrior->pNext = 0; sqlite3ResolveOrderGroupBy(pParse, p, p->pOrderBy, "ORDER"); if( pPrior->pPrior==0 ){ sqlite3ResolveOrderGroupBy(pParse, pPrior, pPrior->pOrderBy, "ORDER"); } /* Compute the limit registers */ computeLimitRegisters(pParse, p, labelEnd); if( p->iLimit && op==TK_ALL ){ regLimitA = ++pParse->nMem; regLimitB = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Copy, p->iOffset ? p->iOffset+1 : p->iLimit, |
︙ | ︙ | |||
3620 3621 3622 3623 3624 3625 3626 | regAddrA = ++pParse->nMem; regAddrB = ++pParse->nMem; regOutA = ++pParse->nMem; regOutB = ++pParse->nMem; sqlite3SelectDestInit(&destA, SRT_Coroutine, regAddrA); sqlite3SelectDestInit(&destB, SRT_Coroutine, regAddrB); | | | 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 | 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)", selectOpName(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")); |
︙ | ︙ | |||
3746 3747 3748 3749 3750 3751 3752 | sqlite3VdbeChangeP5(v, OPFLAG_PERMUTE); sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB); VdbeCoverage(v); /* Jump to the this point in order to terminate the query. */ sqlite3VdbeResolveLabel(v, labelEnd); | | | | < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | 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 | sqlite3VdbeChangeP5(v, OPFLAG_PERMUTE); sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB); VdbeCoverage(v); /* Jump to the this point in order to terminate the query. */ sqlite3VdbeResolveLabel(v, labelEnd); /* 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 #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) /* An instance of the SubstContext object describes an substitution edit ** to be performed on a parse tree. ** ** All references to columns in table iTable are to be replaced by corresponding ** expressions in pEList. */ typedef struct SubstContext { Parse *pParse; /* The parsing context */ int iTable; /* Replace references to this table */ int iNewTable; /* New table number */ int isLeftJoin; /* Add TK_IF_NULL_ROW opcodes on each replacement */ ExprList *pEList; /* Replacement expressions */ } SubstContext; /* Forward Declarations */ static void substExprList(SubstContext*, ExprList*); static void substSelect(SubstContext*, Select*, int); /* |
︙ | ︙ | |||
3831 3832 3833 3834 3835 3836 3837 | ** of the subquery rather the result set of the subquery. */ static Expr *substExpr( SubstContext *pSubst, /* Description of the substitution */ Expr *pExpr /* Expr in which substitution occurs */ ){ if( pExpr==0 ) return 0; | | | < | | < < < < | < < < | | | < < < < < < | | | | < < < < < < < < < < < < < < < < < < < < | < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | ** of the subquery rather the result set of the subquery. */ static Expr *substExpr( SubstContext *pSubst, /* Description of the substitution */ Expr *pExpr /* Expr in which substitution occurs */ ){ 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 ){ if( pExpr->iColumn<0 ){ pExpr->op = TK_NULL; }else{ 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; pCopy = &ifNullRow; } testcase( ExprHasProperty(pCopy, EP_Subquery) ); pNew = sqlite3ExprDup(db, pCopy, 0); if( pNew && pSubst->isLeftJoin ){ ExprSetProperty(pNew, EP_CanBeNull); } if( pNew && ExprHasProperty(pExpr,EP_FromJoin) ){ pNew->iRightJoinTable = pExpr->iRightJoinTable; ExprSetProperty(pNew, EP_FromJoin); } sqlite3ExprDelete(db, pExpr); pExpr = pNew; } } }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( ExprHasProperty(pExpr, EP_xIsSelect) ){ substSelect(pSubst, pExpr->x.pSelect, 1); }else{ substExprList(pSubst, pExpr->x.pList); } } 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; struct SrcList_item *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) /* ** This routine attempts to flatten subqueries as a performance optimization. ** This routine returns 1 if it makes changes and 0 if no flattening occurs. ** ** To understand the concept of flattening, consider the following ** query: |
︙ | ︙ | |||
4175 4176 4177 4178 4179 4180 4181 | ** for flattening. (This is due to ticket [2f7170d73bf9abf80] ** 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 | < < | < | 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 | ** for flattening. (This is due to ticket [2f7170d73bf9abf80] ** 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. ** |
︙ | ︙ | |||
4227 4228 4229 4230 4231 4232 4233 | ** (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 | | < < < < < < < | | | > | | < < < < < < < < < < < | 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 | ** (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, or ** (17d3) a 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 simple references to ** columns of the sub-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. ** ** (**) Subsumed into restriction (17d3). Was: 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 ** return the value X for which Y was maximal.) ** ** (25) If either the subquery or the parent query contains a window ** function in the select list or ORDER BY clause, flattening ** is not attempted. ** ** ** In this routine, the "p" parameter is a pointer to the outer query. ** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query ** uses aggregates. ** ** If flattening is not attempted, this routine is a no-op and returns 0. ** If flattening is attempted this routine returns 1. |
︙ | ︙ | |||
4319 4320 4321 4322 4323 4324 4325 | Select *pParent; /* Current UNION ALL term of the other query */ Select *pSub; /* The inner query or "subquery" */ Select *pSub1; /* Pointer to the rightmost select in sub-query */ 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 */ | | | < < | 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 | Select *pParent; /* Current UNION ALL term of the other query */ Select *pSub; /* The inner query or "subquery" */ Select *pSub1; /* Pointer to the rightmost select in sub-query */ 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 */ struct SrcList_item *pSubitem; /* The subquery */ sqlite3 *db = pParse->db; /* 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; |
︙ | ︙ | |||
4385 4386 4387 4388 4389 4390 4391 4392 4393 | ** ** If we flatten the above, we would get ** ** (t1 LEFT OUTER JOIN t2) JOIN t3 ** ** which is not at all the same thing. ** ** See also tickets #306, #350, and #3300. */ | > > > > > | > | | < < < < | < | < < > | > | > > < | | < < < < < < < < < < > | > | | | > | < | < | < < < | < < | < < < < < < < < < < < | 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 | ** ** If we flatten the above, we would get ** ** (t1 LEFT OUTER JOIN t2) JOIN t3 ** ** which is not at all the same thing. ** ** If the subquery is the right operand of a LEFT JOIN, then the outer ** query cannot be an aggregate. (3c) This is an artifact of the way ** 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 || isAgg || IsVirtual(pSubSrc->a[0].pTab) ){ /* (3a) (3c) (3b) */ 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 ** though they are not necessary. This will stress-test the OP_IfNullRow ** opcode. */ isLeftJoin = -1; } #endif /* Restriction (17): If the sub-query is a compound SELECT, then it must ** use only the UNION ALL operator. And none of the simple select queries ** 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 || pSrc->nSrc!=1 ){ return 0; /* (17d1), (17d2), or (17d3) */ } 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->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) */ ){ 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; } } } /* Ex-restriction (23): ** The only way that the recursive part of a CTE can contain a compound ** subquery is for the subquery to be one term of a join. But if the ** subquery is a join, then the flattening has already been stopped by ** restriction (17d3) */ assert( (p->selFlags & SF_Recursive)==0 || pSub->pPrior==0 ); /***** 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; /* 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> ** ** followed by any ORDER BY, LIMIT and/or OFFSET clauses. This block |
︙ | ︙ | |||
4523 4524 4525 4526 4527 4528 4529 | ** 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; | < < > > < < < < < | > > > > > > | | > > > > | > > | > | < < < < | | < < < > | | > > > > > | | 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 | ** 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; p->pSrc = 0; p->pPrior = 0; p->pLimit = 0; pNew = sqlite3SelectDup(db, p, 0); p->pLimit = pLimit; p->pOrderBy = pOrderBy; p->pSrc = pSrc; p->op = TK_ALL; if( pNew==0 ){ p->pPrior = pPrior; }else{ 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)); } if( db->mallocFailed ) return 1; } /* Begin flattening the iFrom-th entry of the FROM clause ** in the outer query. */ pSub = pSub1 = pSubitem->pSelect; /* Delete the transient table structure associated with the ** subquery */ sqlite3DbFree(db, pSubitem->zDatabase); sqlite3DbFree(db, pSubitem->zName); sqlite3DbFree(db, pSubitem->zAlias); pSubitem->zDatabase = 0; pSubitem->zName = 0; pSubitem->zAlias = 0; pSubitem->pSelect = 0; /* 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); pTabToDel->pNextZombie = pToplevel->pZombieTab; pToplevel->pZombieTab = pTabToDel; }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. */ for(pParent=p; pParent; pParent=pParent->pPrior, pSub=pSub->pPrior){ int nSubSrc; u8 jointype = 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( pSrc ){ assert( pParent==p ); /* First time through the loop */ jointype = pSubitem->fg.jointype; }else{ assert( pParent!=p ); /* 2nd and subsequent times through the loop */ pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); if( pSrc==0 ) break; pParent->pSrc = pSrc; } /* 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: ** |
︙ | ︙ | |||
4628 4629 4630 4631 4632 4633 4634 | pParent->pSrc = pSrc; } /* Transfer the FROM clause terms from the subquery into the ** outer query. */ for(i=0; i<nSubSrc; i++){ | < | | | < < | | 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 | 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); assert( pSrc->a[i+iFrom].fg.isTabFunc==0 ); pSrc->a[i+iFrom] = pSubSrc->a[i]; iNewParent = pSubSrc->a[i].iCursor; memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i])); } pSrc->a[iFrom].fg.jointype = jointype; /* Now begin substituting subquery result set expressions for ** references to the iParent in the outer query. ** ** Example: ** ** SELECT a+5, b*10 FROM (SELECT x*3 AS a, y+10 AS b FROM t1) WHERE a>b; |
︙ | ︙ | |||
4672 4673 4674 4675 4676 4677 4678 | } assert( pParent->pOrderBy==0 ); pParent->pOrderBy = pOrderBy; pSub->pOrderBy = 0; } pWhere = pSub->pWhere; pSub->pWhere = 0; | | | < < < < | < < | < | | > | < < < < < < < < < | | | < < < < | < < < < | | | < < < < < < < < | | | | < < < > | | < < < < | > > > > | | | > > > > | | < | | | < < | < < < < | | < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | > | 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 | } assert( pParent->pOrderBy==0 ); pParent->pOrderBy = pOrderBy; pSub->pOrderBy = 0; } pWhere = pSub->pWhere; pSub->pWhere = 0; if( isLeftJoin>0 ){ sqlite3SetJoinExpr(pWhere, iNewParent); } pParent->pWhere = sqlite3ExprAnd(db, pWhere, pParent->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 distinct if either the inner or the ** outer query is distinct. */ pParent->selFlags |= pSub->selFlags & SF_Distinct; /* ** 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; } } /* Finially, delete what is left of the subquery and return ** success. */ 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 */ int nConst; /* Number for COLUMN=CONSTANT terms */ int nChng; /* Number of times a constant is propagated */ 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. */ 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 */ ){ int i; assert( pColumn->op==TK_COLUMN ); /* 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 *pExpr = pConst->apExpr[i*2]; assert( pExpr->op==TK_COLUMN ); if( pExpr->iTable==pColumn->iTable && pExpr->iColumn==pColumn->iColumn ){ return; /* Already present. Return without doing anything. */ } } pConst->nConst++; pConst->apExpr = sqlite3DbReallocOrFree(pConst->pParse->db, pConst->apExpr, pConst->nConst*2*sizeof(Expr*)); if( pConst->apExpr==0 ){ pConst->nConst = 0; }else{ if( ExprHasProperty(pValue, EP_FixedCol) ) pValue = pValue->pLeft; 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( 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 && !ExprHasProperty(pRight, EP_FixedCol) && sqlite3ExprIsConstant(pLeft) && sqlite3IsBinary(sqlite3BinaryCompareCollSeq(pConst->pParse,pLeft,pRight)) ){ constInsert(pConst, pRight, pLeft); }else if( pLeft->op==TK_COLUMN && !ExprHasProperty(pLeft, EP_FixedCol) && sqlite3ExprIsConstant(pRight) && sqlite3IsBinary(sqlite3BinaryCompareCollSeq(pConst->pParse,pLeft,pRight)) ){ constInsert(pConst, pLeft, pRight); } } /* ** This is a Walker expression callback. 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 its ** corresponding value. */ static int propagateConstantExprRewrite(Walker *pWalker, Expr *pExpr){ int i; WhereConst *pConst; if( pExpr->op!=TK_COLUMN ) return WRC_Continue; if( ExprHasProperty(pExpr, EP_FixedCol) ) return WRC_Continue; pConst = pWalker->u.pConst; 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; /* 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); break; } return WRC_Prune; } /* ** The WHERE-clause constant propagation optimization. ** ** If the WHERE clause contains terms of the form COLUMN=CONSTANT or ** CONSTANT=COLUMN that must be tree (in other words, if the terms 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 within the WHERE clause. ** ** 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 ** |
︙ | ︙ | |||
4946 4947 4948 4949 4950 4951 4952 | ** 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. | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | ** 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; ** |
︙ | ︙ | |||
5080 5081 5082 5083 5084 5085 5086 | ** 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. ** | | | < < < < < < < < < < < | < < < < < < < < < < < < < | > < < < | < < < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < | > < < | | | < < < < | < | | | | < < < < < < < < < | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | < < < | < < < < < < < < | < | | | < < < < < < | < | < < < > | | | < < | < | < < | > | | | < < < | | | | | | | | | < | > < | 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 | ** 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) The inner query features one or more window-functions (since ** changes to the WHERE clause of the inner query could change the ** window over which window functions are calculated). ** ** 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 ) return 0; /* restriction (2) */ #ifndef SQLITE_OMIT_WINDOWFUNC if( pSubq->pWin ) return 0; /* restriction (6) */ #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. */ { Select *pX; for(pX=pSubq; pX; pX=pX->pPrior){ assert( (pX->selFlags & (SF_Recursive))==0 ); } } #endif if( pSubq->pLimit!=0 ){ return 0; /* restriction (3) */ } while( pWhere->op==TK_AND ){ nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, iCursor, isLeftJoin); pWhere = pWhere->pLeft; } if( isLeftJoin && (ExprHasProperty(pWhere,EP_FromJoin)==0 || pWhere->iRightJoinTable!=iCursor) ){ 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 ){ pSubq->pHaving = sqlite3ExprAnd(pParse->db, pSubq->pHaving, pNew); }else{ pSubq->pWhere = sqlite3ExprAnd(pParse->db, pSubq->pWhere, pNew); } pSubq = pSubq->pPrior; } } return nChng; } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ /* ** Check to see if a subquery contains result-set columns that are ** never used. If it does, change the value of those result-set columns ** to NULL so that they do not cause unnecessary work to compute. ** ** Return the number of column that were changed to NULL. */ static int disableUnusedSubqueryResultColumns(struct SrcList_item *pItem){ int nCol; Select *pSub; /* The subquery to be simplified */ Select *pX; /* For looping over compound elements of pSub */ Table *pTab; /* The table that describes the subquery */ int j; /* Column number */ int nChng = 0; /* Number of columns converted to NULL */ Bitmask colUsed; /* Columns that may not be NULLed out */ assert( pItem!=0 ); if( pItem->fg.isCorrelated || pItem->fg.isCte ){ return 0; } assert( pItem->pTab!=0 ); pTab = pItem->pTab; assert( pItem->pSelect!=0 ); if( pTab->tabFlags & TF_Ephemeral ){ return 0; } pSub = pItem->pSelect; assert( pSub->pEList->nExpr==pTab->nCol ); if( (pSub->selFlags & (SF_Distinct|SF_Aggregate))!=0 ){ testcase( pSub->selFlags & SF_Distinct ); testcase( pSub->selFlags & SF_Aggregate ); return 0; } for(pX=pSub; pX; pX=pX->pPrior){ if( pX->pPrior && pX->op!=TK_ALL ){ /* This optimization does not work for compound subqueries that ** use UNION, INTERSECT, or EXCEPT. Only UNION ALL is allowed. */ return 0; } if( pX->pWin ){ /* This optimization does not work for subqueries that use window ** functions. */ return 0; } } colUsed = pItem->colUsed; if( pSub->pOrderBy ){ ExprList *pList = pSub->pOrderBy; for(j=0; j<pList->nExpr; j++){ u16 iCol = pList->a[j].u.x.iOrderByCol; if( iCol>0 ){ iCol--; colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol); } } } nCol = pTab->nCol; for(j=0; j<nCol; j++){ Select *pX; Bitmask m = j<BMS-1 ? MASKBIT(j) : TOPBIT; if( (m & colUsed)!=0 ) continue; for(pX=pSub; pX; pX=pX->pPrior) { Expr *pY = pX->pEList->a[j].pExpr; if( pY->op==TK_NULL ) continue; pY->op = TK_NULL; /* pX->selFlags |= SF_PushDown; */ ExprClearProperty(pY, EP_Skip|EP_Unlikely); nChng++; } } return nChng; } /* ** The pFunc is the only aggregate function in the query. Check to see ** if the query is a candidate for the min/max optimization. ** ** If the query is a candidate for the min/max optimization, then set ** *ppMinMax to be an ORDER BY clause to be used for the optimization ** and return either WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX depending on ** whether pFunc is a min() or max() function. ** ** If the query is not a candidate for the min/max optimization, return ** WHERE_ORDERBY_NORMAL (which must be zero). ** ** 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 = pFunc->x.pList; /* Arguments to agg function */ const char *zFunc; /* Name of aggregate function pFunc */ ExprList *pOrderBy; u8 sortOrder; assert( *ppMinMax==0 ); assert( pFunc->op==TK_AGG_FUNCTION ); if( pEList==0 || pEList->nExpr!=1 ) return eRet; zFunc = pFunc->u.zToken; if( sqlite3StrICmp(zFunc, "min")==0 ){ eRet = WHERE_ORDERBY_MIN; sortOrder = SQLITE_SO_ASC; }else if( sqlite3StrICmp(zFunc, "max")==0 ){ eRet = WHERE_ORDERBY_MAX; sortOrder = SQLITE_SO_DESC; }else{ return eRet; } *ppMinMax = pOrderBy = sqlite3ExprListDup(db, pEList, 0); assert( pOrderBy!=0 || db->mallocFailed ); if( pOrderBy ) pOrderBy->a[0].sortOrder = sortOrder; 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, 0 is returned. */ 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 ){ return 0; } pTab = p->pSrc->a[0].pTab; pExpr = p->pEList->a[0].pExpr; assert( pTab && !pTab->pSelect && pExpr ); if( IsVirtual(pTab) ) return 0; if( pExpr->op!=TK_AGG_FUNCTION ) return 0; if( NEVER(pAggInfo->nFunc==0) ) return 0; if( (pAggInfo->aFunc[0].pFunc->funcFlags&SQLITE_FUNC_COUNT)==0 ) return 0; if( pExpr->flags&EP_Distinct ) 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, struct SrcList_item *pFrom){ if( pFrom->pTab && pFrom->fg.isIndexedBy ){ Table *pTab = pFrom->pTab; char *zIndexedBy = pFrom->u1.zIndexedBy; Index *pIdx; 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; } pFrom->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: |
︙ | ︙ | |||
5398 5399 5400 5401 5402 5403 5404 | 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; | < < < < < < < < | < < < | | | > | < < | | | | | | | | < > | | < < < < < < < | > < < < < < < < | | | > | < < | | < | | | > > < | | > | < | | > > | | < < < | < < < < < < < < < < < < < < < < < < < < < < | | | | < < < < < < < < < < < < | < < < < < < < | | | < | | > | > > > | > > | | | | | < | < < < | < < | | < < < < | | | | < < < < | < < < | < | > | | > > | | | | < < | < < < < | < < < < < < < < < < < < < < < < < < < < < < < | < | 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 | Token dummy; if( p->pPrior==0 ) return WRC_Continue; if( p->pOrderBy==0 ) return WRC_Continue; for(pX=p; pX && (pX->op==TK_ALL || pX->op==TK_SELECT); pX=pX->pPrior){} if( pX==0 ) return WRC_Continue; a = p->pOrderBy->a; for(i=p->pOrderBy->nExpr-1; i>=0; i--){ if( a[i].pExpr->flags & EP_Collate ) break; } if( i<0 ) return WRC_Continue; /* If we reach this point, that means the transformation is required. */ pParse = pWalker->pParse; db = pParse->db; pNew = sqlite3DbMallocZero(db, sizeof(*pNew) ); if( pNew==0 ) return WRC_Abort; memset(&dummy, 0, sizeof(dummy)); pNewSrc = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&dummy,pNew,0,0); if( pNewSrc==0 ) return WRC_Abort; *pNew = *p; p->pSrc = pNewSrc; p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ASTERISK, 0)); p->op = TK_SELECT; 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. */ static int cannotBeFunction(Parse *pParse, struct SrcList_item *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 */ struct SrcList_item *pItem, /* FROM clause element to resolve */ With **ppContext /* OUT: WITH clause return value belongs to */ ){ const char *zName; if( pItem->zDatabase==0 && (zName = pItem->zName)!=0 ){ With *p; 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]; } } } } 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. In this case it ** should 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. */ void sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){ assert( bFree==0 || (pParse->pWith==0 && pParse->pWithToFree==0) ); if( pWith ){ assert( pParse->pWith!=pWith ); pWith->pOuter = pParse->pWith; pParse->pWith = pWith; if( bFree ) pParse->pWithToFree = pWith; } } /* ** This function checks if argument pFrom refers to a CTE declared by ** a WITH clause on the stack currently maintained by the parser. And, ** if currently processing a CTE expression, if it is a recursive ** reference to the current CTE. ** ** If pFrom falls into either of the two categories above, pFrom->pTab ** and other fields are populated accordingly. The caller should check ** (pFrom->pTab!=0) to determine whether or not a successful match ** was found. ** ** Whether or not a match is found, SQLITE_OK is returned if no error ** occurs. If an error does occur, an error message is stored in the ** parser and some error code other than SQLITE_OK returned. */ static int withExpand( Walker *pWalker, struct SrcList_item *pFrom ){ Parse *pParse = pWalker->pParse; sqlite3 *db = pParse->db; struct Cte *pCte; /* Matched CTE (or NULL if no match) */ With *pWith; /* WITH clause that pCte belongs to */ assert( pFrom->pTab==0 ); pCte = searchWith(pParse->pWith, pFrom, &pWith); if( pCte ){ Table *pTab; ExprList *pEList; Select *pSel; Select *pLeft; /* Left-most SELECT statement */ int bMayRecursive; /* True if compound joined by UNION [ALL] */ With *pSavedWith; /* Initial value of pParse->pWith */ /* 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 SQLITE_ERROR; } if( cannotBeFunction(pParse, pFrom) ) return SQLITE_ERROR; assert( pFrom->pTab==0 ); pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table)); if( pTab==0 ) return WRC_Abort; 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 SQLITE_NOMEM_BKPT; assert( pFrom->pSelect ); pFrom->fg.isCte = 1; /* Check if this is a recursive CTE. */ pSel = pFrom->pSelect; bMayRecursive = ( pSel->op==TK_ALL || pSel->op==TK_UNION ); if( bMayRecursive ){ int i; SrcList *pSrc = pFrom->pSelect->pSrc; for(i=0; i<pSrc->nSrc; i++){ struct SrcList_item *pItem = &pSrc->a[i]; if( pItem->zDatabase==0 && pItem->zName!=0 && 0==sqlite3StrICmp(pItem->zName, pCte->zName) ){ pItem->pTab = pTab; pItem->fg.isRecursive = 1; pTab->nTabRef++; pSel->selFlags |= SF_Recursive; } } } /* Only one recursive reference is permitted. */ if( pTab->nTabRef>2 ){ sqlite3ErrorMsg( pParse, "multiple references to recursive table: %s", pCte->zName ); return SQLITE_ERROR; } assert( pTab->nTabRef==1 || ((pSel->selFlags&SF_Recursive) && pTab->nTabRef==2 )); pCte->zCteErr = "circular reference: %s"; pSavedWith = pParse->pWith; pParse->pWith = pWith; if( bMayRecursive ){ Select *pPrior = pSel->pPrior; assert( pPrior->pWith==0 ); pPrior->pWith = pSel->pWith; sqlite3WalkSelect(pWalker, pPrior); pPrior->pWith = 0; }else{ sqlite3WalkSelect(pWalker, pSel); } 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 SQLITE_ERROR; } 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 SQLITE_OK; } #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. */ static void selectPopWith(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->pWith = pWith->pOuter; } } } #else #define selectPopWith 0 #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, struct SrcList_item *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) ); pTab->tabFlags |= TF_Ephemeral; return SQLITE_OK; } /* ** This routine is a Walker callback for "expanding" a SELECT statement. ** "Expanding" means to do the following: ** ** (1) Make sure VDBE cursor numbers have been assigned to every ** element of the FROM clause. |
︙ | ︙ | |||
5815 5816 5817 5818 5819 5820 5821 | ** 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; | | | < < < < < < < < < < < < < | | > > > > < < < < < < | | < < < < < < < < | < < < < < < < < < < < < < < | < | | 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 | ** 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; SrcList *pTabList; ExprList *pEList; struct SrcList_item *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; } pTabList = p->pSrc; pEList = p->pEList; 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->fg.isRecursive ) continue; assert( pFrom->pTab==0 ); #ifndef SQLITE_OMIT_CTE if( withExpand(pWalker, pFrom) ) return WRC_Abort; if( pFrom->pTab ) {} else #endif if( pFrom->zName==0 ){ #ifndef SQLITE_OMIT_SUBQUERY Select *pSel = pFrom->pSelect; /* 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 }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( IsVirtual(pTab) || pTab->pSelect ){ i16 nCol; if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort; assert( pFrom->pSelect==0 ); pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0); nCol = pTab->nCol; pTab->nCol = -1; sqlite3WalkSelect(pWalker, pFrom->pSelect); pTab->nCol = nCol; } #endif } /* Locate the index named by the INDEXED BY clause, if any. */ if( sqlite3IndexedByLookup(pParse, pFrom) ){ return WRC_Abort; } } /* Process NATURAL keywords, and ON and USING clauses of joins. */ if( 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 |
︙ | ︙ | |||
5985 5986 5987 5988 5989 5990 5991 | 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 ){ | | | | > | | | | | < | < < | < | < < < < < < < < < < < < < < < < < < < < < < < < < | < > > > | < | > | | | > | > > | | < < < < | < > > | < < < < < < < < < < > > > > > > | < < | < < | | | | | | < < < < < < | | < < < < | < < | 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 | 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].zName = a[k].zName; pNew->a[pNew->nExpr-1].zSpan = a[k].zSpan; a[k].zName = 0; a[k].zSpan = 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 */ if( pE->op==TK_DOT ){ assert( pE->pLeft!=0 ); assert( !ExprHasProperty(pE->pLeft, EP_IntValue) ); zTName = pE->pLeft->u.zToken; } for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){ Table *pTab = pFrom->pTab; Select *pSub = pFrom->pSelect; char *zTabName = pFrom->zAlias; const char *zSchemaName = 0; int iDb; if( zTabName==0 ){ zTabName = pTab->zName; } if( db->mallocFailed ) break; if( pSub==0 || (pSub->selFlags & SF_NestedFrom)==0 ){ pSub = 0; 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].zName; 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 && sqlite3MatchSpanName(pSub->pEList->a[j].zSpan, 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) ){ /* 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 ** using clause from the table on the right. */ continue; } } pRight = sqlite3Expr(db, TK_ID, zName); zColname = zName; zToFree = 0; if( longNames || pTabList->nSrc>1 ){ Expr *pLeft; pLeft = sqlite3Expr(db, TK_ID, zTabName); pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight); if( zSchemaName ){ pLeft = sqlite3Expr(db, TK_ID, zSchemaName); pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pExpr); } if( longNames ){ zColname = sqlite3MPrintf(db, "%s.%s", zTabName, zName); zToFree = zColname; } }else{ pExpr = pRight; } pNew = sqlite3ExprListAppend(pParse, pNew, pExpr); sqlite3TokenInit(&sColname, zColname); sqlite3ExprListSetName(pParse, pNew, &sColname, 0); if( pNew && (p->selFlags & SF_NestedFrom)!=0 ){ struct ExprList_item *pX = &pNew->a[pNew->nExpr-1]; if( pSub ){ pX->zSpan = sqlite3DbStrDup(db, pSub->pEList->a[j].zSpan); testcase( pX->zSpan==0 ); }else{ pX->zSpan = sqlite3MPrintf(db, "%s.%s.%s", zSchemaName, zTabName, zColname); testcase( pX->zSpan==0 ); } pX->bSpanIsTab = 1; } sqlite3DbFree(db, zToFree); } } if( !tableSeen ){ if( zTName ){ sqlite3ErrorMsg(pParse, "no such table: %s", zTName); }else{ sqlite3ErrorMsg(pParse, "no tables specified"); |
︙ | ︙ | |||
6160 6161 6162 6163 6164 6165 6166 | sqlite3ErrorMsg(pParse, "too many columns in result set"); return WRC_Abort; } if( (elistFlags & (EP_HasFunc|EP_Subquery))!=0 ){ p->selFlags |= SF_ComplexResult; } } | | > | < > > > > > > > > > | > > | | > > > > > > | 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 | sqlite3ErrorMsg(pParse, "too many columns in result set"); return WRC_Abort; } if( (elistFlags & (EP_HasFunc|EP_Subquery))!=0 ){ p->selFlags |= SF_ComplexResult; } } return WRC_Continue; } /* ** 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; } #if SQLITE_DEBUG /* ** Always assert. This xSelectCallback2 implementation proves that the ** xSelectCallback2 is never invoked. |
︙ | ︙ | |||
6202 6203 6204 6205 6206 6207 6208 | w.pParse = pParse; if( OK_IF_ALWAYS_TRUE(pParse->hasCompound) ){ w.xSelectCallback = convertCompoundSelectToSubquery; w.xSelectCallback2 = 0; sqlite3WalkSelect(&w, pSelect); } w.xSelectCallback = selectExpander; | | < | | | | | | | > | | 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 | w.pParse = pParse; if( OK_IF_ALWAYS_TRUE(pParse->hasCompound) ){ w.xSelectCallback = convertCompoundSelectToSubquery; w.xSelectCallback2 = 0; sqlite3WalkSelect(&w, pSelect); } w.xSelectCallback = selectExpander; w.xSelectCallback2 = selectPopWith; sqlite3WalkSelect(&w, pSelect); } #ifndef SQLITE_OMIT_SUBQUERY /* ** This is a Walker.xSelectCallback callback for the sqlite3SelectTypeInfo() ** interface. ** ** For each FROM-clause subquery, add Column.zType and Column.zColl ** information to the Table structure that represents the result set ** of that subquery. ** ** The Table structure that represents the result set was constructed ** by selectExpander() but the type and collation information was omitted ** 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; struct SrcList_item *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); } } } } #endif |
︙ | ︙ | |||
6285 6286 6287 6288 6289 6290 6291 | */ void sqlite3SelectPrep( Parse *pParse, /* The parser context */ Select *p, /* The SELECT statement being coded. */ NameContext *pOuterNC /* Name context for container */ ){ assert( p!=0 || pParse->db->mallocFailed ); | < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > > > > > > > > > > > | | < | | | | < < | | < | < | | | < < < < < < < | < < < | < < < < < < < < < < < < < < < < < < < < < | < | < < > > | | | < | | | 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 | */ void sqlite3SelectPrep( Parse *pParse, /* The parser context */ Select *p, /* The SELECT statement being coded. */ NameContext *pOuterNC /* Name context for container */ ){ assert( p!=0 || pParse->db->mallocFailed ); if( pParse->db->mallocFailed ) return; if( p->selFlags & SF_HasTypeInfo ) return; sqlite3SelectExpand(pParse, p); if( pParse->nErr || pParse->db->mallocFailed ) return; sqlite3ResolveSelectNames(pParse, p, pOuterNC); if( pParse->nErr || pParse->db->mallocFailed ) return; sqlite3SelectAddTypeInfo(pParse, p); } /* ** Reset the aggregate accumulator. ** ** The aggregate accumulator is a set of memory cells that hold ** intermediate results while calculating an aggregate. This ** routine generates code that stores NULLs in all of those memory ** cells. */ 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 ){ Expr *pE = pFunc->pExpr; assert( !ExprHasProperty(pE, EP_xIsSelect) ); 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); sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0, (char*)pKeyInfo, P4_KEYINFO); } } } } /* ** 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 = pF->pExpr->x.pList; assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) ); 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){ 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 = pF->pExpr->x.pList; assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) ); 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 ){ addrNext = sqlite3VdbeMakeLabel(pParse); testcase( nArg==0 ); /* Error condition */ testcase( nArg>1 ); /* Also an error */ codeDistinct(pParse, pF->iDistinct, addrNext, 1, 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++){ pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr); } if( !pColl ){ pColl = pParse->db->pDfltColl; } if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem; sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ); } sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, pF->iMem); sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF); sqlite3VdbeChangeP5(v, (u8)nArg); sqlite3ReleaseTempRange(pParse, regAgg, nArg); if( addrNext ){ sqlite3VdbeResolveLabel(v, addrNext); } } 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->pExpr, pC->iMem); } pAggInfo->directMode = 0; if( addrHitTest ){ sqlite3VdbeJumpHere(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 TABLE %s%s%s", pTab->zName, bCover ? " USING COVERING INDEX " : "", bCover ? pIdx->zName : "" ); } } #else |
︙ | ︙ | |||
6665 6666 6667 6668 6669 6670 6671 | ** 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; | < < < < < < < | < < < | | | 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 | ** 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; if( sqlite3ExprIsConstantOrGroupBy(pWalker->pParse, pExpr, pS->pGroupBy) ){ sqlite3 *db = pWalker->pParse->db; Expr *pNew = sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[1], 0); if( pNew ){ Expr *pWhere = pS->pWhere; SWAP(Expr, *pNew, *pExpr); pNew = sqlite3ExprAnd(db, pWhere, pNew); pS->pWhere = pNew; pWalker->eCode = 1; } } return WRC_Prune; } return WRC_Continue; |
︙ | ︙ | |||
6713 6714 6715 6716 6717 6718 6719 | static void havingToWhere(Parse *pParse, Select *p){ Walker sWalker; memset(&sWalker, 0, sizeof(sWalker)); sWalker.pParse = pParse; sWalker.xExprCallback = havingToWhereExprCb; sWalker.u.pSelect = p; sqlite3WalkExpr(&sWalker, p->pHaving); | | | | | < < < | | | | < | < < < > < | < < | | > > < < < < < < < < < | 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 | static void havingToWhere(Parse *pParse, Select *p){ Walker sWalker; memset(&sWalker, 0, sizeof(sWalker)); sWalker.pParse = pParse; sWalker.xExprCallback = havingToWhereExprCb; sWalker.u.pSelect = p; sqlite3WalkExpr(&sWalker, p->pHaving); #if SELECTTRACE_ENABLED if( sWalker.eCode && (sqlite3SelectTrace & 0x100)!=0 ){ SELECTTRACE(0x100,pParse,p,("Move HAVING terms into WHERE:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif } /* ** 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 struct SrcList_item *isSelfJoinView( SrcList *pTabList, /* Search for self-joins in this FROM clause */ struct SrcList_item *pThis /* Search for prior reference to this subquery */ ){ struct SrcList_item *pItem; for(pItem = pTabList->a; pItem<pThis; pItem++){ Select *pS1; if( pItem->pSelect==0 ) continue; if( pItem->fg.viaCoroutine ) continue; if( pItem->zName==0 ) continue; if( sqlite3_stricmp(pItem->zDatabase, pThis->zDatabase)!=0 ) continue; if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue; pS1 = pItem->pSelect; if( pThis->pSelect->selId!=pS1->selId ){ /* The query flattener left two different CTE tables with identical ** names in the same FROM clause. */ continue; } if( sqlite3ExprCompare(0, pThis->pSelect->pWhere, pS1->pWhere, -1) || sqlite3ExprCompare(0, pThis->pSelect->pHaving, pS1->pHaving, -1) ){ /* The view was modified by some other optimization such as ** pushDownWhereTerms() */ continue; } return pItem; } return 0; } #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: |
︙ | ︙ | |||
6803 6804 6805 6806 6807 6808 6809 | 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 */ | < < | 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 | 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 */ if( sqlite3_stricmp(pExpr->u.zToken,"count") ) return 0; /* Is count() */ 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 */ |
︙ | ︙ | |||
6851 6852 6853 6854 6855 6856 6857 | pExpr = sqlite3PExpr(pParse, TK_PLUS, pTerm, pExpr); } pSub = pPrior; } p->pEList->a[0].pExpr = pExpr; p->selFlags &= ~SF_Aggregate; | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 | pExpr = sqlite3PExpr(pParse, TK_PLUS, pTerm, pExpr); } pSub = pPrior; } p->pEList->a[0].pExpr = pExpr; p->selFlags &= ~SF_Aggregate; #if SELECTTRACE_ENABLED if( sqlite3SelectTrace & 0x400 ){ SELECTTRACE(0x400,pParse,p,("After count-of-view optimization:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif return 1; } #endif /* SQLITE_COUNTOFVIEW_OPTIMIZATION */ /* ** Generate code for the SELECT statement given in the p argument. ** ** The results are returned according to the SelectDest structure. ** See comments in sqliteInt.h for further information. ** ** This routine returns the number of errors. If any errors are |
︙ | ︙ | |||
6973 6974 6975 6976 6977 6978 6979 | 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 */ | < > < | < > | | | < | < < < | | | > | | < | < < < < < < < | < | < | < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < | < | | | | | < < < < < | | < | < | 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 | 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 */ AggInfo sAggInfo; /* Information used by aggregate queries */ 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; memset(&sAggInfo, 0, sizeof(sAggInfo)); #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( IgnorableOrderby(pDest) ){ assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union || pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard || pDest->eDest==SRT_Queue || pDest->eDest==SRT_DistFifo || pDest->eDest==SRT_DistQueue || pDest->eDest==SRT_Fifo); /* If ORDER BY makes no difference in the output then neither does ** DISTINCT so it can be removed too. */ sqlite3ExprListDelete(db, p->pOrderBy); 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( pDest->eDest==SRT_Output ){ generateColumnNames(pParse, p); } #ifndef SQLITE_OMIT_WINDOWFUNC if( sqlite3WindowRewrite(pParse, p) ){ goto select_end; } #if SELECTTRACE_ENABLED if( sqlite3SelectTrace & 0x108 ){ 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 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++){ struct SrcList_item *pItem = &pTabList->a[i]; Select *pSub = pItem->pSelect; Table *pTab = pItem->pTab; /* 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) ){ SELECTTRACE(0x100,pParse,p, ("LEFT-JOIN simplifies to JOIN on term %d\n",i)); pItem->fg.jointype &= ~(JT_LEFT|JT_OUTER); unsetJoinExpr(p->pWhere, pItem->iCursor); } /* No futher action if this term of the FROM clause is no a subquery */ if( pSub==0 ) continue; /* Catch mismatch in the declared columns of a view and the number of ** columns in the SELECT on the RHS */ |
︙ | ︙ | |||
7136 7137 7138 7139 7140 7141 7142 | ** 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 ); | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 | ** 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: ** ** SELECT expensive_function(x) |
︙ | ︙ | |||
7193 7194 7195 7196 7197 7198 7199 | ** ** SELECT x FROM (SELECT x FROM tab ORDER BY y LIMIT 10); */ if( pSub->pOrderBy!=0 && i==0 && (p->selFlags & SF_ComplexResult)!=0 && (pTabList->nSrc==1 | | | 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 | ** ** SELECT x FROM (SELECT x FROM tab ORDER BY y LIMIT 10); */ if( pSub->pOrderBy!=0 && i==0 && (p->selFlags & SF_ComplexResult)!=0 && (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. */ |
︙ | ︙ | |||
7217 7218 7219 7220 7221 7222 7223 | #ifndef SQLITE_OMIT_COMPOUND_SELECT /* Handle compound SELECT statements using the separate multiSelect() ** procedure. */ if( p->pPrior ){ rc = multiSelect(pParse, p, pDest); | | | | | < | | | | | < | 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 | #ifndef SQLITE_OMIT_COMPOUND_SELECT /* Handle compound SELECT statements using the separate multiSelect() ** procedure. */ if( p->pPrior ){ rc = multiSelect(pParse, p, pDest); #if SELECTTRACE_ENABLED SELECTTRACE(0x1,pParse,p,("end compound-select processing\n")); if( (sqlite3SelectTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){ sqlite3TreeViewSelect(0, p, 0); } #endif if( p->pNext==0 ) ExplainQueryPlanPop(pParse); return rc; } #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( pTabList->nSrc>1 && 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); } #endif }else{ SELECTTRACE(0x100,pParse,p,("Constant propagation not helpful\n")); } #ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION if( OptimizationEnabled(db, SQLITE_QueryFlattener|SQLITE_CountOfView) && countOfViewOptimization(pParse, p) ){ if( db->mallocFailed ) goto select_end; pEList = p->pEList; pTabList = p->pSrc; } #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++){ struct SrcList_item *pItem = &pTabList->a[i]; 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 |
︙ | ︙ | |||
7287 7288 7289 7290 7291 7292 7293 | ** 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. */ | | | > > > > < < | > | | | < | > > > > > > > > > > > > > > > > > > > > > > | > > | | < < < < < < < < < < < < < < < < < < < < < | | > > > < | < > > | < | | > > > > > > | | < | > | | < | < < < < < < < | | | | 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 | ** 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 ){ 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, though it is ** technically harmless for it to be generated multiple times. The ** following assert() will detect if something changes to cause ** the same subquery to be coded multiple times, as a signal to the ** developers to try to optimize the situation. */ 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) && 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 }else{ SELECTTRACE(0x100,pParse,p,("Push-down not possible\n")); } /* Convert unused result columns of the subquery into simple NULL ** expressions, to avoid unneeded searching and computation. */ if( disableUnusedSubqueryResultColumns(pItem) ){ #if SELECTTRACE_ENABLED if( sqlite3SelectTrace & 0x4000 ){ SELECTTRACE(0x4000,pParse,p, ("Change unused result columns to NULL for subquery %d:\n", pSub->selId)); sqlite3TreeViewSelect(0, p, 0); } #endif } zSavedAuthContext = pParse->zAuthContext; pParse->zAuthContext = pItem->zName; /* Generate code to implement the subquery ** ** The subquery is implemented as a co-routine if the subquery is ** guaranteed to be the outer loop (so that it does not need to be ** computed more than once) ** ** TODO: Are there other reasons beside (1) to use a co-routine ** implementation? */ if( i==0 && (pTabList->nSrc==1 || (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0) /* (1) */ ){ /* 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->pTab->zName)); pItem->addrFillSub = addrTop; sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); ExplainQueryPlan((pParse, 1, "CO-ROUTINE %u", pSub->selId)); 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{ /* Generate a subroutine that will fill an ephemeral table with ** the content of this subquery. pItem->addrFillSub will point ** to the address of the generated subroutine. pItem->regReturn ** is a register allocated to hold the subroutine return address */ int topAddr; int onceAddr = 0; int retAddr; struct SrcList_item *pPrior; assert( pItem->addrFillSub==0 ); 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->pTab->zName)); }else{ VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName)); } pPrior = isSelfJoinView(pTabList, pItem); if( pPrior ){ sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor); assert( pPrior->pSelect!=0 ); pSub->nSelectRow = pPrior->pSelect->nSelectRow; }else{ sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); ExplainQueryPlan((pParse, 1, "MATERIALIZE %u", pSub->selId)); 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->pTab->zName)); sqlite3VdbeChangeP1(v, topAddr, retAddr); sqlite3ClearTempRegCache(pParse); } if( db->mallocFailed ) goto select_end; pParse->nHeight -= sqlite3SelectExprHeight(p); pParse->zAuthContext = zSavedAuthContext; #endif } /* Various elements of the SELECT copied into local variables for ** convenience */ pEList = p->pEList; pWhere = p->pWhere; pGroupBy = p->pGroupBy; pHaving = p->pHaving; sDistinct.isTnct = (p->selFlags & SF_Distinct)!=0; #if SELECTTRACE_ENABLED if( sqlite3SelectTrace & 0x400 ){ SELECTTRACE(0x400,pParse,p,("After all FROM-clause analysis:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and ** if the select-list is the same as the ORDER BY list, then this query ** can be rewritten as a GROUP BY. In other words, this: |
︙ | ︙ | |||
7453 7454 7455 7456 7457 7458 7459 | ** 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 | < < < < < | | | | 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 | ** 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 ){ SELECTTRACE(0x400,pParse,p,("Transform DISTINCT into GROUP BY:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif } /* If there is an ORDER BY clause, then create an ephemeral index to ** do the sorting. But this sorting ephemeral index might end up |
︙ | ︙ | |||
7500 7501 7502 7503 7504 7505 7506 | sSort.addrSortIndex = -1; } /* If the output is destined for a temporary table, open that table. */ if( pDest->eDest==SRT_EphemTab ){ sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pDest->iSDParm, pEList->nExpr); | < < < < < < < < < < < < | | 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 | sSort.addrSortIndex = -1; } /* If the output is destined for a temporary table, open that table. */ 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; } /* Open an ephemeral index to use for the distinct set. */ |
︙ | ︙ | |||
7545 7546 7547 7548 7549 7550 7551 | } 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 | | | | < | 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 | } 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; /* Master window object (or NULL) */ if( pWin ){ sqlite3WindowCodeInit(pParse, pWin); } #endif assert( WHERE_USE_LIMIT==SF_FixedLimit ); /* Begin the database scan. */ SELECTTRACE(1,pParse,p,("WhereBegin\n")); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy, p->pEList, p, wctrlFlags, p->nSelectRow); if( pWInfo==0 ) goto select_end; if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){ p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo); } if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){ sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo); } 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); |
︙ | ︙ | |||
7610 7611 7612 7613 7614 7615 7616 | /* Use the standard inner loop. */ selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, sqlite3WhereContinueLabel(pWInfo), sqlite3WhereBreakLabel(pWInfo)); /* End the database scan loop. */ | < | 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 | /* 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 */ |
︙ | ︙ | |||
7644 7645 7646 7647 7648 7649 7650 | 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; | < < < < < < < < < < < < < < < < < < < < < < < < < > > > > > > > > > > > > < < < < < < < < < < < < < | > | | | | | > > | > > > > | | > | < > | > | > > | > > < < < < < < < < < < < < < < < < | | < | | 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 | 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; } /* 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( sqlite3ExprListCompare(pGroupBy, sSort.pOrderBy, -1)==0 ){ orderByGrp = 1; } /* 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. */ memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; sNC.pSrcList = pTabList; sNC.uNC.pAggInfo = &sAggInfo; VVA_ONLY( sNC.ncFlags = NC_UAggInfo; ) sAggInfo.mnReg = pParse->nMem+1; sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0; sAggInfo.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); } sAggInfo.nAccumulator = sAggInfo.nColumn; if( p->pGroupBy==0 && p->pHaving==0 && sAggInfo.nFunc==1 ){ minMaxFlag = minMaxQuery(db, sAggInfo.aFunc[0].pExpr, &pMinMaxOrderBy); }else{ minMaxFlag = WHERE_ORDERBY_NORMAL; } for(i=0; i<sAggInfo.nFunc; i++){ assert( !ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_xIsSelect) ); sNC.ncFlags |= NC_InAggFunc; sqlite3ExprAnalyzeAggList(&sNC, sAggInfo.aFunc[i].pExpr->x.pList); sNC.ncFlags &= ~NC_InAggFunc; } sAggInfo.mxReg = pParse->nMem; if( db->mallocFailed ) goto select_end; #if SELECTTRACE_ENABLED if( sqlite3SelectTrace & 0x400 ){ int ii; SELECTTRACE(0x400,pParse,p,("After aggregate analysis:\n")); sqlite3TreeViewSelect(0, p, 0); for(ii=0; ii<sAggInfo.nColumn; ii++){ sqlite3DebugPrintf("agg-column[%d] iMem=%d\n", ii, sAggInfo.aCol[ii].iMem); sqlite3TreeViewExpr(0, sAggInfo.aCol[ii].pExpr, 0); } for(ii=0; ii<sAggInfo.nFunc; ii++){ sqlite3DebugPrintf("agg-func[%d]: iMem=%d\n", ii, sAggInfo.aFunc[ii].iMem); sqlite3TreeViewExpr(0, sAggInfo.aFunc[ii].pExpr, 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 */ /* 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. */ sAggInfo.sortingIdx = pParse->nTab++; pKeyInfo = sqlite3KeyInfoFromExprList(pParse,pGroupBy,0,sAggInfo.nColumn); addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen, sAggInfo.sortingIdx, sAggInfo.nSortingColumn, 0, (char*)pKeyInfo, P4_KEYINFO); /* Initialize memory locations used by GROUP BY aggregate processing */ iUseFlag = ++pParse->nMem; iAbortFlag = ++pParse->nMem; regOutputRow = ++pParse->nMem; |
︙ | ︙ | |||
7798 7799 7800 7801 7802 7803 7804 | /* 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); | | | < | | < < < < < < < < < | 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 | /* 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, 0, p, WHERE_GROUPBY | (orderByGrp ? WHERE_SORTBYGROUP : 0), 0 ); if( pWInfo==0 ) goto select_end; 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{ |
︙ | ︙ | |||
7838 7839 7840 7841 7842 7843 7844 | (sDistinct.isTnct && (p->selFlags&SF_Distinct)==0) ? "DISTINCT" : "GROUP BY"); groupBySort = 1; nGroupBy = pGroupBy->nExpr; nCol = nGroupBy; j = nGroupBy; | | | < | | > | > < | < | | | < < < < < < < < < < < < < < < < < | 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 | (sDistinct.isTnct && (p->selFlags&SF_Distinct)==0) ? "DISTINCT" : "GROUP BY"); groupBySort = 1; nGroupBy = pGroupBy->nExpr; nCol = nGroupBy; j = nGroupBy; for(i=0; i<sAggInfo.nColumn; i++){ if( sAggInfo.aCol[i].iSorterColumn>=j ){ nCol++; j++; } } regBase = sqlite3GetTempRange(pParse, nCol); sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0, 0); j = nGroupBy; for(i=0; i<sAggInfo.nColumn; i++){ struct AggInfo_col *pCol = &sAggInfo.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, sAggInfo.sortingIdx, regRecord); sqlite3ReleaseTempReg(pParse, regRecord); sqlite3ReleaseTempRange(pParse, regBase, nCol); sqlite3WhereEnd(pWInfo); sAggInfo.sortingIdxPTab = sortPTab = pParse->nTab++; sortOut = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_OpenPseudo, sortPTab, sortOut, nCol); sqlite3VdbeAddOp2(v, OP_SorterSort, sAggInfo.sortingIdx, addrEnd); VdbeComment((v, "GROUP BY sort")); VdbeCoverage(v); sAggInfo.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. |
︙ | ︙ | |||
7909 7910 7911 7912 7913 7914 7915 | /* 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 ){ | | | | 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 | /* 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, sAggInfo.sortingIdx, sortOut, sortPTab); } for(j=0; j<pGroupBy->nExpr; j++){ if( groupBySort ){ sqlite3VdbeAddOp3(v, OP_Column, sortPTab, j, iBMem+j); }else{ sAggInfo.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); |
︙ | ︙ | |||
7946 7947 7948 7949 7950 7951 7952 | 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); | | | < < | 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 | 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, &sAggInfo); sqlite3VdbeAddOp2(v, OP_Integer, 1, iUseFlag); VdbeComment((v, "indicate data in accumulator")); /* End of the loop */ if( groupBySort ){ sqlite3VdbeAddOp2(v, OP_SorterNext, sAggInfo.sortingIdx, addrTopOfLoop); VdbeCoverage(v); }else{ sqlite3WhereEnd(pWInfo); sqlite3VdbeChangeToNoop(v, addrSortingIdx); } /* Output the final row of result */ sqlite3VdbeAddOp2(v, OP_Gosub, regOutputRow, addrOutputRow); VdbeComment((v, "output final row")); /* Jump over the subroutines |
︙ | ︙ | |||
7988 7989 7990 7991 7992 7993 7994 | 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); | | | | < < < < > | | < | | | | | | | < | < | | > > < < < | | | < | < < < | | | < < < | < | < | < < < < < | | | < < | < < < < < < < | | > > < | > > < < < < < < < < < < | < < < < < < < | | | | | 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 | 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, &sAggInfo); 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, &sAggInfo); sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag); VdbeComment((v, "indicate accumulator empty")); sqlite3VdbeAddOp1(v, OP_Return, regReset); } /* endif pGroupBy. Begin aggregate queries without GROUP BY: */ else { #ifndef SQLITE_OMIT_BTREECOUNT Table *pTab; if( (pTab = isSimpleCount(p, &sAggInfo))!=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 */ int 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); 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, iRoot, iDb, 1); if( pKeyInfo ){ sqlite3VdbeChangeP4(v, -1, (char *)pKeyInfo, P4_KEYINFO); } sqlite3VdbeAddOp2(v, OP_Count, iCsr, sAggInfo.aFunc[0].iMem); sqlite3VdbeAddOp1(v, OP_Close, iCsr); explainSimpleCount(pParse, pTab, pBest); }else #endif /* SQLITE_OMIT_BTREECOUNT */ { int regAcc = 0; /* "populate accumulators" flag */ /* If there are accumulator registers but no min() or max() functions, ** allocate register regAcc. Register regAcc will contain 0 the first ** time the inner loop runs, and 1 thereafter. The code generated ** by updateAccumulator() only updates the accumulator registers if ** regAcc contains 0. */ if( sAggInfo.nAccumulator ){ for(i=0; i<sAggInfo.nFunc; i++){ if( sAggInfo.aFunc[i].pFunc->funcFlags&SQLITE_FUNC_NEEDCOLL ) break; } if( i==sAggInfo.nFunc ){ regAcc = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, regAcc); } } /* 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, &sAggInfo); /* 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, 0, p, minMaxFlag, 0); if( pWInfo==0 ){ goto select_end; } updateAccumulator(pParse, regAcc, &sAggInfo); if( regAcc ) sqlite3VdbeAddOp2(v, OP_Integer, 1, regAcc); if( sqlite3WhereIsOrdered(pWInfo)>0 ){ sqlite3VdbeGoto(v, sqlite3WhereBreakLabel(pWInfo)); VdbeComment((v, "%s() by index", (minMaxFlag==WHERE_ORDERBY_MIN?"min":"max"))); } sqlite3WhereEnd(pWInfo); finalizeAggFunctions(pParse, &sAggInfo); } sSort.pOrderBy = 0; sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL); selectInnerLoop(pParse, p, -1, 0, 0, pDest, addrEnd, addrEnd); } sqlite3VdbeResolveLabel(v, addrEnd); } /* endif aggregate query */ if( sDistinct.eTnctType==WHERE_DISTINCT_UNORDERED ){ explainTempTable(pParse, "DISTINCT"); } /* If there is an ORDER BY clause, then we need to sort the results ** and send them to the callback one by one. */ if( sSort.pOrderBy ){ explainTempTable(pParse, sSort.nOBSat>0 ? "RIGHT PART OF ORDER BY":"ORDER BY"); assert( p->pEList==pEList ); generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest); } /* Jump here to skip this query */ sqlite3VdbeResolveLabel(v, iEnd); /* The SELECT has been coded. If there is an error in the Parse structure, ** 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); sqlite3DbFree(db, sAggInfo.aCol); sqlite3DbFree(db, sAggInfo.aFunc); #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.
︙ | ︙ | |||
12 13 14 15 16 17 18 | ** This file contains code to implement the "sqlite" command line ** 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 | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ** This file contains code to implement the "sqlite" command line ** 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) |
︙ | ︙ | |||
83 84 85 86 87 88 89 | # define _LARGE_FILE 1 # ifndef _FILE_OFFSET_BITS # define _FILE_OFFSET_BITS 64 # endif # define _LARGEFILE_SOURCE 1 #endif | < < < < < < < < | | 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 | # define _LARGE_FILE 1 # ifndef _FILE_OFFSET_BITS # define _FILE_OFFSET_BITS 64 # endif # define _LARGEFILE_SOURCE 1 #endif #include <stdlib.h> #include <string.h> #include <stdio.h> #include <assert.h> #include "sqlite3.h" typedef sqlite3_int64 i64; typedef sqlite3_uint64 u64; typedef unsigned char u8; #if SQLITE_USER_AUTHENTICATION # include "sqlite3userauth.h" #endif #include <ctype.h> #include <stdarg.h> #if !defined(_WIN32) && !defined(WIN32) # include <signal.h> # if !defined(__RTP__) && !defined(_WRS_KERNEL) # include <pwd.h> # endif #endif #if (!defined(_WIN32) && !defined(WIN32)) || defined(__MINGW32__) # include <unistd.h> # include <dirent.h> # define GETPID getpid |
︙ | ︙ | |||
162 163 164 165 166 167 168 | # define shell_read_history(X) # define shell_write_history(X) # define shell_stifle_history(X) # define SHELL_USE_LOCAL_GETLINE 1 #endif | < < < < < < < < < < < | | | | | | | | | | | | | | | | < | | 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 | # define shell_read_history(X) # define shell_write_history(X) # define shell_stifle_history(X) # define SHELL_USE_LOCAL_GETLINE 1 #endif #if defined(_WIN32) || defined(WIN32) # 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 #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 */ extern FILE *popen(const char*,const char*); extern int pclose(FILE*); # else # define SQLITE_OMIT_POPEN 1 # endif |
︙ | ︙ | |||
220 221 222 223 224 225 226 | /* 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) | < < < | > < < < < < < < < < < < < < | 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 | /* 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. */ #if defined(_WIN32) || defined(WIN32) 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); } #else # define setBinaryMode(X,Y) # define setTextMode(X,Y) #endif /* True if the timer is enabled */ 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); } |
︙ | ︙ | |||
354 355 356 357 358 359 360 | ** 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 { | < < | 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 | ** 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 */ |
︙ | ︙ | |||
471 472 473 474 475 476 477 | */ static char *Argv0; /* ** Prompt strings. Initialized in main. Settable with ** .prompt main continue */ | < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 | */ static char *Argv0; /* ** Prompt strings. Initialized in main. Settable with ** .prompt main continue */ static char mainPrompt[20]; /* First line prompt. default: "sqlite> "*/ static char continuePrompt[20]; /* Continuation prompt. default: " ...> " */ /* ** Render output like fprintf(). Except, if the output is going to the ** console and if this is running on a Windows machine, translate the ** output from UTF-8 into MBCS. */ #if defined(_WIN32) || defined(WIN32) |
︙ | ︙ | |||
612 613 614 615 616 617 618 | /* Indicate out-of-memory and exit. */ static void shell_out_of_memory(void){ raw_printf(stderr,"Error: out of memory\n"); exit(1); } | < < < < < < < | 444 445 446 447 448 449 450 451 452 453 454 455 456 457 | /* 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 |
︙ | ︙ | |||
655 656 657 658 659 660 661 | ** 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; | | > | 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 | ** 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; char zBuf[1000]; if( aw>(int)sizeof(zBuf)/3 ) aw = (int)sizeof(zBuf)/3; for(i=n=0; zUtf[i]; i++){ if( (zUtf[i]&0xc0)!=0x80 ){ n++; if( n==aw ){ do{ i++; }while( (zUtf[i]&0xc0)==0x80 ); break; } |
︙ | ︙ | |||
724 725 726 727 728 729 730 | int n = 0; while( *z ){ if( (0xc0&*(z++))!=0x80 ) n++; } return n; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 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 | 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. ** ** If zLine is not NULL then it is a malloced buffer returned from ** a previous call to this routine that may be reused. */ static char *local_getline(char *zLine, FILE *in){ int nLine = zLine==0 ? 0 : 100; int n = 0; while( 1 ){ if( n+100>nLine ){ nLine = nLine*2 + 100; zLine = realloc(zLine, nLine); if( zLine==0 ) shell_out_of_memory(); } if( fgets(&zLine[n], nLine - n, in)==0 ){ if( n==0 ){ free(zLine); return 0; } zLine[n] = 0; |
︙ | ︙ | |||
799 800 801 802 803 804 805 | } #if defined(_WIN32) || defined(WIN32) /* For interactive input on Windows systems, translate the ** multi-byte characterset characters into UTF-8. */ if( stdin_is_interactive && in==stdin ){ char *zTrans = sqlite3_win32_mbcs_to_utf8_v2(zLine, 0); if( zTrans ){ | | | | 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 | } #if defined(_WIN32) || defined(WIN32) /* For interactive input on Windows systems, translate the ** multi-byte characterset characters into UTF-8. */ if( stdin_is_interactive && in==stdin ){ char *zTrans = sqlite3_win32_mbcs_to_utf8_v2(zLine, 0); if( zTrans ){ int nTrans = strlen30(zTrans)+1; if( nTrans>nLine ){ zLine = realloc(zLine, nTrans); if( zLine==0 ) shell_out_of_memory(); } memcpy(zLine, zTrans, nTrans); sqlite3_free(zTrans); } } #endif /* defined(_WIN32) || defined(WIN32) */ return zLine; |
︙ | ︙ | |||
826 827 828 829 830 831 832 | ** If zPrior is not NULL then it is a buffer from a prior call to this ** routine that can be reused. ** ** The result is stored in space obtained from malloc() and must either ** be freed by the caller or else passed back into this routine via the ** zPrior argument for reuse. */ | < | | | 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 | ** If zPrior is not NULL then it is a buffer from a prior call to this ** routine that can be reused. ** ** The result is stored in space obtained from malloc() and must either ** be freed by the caller or else passed back into this routine via the ** zPrior argument for reuse. */ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){ char *zPrompt; char *zResult; if( in!=0 ){ zResult = local_getline(zPrior, in); }else{ zPrompt = isContinuation ? continuePrompt : mainPrompt; #if SHELL_USE_LOCAL_GETLINE printf("%s", zPrompt); fflush(stdout); zResult = local_getline(zPrior, stdin); #else free(zPrior); zResult = shell_readline(zPrompt); if( zResult && *zResult ) shell_add_history(zResult); #endif } return zResult; } /* ** Return the value of a hexadecimal digit. Return -1 if the input ** is not a hex digit. */ static int hexDigitValue(char c){ if( c>='0' && c<='9' ) return c - '0'; |
︙ | ︙ | |||
934 935 936 937 938 939 940 | ** from malloc(), or a NULL pointer. The string pointed to by zAppend is ** added to zIn, and the result returned in memory obtained from malloc(). ** zIn, if it was not NULL, is freed. ** ** If the third argument, quote, is not '\0', then it is used as a ** quote character for zAppend. */ | | | | | | | | 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 | ** from malloc(), or a NULL pointer. The string pointed to by zAppend is ** added to zIn, and the result returned in memory obtained from malloc(). ** zIn, if it was not NULL, is freed. ** ** If the third argument, quote, is not '\0', then it is used as a ** quote character for zAppend. */ static void appendText(ShellText *p, char const *zAppend, char quote){ int len; int i; int nAppend = strlen30(zAppend); len = nAppend+p->n+1; if( quote ){ len += 2; for(i=0; i<nAppend; i++){ if( zAppend[i]==quote ) len++; } } if( 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; *zCsr++ = quote; for(i=0; i<nAppend; i++){ *zCsr++ = zAppend[i]; |
︙ | ︙ | |||
1005 1006 1007 1008 1009 1010 1011 | ShellText s; char cQuote; char *zDiv = "("; int nRow = 0; zSql = sqlite3_mprintf("PRAGMA \"%w\".table_info=%Q;", zSchema ? zSchema : "main", zName); | < < | 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 | ShellText s; char cQuote; char *zDiv = "("; int nRow = 0; zSql = sqlite3_mprintf("PRAGMA \"%w\".table_info=%Q;", zSchema ? zSchema : "main", zName); sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); initText(&s); if( zSchema ){ cQuote = quoteChar(zSchema); if( cQuote && sqlite3_stricmp(zSchema,"temp")==0 ) cQuote = 0; appendText(&s, zSchema, cQuote); appendText(&s, ".", 0); } cQuote = quoteChar(zName); appendText(&s, zName, cQuote); while( sqlite3_step(pStmt)==SQLITE_ROW ){ const char *zCol = (const char*)sqlite3_column_text(pStmt, 1); nRow++; appendText(&s, zDiv, 0); zDiv = ","; cQuote = quoteChar(zCol); appendText(&s, zCol, cQuote); } appendText(&s, ")", 0); sqlite3_finalize(pStmt); if( nRow==0 ){ freeText(&s); |
︙ | ︙ | |||
1046 1047 1048 1049 1050 1051 1052 | ** table X. */ static void shellModuleSchema( sqlite3_context *pCtx, int nVal, sqlite3_value **apVal ){ | | | < < | 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 | ** table X. */ static void shellModuleSchema( sqlite3_context *pCtx, int nVal, sqlite3_value **apVal ){ const char *zName = (const char*)sqlite3_value_text(apVal[0]); char *zFake = shellFakeSchema(sqlite3_context_db_handle(pCtx), 0, zName); UNUSED_PARAMETER(nVal); if( zFake ){ sqlite3_result_text(pCtx, sqlite3_mprintf("/* %s */", zFake), -1, sqlite3_free); free(zFake); } } |
︙ | ︙ | |||
1075 1076 1077 1078 1079 1080 1081 | ** 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 | | | | | | 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 | ** 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_master.sql field. */ static void shellAddSchemaName( sqlite3_context *pCtx, int nVal, sqlite3_value **apVal ){ static const char *aPrefix[] = { "TABLE", "INDEX", "UNIQUE INDEX", "VIEW", "TRIGGER", "VIRTUAL TABLE" }; int i = 0; const char *zIn = (const char*)sqlite3_value_text(apVal[0]); const char *zSchema = (const char*)sqlite3_value_text(apVal[1]); const char *zName = (const char*)sqlite3_value_text(apVal[2]); sqlite3 *db = sqlite3_context_db_handle(pCtx); UNUSED_PARAMETER(nVal); if( zIn!=0 && strncmp(zIn, "CREATE ", 7)==0 ){ for(i=0; i<(int)(sizeof(aPrefix)/sizeof(aPrefix[0])); i++){ int n = strlen30(aPrefix[i]); if( strncmp(zIn+7, aPrefix[i], n)==0 && zIn[n+7]==' ' ){ char *z = 0; char *zFake = 0; if( zSchema ){ char cQuote = quoteChar(zSchema); if( cQuote && sqlite3_stricmp(zSchema,"temp")!=0 ){ z = sqlite3_mprintf("%.*s \"%w\".%s", n+7, zIn, zSchema, zIn+n+8); }else{ |
︙ | ︙ | |||
1145 1146 1147 1148 1149 1150 1151 | #define SQLITE_EXTENSION_INIT2(X) (void)(X) #if defined(_WIN32) && defined(_MSC_VER) INCLUDE test_windirent.h INCLUDE test_windirent.c #define dirent DIRENT #endif | < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < > > > > > > > > > > > > | 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 | #define SQLITE_EXTENSION_INIT2(X) (void)(X) #if defined(_WIN32) && defined(_MSC_VER) INCLUDE test_windirent.h INCLUDE test_windirent.c #define dirent DIRENT #endif INCLUDE ../ext/misc/shathree.c INCLUDE ../ext/misc/fileio.c INCLUDE ../ext/misc/completion.c INCLUDE ../ext/misc/appendvfs.c INCLUDE ../ext/misc/memtrace.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 /* ** Shell output mode information from before ".explain on", ** saved so that it can be restored by ".explain off" */ typedef struct SavedModeInfo SavedModeInfo; struct SavedModeInfo { int valid; /* Is there legit data in here? */ int mode; /* Mode prior to ".explain on" */ int showHeader; /* The ".header" setting prior to ".explain on" */ int colWidth[100]; /* Column widths prior to ".explain on" */ }; typedef struct ExpertInfo ExpertInfo; struct ExpertInfo { sqlite3expert *pExpert; int bVerbose; }; |
︙ | ︙ | |||
1223 1224 1225 1226 1227 1228 1229 | typedef struct EQPGraph EQPGraph; struct EQPGraph { EQPGraphRow *pRow; /* Linked list of all rows of the EQP output */ EQPGraphRow *pLast; /* Last element of the pRow list */ char zPrefix[100]; /* Graph prefix */ }; | < < < < < < < < < > < < < < < < < | | < > > > < < < < < < < < < < < < | < < < < < > > > < < < < | 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 | typedef struct EQPGraph EQPGraph; struct EQPGraph { EQPGraphRow *pRow; /* Linked list of all rows of the EQP output */ EQPGraphRow *pLast; /* Last element of the pRow list */ char zPrefix[100]; /* Graph prefix */ }; /* ** State information about the database connection is contained in an ** instance of the following structure. */ typedef struct ShellState ShellState; struct ShellState { sqlite3 *db; /* The database */ u8 autoExplain; /* Automatically turn on .explain mode */ u8 autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */ u8 autoEQPtest; /* autoEQP is in test mode */ u8 autoEQPtrace; /* autoEQP is in trace mode */ u8 statsOn; /* True to display memory stats before each finalize */ u8 scanstatsOn; /* True to display scan stats before each finalize */ u8 openMode; /* SHELL_OPEN_NORMAL, _APPENDVFS, or _ZIPFILE */ u8 doXdgOpen; /* Invoke start/open/xdg-open in output_reset() */ u8 nEqpLevel; /* Depth of the EQP output graph */ u8 eTraceType; /* SHELL_TRACE_* value for type of trace */ 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 */ 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 */ 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[100]; /* Requested width of each column when in column mode*/ int actualWidth[100]; /* Actual width of each column */ char nullValue[20]; /* The text to print when a NULL comes back from ** the database */ char outfile[FILENAME_MAX]; /* Filename for *out */ const char *zDbFilename; /* name of the database file */ char *zFreeOnClose; /* Filename to free when closing */ const char *zVfs; /* Name of VFS to use */ sqlite3_stmt *pStmt; /* Current statement if any. */ FILE *pLog; /* Write log output here */ int *aiIndent; /* Array of indents used in MODE_Explain */ int nIndent; /* Size of array aiIndent[] */ int iIndent; /* Index of current op in aiIndent[] */ EQPGraph sGraph; /* Information for the graphical EXPLAIN QUERY PLAN */ #if defined(SQLITE_ENABLE_SESSION) int nSession; /* Number of active sessions */ OpenSession aSession[4]; /* Array of sessions. [0] is in focus. */ #endif ExpertInfo expert; /* Valid if previous command was ".expert OPT..." */ }; /* Allowed values for ShellState.autoEQP */ #define AUTOEQP_off 0 /* Automatic EXPLAIN QUERY PLAN is off */ #define AUTOEQP_on 1 /* Automatic EQP is on */ #define AUTOEQP_trigger 2 /* On and also show plans for triggers */ |
︙ | ︙ | |||
1359 1360 1361 1362 1363 1364 1365 | */ #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 */ | | < < < | 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 | */ #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))) |
︙ | ︙ | |||
1387 1388 1389 1390 1391 1392 1393 | #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 */ | < < < < < < | < < < < < < < < < < < < | 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 | #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", "eqp" }; /* ** These are the column/row/line separators used by the various ** import/export modes. */ #define SEP_Column "|" #define SEP_Row "\n" #define SEP_Tab "\t" #define SEP_Space " " #define SEP_Comma "," #define SEP_CrLf "\r\n" #define SEP_Unit "\x1F" #define SEP_Record "\x1E" /* ** A callback for the sqlite3_log() interface. */ static void shellLog(void *pArg, int iErrCode, const char *zMsg){ ShellState *p = (ShellState*)pArg; if( p->pLog==0 ) return; utf8_printf(p->pLog, "(%d) %s\n", iErrCode, zMsg); |
︙ | ︙ | |||
1462 1463 1464 1465 1466 1467 1468 | ){ 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]); } | < < < < < < < < < < < < < < < < < < < < < | 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 | ){ ShellState *p = (ShellState*)sqlite3_user_data(pCtx); (void)nVal; utf8_printf(p->out, "%s\n", sqlite3_value_text(apVal[0])); sqlite3_result_value(pCtx, apVal[0]); } /* ** SQL function: edit(VALUE) ** edit(VALUE,EDITOR) ** ** These steps: ** ** (1) Write VALUE into a temporary file. |
︙ | ︙ | |||
1552 1553 1554 1555 1556 1557 1558 | 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 ){ | | | | 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 | f = fopen(zTempFile, bBin ? "wb" : "w"); if( f==0 ){ sqlite3_result_error(context, "edit() cannot open temp file", -1); goto edit_func_end; } sz = sqlite3_value_bytes(argv[0]); if( bBin ){ x = fwrite(sqlite3_value_blob(argv[0]), 1, sz, f); }else{ 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, 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; } |
︙ | ︙ | |||
1585 1586 1587 1588 1589 1590 1591 | 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); | | | > | < < < | < < | | < < < < < < < < < | < | 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 | sqlite3_result_error(context, "edit() cannot reopen temp file after edit", -1); goto edit_func_end; } fseek(f, 0, SEEK_END); sz = ftell(f); rewind(f); p = sqlite3_malloc64( sz+(bBin==0) ); if( p==0 ){ sqlite3_result_error_nomem(context); goto edit_func_end; } x = fread(p, 1, 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 */ j = sz; }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]; } sz = j; p[sz] = 0; } sqlite3_result_text64(context, (const char*)p, sz, sqlite3_free, SQLITE_UTF8); } p = 0; edit_func_end: if( f ) fclose(f); unlink(zTempFile); sqlite3_free(zTempFile); sqlite3_free(p); } #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' ) */ static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){ int i; char *zBlob = (char *)pBlob; raw_printf(out,"X'"); for(i=0; i<nBlob; i++){ raw_printf(out,"%02x",zBlob[i]&0xff); } raw_printf(out,"'"); } /* ** Find a string that is not found anywhere in z[]. Return a pointer ** to that string. ** ** Try to use zA and zB first. If both of those are already found in z[] |
︙ | ︙ | |||
1820 1821 1822 1823 1824 1825 1826 | }else{ fputc(c, out); } } fputc('"', out); } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 | }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; if( z==0 ) z = ""; |
︙ | ︙ | |||
1923 1924 1925 1926 1927 1928 1929 | ** 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{ | | > | > > | < | 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 | ** 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{ int i; int nSep = strlen30(p->colSeparator); for(i=0; z[i]; i++){ if( needCsvQuote[((unsigned char*)z)[i]] || (z[i]==p->colSeparator[0] && (nSep==1 || memcmp(z, p->colSeparator, nSep)==0)) ){ i = 0; break; } } if( i==0 ){ char *zQuoted = sqlite3_mprintf("\"%w\"", z); utf8_printf(out, "%s", zQuoted); sqlite3_free(zQuoted); }else{ utf8_printf(out, "%s", z); } } if( bSep ){ |
︙ | ︙ | |||
1970 1971 1972 1973 1974 1975 1976 | return TRUE; } return FALSE; } #endif #ifndef SQLITE_OMIT_AUTHORIZATION | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 | 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, |
︙ | ︙ | |||
2059 2060 2061 2062 2063 2064 2065 | if( az[i] ){ output_c_string(p->out, az[i]); }else{ raw_printf(p->out, "NULL"); } } raw_printf(p->out, "\n"); | < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | 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){ char c = z[n]; z[n] = 0; printSchemaLine(out, z, zTail); z[n] = c; } |
︙ | ︙ | |||
2128 2129 2130 2131 2132 2133 2134 | } /* ** Add a new entry to the EXPLAIN QUERY PLAN data */ static void eqp_append(ShellState *p, int iEqpId, int p2, const char *zText){ EQPGraphRow *pNew; | < < | | | 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 | } /* ** Add a new entry to the EXPLAIN QUERY PLAN data */ static void eqp_append(ShellState *p, int iEqpId, int p2, const char *zText){ EQPGraphRow *pNew; int nText = strlen30(zText); if( p->autoEQPtest ){ utf8_printf(p->out, "%d,%d,%s\n", iEqpId, p2, zText); } pNew = sqlite3_malloc64( sizeof(*pNew) + nText ); if( pNew==0 ) shell_out_of_memory(); pNew->iEqpId = iEqpId; pNew->iParentId = p2; memcpy(pNew->zText, zText, nText+1); pNew->pNext = 0; if( p->sGraph.pLast ){ p->sGraph.pLast->pNext = pNew; }else{ |
︙ | ︙ | |||
2175 2176 2177 2178 2179 2180 2181 | } /* Render a single level of the graph that has iEqpId as its parent. Called ** recursively to render sublevels. */ static void eqp_render_level(ShellState *p, int iEqpId){ EQPGraphRow *pRow, *pNext; | | | < | | < < | 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 | } /* Render a single level of the graph that has iEqpId as its parent. Called ** recursively to render sublevels. */ 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; } } } /* ** Display and reset the EXPLAIN QUERY PLAN data */ static void eqp_render(ShellState *p){ EQPGraphRow *pRow = p->sGraph.pRow; if( pRow ){ if( pRow->zText[0]=='-' ){ if( pRow->pNext==0 ){ eqp_reset(p); return; } utf8_printf(p->out, "%s\n", pRow->zText+3); p->sGraph.pRow = pRow->pNext; sqlite3_free(pRow); }else{ utf8_printf(p->out, "QUERY PLAN\n"); } p->sGraph.zPrefix[0] = 0; eqp_render_level(p, 0); eqp_reset(p); } |
︙ | ︙ | |||
2235 2236 2237 2238 2239 2240 2241 | if( (p->flgProgress & SHELL_PROGRESS_QUIET)==0 ){ raw_printf(p->out, "Progress %u\n", p->nProgress); } return 0; } #endif /* SQLITE_OMIT_PROGRESS_CALLBACK */ | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < | > | | > > > > > > > | > > > > | > > > > > > > > > > > > > | | | > > | > > | > > > > | > > | > > > | > | > | | | 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 | if( (p->flgProgress & SHELL_PROGRESS_QUIET)==0 ){ raw_printf(p->out, "Progress %u\n", p->nProgress); } return 0; } #endif /* SQLITE_OMIT_PROGRESS_CALLBACK */ /* ** 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 */ ){ 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: case MODE_Column: { static const int aExplainWidths[] = {4, 13, 4, 4, 4, 13, 2, 13}; const int *colWidth; int showHdr; char *rowSep; if( p->cMode==MODE_Column ){ colWidth = p->colWidth; showHdr = p->showHeader; rowSep = p->rowSeparator; }else{ colWidth = aExplainWidths; showHdr = 1; rowSep = SEP_Row; } if( p->cnt++==0 ){ for(i=0; i<nArg; i++){ int w, n; if( i<ArraySize(p->colWidth) ){ w = colWidth[i]; }else{ w = 0; } if( w==0 ){ w = strlenChar(azCol[i] ? azCol[i] : ""); if( w<10 ) w = 10; n = strlenChar(azArg && azArg[i] ? azArg[i] : p->nullValue); if( w<n ) w = n; } if( i<ArraySize(p->actualWidth) ){ p->actualWidth[i] = w; } if( showHdr ){ utf8_width_print(p->out, w, azCol[i]); utf8_printf(p->out, "%s", i==nArg-1 ? rowSep : " "); } } if( showHdr ){ for(i=0; i<nArg; i++){ int w; if( i<ArraySize(p->actualWidth) ){ w = p->actualWidth[i]; if( w<0 ) w = -w; }else{ w = 10; } utf8_printf(p->out,"%-*.*s%s",w,w, "----------------------------------------------------------" "----------------------------------------------------------", i==nArg-1 ? rowSep : " "); } } } if( azArg==0 ) break; for(i=0; i<nArg; i++){ int w; if( i<ArraySize(p->actualWidth) ){ w = p->actualWidth[i]; }else{ w = 10; } if( p->cMode==MODE_Explain && 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); utf8_printf(p->out, "%s", i==nArg-1 ? rowSep : " "); } break; } case MODE_Semi: { /* .schema and .fullschema output */ printSchemaLine(p->out, azArg[0], ";\n"); break; } |
︙ | ︙ | |||
2358 2359 2360 2361 2362 2363 2364 | if( sqlite3_strlike("CREATE VIEW%", azArg[0], 0)==0 || sqlite3_strlike("CREATE TRIG%", azArg[0], 0)==0 ){ utf8_printf(p->out, "%s;\n", azArg[0]); break; } z = sqlite3_mprintf("%s", azArg[0]); | < | | 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 | if( sqlite3_strlike("CREATE VIEW%", azArg[0], 0)==0 || sqlite3_strlike("CREATE TRIG%", azArg[0], 0)==0 ){ utf8_printf(p->out, "%s;\n", azArg[0]); break; } z = sqlite3_mprintf("%s", azArg[0]); j = 0; for(i=0; IsSpace(z[i]); i++){} for(; (c = z[i])!=0; i++){ if( IsSpace(c) ){ if( z[j-1]=='\r' ) z[j-1] = '\n'; if( IsSpace(z[j-1]) || z[j-1]=='(' ) continue; }else if( (c=='(' || c==')') && j>0 && IsSpace(z[j-1]) ){ j--; } z[j++] = c; } while( j>0 && IsSpace(z[j-1]) ){ j--; } z[j] = 0; if( strlen30(z)>=79 ){ for(i=j=0; (c = z[i])!=0; i++){ /* Copy changes from z[i] back to z[j] */ if( c==cEnd ){ cEnd = 0; }else if( c=='"' || c=='\'' || c=='`' ){ cEnd = c; }else if( c=='[' ){ cEnd = ']'; }else if( c=='-' && z[i+1]=='-' ){ |
︙ | ︙ | |||
2490 2491 2492 2493 2494 2495 2496 | utf8_printf(p->out,"INSERT INTO %s",p->zDestTable); if( p->showHeader ){ raw_printf(p->out,"("); for(i=0; i<nArg; i++){ if( i>0 ) raw_printf(p->out, ","); if( quoteChar(azCol[i]) ){ char *z = sqlite3_mprintf("\"%w\"", azCol[i]); | < | 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 | utf8_printf(p->out,"INSERT INTO %s",p->zDestTable); if( p->showHeader ){ raw_printf(p->out,"("); for(i=0; i<nArg; i++){ if( i>0 ) raw_printf(p->out, ","); if( quoteChar(azCol[i]) ){ char *z = sqlite3_mprintf("\"%w\"", azCol[i]); utf8_printf(p->out, "%s", z); sqlite3_free(z); }else{ raw_printf(p->out, "%s", azCol[i]); } } raw_printf(p->out,")"); |
︙ | ︙ | |||
2522 2523 2524 2525 2526 2527 2528 | 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{ | < < < < | < | | < < < < < | < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | 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 | 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_hex_blob(p->out, pBlob, nBlob); }else if( isNumber(azArg[i], 0) ){ utf8_printf(p->out,"%s", azArg[i]); }else if( ShellHasFlag(p, SHFLG_Newlines) ){ output_quoted_string(p->out, azArg[i]); }else{ output_quoted_escaped_string(p->out, azArg[i]); } } raw_printf(p->out,");\n"); break; } case MODE_Quote: { if( azArg==0 ) break; if( p->cnt==0 && p->showHeader ){ for(i=0; i<nArg; i++){ if( i>0 ) raw_printf(p->out, ","); output_quoted_string(p->out, azCol[i]); } raw_printf(p->out,"\n"); } p->cnt++; for(i=0; i<nArg; i++){ if( i>0 ) raw_printf(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 ){ |
︙ | ︙ | |||
2620 2621 2622 2623 2624 2625 2626 | 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]); } } | | | 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 | 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]); } } raw_printf(p->out,"\n"); 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] : ""); |
︙ | ︙ | |||
2693 2694 2695 2696 2697 2698 2699 | "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 " | | | | | 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 | "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_master ORDER BY 2'',224))',\n" " hex(sha3_query('SELECT type,name,tbl_name,sql " "FROM sqlite_master 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_master\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" |
︙ | ︙ | |||
2741 2742 2743 2744 2745 2746 2747 | p->zDestTable = 0; } if( zName==0 ) return; cQuote = quoteChar(zName); n = strlen30(zName); if( cQuote ) n += n+2; z = p->zDestTable = malloc( n+1 ); | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > < | | < > > > > | 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 | p->zDestTable = 0; } if( zName==0 ) return; cQuote = quoteChar(zName); n = strlen30(zName); if( cQuote ) n += n+2; z = p->zDestTable = malloc( n+1 ); if( z==0 ) shell_out_of_memory(); n = 0; if( cQuote ) z[n++] = cQuote; for(i=0; zName[i]; i++){ z[n++] = zName[i]; if( zName[i]==cQuote ) z[n++] = cQuote; } if( cQuote ) z[n++] = cQuote; z[n] = 0; } /* ** Execute a query statement that will generate SQL output. Print ** the result columns, comma-separated, on a line and then add a ** semicolon terminator to the end of that line. ** ** 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 */ const char *zFirstRow /* Print before first row, if not NULL */ ){ 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 ){ if( zFirstRow ){ utf8_printf(p->out, "%s", zFirstRow); zFirstRow = 0; } 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++; |
︙ | ︙ | |||
2850 2851 2852 2853 2854 2855 2856 | sqlite3_errmsg(p->db)); if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++; } return rc; } /* | | | < < < > | < < < < < < < | < | < < | | 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 | sqlite3_errmsg(p->db)); if( (rc&0xff)!=SQLITE_CORRUPT ) p->nErr++; } return rc; } /* ** Allocate space and save off current error string. */ static char *save_err_msg( sqlite3 *db /* Database to query */ ){ int nErrMsg = 1+strlen30(sqlite3_errmsg(db)); char *zErrMsg = sqlite3_malloc64(nErrMsg); if( zErrMsg ){ memcpy(zErrMsg, sqlite3_errmsg(db), nErrMsg); } return zErrMsg; } #ifdef __linux__ /* ** Attempt to display I/O stats on Linux using /proc/PID/io */ static void displayLinuxIoStats(FILE *out){ |
︙ | ︙ | |||
2901 2902 2903 2904 2905 2906 2907 | { "read_bytes: ", "Bytes read from storage:" }, { "write_bytes: ", "Bytes written to storage:" }, { "cancelled_write_bytes: ", "Cancelled write bytes:" }, }; int i; for(i=0; i<ArraySize(aTrans); i++){ int n = strlen30(aTrans[i].zPattern); | | | 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 | { "read_bytes: ", "Bytes read from storage:" }, { "write_bytes: ", "Bytes written to storage:" }, { "cancelled_write_bytes: ", "Cancelled write bytes:" }, }; int i; for(i=0; i<ArraySize(aTrans); i++){ int n = strlen30(aTrans[i].zPattern); if( strncmp(aTrans[i].zPattern, z, n)==0 ){ utf8_printf(out, "%-36s %s", aTrans[i].zDesc, &z[n]); break; } } } fclose(in); } |
︙ | ︙ | |||
2951 2952 2953 2954 2955 2956 2957 | ){ int iCur; int iHiwtr; FILE *out; if( pArg==0 || pArg->out==0 ) return 0; out = pArg->out; | | | 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 | ){ 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); |
︙ | ︙ | |||
2975 2976 2977 2978 2979 2980 2981 | 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 } } | < < < < < < < < | 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 | 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:", "%lld (max %lld) pages", SQLITE_STATUS_PAGECACHE_USED, bReset); |
︙ | ︙ | |||
3050 3051 3052 3053 3054 3055 3056 | iHiwtr = iCur = -1; sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset); raw_printf(pArg->out, "Statement Heap/Lookaside Usage: %d bytes\n", iCur); } if( pArg->pStmt ){ | < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | < < | < < < < < < < | < > | > | < | | < < | < < < | | | < < < < | < < | < | < | < < < < | | | | < | | > | | < | | < | < < < | < | < < < | < | 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 | iHiwtr = iCur = -1; sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset); raw_printf(pArg->out, "Statement Heap/Lookaside Usage: %d bytes\n", iCur); } if( pArg->pStmt ){ iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, bReset); 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); } #ifdef __linux__ displayLinuxIoStats(pArg->out); #endif /* Do not remove this machine readable comment: extra-stats-output-here */ return 0; } /* ** Display scan stats. */ static void display_scanstats( sqlite3 *db, /* Database to query */ ShellState *pArg /* Pointer to ShellState */ ){ #ifndef SQLITE_ENABLE_STMT_SCANSTATUS UNUSED_PARAMETER(db); UNUSED_PARAMETER(pArg); #else int i, k, n, mx; raw_printf(pArg->out, "-------- scanstats --------\n"); mx = 0; for(k=0; k<=mx; k++){ double rEstLoop = 1.0; for(i=n=0; 1; i++){ sqlite3_stmt *p = pArg->pStmt; sqlite3_int64 nLoop, nVisit; double rEst; int iSid; const char *zExplain; if( sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop) ){ break; } sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_SELECTID, (void*)&iSid); if( iSid>mx ) mx = iSid; if( iSid!=k ) continue; if( n==0 ){ rEstLoop = (double)nLoop; if( k>0 ) raw_printf(pArg->out, "-------- subquery %d -------\n", k); } n++; sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit); sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EST, (void*)&rEst); sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain); utf8_printf(pArg->out, "Loop %2d: %s\n", n, zExplain); rEstLoop *= rEst; raw_printf(pArg->out, " nLoop=%-8lld nRow=%-8lld estRow=%-8lld estRow/Loop=%-8g\n", nLoop, nVisit, (sqlite3_int64)(rEstLoop+0.5), rEst ); } } raw_printf(pArg->out, "---------------------------\n"); #endif } /* ** Parameter azArray points to a zero-terminated array of strings. zStr ** points to a single nul-terminated string. Return non-zero if zStr ** is equal, according to strcmp(), to any of the strings in the array. ** Otherwise, return zero. */ static int str_in_array(const char *zStr, const char **azArray){ int i; for(i=0; azArray[i]; i++){ if( 0==strcmp(zStr, azArray[i]) ) return 1; } return 0; } /* ** If compiled statement pSql appears to be an EXPLAIN statement, allocate ** and populate the ShellState.aiIndent[] array with the number of ** spaces each opcode should be indented before it is output. ** ** The indenting rules are: ** ** * For each "Next", "Prev", "VNext" or "VPrev" instruction, indent ** all opcodes that occur between the p2 jump destination and the opcode ** itself by 2 spaces. ** ** * For each "Goto", if the jump destination is earlier in the program ** and ends on one of: ** Yield SeekGt SeekLt RowSetRead Rewind ** or if the P1 parameter is one instead of zero, ** then indent all opcodes between the earlier instruction ** and "Goto" by 2 spaces. */ static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){ const char *zSql; /* The text of the SQL statement */ const char *z; /* Used to check if this is an EXPLAIN */ int *abYield = 0; /* True if op is an OP_Yield */ int nAlloc = 0; /* Allocated size of p->aiIndent[], abYield */ int iOp; /* Index of operation in p->aiIndent[] */ const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", 0 }; const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead", "Rewind", 0 }; const char *azGoto[] = { "Goto", 0 }; /* Try to figure out if this is really an EXPLAIN statement. If this ** cannot be verified, return early. */ if( sqlite3_column_count(pSql)!=8 ){ |
︙ | ︙ | |||
3283 3284 3285 3286 3287 3288 3289 | if( iOp==0 ){ /* Do further verfication that this is explain output. Abort if ** it is not */ static const char *explainCols[] = { "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment" }; int jj; for(jj=0; jj<ArraySize(explainCols); jj++){ | | | | | | 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 | if( iOp==0 ){ /* Do further verfication that this is explain output. Abort if ** it is not */ static const char *explainCols[] = { "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment" }; int jj; for(jj=0; jj<ArraySize(explainCols); jj++){ if( strcmp(sqlite3_column_name(pSql,jj),explainCols[jj])!=0 ){ p->cMode = p->mode; sqlite3_reset(pSql); return; } } } nAlloc += 100; p->aiIndent = (int*)sqlite3_realloc64(p->aiIndent, nAlloc*sizeof(int)); if( p->aiIndent==0 ) shell_out_of_memory(); abYield = (int*)sqlite3_realloc64(abYield, nAlloc*sizeof(int)); if( abYield==0 ) shell_out_of_memory(); } abYield[iOp] = str_in_array(zOp, azYield); p->aiIndent[iOp] = 0; p->nIndent = iOp+1; if( str_in_array(zOp, azNext) ){ for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2; } if( str_in_array(zOp, azGoto) && p2op<p->nIndent && (abYield[p2op] || sqlite3_column_int(pSql, 2)) ){ for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2; } |
︙ | ︙ | |||
3326 3327 3328 3329 3330 3331 3332 | sqlite3_free(p->aiIndent); p->aiIndent = 0; p->nIndent = 0; p->iIndent = 0; } /* | | > > | > > > | > < > | | > > | | > > | > > | > < < < | < | | | | 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 | sqlite3_free(p->aiIndent); p->aiIndent = 0; p->nIndent = 0; p->iIndent = 0; } /* ** Disable and restore .wheretrace and .selecttrace settings. */ #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE) extern int sqlite3SelectTrace; static int savedSelectTrace; #endif #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE) extern int sqlite3WhereTrace; static int savedWhereTrace; #endif static void disable_debug_trace_modes(void){ #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE) savedSelectTrace = sqlite3SelectTrace; sqlite3SelectTrace = 0; #endif #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE) savedWhereTrace = sqlite3WhereTrace; sqlite3WhereTrace = 0; #endif } static void restore_debug_trace_modes(void){ #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE) sqlite3SelectTrace = savedSelectTrace; #endif #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE) sqlite3WhereTrace = savedWhereTrace; #endif } /* Create the TEMP table used to store parameter bindings */ static void bind_table_init(ShellState *p){ int wrSchema = 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 ANY\n" ") WITHOUT ROWID;", 0, 0, 0); sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, wrSchema, 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 special character '$' ** is included in the table name to help prevent collisions with actual 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; |
︙ | ︙ | |||
3406 3407 3408 3409 3410 3411 3412 | sqlite3_bind_null(pStmt, i); } sqlite3_reset(pQ); } sqlite3_finalize(pQ); } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < < < | 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 | sqlite3_bind_null(pStmt, i); } sqlite3_reset(pQ); } sqlite3_finalize(pQ); } /* ** Run a prepared statement */ static void exec_prepared_stmt( ShellState *pArg, /* Pointer to ShellState */ sqlite3_stmt *pStmt /* Statment to run */ ){ int rc; /* 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 ){ rc = SQLITE_NOMEM; }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 */ for(i=0; i<nCol; i++){ azCols[i] = (char *)sqlite3_column_name(pStmt, i); } do{ /* extract the data and data types */ for(i=0; i<nCol; i++){ aiTypes[i] = x = sqlite3_column_type(pStmt, i); if( x==SQLITE_BLOB && pArg && pArg->cMode==MODE_Insert ){ azVals[i] = ""; }else{ azVals[i] = (char*)sqlite3_column_text(pStmt, i); } if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){ rc = SQLITE_NOMEM; break; /* from for */ |
︙ | ︙ | |||
3901 3902 3903 3904 3905 3906 3907 | rc = SQLITE_ABORT; }else{ rc = sqlite3_step(pStmt); } } } while( SQLITE_ROW == rc ); sqlite3_free(pData); | < < < < < < < < | | | | 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 | 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 ** was ".expert". It passes the SQL in the second argument directly to ** the sqlite3expert object. ** ** If successful, SQLITE_OK is returned. Otherwise, an SQLite error ** code. In this case, (*pzErr) may be set to point to a buffer containing ** an English language error message. It is the responsibility of the ** caller to eventually free this buffer using sqlite3_free(). */ static int expertHandleSQL( ShellState *pState, const char *zSql, char **pzErr ){ assert( pState->expert.pExpert ); assert( pzErr==0 || *pzErr==0 ); return sqlite3_expert_sql(pState->expert.pExpert, zSql, pzErr); } /* ** This function is called either to silently clean up the object ** created by the ".expert" command (if bCancel==1), or to generate a ** report from it and then clean it up (if bCancel==0). ** ** If successful, SQLITE_OK is returned. Otherwise, an SQLite error ** code. In this case, (*pzErr) may be set to point to a buffer containing ** an English language error message. It is the responsibility of the ** caller to eventually free this buffer using sqlite3_free(). */ |
︙ | ︙ | |||
4007 4008 4009 4010 4011 4012 4013 | memset(&pState->expert, 0, sizeof(ExpertInfo)); for(i=1; rc==SQLITE_OK && i<nArg; i++){ char *z = azArg[i]; int n; if( z[0]=='-' && z[1]=='-' ) z++; n = strlen30(z); | | | | < < | 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 | memset(&pState->expert, 0, sizeof(ExpertInfo)); for(i=1; rc==SQLITE_OK && i<nArg; i++){ char *z = azArg[i]; int n; if( z[0]=='-' && z[1]=='-' ) z++; n = strlen30(z); if( n>=2 && 0==strncmp(z, "-verbose", n) ){ pState->expert.bVerbose = 1; } else if( n>=2 && 0==strncmp(z, "-sample", n) ){ if( i==(nArg-1) ){ raw_printf(stderr, "option requires an argument: %s\n", z); rc = SQLITE_ERROR; }else{ iSample = (int)integerValue(azArg[++i]); if( iSample<0 || iSample>100 ){ raw_printf(stderr, "value out of range: %s\n", azArg[i]); rc = SQLITE_ERROR; } } } else{ raw_printf(stderr, "unknown option: %s\n", z); rc = SQLITE_ERROR; } } if( rc==SQLITE_OK ){ pState->expert.pExpert = sqlite3_expert_new(pState->db, &zErr); if( pState->expert.pExpert==0 ){ raw_printf(stderr, "sqlite3_expert_new: %s\n", zErr); rc = SQLITE_ERROR; }else{ sqlite3_expert_config( pState->expert.pExpert, EXPERT_CONFIG_SAMPLE, iSample ); } } return rc; } #endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */ /* ** Execute a statement or set of statements. Print |
︙ | ︙ | |||
4082 4083 4084 4085 4086 4087 4088 | #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 ){ | | > > > > > < < | | < | 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 | #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); } }else{ if( !pStmt ){ /* this happens for a comment or white-space */ zSql = zLeftover; while( IsSpace(zSql[0]) ) zSql++; continue; } zStmtSql = sqlite3_sql(pStmt); if( zStmtSql==0 ) zStmtSql = ""; while( IsSpace(zStmtSql[0]) ) zStmtSql++; /* save off the prepared statment handle and reset row count */ if( pArg ){ pArg->pStmt = pStmt; pArg->cnt = 0; } /* 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]=='-' ) eqp_render(pArg); eqp_append(pArg, iEqpId, iParentId, zEQPLine); } eqp_render(pArg); } sqlite3_finalize(pExplain); sqlite3_free(zEQP); if( pArg->autoEQP>=AUTOEQP_full ){ /* Also do an EXPLAIN for ".eqp full" mode */ zEQP = sqlite3_mprintf("EXPLAIN %s", zStmtSql); rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0); if( rc==SQLITE_OK ){ pArg->cMode = MODE_Explain; explain_data_prepare(pArg, pExplain); exec_prepared_stmt(pArg, pExplain); explain_data_delete(pArg); } |
︙ | ︙ | |||
4172 4173 4174 4175 4176 4177 4178 | explain_data_prepare(pArg, pStmt); } } bind_prepared_stmt(pArg, pStmt); exec_prepared_stmt(pArg, pStmt); explain_data_delete(pArg); | | | | 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 | 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); } /* print loop-counters if required */ if( pArg && pArg->scanstatsOn ){ display_scanstats(db, pArg); } /* Finalize the statement just executed. If this fails, save a ** copy of the error message. Otherwise, set zSql to point to the ** 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); } /* clear saved stmt handle */ if( pArg ){ pArg->pStmt = NULL; } } |
︙ | ︙ | |||
4243 4244 4245 4246 4247 4248 4249 | int nAlloc = 0; int nPK = 0; /* Number of PRIMARY KEY columns seen */ int isIPK = 0; /* True if one PRIMARY KEY column of type INTEGER */ int preserveRowid = ShellHasFlag(p, SHFLG_PreserveRowid); int rc; zSql = sqlite3_mprintf("PRAGMA table_info=%Q", zTab); | < | < | 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 | int nAlloc = 0; int nPK = 0; /* Number of PRIMARY KEY columns seen */ int isIPK = 0; /* True if one PRIMARY KEY column of type INTEGER */ int preserveRowid = ShellHasFlag(p, SHFLG_PreserveRowid); int rc; zSql = sqlite3_mprintf("PRAGMA table_info=%Q", zTab); 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 ){ nAlloc = nAlloc*2 + nCol + 10; azCol = sqlite3_realloc(azCol, nAlloc*sizeof(azCol[0])); if( azCol==0 ) shell_out_of_memory(); } azCol[++nCol] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 1)); if( sqlite3_column_int(pStmt, 5) ){ nPK++; if( nPK==1 && sqlite3_stricmp((const char*)sqlite3_column_text(pStmt,2), "INTEGER")==0 ){ isIPK = 1; |
︙ | ︙ | |||
4288 4289 4290 4291 4292 4293 4294 | ** table or a INTEGER PRIMARY KEY DESC column, neither of which are ** ROWID aliases. To distinguish these cases, check to see if ** there is a "pk" entry in "PRAGMA index_list". There will be ** no "pk" index if the PRIMARY KEY really is an alias for the ROWID. */ zSql = sqlite3_mprintf("SELECT 1 FROM pragma_index_list(%Q)" " WHERE origin='pk'", zTab); | < | 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 | ** table or a INTEGER PRIMARY KEY DESC column, neither of which are ** ROWID aliases. To distinguish these cases, check to see if ** there is a "pk" entry in "PRAGMA index_list". There will be ** no "pk" index if the PRIMARY KEY really is an alias for the ROWID. */ zSql = sqlite3_mprintf("SELECT 1 FROM pragma_index_list(%Q)" " WHERE origin='pk'", zTab); rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); if( rc ){ freeColumnList(azCol); return 0; } rc = sqlite3_step(pStmt); |
︙ | ︙ | |||
4351 4352 4353 4354 4355 4356 4357 | */ 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; | < < < < < < | | | | | < < | | < | | 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 | */ 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]; if( strcmp(zTable, "sqlite_sequence")==0 ){ raw_printf(p->out, "DELETE FROM sqlite_sequence;\n"); }else if( sqlite3_strglob("sqlite_stat?", zTable)==0 ){ raw_printf(p->out, "ANALYZE sqlite_master;\n"); }else if( strncmp(zTable, "sqlite_", 7)==0 ){ return 0; }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_master(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"); } if( strcmp(zType, "table")==0 ){ ShellText sSelect; ShellText sTable; char **azCol; int i; char *savedDestTable; int savedMode; |
︙ | ︙ | |||
4501 4502 4503 4504 4505 4506 4507 | return rc; } /* ** Text of help messages. ** ** The help text for each individual command begins with a line that starts | | | < | | < | | | < | | | | < < | < < < < < < < < | | < < | < | < | < < < < | > > | < < < < < < < < < < < < < < < < < < | < < | | < | | | | < | | < < | < | | < < < < < < < < < < < | | | | < < < < | | | < < | < < < < < | < | | < < < < < < < < < < | < | | | < | 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 | return rc; } /* ** Text of help messages. ** ** The help text for each individual command begins with a line that starts ** with ".". Subsequent lines are supplimental information. ** ** There must be two or more spaces between the end of the command and the ** 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 files or update files with changed mtime", " -i, --insert Like -u but always add even if mtime unchanged", " -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 Operate on archive FILE (default is current db)", " -a FILE, --append FILE Operate on FILE opened using the apndvfs VFS", " -C DIR, --directory DIR Change to directory DIR to read/extract files", " -n, --dryrun Show the SQL that would have occurred", " Examples:", " .ar -cf archive.sar foo bar # Create archive.sar from files foo and bar", " .ar -tf archive.sar # List members of archive.sar", " .ar -xvf archive.sar # Verbosely extract files from archive.sar", " See also:", " http://sqlite.org/cli.html#sqlar_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 a journal and without 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", ".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 ?TABLE? ... Render all database content as SQL", " Options:", " --preserve-rowids Include ROWID values in the output", " --newlines Allow unescaped newline characters in output", " TABLE is LIKE pattern for the tables to dump", ".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 also enable \"PRAGMA vdbe_trace\"", #endif " trigger Like \"full\" but also show trigger bytecode", ".excel Display the output of next command in a spreadsheet", ".exit ?CODE? Exit this program with return-code CODE", ".expert EXPERIMENTAL. Suggest indexes for specified queries", /* Because explain mode comes on automatically now, the ".explain" mode ** is removed from the help screen. It is still supported for legacy, however */ /*".explain ?on|off|auto? Turn EXPLAIN output mode on or off or to automatic",*/ ".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", #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", " csv Comma-separated values", " column Left-aligned columns. (See .width)", " html HTML <table> code", " insert SQL insert statements for TABLE", " line One value per line", " list Values delimited by \"|\"", " quote Escape answers as for SQL", " tabs Tab-separated values", " tcl TCL list elements", ".nullvalue STRING Use STRING in place of NULL values", ".once (-e|-x|FILE) Output for the next SQL command only to FILE", " If FILE begins with '|' then open as a pipe", " Other options:", " -e Invoke system text editor", " -x Open in a spreadsheet", ".open ?OPTIONS? ?FILE? Close existing database and reopen FILE", " Options:", " --append Use appendvfs to append database to the end of FILE", #ifdef SQLITE_ENABLE_DESERIALIZE " --deserialize Load into memory useing sqlite3_deserialize()", " --hexdb Load the output of \"dbtotxt\" as an in-memory database", " --maxsize N Maximum size for --hexdb or --deserialized database", #endif " --new Initialize FILE to an empty database", " --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.", ".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 '$', ':', '@', or '?'", " 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", ".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", ".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", |
︙ | ︙ | |||
4739 4740 4741 4742 4743 4744 4745 | " 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:", | | | | | < < < < | < < < < < < < < < | | | < < | 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 | " 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_master table", " --sha3-224 Use the sha3-224 algorithm", " --sha3-256 Use the sha3-256 algorithm. This is the 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 ?on|off? Show stats or turn stats on or off", #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'", ".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 */ ".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 column widths for \"column\" mode", " Negative values right-justify", }; /* ** Output help text. ** ** zPattern describes the set of commands for which help text is provided. ** If zPattern is NULL, then show all commands, but only give a one-line ** description of each. ** ** Return the number of matches. */ static int showHelp(FILE *out, const char *zPattern){ int i = 0; 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++; } } }else{ /* Look for commands that for which zPattern is an exact prefix */ zPat = sqlite3_mprintf(".%s*", zPattern); for(i=0; i<ArraySize(azHelp); i++){ if( sqlite3_strglob(zPat, azHelp[i])==0 ){ utf8_printf(out, "%s\n", azHelp[i]); j = i+1; n++; } } |
︙ | ︙ | |||
4847 4848 4849 4850 4851 4852 4853 | } } return n; } /* Look for commands that contain zPattern anywhere. Show the complete ** text of all commands that match. */ zPat = sqlite3_mprintf("%%%s%%", zPattern); | < | 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 | } } return n; } /* Look for commands that contain zPattern anywhere. Show the complete ** text of all commands that match. */ zPat = sqlite3_mprintf("%%%s%%", zPattern); for(i=0; i<ArraySize(azHelp); i++){ if( azHelp[i][0]=='.' ) j = i; if( sqlite3_strlike(zPat, azHelp[i], 0)==0 ){ utf8_printf(out, "%s\n", azHelp[j]); while( j<ArraySize(azHelp)-1 && azHelp[j+1][0]!='.' ){ j++; utf8_printf(out, "%s\n", azHelp[j]); |
︙ | ︙ | |||
4926 4927 4928 4929 4930 4931 4932 | } #endif /* ** Close all OpenSession objects and release all associated resources. */ #if defined(SQLITE_ENABLE_SESSION) | | | < | | | | | 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 | } #endif /* ** Close all OpenSession objects and release all associated resources. */ #if defined(SQLITE_ENABLE_SESSION) static void session_close_all(ShellState *p){ int i; for(i=0; i<p->nSession; i++){ session_close(&p->aSession[i]); } p->nSession = 0; } #else # define session_close_all(X) #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) |
︙ | ︙ | |||
4994 4995 4996 4997 4998 4999 5000 | && zBuf[3]==0x06 ){ rc = SHELL_OPEN_ZIPFILE; }else if( n==0 && dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){ rc = SHELL_OPEN_ZIPFILE; } } fclose(f); | | | | | < | | | | < | < < | > > | > | | > | | < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | < | < | < < < < < < < < < < > < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | | > < < < | < | < < < | | | < | | 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 | && zBuf[3]==0x06 ){ rc = SHELL_OPEN_ZIPFILE; }else if( n==0 && dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){ rc = SHELL_OPEN_ZIPFILE; } } fclose(f); return rc; } #ifdef SQLITE_ENABLE_DESERIALIZE /* ** Reconstruct an in-memory database using the output from the "dbtotxt" ** program. Read content from the file in p->zDbFilename. If p->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; unsigned char x[16]; char zLine[1000]; if( p->zDbFilename ){ in = fopen(p->zDbFilename, "r"); if( in==0 ){ utf8_printf(stderr, "cannot open \"%s\" for reading\n", p->zDbFilename); return 0; } nLine = 0; }else{ in = p->in; nLine = p->lineno; } *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; a = sqlite3_malloc( n ); 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: %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx" " %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx", &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 ){ memcpy(a+k, x, 16); } } } *pnData = n; if( in!=p->in ){ fclose(in); }else{ p->lineno = nLine; } return a; readHexDb_error: if( in!=stdin ){ 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_ENABLE_DESERIALIZE */ /* 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 ){ if( p->openMode==SHELL_OPEN_UNSPEC ){ if( p->zDbFilename==0 || p->zDbFilename[0]==0 ){ p->openMode = SHELL_OPEN_NORMAL; }else{ p->openMode = (u8)deduceDatabaseType(p->zDbFilename, (openFlags & OPEN_DB_ZIPFILE)!=0); } } switch( p->openMode ){ case SHELL_OPEN_APPENDVFS: { sqlite3_open_v2(p->zDbFilename, &p->db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, "apndvfs"); break; } case SHELL_OPEN_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(p->zDbFilename, &p->db, SQLITE_OPEN_READONLY, 0); break; } case SHELL_OPEN_UNSPEC: case SHELL_OPEN_NORMAL: { sqlite3_open(p->zDbFilename, &p->db); break; } } globalDb = p->db; if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){ utf8_printf(stderr,"Error: unable to open database \"%s\": %s\n", p->zDbFilename, sqlite3_errmsg(p->db)); if( 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); #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); #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);", p->zDbFilename); sqlite3_exec(p->db, zSql, 0, 0, 0); sqlite3_free(zSql); } #ifdef SQLITE_ENABLE_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(p->zDbFilename, &nData); }else{ aData = readHexDb(p, &nData); if( aData==0 ){ utf8_printf(stderr, "Error in hexdb input\n"); 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 } } /* ** Attempt to close the databaes connection. Report errors. */ void close_db(sqlite3 *db){ int rc = sqlite3_close(db); if( rc ){ utf8_printf(stderr, "Error: sqlite3_close() returns %d: %s\n", rc, sqlite3_errmsg(db)); } } #if HAVE_READLINE || HAVE_EDITLINE /* ** Readline completion callbacks */ static char *readline_completion_generator(const char *text, int state){ static sqlite3_stmt *pStmt = 0; char *zRet; if( state==0 ){ char *zSql; sqlite3_finalize(pStmt); zSql = sqlite3_mprintf("SELECT DISTINCT candidate COLLATE nocase" " FROM completion(%Q) ORDER BY 1", text); sqlite3_prepare_v2(globalDb, zSql, -1, &pStmt, 0); sqlite3_free(zSql); } if( sqlite3_step(pStmt)==SQLITE_ROW ){ zRet = strdup((const char*)sqlite3_column_text(pStmt, 0)); }else{ sqlite3_finalize(pStmt); pStmt = 0; zRet = 0; } return zRet; } static char **readline_completion(const char *zText, int iStart, int iEnd){ rl_attempted_completion_over = 1; return rl_completion_matches(zText, readline_completion_generator); } #elif HAVE_LINENOISE /* ** Linenoise completion callback */ static void linenoise_completion(const char *zLine, linenoiseCompletions *lc){ int nLine = strlen30(zLine); int i, iStart; sqlite3_stmt *pStmt = 0; char *zSql; char zBuf[1000]; if( nLine>sizeof(zBuf)-30 ) return; if( zLine[0]=='.' || zLine[0]=='#') return; for(i=nLine-1; i>=0 && (isalnum(zLine[i]) || zLine[i]=='_'); i--){} if( i==nLine-1 ) return; iStart = i+1; memcpy(zBuf, zLine, iStart); zSql = sqlite3_mprintf("SELECT DISTINCT candidate COLLATE nocase" " FROM completion(%Q,%Q) ORDER BY 1", &zLine[iStart], zLine); sqlite3_prepare_v2(globalDb, zSql, -1, &pStmt, 0); sqlite3_free(zSql); sqlite3_exec(globalDb, "PRAGMA page_count", 0, 0, 0); /* Load the schema */ while( sqlite3_step(pStmt)==SQLITE_ROW ){ const char *zCompletion = (const char*)sqlite3_column_text(pStmt, 0); int nCompletion = sqlite3_column_bytes(pStmt, 0); if( iStart+nCompletion < sizeof(zBuf)-1 ){ memcpy(zBuf+iStart, zCompletion, nCompletion+1); linenoiseAddCompletion(lc, zBuf); } } sqlite3_finalize(pStmt); } #endif |
︙ | ︙ | |||
5603 5604 5605 5606 5607 5608 5609 | /* ** Try to open an output file. The names "stdout" and "stderr" are ** recognized and do the right thing. NULL is returned if the output ** filename is "off". */ static FILE *output_file_open(const char *zFile, int bTextMode){ FILE *f; | | | | | 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 | /* ** Try to open an output file. The names "stdout" and "stderr" are ** recognized and do the right thing. NULL is returned if the output ** filename is "off". */ static FILE *output_file_open(const char *zFile, int bTextMode){ FILE *f; if( strcmp(zFile,"stdout")==0 ){ f = stdout; }else if( strcmp(zFile, "stderr")==0 ){ f = stderr; }else if( strcmp(zFile, "off")==0 ){ f = 0; }else{ f = fopen(zFile, bTextMode ? "w" : "wb"); if( f==0 ){ utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile); } } |
︙ | ︙ | |||
5631 5632 5633 5634 5635 5636 5637 | void *pArg, /* The ShellState pointer */ void *pP, /* Usually a pointer to sqlite_stmt */ void *pX /* Auxiliary output */ ){ ShellState *p = (ShellState*)pArg; sqlite3_stmt *pStmt; const char *zSql; | | | 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 | void *pArg, /* The ShellState pointer */ void *pP, /* Usually a pointer to sqlite_stmt */ void *pX /* Auxiliary output */ ){ ShellState *p = (ShellState*)pArg; sqlite3_stmt *pStmt; const char *zSql; int nSql; if( p->traceOut==0 ) return 0; if( mType==SQLITE_TRACE_CLOSE ){ utf8_printf(p->traceOut, "-- closing database connection\n"); return 0; } if( mType!=SQLITE_TRACE_ROW && ((const char*)pX)[0]=='-' ){ zSql = (const char*)pX; |
︙ | ︙ | |||
5659 5660 5661 5662 5663 5664 5665 | default: { zSql = sqlite3_sql(pStmt); break; } } } if( zSql==0 ) return 0; | | < | | < < < | | < < < < < < < < < < < < < | | 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 | default: { zSql = sqlite3_sql(pStmt); break; } } } if( zSql==0 ) return 0; nSql = strlen30(zSql); while( nSql>0 && zSql[nSql-1]==';' ){ nSql--; } switch( mType ){ case SQLITE_TRACE_ROW: case SQLITE_TRACE_STMT: { utf8_printf(p->traceOut, "%.*s;\n", nSql, zSql); break; } case SQLITE_TRACE_PROFILE: { sqlite3_int64 nNanosec = *(sqlite3_int64*)pX; utf8_printf(p->traceOut, "%.*s; -- %lld ns\n", nSql, zSql, nNanosec); break; } } return 0; } #endif /* ** A no-op routine that runs with the ".breakpoint" doc-command. This is ** a useful spot to set a debugger breakpoint. */ static void test_breakpoint(void){ static int nCall = 0; nCall++; } /* ** 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(); } p->z[p->n++] = (char)c; } /* Read a single field of CSV text. Compatible with rfc4180 and extended ** with the option of having a separator other than ",". ** |
︙ | ︙ | |||
5877 5878 5879 5880 5881 5882 5883 | int i, j, n; int nTable = strlen30(zTable); int k = 0; int cnt = 0; const int spinRate = 10000; zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable); | < | | 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 | int i, j, n; int nTable = strlen30(zTable); int k = 0; int cnt = 0; const int spinRate = 10000; zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable); rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0); if( rc ){ utf8_printf(stderr, "Error %d: %s on [%s]\n", sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db), zQuery); goto end_data_xfer; } n = sqlite3_column_count(pQuery); zInsert = sqlite3_malloc64(200 + nTable + n*3); if( zInsert==0 ) shell_out_of_memory(); sqlite3_snprintf(200+nTable,zInsert, "INSERT OR IGNORE INTO \"%s\" VALUES(?", zTable); i = strlen30(zInsert); for(j=1; j<n; j++){ memcpy(zInsert+i, ",?", 2); i += 2; } |
︙ | ︙ | |||
5950 5951 5952 5953 5954 5955 5956 | } } /* End while */ if( rc==SQLITE_DONE ) break; sqlite3_finalize(pQuery); sqlite3_free(zQuery); zQuery = sqlite3_mprintf("SELECT * FROM \"%w\" ORDER BY rowid DESC;", zTable); | < | | | < < < | | | | | | < | < | < < | 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 | } } /* End while */ if( rc==SQLITE_DONE ) break; sqlite3_finalize(pQuery); sqlite3_free(zQuery); zQuery = sqlite3_mprintf("SELECT * FROM \"%w\" ORDER BY rowid DESC;", zTable); rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0); if( rc ){ utf8_printf(stderr, "Warning: cannot step \"%s\" backwards", zTable); break; } } /* End for(k=0...) */ end_data_xfer: sqlite3_finalize(pQuery); sqlite3_finalize(pInsert); sqlite3_free(zQuery); sqlite3_free(zInsert); } /* ** 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_master 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_master" " 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; } while( (rc = 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); zErrMsg = 0; } if( xForEach ){ 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_master" " 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( (rc = 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); zErrMsg = 0; } |
︙ | ︙ | |||
6104 6105 6106 6107 6108 6109 6110 | #else "xdg-open"; #endif char *zCmd; zCmd = sqlite3_mprintf("%s %s", zXdgOpenCmd, p->zTempFile); if( system(zCmd) ){ utf8_printf(stderr, "Failed: [%s]\n", zCmd); | < < < < < | | < | | 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 | #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) */ } p->outfile[0] = 0; p->out = stdout; } /* ** Run an SQL command and return the single integer result. */ static int db_int(ShellState *p, const char *zSql){ sqlite3_stmt *pStmt; int res = 0; sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0); if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){ res = sqlite3_column_int(pStmt,0); } sqlite3_finalize(pStmt); return res; } /* ** Convert a 2-byte or 4-byte big-endian integer into a native integer */ static unsigned int get2byteInt(unsigned char *a){ 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 ".info" 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 }, |
︙ | ︙ | |||
6189 6190 6191 6192 6193 6194 6195 | 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 ){ | > > > > | > | 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 | 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 ){ if( !sqlite3_compileoption_used("ENABLE_DBPAGE_VTAB") ){ utf8_printf(stderr, "the \".dbinfo\" command requires the " "-DSQLITE_ENABLE_DBPAGE_VTAB compile-time options\n"); }else{ 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 ){ |
︙ | ︙ | |||
6224 6225 6226 6227 6228 6229 6230 | if( val==2 ) raw_printf(p->out, " (utf16le)"); if( val==3 ) raw_printf(p->out, " (utf16be)"); } } raw_printf(p->out, "\n"); } if( zDb==0 ){ | | | | | | < | 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 | 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_master"); }else if( strcmp(zDb,"temp")==0 ){ zSchemaTab = sqlite3_mprintf("%s", "sqlite_temp_master"); }else{ zSchemaTab = sqlite3_mprintf("\"%w\".sqlite_master", 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); } sqlite3_free(zSchemaTab); sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_DATA_VERSION, &iDataVersion); utf8_printf(p->out, "%-20s %u\n", "data version", iDataVersion); return 0; } /* ** Print the current sqlite3_errmsg() value to stderr and return 1. */ static int shellDatabaseError(sqlite3 *db){ const char *zErr = sqlite3_errmsg(db); utf8_printf(stderr, "Error: %s\n", zErr); |
︙ | ︙ | |||
6358 6359 6360 6361 6362 6363 6364 | ** Compare the string as a command-line option with either one or two ** initial "-" characters. */ static int optionMatch(const char *zStr, const char *zOpt){ if( zStr[0]!='-' ) return 0; zStr++; if( zStr[0]=='-' ) zStr++; | | | 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 | ** Compare the string as a command-line option with either one or two ** initial "-" characters. */ static int optionMatch(const char *zStr, const char *zOpt){ if( zStr[0]!='-' ) return 0; zStr++; if( zStr[0]=='-' ) zStr++; return strcmp(zStr, zOpt)==0; } /* ** Delete a file. */ int shellDeleteFile(const char *zFilename){ int rc; |
︙ | ︙ | |||
6399 6400 6401 6402 6403 6404 6405 | 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 ){ | < < < < < < < < < < < < | | > > > | 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 | clearTempFile(p); sqlite3_free(p->zTempFile); p->zTempFile = 0; if( p->db ){ sqlite3_file_control(p->db, 0, SQLITE_FCNTL_TEMPFILENAME, &p->zTempFile); } if( p->zTempFile==0 ){ sqlite3_uint64 r; sqlite3_randomness(sizeof(r), &r); p->zTempFile = sqlite3_mprintf("temp%llx.%s", r, zSuffix); }else{ p->zTempFile = sqlite3_mprintf("%z.%s", p->zTempFile, zSuffix); } if( p->zTempFile==0 ){ raw_printf(stderr, "out of memory\n"); exit(1); } } /* ** The implementation of SQL scalar function fkey_collate_clause(), used ** by the ".lint fkey-indexes" command. This scalar function is always ** called with four arguments - the parent table name, the parent column name, |
︙ | ︙ | |||
6533 6534 6535 6536 6537 6538 6539 | 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 ')" ", " | | | | | 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 | 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 TABLE ' || 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_master 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 TABLE * USING INTEGER PRIMARY KEY (rowid=?)"; for(i=2; i<nArg; i++){ int n = strlen30(azArg[i]); if( n>1 && sqlite3_strnicmp("-verbose", azArg[i], n)==0 ){ bVerbose = 1; } else if( n>1 && sqlite3_strnicmp("-groupbyparent", azArg[i], n)==0 ){ |
︙ | ︙ | |||
6598 6599 6600 6601 6602 6603 6604 | const char *zEQP = (const char*)sqlite3_column_text(pSql, 0); const char *zGlob = (const char*)sqlite3_column_text(pSql, 1); const char *zFrom = (const char*)sqlite3_column_text(pSql, 2); const char *zTarget = (const char*)sqlite3_column_text(pSql, 3); const char *zCI = (const char*)sqlite3_column_text(pSql, 4); const char *zParent = (const char*)sqlite3_column_text(pSql, 5); | < < > | | > | 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 | const char *zEQP = (const char*)sqlite3_column_text(pSql, 0); const char *zGlob = (const char*)sqlite3_column_text(pSql, 1); const char *zFrom = (const char*)sqlite3_column_text(pSql, 2); const char *zTarget = (const char*)sqlite3_column_text(pSql, 3); const char *zCI = (const char*)sqlite3_column_text(pSql, 4); const char *zParent = (const char*)sqlite3_column_text(pSql, 5); rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0); if( rc!=SQLITE_OK ) break; if( SQLITE_ROW==sqlite3_step(pExplain) ){ const char *zPlan = (const char*)sqlite3_column_text(pExplain, 3); res = ( 0==sqlite3_strglob(zGlob, zPlan) || 0==sqlite3_strglob(zGlobIPK, zPlan) ); } rc = sqlite3_finalize(pExplain); if( rc!=SQLITE_OK ) break; if( res<0 ){ raw_printf(stderr, "Error: internal error"); break; |
︙ | ︙ | |||
6670 6671 6672 6673 6674 6675 6676 | 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; } | | > > > | | | | < < < < < < < | | | | < < < < < < | | < < < < < < | | < < < < < < < | | 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 | usage: raw_printf(stderr, "Usage %s sub-command ?switches...?\n", azArg[0]); raw_printf(stderr, "Where sub-commands are:\n"); raw_printf(stderr, " fkey-indexes\n"); return SQLITE_ERROR; } #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) /********************************************************************************* ** The ".archive" or ".ar" command. */ static void shellPrepare( sqlite3 *db, int *pRc, const char *zSql, sqlite3_stmt **ppStmt ){ *ppStmt = 0; if( *pRc==SQLITE_OK ){ int rc = sqlite3_prepare_v2(db, zSql, -1, ppStmt, 0); if( rc!=SQLITE_OK ){ raw_printf(stderr, "sql error: %s (%d)\n", sqlite3_errmsg(db), sqlite3_errcode(db) ); *pRc = rc; } } } static void shellPreparePrintf( sqlite3 *db, int *pRc, sqlite3_stmt **ppStmt, const char *zFmt, ... ){ *ppStmt = 0; if( *pRc==SQLITE_OK ){ va_list ap; char *z; va_start(ap, zFmt); z = sqlite3_vmprintf(zFmt, ap); va_end(ap); if( z==0 ){ *pRc = SQLITE_NOMEM; }else{ shellPrepare(db, pRc, z, ppStmt); sqlite3_free(z); } } } static void shellFinalize( int *pRc, sqlite3_stmt *pStmt ){ if( pStmt ){ sqlite3 *db = sqlite3_db_handle(pStmt); int rc = sqlite3_finalize(pStmt); if( *pRc==SQLITE_OK ){ if( rc!=SQLITE_OK ){ raw_printf(stderr, "SQL error: %s\n", sqlite3_errmsg(db)); } *pRc = rc; } } } static void shellReset( int *pRc, sqlite3_stmt *pStmt ){ int rc = sqlite3_reset(pStmt); if( *pRc==SQLITE_OK ){ if( rc!=SQLITE_OK ){ sqlite3 *db = sqlite3_db_handle(pStmt); raw_printf(stderr, "SQL error: %s\n", sqlite3_errmsg(db)); } *pRc = rc; } } /* ** Structure representing a single ".ar" command. */ typedef struct ArCommand ArCommand; struct ArCommand { u8 eCmd; /* An AR_CMD_* value */ u8 bVerbose; /* True if --verbose */ u8 bZip; /* True if the archive is a ZIP */ u8 bDryRun; /* True if --dry-run */ u8 bAppend; /* True if --append */ 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 */ sqlite3 *db; /* Database containing the archive */ }; /* ** Print a usage message for the .ar command to stderr and return SQLITE_ERROR. */ static int arUsage(FILE *f){ showHelp(f,"archive"); return SQLITE_ERROR; } /* ** Print an error message for the .ar command to stderr and return ** SQLITE_ERROR. */ static int arErrorMsg(ArCommand *pAr, const char *zFmt, ...){ va_list ap; char *z; va_start(ap, zFmt); z = sqlite3_vmprintf(zFmt, ap); |
︙ | ︙ | |||
6824 6825 6826 6827 6828 6829 6830 | */ #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 | < | | | | | < < < < < | | < < | 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 | */ #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 /* ** Other (non-command) switches. */ #define AR_SWITCH_VERBOSE 7 #define AR_SWITCH_FILE 8 #define AR_SWITCH_DIRECTORY 9 #define AR_SWITCH_APPEND 10 #define AR_SWITCH_DRYRUN 11 static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){ switch( eSwitch ){ case AR_CMD_CREATE: case AR_CMD_EXTRACT: case AR_CMD_LIST: case AR_CMD_UPDATE: case AR_CMD_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_VERBOSE: pAr->bVerbose = 1; break; case AR_SWITCH_APPEND: pAr->bAppend = 1; /* Fall thru into --file */ case AR_SWITCH_FILE: pAr->zFile = zArg; break; case AR_SWITCH_DIRECTORY: pAr->zDir = zArg; break; } return SQLITE_OK; } /* ** Parse the command line for an ".ar" command. The results are written into ** structure (*pAr). SQLITE_OK is returned if the command line is parsed ** successfully, otherwise an error message is written to stderr and ** SQLITE_ERROR returned. */ static int arParseCommand( char **azArg, /* Array of arguments passed to dot command */ int nArg, /* Number of entries in azArg[] */ ArCommand *pAr /* Populate this object */ ){ struct ArSwitch { const char *zLong; char cShort; u8 eSwitch; u8 bArg; } aSwitch[] = { { "create", 'c', AR_CMD_CREATE, 0 }, { "extract", 'x', AR_CMD_EXTRACT, 0 }, { "insert", 'i', AR_CMD_INSERT, 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); |
︙ | ︙ | |||
6970 6971 6972 6973 6974 6975 6976 | } if( pOpt->bArg ){ if( i<(n-1) ){ zArg = &z[i+1]; i = n; }else{ if( iArg>=(nArg-1) ){ | | < | 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 | } 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' ){ |
︙ | ︙ | |||
7020 7021 7022 7023 7024 7025 7026 | } return SQLITE_OK; } /* ** This function assumes that all arguments within the ArCommand.azArg[] | | | | | | < < < < < | > > > | 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 | } return SQLITE_OK; } /* ** This function assumes that all arguments within the ArCommand.azArg[] ** array refer to archive members, as for the --extract or --list commands. ** It checks that each of them are present. If any specified file is not ** present in the archive, an error is printed to stderr and an error ** code returned. Otherwise, if all specified arguments are present in ** the archive, SQLITE_OK is returned. ** ** This function strips any trailing '/' characters from each argument. ** This is consistent with the way the [tar] command seems to work on ** Linux. */ static int arCheckEntries(ArCommand *pAr){ int rc = SQLITE_OK; if( pAr->nArg ){ int i, j; sqlite3_stmt *pTest = 0; shellPreparePrintf(pAr->db, &rc, &pTest, "SELECT name FROM %s WHERE name=$name", pAr->zSrcTable ); j = sqlite3_bind_parameter_index(pTest, "$name"); for(i=0; i<pAr->nArg && rc==SQLITE_OK; i++){ char *z = pAr->azArg[i]; int n = strlen30(z); int bOk = 0; while( n>0 && z[n-1]=='/' ) n--; z[n] = '\0'; |
︙ | ︙ | |||
7069 7070 7071 7072 7073 7074 7075 | } /* ** 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 | | < | | < | | | | | 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 | } /* ** Format a WHERE clause that can be used against the "sqlar" table to ** identify all archive members that match the command arguments held ** in (*pAr). Leave this WHERE clause in (*pzWhere) before returning. ** The caller is responsible for eventually calling sqlite3_free() on ** any non-NULL (*pzWhere) value. */ static void arWhereClause( int *pRc, ArCommand *pAr, char **pzWhere /* OUT: New WHERE clause */ ){ char *zWhere = 0; if( *pRc==SQLITE_OK ){ if( pAr->nArg==0 ){ zWhere = sqlite3_mprintf("1"); }else{ int i; const char *zSep = ""; for(i=0; i<pAr->nArg; i++){ const char *z = pAr->azArg[i]; zWhere = sqlite3_mprintf( "%z%s name = '%q' OR substr(name,1,%d) = '%q/'", zWhere, zSep, z, strlen30(z)+1, z ); if( zWhere==0 ){ *pRc = SQLITE_NOMEM; break; } zSep = " OR "; } } } *pzWhere = zWhere; } /* ** Implementation of .ar "lisT" command. */ static int arListCommand(ArCommand *pAr){ const char *zSql = "SELECT %s FROM %s WHERE %s"; const char *azCols[] = { "name", "lsmode(mode), sz, datetime(mtime, 'unixepoch'), name" }; char *zWhere = 0; sqlite3_stmt *pSql = 0; |
︙ | ︙ | |||
7128 7129 7130 7131 7132 7133 7134 | if( pAr->bDryRun ){ utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql)); }else{ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ if( pAr->bVerbose ){ utf8_printf(pAr->p->out, "%s % 10d %s %s\n", sqlite3_column_text(pSql, 0), | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | 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 | if( pAr->bDryRun ){ utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql)); }else{ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ if( pAr->bVerbose ){ utf8_printf(pAr->p->out, "%s % 10d %s %s\n", sqlite3_column_text(pSql, 0), sqlite3_column_int(pSql, 1), sqlite3_column_text(pSql, 2), sqlite3_column_text(pSql, 3) ); }else{ utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0)); } } } shellFinalize(&rc, pSql); sqlite3_free(zWhere); return rc; } /* ** Implementation of .ar "eXtract" command. */ static int arExtractCommand(ArCommand *pAr){ const char *zSql1 = "SELECT " " ($dir || name)," " writefile(($dir || name), %s, mode, mtime) " "FROM %s WHERE (%s) AND (data IS NULL OR $dirOnly = 0)" " AND name NOT GLOB '*..[/\\]*'"; const char *azExtraArg[] = { "sqlar_uncompress(data, sz)", "data" }; sqlite3_stmt *pSql = 0; int rc = SQLITE_OK; char *zDir = 0; |
︙ | ︙ | |||
7221 7222 7223 7224 7225 7226 7227 | zDir = sqlite3_mprintf("%s/", pAr->zDir); }else{ zDir = sqlite3_mprintf(""); } if( zDir==0 ) rc = SQLITE_NOMEM; } | | | 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 | zDir = sqlite3_mprintf("%s/", pAr->zDir); }else{ zDir = sqlite3_mprintf(""); } if( zDir==0 ) rc = SQLITE_NOMEM; } shellPreparePrintf(pAr->db, &rc, &pSql, zSql1, azExtraArg[pAr->bZip], pAr->zSrcTable, zWhere ); if( rc==SQLITE_OK ){ j = sqlite3_bind_parameter_index(pSql, "$dir"); sqlite3_bind_text(pSql, j, zDir, -1, SQLITE_STATIC); |
︙ | ︙ | |||
7299 7300 7301 7302 7303 7304 7305 | ** "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 */ ){ | | | 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 | ** "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" " data BLOB -- compressed content\n" ")"; |
︙ | ︙ | |||
7341 7342 7343 7344 7345 7346 7347 | 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; | | | 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 | 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 */ if( pAr->zFile ){ sqlite3_uint64 r; sqlite3_randomness(sizeof(r),&r); sqlite3_snprintf(sizeof(zTemp),zTemp,"zip%016llx",r); zTab = zTemp; |
︙ | ︙ | |||
7404 7405 7406 7407 7408 7409 7410 | return rc; } /* ** Implementation of ".ar" dot command. */ static int arDotCommand( | | | | | | 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 | 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 ){ |
︙ | ︙ | |||
7435 7436 7437 7438 7439 7440 7441 | cmd.zSrcTable = sqlite3_mprintf("zipfile(%Q)", cmd.zFile); } } cmd.bZip = 1; }else if( cmd.zFile ){ int flags; if( cmd.bAppend ) eDbType = SHELL_OPEN_APPENDVFS; | | | | | | 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 | 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_UPDATE ){ flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE; }else{ flags = SQLITE_OPEN_READONLY; } cmd.db = 0; if( cmd.bDryRun ){ utf8_printf(pState->out, "-- open database '%s'%s\n", cmd.zFile, eDbType==SHELL_OPEN_APPENDVFS ? " using 'apndvfs'" : ""); } rc = sqlite3_open_v2(cmd.zFile, &cmd.db, flags, eDbType==SHELL_OPEN_APPENDVFS ? "apndvfs" : 0); if( rc!=SQLITE_OK ){ utf8_printf(stderr, "cannot open file: %s (%s)\n", cmd.zFile, sqlite3_errmsg(cmd.db) ); goto end_ar_command; } sqlite3_fileio_init(cmd.db, 0, 0); sqlite3_sqlar_init(cmd.db, 0, 0); sqlite3_create_function(cmd.db, "shell_putsnl", 1, SQLITE_UTF8, cmd.p, |
︙ | ︙ | |||
7492 7493 7494 7495 7496 7497 7498 | arUsage(pState->out); break; case AR_CMD_INSERT: rc = arCreateOrUpdateCommand(&cmd, 1, 0); break; | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | < < | < | < < | | < | | | 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 | arUsage(pState->out); break; case AR_CMD_INSERT: rc = arCreateOrUpdateCommand(&cmd, 1, 0); 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 an input line begins with "." then invoke this routine to ** process that line. ** ** Return 1 on error, 2 to exit, and 0 otherwise. */ static int do_meta_command(char *zLine, ShellState *p){ int h = 1; int nArg = 0; int n, c; int rc = 0; char *azArg[50]; #ifndef SQLITE_OMIT_VIRTUALTABLE if( p->expert.pExpert ){ expertFinish(p, 1, 0); } #endif /* Parse the input line into tokens. */ while( zLine[h] && nArg<ArraySize(azArg) ){ while( IsSpace(zLine[h]) ){ h++; } if( zLine[h]==0 ) break; if( zLine[h]=='\'' || zLine[h]=='"' ){ 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]); } } /* Process the input line. */ if( nArg==0 ) return 0; /* no tokens, no error */ n = strlen30(azArg[0]); c = azArg[0][0]; clearTempFile(p); #ifndef SQLITE_OMIT_AUTHORIZATION if( c=='a' && strncmp(azArg[0], "auth", n)==0 ){ if( nArg!=2 ){ raw_printf(stderr, "Usage: .auth ON|OFF\n"); rc = 1; goto meta_command_exit; } open_db(p, 0); if( booleanValue(azArg[1]) ){ sqlite3_set_authorizer(p->db, shellAuth, p); }else{ sqlite3_set_authorizer(p->db, 0, 0); } }else #endif #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) if( c=='a' && strncmp(azArg[0], "archive", n)==0 ){ open_db(p, 0); rc = arDotCommand(p, 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; 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 if( strcmp(z, "-async")==0 ){ bAsync = 1; }else { utf8_printf(stderr, "unknown option: %s\n", azArg[j]); return 1; } }else if( zDestFile==0 ){ |
︙ | ︙ | |||
7928 7929 7930 7931 7932 7933 7934 | } } if( zDestFile==0 ){ raw_printf(stderr, "missing FILENAME argument on .backup\n"); return 1; } if( zDb==0 ) zDb = "main"; | | | 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 | } } if( zDestFile==0 ){ raw_printf(stderr, "missing FILENAME argument on .backup\n"); return 1; } if( zDb==0 ) zDb = "main"; rc = sqlite3_open_v2(zDestFile, &pDest, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, zVfs); if( rc!=SQLITE_OK ){ utf8_printf(stderr, "Error: cannot open \"%s\"\n", zDestFile); close_db(pDest); return 1; } if( bAsync ){ |
︙ | ︙ | |||
7956 7957 7958 7959 7960 7961 7962 | rc = 0; }else{ utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest)); rc = 1; } close_db(pDest); }else | < | | < < < < < < < < | < | > > > > > > | < | < < | < < | < < < < > | < | < | < < < < < < < < < < < < < < < | < < < | < < < | | < > | < < < | | > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | < | < | < < | | | | | | | | | < | < < < < < < | | < < | < | < | < < < < < < < | < < < < < | < < | < < < < | < < > | | | | < < < < | | | | | < | | > > > > > > > > > > > > > > | | | | < < < | | < | | | | < | < < | < | | | | | | | < | < | | | < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > | | | | | | > > | > > | | | < | < | | < | < < | | > | > | | > > < < | < < | < < < < | < < < < | | | | < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | < | | | | < < | | | | | | | | | | | < < < | | | > > > > > | < < < | < < < | < < < < < < < < < < < < < < < < < | | | < < < | > | > < | < < < < < < < < < | < | > | < | < < < > > | | > > < < > | > < | | < < < > | > < < | 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 | rc = 0; }else{ utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest)); rc = 1; } close_db(pDest); }else if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 ){ if( nArg==2 ){ bail_on_error = booleanValue(azArg[1]); }else{ raw_printf(stderr, "Usage: .bail on|off\n"); rc = 1; } }else if( c=='b' && n>=3 && strncmp(azArg[0], "binary", n)==0 ){ if( nArg==2 ){ if( booleanValue(azArg[1]) ){ setBinaryMode(p->out, 1); }else{ 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 /* 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' && 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; } }else /* Cancel output redirection, if it is currently set (by .testcase) ** Then read the content of the testcase-out.txt file and compare against ** azArg[1]. If there are differences, report an error and exit. */ if( c=='c' && n>=3 && strncmp(azArg[0], "check", n)==0 ){ char *zRes = 0; output_reset(p); if( nArg!=2 ){ raw_printf(stderr, "Usage: .check GLOB-PATTERN\n"); rc = 2; }else if( (zRes = readFile("testcase-out.txt", 0))==0 ){ raw_printf(stderr, "Error: cannot read 'testcase-out.txt'\n"); rc = 2; }else if( testcase_glob(azArg[1],zRes)==0 ){ utf8_printf(stderr, "testcase-%s FAILED\n Expected: [%s]\n Got: [%s]\n", p->zTestcase, azArg[1], zRes); rc = 1; }else{ 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 ){ ShellState data; char *zErrMsg = 0; open_db(p, 0); memcpy(&data, p, sizeof(data)); data.showHeader = 0; data.cMode = data.mode = MODE_List; sqlite3_snprintf(sizeof(data.colSeparator),data.colSeparator,": "); data.cnt = 0; sqlite3_exec(p->db, "SELECT name, file FROM pragma_database_list", callback, &data, &zErrMsg); if( zErrMsg ){ utf8_printf(stderr,"Error: %s\n", zErrMsg); sqlite3_free(zErrMsg); rc = 1; } }else if( c=='d' && n>=3 && strncmp(azArg[0], "dbconfig", n)==0 ){ static const struct DbConfigChoices { const char *zName; int op; } aDbConfig[] = { { "enable_fkey", SQLITE_DBCONFIG_ENABLE_FKEY }, { "enable_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 }, { "enable_qpsg", SQLITE_DBCONFIG_ENABLE_QPSG }, { "trigger_eqp", SQLITE_DBCONFIG_TRIGGER_EQP }, { "reset_database", SQLITE_DBCONFIG_RESET_DATABASE }, { "defensive", SQLITE_DBCONFIG_DEFENSIVE }, }; 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, "%18s %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( c=='d' && strncmp(azArg[0], "dump", n)==0 ){ const char *zLike = 0; int i; int savedShowHeader = p->showHeader; int savedShellFlags = p->shellFlgs; ShellClearFlag(p, SHFLG_PreserveRowid|SHFLG_Newlines|SHFLG_Echo); 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; goto meta_command_exit; #else ShellSetFlag(p, SHFLG_PreserveRowid); #endif }else if( strcmp(z,"newlines")==0 ){ ShellSetFlag(p, SHFLG_Newlines); }else { raw_printf(stderr, "Unknown option \"%s\" on \".dump\"\n", azArg[i]); rc = 1; goto meta_command_exit; } }else if( zLike ){ raw_printf(stderr, "Usage: .dump ?--preserve-rowids? " "?--newlines? ?LIKE-PATTERN?\n"); rc = 1; goto meta_command_exit; }else{ zLike = azArg[i]; } } open_db(p, 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_master table is ** corrupt. */ sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0); p->nErr = 0; if( zLike==0 ){ run_schema_dump_query(p, "SELECT name, type, sql FROM sqlite_master " "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'" ); run_schema_dump_query(p, "SELECT name, type, sql FROM sqlite_master " "WHERE name=='sqlite_sequence'" ); run_table_dump_query(p, "SELECT sql FROM sqlite_master " "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0 ); }else{ char *zSql; zSql = sqlite3_mprintf( "SELECT name, type, sql FROM sqlite_master " "WHERE tbl_name LIKE %Q AND type=='table'" " AND sql NOT NULL", zLike); run_schema_dump_query(p,zSql); sqlite3_free(zSql); zSql = sqlite3_mprintf( "SELECT sql FROM sqlite_master " "WHERE sql NOT NULL" " AND type IN ('index','trigger','view')" " AND tbl_name LIKE %Q", zLike); run_table_dump_query(p, zSql, 0); sqlite3_free(zSql); } 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); 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_master 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; }else /* The ".explain" command is automatic now. It is largely pointless. It ** retained purely for backwards compatibility */ if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){ int val = 1; if( nArg>=2 ){ if( strcmp(azArg[1],"auto")==0 ){ val = 99; }else{ val = booleanValue(azArg[1]); } } if( val==1 && p->mode!=MODE_Explain ){ p->normalMode = p->mode; p->mode = MODE_Explain; p->autoExplain = 0; }else if( val==0 ){ if( p->mode==MODE_Explain ) p->mode = p->normalMode; p->autoExplain = 0; }else if( val==99 ){ if( p->mode==MODE_Explain ) p->mode = p->normalMode; p->autoExplain = 1; } }else #ifndef SQLITE_OMIT_VIRTUALTABLE if( c=='e' && strncmp(azArg[0], "expert", n)==0 ){ open_db(p, 0); expertDotCommand(p, azArg, nArg); }else #endif if( c=='f' && strncmp(azArg[0], "fullschema", n)==0 ){ ShellState data; char *zErrMsg = 0; int doStats = 0; memcpy(&data, p, sizeof(data)); data.showHeader = 0; 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_master UNION ALL" " SELECT sql, type, tbl_name, name, rowid FROM sqlite_temp_master) " "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%' " "ORDER BY rowid", callback, &data, &zErrMsg ); if( rc==SQLITE_OK ){ sqlite3_stmt *pStmt; rc = sqlite3_prepare_v2(p->db, "SELECT rowid FROM sqlite_master" " 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_master;\n"); sqlite3_exec(p->db, "SELECT 'ANALYZE sqlite_master'", callback, &data, &zErrMsg); data.cMode = data.mode = MODE_Insert; data.zDestTable = "sqlite_stat1"; shell_exec(&data, "SELECT * FROM sqlite_stat1", &zErrMsg); data.zDestTable = "sqlite_stat3"; shell_exec(&data, "SELECT * FROM sqlite_stat3", &zErrMsg); data.zDestTable = "sqlite_stat4"; shell_exec(&data, "SELECT * FROM sqlite_stat4", &zErrMsg); raw_printf(p->out, "ANALYZE sqlite_master;\n"); } }else if( c=='h' && strncmp(azArg[0], "headers", n)==0 ){ if( nArg==2 ){ p->showHeader = booleanValue(azArg[1]); }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; /* Insert data into this table */ char *zFile; /* 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 (SQLITE_CDECL *xCloser)(FILE*); /* Func to close file */ if( nArg!=3 ){ raw_printf(stderr, "Usage: .import FILE TABLE\n"); goto meta_command_exit; } zFile = azArg[1]; zTable = azArg[2]; seenInterrupt = 0; memset(&sCtx, 0, sizeof(sCtx)); open_db(p, 0); nSep = strlen30(p->colSeparator); if( nSep==0 ){ raw_printf(stderr, "Error: non-null column separator required for import\n"); return 1; } if( nSep>1 ){ raw_printf(stderr, "Error: multi-character column separators not allowed" " for import\n"); return 1; } nSep = strlen30(p->rowSeparator); if( nSep==0 ){ raw_printf(stderr, "Error: non-null row separator required for import\n"); return 1; } 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"); return 1; } 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"); return 1; #else sCtx.in = popen(sCtx.zFile+1, "r"); sCtx.zFile = "<pipe>"; xCloser = pclose; #endif }else{ sCtx.in = fopen(sCtx.zFile, "rb"); xCloser = fclose; } if( p->mode==MODE_Ascii ){ xRead = ascii_read_one_field; }else{ xRead = csv_read_one_field; } if( sCtx.in==0 ){ utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile); return 1; } sCtx.cColSep = p->colSeparator[0]; sCtx.cRowSep = p->rowSeparator[0]; zSql = sqlite3_mprintf("SELECT * FROM %s", zTable); if( zSql==0 ){ xCloser(sCtx.in); 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 %s", 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); sqlite3_free(sCtx.z); xCloser(sCtx.in); utf8_printf(stderr,"%s: empty file\n", sCtx.zFile); return 1; } zCreate = sqlite3_mprintf("%z\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)); sqlite3_free(sCtx.z); xCloser(sCtx.in); return 1; } 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)); xCloser(sCtx.in); return 1; } 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 ){ xCloser(sCtx.in); 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; 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); xCloser(sCtx.in); return 1; } 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); /* |
︙ | ︙ | |||
8881 8882 8883 8884 8885 8886 8887 | } 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)); | < < < | > < < < < < < | < < < < < < < < < | < | < < < < < < < > > > > > | < < < < < < < < < < | | | < | | | | 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 | } 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 ); xCloser(sCtx.in); sqlite3_free(sCtx.z); sqlite3_finalize(pStmt); if( needCommit ) sqlite3_exec(p->db, "COMMIT", 0, 0, 0); }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 i; if( !(nArg==3 || (nArg==2 && sqlite3_stricmp(azArg[1],"off")==0)) ){ utf8_printf(stderr, "Usage: .imposter INDEX IMPOSTER\n" " .imposter off\n"); 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 FROM sqlite_master" " WHERE name='%q' AND type='index'", 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); } sqlite3_finalize(pStmt); if( tnum==0 ){ utf8_printf(stderr, "no such index: \"%s\"\n", azArg[1]); rc = 1; goto meta_command_exit; } 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( 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( zCollist==0 ){ zCollist = sqlite3_mprintf("\"%w\"", zCol); }else{ zCollist = sqlite3_mprintf("%z,\"%w\"", zCollist, zCol); } } sqlite3_finalize(pStmt); zSql = sqlite3_mprintf( "CREATE TABLE \"%w\"(%s,PRIMARY KEY(%s))WITHOUT ROWID", azArg[2], zCollist, 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 index!\n" ); } }else{ raw_printf(stderr, "SQLITE_TESTCTRL_IMPOSTER returns %d\n", rc); rc = 1; } sqlite3_free(zSql); }else #endif /* !defined(SQLITE_OMIT_TEST_CONTROL) */ #ifdef SQLITE_ENABLE_IOTRACE if( c=='i' && strncmp(azArg[0], "iotrace", n)==0 ){ SQLITE_API extern void (SQLITE_CDECL *sqlite3IoTrace)(const char*, ...); if( iotrace && iotrace!=stdout ) fclose(iotrace); iotrace = 0; if( nArg<2 ){ sqlite3IoTrace = 0; }else if( strcmp(azArg[1], "-")==0 ){ sqlite3IoTrace = iotracePrintf; iotrace = stdout; }else{ iotrace = fopen(azArg[1], "w"); if( iotrace==0 ){ utf8_printf(stderr, "Error: cannot open \"%s\"\n", azArg[1]); sqlite3IoTrace = 0; rc = 1; }else{ sqlite3IoTrace = iotracePrintf; } } }else #endif if( c=='l' && n>=5 && strncmp(azArg[0], "limits", n)==0 ){ static const struct { const char *zLimitName; /* Name of a limit */ int limitCode; /* Integer code for that limit */ } aLimit[] = { { "length", SQLITE_LIMIT_LENGTH }, { "sql_length", SQLITE_LIMIT_SQL_LENGTH }, { "column", SQLITE_LIMIT_COLUMN }, |
︙ | ︙ | |||
9082 9083 9084 9085 9086 9087 9088 | (int)integerValue(azArg[2])); } printf("%20s %d\n", aLimit[iLimit].zLimitName, sqlite3_limit(p->db, aLimit[iLimit].limitCode, -1)); } }else | | | | < < | < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > | | < < < < | | | | | | | | < < | | | < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < | | < | | | > > > > > > > | | | < | | | < < | | | | < < | < < < < < < < < < < < < < < < < < < > | < < < < < < < < < < < < < < < < | < | | | < | < | | < < < < < < < | < > | | > | < < | < < < < < < < < < < < < < | | | | < < | < < < < < | < > < < < < < < > < > | < < < < | < < | < < < | | > > > > | | | | | | | | | | | | | | | 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 | (int)integerValue(azArg[2])); } printf("%20s %d\n", aLimit[iLimit].zLimitName, sqlite3_limit(p->db, aLimit[iLimit].limitCode, -1)); } }else if( c=='l' && n>2 && strncmp(azArg[0], "lint", n)==0 ){ open_db(p, 0); 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; }else if( c2=='t' && strncmp(azArg[1],"tcl",n2)==0 ){ p->mode = MODE_Tcl; sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Space); sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row); }else if( c2=='c' && strncmp(azArg[1],"csv",n2)==0 ){ p->mode = MODE_Csv; sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma); sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf); }else if( c2=='t' && strncmp(azArg[1],"tabs",n2)==0 ){ 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: " "ascii column csv html insert line list quote tabs tcl\n"); rc = 1; } p->cMode = p->mode; }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 if( c=='o' && strncmp(azArg[0], "open", n)==0 && n>=2 ){ char *zNewFilename; /* 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); close_db(p->db); p->db = 0; p->zDbFilename = 0; sqlite3_free(p->zFreeOnClose); p->zFreeOnClose = 0; p->openMode = SHELL_OPEN_UNSPEC; p->szMax = 0; /* Check for command-line arguments */ for(iName=1; iName<nArg && azArg[iName][0]=='-'; iName++){ const char *z = azArg[iName]; if( optionMatch(z,"new") ){ newFlag = 1; #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; #ifdef SQLITE_ENABLE_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_ENABLE_DESERIALIZE */ }else if( z[0]=='-' ){ utf8_printf(stderr, "unknown option: %s\n", z); rc = 1; goto meta_command_exit; } } /* If a filename is specified, try to open it first */ zNewFilename = nArg>iName ? sqlite3_mprintf("%s", azArg[iName]) : 0; if( zNewFilename || p->openMode==SHELL_OPEN_HEXDB ){ if( newFlag ) shellDeleteFile(zNewFilename); p->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->zFreeOnClose = zNewFilename; } } if( p->db==0 ){ /* As a fall-back open a TEMP database */ p->zDbFilename = 0; open_db(p, 0); } }else if( (c=='o' && (strncmp(azArg[0], "output", n)==0||strncmp(azArg[0], "once", n)==0)) || (c=='e' && n==5 && strcmp(azArg[0],"excel")==0) ){ const char *zFile = nArg>=2 ? azArg[1] : "stdout"; int bTxtMode = 0; if( azArg[0][0]=='e' ){ /* Transform the ".excel" command into ".once -x" */ nArg = 2; azArg[0] = "once"; zFile = azArg[1] = "-x"; n = 4; } if( nArg>2 ){ utf8_printf(stderr, "Usage: .%s [-e|-x|FILE]\n", azArg[0]); rc = 1; goto meta_command_exit; } if( n>1 && strncmp(azArg[0], "once", n)==0 ){ if( nArg<2 ){ raw_printf(stderr, "Usage: .once (-e|-x|FILE)\n"); rc = 1; goto meta_command_exit; } p->outCount = 2; }else{ p->outCount = 0; } output_reset(p); if( zFile[0]=='-' && zFile[1]=='-' ) zFile++; #ifndef SQLITE_NOHAVE_SYSTEM if( strcmp(zFile, "-e")==0 || strcmp(zFile, "-x")==0 ){ p->doXdgOpen = 1; outputModePush(p); if( zFile[1]=='x' ){ newTempFile(p, "csv"); p->mode = MODE_Csv; sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma); sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf); }else{ newTempFile(p, "txt"); bTxtMode = 1; } zFile = p->zTempFile; } #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{ 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 { sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", 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 ){ int wrSchema = 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, "DROP TABLE IF EXISTS temp.sqlite_parameters;", 0, 0, 0); sqlite3_db_config(p->db, SQLITE_DBCONFIG_WRITABLE_SCHEMA, wrSchema, 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( 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]); } |
︙ | ︙ | |||
9644 9645 9646 9647 9648 9649 9650 | } } open_db(p, 0); sqlite3_progress_handler(p->db, nn, progress_handler, p); }else #endif /* SQLITE_OMIT_PROGRESS_CALLBACK */ | | | | < | < < | < < < < < < < | | < < < < < < < < < < | < | 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 | } } 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; if( nArg!=2 ){ raw_printf(stderr, "Usage: .read FILE\n"); rc = 1; goto meta_command_exit; } p->in = fopen(azArg[1], "rb"); if( p->in==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; if( nArg==2 ){ zSrcFile = azArg[1]; zDb = "main"; }else if( nArg==3 ){ zSrcFile = azArg[2]; zDb = azArg[1]; }else{ |
︙ | ︙ | |||
9748 9749 9750 9751 9752 9753 9754 | rc = 1; }else{ utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); rc = 1; } close_db(pSrc); }else | < | < < < | < | | < < < < < < < | < | < | < < | < | 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 | rc = 1; }else{ utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); rc = 1; } close_db(pSrc); }else if( c=='s' && strncmp(azArg[0], "scanstats", n)==0 ){ if( nArg==2 ){ p->scanstatsOn = (u8)booleanValue(azArg[1]); #ifndef SQLITE_ENABLE_STMT_SCANSTATUS raw_printf(stderr, "Warning: .scanstats not available in this build.\n"); #endif }else{ raw_printf(stderr, "Usage: .scanstats on|off\n"); rc = 1; } }else if( c=='s' && strncmp(azArg[0], "schema", n)==0 ){ 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{ raw_printf(stderr, "Usage: .schema ?--indent? ?LIKE-PATTERN?\n"); rc = 1; goto meta_command_exit; } } if( zName!=0 ){ int isMaster = sqlite3_strlike(zName, "sqlite_master", '\\')==0; if( isMaster || sqlite3_strlike(zName,"sqlite_temp_master", '\\')==0 ){ 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" ")", isMaster ? "sqlite_master" : "sqlite_temp_master"); new_argv[1] = 0; new_colv[0] = "sql"; new_colv[1] = 0; callback(&data, 1, new_argv, new_colv); sqlite3_free(new_argv[0]); } } |
︙ | ︙ | |||
9845 9846 9847 9848 9849 9850 9851 | 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 ){ | | | | | | < < < | | < < < | > | < < | < > | < | | | | | | | | < < < | < | 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 | 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, '"'); appendText(&sSelect, ".sqlite_master", 0); } sqlite3_finalize(pStmt); #ifdef SQLITE_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); } appendText(&sSelect, "type!='meta' AND 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 defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_SELECTTRACE) if( c=='s' && n==11 && strncmp(azArg[0], "selecttrace", n)==0 ){ sqlite3SelectTrace = (int)integerValue(azArg[1]); }else #endif #if defined(SQLITE_ENABLE_SESSION) if( c=='s' && strncmp(azArg[0],"session",n)==0 && n>=3 ){ OpenSession *pSession = &p->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<p->nSession; iSes++){ if( strcmp(p->aSession[iSes].zName, azArg[1])==0 ) break; } if( iSes<p->nSession ){ pSession = &p->aSession[iSes]; azCmd++; nCmd--; }else{ pSession = &p->aSession[0]; iSes = 0; } } /* .session attach TABLE ** Invoke the sqlite3session_attach() interface to attach a particular ** table so that it is never filtered. */ if( strcmp(azCmd[0],"attach")==0 ){ if( nCmd!=2 ) goto session_syntax_error; if( pSession->p==0 ){ session_not_open: raw_printf(stderr, "ERROR: No sessions are open\n"); }else{ rc = sqlite3session_attach(pSession->p, azCmd[1]); if( rc ){ raw_printf(stderr, "ERROR: sqlite3session_attach() returns %d\n", rc); rc = 0; } } }else /* .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 ){ 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); |
︙ | ︙ | |||
9999 10000 10001 10002 10003 10004 10005 | fclose(out); } }else /* .session close ** Close the identified session */ | | | | | | | | | < | | | | | | | | | | | | < | | < | | | | | | | 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 7643 7644 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 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 7750 7751 7752 7753 7754 7755 7756 7757 7758 7759 7760 7761 7762 7763 7764 7765 7766 7767 7768 7769 7770 7771 7772 | fclose(out); } }else /* .session close ** Close the identified session */ if( strcmp(azCmd[0], "close")==0 ){ if( nCmd!=1 ) goto session_syntax_error; if( p->nSession ){ session_close(pSession); p->aSession[iSes] = p->aSession[--p->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( p->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( p->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 ){ raw_printf(stderr, "Error: out or memory\n"); exit(1); } for(ii=1; ii<nCmd; ii++){ pSession->azFilter[ii-1] = sqlite3_mprintf("%s", azCmd[ii]); } pSession->nFilter = ii-1; } }else /* .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( p->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( p->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<p->nSession; i++){ utf8_printf(p->out, "%d %s\n", i, p->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<p->nSession; i++){ if( strcmp(p->aSession[i].zName,zName)==0 ){ utf8_printf(stderr, "Session \"%s\" already exists\n", zName); goto meta_command_exit; } } if( p->nSession>=ArraySize(p->aSession) ){ raw_printf(stderr, "Maximum of %d sessions\n", ArraySize(p->aSession)); goto meta_command_exit; } pSession = &p->aSession[p->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); p->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 #ifdef SQLITE_DEBUG /* Undocumented commands for internal testing. Subject to change ** without notice. */ if( c=='s' && n>=10 && strncmp(azArg[0], "selftest-", 9)==0 ){ if( strncmp(azArg[0]+9, "boolean", n-9)==0 ){ int i, v; for(i=1; i<nArg; i++){ v = booleanValue(azArg[i]); utf8_printf(p->out, "%s: %d 0x%x\n", azArg[i], v, v); } } if( strncmp(azArg[0]+9, "integer", n-9)==0 ){ int i; sqlite3_int64 v; for(i=1; i<nArg; i++){ char zBuf[200]; v = integerValue(azArg[i]); sqlite3_snprintf(sizeof(zBuf),zBuf,"%s: %lld 0x%llx\n", azArg[i],v,v); utf8_printf(p->out, "%s", zBuf); } } }else #endif if( c=='s' && n>=4 && strncmp(azArg[0],"selftest",n)==0 ){ int bIsInit = 0; /* True to initialize the SELFTEST table */ int bVerbose = 0; /* Verbose output */ int bSelftestExists; /* True if SELFTEST already exists */ int i, k; /* Loop counters */ int nTest = 0; /* Number of tests runs */ int nErr = 0; /* Number of errors seen */ ShellText str; /* Answer for a query */ sqlite3_stmt *pStmt = 0; /* Query against the SELFTEST table */ open_db(p,0); for(i=1; i<nArg; i++){ const char *z = azArg[i]; if( z[0]=='-' && z[1]=='-' ) z++; if( strcmp(z,"-init")==0 ){ bIsInit = 1; }else if( strcmp(z,"-v")==0 ){ bVerbose++; }else { utf8_printf(stderr, "Unknown option \"%s\" on \"%s\"\n", azArg[i], azArg[0]); raw_printf(stderr, "Should be one of: --init -v\n"); rc = 1; |
︙ | ︙ | |||
10207 10208 10209 10210 10211 10212 10213 | } for(i=1; sqlite3_step(pStmt)==SQLITE_ROW; i++){ int tno = sqlite3_column_int(pStmt, 0); const char *zOp = (const char*)sqlite3_column_text(pStmt, 1); const char *zSql = (const char*)sqlite3_column_text(pStmt, 2); const char *zAns = (const char*)sqlite3_column_text(pStmt, 3); | < < < > > | | | | | | | | | | > | | | < | | | | | > | | 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 | } for(i=1; sqlite3_step(pStmt)==SQLITE_ROW; i++){ int tno = sqlite3_column_int(pStmt, 0); const char *zOp = (const char*)sqlite3_column_text(pStmt, 1); const char *zSql = (const char*)sqlite3_column_text(pStmt, 2); const char *zAns = (const char*)sqlite3_column_text(pStmt, 3); k = 0; if( bVerbose>0 ){ char *zQuote = sqlite3_mprintf("%q", zSql); printf("%d: %s %s\n", tno, zOp, zSql); sqlite3_free(zQuote); } if( strcmp(zOp,"memo")==0 ){ utf8_printf(p->out, "%s\n", zSql); }else if( strcmp(zOp,"run")==0 ){ char *zErrMsg = 0; str.n = 0; str.z[0] = 0; rc = sqlite3_exec(p->db, zSql, captureOutputCallback, &str, &zErrMsg); nTest++; if( bVerbose ){ utf8_printf(p->out, "Result: %s\n", str.z); } if( rc || zErrMsg ){ nErr++; rc = 1; utf8_printf(p->out, "%d: error-code-%d: %s\n", tno, rc, zErrMsg); sqlite3_free(zErrMsg); }else if( strcmp(zAns,str.z)!=0 ){ nErr++; rc = 1; utf8_printf(p->out, "%d: Expected: [%s]\n", tno, zAns); utf8_printf(p->out, "%d: Got: [%s]\n", tno, str.z); } }else { utf8_printf(stderr, "Unknown operation \"%s\" on selftest line %d\n", zOp, tno); rc = 1; break; } } /* End loop over rows of content from SELFTEST */ sqlite3_finalize(pStmt); } /* End loop over k */ freeText(&str); utf8_printf(p->out, "%d errors out of %d tests\n", nErr, nTest); }else if( c=='s' && strncmp(azArg[0], "separator", n)==0 ){ if( nArg<2 || nArg>3 ){ raw_printf(stderr, "Usage: .separator COL ?ROW?\n"); rc = 1; } if( nArg>=2 ){ sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, "%.*s", (int)ArraySize(p->colSeparator)-1, azArg[1]); } if( nArg>=3 ){ sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, "%.*s", (int)ArraySize(p->rowSeparator)-1, azArg[2]); } }else if( c=='s' && n>=4 && strncmp(azArg[0],"sha3sum",n)==0 ){ const char *zLike = 0; /* Which table to checksum. 0 means everything */ int i; /* Loop counter */ int bSchema = 0; /* Also hash the schema */ int bSeparate = 0; /* Hash each table separately */ int iSize = 224; /* Hash algorithm to use */ int bDebug = 0; /* Only show the query that would have run */ sqlite3_stmt *pStmt; /* For querying tables names */ char *zSql; /* SQL to be run */ char *zSep; /* Separator */ ShellText sSql; /* Complete SQL for the query to run the hash */ ShellText sQuery; /* Set of queries used to read all content */ open_db(p, 0); for(i=1; i<nArg; i++){ const char *z = azArg[i]; if( z[0]=='-' ){ z++; if( z[0]=='-' ) z++; if( strcmp(z,"schema")==0 ){ bSchema = 1; }else if( strcmp(z,"sha3-224")==0 || strcmp(z,"sha3-256")==0 || strcmp(z,"sha3-384")==0 || strcmp(z,"sha3-512")==0 ){ iSize = atoi(&z[5]); }else if( strcmp(z,"debug")==0 ){ bDebug = 1; }else { utf8_printf(stderr, "Unknown option \"%s\" on \"%s\"\n", azArg[i], azArg[0]); raw_printf(stderr, "Should be one of: --schema" " --sha3-224 --sha3-256 --sha3-384 --sha3-512\n"); 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_master" " WHERE type='table' AND coalesce(rootpage,0)>1" " UNION ALL SELECT 'sqlite_master'" " ORDER BY 1 collate nocase"; }else{ zSql = "SELECT lower(name) FROM sqlite_master" " 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_master")==0 ){ appendText(&sQuery,"SELECT type,name,tbl_name,sql FROM sqlite_master" " 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_stat3")==0 || 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; |
︙ | ︙ | |||
10371 10372 10373 10374 10375 10376 10377 | }else{ zSql = sqlite3_mprintf( "%s))" " SELECT lower(hex(sha3_query(group_concat(a,''),%d))) AS hash" " FROM [sha3sum$query]", sSql.z, iSize); } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < | | | | < | < < < < < < < < < | < < < < < < < | | | | < < < < < | < | | | | | 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 | }else{ zSql = sqlite3_mprintf( "%s))" " SELECT lower(hex(sha3_query(group_concat(a,''),%d))) AS hash" " FROM [sha3sum$query]", sSql.z, iSize); } freeText(&sQuery); freeText(&sSql); if( bDebug ){ utf8_printf(p->out, "%s\n", zSql); }else{ shell_exec(p, zSql, 0); } sqlite3_free(zSql); }else #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", azBool[ShellHasFlag(p, SHFLG_Echo)]); utf8_printf(p->out, "%12.12s: %s\n","eqp", azBool[p->autoEQP&3]); utf8_printf(p->out, "%12.12s: %s\n","explain", p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off"); utf8_printf(p->out,"%12.12s: %s\n","headers", azBool[p->showHeader!=0]); utf8_printf(p->out, "%12.12s: %s\n","mode", modeDescr[p->mode]); utf8_printf(p->out, "%12.12s: ", "nullvalue"); output_c_string(p->out, p->nullValue); raw_printf(p->out, "\n"); utf8_printf(p->out,"%12.12s: %s\n","output", 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"); utf8_printf(p->out, "%12.12s: %s\n","stats", azBool[p->statsOn!=0]); utf8_printf(p->out, "%12.12s: ", "width"); for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) { raw_printf(p->out, "%d ", p->colWidth[i]); } raw_printf(p->out, "\n"); utf8_printf(p->out, "%12.12s: %s\n", "filename", p->zDbFilename ? p->zDbFilename : ""); }else if( c=='s' && strncmp(azArg[0], "stats", n)==0 ){ if( nArg==2 ){ p->statsOn = (u8)booleanValue(azArg[1]); }else if( nArg==1 ){ display_stats(p->db, p, 0); }else{ raw_printf(stderr, "Usage: .stats ?on|off?\n"); rc = 1; } }else 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) ) ){ sqlite3_stmt *pStmt; char **azResult; int nRow, nAlloc; int ii; ShellText s; initText(&s); |
︙ | ︙ | |||
10566 10567 10568 10569 10570 10571 10572 | appendText(&s, "SELECT name FROM ", 0); }else{ appendText(&s, "SELECT ", 0); appendText(&s, zDbName, '\''); appendText(&s, "||'.'||name FROM ", 0); } appendText(&s, zDbName, '"'); | | < | | < | | | 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 | 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_master ", 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); 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; if( nArg>1 ){ sqlite3_bind_text(pStmt, 1, azArg[1], -1, SQLITE_TRANSIENT); }else{ sqlite3_bind_text(pStmt, 1, "%", -1, SQLITE_STATIC); } while( sqlite3_step(pStmt)==SQLITE_ROW ){ if( nRow>=nAlloc ){ char **azNew; int n2 = nAlloc*2 + 10; azNew = sqlite3_realloc64(azResult, sizeof(azResult[0])*n2); if( azNew==0 ) shell_out_of_memory(); nAlloc = n2; azResult = azNew; } azResult[nRow] = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 0)); if( 0==azResult[nRow] ) shell_out_of_memory(); nRow++; } if( sqlite3_finalize(pStmt)!=SQLITE_OK ){ rc = shellDatabaseError(p->db); } /* Pretty-print the contents of array azResult[] to the output */ |
︙ | ︙ | |||
10636 10637 10638 10639 10640 10641 10642 | } } for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]); sqlite3_free(azResult); }else | < | < | < | | | | | < | | | | | | | | > | | | < < < | | < < < < < > | > < < < < < < < < < < < < < < < < < < < < < > < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < | < < | < < < < < < < < < < < < | | | | | 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 | } } for(ii=0; ii<nRow; ii++) sqlite3_free(azResult[ii]); sqlite3_free(azResult); }else /* Begin redirecting output to the file "testcase-out.txt" */ if( c=='t' && strcmp(azArg[0],"testcase")==0 ){ output_reset(p); p->out = output_file_open("testcase-out.txt", 0); if( p->out==0 ){ raw_printf(stderr, "Error: cannot open 'testcase-out.txt'\n"); } if( nArg>=2 ){ sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "%s", azArg[1]); }else{ sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "?"); } }else #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, "" }, /*{ "fault_install", SQLITE_TESTCTRL_FAULT_INSTALL, "" }, */ { "imposter", SQLITE_TESTCTRL_IMPOSTER, "SCHEMA ON/OFF ROOTPAGE"}, { "internal_functions", SQLITE_TESTCTRL_INTERNAL_FUNCTIONS, "BOOLEAN" }, { "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_reset", SQLITE_TESTCTRL_PRNG_RESET, "" }, { "prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE, "" }, { "prng_save", SQLITE_TESTCTRL_PRNG_SAVE, "" }, { "reserve", SQLITE_TESTCTRL_RESERVE, "BYTES-OF-RESERVE" }, }; 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; open_db(p, 0); zCmd = nArg>=2 ? azArg[1] : "help"; /* The argument can optionally begin with "-" or "--" */ if( zCmd[0]=='-' && zCmd[1] ){ zCmd++; if( zCmd[0]=='-' && zCmd[1] ) zCmd++; } /* --help lists all test-controls */ if( strcmp(zCmd,"help")==0 ){ utf8_printf(p->out, "Available test-controls:\n"); for(i=0; i<ArraySize(aCtrl); i++){ utf8_printf(p->out, " .testctrl %s %s\n", aCtrl[i].zCtrlName, aCtrl[i].zUsage); } rc = 1; goto meta_command_exit; } /* convert testctrl 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( testctrl<0 ){ testctrl = aCtrl[i].ctrlCode; iCtrl = i; }else{ utf8_printf(stderr, "Error: ambiguous test-control: \"%s\"\n" "Use \".testctrl --help\" for help\n", zCmd); rc = 1; goto meta_command_exit; } } } if( testctrl<0 ){ 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: case SQLITE_TESTCTRL_RESERVE: if( nArg==3 ){ int opt = (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_PRNG_RESET: 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) */ case SQLITE_TESTCTRL_ASSERT: case SQLITE_TESTCTRL_ALWAYS: case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS: 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; 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; #ifdef YYCOVERAGE case SQLITE_TESTCTRL_PARSER_COVERAGE: if( nArg==2 ){ sqlite3_test_control(testctrl, p->out); isOk = 3; } #endif } } 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 #endif /* !defined(SQLITE_UNTESTABLE) */ if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 ){ open_db(p, 0); sqlite3_busy_timeout(p->db, nArg>=2 ? (int)integerValue(azArg[1]) : 0); }else if( c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 ){ if( nArg==2 ){ enableTimer = booleanValue(azArg[1]); if( enableTimer && !HAS_TIMER ){ raw_printf(stderr, "Error: timer not available on this system.\n"); enableTimer = 0; } }else{ raw_printf(stderr, "Usage: .timer on|off\n"); rc = 1; } }else #ifndef SQLITE_OMIT_TRACE if( c=='t' && strncmp(azArg[0], "trace", n)==0 ){ int mType = 0; int jj; open_db(p, 0); for(jj=1; jj<nArg; jj++){ const char *z = azArg[jj]; if( z[0]=='-' ){ if( optionMatch(z, "expanded") ){ |
︙ | ︙ | |||
10942 10943 10944 10945 10946 10947 10948 | else { raw_printf(stderr, "Unknown option \"%s\" on \".trace\"\n", z); rc = 1; goto meta_command_exit; } }else{ output_file_close(p->traceOut); | | < < < < < < < < < < < < < < < < < < < < < < < < < | | | < | | | | | | | > | | < > | < < < < | < | > > < > | < < | < | < < < < < < | > < < < > < < | < < < < | | > > > > > | < < > | < | | < | < < | < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < | < < < < < < < < < < < | | | | > | > | < > | < | | > > < > | 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 8554 8555 8556 8557 8558 8559 8560 8561 8562 8563 8564 8565 8566 8567 8568 8569 8570 8571 8572 8573 8574 8575 8576 8577 8578 8579 8580 8581 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 | else { raw_printf(stderr, "Unknown option \"%s\" on \".trace\"\n", z); rc = 1; goto meta_command_exit; } }else{ output_file_close(p->traceOut); p->traceOut = output_file_open(azArg[1], 0); } } if( p->traceOut==0 ){ 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; } rc = sqlite3_user_authenticate(p->db, azArg[2], azArg[3], strlen30(azArg[3])); if( rc ){ utf8_printf(stderr, "Authentication failed for user %s\n", azArg[2]); rc = 1; } }else if( strcmp(azArg[1],"add")==0 ){ if( nArg!=5 ){ raw_printf(stderr, "Usage: .user add USER PASSWORD ISADMIN\n"); rc = 1; goto meta_command_exit; } rc = sqlite3_user_add(p->db, azArg[2], azArg[3], strlen30(azArg[3]), booleanValue(azArg[4])); if( rc ){ raw_printf(stderr, "User-Add failed: %d\n", rc); rc = 1; } }else if( strcmp(azArg[1],"edit")==0 ){ if( nArg!=5 ){ raw_printf(stderr, "Usage: .user edit USER PASSWORD ISADMIN\n"); rc = 1; goto meta_command_exit; } rc = sqlite3_user_change(p->db, azArg[2], azArg[3], strlen30(azArg[3]), booleanValue(azArg[4])); if( rc ){ raw_printf(stderr, "User-Edit failed: %d\n", rc); rc = 1; } }else if( strcmp(azArg[1],"delete")==0 ){ if( nArg!=3 ){ raw_printf(stderr, "Usage: .user delete USER\n"); rc = 1; goto meta_command_exit; } rc = sqlite3_user_delete(p->db, azArg[2]); if( rc ){ raw_printf(stderr, "User-Delete failed: %d\n", rc); rc = 1; } }else{ raw_printf(stderr, "Usage: .user login|add|edit|delete ...\n"); rc = 1; goto meta_command_exit; } }else #endif /* SQLITE_USER_AUTHENTICATION */ if( c=='v' && strncmp(azArg[0], "version", n)==0 ){ utf8_printf(p->out, "SQLite %s %s\n" /*extra-version-info*/, sqlite3_libversion(), sqlite3_sourceid()); #if SQLITE_HAVE_ZLIB utf8_printf(p->out, "zlib version %s\n", zlibVersion()); #endif #define CTIMEOPT_VAL_(opt) #opt #define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt) #if defined(__clang__) && defined(__clang_major__) utf8_printf(p->out, "clang-" CTIMEOPT_VAL(__clang_major__) "." CTIMEOPT_VAL(__clang_minor__) "." CTIMEOPT_VAL(__clang_patchlevel__) "\n"); #elif defined(_MSC_VER) utf8_printf(p->out, "msvc-" CTIMEOPT_VAL(_MSC_VER) "\n"); #elif defined(__GNUC__) && defined(__VERSION__) utf8_printf(p->out, "gcc-" __VERSION__ "\n"); #endif }else if( c=='v' && strncmp(azArg[0], "vfsinfo", n)==0 ){ const char *zDbName = nArg==2 ? azArg[1] : "main"; sqlite3_vfs *pVfs = 0; if( p->db ){ sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFS_POINTER, &pVfs); if( pVfs ){ utf8_printf(p->out, "vfs.zName = \"%s\"\n", pVfs->zName); raw_printf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion); raw_printf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile); raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname); } } }else if( c=='v' && strncmp(azArg[0], "vfslist", n)==0 ){ sqlite3_vfs *pVfs; sqlite3_vfs *pCurrent = 0; if( p->db ){ sqlite3_file_control(p->db, "main", SQLITE_FCNTL_VFS_POINTER, &pCurrent); } for(pVfs=sqlite3_vfs_find(0); pVfs; pVfs=pVfs->pNext){ utf8_printf(p->out, "vfs.zName = \"%s\"%s\n", pVfs->zName, pVfs==pCurrent ? " <--- CURRENT" : ""); raw_printf(p->out, "vfs.iVersion = %d\n", pVfs->iVersion); raw_printf(p->out, "vfs.szOsFile = %d\n", pVfs->szOsFile); raw_printf(p->out, "vfs.mxPathname = %d\n", pVfs->mxPathname); if( pVfs->pNext ){ raw_printf(p->out, "-----------------------------------\n"); } } }else if( c=='v' && strncmp(azArg[0], "vfsname", n)==0 ){ const char *zDbName = nArg==2 ? azArg[1] : "main"; char *zVfsName = 0; if( p->db ){ sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFSNAME, &zVfsName); if( zVfsName ){ utf8_printf(p->out, "%s\n", zVfsName); sqlite3_free(zVfsName); } } }else #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE) if( c=='w' && strncmp(azArg[0], "wheretrace", n)==0 ){ sqlite3WhereTrace = nArg>=2 ? booleanValue(azArg[1]) : 0xff; }else #endif if( c=='w' && strncmp(azArg[0], "width", n)==0 ){ int j; assert( nArg<=ArraySize(azArg) ); for(j=1; j<nArg && j<ArraySize(p->colWidth); 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); } return rc; } /* ** Return TRUE if a semicolon occurs anywhere in the first N characters ** of string z[]. */ static int line_contains_semicolon(const char *z, int N){ int i; for(i=0; i<N; i++){ if( z[i]==';' ) return 1; } return 0; } /* ** Test to see if a line consists entirely of whitespace. */ static int _all_whitespace(const char *z){ for(; *z; z++){ if( IsSpace(z[0]) ) continue; if( *z=='/' && z[1]=='*' ){ z += 2; while( *z && (*z!='*' || z[1]!='/') ){ z++; } if( *z==0 ) return 0; z++; continue; } if( *z=='-' && z[1]=='-' ){ z += 2; while( *z && *z!='\n' ){ z++; } if( *z==0 ) return 1; continue; } return 0; } return 1; } /* ** 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(const char *zLine){ while( IsSpace(zLine[0]) ){ zLine++; }; if( zLine[0]=='/' && _all_whitespace(&zLine[1]) ){ return 1; /* Oracle */ } if( ToLower(zLine[0])=='g' && ToLower(zLine[1])=='o' && _all_whitespace(&zLine[2]) ){ return 1; /* SQL Server */ } return 0; } /* ** We need a default sqlite3_complete() implementation to use in case ** the shell is compiled with SQLITE_OMIT_COMPLETE. The default assumes ** any arbitrary text is a complete SQL statement. This is not very ** user-friendly, but it does seem to work. */ #ifdef SQLITE_OMIT_COMPLETE #define sqlite3_complete(x) 1 #endif /* ** Return true if zSql is a complete SQL statement. Return false if it ** ends in the middle of a string literal or C-style comment. */ static int line_is_complete(char *zSql, int nSql){ |
︙ | ︙ | |||
11293 11294 11295 11296 11297 11298 11299 | 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]; | < < < < < < < < < < < < < < < | | > | | | > > > < < | | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | > | < < < < < < < < < < < < < < < < | | < < | < > | > | < | | > | > | < < < < | | < | < < < < | | 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 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 8734 8735 8736 8737 8738 8739 8740 8741 8742 8743 8744 8745 8746 8747 8748 8749 8750 8751 8752 8753 8754 8755 8756 8757 8758 8759 8760 8761 8762 8763 8764 8765 8766 8767 8768 8769 8770 8771 8772 8773 8774 8775 8776 8777 8778 8779 8780 | 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) ){ raw_printf(p->out, "changes: %3d total_changes: %d\n", sqlite3_changes(p->db), sqlite3_total_changes(p->db)); } 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 nSqlPrior = 0; /* Bytes of zSql[] used by prior line */ int rc; /* Error code */ int errCnt = 0; /* Number of errors seen */ int startline = 0; /* Line number for start of current input */ 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( nSql==0 && _all_whitespace(zLine) ){ if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zLine); 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++; } } continue; } if( line_is_command_terminator(zLine) && line_is_complete(zSql, nSql) ){ memcpy(zLine,";",2); } nLine = strlen30(zLine); if( nSql+nLine+2>=nAlloc ){ nAlloc = nSql+nLine+100; zSql = realloc(zSql, nAlloc); if( zSql==0 ) shell_out_of_memory(); } nSqlPrior = nSql; 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 && line_contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior) && sqlite3_complete(zSql) ){ errCnt += runOneSqlLine(p, zSql, p->in, startline); nSql = 0; if( p->outCount ){ output_reset(p); p->outCount = 0; }else{ clearTempFile(p); } }else if( nSql && _all_whitespace(zSql) ){ if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zSql); nSql = 0; } } if( nSql && !_all_whitespace(zSql) ){ errCnt += runOneSqlLine(p, zSql, p->in, startline); } free(zSql); free(zLine); return errCnt>0; } /* ** Return a pathname which is the user's home directory. A ** 0 return indicates an error of some kind. */ static char *find_home_dir(int clearFlag){ static char *home_dir = NULL; if( clearFlag ){ free(home_dir); home_dir = 0; return 0; } if( home_dir ) return home_dir; #if !defined(_WIN32) && !defined(WIN32) && !defined(_WIN32_WCE) \ && !defined(__RTP__) && !defined(_WRS_KERNEL) { struct passwd *pwent; uid_t uid = getuid(); if( (pwent=getpwuid(uid)) != NULL) { home_dir = pwent->pw_dir; } } |
︙ | ︙ | |||
11544 11545 11546 11547 11548 11549 11550 | home_dir = "c:\\"; } #endif #endif /* !_WIN32_WCE */ if( home_dir ){ | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < < < < | < < < < | | < < | < < < < < | 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 8847 8848 8849 8850 8851 8852 8853 8854 8855 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 | home_dir = "c:\\"; } #endif #endif /* !_WIN32_WCE */ if( home_dir ){ int n = strlen30(home_dir) + 1; char *z = malloc( n ); if( z ) memcpy(z, home_dir, n); home_dir = z; } return home_dir; } /* ** Read input from the file given by sqliterc_override. Or if that ** parameter is NULL, take input from ~/.sqliterc ** ** Returns the number of errors. */ static void process_sqliterc( ShellState *p, /* Configuration data */ const char *sqliterc_override /* Name of config file. NULL to use default */ ){ char *home_dir = NULL; const char *sqliterc = sqliterc_override; char *zBuf = 0; FILE *inSaved = p->in; int savedLineno = p->lineno; if (sqliterc == NULL) { home_dir = find_home_dir(0); if( home_dir==0 ){ raw_printf(stderr, "-- warning: cannot find home directory;" " cannot read ~/.sqliterc\n"); return; } zBuf = sqlite3_mprintf("%s/.sqliterc",home_dir); sqliterc = zBuf; } p->in = fopen(sqliterc,"rb"); if( p->in ){ if( stdin_is_interactive ){ utf8_printf(stderr,"-- Loading resources from %s\n",sqliterc); } process_input(p); fclose(p->in); } 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" " -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_ENABLE_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" " -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" #if defined(SQLITE_ENABLE_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" " -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" " -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" " -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" |
︙ | ︙ | |||
11728 11729 11730 11731 11732 11733 11734 | /* ** 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; | < < < < < | 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 | /* ** 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 |
︙ | ︙ | |||
11779 11780 11781 11782 11783 11784 11785 | argv[0], argv[argc-1]); exit(1); } return argv[i]; } #ifndef SQLITE_SHELL_IS_UTF8 | | < < < < < < < < < < < < < < < < < < < < < < | < > | | | | | 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 | argv[0], argv[argc-1]); exit(1); } return argv[i]; } #ifndef SQLITE_SHELL_IS_UTF8 # if (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER) # define SQLITE_SHELL_IS_UTF8 (0) # else # define SQLITE_SHELL_IS_UTF8 (1) # endif #endif #if SQLITE_SHELL_IS_UTF8 int SQLITE_CDECL main(int argc, char **argv){ #else int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ char **argv; #endif char *zErrMsg = 0; ShellState data; const char *zInitFile = 0; int i; int rc = 0; int warnInmemoryDb = 0; int readStdin = 1; int nCmd = 0; char **azCmd = 0; const char *zVfs = 0; /* Value of -vfs command-line option */ #if !SQLITE_SHELL_IS_UTF8 char **argvToFree = 0; 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 #if USE_SYSTEM_SQLITE+0!=1 if( strncmp(sqlite3_sourceid(),SQLITE_SOURCE_ID,60)!=0 ){ utf8_printf(stderr, "SQLite header and source version mismatch\n%s\n%s\n", sqlite3_sourceid(), SQLITE_SOURCE_ID); exit(1); } #endif main_init(&data); /* On Windows, we must translate command-line arguments into UTF-8. ** The SQLite memory allocator subsystem has to be enabled in order to ** do this. But we want to run an sqlite3_shutdown() afterwards so that ** subsequent sqlite3_config() calls will work. So copy all results into ** memory that does not come from the SQLite memory allocator. */ #if !SQLITE_SHELL_IS_UTF8 sqlite3_initialize(); argvToFree = malloc(sizeof(argv[0])*argc*2); argcToFree = argc; argv = argvToFree + argc; if( argv==0 ) shell_out_of_memory(); for(i=0; i<argc; i++){ char *z = sqlite3_win32_unicode_to_utf8(wargv[i]); int n; if( z==0 ) shell_out_of_memory(); n = (int)strlen(z); argv[i] = malloc( n+1 ); if( argv[i]==0 ) shell_out_of_memory(); memcpy(argv[i], z, n+1); argvToFree[i] = argv[i]; sqlite3_free(z); } sqlite3_shutdown(); #endif |
︙ | ︙ | |||
11905 11906 11907 11908 11909 11910 11911 | #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**); | | | | | | | | | | | | | | | | < < < | < < < < < < < < | | | | | | | | | | | < < | | < < < < < < < | 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 | #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.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.zDbFilename==0 ){ data.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(); azCmd[nCmd-1] = z; } } if( z[1]=='-' ) z++; if( strcmp(z,"-separator")==0 || strcmp(z,"-nullvalue")==0 || strcmp(z,"-newline")==0 || strcmp(z,"-cmd")==0 ){ (void)cmdline_option_value(argc, argv, ++i); }else if( strcmp(z,"-init")==0 ){ zInitFile = cmdline_option_value(argc, argv, ++i); }else if( strcmp(z,"-batch")==0 ){ /* Need to check for batch mode here to so we can avoid printing ** informational messages (like from process_sqliterc) before ** we do the actual processing of arguments later in a second pass. */ stdin_is_interactive = 0; }else if( strcmp(z,"-heap")==0 ){ #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) const char *zSize; sqlite3_int64 szHeap; zSize = cmdline_option_value(argc, argv, ++i); szHeap = integerValue(zSize); if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000; sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64); #else (void)cmdline_option_value(argc, argv, ++i); #endif }else if( strcmp(z,"-pagecache")==0 ){ int n, sz; sz = (int)integerValue(cmdline_option_value(argc,argv,++i)); if( sz>70000 ) sz = 70000; if( sz<0 ) sz = 0; n = (int)integerValue(cmdline_option_value(argc,argv,++i)); 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; #ifdef SQLITE_ENABLE_VFSTRACE }else if( strcmp(z,"-vfstrace")==0 ){ extern int vfstrace_register( const char *zTraceName, const char *zOldVfsName, int (*xOut)(const char*,void*), void *pOutArg, int makeDefault ); vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1); #endif #ifdef SQLITE_ENABLE_MULTIPLEX }else if( strcmp(z,"-multiplex")==0 ){ extern int sqlite3_multiple_initialize(const char*,int); sqlite3_multiplex_initialize(0, 1); #endif }else if( strcmp(z,"-mmap")==0 ){ sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i)); sqlite3_config(SQLITE_CONFIG_MMAP_SIZE, sz, sz); #ifdef SQLITE_ENABLE_SORTER_REFERENCES }else if( strcmp(z,"-sorterref")==0 ){ sqlite3_int64 sz = integerValue(cmdline_option_value(argc,argv,++i)); sqlite3_config(SQLITE_CONFIG_SORTERREF_SIZE, (int)sz); #endif }else if( strcmp(z,"-vfs")==0 ){ 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; #ifdef SQLITE_ENABLE_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; #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); } } verify_uninitialized(); #ifdef SQLITE_SHELL_INIT_PROC { |
︙ | ︙ | |||
12069 12070 12071 12072 12073 12074 12075 | #endif if( zVfs ){ sqlite3_vfs *pVfs = sqlite3_vfs_find(zVfs); if( pVfs ){ sqlite3_vfs_register(pVfs, 1); }else{ | | | | < < | | | | | < < | | < < < < < < < < | | | | | | | < < | | > | < < < | | | | | < | < | | | | | | | | | | | | | | < < < < | | | | | | | | | 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 9346 9347 9348 9349 9350 9351 9352 9353 9354 9355 9356 9357 9358 9359 9360 9361 9362 9363 9364 9365 9366 9367 9368 9369 9370 9371 9372 9373 9374 9375 9376 9377 9378 9379 9380 9381 9382 9383 9384 9385 9386 9387 9388 9389 9390 9391 9392 9393 9394 9395 9396 | #endif if( zVfs ){ sqlite3_vfs *pVfs = sqlite3_vfs_find(zVfs); if( pVfs ){ sqlite3_vfs_register(pVfs, 1); }else{ utf8_printf(stderr, "no such VFS: \"%s\"\n", argv[i]); exit(1); } } if( data.zDbFilename==0 ){ #ifndef SQLITE_OMIT_MEMORYDB data.zDbFilename = ":memory:"; warnInmemoryDb = argc==1; #else utf8_printf(stderr,"%s: Error: no database filename specified\n", Argv0); return 1; #endif } data.out = stdout; sqlite3_appendvfs_init(0,0,0); /* Go ahead and open the database file if it already exists. If the ** file does not exist, delay opening it. This prevents empty database ** files from being created if a user mistypes the database name argument ** to the sqlite command-line tool. */ if( access(data.zDbFilename, 0)==0 ){ 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. */ process_sqliterc(&data,zInitFile); /* Make a second pass through the command-line argument and set ** options. This second pass is delayed until after the initialization ** file is processed so that the command-line arguments will override ** settings in the initialization file. */ for(i=1; i<argc; i++){ char *z = argv[i]; if( z[0]!='-' ) continue; if( z[1]=='-' ){ z++; } if( strcmp(z,"-init")==0 ){ 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; #ifdef SQLITE_ENABLE_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,"-ascii")==0 ){ data.mode = MODE_Ascii; sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, SEP_Unit); sqlite3_snprintf(sizeof(data.rowSeparator), data.rowSeparator, SEP_Record); }else if( strcmp(z,"-separator")==0 ){ 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; }else if( strcmp(z,"-noheader")==0 ){ data.showHeader = 0; }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 ){ bail_on_error = 1; }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,"-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++; #ifdef SQLITE_ENABLE_VFSTRACE }else if( strcmp(z,"-vfstrace")==0 ){ i++; #endif #ifdef SQLITE_ENABLE_MULTIPLEX }else if( strcmp(z,"-multiplex")==0 ){ i++; #endif }else if( strcmp(z,"-help")==0 ){ usage(1); }else if( strcmp(z,"-cmd")==0 ){ /* Run commands that follow -cmd first and separately from commands ** that simply appear on the command-line. This seems goofy. It would ** be better if all commands ran in the order that they appear. But ** we retain the goofy behavior for historical compatibility. */ if( i==argc-1 ) break; z = cmdline_option_value(argc,argv,++i); if( z[0]=='.' ){ |
︙ | ︙ | |||
12254 12255 12256 12257 12258 12259 12260 | if( bail_on_error ) return rc!=0 ? rc : 1; }else if( rc!=0 ){ utf8_printf(stderr,"Error: unable to process SQL \"%s\"\n", z); if( bail_on_error ) return rc; } } #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) | | < < < < | < < | | > | | < < < | > | 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 | if( bail_on_error ) return rc!=0 ? rc : 1; }else if( rc!=0 ){ utf8_printf(stderr,"Error: unable to process SQL \"%s\"\n", z); if( bail_on_error ) return rc; } } #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) }else if( strncmp(z, "-A", 2)==0 ){ if( nCmd>0 ){ utf8_printf(stderr, "Error: cannot mix regular SQL or dot-commands" " with \"%s\"\n", z); return 1; } open_db(&data, OPEN_DB_ZIPFILE); if( z[2] ){ argv[i] = &z[2]; 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); if( rc ) return rc==2 ? 0 : rc; }else{ open_db(&data, 0); rc = shell_exec(&data, azCmd[i], &zErrMsg); if( zErrMsg!=0 ){ utf8_printf(stderr,"Error: %s\n", zErrMsg); return rc!=0 ? rc : 1; }else if( rc!=0 ){ utf8_printf(stderr,"Error: unable to process SQL: %s\n", azCmd[i]); return rc; } } } free(azCmd); }else{ /* Run commands received from standard input */ if( stdin_is_interactive ){ char *zHome; char *zHistory; int nHistory; |
︙ | ︙ | |||
12352 12353 12354 12355 12356 12357 12358 | free(zHistory); } }else{ data.in = stdin; rc = process_input(&data); } } | < < < < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | free(zHistory); } }else{ data.in = stdin; rc = process_input(&data); } } set_table_name(&data, 0); if( data.db ){ session_close_all(&data); close_db(data.db); } sqlite3_free(data.zFreeOnClose); find_home_dir(1); output_reset(&data); data.doXdgOpen = 0; clearTempFile(&data); #if !SQLITE_SHELL_IS_UTF8 for(i=0; i<argcToFree; i++) free(argvToFree[i]); free(argvToFree); #endif /* 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 | */ #ifdef __cplusplus extern "C" { #endif /* ** Provide the ability to override linkage features of the interface. */ #ifndef SQLITE_EXTERN # define SQLITE_EXTERN extern #endif #ifndef SQLITE_API # define SQLITE_API #endif |
︙ | ︙ | |||
170 171 172 173 174 175 176 | ** ** ^The sqlite3_version[] string constant contains the text of [SQLITE_VERSION] ** macro. ^The sqlite3_libversion() function returns a pointer to the ** to the sqlite3_version[] string constant. The sqlite3_libversion() ** function is provided for use in DLLs since DLL users usually do not have ** direct access to string constants within the DLL. ^The ** sqlite3_libversion_number() function returns an integer equal to | | | | | | | | | | | 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 | ** ** ^The sqlite3_version[] string constant contains the text of [SQLITE_VERSION] ** macro. ^The sqlite3_libversion() function returns a pointer to the ** to the sqlite3_version[] string constant. The sqlite3_libversion() ** function is provided for use in DLLs since DLL users usually do not have ** direct access to string constants within the DLL. ^The ** sqlite3_libversion_number() function returns an integer equal to ** [SQLITE_VERSION_NUMBER]. ^(The sqlite3_sourceid() function returns ** a pointer to a string constant whose value is the same as the ** [SQLITE_SOURCE_ID] C preprocessor macro. Except if SQLite is built ** using an edited copy of [the amalgamation], then the last four characters ** of the hash might be different from [SQLITE_SOURCE_ID].)^ ** ** See also: [sqlite_version()] and [sqlite_source_id()]. */ SQLITE_EXTERN const char sqlite3_version[]; const char *sqlite3_libversion(void); const char *sqlite3_sourceid(void); int sqlite3_libversion_number(void); /* ** CAPI3REF: Run-Time Library Compilation Options Diagnostics ** ** ^The sqlite3_compileoption_used() function returns 0 or 1 ** indicating whether the specified option was defined at ** compile time. ^The SQLITE_ prefix may be omitted from the ** option name passed to sqlite3_compileoption_used(). ** ** ^The sqlite3_compileoption_get() function allows iterating ** over the list of options that were defined at compile time by ** returning the N-th compile time option string. ^If N is out of range, ** sqlite3_compileoption_get() returns a NULL pointer. ^The SQLITE_ ** prefix is omitted from any strings returned by ** sqlite3_compileoption_get(). ** ** ^Support for the diagnostic functions sqlite3_compileoption_used() ** and sqlite3_compileoption_get() may be omitted by specifying the ** [SQLITE_OMIT_COMPILEOPTION_DIAGS] option at compile time. ** ** 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); |
︙ | ︙ | |||
223 224 225 226 227 228 229 | ** ^The sqlite3_threadsafe() function returns zero if and only if ** SQLite was compiled with mutexing code omitted due to the ** [SQLITE_THREADSAFE] compile-time option being set to 0. ** ** SQLite can be compiled with or without mutexes. When ** the [SQLITE_THREADSAFE] C preprocessor macro is 1 or 2, mutexes ** are enabled and SQLite is threadsafe. When the | | | 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | ** ^The sqlite3_threadsafe() function returns zero if and only if ** SQLite was compiled with mutexing code omitted due to the ** [SQLITE_THREADSAFE] compile-time option being set to 0. ** ** SQLite can be compiled with or without mutexes. When ** the [SQLITE_THREADSAFE] C preprocessor macro is 1 or 2, mutexes ** are enabled and SQLite is threadsafe. When the ** [SQLITE_THREADSAFE] macro is 0, ** the mutexes are omitted. Without the mutexes, it is not safe ** to use SQLite concurrently from more than one thread. ** ** Enabling mutexes incurs a measurable performance penalty. ** So if speed is of utmost importance, it makes sense to disable ** the mutexes. But for maximum safety, mutexes should be enabled. ** ^The default behavior is for mutexes to be enabled. |
︙ | ︙ | |||
280 281 282 283 284 285 286 | ** ** The sqlite3_int64 and sqlite3_uint64 are the preferred type definitions. ** The sqlite_int64 and sqlite_uint64 types are supported for backwards ** compatibility only. ** ** ^The sqlite3_int64 and sqlite_int64 types can store integer values ** between -9223372036854775808 and +9223372036854775807 inclusive. ^The | | | | 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 | ** ** The sqlite3_int64 and sqlite3_uint64 are the preferred type definitions. ** The sqlite_int64 and sqlite_uint64 types are supported for backwards ** compatibility only. ** ** ^The sqlite3_int64 and sqlite_int64 types can store integer values ** between -9223372036854775808 and +9223372036854775807 inclusive. ^The ** sqlite3_uint64 and sqlite_uint64 types can store integer values ** between 0 and +18446744073709551615 inclusive. */ #ifdef SQLITE_INT64_TYPE typedef SQLITE_INT64_TYPE sqlite_int64; # ifdef SQLITE_UINT64_TYPE typedef SQLITE_UINT64_TYPE sqlite_uint64; # else typedef unsigned SQLITE_INT64_TYPE sqlite_uint64; # endif #elif defined(_MSC_VER) || defined(__BORLANDC__) typedef __int64 sqlite_int64; typedef unsigned __int64 sqlite_uint64; #else typedef long long int sqlite_int64; |
︙ | ︙ | |||
318 319 320 321 322 323 324 | ** ** ^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. ** | < < < < | | | | < | < | | | | > > > > > > > > > > | 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 | ** ** ^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 ** statements 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 ** and/or unfinished sqlite3_backups, then the database connection becomes ** an unusable "zombie" which will automatically be deallocated when the ** last prepared statement is finalized or the last sqlite3_backup is ** 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. ** ** 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 ** sqlite3_close_v2() is called on a [database connection] that still has ** outstanding [prepared statements], [BLOB handles], and/or ** [sqlite3_backup] objects then it returns [SQLITE_OK] and the deallocation ** of resources is deferred until all [prepared statements], [BLOB handles], ** and [sqlite3_backup] objects are also destroyed. ** ** ^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 |
︙ | ︙ | |||
363 364 365 366 367 368 369 | /* ** CAPI3REF: One-Step Query Execution Interface ** METHOD: sqlite3 ** ** The sqlite3_exec() interface is a convenience wrapper around ** [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()], ** that allows an application to run multiple statements of SQL | | | 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 | /* ** CAPI3REF: One-Step Query Execution Interface ** METHOD: sqlite3 ** ** The sqlite3_exec() interface is a convenience wrapper around ** [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()], ** that allows an application to run multiple statements of SQL ** without having to use a lot of C code. ** ** ^The sqlite3_exec() interface runs zero or more UTF-8 encoded, ** semicolon-separate SQL statements passed into its 2nd argument, ** in the context of the [database connection] passed in as its 1st ** argument. ^If the callback function of the 3rd argument to ** sqlite3_exec() is not NULL, then it is invoked for each result row ** coming out of the evaluated SQL statements. ^The 4th argument to |
︙ | ︙ | |||
403 404 405 406 407 408 409 | ** result row is NULL then the corresponding string pointer for the ** sqlite3_exec() callback is a NULL pointer. ^The 4th argument to the ** sqlite3_exec() callback is an array of pointers to strings where each ** entry represents the name of corresponding result column as obtained ** from [sqlite3_column_name()]. ** ** ^If the 2nd parameter to sqlite3_exec() is a NULL pointer, a pointer | | | 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 | ** result row is NULL then the corresponding string pointer for the ** sqlite3_exec() callback is a NULL pointer. ^The 4th argument to the ** sqlite3_exec() callback is an array of pointers to strings where each ** entry represents the name of corresponding result column as obtained ** from [sqlite3_column_name()]. ** ** ^If the 2nd parameter to sqlite3_exec() is a NULL pointer, a pointer ** to an empty string, or a pointer that contains only whitespace and/or ** SQL comments, then no SQL statements are evaluated and the database ** is not changed. ** ** Restrictions: ** ** <ul> ** <li> The application must ensure that the 1st parameter to sqlite3_exec() |
︙ | ︙ | |||
522 523 524 525 526 527 528 | #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)) | < < < < < < < < < < < < < < < < < < < < < < | < < < < < | 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 | #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 */ #define SQLITE_OPEN_MASTER_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 */ /* Reserved: 0x00F00000 */ /* ** 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 |
︙ | ︙ | |||
667 668 669 670 671 672 673 | #define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000 /* ** CAPI3REF: File Locking Levels ** ** SQLite uses one of these integer values as the second ** argument to calls it makes to the xLock() and xUnlock() methods | | < < < < | | | | | | 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 | #define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000 /* ** CAPI3REF: File Locking Levels ** ** SQLite uses one of these integer values as the second ** argument to calls it makes to the xLock() and xUnlock() methods ** of an [sqlite3_io_methods] object. */ #define SQLITE_LOCK_NONE 0 #define SQLITE_LOCK_SHARED 1 #define SQLITE_LOCK_RESERVED 2 #define SQLITE_LOCK_PENDING 3 #define SQLITE_LOCK_EXCLUSIVE 4 /* ** CAPI3REF: Synchronization Type Flags ** ** When SQLite invokes the xSync() method of an ** [sqlite3_io_methods] object it uses a combination of ** these integer values as the second argument. |
︙ | ︙ | |||
755 756 757 758 759 760 761 | ** <ul> ** <li> [SQLITE_LOCK_NONE], ** <li> [SQLITE_LOCK_SHARED], ** <li> [SQLITE_LOCK_RESERVED], ** <li> [SQLITE_LOCK_PENDING], or ** <li> [SQLITE_LOCK_EXCLUSIVE]. ** </ul> | < < < < < < < | | 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 | ** <ul> ** <li> [SQLITE_LOCK_NONE], ** <li> [SQLITE_LOCK_SHARED], ** <li> [SQLITE_LOCK_RESERVED], ** <li> [SQLITE_LOCK_PENDING], or ** <li> [SQLITE_LOCK_EXCLUSIVE]. ** </ul> ** xLock() increases the lock. xUnlock() decreases the lock. ** The xCheckReservedLock() method checks whether any database connection, ** either in this process or in some other process, is holding a RESERVED, ** PENDING, or EXCLUSIVE lock on the file. It returns true ** if such a lock exists and false otherwise. ** ** The xFileControl() method is a generic interface that allows custom ** VFS implementations to directly control an open file using the |
︙ | ︙ | |||
867 868 869 870 871 872 873 | ** ** <ul> ** <li>[[SQLITE_FCNTL_LOCKSTATE]] ** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This ** opcode causes the xFileControl method to write the current state of ** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED], ** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE]) | | | > | 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 | ** ** <ul> ** <li>[[SQLITE_FCNTL_LOCKSTATE]] ** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This ** opcode causes the xFileControl method to write the current state of ** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED], ** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE]) ** into an integer that the pArg argument points to. This capability ** is used during testing and is only available when the SQLITE_TEST ** compile-time option is used. ** ** <li>[[SQLITE_FCNTL_SIZE_HINT]] ** 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 |
︙ | ︙ | |||
890 891 892 893 894 895 896 | ** 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 | | | 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 | ** 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 ** improve performance on some systems. ** ** <li>[[SQLITE_FCNTL_FILE_POINTER]] ** The [SQLITE_FCNTL_FILE_POINTER] opcode is used to obtain a pointer |
︙ | ︙ | |||
913 914 915 916 917 918 919 | ** ** <li>[[SQLITE_FCNTL_SYNC_OMITTED]] ** No longer in use. ** ** <li>[[SQLITE_FCNTL_SYNC]] ** The [SQLITE_FCNTL_SYNC] opcode is generated internally by SQLite and ** sent to the VFS immediately before the xSync method is invoked on a | | | | | | | | | | | 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 | ** ** <li>[[SQLITE_FCNTL_SYNC_OMITTED]] ** No longer in use. ** ** <li>[[SQLITE_FCNTL_SYNC]] ** The [SQLITE_FCNTL_SYNC] opcode is generated internally by SQLite and ** 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 master-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 ** but before the database is unlocked. 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_WIN32_AV_RETRY]] ** ^The [SQLITE_FCNTL_WIN32_AV_RETRY] opcode is used to configure automatic ** retry counts and intervals for certain disk I/O operations for the ** windows [VFS] in order to provide robustness in the presence of ** anti-virus programs. By default, the windows VFS will retry file read, ** file write, and file delete operations up to 10 times, with a delay |
︙ | ︙ | |||
1003 1004 1005 1006 1007 1008 1009 | ** sqlite3_file_control(db,SQLITE_FCNTL_VFS_POINTER,X) must be ** of type "[sqlite3_vfs] **". This opcodes will set *X ** to a pointer to the top-level VFS.)^ ** ^When there are multiple VFS shims in the stack, this opcode finds the ** upper-most shim only. ** ** <li>[[SQLITE_FCNTL_PRAGMA]] | | | | | | | | 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 | ** sqlite3_file_control(db,SQLITE_FCNTL_VFS_POINTER,X) must be ** of type "[sqlite3_vfs] **". This opcodes will set *X ** to a pointer to the top-level VFS.)^ ** ^When there are multiple VFS shims in the stack, this opcode finds the ** upper-most shim only. ** ** <li>[[SQLITE_FCNTL_PRAGMA]] ** ^Whenever a [PRAGMA] statement is parsed, an [SQLITE_FCNTL_PRAGMA] ** file control is sent to the open [sqlite3_file] object corresponding ** to the database file to which the pragma statement refers. ^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. ^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. ^If the ** [SQLITE_FCNTL_PRAGMA] file control returns [SQLITE_NOTFOUND], then normal ** [PRAGMA] processing continues. ^If the [SQLITE_FCNTL_PRAGMA] ** file control returns [SQLITE_OK], then the parser assumes that the ** VFS has handled the PRAGMA itself and the parser generates a no-op ** prepared statement if result string is NULL, or that returns a copy ** of the result string if the string is non-NULL. ** ^If the [SQLITE_FCNTL_PRAGMA] file control returns ** any result code other than [SQLITE_OK] or [SQLITE_NOTFOUND], that means ** that the VFS encountered an error while handling the [PRAGMA] and the ** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA] ** file control occurs at the beginning of pragma statement analysis and so ** it is able to override built-in [PRAGMA] statements. ** ** <li>[[SQLITE_FCNTL_BUSYHANDLER]] ** ^The [SQLITE_FCNTL_BUSYHANDLER] ** file-control may be invoked by SQLite on the database file handle ** shortly after it is opened in order to provide a custom VFS with access ** to the connections busy-handler callback. The argument is of type (void **) ** - an array of two (void *) values. The first (void *) actually points ** to a function of type (int (*)(void *)). In order to invoke the connections ** busy-handler, this function should be invoked with the second (void *) in ** the array as the only argument. If it returns non-zero, then the operation ** should be retried. If it returns zero, the custom VFS should abandon the ** current operation. ** ** <li>[[SQLITE_FCNTL_TEMPFILENAME]] ** ^Application can invoke the [SQLITE_FCNTL_TEMPFILENAME] file-control ** to have SQLite generate a ** temporary filename using the same algorithm that is followed to generate ** temporary filenames for TEMP tables and other internal uses. The ** argument should be a char** which will be filled with the filename ** written into memory obtained from [sqlite3_malloc()]. The caller should ** invoke [sqlite3_free()] on the result to avoid a memory leak. ** ** <li>[[SQLITE_FCNTL_MMAP_SIZE]] ** The [SQLITE_FCNTL_MMAP_SIZE] file control is used to query or set the ** maximum number of bytes that will be used for memory-mapped I/O. ** The argument is a pointer to a value of type sqlite3_int64 that ** is an advisory maximum number of bytes in the file to memory map. The ** pointer is overwritten with the old value. The limit is not changed if ** the value originally pointed to is negative, and so the current limit ** can be queried by passing in a pointer to a negative number. This ** file-control is used internally to implement [PRAGMA mmap_size]. ** ** <li>[[SQLITE_FCNTL_TRACE]] ** The [SQLITE_FCNTL_TRACE] file control provides advisory information ** to the VFS about what the higher layers of the SQLite stack are doing. ** This file control is used by some VFS activity tracing [shims]. |
︙ | ︙ | |||
1098 1099 1100 1101 1102 1103 1104 | ** <li>[[SQLITE_FCNTL_ZIPVFS]] ** The [SQLITE_FCNTL_ZIPVFS] opcode is implemented by zipvfs only. All other ** VFS should return SQLITE_NOTFOUND for this opcode. ** ** <li>[[SQLITE_FCNTL_RBU]] ** The [SQLITE_FCNTL_RBU] opcode is implemented by the special VFS used by ** the RBU extension only. All other VFS should return SQLITE_NOTFOUND for | | | | | < | > | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | ** <li>[[SQLITE_FCNTL_ZIPVFS]] ** The [SQLITE_FCNTL_ZIPVFS] opcode is implemented by zipvfs only. All other ** VFS should return SQLITE_NOTFOUND for this opcode. ** ** <li>[[SQLITE_FCNTL_RBU]] ** The [SQLITE_FCNTL_RBU] opcode is implemented by the special VFS used by ** the RBU extension only. All other VFS should return SQLITE_NOTFOUND for ** this opcode. ** ** <li>[[SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]] ** If the [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] opcode returns SQLITE_OK, then ** the file descriptor is placed in "batch write mode", which ** means all subsequent write operations will be deferred and done ** atomically at the next [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. Systems ** that do not support batch atomic writes will return SQLITE_NOTFOUND. ** ^Following a successful SQLITE_FCNTL_BEGIN_ATOMIC_WRITE and prior to ** the closing [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] or ** [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE], SQLite will make ** no VFS interface calls on the same [sqlite3_file] file descriptor ** except for calls to the xWrite method and the xFileControl method ** with [SQLITE_FCNTL_SIZE_HINT]. ** ** <li>[[SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]] ** The [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] opcode causes all write ** operations since the previous successful call to ** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be performed atomically. ** This file control returns [SQLITE_OK] if and only if the writes were ** all performed successfully and have been committed to persistent storage. ** ^Regardless of whether or not it is successful, 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_COMMIT_ATOMIC_WRITE without ** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]. ** ** <li>[[SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE]] ** The [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE] opcode causes all write ** operations since the previous successful call to ** [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 causes attempts to obtain ** a file lock using the xLock or xShmLock methods of the VFS to wait ** for up to M milliseconds before failing, where M is the single ** unsigned integer parameter. ** ** <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 provide 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. ** </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 |
︙ | ︙ | |||
1232 1233 1234 1235 1236 1237 1238 | #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 | < < < < < < | 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 | #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 /* 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 |
︙ | ︙ | |||
1267 1268 1269 1270 1271 1272 1273 | ** A pointer to the opaque sqlite3_api_routines structure is passed as ** the third parameter to entry points of [loadable extensions]. This ** structure must be typedefed in order to work around compiler warnings ** on some platforms. */ typedef struct sqlite3_api_routines sqlite3_api_routines; | < < < < < < < < < < < < < < < < < < < < | | | | 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 | ** A pointer to the opaque sqlite3_api_routines structure is passed as ** the third parameter to entry points of [loadable extensions]. This ** structure must be typedefed in order to work around compiler warnings ** on some platforms. */ typedef struct sqlite3_api_routines sqlite3_api_routines; /* ** CAPI3REF: OS Interface Object ** ** An instance of the sqlite3_vfs object defines the interface between ** the SQLite core and the underlying operating system. The "vfs" ** in the name of the object stands for "virtual file system". See ** the [VFS | VFS documentation] for further information. ** ** The VFS interface is sometimes extended by adding new methods onto ** 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 the structure ** of the sqlite3_vfs object changes 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 modified. ** ** 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()] |
︙ | ︙ | |||
1341 1342 1343 1344 1345 1346 1347 | ** 11 alphanumeric and/or "-" characters. ** ^SQLite further guarantees that ** the string will be valid and unchanged until xClose() is ** called. Because of the previous sentence, ** the [sqlite3_file] can safely store a pointer to the ** filename if it needs to remember the filename for some reason. ** If the zFilename parameter to xOpen is a NULL pointer then xOpen | | | | | 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 | ** 11 alphanumeric and/or "-" characters. ** ^SQLite further guarantees that ** the string will be valid and unchanged until xClose() is ** called. Because of the previous sentence, ** the [sqlite3_file] can safely store a pointer to the ** filename if it needs to remember the filename for some reason. ** If the zFilename parameter to xOpen is a NULL pointer then xOpen ** must invent its own temporary name for the file. ^Whenever the ** xFilename parameter is NULL it will also be the case that the ** flags parameter will include [SQLITE_OPEN_DELETEONCLOSE]. ** ** The flags argument to xOpen() includes all bits set in ** the flags argument to [sqlite3_open_v2()]. Or if [sqlite3_open()] ** or [sqlite3_open16()] is used, then flags includes at least ** [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]. ** If xOpen() opens a file read-only then it sets *pOutFlags to ** include [SQLITE_OPEN_READONLY]. Other bits in *pOutFlags may be set. ** ** ^(SQLite will also add one of the following flags to the xOpen() ** call, depending on the object being opened: ** ** <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_MASTER_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 |
︙ | ︙ | |||
1390 1391 1392 1393 1394 1395 1396 | ** deleted when it is closed. ^The [SQLITE_OPEN_DELETEONCLOSE] ** will be set for TEMP databases and their journals, transient ** databases, and subjournals. ** ** ^The [SQLITE_OPEN_EXCLUSIVE] flag is always used in conjunction ** with the [SQLITE_OPEN_CREATE] flag, which are both directly ** analogous to the O_EXCL and O_CREAT flags of the POSIX open() | | | | | < < | < < < < | | | | | | 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 | ** deleted when it is closed. ^The [SQLITE_OPEN_DELETEONCLOSE] ** will be set for TEMP databases and their journals, transient ** databases, and subjournals. ** ** ^The [SQLITE_OPEN_EXCLUSIVE] flag is always used in conjunction ** with the [SQLITE_OPEN_CREATE] flag, which are both directly ** analogous to the O_EXCL and O_CREAT flags of the POSIX open() ** 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 file can be a ** directory. ** ** ^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. ** ** The xRandomness(), xSleep(), xCurrentTime(), and xCurrentTimeInt64() ** interfaces are not strictly a part of the filesystem, but they are ** included in the VFS structure for completeness. ** The xRandomness() function attempts to return nBytes bytes ** of good-quality randomness into zOut. The return value is ** the actual number of bytes of randomness obtained. ** The xSleep() method causes the calling thread to sleep for at ** least the number of microseconds given. ^The xCurrentTime() ** method returns a Julian Day Number for the current date and time as ** a floating point value. ** ^The xCurrentTimeInt64() method returns, as an integer, the Julian ** Day Number multiplied by 86400000 (the number of milliseconds in ** a 24-hour day). ** ^SQLite will use the xCurrentTimeInt64() method to get the current ** date and time if that method is available (if iVersion is 2 or ** greater and the function pointer is not NULL) and will fall back ** to xCurrentTime() if xCurrentTimeInt64() is unavailable. ** ** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces ** are not used by the SQLite core. These optional interfaces are provided ** by some VFSes to facilitate testing of the VFS code. By overriding ** system calls with functions under its control, a test program can ** simulate faults and error conditions that would otherwise be difficult ** or impossible to induce. The set of system calls that can be overridden ** varies from one VFS to another, and from one version of the same VFS to the ** next. Applications that use these interfaces must be prepared for any ** or all of these interfaces to be NULL or for their behavior to change ** from one release to the next. Applications must not attempt to access ** any of these methods if the iVersion of the VFS is less than 3. */ typedef struct sqlite3_vfs sqlite3_vfs; typedef void (*sqlite3_syscall_ptr)(void); struct sqlite3_vfs { int iVersion; /* Structure version number (currently 3) */ int szOsFile; /* Size of subclassed sqlite3_file */ int mxPathname; /* Maximum file pathname length */ sqlite3_vfs *pNext; /* Next registered VFS */ const char *zName; /* Name of this virtual file system */ void *pAppData; /* Pointer to application-specific data */ int (*xOpen)(sqlite3_vfs*, const char *zName, sqlite3_file*, int flags, int *pOutFlags); int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir); int (*xAccess)(sqlite3_vfs*, const char *zName, int flags, int *pResOut); int (*xFullPathname)(sqlite3_vfs*, const char *zName, int nOut, char *zOut); void *(*xDlOpen)(sqlite3_vfs*, const char *zFilename); void (*xDlError)(sqlite3_vfs*, int nByte, char *zErrMsg); void (*(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol))(void); |
︙ | ︙ | |||
1537 1538 1539 1540 1541 1542 1543 | ** <li> SQLITE_SHM_LOCK | SQLITE_SHM_SHARED ** <li> SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE ** <li> SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED ** <li> SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE ** </ul> ** ** When unlocking, the same SHARED or EXCLUSIVE flag must be supplied as | | | 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 | ** <li> SQLITE_SHM_LOCK | SQLITE_SHM_SHARED ** <li> SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE ** <li> SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED ** <li> SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE ** </ul> ** ** When unlocking, the same SHARED or EXCLUSIVE flag must be supplied as ** was given on the corresponding lock. ** ** The xShmLock method can transition between unlocked and SHARED or ** between unlocked and EXCLUSIVE. It cannot transition between SHARED ** and EXCLUSIVE. */ #define SQLITE_SHM_UNLOCK 1 #define SQLITE_SHM_LOCK 2 |
︙ | ︙ | |||
1700 1701 1702 1703 1704 1705 1706 | ** ** An instance of this object defines the interface between SQLite ** and low-level memory allocation routines. ** ** This object is used in only one place in the SQLite interface. ** A pointer to an instance of this object is the argument to ** [sqlite3_config()] when the configuration option is | | | 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 | ** ** An instance of this object defines the interface between SQLite ** and low-level memory allocation routines. ** ** This object is used in only one place in the SQLite interface. ** A pointer to an instance of this object is the argument to ** [sqlite3_config()] when the configuration option is ** [SQLITE_CONFIG_MALLOC] or [SQLITE_CONFIG_GETMALLOC]. ** By creating an instance of this object ** and passing it to [sqlite3_config]([SQLITE_CONFIG_MALLOC]) ** during configuration, an application can specify an alternative ** memory allocation subsystem for SQLite to use for all of its ** dynamic memory needs. ** ** Note that SQLite comes with several [built-in memory allocators] |
︙ | ︙ | |||
1734 1735 1736 1737 1738 1739 1740 | ** 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, | | | | 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 | ** 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 require 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_MASTER] 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 |
︙ | ︙ | |||
1823 1824 1825 1826 1827 1828 1829 | ** ^If SQLite is compiled with ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then ** it is not possible to set the Serialized [threading mode] and ** [sqlite3_config()] will return [SQLITE_ERROR] if called with the ** SQLITE_CONFIG_SERIALIZED configuration option.</dd> ** ** [[SQLITE_CONFIG_MALLOC]] <dt>SQLITE_CONFIG_MALLOC</dt> | | | 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 | ** ^If SQLite is compiled with ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then ** it is not possible to set the Serialized [threading mode] and ** [sqlite3_config()] will return [SQLITE_ERROR] if called with the ** SQLITE_CONFIG_SERIALIZED configuration option.</dd> ** ** [[SQLITE_CONFIG_MALLOC]] <dt>SQLITE_CONFIG_MALLOC</dt> ** <dd> ^(The SQLITE_CONFIG_MALLOC option takes a single argument which is ** a pointer to an instance of the [sqlite3_mem_methods] structure. ** The argument specifies ** alternative low-level memory allocation routines to be used in place of ** the memory allocation routines built into SQLite.)^ ^SQLite makes ** its own private copy of the content of the [sqlite3_mem_methods] structure ** before the [sqlite3_config()] call returns.</dd> ** |
︙ | ︙ | |||
1856 1857 1858 1859 1860 1861 1862 | ** ** [[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> | < | | | 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 | ** ** [[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. ** This configuration option is a no-op if an application-define 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 |
︙ | ︙ | |||
1902 1903 1904 1905 1906 1907 1908 | ** from [sqlite3_malloc()] sufficient for N cache lines if N is positive or ** of -1024*N bytes if N is negative, . ^If additional ** page cache memory is needed beyond what is provided by the initial ** allocation, then SQLite goes to [sqlite3_malloc()] separately for each ** additional cache line. </dd> ** ** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt> | | | 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 | ** from [sqlite3_malloc()] sufficient for N cache lines if N is positive or ** of -1024*N bytes if N is negative, . ^If additional ** page cache memory is needed beyond what is provided by the initial ** allocation, then SQLite goes to [sqlite3_malloc()] separately for each ** additional cache line. </dd> ** ** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt> ** <dd> ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer ** that SQLite will use for all of its dynamic memory allocation needs ** beyond those provided for by [SQLITE_CONFIG_PAGECACHE]. ** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled ** with either [SQLITE_ENABLE_MEMSYS3] or [SQLITE_ENABLE_MEMSYS5] and returns ** [SQLITE_ERROR] if invoked otherwise. ** ^There are three arguments to SQLITE_CONFIG_HEAP: ** An 8-byte aligned pointer to the memory, |
︙ | ︙ | |||
1957 1958 1959 1960 1961 1962 1963 | ** size of each lookaside buffer slot and the second is the number of ** slots allocated to each database connection.)^ ^(SQLITE_CONFIG_LOOKASIDE ** sets the <i>default</i> lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] ** option to [sqlite3_db_config()] can be used to change the lookaside ** configuration on individual connections.)^ </dd> ** ** [[SQLITE_CONFIG_PCACHE2]] <dt>SQLITE_CONFIG_PCACHE2</dt> | | | | 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 | ** size of each lookaside buffer slot and the second is the number of ** slots allocated to each database connection.)^ ^(SQLITE_CONFIG_LOOKASIDE ** sets the <i>default</i> lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] ** option to [sqlite3_db_config()] can be used to change the lookaside ** configuration on individual connections.)^ </dd> ** ** [[SQLITE_CONFIG_PCACHE2]] <dt>SQLITE_CONFIG_PCACHE2</dt> ** <dd> ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is ** a pointer to an [sqlite3_pcache_methods2] object. This object specifies ** the interface to a custom page cache implementation.)^ ** ^SQLite makes a copy of the [sqlite3_pcache_methods2] object.</dd> ** ** [[SQLITE_CONFIG_GETPCACHE2]] <dt>SQLITE_CONFIG_GETPCACHE2</dt> ** <dd> ^(The SQLITE_CONFIG_GETPCACHE2 option takes a single argument which ** is a pointer to an [sqlite3_pcache_methods2] object. SQLite copies of ** the current page cache implementation into that object.)^ </dd> ** ** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt> ** <dd> The SQLITE_CONFIG_LOG option is used to configure the SQLite ** global [error log]. ** (^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a ** function with a call signature of void(*)(void*,int,const char*), ** and a pointer to void. ^If the function pointer is not NULL, it is ** invoked by [sqlite3_log()] to process each logging event. ^If the ** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op. ** ^The void pointer that is the second argument to SQLITE_CONFIG_LOG is ** passed through as the first parameter to the application-defined logger ** function whenever that function is invoked. ^The second parameter to ** the logger function is a copy of the first parameter to the corresponding |
︙ | ︙ | |||
2080 2081 2082 2083 2084 2085 2086 | ** is enabled (using the [PRAGMA threads] command) and the amount of content ** to be sorted exceeds the page size times the minimum of the ** [PRAGMA cache_size] setting and this value. ** ** [[SQLITE_CONFIG_STMTJRNL_SPILL]] ** <dt>SQLITE_CONFIG_STMTJRNL_SPILL ** <dd>^The SQLITE_CONFIG_STMTJRNL_SPILL option takes a single parameter which | | | 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 | ** is enabled (using the [PRAGMA threads] command) and the amount of content ** to be sorted exceeds the page size times the minimum of the ** [PRAGMA cache_size] setting and this value. ** ** [[SQLITE_CONFIG_STMTJRNL_SPILL]] ** <dt>SQLITE_CONFIG_STMTJRNL_SPILL ** <dd>^The SQLITE_CONFIG_STMTJRNL_SPILL option takes a single parameter which ** becomes the [statement journal] spill-to-disk threshold. ** [Statement journals] are held in memory until their size (in bytes) ** exceeds this threshold, at which point they are written to disk. ** Or if the threshold is -1, statement journals are always held ** exclusively in memory. ** Since many statement journals never become large, setting the spill ** threshold to a value such as 64KiB can greatly reduce the amount of ** I/O required to support statement rollback. |
︙ | ︙ | |||
2102 2103 2104 2105 2106 2107 2108 | ** Usually, when SQLite uses an external sort to order records according ** to an ORDER BY clause, all fields required by the caller are present in the ** sorted records. However, if SQLite determines based on the declared type ** of a table column that its values are likely to be very large - larger ** 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 | | | 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 | ** Usually, when SQLite uses an external sort to order records according ** to an ORDER BY clause, all fields required by the caller are present in the ** sorted records. However, if SQLite determines based on the declared type ** of a table column that its values are likely to be very large - larger ** 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 |
︙ | ︙ | |||
2130 2131 2132 2133 2134 2135 2136 | #define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */ #define SQLITE_CONFIG_SCRATCH 6 /* No longer used */ #define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */ #define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */ #define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */ #define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */ #define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */ | | | 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 | #define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */ #define SQLITE_CONFIG_SCRATCH 6 /* No longer used */ #define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */ #define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */ #define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */ #define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */ #define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */ /* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ #define SQLITE_CONFIG_LOOKASIDE 13 /* int int */ #define SQLITE_CONFIG_PCACHE 14 /* no-op */ #define SQLITE_CONFIG_GETPCACHE 15 /* no-op */ #define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ #define SQLITE_CONFIG_URI 17 /* int */ #define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */ #define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */ |
︙ | ︙ | |||
2165 2166 2167 2168 2169 2170 2171 | ** the call worked. ^The [sqlite3_db_config()] interface will return a ** non-zero [error code] if a discontinued or unsupported configuration option ** is invoked. ** ** <dl> ** [[SQLITE_DBCONFIG_LOOKASIDE]] ** <dt>SQLITE_DBCONFIG_LOOKASIDE</dt> | | | | | 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 | ** the call worked. ^The [sqlite3_db_config()] interface will return a ** non-zero [error code] if a discontinued or unsupported configuration option ** is invoked. ** ** <dl> ** [[SQLITE_DBCONFIG_LOOKASIDE]] ** <dt>SQLITE_DBCONFIG_LOOKASIDE</dt> ** <dd> ^This option takes three additional arguments that determine the ** [lookaside memory allocator] configuration for the [database connection]. ** ^The first argument (the third parameter to [sqlite3_db_config()] is a ** pointer to a memory buffer to use for lookaside memory. ** ^The first argument after the SQLITE_DBCONFIG_LOOKASIDE verb ** may be NULL in which case SQLite will allocate the ** lookaside buffer itself using [sqlite3_malloc()]. ^The second argument is the ** size of each lookaside buffer slot. ^The third argument is the number of ** slots. The size of the buffer in the first argument must be greater than ** or equal to the product of the second and third arguments. The buffer ** must be aligned to an 8-byte boundary. ^If the second argument to ** SQLITE_DBCONFIG_LOOKASIDE is not a multiple of 8, it is internally ** rounded down to the next smaller multiple of 8. ^(The lookaside memory ** configuration for a database connection can only be changed when that ** connection is not currently using lookaside memory, or in other words ** when the "current value" returned by ** [sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero. ** Any attempt to change the lookaside memory configuration when lookaside ** memory is in use leaves the configuration unchanged and returns ** [SQLITE_BUSY].)^</dd> ** ** [[SQLITE_DBCONFIG_ENABLE_FKEY]] ** <dt>SQLITE_DBCONFIG_ENABLE_FKEY</dt> ** <dd> ^This option is used to enable or disable the enforcement of ** [foreign key constraints]. There should be two additional arguments. ** The first argument is an integer which is 0 to disable FK enforcement, |
︙ | ︙ | |||
2206 2207 2208 2209 2210 2211 2212 | ** <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 | | < < < < < < < < < < < < < < < < < < < < < < < | 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 | ** <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. </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. |
︙ | ︙ | |||
2331 2332 2333 2334 2335 2336 2337 | ** the database in WAL mode after the reset if it was in WAL mode before ** the reset. ** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0); ** <li> [sqlite3_exec](db, "[VACUUM]", 0, 0, 0); ** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0); ** </ol> ** Because resetting a database is destructive and irreversible, the | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 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 | ** the database in WAL mode after the reset if it was in WAL mode before ** the reset. ** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0); ** <li> [sqlite3_exec](db, "[VACUUM]", 0, 0, 0); ** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0); ** </ol> ** Because resetting a database is destructive and irreversible, the ** process requires the use of this obscure API and multiple steps to help ** ensure that it does not happen by accident. ** ** [[SQLITE_DBCONFIG_DEFENSIVE]] <dt>SQLITE_DBCONFIG_DEFENSIVE</dt> ** <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> ** ** [[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> ** </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_MAX 1011 /* 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 |
︙ | ︙ | |||
2541 2542 2543 2544 2545 2546 2547 | */ void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64); /* ** CAPI3REF: Count The Number Of Rows Modified ** METHOD: sqlite3 ** | | < < < < | > | 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 | */ void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64); /* ** CAPI3REF: Count The Number Of Rows Modified ** METHOD: sqlite3 ** ** ^This function returns 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. ** ^Executing any other type of SQL statement does not modify the value ** returned by this function. ** ** ^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 |
︙ | ︙ | |||
2597 2598 2599 2600 2601 2602 2603 | ** <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*); | < | | < < < | < | 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 | ** <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 ** ** ^This function returns 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. ^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 |
︙ | ︙ | |||
2639 2640 2641 2642 2643 2644 2645 | ** <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*); | < | 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 | ** <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*); /* ** 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 |
︙ | ︙ | |||
2668 2669 2670 2671 2672 2673 2674 | ** ^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 | | < < < < | 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 | ** ^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 statements 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. */ void sqlite3_interrupt(sqlite3*); /* ** CAPI3REF: Determine If An SQL Statement Is Complete ** ** These routines are useful during command-line input to determine if the ** currently entered text seems to form a complete SQL statement or ** if additional input is needed before sending the text into |
︙ | ︙ | |||
2840 2841 2842 2843 2844 2845 2846 | ** Name | Age ** ----------------------- ** Alice | 43 ** Bob | 28 ** Cindy | 21 ** </pre></blockquote> ** | | | | 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 | ** Name | Age ** ----------------------- ** Alice | 43 ** Bob | 28 ** Cindy | 21 ** </pre></blockquote> ** ** There are two column (M==2) and three rows (N==3). Thus the ** result table has 8 entries. Suppose the result table is stored ** in an array names azResult. Then azResult holds this content: ** ** <blockquote><pre> ** azResult[0] = "Name"; ** azResult[1] = "Age"; ** azResult[2] = "Alice"; ** azResult[3] = "43"; ** azResult[4] = "Bob"; |
︙ | ︙ | |||
2935 2936 2937 2938 2939 2940 2941 | 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 | | | 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 | 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 |
︙ | ︙ | |||
2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 | ** of sqlite3_msize(X) is undefined and possibly harmful. ** ** ^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 | > > > > > > > > > > > > > | 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 | ** of sqlite3_msize(X) is undefined and possibly harmful. ** ** ^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. ** ** In SQLite version 3.5.0 and 3.5.1, it was possible to define ** the SQLITE_OMIT_MEMORY_ALLOCATION which would cause the built-in ** implementation of these routines to be omitted. That capability ** is no longer provided. Only built-in memory allocators can be used. ** ** Prior to SQLite version 3.7.10, the Windows OS interface layer called ** the system malloc() and free() directly when converting ** filenames between the UTF-8 encoding used by SQLite ** and whatever filename encoding is used by the particular Windows ** installation. Memory allocation errors were detected, but ** they were reported back as [SQLITE_CANTOPEN] or ** [SQLITE_IOERR] rather than [SQLITE_NOMEM]. ** ** 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 |
︙ | ︙ | |||
3044 3045 3046 3047 3048 3049 3050 | /* ** 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 | | | 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 | /* ** 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 build-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 |
︙ | ︙ | |||
3288 3289 3290 3291 3292 3293 3294 | ** <dl> ** [[SQLITE_TRACE_STMT]] <dt>SQLITE_TRACE_STMT</dt> ** <dd>^An SQLITE_TRACE_STMT callback is invoked when a prepared statement ** first begins running and possibly at other times during the ** execution of the prepared statement, such as at the start of each ** trigger subprogram. ^The P argument is a pointer to the ** [prepared statement]. ^The X argument is a pointer to a string which | | | | | | 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 | ** <dl> ** [[SQLITE_TRACE_STMT]] <dt>SQLITE_TRACE_STMT</dt> ** <dd>^An SQLITE_TRACE_STMT callback is invoked when a prepared statement ** first begins running and possibly at other times during the ** execution of the prepared statement, such as at the start of each ** trigger subprogram. ^The P argument is a pointer to the ** [prepared statement]. ^The X argument is a pointer to a string which ** is the unexpanded SQL text of the prepared statement or an SQL comment ** that indicates the invocation of a trigger. ^The callback can compute ** the same text that would have been returned by the legacy [sqlite3_trace()] ** interface by using the X argument when X begins with "--" and invoking ** [sqlite3_expanded_sql(P)] otherwise. ** ** [[SQLITE_TRACE_PROFILE]] <dt>SQLITE_TRACE_PROFILE</dt> ** <dd>^An SQLITE_TRACE_PROFILE callback provides approximately the same ** information as is provided by the [sqlite3_profile()] callback. ** ^The P argument is a pointer to the [prepared statement] and the ** X argument points to a 64-bit integer which is the estimated of ** the number of nanosecond that the prepared statement took to run. ** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes. ** ** [[SQLITE_TRACE_ROW]] <dt>SQLITE_TRACE_ROW</dt> ** <dd>^An SQLITE_TRACE_ROW callback is invoked whenever a prepared ** statement generates a single row of result. ** ^The P argument is a pointer to the [prepared statement] and the ** X argument is unused. ** ** [[SQLITE_TRACE_CLOSE]] <dt>SQLITE_TRACE_CLOSE</dt> ** <dd>^An SQLITE_TRACE_CLOSE callback is invoked when a database ** connection closes. ** ^The P argument is a pointer to the [database connection] object |
︙ | ︙ | |||
3362 3363 3364 3365 3366 3367 3368 | /* ** CAPI3REF: Query Progress Callbacks ** METHOD: sqlite3 ** ** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback ** function X to be invoked periodically during long running calls to | | | 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 | /* ** CAPI3REF: Query Progress Callbacks ** METHOD: sqlite3 ** ** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback ** function X to be invoked periodically during long running calls to ** [sqlite3_exec()], [sqlite3_step()] and [sqlite3_get_table()] for ** database connection D. An example use for this ** interface is to keep a GUI updated during a large query. ** ** ^The parameter P is passed through as the only parameter to the ** callback function X. ^The parameter N is the approximate number of ** [virtual machine instructions] that are evaluated between successive ** invocations of the callback X. ^If N is less than one then the progress |
︙ | ︙ | |||
3387 3388 3389 3390 3391 3392 3393 | ** "Cancel" button on a GUI progress dialog box. ** ** The progress handler callback must not do anything that will modify ** the database connection that invoked the progress handler. ** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their ** database connections for the meaning of "modify" in this paragraph. ** | < < < < < < < | | 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 | ** "Cancel" button on a GUI progress dialog box. ** ** The progress handler callback must not do anything that will modify ** the database connection that invoked the progress handler. ** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their ** database connections for the meaning of "modify" in this paragraph. ** */ void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); /* ** CAPI3REF: Opening A New Database Connection ** CONSTRUCTOR: sqlite3 ** ** ^These routines open an SQLite database file as specified by the ** filename argument. ^The filename argument is interpreted as UTF-8 for ** sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte ** order for sqlite3_open16(). ^(A [database connection] handle is usually ** returned in *ppDb, even if an error occurs. The only exception is that ** if SQLite is unable to allocate memory to hold the [sqlite3] object, ** a NULL will be written into *ppDb instead of a pointer to the [sqlite3] ** object.)^ ^(If the database is opened (and/or created) successfully, then |
︙ | ︙ | |||
3425 3426 3427 3428 3429 3430 3431 | ** 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 | | | > > | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | < < | > > | > > | < > | > > | 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 | ** 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() can take one of ** the following three values, optionally combined with the ** [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], [SQLITE_OPEN_SHAREDCACHE], ** [SQLITE_OPEN_PRIVATECACHE], and/or [SQLITE_OPEN_URI] flags:)^ ** ** <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> ** ** If the 3rd parameter to sqlite3_open_v2() is not one of the ** combinations shown above optionally combined with other ** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits] ** then the behavior is undefined. ** ** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection ** opens in the multi-thread [threading mode] as long as the single-thread ** mode has not been set at compile-time or start-time. ^If the ** [SQLITE_OPEN_FULLMUTEX] flag is set then the database connection opens ** in the serialized [threading mode] unless single-thread was ** previously selected at compile-time or start-time. ** ^The [SQLITE_OPEN_SHAREDCACHE] flag causes the database connection to be ** eligible to use [shared cache mode], regardless of whether or not shared ** cache is enabled using [sqlite3_enable_shared_cache()]. ^The ** [SQLITE_OPEN_PRIVATECACHE] flag causes the database connection to not ** participate in [shared cache mode] even if it is enabled. ** ** ^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 |
︙ | ︙ | |||
3651 3652 3653 3654 3655 3656 3657 | ** 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. | < | 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 | ** 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 |
︙ | ︙ | |||
3693 3694 3695 3696 3697 3698 3699 | int flags, /* Flags */ const char *zVfs /* Name of VFS module to use */ ); /* ** CAPI3REF: Obtain Values For URI Parameters ** | | | < < < | | < < < | < < < < | | | < < < < < < < | | | < < < < < < < < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < | 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 | 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 implementations, that check ** to see if a database file was a URI that contained a specific query ** parameter, and if so obtains the value of that query parameter. ** ** If F is the database filename pointer passed into the xOpen() method of ** a VFS implementation when the flags parameter to xOpen() has one or ** more of the [SQLITE_OPEN_URI] or [SQLITE_OPEN_MAIN_DB] bits set and ** 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 ** 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 is 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. ** ** 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 SQLite passed into the xOpen ** VFS method, then the behavior of this routine is undefined and probably ** undesirable. ** ** 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); /* ** 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 ** returns the numeric [result code] or [extended result code] for that ** API call. ** ^The sqlite3_extended_errcode() ** interface is the same except that it always returns the ** [extended result code] even when extended result codes are ** disabled. ** ** The values returned by sqlite3_errcode() and/or ** sqlite3_extended_errcode() might change with each API call. ** Except, there are some interfaces that are guaranteed to never ** change the value of the error code. The error-code preserving ** interfaces are: ** ** <ul> ** <li> sqlite3_errcode() ** <li> sqlite3_extended_errcode() ** <li> sqlite3_errmsg() ** <li> sqlite3_errmsg16() ** </ul> ** ** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language ** text that describes the error, as either UTF-8 or UTF-16 respectively. ** ^(Memory to hold the error message string is managed internally. ** The application does not need to worry about freeing the result. ** However, the error string might be overwritten or deallocated by ** subsequent calls to other SQLite interface functions.)^ ** ** ^The sqlite3_errstr() interface returns the English-language text ** that describes the [result code], as UTF-8. ** ^(Memory to hold the error message string is managed internally ** and must not be freed by the application)^. ** ** When the serialized [threading mode] is in use, it might be the ** case that a second error occurs on a separate thread in between ** the time of the first error and the call to these interfaces. ** When that happens, the second error will be reported since these ** interfaces always report the most recent result. To avoid ** this, each thread can obtain exclusive use of the [database connection] D ** by invoking [sqlite3_mutex_enter]([sqlite3_db_mutex](D)) before beginning ** to use D and invoking [sqlite3_mutex_leave]([sqlite3_db_mutex](D)) after ** all calls to the interfaces listed here are completed. ** ** If an interface fails with SQLITE_MISUSE, that means the interface ** was invoked incorrectly by the application. In that case, the ** error code and message may or may not be set. */ int sqlite3_errcode(sqlite3 *db); int sqlite3_extended_errcode(sqlite3 *db); const char *sqlite3_errmsg(sqlite3*); const void *sqlite3_errmsg16(sqlite3*); const char *sqlite3_errstr(int); /* ** CAPI3REF: Prepared Statement Object ** KEYWORDS: {prepared statement} {prepared statements} ** ** An instance of this object represents a single SQL statement that ** has been compiled into binary form and is ready to be evaluated. |
︙ | ︙ | |||
4190 4191 4192 4193 4194 4195 4196 | ** [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> | | | | | | 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 | ** [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 [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 WHERE-clause [parameter] might influence the ** choice of query plan if the parameter is the left-hand side of a [LIKE] ** or [GLOB] operator or if the parameter is compared to an indexed column ** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled. ** </li> ** </ol> ** ** <p>^sqlite3_prepare_v3() differs from sqlite3_prepare_v2() only in having ** the extra prepFlags parameter, which is a bit array consisting of zero or ** more of the [SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_*] flags. ^The ** sqlite3_prepare_v2() interface works exactly the same as |
︙ | ︙ | |||
4288 4289 4290 4291 4292 4293 4294 | ** 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, | | < < < < < | 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 | ** 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 free by the application ** by passing it to [sqlite3_free()]. */ const char *sqlite3_sql(sqlite3_stmt *pStmt); char *sqlite3_expanded_sql(sqlite3_stmt *pStmt); const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt); /* ** 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 |
︙ | ︙ | |||
4333 4334 4335 4336 4337 4338 4339 | ** 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. | < < < < < < < < < < < < < | 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 | ** 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: Query The EXPLAIN Setting For A Prepared Statement ** METHOD: sqlite3_stmt ** |
︙ | ︙ | |||
4414 4415 4416 4417 4418 4419 4420 | ** sqlite3_value objects and they can be used interchangeably. However, ** for maximum code portability it is recommended that applications ** still make the distinction between protected and unprotected ** sqlite3_value objects even when not strictly required. ** ** ^The sqlite3_value objects that are passed as parameters into the ** implementation of [application-defined SQL functions] are protected. | < < | 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 | ** sqlite3_value objects and they can be used interchangeably. However, ** for maximum code portability it is recommended that applications ** still make the distinction between protected and unprotected ** sqlite3_value objects even when not strictly required. ** ** ^The sqlite3_value objects that are passed as parameters into the ** implementation of [application-defined SQL functions] are protected. ** ^The sqlite3_value object returned by ** [sqlite3_column_value()] is unprotected. ** Unprotected sqlite3_value objects may only be used as arguments ** to [sqlite3_result_value()], [sqlite3_bind_value()], and ** [sqlite3_value_dup()]. ** The [sqlite3_value_blob | sqlite3_value_type()] family of ** interfaces require protected sqlite3_value objects. |
︙ | ︙ | |||
4475 4476 4477 4478 4479 4480 4481 | ** ^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()] | | < < < < < < < < < < < < < < < < < < | | | < | | | | > | | < < < | > | < < | 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 | ** ^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: 999). ** ** ^The third argument is the value to bind to the parameter. ** ^If the third parameter to sqlite3_bind_text() or sqlite3_bind_text16() ** or sqlite3_bind_blob() is a NULL pointer then the fourth parameter ** is ignored and the end result is the same as sqlite3_bind_null(). ** ** ^(In those routines that have a fourth argument, its value is the ** number of bytes in the parameter. To be clear: the value is the ** number of <u>bytes</u> in the value, not the number of characters.)^ ** ^If the fourth parameter to sqlite3_bind_text() or sqlite3_bind_text16() ** is negative, then the length of the string is ** the number of bytes up to the first zero terminator. ** 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 occur 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 ** is a destructor used to dispose of the BLOB or ** string after SQLite has finished with it. ^The destructor 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. ** ^If the fifth argument is ** the special value [SQLITE_STATIC], then SQLite assumes that the ** information is in static, unmanaged space and does not need to be freed. ** ^If the fifth argument has the value [SQLITE_TRANSIENT], then ** SQLite makes its own private copy of the data immediately, before ** the sqlite3_bind_*() routine returns. ** ** ^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 |
︙ | ︙ | |||
4746 4747 4748 4749 4750 4751 4752 | ** ^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 | | > > > > | 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 | ** ^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 routine 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 of these routines against the same ** prepared statement and column at the same time then the results are ** undefined. ** ** 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); |
︙ | ︙ | |||
4892 4893 4894 4895 4896 4897 4898 | /* ** 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 | | | 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 | /* ** 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_*()] 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 |
︙ | ︙ | |||
5037 5038 5039 5040 5041 5042 5043 | ** [sqlite3_column_bytes()] and [sqlite3_column_bytes16()] are the number of ** bytes in the string, not the number of characters. ** ** ^Strings returned by sqlite3_column_text() and sqlite3_column_text16(), ** even empty strings, are always zero-terminated. ^The return ** value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer. ** | < < < < | | 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 | ** [sqlite3_column_bytes()] and [sqlite3_column_bytes16()] are the number of ** bytes in the string, not the number of characters. ** ** ^Strings returned by sqlite3_column_text() and sqlite3_column_text16(), ** even empty strings, are always zero-terminated. ^The return ** value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer. ** ** <b>Warning:</b> ^The object returned by [sqlite3_column_value()] is an ** [unprotected sqlite3_value] object. In a multithreaded environment, ** an unprotected sqlite3_value object may only be used safely with ** [sqlite3_bind_value()] and [sqlite3_result_value()]. ** If the [unprotected sqlite3_value] object returned by ** [sqlite3_column_value()] is used in any other way, including calls ** to routines like [sqlite3_value_int()], [sqlite3_value_text()], ** or [sqlite3_value_bytes()], the behavior is not threadsafe. ** Hence, the sqlite3_column_value() interface ** is normally only useful within the implementation of ** [application-defined SQL functions] or [virtual tables], not within ** top-level application code. ** ** The these routines may attempt to convert the datatype of the result. ** ^For example, if the internal representation is FLOAT and a text result ** is requested, [sqlite3_snprintf()] is used internally to perform the ** conversion automatically. ^(The following table details the conversions ** that are applied: ** ** <blockquote> ** <table border="1"> |
︙ | ︙ | |||
5079 5080 5081 5082 5083 5084 5085 | ** <tr><td> FLOAT <td> TEXT <td> ASCII rendering of the float ** <tr><td> FLOAT <td> BLOB <td> [CAST] to BLOB ** <tr><td> TEXT <td> INTEGER <td> [CAST] to INTEGER ** <tr><td> TEXT <td> FLOAT <td> [CAST] to REAL ** <tr><td> TEXT <td> BLOB <td> No change ** <tr><td> BLOB <td> INTEGER <td> [CAST] to INTEGER ** <tr><td> BLOB <td> FLOAT <td> [CAST] to REAL | | | 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 | ** <tr><td> FLOAT <td> TEXT <td> ASCII rendering of the float ** <tr><td> FLOAT <td> BLOB <td> [CAST] to BLOB ** <tr><td> TEXT <td> INTEGER <td> [CAST] to INTEGER ** <tr><td> TEXT <td> FLOAT <td> [CAST] to REAL ** <tr><td> TEXT <td> BLOB <td> No change ** <tr><td> BLOB <td> INTEGER <td> [CAST] to INTEGER ** <tr><td> BLOB <td> FLOAT <td> [CAST] to REAL ** <tr><td> BLOB <td> TEXT <td> Add a zero terminator if needed ** </table> ** </blockquote>)^ ** ** Note that when type conversions occur, pointers returned by prior ** calls to sqlite3_column_blob(), sqlite3_column_text(), and/or ** sqlite3_column_text16() may be invalidated. ** Type conversions and pointer invalidations might occur |
︙ | ︙ | |||
5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 | ** 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 | > > | 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 | ** 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} ** KEYWORDS: {application-defined SQL function} ** KEYWORDS: {application-defined SQL functions} ** 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 |
︙ | ︙ | |||
5273 5274 5275 5276 5277 5278 5279 | ** 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. ** | < < < < < < < < < < < < < < < | 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 | ** 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 ** aggregate. ^A scalar SQL function requires an implementation of the xFunc |
︙ | ︙ | |||
5404 5405 5406 5407 5408 5409 5410 | /* ** 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()]. | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 | /* ** 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()]. */ #define SQLITE_DETERMINISTIC 0x000000800 #define SQLITE_DIRECTONLY 0x000080000 /* ** CAPI3REF: Deprecated Functions ** DEPRECATED ** ** These functions are [deprecated]. In order to maintain ** backwards compatibility with older code, these functions continue |
︙ | ︙ | |||
5535 5536 5537 5538 5539 5540 5541 | ** <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 | | | | 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 | ** <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 implementation of ** [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 |
︙ | ︙ | |||
5593 5594 5595 5596 5597 5598 5599 | ** 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, | | | 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 | ** 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, ** and 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()]. ** |
︙ | ︙ | |||
5642 5643 5644 5645 5646 5647 5648 | 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*); | < < < < < < < < < < < < < < < < < < < < < < | < | | | | | 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 | 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 ** information can be used to pass a limited amount of context from ** one SQL function to another. Use the [sqlite3_result_subtype()] ** routine to set the subtype for the return value of an SQL function. */ unsigned int sqlite3_value_subtype(sqlite3_value*); /* ** CAPI3REF: Copy And Free SQL Values ** METHOD: sqlite3_value ** ** ^The sqlite3_value_dup(V) interface makes a copy of the [sqlite3_value] ** object D and returns a pointer to that copy. ^The [sqlite3_value] returned ** is a [protected sqlite3_value] object even if the input is not. ** ^The sqlite3_value_dup(V) interface returns NULL if V is NULL or if a ** memory allocation fails. ** ** ^The sqlite3_value_free(V) interface frees an [sqlite3_value] object ** previously obtained from [sqlite3_value_dup()]. ^If V is a NULL pointer ** then sqlite3_value_free(V) is a harmless no-op. */ sqlite3_value *sqlite3_value_dup(const sqlite3_value*); void sqlite3_value_free(sqlite3_value*); /* ** 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 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 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. |
︙ | ︙ | |||
5877 5878 5879 5880 5881 5882 5883 | ** ** ^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 | | < | | 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 | ** ** ^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 in native ** byte order. ^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 |
︙ | ︙ | |||
5921 5922 5923 5924 5925 5926 5927 | ** UTF-16 little endian, or UTF-16 big endian, respectively. ** ^The sqlite3_result_text64() interface sets the return value of an ** application-defined function to be a text string in an encoding ** specified by the fifth (and last) parameter, which must be one ** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]. ** ^SQLite takes the text result from the application from ** the 2nd parameter of the sqlite3_result_text* interfaces. | | | < | | 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 | ** UTF-16 little endian, or UTF-16 big endian, respectively. ** ^The sqlite3_result_text64() interface sets the return value of an ** application-defined function to be a text string in an encoding ** specified by the fifth (and last) parameter, which must be one ** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]. ** ^SQLite takes the text result from the application from ** the 2nd parameter of the sqlite3_result_text* interfaces. ** ^If the 3rd parameter to the sqlite3_result_text* interfaces ** is negative, then SQLite takes result text from the 2nd parameter ** through the first zero character. ** ^If the 3rd parameter to the sqlite3_result_text* interfaces ** is non-negative, then as many bytes (not characters) of the text ** pointed to by the 2nd parameter are taken as the application-defined ** function result. If the 3rd parameter is non-negative, then it ** must be the byte offset into the string where the NUL terminator would ** appear if the string where NUL terminated. If any NUL characters occur ** in the string at a byte offset that is less than the value of the 3rd |
︙ | ︙ | |||
5948 5949 5950 5951 5952 5953 5954 | ** 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. ** | < < < < < < < < < < < < < < < < < < < | 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 | ** 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. ** ^A [protected sqlite3_value] object may always be used where an |
︙ | ︙ | |||
6052 6053 6054 6055 6056 6057 6058 | ** <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 | | | | | < | | | 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 | ** <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, xCallback. ** ^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, xCallback, 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 xCallback 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 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 |
︙ | ︙ | |||
6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 | void(*)(void*,sqlite3*,int eTextRep,const char*) ); 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( | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | void(*)(void*,sqlite3*,int eTextRep,const char*) ); int sqlite3_collation_needed16( sqlite3*, void*, void(*)(void*,sqlite3*,int eTextRep,const void*) ); #ifdef SQLITE_HAS_CODEC /* ** Specify the key for an encrypted database. This routine should be ** called right after sqlite3_open(). ** ** The code to implement this API is not available in the public release ** of SQLite. */ int sqlite3_key( sqlite3 *db, /* Database to be rekeyed */ const void *pKey, int nKey /* The key */ ); int sqlite3_key_v2( sqlite3 *db, /* Database to be rekeyed */ const char *zDbName, /* Name of the database */ const void *pKey, int nKey /* The key */ ); /* ** Change the key on an open database. If the current database is not ** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the ** database is decrypted. ** ** The code to implement this API is not available in the public release ** of SQLite. */ int sqlite3_rekey( sqlite3 *db, /* Database to be rekeyed */ const void *pKey, int nKey /* The new key */ ); int sqlite3_rekey_v2( sqlite3 *db, /* Database to be rekeyed */ const char *zDbName, /* Name of the database */ const void *pKey, int nKey /* The new key */ ); /* ** Specify the activation key for a SEE database. Unless ** activated, none of the SEE routines will work. */ void sqlite3_activate_see( const char *zPassPhrase /* Activation phrase */ ); #endif #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( |
︙ | ︙ | |||
6368 6369 6370 6371 6372 6373 6374 | ** returned by sqlite3_db_handle is the same [database connection] ** that was the first argument ** to the [sqlite3_prepare_v2()] call (or its variants) that was used to ** create the statement in the first place. */ sqlite3 *sqlite3_db_handle(sqlite3_stmt*); | < < < < < < < < < < < < < < < < < < < < < < | | | < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | ** returned by sqlite3_db_handle is the same [database connection] ** that was the first argument ** to the [sqlite3_prepare_v2()] call (or its variants) that was used to ** create the statement in the first place. */ 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 a filename ** associated with database N of connection D. ^The main database file ** has the name "main". 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 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. */ 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: 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 |
︙ | ︙ | |||
6548 6549 6550 6551 6552 6553 6554 | ** ^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*); | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 | ** ^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 |
︙ | ︙ | |||
6639 6640 6641 6642 6643 6644 6645 | ** 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 | | | 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 | ** 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_master and 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 |
︙ | ︙ | |||
6678 6679 6680 6681 6682 6683 6684 | ** CAPI3REF: Enable Or Disable Shared Pager Cache ** ** ^(This routine enables or disables the sharing of the database cache ** and schema data structures between [database connection | connections] ** to the same database. Sharing is enabled if the argument is true ** and disabled if the argument is false.)^ ** | < < < < < | | | < | < < < | 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 | ** CAPI3REF: Enable Or Disable Shared Pager Cache ** ** ^(This routine enables or disables the sharing of the database cache ** and schema data structures between [database connection | connections] ** to the same database. Sharing is enabled if the argument is true ** and disabled if the argument is false.)^ ** ** ^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 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. But this might change in ** future releases of SQLite. Applications that care about shared ** cache setting should set it explicitly. ** ** 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 |
︙ | ︙ | |||
6749 6750 6751 6752 6753 6754 6755 | ** See also: [sqlite3_release_memory()] */ int sqlite3_db_release_memory(sqlite3*); /* ** CAPI3REF: Impose A Limit On Heap Size ** | < < < < < < < < < < | | | | | < < < | < < < < < < < < < < < | | > > > > > > > > > > > | < | 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 | ** 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. ** ** ^The return value from sqlite3_soft_heap_limit64() is the size of ** the soft 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 soft heap limit. Hence, the current ** size of the soft heap limit can be determined by invoking ** sqlite3_soft_heap_limit64() with a negative argument. ** ** ^If the argument N is zero then the soft heap limit is disabled. ** ** ^(The soft heap limit is not enforced in the current implementation ** if one or more of following conditions are true: ** ** <ul> ** <li> The soft heap limit 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>)^ ** ** Beginning with SQLite [version 3.7.3] ([dateof:3.7.3]), ** the soft heap limit is enforced ** regardless of whether or not the [SQLITE_ENABLE_MEMORY_MANAGEMENT] ** compile-time option is invoked. With [SQLITE_ENABLE_MEMORY_MANAGEMENT], ** the soft heap limit is enforced on every memory allocation. Without ** [SQLITE_ENABLE_MEMORY_MANAGEMENT], the soft heap limit is only enforced ** when memory is allocated by the page cache. Testing suggests that because ** the page cache is the predominate memory user in SQLite, most ** applications will achieve adequate soft heap limit enforcement without ** the use of [SQLITE_ENABLE_MEMORY_MANAGEMENT]. ** ** The circumstances under which SQLite will enforce the soft heap limit may ** changes in future releases of SQLite. */ sqlite3_int64 sqlite3_soft_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 |
︙ | ︙ | |||
6835 6836 6837 6838 6839 6840 6841 | ** ** ^(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 | | | 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 | ** ** ^(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 and 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. ** |
︙ | ︙ | |||
6977 6978 6979 6980 6981 6982 6983 | ** ** ^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 | | | 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 | ** ** ^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 disabled 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); /* |
︙ | ︙ | |||
7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 | ** CAPI3REF: Reset Automatic Extension Loading ** ** ^This interface disables all automatic extensions previously ** registered using [sqlite3_auto_extension()]. */ void sqlite3_reset_auto_extension(void); /* ** Structures used by the virtual table interface */ typedef struct sqlite3_vtab sqlite3_vtab; typedef struct sqlite3_index_info sqlite3_index_info; typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor; typedef struct sqlite3_module sqlite3_module; /* ** CAPI3REF: Virtual Table Object ** KEYWORDS: sqlite3_module {virtual table module} ** ** This structure, sometimes called a "virtual table module", | > > > > > > > > > | | 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 | ** CAPI3REF: Reset Automatic Extension Loading ** ** ^This interface disables all automatic extensions previously ** registered using [sqlite3_auto_extension()]. */ void sqlite3_reset_auto_extension(void); /* ** The interface to the virtual-table mechanism is currently considered ** to be experimental. The interface might change in incompatible ways. ** If this is a problem for you, do not use the interface at this time. ** ** When the virtual-table mechanism stabilizes, we will declare the ** interface fixed, support it indefinitely, and remove this comment. */ /* ** Structures used by the virtual table interface */ typedef struct sqlite3_vtab sqlite3_vtab; typedef struct sqlite3_index_info sqlite3_index_info; typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor; 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 tables]. ** 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 |
︙ | ︙ | |||
7152 7153 7154 7155 7156 7157 7158 | ** 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 | | < < < < < < | | | | 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 | ** 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 is not checked again by SQLite.)^ ** ** ^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 ** the correct order to satisfy the ORDER BY clause so that no separate ** sorting step is required. ** ** ^The estimatedCost value is an estimate of the cost of a particular ** strategy. A cost of N indicates that the cost of the strategy is similar |
︙ | ︙ | |||
7198 7199 7200 7201 7202 7203 7204 | ** 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 | | | 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 | ** 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 included crashing the application). The estimatedRows field should ** therefore only be used if [sqlite3_libversion_number()] returns a ** value greater than or equal to 3008002. Similarly, the idxFlags field ** was added for [version 3.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. */ |
︙ | ︙ | |||
7250 7251 7252 7253 7254 7255 7256 | ** these bits. */ #define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */ /* ** CAPI3REF: Virtual Table Constraint Operator Codes ** | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | | | | | | | | < < | 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 | ** these bits. */ #define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */ /* ** CAPI3REF: Virtual Table Constraint Operator Codes ** ** These macros defined the allowed values for the ** [sqlite3_index_info].aConstraint[].op field. Each value represents ** an operator that is part of a constraint term in the wHERE clause of ** a query that uses a [virtual table]. */ #define SQLITE_INDEX_CONSTRAINT_EQ 2 #define SQLITE_INDEX_CONSTRAINT_GT 4 #define SQLITE_INDEX_CONSTRAINT_LE 8 #define SQLITE_INDEX_CONSTRAINT_LT 16 #define SQLITE_INDEX_CONSTRAINT_GE 32 #define SQLITE_INDEX_CONSTRAINT_MATCH 64 #define SQLITE_INDEX_CONSTRAINT_LIKE 65 #define SQLITE_INDEX_CONSTRAINT_GLOB 66 #define SQLITE_INDEX_CONSTRAINT_REGEXP 67 #define SQLITE_INDEX_CONSTRAINT_NE 68 #define SQLITE_INDEX_CONSTRAINT_ISNOT 69 #define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70 #define SQLITE_INDEX_CONSTRAINT_ISNULL 71 #define SQLITE_INDEX_CONSTRAINT_IS 72 #define SQLITE_INDEX_CONSTRAINT_FUNCTION 150 /* ** CAPI3REF: Register A Virtual Table Implementation ** METHOD: sqlite3 ** ** ^These routines are used to register a new [virtual table module] name. ** ^Module names must be registered before |
︙ | ︙ | |||
7328 7329 7330 7331 7332 7333 7334 | ** 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. | < < < < < < < < < < < < < < < < < < < < < < < | 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 | ** 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 ** of the [virtual table]. Each subclass will |
︙ | ︙ | |||
7441 7442 7443 7444 7445 7446 7447 7448 7449 7450 7451 7452 7453 7454 | ** before this API is called, a new function is created.)^ ^The implementation ** of the new function always causes an exception to be thrown. So ** the new function is not good for anything by itself. Its only ** purpose is to be a placeholder function that can be overloaded ** by a [virtual table]. */ int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg); /* ** CAPI3REF: A Handle To An Open BLOB ** KEYWORDS: {BLOB handle} {BLOB handles} ** ** An instance of this object represents an open BLOB on which ** [sqlite3_blob_open | incremental BLOB I/O] can be performed. | > > > > > > > > > > | 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 | ** before this API is called, a new function is created.)^ ^The implementation ** of the new function always causes an exception to be thrown. So ** the new function is not good for anything by itself. Its only ** purpose is to be a placeholder function that can be overloaded ** by a [virtual table]. */ int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg); /* ** The interface to the virtual-table mechanism defined above (back up ** to a comment remarkably similar to this one) is currently considered ** to be experimental. The interface might change in incompatible ways. ** If this is a problem for you, do not use the interface at this time. ** ** When the virtual-table mechanism stabilizes, we will declare the ** interface fixed, support it indefinitely, and remove this comment. */ /* ** CAPI3REF: A Handle To An Open BLOB ** KEYWORDS: {BLOB handle} {BLOB handles} ** ** An instance of this object represents an open BLOB on which ** [sqlite3_blob_open | incremental BLOB I/O] can be performed. |
︙ | ︙ | |||
7759 7760 7761 7762 7763 7764 7765 | ** 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 | | | 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 | ** 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_MASTER ** <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 |
︙ | ︙ | |||
7882 7883 7884 7885 7886 7887 7888 | ** <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 | | | 7112 7113 7114 7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 | ** <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 |
︙ | ︙ | |||
7961 7962 7963 7964 7965 7966 7967 | ** ** 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 | | < < < < | 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 | ** ** 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_MASTER 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 */ /* ** 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 |
︙ | ︙ | |||
8068 8069 8070 8071 8072 8073 8074 | ** 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 | | | < < < < < < < | | 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 | ** 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 #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 #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_LAST 26 /* 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, |
︙ | ︙ | |||
8363 8364 8365 8366 8367 8368 8369 | ** 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 | | | 7582 7583 7584 7585 7586 7587 7588 7589 7590 7591 7592 7593 7594 7595 7596 | ** 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 [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> |
︙ | ︙ | |||
8439 8440 8441 8442 8443 8444 8445 | ** ** <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> | | | 7658 7659 7660 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 | ** ** <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 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 |
︙ | ︙ | |||
8521 8522 8523 8524 8525 8526 8527 | ** ** [[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 | | | 7740 7741 7742 7743 7744 7745 7746 7747 7748 7749 7750 7751 7752 7753 7754 | ** ** [[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 resolve 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> |
︙ | ︙ | |||
8610 8611 8612 8613 8614 8615 8616 | ** 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 | | < < < < < < < < < < < < | 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 | ** 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 change 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 ** cycle. ** ** [[SQLITE_STMTSTATUS_MEMUSED]] <dt>SQLITE_STMTSTATUS_MEMUSED</dt> ** <dd>^This is the approximate number of bytes of heap memory ** used to store the prepared statement. ^This value is not actually ** a counter, and so the resetFlg parameter to sqlite3_stmt_status() ** is ignored when the opcode is SQLITE_STMTSTATUS_MEMUSED. ** </dd> ** </dl> */ #define SQLITE_STMTSTATUS_FULLSCAN_STEP 1 #define SQLITE_STMTSTATUS_SORT 2 #define SQLITE_STMTSTATUS_AUTOINDEX 3 #define SQLITE_STMTSTATUS_VM_STEP 4 #define SQLITE_STMTSTATUS_REPREPARE 5 #define SQLITE_STMTSTATUS_RUN 6 #define SQLITE_STMTSTATUS_MEMUSED 99 /* ** CAPI3REF: Custom Page Cache Object ** ** The sqlite3_pcache type is opaque. It is implemented by ** the pluggable module. The SQLite core has no knowledge of |
︙ | ︙ | |||
8793 8794 8795 8796 8797 8798 8799 | ** 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 | | | 8000 8001 8002 8003 8004 8005 8006 8007 8008 8009 8010 8011 8012 8013 8014 | ** 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 to 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. |
︙ | ︙ | |||
9057 9058 9059 9060 9061 9062 9063 | ** However, the application must guarantee that the destination ** [database connection] is not passed to any other API (by any thread) after ** sqlite3_backup_init() is called and before the corresponding call to ** sqlite3_backup_finish(). SQLite does not currently check to see ** if the application incorrectly accesses the destination [database connection] ** and so no error code is reported, but the operations may malfunction ** nevertheless. Use of the destination database connection while a | | | 8264 8265 8266 8267 8268 8269 8270 8271 8272 8273 8274 8275 8276 8277 8278 | ** However, the application must guarantee that the destination ** [database connection] is not passed to any other API (by any thread) after ** sqlite3_backup_init() is called and before the corresponding call to ** sqlite3_backup_finish(). SQLite does not currently check to see ** if the application incorrectly accesses the destination [database connection] ** and so no error code is reported, but the operations may malfunction ** nevertheless. Use of the destination database connection while a ** backup is in progress might also also cause a mutex deadlock. ** ** If running in [shared cache mode], the application must ** guarantee that the shared cache used by the destination database ** is not accessed while the backup is running. In practice this means ** that the application must guarantee that the disk file being ** backed up to is not accessed by any connection within the process, ** not just the specific connection that was passed to sqlite3_backup_init(). |
︙ | ︙ | |||
9111 9112 9113 9114 9115 9116 9117 | ** 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] | | | 8318 8319 8320 8321 8322 8323 8324 8325 8326 8327 8328 8329 8330 8331 8332 | ** 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 connections 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().)^ ** |
︙ | ︙ | |||
9149 9150 9151 9152 9153 9154 9155 | ** 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. ** | | | 8356 8357 8358 8359 8360 8361 8362 8363 8364 8365 8366 8367 8368 8369 8370 | ** 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 connections 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. |
︙ | ︙ | |||
9309 9310 9311 9312 9313 9314 9315 | ** 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 | | < | | 8516 8517 8518 8519 8520 8521 8522 8523 8524 8525 8526 8527 8528 8529 8530 8531 | ** 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. ^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* |
︙ | ︙ | |||
9485 9486 9487 9488 9489 9490 9491 | ** These constants define all valid values for the "checkpoint mode" passed ** as the third parameter to the [sqlite3_wal_checkpoint_v2()] interface. ** See the [sqlite3_wal_checkpoint_v2()] documentation for details on the ** meaning of each of these checkpoint modes. */ #define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */ #define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */ | | | | < < < < | < < | | 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 | ** These constants define all valid values for the "checkpoint mode" passed ** as the third parameter to the [sqlite3_wal_checkpoint_v2()] interface. ** See the [sqlite3_wal_checkpoint_v2()] documentation for details on the ** meaning of each of these checkpoint modes. */ #define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */ #define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */ #define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for for readers */ #define SQLITE_CHECKPOINT_TRUNCATE 3 /* Like RESTART but also truncate WAL */ /* ** CAPI3REF: Virtual Table Interface Configuration ** ** 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. ** ** At present, there is only one option that may be configured using ** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].) Further options ** may be added in the future. */ int sqlite3_vtab_config(sqlite3*, int op, ...); /* ** CAPI3REF: Virtual Table Configuration Options ** ** 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 ** <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 |
︙ | ︙ | |||
9548 9549 9550 9551 9552 9553 9554 | ** 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. | < < < < < < < < < < < < < < < < < < < < < < | | < | < < < < < < < | < < | | | | < < < < < < < < < < | < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 8748 8749 8750 8751 8752 8753 8754 8755 8756 8757 8758 8759 8760 8761 8762 8763 8764 8765 8766 8767 8768 8769 8770 8771 8772 8773 8774 8775 8776 8777 8778 8779 8780 8781 8782 8783 8784 8785 8786 8787 8788 8789 8790 8791 8792 8793 8794 8795 8796 8797 8798 8799 8800 8801 8802 8803 8804 8805 8806 8807 8808 8809 8810 | ** 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] ** method of a [virtual table], then it returns true if and only if the ** column is being fetched as part of an UPDATE operation during which the ** column value will not change. Applications might use this to substitute ** a 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. */ int sqlite3_vtab_nochange(sqlite3_context*); /* ** CAPI3REF: Determine The Collation For a Virtual Table Constraint ** ** This function may only be called from within a call to the [xBestIndex] ** method of a [virtual table]. ** ** The first argument must be the sqlite3_index_info object that is the ** first parameter to the xBestIndex() method. The second argument must be ** an index into the aConstraint[] array belonging to the sqlite3_index_info ** structure passed to xBestIndex. This function returns a pointer to a buffer ** containing the name of the collation sequence for the corresponding ** constraint. */ SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int); /* ** CAPI3REF: Conflict resolution modes ** KEYWORDS: {conflict resolution mode} ** ** These constants are returned by [sqlite3_vtab_on_conflict()] to ** inform a [virtual table] implementation what the [ON CONFLICT] mode |
︙ | ︙ | |||
9913 9914 9915 9916 9917 9918 9919 | ** [sqlite3_stmt_scanstatus(S,X,T,V)] interface. Each constant designates a ** different metric for sqlite3_stmt_scanstatus() to return. ** ** 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. ** | < < < < | | | | | | | | > | | < < < < < < < < < < < < < < < | | > | < < < < < < < < < < < | | < | | | > > > > > < < < < < < < < < < < < < < | 8828 8829 8830 8831 8832 8833 8834 8835 8836 8837 8838 8839 8840 8841 8842 8843 8844 8845 8846 8847 8848 8849 8850 8851 8852 8853 8854 8855 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 | ** [sqlite3_stmt_scanstatus(S,X,T,V)] interface. Each constant designates a ** different metric for sqlite3_stmt_scanstatus() to return. ** ** 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 T 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 T 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 T 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 T 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 T 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 T 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 #define SQLITE_SCANSTAT_NVISIT 1 #define SQLITE_SCANSTAT_EST 2 #define SQLITE_SCANSTAT_NAME 3 #define SQLITE_SCANSTAT_EXPLAIN 4 #define SQLITE_SCANSTAT_SELECTID 5 /* ** CAPI3REF: Prepared Statement Scan Status ** METHOD: sqlite3_stmt ** ** This interface returns information about the predicted and measured ** performance for pStmt. Advanced applications can use this ** interface to compare the predicted and the measured performance and ** issue warnings and/or rerun [ANALYZE] if discrepancies are found. ** ** Since this interface is expected to be rarely used, it is only ** available if SQLite is compiled using the [SQLITE_ENABLE_STMT_SCANSTATUS] ** compile-time option. ** ** The "iScanStatusOp" parameter determines which status information to return. ** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior ** of this interface is undefined. ** ^The requested measurement is written into a variable pointed to by ** the "pOut" parameter. ** Parameter "idx" identifies the specific loop to retrieve statistics for. ** Loops are numbered starting from zero. ^If idx is out of range - less than ** zero or greater than or equal to the total number of loops used to implement ** the statement - a non-zero value is returned and the variable that pOut ** points to is unchanged. ** ** ^Statistics might not be available for all loops in all statements. ^In cases ** where there exist loops with no available statistics, this function behaves ** as if the loop did not exist - it returns non-zero and leave the variable ** that pOut points to unchanged. ** ** See also: [sqlite3_stmt_scanstatus_reset()] */ int sqlite3_stmt_scanstatus( sqlite3_stmt *pStmt, /* Prepared statement for which info desired */ int idx, /* Index of loop to report on */ int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */ void *pOut /* Result written here */ ); /* ** CAPI3REF: Zero Scan-Status Counters ** METHOD: sqlite3_stmt ** ** ^Zero all [sqlite3_stmt_scanstatus()] related event counters. ** ** 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)] |
︙ | ︙ | |||
10076 10077 10078 10079 10080 10081 10082 | ** ^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. | < | | 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 | ** ^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 ** system tables like sqlite_master 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 |
︙ | ︙ | |||
10117 10118 10119 10120 10121 10122 10123 | ** 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 | | < < < < | 8993 8994 8995 8996 8997 8998 8999 9000 9001 9002 9003 9004 9005 9006 9007 | ** 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 ** INSERT 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 |
︙ | ︙ | |||
10159 10160 10161 10162 10163 10164 10165 | ** ** ^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. ** | < < < < < < < < < < < | 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 | ** ** ^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. |
︙ | ︙ | |||
10427 10428 10429 10430 10431 10432 10433 | ** 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. ** | | | | 9288 9289 9290 9291 9292 9293 9294 9295 9296 9297 9298 9299 9300 9301 9302 9303 | ** 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 only available if SQLite is compiled with the ** [SQLITE_ENABLE_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 */ ); |
︙ | ︙ | |||
10475 10476 10477 10478 10479 10480 10481 | ** 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. ** | < < < < | | | 9336 9337 9338 9339 9340 9341 9342 9343 9344 9345 9346 9347 9348 9349 9350 9351 9352 9353 9354 9355 | ** 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. ** ** This interface is only available if SQLite is compiled with the ** [SQLITE_ENABLE_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[] */ |
︙ | ︙ | |||
10528 10529 10530 10531 10532 10533 10534 | ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. */ #ifdef SQLITE_OMIT_FLOATING_POINT # undef double #endif | < < < < < < < < < < < < < | 9385 9386 9387 9388 9389 9390 9391 9392 9393 9394 9395 | ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. */ #ifdef SQLITE_OMIT_FLOATING_POINT # undef double #endif #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif #endif /* SQLITE3_H */ |
Changes to src/sqlite3ext.h.
︙ | ︙ | |||
318 319 320 321 322 323 324 | 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*); | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 318 319 320 321 322 323 324 325 326 327 328 329 330 331 | 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*); }; /* ** 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)( |
︙ | ︙ | |||
647 648 649 650 651 652 653 | #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 */ | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 | #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->isexplain #define sqlite3_value_frombind sqlite3_api->frombind #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 | #endif #if defined(_MSC_VER) && !defined(SQLITE_DISABLE_INTRINSIC) # define MSVC_VERSION _MSC_VER #else # define MSVC_VERSION 0 #endif | < < < < < < < < < < < < < < < < < < < < < | 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 |
︙ | ︙ | |||
177 178 179 180 181 182 183 | #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 | < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < | 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 | #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" /* ** 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 #include "sqliteLimit.h" /* Disable nuisance warnings on Borland compilers */ #if defined(__BORLANDC__) #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 |
︙ | ︙ | |||
262 263 264 265 266 267 268 | ** 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. */ | < < < | > > > | 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | ** 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(__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)) #elif 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)) #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 |
︙ | ︙ | |||
436 437 438 439 440 441 442 443 | ** 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. */ | > | < | < | | 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 | ** 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. ** */ #ifdef SQLITE_COVERAGE_TEST void sqlite3Coverage(int); # define testcase(X) if( X ){ sqlite3Coverage(__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 |
︙ | ︙ | |||
471 472 473 474 475 476 477 | */ #ifndef NDEBUG # define VVA_ONLY(X) X #else # define VVA_ONLY(X) #endif | < < < < < < < < | | 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 | */ #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. */ #if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST) # 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) |
︙ | ︙ | |||
568 569 570 571 572 573 574 | /* ** SQLITE_ENABLE_EXPLAIN_COMMENTS is incompatible with SQLITE_OMIT_EXPLAIN */ #ifdef SQLITE_OMIT_EXPLAIN # undef SQLITE_ENABLE_EXPLAIN_COMMENTS #endif | < < < < < < < | 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) |
︙ | ︙ | |||
696 697 698 699 700 701 702 | /* ** 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. ** | | | 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 | /* ** 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 choosen 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 /* |
︙ | ︙ | |||
815 816 817 818 819 820 821 | ** is 0x00000000ffffffff. But because of quirks of some compilers, we ** have to specify the value in the less intuitive manner shown: */ #define SQLITE_MAX_U32 ((((u64)1)<<32)-1) /* ** The datatype used to store estimates of the number of rows in a | | > > > | > > > | 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 | ** is 0x00000000ffffffff. But because of quirks of some compilers, we ** have to specify the value in the less intuitive manner shown: */ #define SQLITE_MAX_U32 ((((u64)1)<<32)-1) /* ** The datatype used to store estimates of the number of rows in a ** table or index. This is an unsigned integer type. For 99.9% of ** the world, a 32-bit integer is sufficient. But a 64-bit integer ** can be used at compile-time if desired. */ #ifdef SQLITE_64BIT_STATS typedef u64 tRowcnt; /* 64-bit only if requested at compile-time */ #else typedef u32 tRowcnt; /* 32-bit is the default */ #endif /* ** Estimated quantities used for query planning are stored as 16-bit ** logarithms. For quantity X, the value stored is 10*log2(X). This ** gives a possible range of values of approximately 1.0e986 to 1e-986. ** But the allowed values are "grainy". Not every value is representable. ** For example, quantities 16 and 17 are both represented by a LogEst |
︙ | ︙ | |||
852 853 854 855 856 857 858 | ** 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) || \ | < | 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 |
︙ | ︙ | |||
891 892 893 894 895 896 897 | ** ** 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 | | | | | | < | 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 | ** ** 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(__arm__) || defined(_M_ARM64) # define SQLITE_BYTEORDER 1234 # elif defined(sparc) || defined(__ppc__) # define SQLITE_BYTEORDER 4321 # else # define SQLITE_BYTEORDER 0 # endif #endif #if SQLITE_BYTEORDER==4321 # define SQLITE_BIGENDIAN 1 |
︙ | ︙ | |||
928 929 930 931 932 933 934 | /* ** 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)) | < < < < < < < < < < < < | | | 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 | /* ** 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) /* ** Round down to the nearest multiple of 8 */ #define ROUNDDOWN8(x) ((x)&~7) /* ** Assert that the pointer X is aligned to an 8-byte boundary. This ** macro is used only within assert() to verify that the code gets ** all alignment restrictions correct. ** ** Except, if SQLITE_4_BYTE_ALIGNED_MALLOC is defined, then the ** underlying malloc() implementation might return us 4-byte aligned ** pointers. In that case, only verify 4-byte alignment. */ #ifdef SQLITE_4_BYTE_ALIGNED_MALLOC # define EIGHT_BYTE_ALIGNMENT(X) ((((char*)(X) - (char*)0)&3)==0) #else # define EIGHT_BYTE_ALIGNMENT(X) ((((char*)(X) - (char*)0)&7)==0) #endif /* ** Disable MMAP on platforms where it is known to not work */ #if defined(__OpenBSD__) || defined(__QNXNTO__) # undef SQLITE_MAX_MMAP_SIZE |
︙ | ︙ | |||
1009 1010 1011 1012 1013 1014 1015 | #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 /* | | | > < < < | | | | | < < < | < | < < < < < < < < < < < < < < < < < < < < < < < | > < | < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > | < < | < < < < < < < < < < < | | < < < | | | | < | | 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 | #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 /* ** Only one of SQLITE_ENABLE_STAT3 or SQLITE_ENABLE_STAT4 can be defined. ** Priority is given to SQLITE_ENABLE_STAT4. If either are defined, also ** define SQLITE_ENABLE_STAT3_OR_STAT4 */ #ifdef SQLITE_ENABLE_STAT4 # undef SQLITE_ENABLE_STAT3 # define SQLITE_ENABLE_STAT3_OR_STAT4 1 #elif SQLITE_ENABLE_STAT3 # define SQLITE_ENABLE_STAT3_OR_STAT4 1 #elif SQLITE_ENABLE_STAT3_OR_STAT4 # undef SQLITE_ENABLE_STAT3_OR_STAT4 #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_ENABLE_SELECTTRACE) # define SELECTTRACE_ENABLED 1 #else # define SELECTTRACE_ENABLED 0 #endif /* ** An instance of the following structure is used to store the busy-handler ** callback for a given sqlite handle. ** ** The sqlite.busyHandler member of the sqlite struct contains the busy ** callback for the database handle. Each pager opened via the sqlite ** 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 */ u8 bExtraFileArg; /* Include sqlite3_file as callback arg */ }; /* ** Name of the master database table. The master database table ** is a special table that holds the names and attributes of all ** user tables and indices. */ #define MASTER_NAME "sqlite_master" #define TEMP_MASTER_NAME "sqlite_temp_master" /* ** The root-page of the master database table. */ #define MASTER_ROOT 1 /* ** The name of the schema table. */ #define SCHEMA_TABLE(x) ((!OMIT_TEMPDB)&&(x==1)?TEMP_MASTER_NAME:MASTER_NAME) /* ** 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)sqlite3MallocSize) /* ** 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 |
︙ | ︙ | |||
1219 1220 1221 1222 1223 1224 1225 | */ typedef struct AggInfo AggInfo; typedef struct AuthContext AuthContext; typedef struct AutoincInfo AutoincInfo; typedef struct Bitvec Bitvec; typedef struct CollSeq CollSeq; typedef struct Column Column; | < < < < < < < | 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 | */ 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 IndexedExpr IndexedExpr; 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; |
︙ | ︙ | |||
1293 1294 1295 1296 1297 1298 1299 | ** The number of bits in a Bitmask. "BMS" means "BitMask Size". */ #define BMS ((int)(sizeof(Bitmask)*8)) /* ** A bit in a Bitmask */ | | < | < | | | | | | | 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 | ** The number of bits in a Bitmask. "BMS" means "BitMask Size". */ #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) #define TOPBIT (((Bitmask)1)<<(BMS-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 "btree.h" #include "vdbe.h" #include "pager.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. */ #ifdef SQLITE_EXTRA_DURABLE # warning Use SQLITE_DEFAULT_SYNCHRONOUS=3 instead of SQLITE_EXTRA_DURABLE |
︙ | ︙ | |||
1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 | ** ** 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) | > | 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 | ** ** 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_Empty 0x0004 /* The file is empty (length 0 bytes) */ #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) |
︙ | ︙ | |||
1445 1446 1447 1448 1449 1450 1451 | ** ** 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. | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | ** ** 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() ** macro to compute a hash on the function name. |
︙ | ︙ | |||
1569 1570 1571 1572 1573 1574 1575 | #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 */ | < < < < < | < | < > | | | | < < | < | < < < | 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 | #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 */ CollSeq *pDfltColl; /* The default collating sequence (BINARY) */ 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 */ u16 dbOptFlags; /* Flags to enable/disable optimizations */ u8 enc; /* Text encoding */ u8 autoCommit; /* The auto-commit flag. */ u8 temp_store; /* 1: file 2: memory 0: default */ u8 mallocFailed; /* True if we have seen a malloc failure */ 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 */ int nextPagesize; /* Pagesize after VACUUM if >0 */ u32 magic; /* Magic number for detect library misuse */ int nChange; /* Value returned by sqlite3_changes() */ int 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 */ int 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 */ 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 */ int (*xTrace)(u32,void*,void*,void*); /* Trace function */ 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); 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 */ |
︙ | ︙ | |||
1691 1692 1693 1694 1695 1696 1697 | 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 */ | < | | 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 | 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 /* The following variables are all protected by the STATIC_MASTER ** 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 |
︙ | ︙ | |||
1726 1727 1728 1729 1730 1731 1732 | /* ** A macro to discover the encoding of a database. */ #define SCHEMA_ENC(db) ((db)->aDb[0].pSchema->enc) #define ENC(db) ((db)->enc) | < < < < < < < | | > | | 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 | /* ** A macro to discover the encoding of a database. */ #define SCHEMA_ENC(db) ((db)->aDb[0].pSchema->enc) #define ENC(db) ((db)->enc) /* ** 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_MASTER */ #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_CountRows 0x00000080 /* Count rows changed by INSERT, */ /* DELETE, or UPDATE and return */ /* the count using a callback. */ #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 */ |
︙ | ︙ | |||
1772 1773 1774 1775 1776 1777 1778 | #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 */ | < < < < < < < > | | | | | | < < | | | | | | | | | | | | | | | | | < < < < < < < < < < < < | > | | < > | | | | | | | 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 | #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 */ #define HI(X) ((u64)(X)<<32) #ifdef SQLITE_DEBUG #define SQLITE_SqlTrace HI(0x0001) /* Debug print SQL as it executes */ #define SQLITE_VdbeListing HI(0x0002) /* Debug listings of VDBE progs */ #define SQLITE_VdbeTrace HI(0x0004) /* True to trace VDBE execution */ #define SQLITE_VdbeAddopTrace HI(0x0008) /* Trace sqlite3VdbeAddOp() calls */ #define SQLITE_VdbeEQP HI(0x0010) /* Debug EXPLAIN QUERY PLAN */ #define SQLITE_ParserTrace HI(0x0020) /* 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 */ /* ** 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 0x0001 /* Query flattening */ #define SQLITE_WindowFunc 0x0002 /* Use xInverse for window functions */ #define SQLITE_GroupByOrder 0x0004 /* GROUPBY cover of ORDERBY */ #define SQLITE_FactorOutConst 0x0008 /* Constant factoring */ #define SQLITE_DistinctOpt 0x0010 /* DISTINCT using indexes */ #define SQLITE_CoverIdxScan 0x0020 /* Covering index scans */ #define SQLITE_OrderByIdxJoin 0x0040 /* ORDER BY of joins via index */ #define SQLITE_Transitive 0x0080 /* Transitive constraints */ #define SQLITE_OmitNoopJoin 0x0100 /* Omit unused tables in joins */ #define SQLITE_CountOfView 0x0200 /* The count-of-view optimization */ #define SQLITE_CursorHints 0x0400 /* Add OP_CursorHint opcodes */ #define SQLITE_Stat34 0x0800 /* Use STAT3 or STAT4 data */ /* TH3 expects the Stat34 ^^^^^^ value to be 0x0800. Don't change it */ #define SQLITE_PushDown 0x1000 /* The push-down optimization */ #define SQLITE_SimplifyJoin 0x2000 /* Convert LEFT JOIN to JOIN */ #define SQLITE_SkipScan 0x4000 /* Skip-scans */ #define SQLITE_PropagateConst 0x8000 /* The constant propagation opt */ #define SQLITE_AllOpts 0xffff /* 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 sqlite.magic field. ** The numbers are obtained at random and have no special meaning, other ** than being distinct from one another. */ #define SQLITE_MAGIC_OPEN 0xa029a697 /* Database is open */ #define SQLITE_MAGIC_CLOSED 0x9f3c2d33 /* Database is closed */ #define SQLITE_MAGIC_SICK 0x4b771290 /* Error and awaiting close */ #define SQLITE_MAGIC_BUSY 0xf03b7906 /* Database currently in use */ #define SQLITE_MAGIC_ERROR 0xb5357930 /* An SQLITE_MISUSE error occurred */ #define SQLITE_MAGIC_ZOMBIE 0x64cffc7f /* 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. |
︙ | ︙ | |||
1883 1884 1885 1886 1887 1888 1889 | 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 */ | | | 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 | 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; }; /* ** 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 |
︙ | ︙ | |||
1913 1914 1915 1916 1917 1918 1919 | /* ** 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()): | | < | | | < < < < < < < < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | | < < < < < < < < < < < < < < < < < < < | < | < | < | | > > > > > > | < | | 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 | /* ** 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_LENGTH == OPFLAG_LENGTHARG ** SQLITE_FUNC_TYPEOF == OPFLAG_TYPEOFARG ** SQLITE_FUNC_CONSTANT == SQLITE_DETERMINISTIC from the API ** 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 */ #define SQLITE_FUNC_COALESCE 0x0200 /* Built-in coalesce() or ifnull() */ #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_AFFINITY 0x4000 /* Built-in affinity() function */ #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 */ /* ** 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. ** ** 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. ** ** 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) ** Used to create an aggregate function definition implemented by ** the C functions xStep and xFinal. The first four parameters ** are interpreted in the same way as the first 4 parameters to ** FUNCTION(). ** ** WFUNCTION(zName, nArg, iArg, xStep, xFinal, xValue, xInverse) ** Used to create an aggregate function definition implemented by ** the C functions xStep and xFinal. The first four parameters ** are interpreted in the same way as the first 4 parameters to ** FUNCTION(). ** ** LIKEFUNC(zName, nArg, pArg, flags) ** Used to create a scalar function definition of a function zName ** 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_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_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} } #define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \ {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8, \ 0, 0, xFunc, 0, 0, 0, #zName, {0} } #define PURE_DATE(zName, nArg, iArg, bNC, xFunc) \ {nArg, 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_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_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ pArg, 0, xFunc, 0, 0, 0, #zName, } #define LIKEFUNC(zName, nArg, arg, flags) \ {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \ (void *)arg, 0, likeFunc, 0, 0, 0, #zName, {0} } #define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal, xValue) \ {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \ SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xValue,0,#zName, {0}} #define AGGREGATE2(zName, nArg, arg, nc, xStep, xFinal, extraFlags) \ {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|extraFlags, \ SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xFinal,0,#zName, {0}} #define WAGGREGATE(zName, nArg, arg, nc, xStep, xFinal, xValue, xInverse, f) \ {nArg, 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_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 |
︙ | ︙ | |||
2112 2113 2114 2115 2116 2117 2118 | ** 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() */ | < | | < < < < < < < < < < < < < < < < < < < < < | > > | < | | < < | < < < < < < < < < < < < < < < < | < < < < < | | | | < < < < < < < < | 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 | ** 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 */ }; /* ** information about each column of an SQL table is held in an instance ** of this structure. */ struct Column { char *zName; /* Name of this column, \000, then the type */ Expr *pDflt; /* Default value of this column */ char *zColl; /* Collating sequence. If NULL, use the default */ u8 notNull; /* An OE_ code for handling a NOT NULL constraint */ char affinity; /* One of the SQLITE_AFF_... values */ u8 szEst; /* Estimated size of value in this column. sizeof(INT)==1 */ u8 colFlags; /* Boolean properties. See COLFLAG_ defines below */ }; /* Allowed values for Column.colFlags: */ #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 */ /* ** 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 |
︙ | ︙ | |||
2229 2230 2231 2232 2233 2234 2235 | ** 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. */ | < | | | | | < > > | 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 | ** 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_BLOB 'A' #define SQLITE_AFF_TEXT 'B' #define SQLITE_AFF_NUMERIC 'C' #define SQLITE_AFF_INTEGER 'D' #define SQLITE_AFF_REAL '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_KEEPNULL 0x08 /* Used by vector == or <> */ #define SQLITE_JUMPIFNULL 0x10 /* jumps if either operand is NULL */ #define SQLITE_STOREP2 0x20 /* Store result in reg[P2] rather than jump */ #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. ** |
︙ | ︙ | |||
2306 2307 2308 2309 2310 2311 2312 | */ 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 */ | < < < < < < < | | > > | < | < < | < < < < < < | < > | | | < < > | > | < < < < < < | | | | | < < < | > > | < < | | | < < < < < < < < < < < < < | < < < | 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 | */ 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) */ }; /* ** The schema for each SQL 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. */ Select *pSelect; /* NULL for tables. Points to definition if a view. */ FKey *pFKey; /* Linked list of all foreign keys in 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 */ int 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 */ 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 */ #ifndef SQLITE_OMIT_ALTERTABLE int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */ #endif #ifndef SQLITE_OMIT_VIRTUALTABLE int nModuleArg; /* Number of arguments to the module */ char **azModuleArg; /* 0: module 1: schema 2: vtab name 3...: args */ VTable *pVTable; /* List of VTable objects. */ #endif Trigger *pTrigger; /* List of triggers stored in pSchema */ Schema *pSchema; /* Schema that contains this table */ Table *pNextZombie; /* Next on the Parse.pZombieTab list */ }; /* ** 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. */ #define TF_Readonly 0x0001 /* Read-only system table */ #define TF_Ephemeral 0x0002 /* An ephemeral table */ #define TF_HasPrimaryKey 0x0004 /* Table has a primary key */ #define TF_Autoincrement 0x0008 /* Integer primary key is autoincrement */ #define TF_HasStat1 0x0010 /* nRowLogEst set from sqlite_stat1 */ #define TF_WithoutRowid 0x0020 /* No rowid. PRIMARY KEY is the key */ #define TF_NoVisibleRowid 0x0040 /* No user-visible "rowid" column */ #define TF_OOOHidden 0x0080 /* Out-of-Order hidden columns */ #define TF_StatsUsed 0x0100 /* Query planner decisions affected by ** Index.aiRowLogEst[] values */ #define TF_HasNotNull 0x0200 /* Contains NOT NULL constraints */ #define TF_Shadow 0x0400 /* True for a shadow table */ #define TF_HasStat4 0x2000 /* STAT4 info available for this table */ /* ** 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)->nModuleArg) #else # define IsVirtual(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. |
︙ | ︙ | |||
2501 2502 2503 2504 2505 2506 2507 | ** 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. | < < | < | < < < | | 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 | ** 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. ** ** RESTRICT, SETNULL, 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. CASCADE means that a DELETE or UPDATE of the ** referenced table row is propagated into the row that holds the ** foreign key. ** ** The following symbolic values are used to record which type ** of 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 */ |
︙ | ︙ | |||
2547 2548 2549 2550 2551 2552 2553 | */ 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 */ | | < < < < < < | 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 | */ 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 *aSortOrder; /* Sort order for each column. */ CollSeq *aColl[1]; /* Collating sequence for each term of the key */ }; /* ** 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 |
︙ | ︙ | |||
2595 2596 2597 2598 2599 2600 2601 | ** before the first match or immediately after the last match. The ** eqSeen field will indicate whether or not an exact match exists in the ** b-tree. */ struct UnpackedRecord { KeyInfo *pKeyInfo; /* Collation and sort-order information */ Mem *aMem; /* Values */ | < < < < < | 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 | ** before the first match or immediately after the last match. The ** eqSeen field will indicate whether or not an exact match exists in the ** b-tree. */ struct UnpackedRecord { KeyInfo *pKeyInfo; /* Collation and sort-order information */ Mem *aMem; /* Values */ u16 nField; /* Number of entries in apMem[] */ i8 default_rc; /* Comparison result if keys are equal */ u8 errCode; /* Error detected by xRecordCompare (CORRUPT or NOMEM) */ i8 r1; /* Value to return if (lhs < rhs) */ i8 r2; /* Value to return if (lhs > rhs) */ u8 eqSeen; /* True if an equality comparison has been seen */ }; |
︙ | ︙ | |||
2631 2632 2633 2634 2635 2636 2637 | ** first column to be indexed (c3) has an index of 2 in Ex1.aCol[]. ** The second column to be indexed (c1) has an index of 0 in ** Ex1.aCol[], hence Ex2.aiColumn[1]==0. ** ** The Index.onError field determines whether or not the indexed columns ** 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 | | | < < < < < < < < < < < < | | < < | | | 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 | ** first column to be indexed (c3) has an index of 2 in Ex1.aCol[]. ** The second column to be indexed (c1) has an index of 0 in ** Ex1.aCol[], hence Ex2.aiColumn[1]==0. ** ** The Index.onError field determines whether or not the indexed columns ** 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_master ** 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 */ int 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 bHasExpr:1; /* Index contains an expression, either a literal ** expression, or a reference to a VIRTUAL column */ #ifdef SQLITE_ENABLE_STAT3_OR_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 */ |
︙ | ︙ | |||
2716 2717 2718 2719 2720 2721 2722 | /* 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 */ /* | | | 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 | /* The Index.aiColumn[] values are normally positive integer. But ** there are some negative values that have special meaning: */ #define XN_ROWID (-1) /* Indexed column is the rowid */ #define XN_EXPR (-2) /* Indexed column is an expression */ /* ** Each sample stored in the sqlite_stat3 table is represented in memory ** using a structure of this type. See documentation at the top of the ** analyze.c source file for additional information. */ struct IndexSample { void *p; /* Pointer to sampled record */ int n; /* Size of record in bytes */ tRowcnt *anEq; /* Est. number of rows where the key equals this sample */ |
︙ | ︙ | |||
2754 2755 2756 2757 2758 2759 2760 | }; /* ** 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 | | < > | < | | > > | > < < < < < < < < < < < < < < < < | | | | | | 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 | }; /* ** 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.iColumn 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 */ int iTable; /* Cursor number of the source table */ int iColumn; /* Column number within the source table */ int iSorterColumn; /* Column number in the sorting index */ int iMem; /* Memory location that acts as accumulator */ Expr *pExpr; /* The original expression */ } *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 *pExpr; /* 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 */ } *aFunc; int nFunc; /* Number of entries in aFunc[] */ }; /* ** 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 32767 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.token contains the text of the SQL literal. If ** the expression is a variable (TK_VARIABLE), then Expr.token contains the ** variable name. Finally, if the expression is an SQL function (TK_FUNCTION), ** then Expr.token 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 |
︙ | ︙ | |||
2877 2878 2879 2880 2881 2882 2883 | ** ** 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, | | < < < < < < | < | 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 | ** ** 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.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 affinity; /* The affinity of the column or 0 if not a column */ 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 |
︙ | ︙ | |||
2926 2927 2928 2929 2930 2931 2932 | #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 | < < < | | > | | > | | < | | > | < | | | | | | | | | > | | | < | | | | > | | | | | < < < < > | > | < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < | | | | | | | < < < < < < < | < | | | > | | < < < < < < | | < < < < < < < < < < < | < | < > < > > | | > > > | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | < < | > | | | 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 | #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[] */ i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */ u8 op2; /* TK_REGISTER: original value of Expr.op ** TK_COLUMN: the value of p5 for OP_Column ** TK_AGG_FUNCTION: nesting depth */ 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; /* TK_FUNCTION: Window definition for the func */ 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_Generic 0x000200 /* Ignore COLLATE or affinity on this tree */ #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 /* COLLATE, AS, or UNLIKELY */ #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_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */ #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 */ #define EP_Alias 0x400000 /* Is an alias for a result set column */ #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() */ /* ** 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) /* ** These 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) /* 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)->flags|=(P) #else # define ExprSetVVAProperty(E,P) #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 */ /* ** 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. ** ** By default the Expr.zSpan field holds a human-readable description of ** the expression that is used in the generation of error messages and ** column labels. In this case, Expr.zSpan is typically the text of a ** column expression as it exists in a SELECT statement. However, if ** the bSpanIsTab flag is set, then zSpan is overloaded to mean the name ** of the result column in the form: DATABASE.TABLE.COLUMN. This later ** form is used for name resolution with nested FROM clauses. */ struct ExprList { int nExpr; /* Number of expressions on the list */ struct ExprList_item { /* For each expression in the list */ Expr *pExpr; /* The parse tree for this expression */ char *zName; /* Token associated with this expression */ char *zSpan; /* Original text of the expression */ u8 sortOrder; /* 1 for DESC or 0 for ASC */ unsigned done :1; /* A flag to indicate when processing is finished */ unsigned bSpanIsTab :1; /* zSpan holds DB.TABLE.COLUMN */ unsigned reusable :1; /* Constant expression is reusable */ unsigned bSorterRef :1; /* Defer evaluation until after sorting */ union { struct { 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 */ } u; } a[1]; /* One slot for each expression in the list */ }; /* ** 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) ...; ** ** The IdList.a.idx field is used when the IdList represents the list of ** column names after a table name in an INSERT statement. In the statement ** ** INSERT INTO t(a,b,c) ... ** ** If "a" is the k-th column of table "t", then IdList.a[0].idx==k. */ struct IdList { 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 ** is modified by an INSERT, DELETE, or UPDATE statement. In standard SQL, ** such a table must be a simple name: ID. But in SQLite, the table can ** now be identified by a database name, a dot, then the table name: ID.ID. ** ** The jointype starts out showing the join type between the current table ** and the next table on the list. The parser builds the list this way. ** But sqlite3SrcListShiftJoinType() later shifts the jointypes so that each ** jointype expresses the join between the table and the previous table. ** ** 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 */ struct SrcList_item { 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 isCte :1; /* This is 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; Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */ } 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 */ #define JT_NATURAL 0x0004 /* True for a "natural" join */ #define JT_LEFT 0x0008 /* Left outer join */ #define JT_RIGHT 0x0010 /* Right outer join */ #define JT_OUTER 0x0020 /* The "OUTER" keyword is present */ #define JT_ERROR 0x0040 /* unknown or unsupported join type */ /* ** Flags appropriate for the wctrlFlags parameter of sqlite3WhereBegin() ** and the WhereInfo.wctrlFlags member. ** ** Value constraints (enforced via assert()): ** WHERE_USE_LIMIT == SF_FixedLimit */ #define WHERE_ORDERBY_NORMAL 0x0000 /* No-op */ #define WHERE_ORDERBY_MIN 0x0001 /* ORDER BY processing for min() func */ #define WHERE_ORDERBY_MAX 0x0002 /* ORDER BY processing for max() func */ #define WHERE_ONEPASS_DESIRED 0x0004 /* Want to do one-pass UPDATE/DELETE */ #define WHERE_ONEPASS_MULTIROW 0x0008 /* ONEPASS is ok with multiple rows */ #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() */ /* 0x0400 not currently used */ #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 */ |
︙ | ︙ | |||
3311 3312 3313 3314 3315 3316 3317 | 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 */ | < | | | | < | | | | | | < | | | | < | | | | < < < < < | < < | < < < | | < < > | | 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 | 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 */ int nErr; /* Number of errors encountered while resolving names */ u16 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_HasWin == EP_Win ** */ #define NC_AllowAgg 0x0001 /* Aggregate functions are allowed here */ #define NC_PartIdx 0x0002 /* True if resolving a partial index WHERE */ #define NC_IsCheck 0x0004 /* True if resolving names in a CHECK constraint */ #define NC_InAggFunc 0x0008 /* True if analyzing arguments to an agg func */ #define NC_HasAgg 0x0010 /* One or more aggregate functions seen */ #define NC_IdxExpr 0x0020 /* True if resolving columns of CREATE INDEX */ #define NC_VarSelect 0x0040 /* A correlated subquery has been seen */ #define NC_UEList 0x0080 /* True if uNC.pEList is used */ #define NC_UAggInfo 0x0100 /* True if uNC.pAggInfo is used */ #define NC_UUpsert 0x0200 /* True if uNC.pUpsert is used */ #define NC_MinMaxAgg 0x1000 /* min/max aggregates seen. See note above */ #define NC_Complex 0x2000 /* True if a function or subquery seen */ #define NC_AllowWin 0x4000 /* Window functions are allowed here */ #define NC_HasWin 0x8000 /* One or more window functions seen */ /* ** 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 conflicting index */ 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 */ /* The fields above comprise the parse tree for the upsert clause. ** The fields below are used to transfer information from the INSERT ** processing down into the UPDATE processing while generating code. ** Upsert owns the memory allocated above, but not the memory below. */ Index *pUpsertIdx; /* Constraint that pUpsertTarget identifies */ 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 */ }; /* |
︙ | ︙ | |||
3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 | ** 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 */ | > < | | < | | | | | | | | | | | | | | | | | | | | < < < < < < < < < < < < > > > | 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 | ** 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 { ExprList *pEList; /* The fields of the result */ 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 */ 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_FixedLimit == WHERE_USE_LIMIT */ #define SF_Distinct 0x00001 /* Output should be DISTINCT */ #define SF_All 0x00002 /* Includes the ALL keyword */ #define SF_Resolved 0x00004 /* Identifiers have been resolved */ #define SF_Aggregate 0x00008 /* Contains agg functions or a GROUP BY */ #define SF_HasAgg 0x00010 /* Contains aggregate functions */ #define SF_UsesEphemeral 0x00020 /* Uses the OpenEphemeral opcode */ #define SF_Expanded 0x00040 /* sqlite3SelectExpand() called on this */ #define SF_HasTypeInfo 0x00080 /* FROM subqueries have Table metadata */ #define SF_Compound 0x00100 /* Part of a compound query */ #define SF_Values 0x00200 /* Synthesized from VALUES clause */ #define SF_MultiValue 0x00400 /* Single VALUES term with multiple rows */ #define SF_NestedFrom 0x00800 /* Part of a parenthesized FROM clause */ #define SF_MinMaxAgg 0x01000 /* Aggregate containing min() or max() */ #define SF_Recursive 0x02000 /* The recursive part of a recursive CTE */ #define SF_FixedLimit 0x04000 /* nSelectRow set by a constant LIMIT */ #define SF_MaybeConvert 0x08000 /* Need convertCompoundSelectToSubquery() */ #define SF_Converted 0x10000 /* By convertCompoundSelectToSubquery() */ #define SF_IncludeHidden 0x20000 /* Include hidden columns in output */ #define SF_ComplexResult 0x40000 /* Result contains subquery or function */ #define SF_NoopOrderBy 0x0400000 /* ORDER BY is ignored for this query */ /* ** 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. ** ** All of the above are free to ignore their ORDER BY clause. Those that ** follow must honor the ORDER BY clause. ** ** 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 |
︙ | ︙ | |||
3531 3532 3533 3534 3535 3536 3537 | ** 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. | < < < < < < < < < < | < < < | | | < | < | | 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 | ** 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 */ #define SRT_Fifo 5 /* Store result as data with an automatic rowid */ #define SRT_DistFifo 6 /* Like SRT_Fifo, but unique results only */ #define SRT_Queue 7 /* Store result in an queue */ #define SRT_DistQueue 8 /* Like SRT_Queue, but unique results only */ /* The ORDER BY clause is ignored for all of the above */ #define IgnorableOrderby(X) ((X->eDest)<=SRT_DistQueue) #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 */ /* ** 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. On of SRT_* above. */ int iSDParm; /* A parameter used by 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 */ }; /* ** During code generation of statements that do inserts into AUTOINCREMENT ** tables, the following information is attached to the Table.u.autoInc.p ** pointer of each autoincrement table to record some side information that |
︙ | ︙ | |||
3634 3635 3636 3637 3638 3639 3640 | # define DbMaskZero(M) memset((M),0,sizeof(M)) # define DbMaskSet(M,I) (M)[(I)/8]|=(1<<((I)&7)) # define DbMaskAllZero(M) sqlite3DbMaskAllZero(M) # define DbMaskNonZero(M) (sqlite3DbMaskAllZero(M)==0) #else typedef unsigned int yDbMask; # define DbMaskTest(M,I) (((M)&(((yDbMask)1)<<(I)))!=0) | | | | | | 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 | # define DbMaskZero(M) memset((M),0,sizeof(M)) # define DbMaskSet(M,I) (M)[(I)/8]|=(1<<((I)&7)) # define DbMaskAllZero(M) sqlite3DbMaskAllZero(M) # define DbMaskNonZero(M) (sqlite3DbMaskAllZero(M)==0) #else typedef unsigned int yDbMask; # 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 /* ** For each index X that has as one of its arguments either an expression ** or the name of a virtual generated column, and if X is in scope such that ** the value of the expression can simply be read from the index, then ** there is an instance of this object on the Parse.pIdxExpr list. |
︙ | ︙ | |||
3662 3663 3664 3665 3666 3667 3668 | u8 bMaybeNullRow; /* True if we need an OP_IfNullRow check */ IndexedExpr *pIENext; /* Next in a list of all indexed expressions */ #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS const char *zIdxName; /* Name of index, used only for bytecode comments */ #endif }; | < < < < < < < < < < < | 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 | u8 bMaybeNullRow; /* True if we need an OP_IfNullRow check */ IndexedExpr *pIENext; /* Next in a list of all indexed expressions */ #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS const char *zIdxName; /* Name of index, used only for bytecode comments */ #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 |
︙ | ︙ | |||
3703 3704 3705 3706 3707 3708 3709 | 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 */ | | < < < < | | < < | < < < < < < < > > > > > < < | | < | | | 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 | 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 */ 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 */ IndexedExpr *pIdxExpr;/* List of expressions used by active indexes */ 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 */ Parse *pParentParse; /* Parent parser if this parser is nested */ int addrCrTab; /* Address of OP_CreateBtree opcode on CREATE TABLE */ 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 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 ** determined by offsetof(Parse,aTempReg). **************************************************************************/ int aTempReg[8]; /* Holding area for temporary registers */ Token sNameToken; /* Token with unqualified schema object name */ /************************************************************************ ** Above is constant between recursions. Below is reset before and after ** each recursion. The boundary between these two regions is determined ** using offsetof(Parse,sLastToken) so the sLastToken field must be the ** 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 */ #if !(defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_OMIT_ALTERTABLE)) u8 eParseMode; /* PARSE_MODE_XXX constant */ #endif #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 Table *pZombieTab; /* List of Table objects to delete after code gen */ TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */ With *pWith; /* Current WITH clause, or NULL */ With *pWithToFree; /* Free this WITH object at the end of the parse */ #ifndef SQLITE_OMIT_ALTERTABLE RenameToken *pRename; /* Tokens subject to renaming by ALTER TABLE */ #endif }; #define PARSE_MODE_NORMAL 0 #define PARSE_MODE_DECLARE_VTAB 1 #define PARSE_MODE_RENAME_COLUMN 2 #define PARSE_MODE_RENAME_TABLE 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 */ #define PARSE_TAIL(X) (((char*)(X))+PARSE_RECURSE_SZ) /* Pointer to tail */ /* ** Return true if currently inside an sqlite3_declare_vtab() call. */ #ifdef SQLITE_OMIT_VIRTUALTABLE #define IN_DECLARE_VTAB 0 #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_COLUMN) #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 |
︙ | ︙ | |||
3878 3879 3880 3881 3882 3883 3884 | #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 */ | < | | < > | | | | | | | < > | | | < | | < > | | | | < > | | | < > | | | | | > > | | | > > | > > > > > > > > > > > < < < < < < < < < < < < < < < < < < < < | | < < | | > > > | | < < < | | | > > | 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 | #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 * database). This allows Trigger structures to be retrieved by name. * 2. All triggers associated with a single table form a linked list, using the * pNext member of struct Trigger. A pointer to the first element of the * linked list is stored as the "pTrigger" member of the associated * struct Table. * * The "step_list" member points to the first element of a linked list * 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 */ }; /* ** A trigger is either a BEFORE or an AFTER trigger. The following constants ** determine which. ** ** If there are multiple triggers, you might of some BEFORE and some AFTER. ** In that cases, the constants below can be ORed together. */ #define TRIGGER_BEFORE 1 #define TRIGGER_AFTER 2 /* * An instance of struct TriggerStep is used to store a single SQL statement * that is a part of a trigger-program. * * Instances of struct TriggerStep are stored in a singly linked list (linked * using the "pNext" member) referenced by the "step_list" member of the * associated struct Trigger instance. The first element of the linked list is * the first step of the trigger-program. * * The "op" member indicates whether this is a "DELETE", "INSERT", "UPDATE" or * "SELECT" statement. The meanings of the other members is determined by the * value of "op" as follows: * * (op == TK_INSERT) * orconf -> stores the ON CONFLICT algorithm * pSelect -> If this is an INSERT INTO ... SELECT ... statement, then * this stores a pointer to the SELECT statement. Otherwise NULL. * zTarget -> Dequoted name of the table to insert into. * pExprList -> If this is an INSERT INTO ... VALUES ... statement, then * this stores values to be inserted. Otherwise NULL. * pIdList -> If this is an INSERT INTO ... (<column-names>) VALUES ... * statement, then this stores the column-names to be * inserted into. * * (op == TK_DELETE) * zTarget -> Dequoted name of the table to delete from. * pWhere -> The WHERE clause of the DELETE statement if one is specified. * Otherwise NULL. * * (op == TK_UPDATE) * zTarget -> Dequoted name of the table to update. * pWhere -> The WHERE clause of the UPDATE statement if one is specified. * 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 */ 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 */ Expr *pWhere; /* The WHERE clause for DELETE or UPDATE steps */ ExprList *pExprList; /* SET clause for UPDATE */ 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 */ }; /* ** The following structure contains information used by the sqliteFix... ** routines as they walk the parse tree to make database references ** explicit. */ typedef struct DbFixer DbFixer; struct DbFixer { Parse *pParse; /* The parsing context. Error messages written here */ Schema *pSchema; /* Fix items to this schema */ int bVarOnly; /* Check for variable references only */ 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 */ }; /* ** 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 { |
︙ | ︙ | |||
4024 4025 4026 4027 4028 4029 4030 | 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 */ | < < < < < | < < < < < < < < < < < < < < < | | | | | < | 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 | 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 */ } InitData; /* ** Allowed values for mInitFlags */ #define INITFLAG_AlterTable 0x0001 /* This is a reparse after ALTER TABLE */ /* ** 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 */ int bCoreMutex; /* True to enable core mutexing */ int bFullMutex; /* True to enable full mutexing */ int bOpenUri; /* True to interpret filenames as URIs */ int bUseCis; /* Use covering indices for full-scans */ int bSmallMalloc; /* Avoid large memory allocations if true */ 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 */ |
︙ | ︙ | |||
4105 4106 4107 4108 4109 4110 4111 | #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 | | | < < < < < | 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 | #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 #ifdef SQLITE_ENABLE_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 bInternalFunctions; /* Internal SQL functions are visible */ int iOnceResetThreshold; /* When to reset OP_Once counters */ u32 szSorterRef; /* Min size in bytes to use sorter-refs */ }; /* ** 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 ); |
︙ | ︙ | |||
4149 4150 4151 4152 4153 4154 4155 | */ 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 */ | | > < > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < | | < | | < | < < < < < < < < < < < < | < < | < | > < | < | < < < < | | | < < < < | | > | 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 | */ 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 */ u8 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 SrcCount *pSrcCount; /* Counting column references */ struct CCurHint *pCCurHint; /* Used by codeCursorHint() */ 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 CoveringIndexCheck *pCovIdxCk; /* Check for covering index */ } u; }; /* 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*); #ifdef SQLITE_DEBUG void sqlite3SelectWalkAssert2(Walker*, Select*); #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 */ /* ** An instance of this structure represents a set of one or more CTEs ** (common table expressions) created by a single WITH clause. */ struct With { int nCte; /* Number of CTEs in the WITH clause */ With *pOuter; /* Containing WITH clause, or NULL */ struct Cte { /* For each CTE in the WITH clause.... */ 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 */ } a[1]; }; #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, all related to window functions ** ** (1) A single instance of this structure is attached to the ** the Expr.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. ** ** 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; int regResult; 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; }; #ifndef SQLITE_OMIT_WINDOWFUNC void sqlite3WindowDelete(sqlite3*, Window*); void sqlite3WindowListDelete(sqlite3 *db, Window *p); Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*, u8); void sqlite3WindowAttach(Parse*, Expr*, Window*); int sqlite3WindowCompare(Parse*, Window*, Window*); void sqlite3WindowCodeInit(Parse*, Window*); void sqlite3WindowCodeStep(Parse*, Select*, WhereInfo*, int, int); int sqlite3WindowRewrite(Parse*, Select*); int sqlite3ExpandSubquery(Parse*, struct SrcList_item*); 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 |
︙ | ︙ | |||
4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 | 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 | > > < < < < < | 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 | 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); int sqlite3CorruptPgnoError(int,Pgno); # define SQLITE_NOMEM_BKPT sqlite3NomemError(__LINE__) # define SQLITE_IOERR_NOMEM_BKPT sqlite3IoerrnomemError(__LINE__) # define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptPgnoError(__LINE__,(P)) #else # define SQLITE_NOMEM_BKPT SQLITE_NOMEM # define SQLITE_IOERR_NOMEM_BKPT SQLITE_IOERR_NOMEM # define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptError(__LINE__) #endif /* ** FTS3 and FTS4 both require virtual table support */ #if defined(SQLITE_OMIT_VIRTUALTABLE) |
︙ | ︙ | |||
4473 4474 4475 4476 4477 4478 4479 | 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*); | < | | | < | < | 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 | 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(void*); int sqlite3DbMallocSize(sqlite3*, void*); void *sqlite3PageMalloc(int); void sqlite3PageFree(void*); void sqlite3MemSetDefault(void); #ifndef SQLITE_UNTESTABLE void sqlite3BenignMallocHooks(void (*)(void), void (*)(void)); #endif int sqlite3HeapNearlyFull(void); /* ** On systems with ample stack space and that support alloca(), make ** use of alloca() to obtain space for large automatic objects. By default, ** obtain space from malloc(). ** ** The alloca() routine never returns NULL. This will cause code paths ** that deal with sqlite3StackAlloc() failures to be unreachable. */ #ifdef SQLITE_USE_ALLOCA # define sqlite3StackAllocRaw(D,N) alloca(N) # define sqlite3StackAllocZero(D,N) memset(alloca(N), 0, N) # define sqlite3StackFree(D,P) #else # define sqlite3StackAllocRaw(D,N) sqlite3DbMallocRaw(D,N) # define sqlite3StackAllocZero(D,N) sqlite3DbMallocZero(D,N) # define sqlite3StackFree(D,P) sqlite3DbFree(D,P) #endif /* Do not allow both MEMSYS5 and MEMSYS3 to be defined together. If they ** are, disable MEMSYS3 */ #ifdef SQLITE_ENABLE_MEMSYS5 const sqlite3_mem_methods *sqlite3MemGetMemsys5(void); |
︙ | ︙ | |||
4546 4547 4548 4549 4550 4551 4552 | #if defined(SQLITE_ENABLE_MULTITHREADED_CHECKS) && !defined(SQLITE_MUTEX_OMIT) void sqlite3MutexWarnOnContention(sqlite3_mutex*); #else # define sqlite3MutexWarnOnContention(x) #endif #ifndef SQLITE_OMIT_FLOATING_POINT | < < < < | 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 | #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. */ |
︙ | ︙ | |||
4575 4576 4577 4578 4579 4580 4581 | void sqlite3DebugPrintf(const char*, ...); #endif #if defined(SQLITE_TEST) void *sqlite3TestTextToPtr(const char*); #endif #if defined(SQLITE_DEBUG) | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < | | < | < < < < | | < < < < < | | | | < < < < < < < | | < | < > > > | > | 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 | void sqlite3DebugPrintf(const char*, ...); #endif #if defined(SQLITE_TEST) void *sqlite3TestTextToPtr(const char*); #endif #if defined(SQLITE_DEBUG) void sqlite3TreeViewExpr(TreeView*, const Expr*, u8); void sqlite3TreeViewBareExprList(TreeView*, const ExprList*, const char*); void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*); void sqlite3TreeViewSrcList(TreeView*, const SrcList*); void sqlite3TreeViewSelect(TreeView*, const Select*, u8); void sqlite3TreeViewWith(TreeView*, const With*, u8); #ifndef SQLITE_OMIT_WINDOWFUNC void sqlite3TreeViewWindow(TreeView*, const Window*, u8); 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 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(sqlite3*,Expr*, Expr*); Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*, int); void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32); void sqlite3ExprDelete(sqlite3*, Expr*); ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*); ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*); void sqlite3ExprListSetSortOrder(ExprList*,int); void sqlite3ExprListSetName(Parse*,ExprList*,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 sqlite3DeleteColumnNames(sqlite3*,Table*); int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**); void sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*); Table *sqlite3ResultSetOfSelect(Parse*,Select*); void sqlite3OpenMasterTable(Parse *, int); Index *sqlite3PrimaryKeyIndex(Table*); i16 sqlite3ColumnOfIndex(Index*, i16); 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*); void sqlite3AddDefaultValue(Parse*,Expr*,const char*,const char*); void sqlite3AddCollateType(Parse*, Token*); void sqlite3EndTable(Parse*,Token*,Token*,u8,Select*); int sqlite3ParseUri(const char*,const char*,unsigned int*, sqlite3_vfs**,char**,char **); #ifdef SQLITE_HAS_CODEC int sqlite3CodecQueryParameters(sqlite3*,const char*,const char*); #else # define sqlite3CodecQueryParameters(A,B,C) 0 #endif Btree *sqlite3DbNameToBtree(sqlite3*,const char*); #ifdef SQLITE_UNTESTABLE # define sqlite3FaultSim(X) SQLITE_OK #else int sqlite3FaultSim(int); #endif |
︙ | ︙ | |||
4761 4762 4763 4764 4765 4766 4767 | void sqlite3AutoincrementBegin(Parse *pParse); void sqlite3AutoincrementEnd(Parse *pParse); #else # define sqlite3AutoincrementBegin(X) # define sqlite3AutoincrementEnd(X) #endif void sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int, Upsert*); | < < < < | | | < < | < < < < < | > < | | | | | | < | < < | | 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 | 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*); SrcList *sqlite3SrcListEnlarge(Parse*, SrcList*, int, int); 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 *, struct SrcList_item *); 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); void sqlite3DropIndex(Parse*, SrcList*, int); int sqlite3Select(Parse*, Select*, SelectDest*); Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*, Expr*,ExprList*,u32,Expr*); void sqlite3SelectDelete(sqlite3*, Select*); Table *sqlite3SrcListLookup(Parse*, SrcList*); int sqlite3IsReadOnly(Parse*, Table*, int); void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int); #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,char*); #endif void sqlite3DeleteFrom(Parse*, SrcList*, Expr*, ExprList*, Expr*); void sqlite3Update(Parse*, SrcList*, ExprList*,Expr*,int,ExprList*,Expr*, Upsert*); WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,Select*,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 */ 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); void sqlite3ExprCodeCopy(Parse*, Expr*, int); void sqlite3ExprCodeFactorable(Parse*, Expr*, int); int sqlite3ExprCodeAtInit(Parse*, Expr*, int); int sqlite3ExprCodeTemp(Parse*, Expr*, int*); int sqlite3ExprCodeTarget(Parse*, Expr*, int); void sqlite3ExprCodeAndCache(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*); Table *sqlite3LocateTableItem(Parse*,u32 flags,struct SrcList_item *); 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*, Token*); int sqlite3ExprCompare(Parse*,Expr*, Expr*, int); int sqlite3ExprCompareSkip(Expr*, Expr*, int); int sqlite3ExprListCompare(ExprList*, ExprList*, int); int sqlite3ExprImpliesExpr(Parse*,Expr*, Expr*, int); int sqlite3ExprImpliesNonNullRow(Expr*,int); void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); int sqlite3ExprCoveredByIndex(Expr*, int iCur, Index *pIdx); int sqlite3FunctionUsesThisSrc(Expr*, SrcList*); Vdbe *sqlite3GetVdbe(Parse*); #ifndef SQLITE_UNTESTABLE void sqlite3PrngSaveState(void); void sqlite3PrngRestoreState(void); #endif 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*); 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(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); |
︙ | ︙ | |||
4907 4908 4909 4910 4911 4912 4913 | 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*); | | | | | | < < < < < < | 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 | 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*,Expr*,int); ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int); SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int); IdList *sqlite3IdListDup(sqlite3*,IdList*); Select *sqlite3SelectDup(sqlite3*,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); #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*, |
︙ | ︙ | |||
4950 4951 4952 4953 4954 4955 4956 | 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*); | | | < < < < | < > < < < < > > > > > > | 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 | 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*,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); # define sqlite3ParseToplevel(p) ((p)->pToplevel ? (p)->pToplevel : (p)) # define sqlite3IsToplevel(p) ((p)->pToplevel==0) #else # define sqlite3TriggersExist(B,C,D,E,F) 0 # define sqlite3DeleteTrigger(A,B) # define sqlite3DropTriggerPtr(A,B) # define sqlite3UnlinkAndDeleteTrigger(A,B,C) # define sqlite3CodeRowTrigger(A,B,C,D,E,F,G,H,I) # define sqlite3CodeRowTriggerDirect(A,B,C,D,E,F) # define sqlite3TriggerList(X, Y) 0 # define sqlite3ParseToplevel(p) p # define sqlite3IsToplevel(p) 1 # define sqlite3TriggerColmask(A,B,C,D,E,F,G) 0 #endif int sqlite3JoinType(Parse*, Token*, Token*, Token*); void 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 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 sqlite3FixExprList(DbFixer*, ExprList*); int sqlite3FixTriggerStep(DbFixer*, TriggerStep*); int sqlite3AtoF(const char *z, double*, int, u8); int sqlite3GetInt32(const char *, int*); 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_STAT3_OR_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); /* ** Routines to read and write variable-length integers. These used to ** be defined locally, but now we use the varint routines in the util.c |
︙ | ︙ | |||
5037 5038 5039 5040 5041 5042 5043 | /* ** 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))) | < < < | | | | < < | < < < < | | | | | < | < < < | < < < | | < < | | < | < < < < < < < < | | | < < | < < < < < | > | 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 | /* ** 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); char sqlite3CompareAffinity(Expr *pExpr, char aff2); int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); char sqlite3TableColumnAffinity(Table*,int); char sqlite3ExprAffinity(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 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 #ifdef SQLITE_ENABLE_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); CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr); CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr); int sqlite3ExprCollSeqMatch(Parse*,Expr*,Expr*); Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int); Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*); Expr *sqlite3ExprSkipCollate(Expr*); int sqlite3CheckCollSeq(Parse *, CollSeq *); int sqlite3WritableSchema(sqlite3*); int sqlite3CheckObjectName(Parse*, const char*,const char*,const char*); void sqlite3VdbeSetChanges(sqlite3 *, int); 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*); sqlite3_value *sqlite3ValueNew(sqlite3 *); #ifndef SQLITE_OMIT_UTF16 char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8); #endif int sqlite3ValueFromExpr(sqlite3 *, 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 sqlite3UpperToLower[]; extern const unsigned char sqlite3CtypeMap[]; extern const Token sqlite3IntTokens[]; extern SQLITE_WSD struct Sqlite3Config sqlite3Config; extern FuncDefHash sqlite3BuiltinFunctions; #ifndef SQLITE_OMIT_WSD extern int sqlite3PendingByte; #endif #endif #ifdef VDBE_PROFILE extern sqlite3_uint64 sqlite3NProfileCnt; #endif void sqlite3RootPageMoved(sqlite3*, int, int, int); 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*); void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p); int sqlite3MatchSpanName(const char*, const char*, const char*, 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 *sqlite3RenameTokenMap(Parse*, void*, Token*); void sqlite3RenameTokenRemap(Parse*, void *pTo, 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*, sqlite3_file*); 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); #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 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_STAT3_OR_STAT4 void sqlite3AnalyzeFunctions(void); 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 |
︙ | ︙ | |||
5260 5261 5262 5263 5264 5265 5266 | #ifndef SQLITE_OMIT_LOAD_EXTENSION void sqlite3CloseExtensions(sqlite3*); #else # define sqlite3CloseExtensions(X) #endif #ifndef SQLITE_OMIT_SHARED_CACHE | | | < < < < < < < < < < < < | < < | < < | | < | < | < | < < | | < < < < | 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 | #ifndef SQLITE_OMIT_LOAD_EXTENSION void sqlite3CloseExtensions(sqlite3*); #else # define sqlite3CloseExtensions(X) #endif #ifndef SQLITE_OMIT_SHARED_CACHE void sqlite3TableLock(Parse *, int, int, 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(Y) # define sqlite3VtabSync(X,Y) SQLITE_OK # define sqlite3VtabRollback(X) # define sqlite3VtabCommit(X) # define sqlite3VtabInSync(db) 0 # define sqlite3VtabLock(X) # define sqlite3VtabUnlock(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 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); #else # define sqlite3ShadowTableName(A,B) 0 #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*); #ifdef SQLITE_ENABLE_NORMALIZE char *sqlite3Normalize(Vdbe*, const char*); #endif int sqlite3Reprepare(Vdbe*); void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*); CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, 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 With *sqlite3WithAdd(Parse*,With*,Token*,ExprList*,Select*); void sqlite3WithDelete(sqlite3*,With*); void sqlite3WithPush(Parse*, With*, u8); #else #define sqlite3WithPush(x,y,z) #define sqlite3WithDelete(x,y) #endif #ifndef SQLITE_OMIT_UPSERT Upsert *sqlite3UpsertNew(sqlite3*,ExprList*,Expr*,ExprList*,Expr*); void sqlite3UpsertDelete(sqlite3*,Upsert*); Upsert *sqlite3UpsertDup(sqlite3*,Upsert*); int sqlite3UpsertAnalyzeTarget(Parse*,SrcList*,Upsert*); void sqlite3UpsertDoUpdate(Parse*,Upsert*,Table*,Index*,int); #else #define sqlite3UpsertNew(v,w,x,y,z) ((Upsert*)0) #define sqlite3UpsertDelete(x,y) #define sqlite3UpsertDup(x,y) ((Upsert*)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 ** this case foreign keys are parsed, but no other functionality is ** provided (enforcement of FK constraints requires the triggers sub-system). */ #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) void sqlite3FkCheck(Parse*, Table*, int, int, int*, int); void sqlite3FkDropTable(Parse*, SrcList *, Table*); void sqlite3FkActions(Parse*, Table*, ExprList*, int, int*, int); int sqlite3FkRequired(Parse*, Table*, int*, int); u32 sqlite3FkOldmask(Parse*, Table*); FKey *sqlite3FkReferences(Table *); #else #define sqlite3FkActions(a,b,c,d,e,f) #define sqlite3FkCheck(a,b,c,d,e,f) #define sqlite3FkDropTable(a,b,c) #define sqlite3FkOldmask(a,b) 0 #define sqlite3FkRequired(a,b,c,d) 0 #define sqlite3FkReferences(a) 0 #endif #ifndef SQLITE_OMIT_FOREIGN_KEY void sqlite3FkDelete(sqlite3 *, Table*); int sqlite3FkLocateIndex(Parse*,Table*,FKey*,Index**,int**); #else #define sqlite3FkDelete(a,b) #define sqlite3FkLocateIndex(a,b,c,d,e) |
︙ | ︙ | |||
5459 5460 5461 5462 5463 5464 5465 | #endif int sqlite3JournalIsInMemory(sqlite3_file *p); void sqlite3MemJournalOpen(sqlite3_file *); void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p); #if SQLITE_MAX_EXPR_DEPTH>0 | | | 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 | #endif int sqlite3JournalIsInMemory(sqlite3_file *p); void sqlite3MemJournalOpen(sqlite3_file *); void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p); #if SQLITE_MAX_EXPR_DEPTH>0 int sqlite3SelectExprHeight(Select *); int sqlite3ExprCheckHeight(Parse*, int); #else #define sqlite3SelectExprHeight(x) 0 #define sqlite3ExprCheckHeight(x,y) #endif u32 sqlite3Get4byte(const u8*); |
︙ | ︙ | |||
5530 5531 5532 5533 5534 5535 5536 | ** 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); | | | | 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 | ** 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(void*,u8); int sqlite3MemdebugNoType(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 */ |
︙ | ︙ | |||
5556 5557 5558 5559 5560 5561 5562 | #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 | | | | < < < < < < < < < < | 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 | #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(Expr *pExpr); int sqlite3ExprIsVector(Expr *pExpr); Expr *sqlite3VectorFieldSubexpr(Expr*, int); Expr *sqlite3ExprForVectorField(Parse*,Expr*,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 71 72 73 74 | # 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 used to mean that the limit was not enforced. ** But that is no longer true. The limit is now strictly enforced ** at all times. */ #ifndef SQLITE_MAX_EXPR_DEPTH # define SQLITE_MAX_EXPR_DEPTH 1000 #endif /* ** The maximum number of terms in a compound SELECT statement. |
︙ | ︙ | |||
123 124 125 126 127 128 129 | #ifndef SQLITE_MAX_ATTACHED # define SQLITE_MAX_ATTACHED 10 #endif /* ** The maximum value of a ?nnn wildcard that the parser will accept. | < < < | | 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | #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 # define SQLITE_MAX_VARIABLE_NUMBER 999 #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 | /* ** 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); | < < < < | 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 */ |
︙ | ︙ | |||
220 221 222 223 224 225 226 | 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; } | < < < < < < < < < | 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: { |
︙ | ︙ | |||
287 288 289 290 291 292 293 | */ case SQLITE_DBSTATUS_SCHEMA_USED: { int i; /* Used to iterate through schemas */ int nByte = 0; /* Used to accumulate return value */ sqlite3BtreeEnterAll(db); db->pnBytesFreed = &nByte; | < < | 274 275 276 277 278 279 280 281 282 283 284 285 286 287 | */ case SQLITE_DBSTATUS_SCHEMA_USED: { int i; /* Used to iterate through schemas */ int nByte = 0; /* Used to accumulate return value */ sqlite3BtreeEnterAll(db); db->pnBytesFreed = &nByte; for(i=0; i<db->nDb; i++){ Schema *pSchema = db->aDb[i].pSchema; if( ALWAYS(pSchema!=0) ){ HashElem *p; nByte += sqlite3GlobalConfig.m.xRoundup(sizeof(HashElem)) * ( pSchema->tblHash.count |
︙ | ︙ | |||
314 315 316 317 318 319 320 | } for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){ sqlite3DeleteTable(db, (Table *)sqliteHashData(p)); } } } db->pnBytesFreed = 0; | < < < | | > < | | 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 | } for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){ sqlite3DeleteTable(db, (Table *)sqliteHashData(p)); } } } db->pnBytesFreed = 0; sqlite3BtreeLeaveAll(db); *pHighwater = 0; *pCurrent = nByte; break; } /* ** *pCurrent gets an accurate estimate of the amount of memory used ** to store all prepared statements. ** *pHighwater is set to zero. */ case SQLITE_DBSTATUS_STMT_USED: { struct Vdbe *pVdbe; /* Used to iterate through VMs */ int nByte = 0; /* Used to accumulate return value */ db->pnBytesFreed = &nByte; for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){ sqlite3VdbeClearObject(db, pVdbe); sqlite3DbFree(db, pVdbe); } db->pnBytesFreed = 0; *pHighwater = 0; /* IMP: R-64479-57858 */ *pCurrent = nByte; break; } /* ** 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; /* Fall through into the next case */ 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 = sqlite3_realloc64( 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 = sqlite3_realloc64( 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.
︙ | ︙ | |||
177 178 179 180 181 182 183 | 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) */ | < | 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | 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 */ |
︙ | ︙ | |||
514 515 516 517 518 519 520 | dbFreeStmt(pPreStmt); } pDb->nStmt = 0; pDb->stmtLast = 0; pDb->stmtList = 0; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | 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; 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); } /* ** This routine is called when a database file is locked while trying ** to execute SQL. */ static int DbBusyHandler(void *cd, int nTries){ |
︙ | ︙ | |||
1263 1264 1265 1266 1267 1268 1269 | Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0); rc = TCL_ERROR; } sqlite3_exec(pDb->db, "ROLLBACK", 0, 0, 0); } pDb->disableAuth--; | < | 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 | 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 |
︙ | ︙ | |||
1597 1598 1599 1600 1601 1602 1603 | p->pSql = pSql; Tcl_IncrRefCount(pSql); if( pArray ){ p->pArray = pArray; Tcl_IncrRefCount(pArray); } p->evalFlags = evalFlags; | < | 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 | 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( |
︙ | ︙ | |||
1738 1739 1740 1741 1742 1743 1744 | } if( p->pArray ){ Tcl_DecrRefCount(p->pArray); p->pArray = 0; } Tcl_DecrRefCount(p->pSql); dbReleaseColumnNames(p); | < | 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 | } 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. */ |
︙ | ︙ | |||
1937 1938 1939 1940 1941 1942 1943 | 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", | | | < | | | | | | | > | < | | < | | | | | | | | > | 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 | 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", "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_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; } |
︙ | ︙ | |||
2228 2229 2230 2231 2232 2233 2234 | case DB_CHANGES: { Tcl_Obj *pResult; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } pResult = Tcl_GetObjResult(interp); | | | 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 | case DB_CHANGES: { Tcl_Obj *pResult; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } pResult = Tcl_GetObjResult(interp); Tcl_SetIntObj(pResult, sqlite3_changes(pDb->db)); break; } /* $db close ** ** Shutdown the database */ |
︙ | ︙ | |||
2352 2353 2354 2355 2356 2357 2358 | isComplete = sqlite3_complete( Tcl_GetStringFromObj(objv[2], 0) ); pResult = Tcl_GetObjResult(interp); Tcl_SetBooleanObj(pResult, isComplete); #endif break; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 | 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: ** rollback, abort, fail, ignore, replace |
︙ | ︙ | |||
2621 2622 2623 2624 2625 2626 2627 | /* ** $db deserialize ?-maxsize N? ?-readonly BOOL? ?DATABASE? VALUE ** ** Reopen DATABASE (default "main") using the content in $VALUE */ case DB_DESERIALIZE: { | | | 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 | /* ** $db deserialize ?-maxsize N? ?-readonly BOOL? ?DATABASE? VALUE ** ** Reopen DATABASE (default "main") using the content in $VALUE */ case DB_DESERIALIZE: { #ifndef SQLITE_ENABLE_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; |
︙ | ︙ | |||
2644 2645 2646 2647 2648 2649 2650 | 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 ){ | < | < | 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 | 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 ){ rc = Tcl_GetWideIntFromObj(interp, objv[++i], &mxSize); if( rc ) goto deserialize_error; continue; } if( strcmp(z,"-readonly")==0 && i<objc-2 ){ rc = Tcl_GetBooleanFromObj(interp, objv[++i], &isReadonly); if( rc ) goto deserialize_error; continue; } |
︙ | ︙ | |||
2727 2728 2729 2730 2731 2732 2733 | ** call to sqlite3_exec(). */ case DB_ERRORCODE: { Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_errcode(pDb->db))); break; } | < < < < < < < < < < < | 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 | ** call to sqlite3_exec(). */ case DB_ERRORCODE: { Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_errcode(pDb->db))); break; } /* ** $db exists $sql ** $db onecolumn $sql ** ** The onecolumn method is the equivalent of: ** lindex [$db eval $sql] 0 */ |
︙ | ︙ | |||
2845 2846 2847 2848 2849 2850 2851 | cd2[1] = (void *)pScript; rc = DbEvalNextCmd(cd2, interp, TCL_OK); } break; } /* | | < < < < < < < | 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 | cd2[1] = (void *)pScript; rc = DbEvalNextCmd(cd2, interp, TCL_OK); } break; } /* ** $db function NAME [-argcount N] [-deterministic] SCRIPT ** ** Create a new SQL function called NAME. Whenever that function is ** called, invoke SCRIPT to evaluate the function. */ case DB_FUNCTION: { int flags = SQLITE_UTF8; SqlFunc *pFunc; Tcl_Obj *pScript; char *zName; int nArg = -1; |
︙ | ︙ | |||
2888 2889 2890 2891 2892 2893 2894 | return TCL_ERROR; } i++; }else if( n>1 && strncmp(z, "-deterministic",n)==0 ){ flags |= SQLITE_DETERMINISTIC; }else | < < < < < < | < | 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 | return TCL_ERROR; } i++; }else if( n>1 && strncmp(z, "-deterministic",n)==0 ){ flags |= SQLITE_DETERMINISTIC; }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 or -returntype", (char*)0 ); return TCL_ERROR; } } pScript = objv[objc-1]; zName = Tcl_GetStringFromObj(objv[2], 0); |
︙ | ︙ | |||
2961 2962 2963 2964 2965 2966 2967 | if( objc!=(5+isReadonly) && objc!=(6+isReadonly) ){ Tcl_WrongNumArgs(interp, 2, objv, "?-readonly? ?DB? TABLE COLUMN ROWID"); return TCL_ERROR; } if( objc==(6+isReadonly) ){ | | | 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 | if( objc!=(5+isReadonly) && objc!=(6+isReadonly) ){ Tcl_WrongNumArgs(interp, 2, objv, "?-readonly? ?DB? TABLE COLUMN ROWID"); return TCL_ERROR; } if( objc==(6+isReadonly) ){ zDb = Tcl_GetString(objv[2]); } zTable = Tcl_GetString(objv[objc-3]); zColumn = Tcl_GetString(objv[objc-2]); rc = Tcl_GetWideIntFromObj(interp, objv[objc-1], &iRow); if( rc==TCL_OK ){ rc = createIncrblobChannel( |
︙ | ︙ | |||
3050 3051 3052 3053 3054 3055 3056 | ** queries. */ case DB_PROGRESS: { if( objc==2 ){ if( pDb->zProgress ){ Tcl_AppendResult(interp, pDb->zProgress, (char*)0); } | < < < | 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 | ** queries. */ case DB_PROGRESS: { if( objc==2 ){ if( pDb->zProgress ){ Tcl_AppendResult(interp, pDb->zProgress, (char*)0); } }else if( objc==4 ){ char *zProgress; int len; int N; if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &N) ){ return TCL_ERROR; }; |
︙ | ︙ | |||
3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 | /* ** $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"). | > > > > > > > > > > > > | 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 | /* ** $db rekey KEY ** ** Change the encryption key on the currently open database. */ case DB_REKEY: { #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) int nKey; void *pKey; #endif if( objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "KEY"); return TCL_ERROR; } #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey); rc = sqlite3_rekey(pDb->db, pKey, nKey); if( rc ){ Tcl_AppendResult(interp, sqlite3_errstr(rc), (char*)0); rc = TCL_ERROR; } #endif break; } /* $db restore ?DATABASE? FILENAME ** ** Open a database file named FILENAME. Transfer the content ** of FILENAME into the local database DATABASE (default: "main"). |
︙ | ︙ | |||
3204 3205 3206 3207 3208 3209 3210 | /* ** $db serialize ?DATABASE? ** ** Return a serialization of a database. */ case DB_SERIALIZE: { | | | 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 | /* ** $db serialize ?DATABASE? ** ** Return a serialization of a database. */ case DB_SERIALIZE: { #ifndef SQLITE_ENABLE_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; |
︙ | ︙ | |||
3292 3293 3294 3295 3296 3297 3298 | case DB_TOTAL_CHANGES: { Tcl_Obj *pResult; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } pResult = Tcl_GetObjResult(interp); | | | 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 | case DB_TOTAL_CHANGES: { Tcl_Obj *pResult; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } pResult = Tcl_GetObjResult(interp); Tcl_SetIntObj(pResult, sqlite3_total_changes(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 |
︙ | ︙ | |||
3472 3473 3474 3475 3476 3477 3478 | 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. */ | < | 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 | 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; |
︙ | ︙ | |||
3702 3703 3704 3705 3706 3707 3708 | */ static int sqliteCmdUsage( Tcl_Interp *interp, Tcl_Obj *const*objv ){ Tcl_WrongNumArgs(interp, 1, objv, "HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?" | < > > > < | 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 | */ 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?" #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) " ?-key CODECKEY?" #endif ); return TCL_ERROR; } /* ** sqlite3 DBNAME FILENAME ?-vfs VFSNAME? ?-key KEY? ?-readonly BOOLEAN? ** ?-create BOOLEAN? ?-nomutex 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 |
︙ | ︙ | |||
3737 3738 3739 3740 3741 3742 3743 | SqliteDb *p; const char *zArg; char *zErrMsg; int i; const char *zFile = 0; const char *zVfs = 0; int flags; | < > > > > | 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 | SqliteDb *p; const char *zArg; char *zErrMsg; int i; const char *zFile = 0; const char *zVfs = 0; int flags; Tcl_DString translatedFilename; #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) void *pKey = 0; int nKey = 0; #endif 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. |
︙ | ︙ | |||
3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 | 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 ){ | > > > > > > | < < < < < < < < | 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 | return TCL_OK; } if( strcmp(zArg,"-sourceid")==0 ){ Tcl_AppendResult(interp,sqlite3_sourceid(), (char*)0); return TCL_OK; } if( strcmp(zArg,"-has-codec")==0 ){ #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) Tcl_AppendResult(interp,"1",(char*)0); #else Tcl_AppendResult(interp,"0",(char*)0); #endif 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 ){ #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) pKey = Tcl_GetByteArrayFromObj(objv[i], &nKey); #endif }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, "-nomutex")==0 ){ int b; if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR; if( b ){ flags |= SQLITE_OPEN_NOMUTEX; flags &= ~SQLITE_OPEN_FULLMUTEX; }else{ |
︙ | ︙ | |||
3835 3836 3837 3838 3839 3840 3841 | int b; if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR; if( b ){ flags |= SQLITE_OPEN_URI; }else{ flags &= ~SQLITE_OPEN_URI; } | < < < < < | < < | < > > > > > < | 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 | 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 = ""; zFile = Tcl_TranslateFileName(interp, zFile, &translatedFilename); rc = sqlite3_open_v2(zFile, &p->db, flags, zVfs); 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 defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) if( p->db ){ sqlite3_key(p->db, pKey, nKey); } #endif 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); } return TCL_OK; } /* ** Provide a dummy Tcl_InitStubs if we are using this as a static ** library. */ |
︙ | ︙ | |||
3988 3989 3990 3991 3992 3993 3994 | "}\n" "}\n" "}\n" ; return zMainloop; } | < | < | 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 | "}\n" "}\n" "}\n" ; return zMainloop; } #define TCLSH_MAIN main /* Needed to fake out mktclapp */ 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 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. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | */ 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 */ ){ #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) sqlite3 *db; const char *zKey; int nKey; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " FILENAME\"", 0); return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; zKey = argv[2]; nKey = strlen(zKey); sqlite3_key(db, zKey, nKey); #endif 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 */ ){ #ifdef SQLITE_HAS_CODEC sqlite3 *db; const char *zKey; int nKey; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " FILENAME\"", 0); return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; zKey = argv[2]; nKey = strlen(zKey); sqlite3_rekey(db, zKey, nKey); #endif return TCL_OK; } /* ** Usage: sqlite3_close DB ** ** Closes the database opened by sqlite3_open. |
︙ | ︙ | |||
966 967 968 969 970 971 972 | int argc, sqlite3_value **argv ){ static int cnt = 0; sqlite3_result_int(context, cnt++); } | < < < < < < < < < < < < < < | 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 | 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 ** named "x_sqlite_exec" that invokes sqlite3_exec(). Invoking sqlite3_exec() |
︙ | ︙ | |||
1044 1045 1046 1047 1048 1049 1050 | 0, nondeterministicFunction, 0, 0); } if( rc==SQLITE_OK ){ rc = sqlite3_create_function(db, "counter2", -1, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, nondeterministicFunction, 0, 0); } | < < < < < < < < | 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 | 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; sqlite3_mutex_enter(db->mutex); |
︙ | ︙ | |||
1075 1076 1077 1078 1079 1080 1081 | sqlite3ValueFree(pVal); sqlite3_mutex_leave(db->mutex); } #endif if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0); | < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 | sqlite3ValueFree(pVal); sqlite3_mutex_leave(db->mutex); } #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 |
︙ | ︙ | |||
1848 1849 1850 1851 1852 1853 1854 | int enc; } aEnc[] = { {"utf8", SQLITE_UTF8 }, {"utf16", SQLITE_UTF16 }, {"utf16le", SQLITE_UTF16LE }, {"utf16be", SQLITE_UTF16BE }, {"any", SQLITE_ANY }, | | < | 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 | int enc; } aEnc[] = { {"utf8", SQLITE_UTF8 }, {"utf16", SQLITE_UTF16 }, {"utf16le", SQLITE_UTF16LE }, {"utf16be", SQLITE_UTF16BE }, {"any", SQLITE_ANY }, {"0", 0 } }; if( objc<5 || (objc%2)==0 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB NAME NARG ENC SWITCHES..."); return TCL_ERROR; } |
︙ | ︙ | |||
2184 2185 2186 2187 2188 2189 2190 | iValue = sqlite3_stmt_status(pStmt, op, resetFlag); Tcl_SetObjResult(interp, Tcl_NewIntObj(iValue)); return TCL_OK; } #ifdef SQLITE_ENABLE_STMT_SCANSTATUS /* | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | < < | | | < > > < < | < < < < < < < < < < < < < < | | | < | | | < | | | < | | < < < < < < < < < < < < | | | < | 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 | iValue = sqlite3_stmt_status(pStmt, op, resetFlag); Tcl_SetObjResult(interp, Tcl_NewIntObj(iValue)); return TCL_OK; } #ifdef SQLITE_ENABLE_STMT_SCANSTATUS /* ** Usage: sqlite3_stmt_scanstatus STMT IDX */ static int SQLITE_TCLAPI test_stmt_scanstatus( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; /* First argument */ int idx; /* Second argument */ const char *zName; const char *zExplain; sqlite3_int64 nLoop; sqlite3_int64 nVisit; double rEst; int res; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 1, objv, "STMT IDX"); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; res = sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop); if( res==0 ){ Tcl_Obj *pRet = Tcl_NewObj(); Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nLoop", -1)); Tcl_ListObjAppendElement(0, pRet, Tcl_NewWideIntObj(nLoop)); sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit); Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nVisit", -1)); Tcl_ListObjAppendElement(0, pRet, Tcl_NewWideIntObj(nVisit)); sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_EST, (void*)&rEst); Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nEst", -1)); Tcl_ListObjAppendElement(0, pRet, Tcl_NewDoubleObj(rEst)); sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_NAME, (void*)&zName); Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("zName", -1)); Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zName, -1)); sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain); Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("zExplain", -1)); Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zExplain, -1)); Tcl_SetObjResult(interp, pRet); }else{ Tcl_ResetResult(interp); } return TCL_OK; } /* ** Usage: sqlite3_stmt_scanstatus_reset STMT */ |
︙ | ︙ | |||
3885 3886 3887 3888 3889 3890 3891 | void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int idx; | < < | < < < < < | < < < < < | | 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 | 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; value = (char*)Tcl_GetByteArrayFromObj(objv[3], &bytes); if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR; rc = sqlite3_bind_text(pStmt, idx, value, bytes, SQLITE_TRANSIENT); if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; } return TCL_OK; } /* |
︙ | ︙ | |||
3941 3942 3943 3944 3945 3946 3947 | Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_OMIT_UTF16 sqlite3_stmt *pStmt; int idx; int bytes; char *value; | < < | < < < < < | < < < < < | 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 | 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; value = (char*)Tcl_GetByteArrayFromObj(oString, 0); if( Tcl_GetIntFromObj(interp, oBytes, &bytes) ) return TCL_ERROR; rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, xDel); if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); return TCL_ERROR; } #endif /* SQLITE_OMIT_UTF16 */ |
︙ | ︙ | |||
4024 4025 4026 4027 4028 4029 4030 | 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); | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | 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, -1); 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; } /* ** 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, |
︙ | ︙ | |||
4564 4565 4566 4567 4568 4569 4570 | if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; zErr = sqlite3_errmsg(db); Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1)); return TCL_OK; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 | if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; zErr = sqlite3_errmsg(db); Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1)); return TCL_OK; } /* ** Usage: test_errmsg16 DB ** ** Returns the UTF-16 representation of the error message string for the ** most recent sqlite3_* API call. This is a byte array object at the TCL ** level, and it includes the 0x00 0x00 terminator bytes at the end of the ** UTF-16 string. |
︙ | ︙ | |||
5069 5070 5071 5072 5073 5074 5075 | { "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 }, | | < | 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 | { "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_MASTER_JOURNAL", SQLITE_OPEN_MASTER_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 }, { 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; |
︙ | ︙ | |||
5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 | 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( | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | 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: sqlite_set_magic DB MAGIC-NUMBER ** ** Set the db->magic value. This is used to test error recovery logic. */ static int SQLITE_TCLAPI sqlite_set_magic( void * clientData, Tcl_Interp *interp, int argc, char **argv ){ sqlite3 *db; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB MAGIC", 0); return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; if( strcmp(argv[2], "SQLITE_MAGIC_OPEN")==0 ){ db->magic = SQLITE_MAGIC_OPEN; }else if( strcmp(argv[2], "SQLITE_MAGIC_CLOSED")==0 ){ db->magic = SQLITE_MAGIC_CLOSED; }else if( strcmp(argv[2], "SQLITE_MAGIC_BUSY")==0 ){ db->magic = SQLITE_MAGIC_BUSY; }else if( strcmp(argv[2], "SQLITE_MAGIC_ERROR")==0 ){ db->magic = SQLITE_MAGIC_ERROR; }else if( Tcl_GetInt(interp, argv[2], (int*)&db->magic) ){ return TCL_ERROR; } return TCL_OK; } /* ** Usage: sqlite3_interrupt DB ** ** Trigger an interrupt on DB */ static int SQLITE_TCLAPI test_interrupt( |
︙ | ︙ | |||
5596 5597 5598 5599 5600 5601 5602 | return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; sqlite3_interrupt(db); return TCL_OK; } | < < < < < < < < < < < < < < < < < < < < < < < | 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 | return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; sqlite3_interrupt(db); return TCL_OK; } /* ** Usage: sqlite_delete_function DB function-name ** ** Delete the user function 'function-name' from database handle DB. It ** is assumed that the user function was created as UTF8, any number of ** arguments (the way the TCL interface does it). */ |
︙ | ︙ | |||
5925 5926 5927 5928 5929 5930 5931 | Tcl_WrongNumArgs(interp, 1, objv, "?N?"); return TCL_ERROR; } if( objc==2 ){ if( Tcl_GetWideIntFromObj(interp, objv[1], &N) ) return TCL_ERROR; } amt = sqlite3_soft_heap_limit64(N); | < < < < < < < < < < < < < < < < < < < < < < < < < < < | 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 | Tcl_WrongNumArgs(interp, 1, objv, "?N?"); return TCL_ERROR; } 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 ** |
︙ | ︙ | |||
6669 6670 6671 6672 6673 6674 6675 | 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; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 | 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( |
︙ | ︙ | |||
6732 6733 6734 6735 6736 6737 6738 | } sqlite3_file_control(db, zDbName, SQLITE_FCNTL_TEMPFILENAME, (void*)&zTName); Tcl_AppendResult(interp, zTName, (char*)0); sqlite3_free(zTName); return TCL_OK; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 | } 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. */ static int SQLITE_TCLAPI vfs_list( |
︙ | ︙ | |||
6896 6897 6898 6899 6900 6901 6902 | */ 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 */ ){ | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < | 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 | */ 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_test_control(SQLITE_TESTCTRL_PRNG_RESET); return TCL_OK; } /* ** tclcmd: database_may_be_corrupt ** ** Indicate that database files might be corrupt. In other words, set the normal |
︙ | ︙ | |||
7331 7332 7333 7334 7335 7336 7337 | */ fflush(stdout); Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0); return TCL_OK; } #endif /* SQLITE_OMIT_EXPLAIN */ | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < | | | | 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 | */ fflush(stdout); Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0); return TCL_OK; } #endif /* SQLITE_OMIT_EXPLAIN */ /* ** sqlite3_test_control VERB ARGS... */ static int SQLITE_TCLAPI test_test_control( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ struct Verb { const char *zName; int i; } aVerb[] = { { "SQLITE_TESTCTRL_LOCALTIME_FAULT", SQLITE_TESTCTRL_LOCALTIME_FAULT }, { "SQLITE_TESTCTRL_SORTER_MMAP", SQLITE_TESTCTRL_SORTER_MMAP }, { "SQLITE_TESTCTRL_IMPOSTER", SQLITE_TESTCTRL_IMPOSTER }, { "SQLITE_TESTCTRL_INTERNAL_FUNCTIONS", SQLITE_TESTCTRL_INTERNAL_FUNCTIONS}, }; int iVerb; int iFlag; int rc; if( objc<2 ){ Tcl_WrongNumArgs(interp, 1, objv, "VERB ARGS..."); return TCL_ERROR; } 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: 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; sqlite3_test_control(iFlag, val); break; } case SQLITE_TESTCTRL_SORTER_MMAP: { int val; sqlite3 *db; if( objc!=4 ){ |
︙ | ︙ | |||
7752 7753 7754 7755 7756 7757 7758 | /* ** optimization_control DB OPT BOOLEAN ** ** Enable or disable query optimizations using the sqlite3_test_control() ** interface. Disable if BOOLEAN is false and enable if BOOLEAN is true. | | < < < < < < > | < < < | | < > | < < < < < < < < < | 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 | /* ** optimization_control DB OPT BOOLEAN ** ** Enable or disable query optimizations using the sqlite3_test_control() ** interface. Disable if BOOLEAN is false and enable if BOOLEAN is true. ** OPT is the name of the optimization to be disabled. */ static int SQLITE_TCLAPI optimization_control( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int i; sqlite3 *db; const char *zOpt; int onoff; int mask = 0; static const struct { const char *zOptName; int mask; } aOpt[] = { { "all", SQLITE_AllOpts }, { "none", 0 }, { "query-flattener", SQLITE_QueryFlattener }, { "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 }, { "stat3", SQLITE_Stat34 }, { "stat4", SQLITE_Stat34 }, { "skip-scan", SQLITE_SkipScan }, }; 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; if( Tcl_GetBooleanFromObj(interp, objv[3], &onoff) ) return TCL_ERROR; zOpt = Tcl_GetString(objv[2]); for(i=0; i<sizeof(aOpt)/sizeof(aOpt[0]); i++){ if( strcmp(zOpt, aOpt[i].zOptName)==0 ){ mask = aOpt[i].mask; break; } } if( onoff ) mask = ~mask; if( i>=sizeof(aOpt)/sizeof(aOpt[0]) ){ Tcl_AppendResult(interp, "unknown optimization - should be one of:", (char*)0); for(i=0; i<sizeof(aOpt)/sizeof(aOpt[0]); i++){ Tcl_AppendResult(interp, " ", aOpt[i].zOptName, (char*)0); } return TCL_ERROR; } sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, db, mask); return TCL_OK; } /* ** load_static_extension DB NAME ... ** ** Load one or more statically linked extensions. */ 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*); #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 }, { "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 }, #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 }, |
︙ | ︙ | |||
7914 7915 7916 7917 7918 7919 7920 | return TCL_ERROR; } if( aExtension[i].pInit ){ rc = aExtension[i].pInit(db, &zErrMsg, 0); }else{ rc = SQLITE_OK; } | | | 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 7244 7245 | return TCL_ERROR; } if( aExtension[i].pInit ){ rc = aExtension[i].pInit(db, &zErrMsg, 0); }else{ rc = SQLITE_OK; } if( rc!=SQLITE_OK || zErrMsg ){ Tcl_AppendResult(interp, "initialization of ", zName, " failed: ", zErrMsg, (char*)0); sqlite3_free(zErrMsg); return TCL_ERROR; } } return TCL_OK; |
︙ | ︙ | |||
8265 8266 8267 8268 8269 8270 8271 | int objc, Tcl_Obj *CONST objv[] ){ static const struct { const char *zName; int eVal; } aSetting[] = { | | | | | | | | | | < < < < < | | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | 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 }, }; int i; int v; const char *zSetting; sqlite3 *db; if( objc!=4 ){ 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( Tcl_GetIntFromObj(interp, objv[3], &v) ) return TCL_ERROR; sqlite3_db_config(db, aSetting[i].eVal, v, &v); Tcl_SetObjResult(interp, Tcl_NewIntObj(v)); 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, |
︙ | ︙ | |||
8391 8392 8393 8394 8395 8396 8397 | } rc = sqlite3_mmap_warm(db, zDb); Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); return TCL_OK; } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 7672 7673 7674 7675 7676 7677 7678 7679 7680 7681 7682 7683 7684 7685 | } 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 ** is constructed from a text input which is the output of the "dbtotxt" |
︙ | ︙ | |||
8491 8492 8493 8494 8495 8496 8497 | unsigned char *a = 0; int n = 0; int lineno = 0; int i, iNext; int iOffset = 0; int j, k; int rc; | | < < < < < | > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 7695 7696 7697 7698 7699 7700 7701 7702 7703 7704 7705 7706 7707 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 7750 7751 7752 7753 7754 | unsigned char *a = 0; int n = 0; int lineno = 0; int i, iNext; int iOffset = 0; int j, k; int rc; unsigned char 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( 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: %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx" " %hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx", &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 ){ memcpy(a+k, x, 16); } continue; } } Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(a, n)); free(a); return TCL_OK; } /* ** Register commands with the TCL interpreter. */ |
︙ | ︙ | |||
8683 8684 8685 8686 8687 8688 8689 | #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 }, | < > < < < < < < < < | 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 | #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 }, { "sqlite_set_magic", (Tcl_CmdProc*)sqlite_set_magic }, { "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 }, { "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 }, { "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 }, { "sqlite3_errmsg", test_errmsg ,0 }, { "sqlite3_errmsg16", test_errmsg16 ,0 }, { "sqlite3_open", test_open ,0 }, { "sqlite3_open16", test_open16 ,0 }, { "sqlite3_open_v2", test_open_v2 ,0 }, { "sqlite3_complete16", test_complete16 ,0 }, { "sqlite3_normalize", test_normalize ,0 }, |
︙ | ︙ | |||
8775 8776 8777 8778 8779 8780 8781 | { "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}, | < < < < | 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 | { "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 }, |
︙ | ︙ | |||
8860 8861 8862 8863 8864 8865 8866 | { "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 }, | < < | 7957 7958 7959 7960 7961 7962 7963 7964 7965 7966 7967 7968 7969 7970 7971 | { "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 }, |
︙ | ︙ | |||
8930 8931 8932 8933 8934 8935 8936 | { "sqlite3_snapshot_open_blob", test_snapshot_open_blob, 0 }, { "sqlite3_snapshot_cmp_blob", test_snapshot_cmp_blob, 0 }, #endif { "sqlite3_delete_database", test_delete_database, 0 }, { "atomic_batch_write", test_atomic_batch_write, 0 }, { "sqlite3_mmap_warm", test_mmap_warm, 0 }, { "sqlite3_config_sorterref", test_config_sorterref, 0 }, | < < < < | > > > | 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 | { "sqlite3_snapshot_open_blob", test_snapshot_open_blob, 0 }, { "sqlite3_snapshot_cmp_blob", test_snapshot_cmp_blob, 0 }, #endif { "sqlite3_delete_database", test_delete_database, 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 extern int sqlite3WhereTrace; extern int sqlite3OSTrace; extern int sqlite3WalTrace; #endif #ifdef SQLITE_TEST #ifdef SQLITE_ENABLE_FTS3 extern int sqlite3_fts3_enable_parentheses; #endif #endif #if defined(SQLITE_ENABLE_SELECTTRACE) extern int sqlite3SelectTrace; #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, |
︙ | ︙ | |||
9044 9045 9046 9047 9048 9049 9050 | (char*)&bitmask_size, TCL_LINK_INT|TCL_LINK_READ_ONLY); 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); | | | | | 8138 8139 8140 8141 8142 8143 8144 8145 8146 8147 8148 8149 8150 8151 8152 8153 8154 | (char*)&bitmask_size, TCL_LINK_INT|TCL_LINK_READ_ONLY); 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, "sqlite3SelectTrace", (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/test2.c.
︙ | ︙ | |||
517 518 519 520 521 522 523 | int nFile; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N-MEGABYTES FILE\"", 0); return TCL_ERROR; } if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR; | < < < < < < < < | 517 518 519 520 521 522 523 524 525 526 527 528 529 530 | int nFile; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N-MEGABYTES FILE\"", 0); return TCL_ERROR; } if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR; pVfs = sqlite3_vfs_find(0); nFile = (int)strlen(argv[2]); zFile = sqlite3_malloc( nFile+2 ); if( zFile==0 ) return TCL_ERROR; memcpy(zFile, argv[2], nFile+1); zFile[nFile+1] = 0; |
︙ | ︙ |
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 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 | /* ** Each thread is controlled by an instance of the following ** structure. */ typedef struct Thread Thread; struct Thread { /* The first group of fields are writable by the master and read-only ** 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 ** master. */ 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 */ const char *argv[100]; /* result columns */ const char *colv[100]; /* result column names */ }; /* ** There can be as many as 26 threads running at once. Each is named ** by a capital letter: A, B, C, ..., Y, Z. */ #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)); sqlite3_close(p->db); p->db = 0; } p->pStmt = 0; p->completed = 1; while( p->opnum<=p->completed ) sched_yield(); while( p->xOp ){ if( p->zErr && p->zErr!=p->zStaticErr ){ sqlite3_free(p->zErr); p->zErr = 0; } (*p->xOp)(p); p->completed++; while( p->opnum<=p->completed ) sched_yield(); } if( p->pStmt ){ sqlite3_finalize(p->pStmt); p->pStmt = 0; } if( p->db ){ sqlite3_close(p->db); p->db = 0; } if( p->zErr && p->zErr!=p->zStaticErr ){ sqlite3_free(p->zErr); p->zErr = 0; } p->completed++; #ifndef SQLITE_OMIT_DEPRECATED sqlite3_thread_cleanup(); #endif return 0; } |
︙ | ︙ | |||
172 173 174 175 176 177 178 | return TCL_OK; } /* ** Wait for a thread to reach its idle state. */ static void test_thread_wait(Thread *p){ | < < | 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | 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. */ |
︙ | ︙ | |||
464 465 466 467 468 469 470 | 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]); | < | 452 453 454 455 456 457 458 459 460 461 462 463 464 465 | 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; } /* ** This procedure runs in the thread to step the virtual machine. */ |
︙ | ︙ | |||
516 517 518 519 520 521 522 | 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; | < | 503 504 505 506 507 508 509 510 511 512 513 514 515 516 | 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. */ |
︙ | ︙ | |||
561 562 563 564 565 566 567 | 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; | < | 547 548 549 550 551 552 553 554 555 556 557 558 559 560 | 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; } /* ** Usage: thread_swap ID ID ** |
︙ | ︙ |
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 | return g.iDeviceCharacteristics; } /* ** Pass-throughs for WAL support. */ static int cfShmLock(sqlite3_file *pFile, int ofst, int n, int flags){ return sqlite3OsShmLock(((CrashFile*)pFile)->pRealFile, ofst, n, flags); } static void cfShmBarrier(sqlite3_file *pFile){ sqlite3OsShmBarrier(((CrashFile*)pFile)->pRealFile); } static int cfShmUnmap(sqlite3_file *pFile, int delFlag){ return sqlite3OsShmUnmap(((CrashFile*)pFile)->pRealFile, 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 */ ){ return sqlite3OsShmMap(((CrashFile*)pFile)->pRealFile, iRegion, sz, w, pp); } static const sqlite3_io_methods CrashFileVtab = { 2, /* iVersion */ cfClose, /* xClose */ cfRead, /* xRead */ cfWrite, /* xWrite */ |
︙ | ︙ |
Added src/test7.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 | /* ** 2006 January 09 ** ** 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 the client/server version of the SQLite library. ** Derived from test4.c. */ #include "sqliteInt.h" #if defined(INCLUDE_SQLITE_TCL_H) # include "sqlite_tcl.h" #else # include "tcl.h" #endif /* ** This test only works on UNIX with a SQLITE_THREADSAFE build that includes ** the SQLITE_SERVER option. */ #if defined(SQLITE_SERVER) && !defined(SQLITE_OMIT_SHARED_CACHE) && \ SQLITE_OS_UNIX && SQLITE_THREADSAFE #include <stdlib.h> #include <string.h> #include <pthread.h> #include <sched.h> #include <ctype.h> /* ** Interfaces defined in server.c */ int sqlite3_client_open(const char*, sqlite3**); int sqlite3_client_prepare(sqlite3*,const char*,int, sqlite3_stmt**,const char**); int sqlite3_client_step(sqlite3_stmt*); int sqlite3_client_reset(sqlite3_stmt*); int sqlite3_client_finalize(sqlite3_stmt*); int sqlite3_client_close(sqlite3*); int sqlite3_server_start(void); int sqlite3_server_stop(void); void sqlite3_server_start2(int *pnDecr); /* ** 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 supervisor thread ** and read-only to the client threads */ char *zFilename; /* Name of database file */ void (*xOp)(Thread*); /* next operation to do */ char *zArg; /* argument usable by xOp */ volatile int opnum; /* Operation number */ volatile int busy; /* True if this thread is in use */ /* The next group of fields are writable by the client threads ** but read-only to the superviser thread. */ volatile 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 */ const char *argv[100]; /* result columns */ const char *colv[100]; /* result column names */ /* Initialized to 1 by the supervisor thread when the client is ** created, and then deemed read-only to the supervisor thread. ** Is set to 0 by the server thread belonging to this client ** just before it exits. */ int nServer; /* Number of server threads running */ }; /* ** There can be as many as 26 threads running at once. Each is named ** by a capital letter: A, B, C, ..., Y, Z. */ #define N_THREAD 26 static Thread threadset[N_THREAD]; /* ** The main loop for a thread. Threads use busy waiting. */ static void *client_main(void *pArg){ Thread *p = (Thread*)pArg; if( p->db ){ sqlite3_client_close(p->db); } sqlite3_client_open(p->zFilename, &p->db); if( SQLITE_OK!=sqlite3_errcode(p->db) ){ p->zErr = strdup(sqlite3_errmsg(p->db)); sqlite3_client_close(p->db); p->db = 0; } p->pStmt = 0; p->completed = 1; while( p->opnum<=p->completed ) sched_yield(); while( p->xOp ){ if( p->zErr && p->zErr!=p->zStaticErr ){ sqlite3_free(p->zErr); p->zErr = 0; } (*p->xOp)(p); p->completed++; while( p->opnum<=p->completed ) sched_yield(); } if( p->pStmt ){ sqlite3_client_finalize(p->pStmt); p->pStmt = 0; } if( p->db ){ sqlite3_client_close(p->db); p->db = 0; } if( p->zErr && p->zErr!=p->zStaticErr ){ sqlite3_free(p->zErr); p->zErr = 0; } p->completed++; #ifndef SQLITE_OMIT_DEPRECATED sqlite3_thread_cleanup(); #endif return 0; } /* ** Get a thread ID which is an upper case letter. Return the index. ** If the argument is not a valid thread ID put an error message in ** the interpreter and return -1. */ static int parse_client_id(Tcl_Interp *interp, const char *zArg){ if( zArg==0 || zArg[0]==0 || zArg[1]!=0 || !isupper((unsigned char)zArg[0]) ){ Tcl_AppendResult(interp, "thread ID must be an upper case letter", 0); return -1; } return zArg[0] - 'A'; } /* ** Usage: client_create NAME FILENAME ** ** NAME should be an upper case letter. Start the thread running with ** an open connection to the given database. */ static int SQLITE_TCLAPI tcl_client_create( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; pthread_t x; int rc; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID FILENAME", 0); return TCL_ERROR; } i = parse_client_id(interp, argv[1]); if( i<0 ) return TCL_ERROR; if( threadset[i].busy ){ Tcl_AppendResult(interp, "thread ", argv[1], " is already running", 0); 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, client_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); if( threadset[i].nServer==0 ){ threadset[i].nServer = 1; sqlite3_server_start2(&threadset[i].nServer); } return TCL_OK; } /* ** Wait for a thread to reach its idle state. */ static void client_wait(Thread *p){ while( p->opnum>p->completed ) sched_yield(); } /* ** Usage: client_wait ID ** ** Wait on thread ID to reach its idle state. */ static int SQLITE_TCLAPI tcl_client_wait( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID", 0); return TCL_ERROR; } i = parse_client_id(interp, argv[1]); if( i<0 ) return TCL_ERROR; if( !threadset[i].busy ){ Tcl_AppendResult(interp, "no such thread", 0); return TCL_ERROR; } client_wait(&threadset[i]); return TCL_OK; } /* ** Stop a thread. */ static void stop_thread(Thread *p){ client_wait(p); p->xOp = 0; p->opnum++; client_wait(p); sqlite3_free(p->zArg); p->zArg = 0; sqlite3_free(p->zFilename); p->zFilename = 0; p->busy = 0; } /* ** Usage: client_halt ID ** ** Cause a client thread to shut itself down. Wait for the shutdown to be ** completed. If ID is "*" then stop all client threads. */ static int SQLITE_TCLAPI tcl_client_halt( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; 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 ){ stop_thread(&threadset[i]); } } }else{ i = parse_client_id(interp, argv[1]); if( i<0 ) return TCL_ERROR; if( !threadset[i].busy ){ Tcl_AppendResult(interp, "no such thread", 0); return TCL_ERROR; } stop_thread(&threadset[i]); } /* If no client threads are still running, also stop the server */ for(i=0; i<N_THREAD && threadset[i].busy==0; i++){} if( i>=N_THREAD ){ sqlite3_server_stop(); while( 1 ){ for(i=0; i<N_THREAD && threadset[i].nServer==0; i++); if( i==N_THREAD ) break; sched_yield(); } } return TCL_OK; } /* ** Usage: client_argc ID ** ** Wait on the most recent client_step to complete, then return the ** number of columns in the result set. */ static int SQLITE_TCLAPI tcl_client_argc( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; char zBuf[100]; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID", 0); return TCL_ERROR; } i = parse_client_id(interp, argv[1]); if( i<0 ) return TCL_ERROR; if( !threadset[i].busy ){ Tcl_AppendResult(interp, "no such thread", 0); return TCL_ERROR; } client_wait(&threadset[i]); sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", threadset[i].argc); Tcl_AppendResult(interp, zBuf, 0); return TCL_OK; } /* ** Usage: client_argv ID N ** ** Wait on the most recent client_step to complete, then return the ** value of the N-th columns in the result set. */ static int SQLITE_TCLAPI tcl_client_argv( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; int n; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID N", 0); return TCL_ERROR; } i = parse_client_id(interp, argv[1]); if( i<0 ) return TCL_ERROR; if( !threadset[i].busy ){ Tcl_AppendResult(interp, "no such thread", 0); return TCL_ERROR; } if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR; client_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; } /* ** Usage: client_colname ID N ** ** Wait on the most recent client_step to complete, then return the ** name of the N-th columns in the result set. */ static int SQLITE_TCLAPI tcl_client_colname( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; int n; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID N", 0); return TCL_ERROR; } i = parse_client_id(interp, argv[1]); if( i<0 ) return TCL_ERROR; if( !threadset[i].busy ){ Tcl_AppendResult(interp, "no such thread", 0); return TCL_ERROR; } if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR; client_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; } extern const char *sqlite3ErrName(int); /* ** Usage: client_result ID ** ** Wait on the most recent operation to complete, then return the ** result code from that operation. */ static int SQLITE_TCLAPI tcl_client_result( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; const char *zName; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID", 0); return TCL_ERROR; } i = parse_client_id(interp, argv[1]); if( i<0 ) return TCL_ERROR; if( !threadset[i].busy ){ Tcl_AppendResult(interp, "no such thread", 0); return TCL_ERROR; } client_wait(&threadset[i]); zName = sqlite3ErrName(threadset[i].rc); Tcl_AppendResult(interp, zName, 0); return TCL_OK; } /* ** Usage: client_error ID ** ** Wait on the most recent operation to complete, then return the ** error string. */ static int SQLITE_TCLAPI tcl_client_error( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID", 0); return TCL_ERROR; } i = parse_client_id(interp, argv[1]); if( i<0 ) return TCL_ERROR; if( !threadset[i].busy ){ Tcl_AppendResult(interp, "no such thread", 0); return TCL_ERROR; } client_wait(&threadset[i]); Tcl_AppendResult(interp, threadset[i].zErr, 0); return TCL_OK; } /* ** This procedure runs in the thread to compile an SQL statement. */ static void do_compile(Thread *p){ if( p->db==0 ){ p->zErr = p->zStaticErr = "no database is open"; p->rc = SQLITE_ERROR; return; } if( p->pStmt ){ sqlite3_client_finalize(p->pStmt); p->pStmt = 0; } p->rc = sqlite3_client_prepare(p->db, p->zArg, -1, &p->pStmt, 0); } /* ** Usage: client_compile ID SQL ** ** Compile a new virtual machine. */ static int SQLITE_TCLAPI tcl_client_compile( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID SQL", 0); return TCL_ERROR; } i = parse_client_id(interp, argv[1]); if( i<0 ) return TCL_ERROR; if( !threadset[i].busy ){ Tcl_AppendResult(interp, "no such thread", 0); return TCL_ERROR; } client_wait(&threadset[i]); threadset[i].xOp = do_compile; sqlite3_free(threadset[i].zArg); threadset[i].zArg = sqlite3_mprintf("%s", argv[2]); threadset[i].opnum++; return TCL_OK; } /* ** This procedure runs in the thread to step the virtual machine. */ static void do_step(Thread *p){ int i; if( p->pStmt==0 ){ p->zErr = p->zStaticErr = "no virtual machine available"; p->rc = SQLITE_ERROR; return; } p->rc = sqlite3_client_step(p->pStmt); if( p->rc==SQLITE_ROW ){ p->argc = sqlite3_column_count(p->pStmt); for(i=0; i<sqlite3_data_count(p->pStmt); i++){ p->argv[i] = (char*)sqlite3_column_text(p->pStmt, i); } for(i=0; i<p->argc; i++){ p->colv[i] = sqlite3_column_name(p->pStmt, i); } } } /* ** Usage: client_step ID ** ** Advance the virtual machine by one step */ static int SQLITE_TCLAPI tcl_client_step( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " IDL", 0); return TCL_ERROR; } i = parse_client_id(interp, argv[1]); if( i<0 ) return TCL_ERROR; if( !threadset[i].busy ){ Tcl_AppendResult(interp, "no such thread", 0); return TCL_ERROR; } client_wait(&threadset[i]); threadset[i].xOp = do_step; threadset[i].opnum++; return TCL_OK; } /* ** This procedure runs in the thread to finalize a virtual machine. */ static void do_finalize(Thread *p){ if( p->pStmt==0 ){ p->zErr = p->zStaticErr = "no virtual machine available"; p->rc = SQLITE_ERROR; return; } p->rc = sqlite3_client_finalize(p->pStmt); p->pStmt = 0; } /* ** Usage: client_finalize ID ** ** Finalize the virtual machine. */ static int SQLITE_TCLAPI tcl_client_finalize( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " IDL", 0); return TCL_ERROR; } i = parse_client_id(interp, argv[1]); if( i<0 ) return TCL_ERROR; if( !threadset[i].busy ){ Tcl_AppendResult(interp, "no such thread", 0); return TCL_ERROR; } client_wait(&threadset[i]); threadset[i].xOp = do_finalize; sqlite3_free(threadset[i].zArg); threadset[i].zArg = 0; threadset[i].opnum++; return TCL_OK; } /* ** This procedure runs in the thread to reset a virtual machine. */ static void do_reset(Thread *p){ if( p->pStmt==0 ){ p->zErr = p->zStaticErr = "no virtual machine available"; p->rc = SQLITE_ERROR; return; } p->rc = sqlite3_client_reset(p->pStmt); p->pStmt = 0; } /* ** Usage: client_reset ID ** ** Finalize the virtual machine. */ static int SQLITE_TCLAPI tcl_client_reset( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " IDL", 0); return TCL_ERROR; } i = parse_client_id(interp, argv[1]); if( i<0 ) return TCL_ERROR; if( !threadset[i].busy ){ Tcl_AppendResult(interp, "no such thread", 0); return TCL_ERROR; } client_wait(&threadset[i]); threadset[i].xOp = do_reset; sqlite3_free(threadset[i].zArg); threadset[i].zArg = 0; threadset[i].opnum++; return TCL_OK; } /* ** Usage: client_swap ID ID ** ** Interchange the sqlite* pointer between two threads. */ static int SQLITE_TCLAPI tcl_client_swap( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int i, j; sqlite3 *temp; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID1 ID2", 0); return TCL_ERROR; } i = parse_client_id(interp, argv[1]); if( i<0 ) return TCL_ERROR; if( !threadset[i].busy ){ Tcl_AppendResult(interp, "no such thread", 0); return TCL_ERROR; } client_wait(&threadset[i]); j = parse_client_id(interp, argv[2]); if( j<0 ) return TCL_ERROR; if( !threadset[j].busy ){ Tcl_AppendResult(interp, "no such thread", 0); return TCL_ERROR; } client_wait(&threadset[j]); temp = threadset[i].db; threadset[i].db = threadset[j].db; threadset[j].db = temp; return TCL_OK; } /* ** Register commands with the TCL interpreter. */ int Sqlitetest7_Init(Tcl_Interp *interp){ static struct { char *zName; Tcl_CmdProc *xProc; } aCmd[] = { { "client_create", (Tcl_CmdProc*)tcl_client_create }, { "client_wait", (Tcl_CmdProc*)tcl_client_wait }, { "client_halt", (Tcl_CmdProc*)tcl_client_halt }, { "client_argc", (Tcl_CmdProc*)tcl_client_argc }, { "client_argv", (Tcl_CmdProc*)tcl_client_argv }, { "client_colname", (Tcl_CmdProc*)tcl_client_colname }, { "client_result", (Tcl_CmdProc*)tcl_client_result }, { "client_error", (Tcl_CmdProc*)tcl_client_error }, { "client_compile", (Tcl_CmdProc*)tcl_client_compile }, { "client_step", (Tcl_CmdProc*)tcl_client_step }, { "client_reset", (Tcl_CmdProc*)tcl_client_reset }, { "client_finalize", (Tcl_CmdProc*)tcl_client_finalize }, { "client_swap", (Tcl_CmdProc*)tcl_client_swap }, }; int i; for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); } return TCL_OK; } #else int Sqlitetest7_Init(Tcl_Interp *interp){ return TCL_OK; } #endif /* SQLITE_OS_UNIX */ |
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_master 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 | sqlite3_free(p); return 0; } typedef struct EchoModule EchoModule; struct EchoModule { Tcl_Interp *interp; | < | 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. */ |
︙ | ︙ | |||
1349 1350 1351 1352 1353 1354 1355 | /* ** 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){ | < < < | 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( |
︙ | ︙ | |||
1376 1377 1378 1379 1380 1381 1382 | 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; | < < | 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; |
︙ | ︙ |
Changes to src/test_bestindex.c.
︙ | ︙ | |||
97 98 99 100 101 102 103 | # include "sqlite_tcl.h" #else # include "tcl.h" #endif #ifndef SQLITE_OMIT_VIRTUALTABLE | < < < < < < < < < < | 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 | # include "sqlite_tcl.h" #else # include "tcl.h" #endif #ifndef SQLITE_OMIT_VIRTUALTABLE typedef struct tcl_vtab tcl_vtab; typedef struct tcl_cursor tcl_cursor; /* ** A fs virtual-table object */ struct tcl_vtab { sqlite3_vtab base; Tcl_Interp *interp; Tcl_Obj *pCmd; sqlite3 *db; }; /* A tcl cursor object */ struct tcl_cursor { sqlite3_vtab_cursor base; sqlite3_stmt *pStmt; /* Read data from here */ }; /* ** Dequote string z in place. */ static void tclDequote(char *z){ char q = z[0]; |
︙ | ︙ | |||
229 230 231 232 233 234 235 | *ppVtab = &pTab->base; return rc; } /* The xDisconnect and xDestroy methods are also the same */ static int tclDisconnect(sqlite3_vtab *pVtab){ tcl_vtab *pTab = (tcl_vtab*)pVtab; | < < < < < | 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | *ppVtab = &pTab->base; return rc; } /* The xDisconnect and xDestroy methods are also the same */ static int tclDisconnect(sqlite3_vtab *pVtab){ tcl_vtab *pTab = (tcl_vtab*)pVtab; Tcl_DecrRefCount(pTab->pCmd); sqlite3_free(pTab); return SQLITE_OK; } /* ** Open a new tcl cursor. |
︙ | ︙ | |||
310 311 312 313 314 315 316 | pArg = Tcl_NewObj(); Tcl_IncrRefCount(pArg); for(ii=0; ii<argc; ii++){ const char *zVal = (const char*)sqlite3_value_text(argv[ii]); Tcl_Obj *pVal; if( zVal==0 ){ | < < < < < < < < < < < < < < | 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 | pArg = Tcl_NewObj(); Tcl_IncrRefCount(pArg); for(ii=0; ii<argc; ii++){ const char *zVal = (const char*)sqlite3_value_text(argv[ii]); Tcl_Obj *pVal; if( zVal==0 ){ pVal = Tcl_NewObj(); }else{ pVal = Tcl_NewStringObj(zVal, -1); } Tcl_ListObjAppendElement(interp, pArg, pVal); } Tcl_ListObjAppendElement(interp, pScript, pArg); Tcl_DecrRefCount(pArg); |
︙ | ︙ | |||
399 400 401 402 403 404 405 | } static int tclEof(sqlite3_vtab_cursor *pVtabCursor){ tcl_cursor *pCsr = (tcl_cursor*)pVtabCursor; return (pCsr->pStmt==0); } | | > | | < > > > > > > > | | | | 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 | } static int tclEof(sqlite3_vtab_cursor *pVtabCursor){ tcl_cursor *pCsr = (tcl_cursor*)pVtabCursor; return (pCsr->pStmt==0); } static int tclBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ tcl_vtab *pTab = (tcl_vtab*)tab; Tcl_Interp *interp = pTab->interp; Tcl_Obj *pArg; Tcl_Obj *pScript; int ii; int rc = SQLITE_OK; pScript = Tcl_DuplicateObj(pTab->pCmd); Tcl_IncrRefCount(pScript); Tcl_ListObjAppendElement(interp, pScript, Tcl_NewStringObj("xBestIndex", -1)); pArg = Tcl_NewObj(); Tcl_IncrRefCount(pArg); for(ii=0; ii<pIdxInfo->nConstraint; ii++){ struct sqlite3_index_constraint const *pCons = &pIdxInfo->aConstraint[ii]; Tcl_Obj *pElem = Tcl_NewObj(); const char *zOp = "?"; Tcl_IncrRefCount(pElem); switch( pCons->op ){ case SQLITE_INDEX_CONSTRAINT_EQ: zOp = "eq"; break; case SQLITE_INDEX_CONSTRAINT_GT: |
︙ | ︙ | |||
442 443 444 445 446 447 448 | zOp = "isnot"; break; case SQLITE_INDEX_CONSTRAINT_ISNOTNULL: zOp = "isnotnull"; break; case SQLITE_INDEX_CONSTRAINT_ISNULL: zOp = "isnull"; break; case SQLITE_INDEX_CONSTRAINT_IS: zOp = "is"; break; | < < < < < | < < < | | | | < < < < < < | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | zOp = "isnot"; break; case SQLITE_INDEX_CONSTRAINT_ISNOTNULL: zOp = "isnotnull"; break; case SQLITE_INDEX_CONSTRAINT_ISNULL: zOp = "isnull"; break; case SQLITE_INDEX_CONSTRAINT_IS: zOp = "is"; break; } Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("op", -1)); Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj(zOp, -1)); Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("column", -1)); Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(pCons->iColumn)); Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("usable", -1)); Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(pCons->usable)); Tcl_ListObjAppendElement(0, pArg, pElem); Tcl_DecrRefCount(pElem); } Tcl_ListObjAppendElement(0, pScript, pArg); Tcl_DecrRefCount(pArg); pArg = Tcl_NewObj(); Tcl_IncrRefCount(pArg); for(ii=0; ii<pIdxInfo->nOrderBy; ii++){ struct sqlite3_index_orderby const *pOrder = &pIdxInfo->aOrderBy[ii]; Tcl_Obj *pElem = Tcl_NewObj(); Tcl_IncrRefCount(pElem); Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("column", -1)); Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(pOrder->iColumn)); Tcl_ListObjAppendElement(0, pElem, Tcl_NewStringObj("desc", -1)); Tcl_ListObjAppendElement(0, pElem, Tcl_NewIntObj(pOrder->desc)); Tcl_ListObjAppendElement(0, pArg, pElem); Tcl_DecrRefCount(pElem); } Tcl_ListObjAppendElement(0, pScript, pArg); Tcl_DecrRefCount(pArg); Tcl_ListObjAppendElement(0, pScript, Tcl_NewWideIntObj(pIdxInfo->colUsed)); rc = Tcl_EvalObjEx(interp, pScript, TCL_EVAL_GLOBAL); Tcl_DecrRefCount(pScript); if( rc!=TCL_OK ){ const char *zErr = Tcl_GetStringResult(interp); rc = SQLITE_ERROR; pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr); }else{ /* Analyze the scripts return value. The return value should be a tcl ** list object with an even number of elements. The first element of each |
︙ | ︙ | |||
654 655 656 657 658 659 660 | int nElem; rc = Tcl_ListObjGetElements(interp, pRes, &nElem, &apElem); if( rc!=TCL_OK ){ const char *zErr = Tcl_GetStringResult(interp); rc = SQLITE_ERROR; pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr); }else{ | < | 485 486 487 488 489 490 491 492 493 494 495 496 497 498 | int nElem; rc = Tcl_ListObjGetElements(interp, pRes, &nElem, &apElem); if( rc!=TCL_OK ){ const char *zErr = Tcl_GetStringResult(interp); rc = SQLITE_ERROR; pTab->base.zErrMsg = sqlite3_mprintf("%s", zErr); }else{ int iArgv = 1; for(ii=0; rc==SQLITE_OK && ii<nElem; ii+=2){ const char *zCmd = Tcl_GetString(apElem[ii]); Tcl_Obj *p = apElem[ii+1]; if( sqlite3_stricmp("cost", zCmd)==0 ){ rc = Tcl_GetDoubleFromObj(interp, p, &pIdxInfo->estimatedCost); }else |
︙ | ︙ | |||
708 709 710 711 712 713 714 | } } } return rc; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 538 539 540 541 542 543 544 545 546 547 548 549 550 551 | } } } return rc; } /* ** A virtual table module that provides read-only access to a ** Tcl global variable namespace. */ static sqlite3_module tclModule = { 0, /* iVersion */ tclConnect, |
︙ | ︙ | |||
808 809 810 811 812 813 814 | tclColumn, /* xColumn - read data */ tclRowid, /* xRowid - read data */ 0, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ | | | 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 | tclColumn, /* xColumn - read data */ tclRowid, /* xRowid - read data */ 0, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ }; /* ** Decode a pointer to an sqlite3 object. */ extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); |
︙ | ︙ |
Changes to src/test_config.c.
︙ | ︙ | |||
61 62 63 64 65 66 67 | #ifdef SQLITE_CASE_SENSITIVE_LIKE Tcl_SetVar2(interp, "sqlite_options","casesensitivelike","1",TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options","casesensitivelike","0",TCL_GLOBAL_ONLY); #endif | < < < < < < < | 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | #ifdef SQLITE_CASE_SENSITIVE_LIKE Tcl_SetVar2(interp, "sqlite_options","casesensitivelike","1",TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options","casesensitivelike","0",TCL_GLOBAL_ONLY); #endif #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT Tcl_SetVar2(interp, "sqlite_options", "curdir", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "curdir", "0", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_WIN32_MALLOC |
︙ | ︙ | |||
151 152 153 154 155 156 157 | #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 | | < < < < < < | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | #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 #ifdef SQLITE_ENABLE_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_MEMSYS3 Tcl_SetVar2(interp, "sqlite_options", "mem3", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "mem3", "0", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_ENABLE_MEMSYS5 |
︙ | ︙ | |||
229 230 231 232 233 234 235 | #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 | | < < < < < < > > > > | 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 | #ifdef SQLITE_ENABLE_ATOMIC_WRITE Tcl_SetVar2(interp, "sqlite_options", "atomicwrite", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "atomicwrite", "0", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_ENABLE_JSON1 Tcl_SetVar2(interp, "sqlite_options", "json1", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "json1", "0", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_HAS_CODEC Tcl_SetVar2(interp, "sqlite_options", "has_codec", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "has_codec", "0", TCL_GLOBAL_ONLY); #endif #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 |
︙ | ︙ | |||
585 586 587 588 589 590 591 | #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 | | > > > > > > | 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 | #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 #ifdef SQLITE_ENABLE_SESSION 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_STAT3) && !defined(SQLITE_ENABLE_STAT4) Tcl_SetVar2(interp, "sqlite_options", "stat3", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "stat3", "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 | return SQLITE_IOERR_READ; } nRead = read(p->fd, zBuf, iAmt); if( nRead==iAmt ){ return SQLITE_OK; }else if( nRead>=0 ){ | < < < | 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; } /* |
︙ | ︙ | |||
368 369 370 371 372 373 374 | return SQLITE_OK; } /* ** No xFileControl() verbs are implemented by this VFS. */ static int demoFileControl(sqlite3_file *pFile, int op, void *pArg){ | | | 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 | return SQLITE_OK; } /* ** No xFileControl() verbs are implemented by this VFS. */ static int demoFileControl(sqlite3_file *pFile, int op, void *pArg){ return SQLITE_OK; } /* ** 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. */ |
︙ | ︙ | |||
457 458 459 460 461 462 463 | int rc; /* Return code */ rc = unlink(zPath); if( rc!=0 && errno==ENOENT ) return SQLITE_OK; if( rc==0 && dirSync ){ int dfd; /* File descriptor open on directory */ | | > | | | < | | | | | | < | 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 | int rc; /* Return code */ rc = unlink(zPath); if( rc!=0 && errno==ENOENT ) return SQLITE_OK; if( rc==0 && dirSync ){ int dfd; /* File descriptor open on directory */ int i; /* Iterator variable */ char zDir[MAXPATHNAME+1]; /* Name of directory containing file zPath */ /* Figure out the directory name from the path of the file deleted. */ sqlite3_snprintf(MAXPATHNAME, zDir, "%s", zPath); zDir[MAXPATHNAME] = '\0'; for(i=strlen(zDir); i>1 && zDir[i]!='/'; i++); zDir[i] = '\0'; /* Open a file-descriptor on the directory. Sync. Close. */ dfd = open(zDir, O_RDONLY, 0); if( dfd<0 ){ rc = -1; }else{ rc = fsync(dfd); close(dfd); } } return (rc==0 ? SQLITE_OK : SQLITE_IOERR_DELETE); } #ifndef F_OK # define F_OK 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 sqlite3OsShmLock(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 sqlite3OsShmMap(p->pReal, iRegion, szRegion, isWrite, pp); } static void devsymShmBarrier(sqlite3_file *pFile){ devsym_file *p = (devsym_file *)pFile; sqlite3OsShmBarrier(p->pReal); } static int devsymShmUnmap(sqlite3_file *pFile, int delFlag){ devsym_file *p = (devsym_file *)pFile; return sqlite3OsShmUnmap(p->pReal, delFlag); } /* ** Open an devsym file handle. */ |
︙ | ︙ | |||
501 502 503 504 505 506 507 | }else{ g.iSectorSize = 512; } } void devsym_unregister(){ sqlite3_vfs_unregister(&devsym_vfs); | < | 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 ){ |
︙ | ︙ |
Changes to src/test_func.c.
︙ | ︙ | |||
495 496 497 498 499 500 501 | u64 iSerialType; Mem mem; memset(&mem, 0, sizeof(mem)); mem.db = db; mem.enc = ENC(db); pHdr += sqlite3GetVarint(pHdr, &iSerialType); | | < | 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 | u64 iSerialType; Mem mem; memset(&mem, 0, sizeof(mem)); mem.db = db; mem.enc = ENC(db); pHdr += sqlite3GetVarint(pHdr, &iSerialType); pBody += sqlite3VdbeSerialGet(pBody, (u32)iSerialType, &mem); if( iCurrent==iIdx ){ sqlite3_result_value(context, &mem); } if( mem.szMalloc ) sqlite3DbFree(db, mem.zMalloc); } |
︙ | ︙ | |||
544 545 546 547 548 549 550 | u64 iSerialType; Mem mem; memset(&mem, 0, sizeof(mem)); mem.db = db; mem.enc = ENC(db); pHdr += sqlite3GetVarint(pHdr, &iSerialType); | | < | 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 | u64 iSerialType; Mem mem; memset(&mem, 0, sizeof(mem)); mem.db = db; mem.enc = ENC(db); pHdr += sqlite3GetVarint(pHdr, &iSerialType); pBody += sqlite3VdbeSerialGet(pBody, (u32)iSerialType, &mem); switch( sqlite3_value_type(&mem) ){ case SQLITE_TEXT: pVal = Tcl_NewStringObj((const char*)sqlite3_value_text(&mem), -1); break; case SQLITE_BLOB: { |
︙ | ︙ |
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( 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( 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+3 ); 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 | y <<= 7; } x += y * (*q++); *v = (sqlite_int64) x; return (int) (q - (unsigned char *)p); } | < < < < < < < < < < < | 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. */ |
︙ | ︙ | |||
374 375 376 377 378 379 380 | 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; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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; } |
Changes to src/test_malloc.c.
︙ | ︙ | |||
107 108 109 110 111 112 113 114 115 116 117 118 119 120 | static void *faultsimRealloc(void *pOld, int n){ 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. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | static void *faultsimRealloc(void *pOld, int n){ void *p = 0; if( !faultsimStep() ){ p = memfault.m.xRealloc(pOld, n); } return p; } /* ** The following method calls are passed directly through to the underlying ** malloc system: ** ** xFree ** xSize ** xRoundup ** xInit ** xShutdown */ static void faultsimFree(void *p){ memfault.m.xFree(p); } static int faultsimSize(void *p){ return memfault.m.xSize(p); } static int faultsimRoundup(int n){ return memfault.m.xRoundup(n); } static int faultsimInit(void *p){ return memfault.m.xInit(memfault.m.pAppData); } static void faultsimShutdown(void *p){ memfault.m.xShutdown(memfault.m.pAppData); } /* ** 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. */ |
︙ | ︙ | |||
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | } /* ** 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 ){ | > > > > > > > > > > < < < | 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 | } /* ** Add or remove the fault-simulation layer using sqlite3_config(). If ** the argument is non-zero, the */ static int faultsimInstall(int install){ static struct sqlite3_mem_methods m = { faultsimMalloc, /* xMalloc */ faultsimFree, /* xFree */ faultsimRealloc, /* xRealloc */ faultsimSize, /* xSize */ faultsimRoundup, /* xRoundup */ faultsimInit, /* xInit */ faultsimShutdown, /* xShutdown */ 0 /* pAppData */ }; 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 ){ 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 | 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; pGroup->aReal[iChunk].z = z = sqlite3_malloc64( n+5 ); if( z==0 ){ return SQLITE_NOMEM; } multiplexFilename(pGroup->zName, pGroup->nName, pGroup->flags, iChunk, z); } return SQLITE_OK; } /* Translate an sqlite3_file* that is really a multiplexGroup* into ** the sqlite3_file* for the underlying original VFS. ** |
︙ | ︙ | |||
437 438 439 440 441 442 443 | 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); } | | | 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 | 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(pGroup->aReal[iChunk].z); memset(&pGroup->aReal[iChunk], 0, sizeof(pGroup->aReal[iChunk])); } /* ** Deallocate memory held by a multiplexGroup */ static void multiplexFreeComponents(multiplexGroup *pGroup){ |
︙ | ︙ | |||
529 530 531 532 533 534 535 | #else int sqlite3PendingByte = 0x40000000; #endif while( (sqlite3PendingByte % pGroup->szChunk)>=(pGroup->szChunk-65536) ){ pGroup->szChunk += 65536; } } | | | | 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 | #else int sqlite3PendingByte = 0x40000000; #endif while( (sqlite3PendingByte % pGroup->szChunk)>=(pGroup->szChunk-65536) ){ pGroup->szChunk += 65536; } } pGroup->flags = flags; 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_MASTER_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. */ |
︙ | ︙ | |||
587 588 589 590 591 592 593 | } } } } if( rc==SQLITE_OK ){ if( pSubOpen->pMethods->iVersion==1 ){ | | | | 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 | } } } } if( rc==SQLITE_OK ){ if( pSubOpen->pMethods->iVersion==1 ){ pMultiplexOpen->base.pMethods = &gMultiplex.sIoMethodsV1; }else{ pMultiplexOpen->base.pMethods = &gMultiplex.sIoMethodsV2; } }else{ multiplexFreeComponents(pGroup); sqlite3_free(pGroup); } } sqlite3_free(zToFree); |
︙ | ︙ | |||
958 959 960 961 962 963 964 | /* ** 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. */ | < < < < < < < < < < < | | | | | | | | | | | | | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | /* ** 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_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; } /* 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_master", "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_MASTER_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_MASTER_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_master (or sqlite_temp_master) 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_master WHERE type='table'" ); }else{ sqlite3_stmt *pDbList = pCur->pDbList; zSql = sqlite3_mprintf( "SELECT name FROM %Q.sqlite_master WHERE type='table'", sqlite3_column_text(pDbList, 1) ); } if( !zSql ){ rc = SQLITE_NOMEM; goto next_exit; } |
︙ | ︙ |
Added src/test_server.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 | /* ** 2006 January 07 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains demonstration code. Nothing in this file gets compiled ** or linked into the SQLite library unless you use a non-standard option: ** ** -DSQLITE_SERVER=1 ** ** The configure script will never generate a Makefile with the option ** above. You will need to manually modify the Makefile if you want to ** include any of the code from this file in your project. Or, at your ** option, you may copy and paste the code from this file and ** thereby avoiding a recompile of SQLite. ** ** ** This source file demonstrates how to use SQLite to create an SQL database ** server thread in a multiple-threaded program. One or more client threads ** send messages to the server thread and the server thread processes those ** messages in the order received and returns the results to the client. ** ** One might ask: "Why bother? Why not just let each thread connect ** to the database directly?" There are a several of reasons to ** prefer the client/server approach. ** ** (1) Some systems (ex: Redhat9) have broken threading implementations ** that prevent SQLite database connections from being used in ** a thread different from the one where they were created. With ** the client/server approach, all database connections are created ** and used within the server thread. Client calls to the database ** can be made from multiple threads (though not at the same time!) ** ** (2) Beginning with SQLite version 3.3.0, when two or more ** connections to the same database occur within the same thread, ** they can optionally share their database cache. This reduces ** I/O and memory requirements. Cache shared is controlled using ** the sqlite3_enable_shared_cache() API. ** ** (3) Database connections on a shared cache use table-level locking ** instead of file-level locking for improved concurrency. ** ** (4) Database connections on a shared cache can by optionally ** set to READ UNCOMMITTED isolation. (The default isolation for ** SQLite is SERIALIZABLE.) When this occurs, readers will ** never be blocked by a writer and writers will not be ** blocked by readers. There can still only be a single writer ** at a time, but multiple readers can simultaneously exist with ** that writer. This is a huge increase in concurrency. ** ** To summarize the rational for using a client/server approach: prior ** to SQLite version 3.3.0 it probably was not worth the trouble. But ** with SQLite version 3.3.0 and beyond you can get significant performance ** and concurrency improvements and memory usage reductions by going ** client/server. ** ** Note: The extra features of version 3.3.0 described by points (2) ** through (4) above are only available if you compile without the ** option -DSQLITE_OMIT_SHARED_CACHE. ** ** Here is how the client/server approach works: The database server ** thread is started on this procedure: ** ** void *sqlite3_server(void *NotUsed); ** ** The sqlite_server procedure runs as long as the g.serverHalt variable ** is false. A mutex is used to make sure no more than one server runs ** at a time. The server waits for messages to arrive on a message ** queue and processes the messages in order. ** ** Two convenience routines are provided for starting and stopping the ** server thread: ** ** void sqlite3_server_start(void); ** void sqlite3_server_stop(void); ** ** Both of the convenience routines return immediately. Neither will ** ever give an error. If a server is already started or already halted, ** then the routines are effectively no-ops. ** ** Clients use the following interfaces: ** ** sqlite3_client_open ** sqlite3_client_prepare ** sqlite3_client_step ** sqlite3_client_reset ** sqlite3_client_finalize ** sqlite3_client_close ** ** These interfaces work exactly like the standard core SQLite interfaces ** having the same names without the "_client_" infix. Many other SQLite ** interfaces can be used directly without having to send messages to the ** server as long as SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined. ** The following interfaces fall into this second category: ** ** sqlite3_bind_* ** sqlite3_changes ** sqlite3_clear_bindings ** sqlite3_column_* ** sqlite3_complete ** sqlite3_create_collation ** sqlite3_create_function ** sqlite3_data_count ** sqlite3_db_handle ** sqlite3_errcode ** sqlite3_errmsg ** sqlite3_last_insert_rowid ** sqlite3_total_changes ** sqlite3_transfer_bindings ** ** A single SQLite connection (an sqlite3* object) or an SQLite statement ** (an sqlite3_stmt* object) should only be passed to a single interface ** function at a time. The connections and statements can be passed from ** any thread to any of the functions listed in the second group above as ** long as the same connection is not in use by two threads at once and ** as long as SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined. Additional ** information about the SQLITE_ENABLE_MEMORY_MANAGEMENT constraint is ** below. ** ** The busy handler for all database connections should remain turned ** off. That means that any lock contention will cause the associated ** sqlite3_client_step() call to return immediately with an SQLITE_BUSY ** error code. If a busy handler is enabled and lock contention occurs, ** then the entire server thread will block. This will cause not only ** the requesting client to block but every other database client as ** well. It is possible to enhance the code below so that lock ** contention will cause the message to be placed back on the top of ** the queue to be tried again later. But such enhanced processing is ** not included here, in order to keep the example simple. ** ** This example code assumes the use of pthreads. Pthreads ** implementations are available for windows. (See, for example ** http://sourceware.org/pthreads-win32/announcement.html.) Or, you ** can translate the locking and thread synchronization code to use ** windows primitives easily enough. The details are left as an ** exercise to the reader. ** **** Restrictions Associated With SQLITE_ENABLE_MEMORY_MANAGEMENT **** ** ** If you compile with SQLITE_ENABLE_MEMORY_MANAGEMENT defined, then ** SQLite includes code that tracks how much memory is being used by ** each thread. These memory counts can become confused if memory ** is allocated by one thread and then freed by another. For that ** reason, when SQLITE_ENABLE_MEMORY_MANAGEMENT is used, all operations ** that might allocate or free memory should be performanced in the same ** thread that originally created the database connection. In that case, ** many of the operations that are listed above as safe to be performed ** in separate threads would need to be sent over to the server to be ** done there. If SQLITE_ENABLE_MEMORY_MANAGEMENT is defined, then ** the following functions can be used safely from different threads ** without messing up the allocation counts: ** ** sqlite3_bind_parameter_name ** sqlite3_bind_parameter_index ** sqlite3_changes ** sqlite3_column_blob ** sqlite3_column_count ** sqlite3_complete ** sqlite3_data_count ** sqlite3_db_handle ** sqlite3_errcode ** sqlite3_errmsg ** sqlite3_last_insert_rowid ** sqlite3_total_changes ** ** The remaining functions are not thread-safe when memory management ** is enabled. So one would have to define some new interface routines ** along the following lines: ** ** sqlite3_client_bind_* ** sqlite3_client_clear_bindings ** sqlite3_client_column_* ** sqlite3_client_create_collation ** sqlite3_client_create_function ** sqlite3_client_transfer_bindings ** ** The example code in this file is intended for use with memory ** management turned off. So the implementation of these additional ** client interfaces is left as an exercise to the reader. ** ** It may seem surprising to the reader that the list of safe functions ** above does not include things like sqlite3_bind_int() or ** sqlite3_column_int(). But those routines might, in fact, allocate ** or deallocate memory. In the case of sqlite3_bind_int(), if the ** parameter was previously bound to a string that string might need ** to be deallocated before the new integer value is inserted. In ** the case of sqlite3_column_int(), the value of the column might be ** a UTF-16 string which will need to be converted to UTF-8 then into ** an integer. */ /* Include this to get the definition of SQLITE_THREADSAFE, in the ** case that default values are used. */ #include "sqliteInt.h" /* ** Only compile the code in this file on UNIX with a SQLITE_THREADSAFE build ** and only if the SQLITE_SERVER macro is defined. */ #if defined(SQLITE_SERVER) && !defined(SQLITE_OMIT_SHARED_CACHE) #if SQLITE_OS_UNIX && SQLITE_THREADSAFE /* ** We require only pthreads and the public interface of SQLite. */ #include <pthread.h> #include "sqlite3.h" /* ** Messages are passed from client to server and back again as ** instances of the following structure. */ typedef struct SqlMessage SqlMessage; struct SqlMessage { int op; /* Opcode for the message */ sqlite3 *pDb; /* The SQLite connection */ sqlite3_stmt *pStmt; /* A specific statement */ int errCode; /* Error code returned */ const char *zIn; /* Input filename or SQL statement */ int nByte; /* Size of the zIn parameter for prepare() */ const char *zOut; /* Tail of the SQL statement */ SqlMessage *pNext; /* Next message in the queue */ SqlMessage *pPrev; /* Previous message in the queue */ pthread_mutex_t clientMutex; /* Hold this mutex to access the message */ pthread_cond_t clientWakeup; /* Signal to wake up the client */ }; /* ** Legal values for SqlMessage.op */ #define MSG_Open 1 /* sqlite3_open(zIn, &pDb) */ #define MSG_Prepare 2 /* sqlite3_prepare(pDb, zIn, nByte, &pStmt, &zOut) */ #define MSG_Step 3 /* sqlite3_step(pStmt) */ #define MSG_Reset 4 /* sqlite3_reset(pStmt) */ #define MSG_Finalize 5 /* sqlite3_finalize(pStmt) */ #define MSG_Close 6 /* sqlite3_close(pDb) */ #define MSG_Done 7 /* Server has finished with this message */ /* ** State information about the server is stored in a static variable ** named "g" as follows: */ static struct ServerState { pthread_mutex_t queueMutex; /* Hold this mutex to access the msg queue */ pthread_mutex_t serverMutex; /* Held by the server while it is running */ pthread_cond_t serverWakeup; /* Signal this condvar to wake up the server */ volatile int serverHalt; /* Server halts itself when true */ SqlMessage *pQueueHead; /* Head of the message queue */ SqlMessage *pQueueTail; /* Tail of the message queue */ } g = { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, }; /* ** Send a message to the server. Block until we get a reply. ** ** The mutex and condition variable in the message are uninitialized ** when this routine is called. This routine takes care of ** initializing them and destroying them when it has finished. */ static void sendToServer(SqlMessage *pMsg){ /* Initialize the mutex and condition variable on the message */ pthread_mutex_init(&pMsg->clientMutex, 0); pthread_cond_init(&pMsg->clientWakeup, 0); /* Add the message to the head of the server's message queue. */ pthread_mutex_lock(&g.queueMutex); pMsg->pNext = g.pQueueHead; if( g.pQueueHead==0 ){ g.pQueueTail = pMsg; }else{ g.pQueueHead->pPrev = pMsg; } pMsg->pPrev = 0; g.pQueueHead = pMsg; pthread_mutex_unlock(&g.queueMutex); /* Signal the server that the new message has be queued, then ** block waiting for the server to process the message. */ pthread_mutex_lock(&pMsg->clientMutex); pthread_cond_signal(&g.serverWakeup); while( pMsg->op!=MSG_Done ){ pthread_cond_wait(&pMsg->clientWakeup, &pMsg->clientMutex); } pthread_mutex_unlock(&pMsg->clientMutex); /* Destroy the mutex and condition variable of the message. */ pthread_mutex_destroy(&pMsg->clientMutex); pthread_cond_destroy(&pMsg->clientWakeup); } /* ** The following 6 routines are client-side implementations of the ** core SQLite interfaces: ** ** sqlite3_open ** sqlite3_prepare ** sqlite3_step ** sqlite3_reset ** sqlite3_finalize ** sqlite3_close ** ** Clients should use the following client-side routines instead of ** the core routines above. ** ** sqlite3_client_open ** sqlite3_client_prepare ** sqlite3_client_step ** sqlite3_client_reset ** sqlite3_client_finalize ** sqlite3_client_close ** ** Each of these routines creates a message for the desired operation, ** sends that message to the server, waits for the server to process ** then message and return a response. */ int sqlite3_client_open(const char *zDatabaseName, sqlite3 **ppDb){ SqlMessage msg; msg.op = MSG_Open; msg.zIn = zDatabaseName; sendToServer(&msg); *ppDb = msg.pDb; return msg.errCode; } int sqlite3_client_prepare( sqlite3 *pDb, const char *zSql, int nByte, sqlite3_stmt **ppStmt, const char **pzTail ){ SqlMessage msg; msg.op = MSG_Prepare; msg.pDb = pDb; msg.zIn = zSql; msg.nByte = nByte; sendToServer(&msg); *ppStmt = msg.pStmt; if( pzTail ) *pzTail = msg.zOut; return msg.errCode; } int sqlite3_client_step(sqlite3_stmt *pStmt){ SqlMessage msg; msg.op = MSG_Step; msg.pStmt = pStmt; sendToServer(&msg); return msg.errCode; } int sqlite3_client_reset(sqlite3_stmt *pStmt){ SqlMessage msg; msg.op = MSG_Reset; msg.pStmt = pStmt; sendToServer(&msg); return msg.errCode; } int sqlite3_client_finalize(sqlite3_stmt *pStmt){ SqlMessage msg; msg.op = MSG_Finalize; msg.pStmt = pStmt; sendToServer(&msg); return msg.errCode; } int sqlite3_client_close(sqlite3 *pDb){ SqlMessage msg; msg.op = MSG_Close; msg.pDb = pDb; sendToServer(&msg); return msg.errCode; } /* ** This routine implements the server. To start the server, first ** make sure g.serverHalt is false, then create a new detached thread ** on this procedure. See the sqlite3_server_start() routine below ** for an example. This procedure loops until g.serverHalt becomes ** true. */ void *sqlite3_server(void *NotUsed){ if( pthread_mutex_trylock(&g.serverMutex) ){ return 0; /* Another server is already running */ } sqlite3_enable_shared_cache(1); while( !g.serverHalt ){ SqlMessage *pMsg; /* Remove the last message from the message queue. */ pthread_mutex_lock(&g.queueMutex); while( g.pQueueTail==0 && g.serverHalt==0 ){ pthread_cond_wait(&g.serverWakeup, &g.queueMutex); } pMsg = g.pQueueTail; if( pMsg ){ if( pMsg->pPrev ){ pMsg->pPrev->pNext = 0; }else{ g.pQueueHead = 0; } g.pQueueTail = pMsg->pPrev; } pthread_mutex_unlock(&g.queueMutex); if( pMsg==0 ) break; /* Process the message just removed */ pthread_mutex_lock(&pMsg->clientMutex); switch( pMsg->op ){ case MSG_Open: { pMsg->errCode = sqlite3_open(pMsg->zIn, &pMsg->pDb); break; } case MSG_Prepare: { pMsg->errCode = sqlite3_prepare(pMsg->pDb, pMsg->zIn, pMsg->nByte, &pMsg->pStmt, &pMsg->zOut); break; } case MSG_Step: { pMsg->errCode = sqlite3_step(pMsg->pStmt); break; } case MSG_Reset: { pMsg->errCode = sqlite3_reset(pMsg->pStmt); break; } case MSG_Finalize: { pMsg->errCode = sqlite3_finalize(pMsg->pStmt); break; } case MSG_Close: { pMsg->errCode = sqlite3_close(pMsg->pDb); break; } } /* Signal the client that the message has been processed. */ pMsg->op = MSG_Done; pthread_mutex_unlock(&pMsg->clientMutex); pthread_cond_signal(&pMsg->clientWakeup); } pthread_mutex_unlock(&g.serverMutex); return 0; } /* ** Start a server thread if one is not already running. If there ** is aleady a server thread running, the new thread will quickly ** die and this routine is effectively a no-op. */ void sqlite3_server_start(void){ pthread_t x; int rc; g.serverHalt = 0; rc = pthread_create(&x, 0, sqlite3_server, 0); if( rc==0 ){ pthread_detach(x); } } /* ** A wrapper around sqlite3_server() that decrements the int variable ** pointed to by the first argument after the sqlite3_server() call ** returns. */ static void *serverWrapper(void *pnDecr){ void *p = sqlite3_server(0); (*(int*)pnDecr)--; return p; } /* ** This function is the similar to sqlite3_server_start(), except that ** the integer pointed to by the first argument is decremented when ** the server thread exits. */ void sqlite3_server_start2(int *pnDecr){ pthread_t x; int rc; g.serverHalt = 0; rc = pthread_create(&x, 0, serverWrapper, (void*)pnDecr); if( rc==0 ){ pthread_detach(x); } } /* ** If a server thread is running, then stop it. If no server is ** running, this routine is effectively a no-op. ** ** This routine waits until the server has actually stopped before ** returning. */ void sqlite3_server_stop(void){ g.serverHalt = 1; pthread_cond_broadcast(&g.serverWakeup); pthread_mutex_lock(&g.serverMutex); pthread_mutex_unlock(&g.serverMutex); } #endif /* SQLITE_OS_UNIX && SQLITE_THREADSAFE */ #endif /* defined(SQLITE_SERVER) */ |
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_MASTER */ 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 *master = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER); assert( eType==0 || eType==1 || eType==2 ); assert( (eType==2)==(zSql==0) ); /* This is a database open command. */ if( eType==0 ){ sqlite3_mutex_enter(master); if( sqllogglobal.mutex==0 ){ sqllogglobal.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE); } sqlite3_mutex_leave(master); sqlite3_mutex_enter(sqllogglobal.mutex); if( sqllogglobal.bRec==0 && sqllogTraceDb(db) ){ sqlite3_mutex_enter(master); p = &sqllogglobal.aConn[sqllogglobal.nConn++]; p->fd = 0; p->db = db; p->iLog = sqllogglobal.iNextLog++; sqlite3_mutex_leave(master); /* 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(master); 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(master); /* 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.
︙ | ︙ | |||
60 61 62 63 64 65 66 67 68 69 70 71 72 73 | extern int Sqliteconfig_Init(Tcl_Interp*); extern int Sqlitetest1_Init(Tcl_Interp*); extern int Sqlitetest2_Init(Tcl_Interp*); extern int Sqlitetest3_Init(Tcl_Interp*); extern int Sqlitetest4_Init(Tcl_Interp*); extern int Sqlitetest5_Init(Tcl_Interp*); extern int Sqlitetest6_Init(Tcl_Interp*); extern int Sqlitetest8_Init(Tcl_Interp*); extern int Sqlitetest9_Init(Tcl_Interp*); extern int Sqlitetestasync_Init(Tcl_Interp*); extern int Sqlitetest_autoext_Init(Tcl_Interp*); extern int Sqlitetest_blob_Init(Tcl_Interp*); extern int Sqlitetest_demovfs_Init(Tcl_Interp *); extern int Sqlitetest_func_Init(Tcl_Interp*); | > | 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | extern int Sqliteconfig_Init(Tcl_Interp*); extern int Sqlitetest1_Init(Tcl_Interp*); extern int Sqlitetest2_Init(Tcl_Interp*); extern int Sqlitetest3_Init(Tcl_Interp*); extern int Sqlitetest4_Init(Tcl_Interp*); extern int Sqlitetest5_Init(Tcl_Interp*); extern int Sqlitetest6_Init(Tcl_Interp*); extern int Sqlitetest7_Init(Tcl_Interp*); extern int Sqlitetest8_Init(Tcl_Interp*); extern int Sqlitetest9_Init(Tcl_Interp*); extern int Sqlitetestasync_Init(Tcl_Interp*); extern int Sqlitetest_autoext_Init(Tcl_Interp*); extern int Sqlitetest_blob_Init(Tcl_Interp*); extern int Sqlitetest_demovfs_Init(Tcl_Interp *); extern int Sqlitetest_func_Init(Tcl_Interp*); |
︙ | ︙ | |||
82 83 84 85 86 87 88 | 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*); | < < | 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 | 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 *); 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; |
︙ | ︙ | |||
131 132 133 134 135 136 137 138 139 140 141 142 143 144 | Sqliteconfig_Init(interp); Sqlitetest1_Init(interp); Sqlitetest2_Init(interp); Sqlitetest3_Init(interp); Sqlitetest4_Init(interp); Sqlitetest5_Init(interp); Sqlitetest6_Init(interp); Sqlitetest8_Init(interp); Sqlitetest9_Init(interp); Sqlitetestasync_Init(interp); Sqlitetest_autoext_Init(interp); Sqlitetest_blob_Init(interp); Sqlitetest_demovfs_Init(interp); Sqlitetest_func_Init(interp); | > | 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | Sqliteconfig_Init(interp); Sqlitetest1_Init(interp); Sqlitetest2_Init(interp); Sqlitetest3_Init(interp); Sqlitetest4_Init(interp); Sqlitetest5_Init(interp); Sqlitetest6_Init(interp); Sqlitetest7_Init(interp); Sqlitetest8_Init(interp); Sqlitetest9_Init(interp); Sqlitetestasync_Init(interp); Sqlitetest_autoext_Init(interp); Sqlitetest_blob_Init(interp); Sqlitetest_demovfs_Init(interp); Sqlitetest_func_Init(interp); |
︙ | ︙ | |||
152 153 154 155 156 157 158 | SqlitetestThread_Init(interp); SqlitetestOnefile_Init(); SqlitetestOsinst_Init(interp); Sqlitetestbackup_Init(interp); Sqlitetestintarray_Init(interp); Sqlitetestvfs_Init(interp); Sqlitetestrtree_Init(interp); | < < | 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 | 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); 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 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; | > > > > > > > > > > > > > > > > | 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 | 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); #ifdef SQLITE_HAS_CODEC if( db && objc>=4 ){ const char *zKey; int nKey; int rc; zKey = Tcl_GetStringFromObj(objv[3], &nKey); rc = sqlite3_key(db, zKey, nKey); if( rc!=SQLITE_OK ){ char *zErrMsg = sqlite3_mprintf("error %d: %s", rc, sqlite3_errmsg(db)); sqlite3_close(db); Tcl_AppendResult(interp, zErrMsg, (char*)0); sqlite3_free(zErrMsg); return TCL_ERROR; } } #endif 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; |
︙ | ︙ | |||
374 375 376 377 378 379 380 | Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ Tcl_Time now; Tcl_GetTime(&now); Tcl_SetObjResult(interp, Tcl_NewIntObj(now.sec)); | < < < < < < < < < < < < < < < < < < < < < | 390 391 392 393 394 395 396 397 398 399 400 401 402 403 | Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ Tcl_Time now; Tcl_GetTime(&now); Tcl_SetObjResult(interp, Tcl_NewIntObj(now.sec)); UNUSED_PARAMETER(clientData); UNUSED_PARAMETER(objc); UNUSED_PARAMETER(objv); return TCL_OK; } /************************************************************************* |
︙ | ︙ | |||
634 635 636 637 638 639 640 | ** End of implementation of [sqlite3_blocking_step]. ************************************************************************/ /* ** Register commands with the TCL interpreter. */ int SqlitetestThread_Init(Tcl_Interp *interp){ | < < < < < | | < | > | > | < < < < < < < | 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 | ** End of implementation of [sqlite3_blocking_step]. ************************************************************************/ /* ** Register commands with the TCL interpreter. */ int SqlitetestThread_Init(Tcl_Interp *interp){ Tcl_CreateObjCommand(interp, "sqlthread", sqlthread_proc, 0, 0); Tcl_CreateObjCommand(interp, "clock_seconds", clock_seconds_proc, 0, 0); #if SQLITE_OS_UNIX && defined(SQLITE_ENABLE_UNLOCK_NOTIFY) Tcl_CreateObjCommand(interp, "sqlite3_blocking_step", blocking_step_proc,0,0); Tcl_CreateObjCommand(interp, "sqlite3_blocking_prepare_v2", blocking_prepare_v2_proc, (void *)1, 0); Tcl_CreateObjCommand(interp, "sqlite3_nonblocking_prepare_v2", blocking_prepare_v2_proc, 0, 0); #endif return TCL_OK; } #else int SqlitetestThread_Init(Tcl_Interp *interp){ return TCL_OK; } #endif |
Changes to src/test_vfs.c.
︙ | ︙ | |||
231 232 233 234 235 236 237 | { 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" }, | < | 231 232 233 234 235 236 237 238 239 240 241 242 243 244 | { 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" }, { -1, "SQLITE_OMIT" }, }; const char *z; int i; z = Tcl_GetStringResult(p->interp); |
︙ | ︙ | |||
481 482 483 484 485 486 487 | Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_LOCK_MASK ){ char zLock[30]; sqlite3_snprintf(sizeof(zLock),zLock,"%d",eLock); tvfsExecTcl(p, "xLock", Tcl_NewStringObj(pFd->zFilename, -1), Tcl_NewStringObj(zLock, -1), 0, 0); } | < < < | | 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 | Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_LOCK_MASK ){ char zLock[30]; sqlite3_snprintf(sizeof(zLock),zLock,"%d",eLock); tvfsExecTcl(p, "xLock", Tcl_NewStringObj(pFd->zFilename, -1), Tcl_NewStringObj(zLock, -1), 0, 0); } return sqlite3OsLock(pFd->pReal, eLock); } /* ** Unlock an tvfs-file. */ static int tvfsUnlock(sqlite3_file *pFile, int eLock){ TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_UNLOCK_MASK ){ char zLock[30]; sqlite3_snprintf(sizeof(zLock),zLock,"%d",eLock); tvfsExecTcl(p, "xUnlock", Tcl_NewStringObj(pFd->zFilename, -1), Tcl_NewStringObj(zLock, -1), 0, 0); } if( p->mask&TESTVFS_WRITE_MASK && tvfsInjectIoerr(p) ){ return SQLITE_IOERR_UNLOCK; } return sqlite3OsUnlock(pFd->pReal, eLock); } /* ** Check if another file-handle holds a RESERVED lock on an tvfs-file. |
︙ | ︙ | |||
552 553 554 555 556 557 558 | 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" }, | < | | 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 | 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); if( rc ) return rc; } } return sqlite3OsFileControl(pFd->pReal, op, pArg); } /* ** Return the sector-size in bytes for an tvfs-file. |
︙ | ︙ | |||
894 895 896 897 898 899 900 | void volatile **pp /* OUT: Mapped memory */ ){ int rc = SQLITE_OK; TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); if( p->isFullshm ){ | < | | 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 | void volatile **pp /* OUT: Mapped memory */ ){ int rc = SQLITE_OK; TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); if( p->isFullshm ){ return sqlite3OsShmMap(pFd->pReal, iPage, pgsz, isWrite, pp); } if( 0==pFd->pShm ){ rc = tvfsShmOpen(pFile); if( rc!=SQLITE_OK ){ return rc; } |
︙ | ︙ | |||
945 946 947 948 949 950 951 | int rc = SQLITE_OK; TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); int nLock; char zLock[80]; if( p->isFullshm ){ | < | | 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 | int rc = SQLITE_OK; TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData); int nLock; char zLock[80]; if( p->isFullshm ){ return sqlite3OsShmLock(pFd->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"); |
︙ | ︙ | |||
1010 1011 1012 1013 1014 1015 1016 | 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 ){ | < | < | | 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 | 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 ){ sqlite3OsShmBarrier(pFd->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 ){ return sqlite3OsShmUnmap(pFd->pReal, deleteFlag); } if( !pBuffer ) return SQLITE_OK; assert( pFd->pShmId && pFd->pShm ); if( p->pScript && p->mask&TESTVFS_SHMCLOSE_MASK ){ tvfsExecTcl(p, "xShmUnmap", |
︙ | ︙ | |||
1393 1394 1395 1396 1397 1398 1399 | 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); | < < | 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 | 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: |
︙ | ︙ |
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_KYWD 1 /* Alphabetics or '_'. Usable in a keyword */ #define CC_ID 2 /* unicode characters usable in IDs */ #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 | #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_ILLEGAL 27 /* Illegal character */ #define CC_NUL 28 /* 0x00 */ 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 */ 28, 27, 27, 27, 27, 27, 27, 27, 27, 7, 7, 27, 7, 7, 27, 27, /* 1x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, /* 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, 1, 1, 9, 27, 27, 27, 1, /* 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, 1, 1, 27, 10, 27, 25, 27, /* 8x */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 9x */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* Ax */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* Bx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* Cx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* Dx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* Ex */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* Fx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 #endif #ifdef SQLITE_EBCDIC /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */ /* 0x */ 27, 27, 27, 27, 27, 7, 27, 27, 27, 27, 27, 27, 7, 7, 27, 27, /* 1x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, /* 2x */ 27, 27, 27, 27, 27, 7, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, /* 3x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, /* 4x */ 7, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 26, 12, 17, 20, 10, /* 5x */ 24, 27, 27, 27, 27, 27, 27, 27, 27, 27, 15, 4, 21, 18, 19, 27, /* 6x */ 11, 16, 27, 27, 27, 27, 27, 27, 27, 27, 27, 23, 22, 1, 13, 6, /* 7x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 8, 5, 5, 5, 8, 14, 8, /* 8x */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27, /* 9x */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27, /* Ax */ 27, 25, 1, 1, 1, 1, 1, 0, 1, 1, 27, 27, 27, 27, 27, 27, /* Bx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 9, 27, 27, 27, 27, 27, /* Cx */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27, /* Dx */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27, /* Ex */ 27, 27, 1, 1, 1, 1, 1, 0, 1, 1, 27, 27, 27, 27, 27, 27, /* Fx */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 27, 27, 27, 27, 27, 27, #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 |
︙ | ︙ | |||
286 287 288 289 290 291 292 | return i; } case CC_MINUS: { if( z[1]=='-' ){ for(i=2; (c=z[i])!=0 && c!='\n'; i++){} *tokenType = TK_SPACE; /* IMP: R-22934-25134 */ return i; | < < < | 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | return i; } case CC_MINUS: { if( z[1]=='-' ){ for(i=2; (c=z[i])!=0 && c!='\n'; i++){} *tokenType = TK_SPACE; /* IMP: R-22934-25134 */ return i; } *tokenType = TK_MINUS; return 1; } case CC_LP: { *tokenType = TK_LP; return 1; |
︙ | ︙ | |||
423 424 425 426 427 428 429 | #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 */ | < | 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; |
︙ | ︙ | |||
500 501 502 503 504 505 506 | }else{ break; } } if( n==0 ) *tokenType = TK_ILLEGAL; return i; } | | | 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 | }else{ break; } } if( n==0 ) *tokenType = TK_ILLEGAL; return i; } case CC_KYWD: { 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; |
︙ | ︙ | |||
528 529 530 531 532 533 534 | } 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 */ | < < < < < < < < < < | > > > > | < | > | 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 | } 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; } default: { *tokenType = TK_ILLEGAL; return 1; } } while( IdChar(z[i]) ){ i++; } *tokenType = TK_ID; return i; } /* ** Run the parser on the given SQL string. The parser structure is ** passed in. An SQLITE_ status code is returned. If an error occurs ** then an and attempt is made to write an error message into ** memory obtained from sqlite3_malloc() and to make *pzErrMsg point to that ** error message. */ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){ 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 VVA_ONLY( u8 startedWithOom = db->mallocFailed ); assert( zSql!=0 ); mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH]; if( db->nVdbeActive==0 ){ 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); } |
︙ | ︙ | |||
603 604 605 606 607 608 609 | return SQLITE_NOMEM_BKPT; } #endif assert( pParse->pNewTable==0 ); assert( pParse->pNewTrigger==0 ); assert( pParse->nVar==0 ); assert( pParse->pVList==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 | return SQLITE_NOMEM_BKPT; } #endif assert( pParse->pNewTable==0 ); assert( pParse->pNewTrigger==0 ); assert( pParse->nVar==0 ); assert( pParse->pVList==0 ); pParse->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( db->u1.isInterrupted ){ pParse->rc = SQLITE_INTERRUPT; break; } if( tokenType==TK_SPACE ){ zSql += n; continue; } if( zSql[0]==0 ){ |
︙ | ︙ | |||
654 655 656 657 658 659 660 | assert( n==4 ); tokenType = analyzeOverKeyword((const u8*)&zSql[4], lastTokenParsed); }else if( tokenType==TK_FILTER ){ assert( n==6 ); tokenType = analyzeFilterKeyword((const u8*)&zSql[6], lastTokenParsed); #endif /* SQLITE_OMIT_WINDOWFUNC */ }else{ | < < < | | 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 | assert( n==4 ); tokenType = analyzeOverKeyword((const u8*)&zSql[4], lastTokenParsed); }else if( tokenType==TK_FILTER ){ assert( n==6 ); tokenType = analyzeFilterKeyword((const u8*)&zSql[6], lastTokenParsed); #endif /* SQLITE_OMIT_WINDOWFUNC */ }else{ sqlite3ErrorMsg(pParse, "unrecognized token: \"%.*s\"", n, zSql); break; } } pParse->sLastToken.z = zSql; pParse->sLastToken.n = n; sqlite3Parser(pEngine, tokenType, pParse->sLastToken); lastTokenParsed = tokenType; |
︙ | ︙ | |||
685 686 687 688 689 690 691 | sqlite3ParserFinalize(pEngine); #else sqlite3ParserFree(pEngine, sqlite3_free); #endif if( db->mallocFailed ){ pParse->rc = SQLITE_NOMEM_BKPT; } | | < | | > > > | > > > > > > > > > > > > > | | > > | > > > > > > > > > > | > | 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 | sqlite3ParserFinalize(pEngine); #else sqlite3ParserFree(pEngine, sqlite3_free); #endif if( db->mallocFailed ){ pParse->rc = SQLITE_NOMEM_BKPT; } if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){ pParse->zErrMsg = sqlite3MPrintf(db, "%s", sqlite3ErrStr(pParse->rc)); } assert( pzErrMsg!=0 ); if( pParse->zErrMsg ){ *pzErrMsg = pParse->zErrMsg; sqlite3_log(pParse->rc, "%s in \"%s\"", *pzErrMsg, pParse->zTail); pParse->zErrMsg = 0; nErr++; } pParse->zTail = zSql; if( pParse->pVdbe && pParse->nErr>0 && pParse->nested==0 ){ sqlite3VdbeDelete(pParse->pVdbe); pParse->pVdbe = 0; } #ifndef SQLITE_OMIT_SHARED_CACHE if( pParse->nested==0 ){ sqlite3DbFree(db, pParse->aTableLock); pParse->aTableLock = 0; pParse->nTableLock = 0; } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3_free(pParse->apVtabLock); #endif if( !IN_SPECIAL_PARSE ){ /* If the pParse->declareVtab flag is set, do not delete any table ** structure built up in pParse->pNewTable. The calling code (see vtab.c) ** will take responsibility for freeing the Table structure. */ sqlite3DeleteTable(db, pParse->pNewTable); } if( !IN_RENAME_OBJECT ){ sqlite3DeleteTrigger(db, pParse->pNewTrigger); } if( pParse->pWithToFree ) sqlite3WithDelete(db, pParse->pWithToFree); sqlite3DbFree(db, pParse->pVList); while( pParse->pAinc ){ AutoincInfo *p = pParse->pAinc; pParse->pAinc = p->pNext; sqlite3DbFreeNN(db, p); } while( pParse->pZombieTab ){ Table *p = pParse->pZombieTab; pParse->pZombieTab = p->pNextZombie; sqlite3DeleteTable(db, p); } db->pParse = pParse->pParentParse; pParse->pParentParse = 0; assert( nErr==0 || pParse->rc!=SQLITE_OK ); return nErr; } #ifdef SQLITE_ENABLE_NORMALIZE /* |
︙ | ︙ | |||
742 743 744 745 746 747 748 | 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 */ | | | 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 | 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 */ int 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 */ |
︙ | ︙ | |||
786 787 788 789 790 791 792 | nParenAtIN = nParen; } sqlite3_str_append(pStr, "(", 1); break; } case TK_RP: { if( iStartIN>0 && nParen==nParenAtIN ){ | | | 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 | nParenAtIN = nParen; } sqlite3_str_append(pStr, "(", 1); break; } case TK_RP: { if( iStartIN>0 && nParen==nParenAtIN ){ assert( pStr->nChar>=iStartIN ); pStr->nChar = iStartIN+1; sqlite3_str_append(pStr, "?,?,?", 5); iStartIN = 0; } nParen--; sqlite3_str_append(pStr, ")", 1); break; |
︙ | ︙ |
Changes to src/treeview.c.
︙ | ︙ | |||
20 21 22 23 24 25 26 | #include "sqliteInt.h" #ifdef SQLITE_DEBUG /* ** Add a new subitem to the tree. The moreToFollow flag indicates that this ** is not the last item in the tree. */ | | < | | | > | < | < < < | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | < < < < < < | | < | < | < | | < < < < < < | | | < < | | > | | | < < < | < < < < < < < | < < < < < < < < < < < < | | | | < < < | | | | | | | < | < | < < | | | | | | | | | | | | | | < | | | | | | | | < | | | | | | | < < < < | | < < | | < | < < < < < < < < < < < < < | < < | | < < < | | < < < < | 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 | #include "sqliteInt.h" #ifdef SQLITE_DEBUG /* ** Add a new subitem to the tree. The moreToFollow flag indicates that this ** is not the last item in the tree. */ static TreeView *sqlite3TreeViewPush(TreeView *p, u8 moreToFollow){ if( p==0 ){ p = sqlite3_malloc64( sizeof(*p) ); if( p==0 ) return 0; memset(p, 0, sizeof(*p)); }else{ p->iLevel++; } assert( moreToFollow==0 || moreToFollow==1 ); if( p->iLevel<sizeof(p->bLine) ) p->bLine[p->iLevel] = moreToFollow; return p; } /* ** Finished with one layer of the tree */ static void sqlite3TreeViewPop(TreeView *p){ if( p==0 ) return; p->iLevel--; if( p->iLevel<0 ) sqlite3_free(p); } /* ** Generate a single line of output for the tree, with a prefix that contains ** all the appropriate tree lines */ static void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){ va_list ap; int i; StrAccum acc; char zBuf[500]; sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0); if( p ){ for(i=0; i<p->iLevel && i<sizeof(p->bLine)-1; i++){ sqlite3_str_append(&acc, p->bLine[i] ? "| " : " ", 4); } 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 ); sqlite3_str_append(&acc, "\n", 1); } sqlite3StrAccumFinish(&acc); fprintf(stdout,"%s", zBuf); fflush(stdout); } /* ** Shorthand for starting a new tree item that consists of a single label */ static void sqlite3TreeViewItem(TreeView *p, const char *zLabel,u8 moreFollows){ p = sqlite3TreeViewPush(p, moreFollows); sqlite3TreeViewLine(p, "%s", zLabel); } /* ** Generate a human-readable description of a WITH clause. */ void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 moreToFollow){ int i; if( pWith==0 ) return; if( pWith->nCte==0 ) return; if( pWith->pOuter ){ sqlite3TreeViewLine(pView, "WITH (0x%p, pOuter=0x%p)",pWith,pWith->pOuter); }else{ sqlite3TreeViewLine(pView, "WITH (0x%p)", pWith); } if( pWith->nCte>0 ){ pView = sqlite3TreeViewPush(pView, 1); for(i=0; i<pWith->nCte; i++){ StrAccum x; char zLine[1000]; 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].zName); cSep = ','; } sqlite3_str_appendf(&x, ")"); } sqlite3_str_appendf(&x, " AS"); 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 struct SrcList_item *pItem = &pSrc->a[i]; StrAccum x; char zLine[100]; sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); sqlite3_str_appendf(&x, "{%d,*}", pItem->iCursor); if( pItem->zDatabase ){ sqlite3_str_appendf(&x, " %s.%s", pItem->zDatabase, pItem->zName); }else if( pItem->zName ){ sqlite3_str_appendf(&x, " %s", pItem->zName); } if( pItem->pTab ){ sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p", pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab); } if( pItem->zAlias ){ sqlite3_str_appendf(&x, " (AS %s)", pItem->zAlias); } if( pItem->fg.jointype & JT_LEFT ){ sqlite3_str_appendf(&x, " LEFT-JOIN"); } sqlite3StrAccumFinish(&x); sqlite3TreeViewItem(pView, zLine, i<pSrc->nSrc-1); if( pItem->pSelect ){ sqlite3TreeViewSelect(pView, pItem->pSelect, 0); } if( pItem->fg.isTabFunc ){ sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:"); } sqlite3TreeViewPop(pView); } } /* ** Generate a human-readable description of a Select object. */ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){ int n = 0; int cnt = 0; if( p==0 ){ sqlite3TreeViewLine(pView, "nil-SELECT"); return; } pView = sqlite3TreeViewPush(pView, moreToFollow); if( p->pWith ){ sqlite3TreeViewWith(pView, p->pWith, 1); cnt = 1; sqlite3TreeViewPush(pView, 1); } do{ 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 } sqlite3TreeViewExprList(pView, p->pEList, (n--)>0, "result-set"); #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); } sqlite3TreeViewPop(pView); } #endif if( p->pSrc && p->pSrc->nSrc ){ pView = sqlite3TreeViewPush(pView, (n--)>0); sqlite3TreeViewLine(pView, "FROM"); sqlite3TreeViewSrcList(pView, p->pSrc); sqlite3TreeViewPop(pView); } if( p->pWhere ){ sqlite3TreeViewItem(pView, "WHERE", (n--)>0); sqlite3TreeViewExpr(pView, p->pWhere, 0); sqlite3TreeViewPop(pView); } if( p->pGroupBy ){ sqlite3TreeViewExprList(pView, p->pGroupBy, (n--)>0, "GROUPBY"); } if( p->pHaving ){ sqlite3TreeViewItem(pView, "HAVING", (n--)>0); sqlite3TreeViewExpr(pView, p->pHaving, 0); sqlite3TreeViewPop(pView); } #ifndef SQLITE_OMIT_WINDOWFUNC if( p->pWinDefn ){ Window *pX; sqlite3TreeViewItem(pView, "WINDOW", (n--)>0); for(pX=p->pWinDefn; pX; pX=pX->pNextWin){ sqlite3TreeViewWindow(pView, pX, pX->pNextWin!=0); } sqlite3TreeViewPop(pView); } #endif if( p->pOrderBy ){ sqlite3TreeViewExprList(pView, p->pOrderBy, (n--)>0, "ORDERBY"); } if( p->pLimit ){ sqlite3TreeViewItem(pView, "LIMIT", (n--)>0); sqlite3TreeViewExpr(pView, p->pLimit->pLeft, p->pLimit->pRight!=0); if( p->pLimit->pRight ){ sqlite3TreeViewItem(pView, "OFFSET", (n--)>0); sqlite3TreeViewExpr(pView, p->pLimit->pRight, 0); sqlite3TreeViewPop(pView); } sqlite3TreeViewPop(pView); } if( p->pPrior ){ const char *zOp = "UNION"; switch( p->op ){ case TK_ALL: zOp = "UNION ALL"; break; case TK_INTERSECT: zOp = "INTERSECT"; break; case TK_EXCEPT: zOp = "EXCEPT"; break; } sqlite3TreeViewItem(pView, zOp, 1); } p = p->pPrior; }while( p!=0 ); sqlite3TreeViewPop(pView); } #ifndef SQLITE_OMIT_WINDOWFUNC /* ** Generate a description of starting or stopping bounds */ void sqlite3TreeViewBound( TreeView *pView, /* View context */ u8 eBound, /* UNBOUNDED, CURRENT, PRECEDING, FOLLOWING */ Expr *pExpr, /* Value for PRECEDING or FOLLOWING */ u8 moreToFollow /* True if more to follow */ ){ switch( eBound ){ case TK_UNBOUNDED: { sqlite3TreeViewItem(pView, "UNBOUNDED", moreToFollow); sqlite3TreeViewPop(pView); break; } case TK_CURRENT: { sqlite3TreeViewItem(pView, "CURRENT", moreToFollow); sqlite3TreeViewPop(pView); break; } case TK_PRECEDING: { sqlite3TreeViewItem(pView, "PRECEDING", moreToFollow); sqlite3TreeViewExpr(pView, pExpr, 0); sqlite3TreeViewPop(pView); break; } case TK_FOLLOWING: { sqlite3TreeViewItem(pView, "FOLLOWING", moreToFollow); sqlite3TreeViewExpr(pView, pExpr, 0); sqlite3TreeViewPop(pView); break; } } } #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 */ void sqlite3TreeViewWinFunc(TreeView *pView, const Window *pWin, u8 more){ pView = sqlite3TreeViewPush(pView, more); sqlite3TreeViewLine(pView, "WINFUNC %s(%d)", pWin->pFunc->zName, pWin->pFunc->nArg); sqlite3TreeViewWindow(pView, pWin, 0); sqlite3TreeViewPop(pView); } #endif /* SQLITE_OMIT_WINDOWFUNC */ /* ** 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[60]; pView = sqlite3TreeViewPush(pView, moreToFollow); if( pExpr==0 ){ sqlite3TreeViewLine(pView, "nil"); sqlite3TreeViewPop(pView); return; } if( pExpr->flags ){ if( ExprHasProperty(pExpr, EP_FromJoin) ){ sqlite3_snprintf(sizeof(zFlgs),zFlgs," flags=0x%x iRJT=%d", pExpr->flags, pExpr->iRightJoinTable); }else{ sqlite3_snprintf(sizeof(zFlgs),zFlgs," flags=0x%x",pExpr->flags); } }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 */ sqlite3TreeViewLine(pView, "COLUMN(%d)%s", pExpr->iColumn, zFlgs); }else{ sqlite3TreeViewLine(pView, "{%d:%d}%s", pExpr->iTable, pExpr->iColumn, 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: { sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); break; } #endif case TK_STRING: { sqlite3TreeViewLine(pView,"%Q", pExpr->u.zToken); break; } case TK_NULL: { sqlite3TreeViewLine(pView,"NULL"); break; } case TK_TRUEFALSE: { sqlite3TreeViewLine(pView, sqlite3ExprTruthValue(pExpr) ? "TRUE" : "FALSE"); break; } #ifndef SQLITE_OMIT_BLOB_LITERAL case TK_BLOB: { sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); break; } #endif case TK_VARIABLE: { sqlite3TreeViewLine(pView,"VARIABLE(%s,%d)", pExpr->u.zToken, pExpr->iColumn); break; } case TK_REGISTER: { sqlite3TreeViewLine(pView,"REGISTER(%d)", pExpr->iTable); break; } case TK_ID: { sqlite3TreeViewLine(pView,"ID \"%w\"", pExpr->u.zToken); break; } #ifndef SQLITE_OMIT_CAST case TK_CAST: { /* Expressions of the form: CAST(pLeft AS token) */ 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; |
︙ | ︙ | |||
623 624 625 626 627 628 629 | 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; | < | < < < < < < < | < < < | < | | < < < < < < < < < < < < < | < < | < < < < < < < < < | < | < | < < | | | 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 | 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 ); assert( pExpr->pRight->op==TK_TRUEFALSE ); x = (pExpr->op2==TK_ISNOT)*2 + sqlite3ExprTruthValue(pExpr->pRight); zUniOp = azOp[x]; break; } case TK_SPAN: { sqlite3TreeViewLine(pView, "SPAN %Q", pExpr->u.zToken); sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); break; } case TK_COLLATE: { sqlite3TreeViewLine(pView, "COLLATE %Q", pExpr->u.zToken); 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{ pFarg = pExpr->x.pList; #ifndef SQLITE_OMIT_WINDOWFUNC pWin = pExpr->y.pWin; #else pWin = 0; #endif } if( pExpr->op==TK_AGG_FUNCTION ){ sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q", pExpr->op2, pExpr->u.zToken); }else{ sqlite3TreeViewLine(pView, "FUNCTION %Q", pExpr->u.zToken); } 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: { sqlite3TreeViewLine(pView, "EXISTS-expr flags=0x%x", pExpr->flags); sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); break; } case TK_SELECT: { sqlite3TreeViewLine(pView, "SELECT-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( ExprHasProperty(pExpr, EP_xIsSelect) ){ 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: { Expr *pX = pExpr->pLeft; Expr *pY = pExpr->x.pList->a[0].pExpr; Expr *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: { |
︙ | ︙ | |||
786 787 788 789 790 791 792 | sqlite3TreeViewLine(pView, "%s(%d)", pExpr->iTable ? "NEW" : "OLD", pExpr->iColumn); break; } case TK_CASE: { sqlite3TreeViewLine(pView, "CASE"); sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); | < | < < < | < | < < < < < < < < < < < < < < < < < < < < | | | | < < | < < < < < < < < < < < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | 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"; switch( pExpr->affinity ){ case OE_Rollback: zType = "rollback"; break; case OE_Abort: zType = "abort"; break; case OE_Fail: zType = "fail"; break; case OE_Ignore: zType = "ignore"; break; } 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: { sqlite3TreeViewBareExprList(pView, pExpr->x.pList, "VECTOR"); break; } case TK_SELECT_COLUMN: { sqlite3TreeViewLine(pView, "SELECT-COLUMN %d", pExpr->iColumn); 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; } 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. */ void sqlite3TreeViewBareExprList( TreeView *pView, const ExprList *pList, const char *zLabel ){ if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST"; 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].zName; int moreToFollow = i<pList->nExpr - 1; if( j || zName ){ sqlite3TreeViewPush(pView, moreToFollow); moreToFollow = 0; sqlite3TreeViewLine(pView, 0); if( zName ){ fprintf(stdout, "AS %s ", zName); } if( j ){ fprintf(stdout, "iOrderByCol=%d", j); } fprintf(stdout, "\n"); fflush(stdout); } sqlite3TreeViewExpr(pView, pList->a[i].pExpr, moreToFollow); if( j || zName ){ sqlite3TreeViewPop(pView); } } } } void sqlite3TreeViewExprList( TreeView *pView, const ExprList *pList, u8 moreToFollow, const char *zLabel ){ pView = sqlite3TreeViewPush(pView, moreToFollow); sqlite3TreeViewBareExprList(pView, pList, zLabel); sqlite3TreeViewPop(pView); } #endif /* SQLITE_DEBUG */ |
Changes to src/trigger.c.
︙ | ︙ | |||
22 23 24 25 26 27 28 | pTriggerStep = pTriggerStep->pNext; sqlite3ExprDelete(db, pTmp->pWhere); sqlite3ExprListDelete(db, pTmp->pExprList); sqlite3SelectDelete(db, pTmp->pSelect); sqlite3IdListDelete(db, pTmp->pIdList); sqlite3UpsertDelete(db, pTmp->pUpsert); | < | 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); } } /* |
︙ | ︙ | |||
44 45 46 47 48 49 50 | ** 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){ | | | < | > > | > > > | < < | | < | < | | | < < < < < < < < < < | < | < < < < < < | < < | < | | 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 | ** 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 * const pTmpSchema = pParse->db->aDb[1].pSchema; Trigger *pList = 0; /* List of triggers to return */ if( pParse->disableTriggers ){ return 0; } if( pTmpSchema!=pTab->pSchema ){ HashElem *p; assert( sqlite3SchemaMutexHeld(pParse->db, 0, pTmpSchema) ); for(p=sqliteHashFirst(&pTmpSchema->trigHash); p; p=sqliteHashNext(p)){ Trigger *pTrig = (Trigger *)sqliteHashData(p); if( pTrig->pTabSchema==pTab->pSchema && 0==sqlite3StrICmp(pTrig->table, pTab->zName) ){ pTrig->pNext = (pList ? pList : pTab->pTrigger); pList = pTrig; } } } return (pList ? pList : pTab->pTrigger); } /* ** 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 |
︙ | ︙ | |||
145 146 147 148 149 150 151 | /* 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 | | | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | /* 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 SQLITE_MASTER. */ 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, |
︙ | ︙ | |||
173 174 175 176 177 178 179 | sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName); if( sqlite3FixSrcList(&sFix, pTableName) ){ goto trigger_cleanup; } pTab = sqlite3SrcListLookup(pParse, pTableName); if( !pTab ){ /* The table does not exist. */ | > > > > > > > > > > > | | | 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 | sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName); if( sqlite3FixSrcList(&sFix, pTableName) ){ goto trigger_cleanup; } pTab = sqlite3SrcListLookup(pParse, pTableName); if( !pTab ){ /* The table does not exist. */ 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. */ db->init.orphanTrigger = 1; } goto trigger_cleanup; } if( IsVirtual(pTab) ){ sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables"); goto trigger_cleanup; } /* 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 ); |
︙ | ︙ | |||
212 213 214 215 216 217 218 | 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. */ | | | | | | | | 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 | 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( pTab->pSelect && tr_tm!=TK_INSTEAD ){ sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S", (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0); goto trigger_cleanup; } if( !pTab->pSelect && tr_tm==TK_INSTEAD ){ sqlite3ErrorMsg(pParse, "cannot create INSTEAD OF" " trigger on table: %S", pTableName, 0); goto trigger_cleanup; } #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; |
︙ | ︙ | |||
280 281 282 283 284 285 286 | sqlite3IdListDelete(db, pColumns); sqlite3ExprDelete(db, pWhen); if( !pParse->pNewTrigger ){ sqlite3DeleteTrigger(db, pTrigger); }else{ assert( pParse->pNewTrigger==pTrigger ); } | < < < < < < < < < < < < < < < < < | 270 271 272 273 274 275 276 277 278 279 280 281 282 283 | 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( |
︙ | ︙ | |||
341 342 343 344 345 346 347 | assert( !db->init.busy ); pParse->pNewTrigger = pTrig; pTrig = 0; }else #endif /* if we are not initializing, | | < < < < < < < < < < < < < < < < < | < | | | < | 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 | assert( !db->init.busy ); pParse->pNewTrigger = pTrig; pTrig = 0; }else #endif /* if we are not initializing, ** build the sqlite_master entry */ if( !db->init.busy ){ Vdbe *v; char *z; /* Make an entry in the sqlite_master 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.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')", db->aDb[iDb].zDbSName, MASTER_NAME, zName, pTrig->table, z); sqlite3DbFree(db, z); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddParseSchemaOp(v, iDb, sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName)); } if( db->init.busy ){ Trigger *pLink = pTrig; Hash *pHash = &db->aDb[iDb].pSchema->trigHash; assert( sqlite3SchemaMutexHeld(db, iDb, 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 ); |
︙ | ︙ | |||
456 457 458 459 460 461 462 | Token *pName, /* The target name */ const char *zStart, /* Start of SQL text */ const char *zEnd /* End of SQL text */ ){ sqlite3 *db = pParse->db; TriggerStep *pTriggerStep; | < | 410 411 412 413 414 415 416 417 418 419 420 421 422 423 | Token *pName, /* The target name */ const char *zStart, /* Start of SQL text */ const char *zEnd /* End of SQL text */ ){ sqlite3 *db = pParse->db; TriggerStep *pTriggerStep; pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep) + pName->n + 1); if( pTriggerStep ){ char *z = (char*)&pTriggerStep[1]; memcpy(z, pName->z, pName->n); sqlite3Dequote(z); pTriggerStep->zTarget = z; pTriggerStep->op = op; |
︙ | ︙ | |||
505 506 507 508 509 510 511 | pSelect = 0; }else{ pTriggerStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); } pTriggerStep->pIdList = pColumn; pTriggerStep->pUpsert = pUpsert; pTriggerStep->orconf = orconf; | < < < < < < < < | 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 | 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. |
︙ | ︙ | |||
592 593 594 595 596 597 598 | return pTriggerStep; } /* ** Recursively delete a Trigger structure */ void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){ | | | 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 | return pTriggerStep; } /* ** Recursively delete a Trigger structure */ void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){ if( pTrigger==0 ) 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); } |
︙ | ︙ | |||
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 */ | | | | 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 | 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 && sqlite3StrICmp(db->aDb[j].zDbSName, zDb) ) 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, 0); }else{ sqlite3CodeVerifyNamedSchema(pParse, zDb); } pParse->checkSchema = 1; goto drop_trigger_cleanup; } sqlite3DropTriggerPtr(pParse, pTrigger); |
︙ | ︙ | |||
668 669 670 671 672 673 674 | Vdbe *v; sqlite3 *db = pParse->db; int iDb; iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema); assert( iDb>=0 && iDb<db->nDb ); pTable = tableOfTrigger(pTrigger); | > | < > > | | < | | < | < < < < | < < < < < < < < < | < < < < < | < < < < < < | < | < > | < < < | | < < < < < < < < < < | < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < | > | | < < < | < < < | | | | | < | < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | 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 ); assert( pTable->pSchema==pTrigger->pSchema || iDb==1 ); #ifndef SQLITE_OMIT_AUTHORIZATION { 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. */ assert( pTable!=0 ); if( (v = sqlite3GetVdbe(pParse))!=0 ){ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE name=%Q AND type='trigger'", db->aDb[iDb].zDbSName, MASTER_NAME, 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); Trigger **pp; for(pp=&pTab->pTrigger; *pp!=pTrigger; pp=&((*pp)->pNext)); *pp = (*pp)->pNext; } 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].zName)>=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 ** performed on the table, and, if that operation is an UPDATE, if at ** least one of the columns in pChanges is being modified. */ Trigger *sqlite3TriggersExist( Parse *pParse, /* Parse context */ Table *pTab, /* The table the contains the triggers */ int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */ 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; if( (pParse->db->flags & SQLITE_EnableTrigger)!=0 ){ pList = sqlite3TriggerList(pParse, pTab); } assert( pList==0 || IsVirtual(pTab)==0 ); for(p=pList; p; p=p->pNext){ if( p->op==op && checkColumnOverlap(p->pColumns, pChanges) ){ mask |= p->tr_tm; } } 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. */ static SrcList *targetSrcList( Parse *pParse, /* The parsing context */ TriggerStep *pStep /* The trigger containing the target token */ ){ sqlite3 *db = pParse->db; int iDb; /* Index of the database to use */ SrcList *pSrc; /* SrcList to be returned */ pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); if( pSrc ){ assert( pSrc->nSrc>0 ); pSrc->a[pSrc->nSrc-1].zName = sqlite3DbStrDup(db, pStep->zTarget); iDb = sqlite3SchemaToIndex(db, pStep->pTrig->pSchema); if( iDb==0 || iDb>=2 ){ const char *zDb; assert( iDb<db->nDb ); zDb = db->aDb[iDb].zDbSName; pSrc->a[pSrc->nSrc-1].zDatabase = sqlite3DbStrDup(db, zDb); } } return pSrc; } /* ** Generate VDBE code for the statements inside the body of a single ** trigger. */ static int codeTriggerProgram( Parse *pParse, /* The parser context */ |
︙ | ︙ | |||
1063 1064 1065 1066 1067 1068 1069 | P4_DYNAMIC); } #endif switch( pStep->op ){ case TK_UPDATE: { sqlite3Update(pParse, | | < | < | < > > > | 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 | P4_DYNAMIC); } #endif switch( pStep->op ){ case TK_UPDATE: { sqlite3Update(pParse, targetSrcList(pParse, pStep), sqlite3ExprListDup(db, pStep->pExprList, 0), sqlite3ExprDup(db, pStep->pWhere, 0), pParse->eOrconf, 0, 0, 0 ); break; } case TK_INSERT: { sqlite3Insert(pParse, targetSrcList(pParse, pStep), sqlite3SelectDup(db, pStep->pSelect, 0), sqlite3IdListDup(db, pStep->pIdList), pParse->eOrconf, sqlite3UpsertDup(db, pStep->pUpsert) ); break; } case TK_DELETE: { sqlite3DeleteFrom(pParse, targetSrcList(pParse, pStep), sqlite3ExprDup(db, pStep->pWhere, 0), 0, 0 ); 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; } } if( pStep->op!=TK_SELECT ){ sqlite3VdbeAddOp0(v, OP_ResetCount); } } return 0; } #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS /* |
︙ | ︙ | |||
1156 1157 1158 1159 1160 1161 1162 1163 | Parse *pTop = sqlite3ParseToplevel(pParse); sqlite3 *db = pParse->db; /* Database handle */ TriggerPrg *pPrg; /* Value to return */ Expr *pWhen = 0; /* Duplicate of trigger WHEN expression */ Vdbe *v; /* Temporary VM */ NameContext sNC; /* Name context for sub-vdbe */ SubProgram *pProgram = 0; /* Sub-vdbe for trigger program */ int iEndTrigger = 0; /* Label to jump to if WHEN is false */ | > < | 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 | Parse *pTop = sqlite3ParseToplevel(pParse); sqlite3 *db = pParse->db; /* Database handle */ TriggerPrg *pPrg; /* Value to return */ Expr *pWhen = 0; /* Duplicate of trigger WHEN expression */ Vdbe *v; /* Temporary VM */ NameContext sNC; /* Name context for sub-vdbe */ SubProgram *pProgram = 0; /* Sub-vdbe for trigger program */ Parse *pSubParse; /* Parse context for sub-vdbe */ int iEndTrigger = 0; /* Label to jump to if WHEN is false */ assert( pTrigger->zName==0 || pTab==tableOfTrigger(pTrigger) ); assert( pTop->pVdbe ); /* Allocate the TriggerPrg and SubProgram objects. To ensure that they ** are freed if an error occurs, link them into the Parse.pTriggerPrg ** list of the top-level Parse object sooner rather than later. */ |
︙ | ︙ | |||
1179 1180 1181 1182 1183 1184 1185 | pPrg->pTrigger = pTrigger; pPrg->orconf = orconf; pPrg->aColmask[0] = 0xffffffff; pPrg->aColmask[1] = 0xffffffff; /* Allocate and populate a new Parse context to use for coding the ** trigger sub-program. */ | > | | > | | | | | | | | 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 | pPrg->pTrigger = pTrigger; pPrg->orconf = orconf; pPrg->aColmask[0] = 0xffffffff; pPrg->aColmask[1] = 0xffffffff; /* Allocate and populate a new Parse context to use for coding the ** trigger sub-program. */ pSubParse = sqlite3StackAllocZero(db, sizeof(Parse)); if( !pSubParse ) return 0; memset(&sNC, 0, sizeof(sNC)); 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" : ""), (pTrigger->op==TK_INSERT ? "INSERT" : ""), (pTrigger->op==TK_DELETE ? "DELETE" : ""), |
︙ | ︙ | |||
1212 1213 1214 1215 1216 1217 1218 | #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); | < | > | | | < | | | | | | < < > | | > > | 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 | #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( SQLITE_OK==sqlite3ResolveExprNames(&sNC, pWhen) && db->mallocFailed==0 ){ 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); /* Insert an OP_Halt at the end of the sub-program. */ if( iEndTrigger ){ sqlite3VdbeResolveLabel(v, iEndTrigger); } sqlite3VdbeAddOp0(v, OP_Halt); VdbeComment((v, "End: %s.%s", pTrigger->zName, onErrorText(orconf))); transferParseError(pParse, pSubParse); if( db->mallocFailed==0 && pParse->nErr==0 ){ pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pTop->nMaxArg); } pProgram->nMem = pSubParse->nMem; pProgram->nCsr = pSubParse->nTab; pProgram->token = (void *)pTrigger; pPrg->aColmask[0] = pSubParse->oldmask; pPrg->aColmask[1] = pSubParse->newmask; sqlite3VdbeDelete(v); } assert( !pSubParse->pAinc && !pSubParse->pZombieTab ); assert( !pSubParse->pTriggerPrg && !pSubParse->nMaxArg ); sqlite3ParserReset(pSubParse); sqlite3StackFree(db, pSubParse); return pPrg; } /* ** Return a pointer to a TriggerPrg object containing the sub-program for ** trigger pTrigger with default ON CONFLICT algorithm orconf. If no such ** TriggerPrg object exists, a new object is allocated and populated before |
︙ | ︙ | |||
1280 1281 1282 1283 1284 1285 1286 | pPrg && (pPrg->pTrigger!=pTrigger || pPrg->orconf!=orconf); pPrg=pPrg->pNext ); /* If an existing TriggerPrg could not be located, create a new one. */ if( !pPrg ){ pPrg = codeRowTrigger(pParse, pTrigger, pTab, orconf); | < | 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 | pPrg && (pPrg->pTrigger!=pTrigger || pPrg->orconf!=orconf); pPrg=pPrg->pNext ); /* If an existing TriggerPrg could not be located, create a new one. */ if( !pPrg ){ pPrg = codeRowTrigger(pParse, pTrigger, pTab, orconf); } return pPrg; } /* ** Generate code for the trigger program associated with trigger p on |
︙ | ︙ | |||
1303 1304 1305 1306 1307 1308 1309 | int reg, /* Reg array containing OLD.* and NEW.* values */ int orconf, /* ON CONFLICT policy */ int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */ ){ Vdbe *v = sqlite3GetVdbe(pParse); /* Main VM */ TriggerPrg *pPrg; pPrg = getRowTrigger(pParse, p, pTab, orconf); | | | 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 | int reg, /* Reg array containing OLD.* and NEW.* values */ int orconf, /* ON CONFLICT policy */ int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */ ){ Vdbe *v = sqlite3GetVdbe(pParse); /* Main VM */ TriggerPrg *pPrg; pPrg = getRowTrigger(pParse, p, pTab, orconf); assert( pPrg || pParse->nErr || pParse->db->mallocFailed ); /* Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program ** is a pointer to the sub-vdbe containing the trigger program. */ if( pPrg ){ int bRecursive = (p->zName && 0==(pParse->db->flags&SQLITE_RecTriggers)); sqlite3VdbeAddOp4(v, OP_Program, reg, ignoreJump, ++pParse->nMem, |
︙ | ︙ | |||
1346 1347 1348 1349 1350 1351 1352 | ** 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 | | | 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 | ** 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 OLD.* 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 |
︙ | ︙ | |||
1391 1392 1393 1394 1395 1396 1397 | ** 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 ); | | < < < < | < | < < < | 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 | ** 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 */ if( p->op==op && p->tr_tm==tr_tm && checkColumnOverlap(p->pColumns, pChanges) ){ sqlite3CodeRowTriggerDirect(pParse, p, pTab, reg, orconf, ignoreJump); } } } /* ** Triggers may access values stored in the old.* or new.* pseudo-table. ** This function returns a 32-bit bitmask indicating which columns of the |
︙ | ︙ | |||
1449 1450 1451 1452 1453 1454 1455 | ){ 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){ | | < < < < | | | | < | 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 | ){ 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) ){ 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 | ** 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_master 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 parameter iReg is not negative, code an OP_RealAffinity instruction ** on register iReg. This is used when an equivalent integer value is ** stored in place of an 8-byte floating point value in order to save ** space. */ void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){ assert( pTab!=0 ); if( !pTab->pSelect ){ sqlite3_value *pValue = 0; u8 enc = ENC(sqlite3VdbeDb(v)); Column *pCol = &pTab->aCol[i]; VdbeComment((v, "%s.%s", pTab->zName, pCol->zName)); assert( i<pTab->nCol ); sqlite3ValueFromExpr(sqlite3VdbeDb(v), pCol->pDflt, enc, pCol->affinity, &pValue); if( pValue ){ sqlite3VdbeAppendP4(v, pValue, P4_MEM); } } #ifndef SQLITE_OMIT_FLOATING_POINT if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){ sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg); } #endif } /* ** Check to see if column iCol of index pIdx references any of the |
︙ | ︙ | |||
130 131 132 133 134 135 136 137 | int chngRowid /* true if the rowid is being updated */ ){ if( pIdx->pPartIdxWhere==0 ) return 0; return sqlite3ExprReferencesUpdatedColumn(pIdx->pPartIdxWhere, aXRef, chngRowid); } /* | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < | | | < | < | 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 | 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. ** ** UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL; ** \_______/ \________/ \______/ \________________/ * onError pTabList pChanges pWhere */ 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; /* Loop counters */ Table *pTab; /* The table to be updated */ int addrTop = 0; /* VDBE instruction address of the start of the loop */ WhereInfo *pWInfo; /* 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 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; /* First register in array assigned to each index */ 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 */ 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 */ |
︙ | ︙ | |||
333 334 335 336 337 338 339 | 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 */ | < < < | | | < < < < < < < < < < < < < < < | | 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 | 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; } assert( pTabList->nSrc==1 ); /* 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 = pTab->pSelect!=0; 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 #ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT if( !isView ){ pWhere = sqlite3LimitWhere( pParse, pTabList, pWhere, pOrderBy, pLimit, "UPDATE" ); pOrderBy = 0; pLimit = 0; } #endif |
︙ | ︙ | |||
434 435 436 437 438 439 440 | pParse->nTab = iBaseCur; } pTabList->a[0].iCursor = iDataCur; /* Allocate space for aXRef[], aRegIdx[], and aToOpen[]. ** Initialize aXRef[] and aToOpen[] to their default values. */ | | | < < < < < < < | < | < < < < < < < < < < < < | < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | < > > > < < < < < < | | 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 | 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) + nIdx+2 ); if( aXRef==0 ) goto update_cleanup; aRegIdx = aXRef+pTab->nCol; aToOpen = (u8*)(aRegIdx+nIdx); 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; /* 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( sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){ goto update_cleanup; } for(j=0; j<pTab->nCol; j++){ if( sqlite3StrICmp(pTab->aCol[j].zName, pChanges->a[i].zName)==0 ){ if( j==pTab->iPKey ){ chngRowid = 1; pRowidExpr = pChanges->a[i].pExpr; }else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){ chngPk = 1; } aXRef[j] = i; break; } } if( j>=pTab->nCol ){ if( pPk==0 && sqlite3IsRowid(pChanges->a[i].zName) ){ j = -1; chngRowid = 1; pRowidExpr = pChanges->a[i].pExpr; }else{ sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zName); pParse->checkSchema = 1; goto update_cleanup; } } #ifndef SQLITE_OMIT_AUTHORIZATION { int rc; rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName, j<0 ? "ROWID" : pTab->aCol[j].zName, db->aDb[iDb].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; /* 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(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ 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[j+1] = 0; aRegIdx[j] = reg; } 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); } /* Begin generating code. */ v = sqlite3GetVdbe(pParse); if( v==0 ) goto update_cleanup; if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); sqlite3BeginWriteOperation(pParse, pTrigger || hasFK, iDb); /* Allocate required registers. */ if( !IsVirtual(pTab) ){ regRowSet = ++pParse->nMem; regOldRowid = regNewRowid = ++pParse->nMem; if( chngPk || pTrigger || hasFK ){ regOld = pParse->nMem + 1; pParse->nMem += pTab->nCol; } if( chngKey || pTrigger || hasFK ){ regNewRowid = ++pParse->nMem; |
︙ | ︙ | |||
629 630 631 632 633 634 635 | 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) | | | < | < < | | < < | | < | < < < | | < < < < < < < | < < < < < < < < < | | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | | | | < | < < | | | | | | | | | | < | | | | | | | | | | | | < | | < < | < < < < < | < < < < < < < < < < < < < < < < < < | | | < < | | < < | < < < < < | | | | 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 | 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( 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( 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 && pUpsert==0 ){ regRowCount = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount); } if( HasRowid(pTab) ){ sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid); }else{ assert( pPk!=0 ); nPk = pPk->nKeyCol; iPk = pParse->nMem+1; pParse->nMem += nPk; regKey = ++pParse->nMem; if( pUpsert==0 ){ iEph = pParse->nTab++; sqlite3VdbeAddOp3(v, OP_Null, 0, iPk, iPk+nPk-1); addrOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nPk); sqlite3VdbeSetP4KeyInfo(pParse, pPk); } } 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); }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,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); 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 ){ sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid); } }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( 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 ) sqlite3VdbeJumpHere(v, addrOnce); } /* Top of the update loop */ if( eOnePass!=ONEPASS_OFF ){ if( !isView && aiCurOnePass[0]!=iDataCur && aiCurOnePass[1]!=iDataCur ){ 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 ){ labelContinue = sqlite3VdbeMakeLabel(pParse); sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v); addrTop = sqlite3VdbeAddOp2(v, OP_RowData, iEph, regKey); sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey, 0); VdbeCoverage(v); }else{ labelContinue = sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowSet,labelBreak, 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 ){ sqlite3ExprCode(pParse, pRowidExpr, 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++){ if( oldmask==0xffffffff || (i<32 && (oldmask & MASKBIT32(i))!=0) || (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0 ){ testcase( oldmask!=0xffffffff && i==31 ); sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regOld+i); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, regOld+i); } } if( chngRowid==0 && pPk==0 ){ sqlite3VdbeAddOp2(v, OP_Copy, regOldRowid, regNewRowid); } } |
︙ | ︙ | |||
925 926 927 928 929 930 931 | ** 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 ); | | | < < < < < < < | < | < | < < < < < < < < | | | | | | | | | | | | | | | | | | | | | | | < < | | | | < < < < < | < | < < > > < < < < < < < < < < < < > > > > > > > > < < < < < < | < | 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 | ** the database after the BEFORE triggers are fired anyway (as the trigger ** may have modified them). So not loading those that are not going to ** be used eliminates some redundant opcodes. */ newmask = sqlite3TriggerColmask( pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError ); for(i=0; i<pTab->nCol; i++){ if( i==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i); }else{ j = aXRef[i]; if( j>=0 ){ sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regNew+i); }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, regNew+i); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i); } } } /* 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); /* 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; i<pTab->nCol; i++){ if( aXRef[i]<0 && i!=pTab->iPKey ){ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, regNew+i); } } } if( !isView ){ int addr1 = 0; /* Address of jump instruction */ /* Do constraint checks. */ assert( regOldRowid>0 ); sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur, regNewRowid, regOldRowid, chngKey, onError, labelContinue, &bReplace, aXRef, 0); /* Do FK constraint checks. */ if( hasFK ){ sqlite3FkCheck(pParse, pTab, regOldRowid, 0, aXRef, chngKey); } /* Delete the index entries associated with the current record. */ if( bReplace || chngKey ){ if( pPk ){ addr1 = sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, 0, regKey, nKey); }else{ addr1 = sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, 0, regOldRowid); } VdbeCoverageNeverTaken(v); } sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, aRegIdx, -1); 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 |
︙ | ︙ | |||
1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 | 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( | > > > | 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 | sqlite3VdbeAppendP4(v, pTab, P4_TABLE); } #else if( hasFK>1 || chngKey ){ sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, 0); } #endif if( bReplace || chngKey ){ sqlite3VdbeJumpHere(v, addr1); } if( hasFK ){ sqlite3FkCheck(pParse, pTab, 0, regNewRowid, aXRef, chngKey); } /* Insert the new index entries and the new record. */ sqlite3CompleteInsertion( |
︙ | ︙ | |||
1112 1113 1114 1115 1116 1117 1118 | ** 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); | | > > | > > | 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 | ** 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 if( pPk ){ sqlite3VdbeResolveLabel(v, labelContinue); sqlite3VdbeAddOp2(v, OP_Next, iEph, addrTop); VdbeCoverage(v); }else{ sqlite3VdbeGoto(v, labelContinue); } 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_ResultRow, 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[] */ sqlite3SrcListDelete(db, pTabList); sqlite3ExprListDelete(db, pChanges); |
︙ | ︙ | |||
1193 1194 1195 1196 1197 1198 1199 | 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); | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | < < | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < | < | 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 | int onError /* ON CONFLICT strategy */ ){ Vdbe *v = pParse->pVdbe; /* Virtual machine under construction */ int ephemTab; /* Table holding the result of the SELECT */ int i; /* Loop counter */ sqlite3 *db = pParse->db; /* Database connection */ const char *pVTab = (const char*)sqlite3GetVTable(db, pTab); WhereInfo *pWInfo; int nArg = 2 + pTab->nCol; /* Number of arguments to VUpdate */ int regArg; /* First register in VUpdate arg array */ int regRec; /* Register in which to assemble record */ int regRowid; /* Register for ephem table rowid */ int iCsr = pSrc->a[0].iCursor; /* Cursor used for virtual table scan */ int aDummy[2]; /* Unused arg for sqlite3WhereOkOnePass() */ int 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; regRec = ++pParse->nMem; regRowid = ++pParse->nMem; /* Start scanning the virtual table */ pWInfo = sqlite3WhereBegin(pParse, pSrc,pWhere,0,0,0,WHERE_ONEPASS_DESIRED,0); if( pWInfo==0 ) return; /* Populate the argument registers. */ for(i=0; i<pTab->nCol; i++){ if( aXRef[i]>=0 ){ sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i); }else{ sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i); sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG);/* Enable 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); #ifdef SQLITE_DEBUG /* Signal an assert() within OP_MakeRecord that it is allowed to ** accept no-change records with serial_type 10 */ sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG_MAGIC); #endif sqlite3VdbeAddOp2(v, OP_NewRowid, ephemTab, regRowid); sqlite3VdbeAddOp3(v, OP_Insert, ephemTab, regRec, regRowid); } if( eOnePass==ONEPASS_OFF ){ /* End the virtual table scan */ sqlite3WhereEnd(pWInfo); /* Begin scannning through the ephemeral table. */ addr = sqlite3VdbeAddOp1(v, OP_Rewind, ephemTab); VdbeCoverage(v); /* Extract arguments from the current row of the ephemeral table and ** invoke the VUpdate method. */ for(i=0; i<nArg; i++){ |
︙ | ︙ |
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 | */ #include "sqliteInt.h" #ifndef SQLITE_OMIT_UPSERT /* ** Free a list of Upsert objects */ void sqlite3UpsertDelete(sqlite3 *db, Upsert *p){ if( p ){ sqlite3ExprListDelete(db, p->pUpsertTarget); sqlite3ExprDelete(db, p->pUpsertTargetWhere); sqlite3ExprListDelete(db, p->pUpsertSet); sqlite3ExprDelete(db, p->pUpsertWhere); sqlite3DbFree(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) ); } /* ** 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 *pNew; pNew = sqlite3DbMallocRaw(db, sizeof(Upsert)); if( pNew==0 ){ sqlite3ExprListDelete(db, pTarget); sqlite3ExprDelete(db, pTargetWhere); sqlite3ExprListDelete(db, pSet); sqlite3ExprDelete(db, pWhere); return 0; }else{ pNew->pUpsertTarget = pTarget; pNew->pUpsertTargetWhere = pTargetWhere; pNew->pUpsertSet = pSet; pNew->pUpsertWhere = pWhere; pNew->pUpsertIdx = 0; } return pNew; } /* ** Analyze the ON CONFLICT clause described by pUpsert. Resolve all ** symbols in the conflict-target. |
︙ | ︙ | |||
96 97 98 99 100 101 102 | 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 */ | < < < | | | | | | | | | | | | | | | | < > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < < < < < < | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | 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; 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 ); return SQLITE_OK; } /* 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; return SQLITE_OK; } sqlite3ErrorMsg(pParse, "ON CONFLICT clause does not match any " "PRIMARY KEY or UNIQUE constraint"); return SQLITE_ERROR; } /* ** 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 |
︙ | ︙ | |||
258 259 260 261 262 263 264 | 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; | < < < < > > | | < | | | < < < < < < | | > > | 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 | 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 ); VdbeNoopComment((v, "Begin DO UPDATE of UPSERT")); iDataCur = pUpsert->iDataCur; 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; int i; pParse->nMem += nPk; for(i=0; i<nPk; i++){ int k; assert( pPk->aiColumn[i]>=0 ); k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]); sqlite3VdbeAddOp3(v, OP_Column, iCur, k, iPk+i); VdbeComment((v, "%s.%s", pIdx->zName, pTab->aCol[pPk->aiColumn[i]].zName)); } 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); sqlite3VdbeJumpHere(v, i); } } /* pUpsert does not own pUpsertSrc - the outer INSERT statement does. So ** we have to make a copy before passing it down into sqlite3Update() */ pSrc = sqlite3SrcListDup(db, pUpsert->pUpsertSrc, 0); sqlite3Update(pParse, pSrc, pUpsert->pUpsertSet, pUpsert->pUpsertWhere, OE_Abort, 0, 0, pUpsert); pUpsert->pUpsertSet = 0; /* Will have been deleted by sqlite3Update() */ pUpsert->pUpsertWhere = 0; /* Will have been deleted by sqlite3Update() */ VdbeNoopComment((v, "End DO UPDATE of UPSERT")); } #endif /* SQLITE_OMIT_UPSERT */ |
Changes to src/utf.c.
︙ | ︙ | |||
100 101 102 103 104 105 106 107 108 109 110 111 112 113 | }else{ \ *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. ** | > > > > > > > > > > > > > > > > > > > > | 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 | }else{ \ *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); \ } \ } #define READ_UTF16LE(zIn, TERM, c){ \ c = (*zIn++); \ c += ((*zIn++)<<8); \ if( c>=0xD800 && c<0xE000 && TERM ){ \ int c2 = (*zIn++); \ c2 += ((*zIn++)<<8); \ c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \ } \ } #define READ_UTF16BE(zIn, TERM, c){ \ c = ((*zIn++)<<8); \ c += (*zIn++); \ if( c>=0xD800 && c<0xE000 && TERM ){ \ int c2 = ((*zIn++)<<8); \ c2 += (*zIn++); \ c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \ } \ } /* ** Translate a single UTF-8 character. Return the unicode value. ** ** During translation, assume that the byte that zTerm points ** is a 0x00. ** |
︙ | ︙ | |||
191 192 193 194 195 196 197 | assert( pMem->flags&MEM_Str ); assert( pMem->enc!=desiredEnc ); assert( pMem->enc!=0 ); assert( pMem->n>=0 ); #if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG) { | < | < | | | 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | assert( pMem->flags&MEM_Str ); assert( pMem->enc!=desiredEnc ); assert( pMem->enc!=0 ); assert( pMem->n>=0 ); #if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG) { char zBuf[100]; sqlite3VdbeMemPrettyPrint(pMem, zBuf); fprintf(stderr, "INPUT: %s\n", zBuf); } #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. */ |
︙ | ︙ | |||
277 278 279 280 281 282 283 | 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 ){ | < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < | | < | < | | | 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 | 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 ){ READ_UTF16LE(zIn, zIn<zTerm, c); WRITE_UTF8(z, c); } }else{ /* UTF-16 Big-endian -> UTF-8 */ while( zIn<zTerm ){ READ_UTF16BE(zIn, zIn<zTerm, c); WRITE_UTF8(z, c); } } pMem->n = (int)(z - zOut); } *z = 0; assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len ); c = pMem->flags; sqlite3VdbeMemRelease(pMem); pMem->flags = MEM_Str|MEM_Term|(c&(MEM_AffMask|MEM_Subtype)); 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) { char zBuf[100]; sqlite3VdbeMemPrettyPrint(pMem, zBuf); fprintf(stderr, "OUTPUT: %s\n", zBuf); } #endif return SQLITE_OK; } #endif /* SQLITE_OMIT_UTF16 */ #ifndef SQLITE_OMIT_UTF16 |
︙ | ︙ | |||
488 489 490 491 492 493 494 | ** in pZ. nChar must be non-negative. */ int sqlite3Utf16ByteLen(const void *zIn, int nChar){ int c; unsigned char const *z = zIn; int n = 0; | | | | | < > > > > | | > | < | 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 | ** 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_UTF16BE ){ while( n<nChar ){ READ_UTF16BE(z, 1, c); n++; } }else{ while( n<nChar ){ READ_UTF16LE(z, 1, c); n++; } } return (int)(z-(unsigned char const *)zIn); } #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. |
︙ | ︙ | |||
525 526 527 528 529 530 531 532 533 534 535 | 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 */ | > > > > > > > > > > > > > > > > > > > > > > > > | 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 | 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 ); } for(i=0; i<0x00110000; i++){ if( i>=0xD800 && i<0xE000 ) continue; z = zBuf; WRITE_UTF16LE(z, i); n = (int)(z-zBuf); assert( n>0 && n<=4 ); z[0] = 0; z = zBuf; READ_UTF16LE(z, 1, c); assert( c==i ); assert( (z-zBuf)==n ); } for(i=0; i<0x00110000; i++){ if( i>=0xD800 && i<0xE000 ) continue; z = zBuf; WRITE_UTF16BE(z, i); n = (int)(z-zBuf); assert( n>0 && n<=4 ); z[0] = 0; z = zBuf; READ_UTF16BE(z, 1, c); assert( c==i ); 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 | ** ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** */ #include "sqliteInt.h" #include <stdarg.h> #if HAVE_ISNAN || SQLITE_HAVE_ISNAN # include <math.h> #endif /* ** Routine needed to support the testcase() macro. */ #ifdef SQLITE_COVERAGE_TEST void sqlite3Coverage(int x){ static unsigned dummy = 0; dummy += (unsigned)x; } #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. ** |
︙ | ︙ | |||
53 54 55 56 57 58 59 | ** ** 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 | > > > > > > > > | > > > > > > > > | > > > > > > > > > > | | | 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 | ** ** 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 /* ** Systems that support the isnan() library function should probably ** make use of it by compiling with -DSQLITE_HAVE_ISNAN. But we have ** found that many systems do not have a working isnan() function so ** this implementation is provided as an alternative. ** ** This NaN test sometimes fails if compiled on GCC with -ffast-math. ** On the other hand, the use of -ffast-math comes with the following ** warning: ** ** This option [-ffast-math] should never be turned on by any ** -O option since it can result in incorrect output for programs ** which depend on an exact implementation of IEEE or ISO ** rules/specifications for math functions. ** ** Under MSVC, this NaN test may fail if compiled with a floating- ** point precision mode other than /fp:precise. From the MSDN ** documentation: ** ** The compiler [with /fp:precise] will properly handle comparisons ** involving NaN. For example, x != x evaluates to true if x is NaN ** ... */ #ifdef __FAST_MATH__ # error SQLite will not work correctly with the -ffast-math option of GCC. #endif volatile double y = x; volatile double z = y; rc = (y!=z); #else /* if HAVE_ISNAN */ rc = isnan(x); #endif /* HAVE_ISNAN */ testcase( rc ); return rc; } #endif /* SQLITE_OMIT_FLOATING_POINT */ |
︙ | ︙ | |||
85 86 87 88 89 90 91 | ** 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){ | | | < < < < < < | < < < < < < < < < < < < < < < > > > > > > > > > | | | 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 | ** 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)==0 ) return zDflt; return pCol->zName + strlen(pCol->zName) + 1; } /* ** Helper function for sqlite3Error() - called rarely. Broken out into ** a separate routine to avoid unnecessary register saves on entry to ** sqlite3Error(). */ static SQLITE_NOINLINE void sqlite3ErrorFinish(sqlite3 *db, int err_code){ if( db->pErr ) sqlite3ValueSetNull(db->pErr); sqlite3SystemError(db, err_code); } /* ** Set the current error code to err_code and clear any prior error message. ** Also set iSysErrno (by calling sqlite3System) if the err_code indicates ** 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; rc &= 0xff; if( rc==SQLITE_CANTOPEN || rc==SQLITE_IOERR ){ db->iSysErrno = sqlite3OsGetLastError(db->pVfs); } } /* ** Set the most recent error code and error string for the sqlite ** handle "db". The error code is set to "err_code". ** ** If it is not NULL, string zFormat specifies the format of the ** error string in the style of the printf functions: The following ** format characters are allowed: ** ** %s Insert a string ** %z A string that should be freed after use ** %d Insert an integer ** %T Insert a token ** %S Insert the first element of a SrcList ** ** zFormat and any string tokens that follow it are assumed to be ** encoded in UTF-8. ** ** To clear the most recent error for sqlite handle "db", sqlite3Error ** should be called with err_code set to SQLITE_OK and zFormat set ** to NULL. */ void sqlite3ErrorWithMsg(sqlite3 *db, int err_code, const char *zFormat, ...){ assert( db!=0 ); |
︙ | ︙ | |||
171 172 173 174 175 176 177 178 | va_start(ap, zFormat); z = sqlite3VMPrintf(db, zFormat, ap); va_end(ap); sqlite3ValueSetStr(db->pErr, -1, z, SQLITE_UTF8, SQLITE_DYNAMIC); } } /* | | > | < | | | | < < < < < < < < < < < | < < < < < < < < < < < | 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 | va_start(ap, zFormat); z = sqlite3VMPrintf(db, zFormat, ap); va_end(ap); sqlite3ValueSetStr(db->pErr, -1, z, SQLITE_UTF8, SQLITE_DYNAMIC); } } /* ** Add an error message to pParse->zErrMsg and increment pParse->nErr. ** The following formatting characters are allowed: ** ** %s Insert a string ** %z A string that should be freed after use ** %d Insert an integer ** %T Insert a token ** %S Insert the first element of a SrcList ** ** This function should be used to report any error that occurs while ** compiling an SQL statement (i.e. within sqlite3_prepare()). The ** last thing the sqlite3_prepare() function does is copy the error ** stored by this function into the database handle using sqlite3Error(). ** Functions sqlite3Error() or sqlite3ErrorWithMsg() should be used ** during statement execution (sqlite3_step() etc.). */ void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){ char *zMsg; va_list ap; sqlite3 *db = pParse->db; va_start(ap, zFormat); zMsg = sqlite3VMPrintf(db, zFormat, ap); va_end(ap); if( db->suppressErr ){ sqlite3DbFree(db, zMsg); }else{ pParse->nErr++; sqlite3DbFree(db, pParse->zErrMsg); pParse->zErrMsg = zMsg; pParse->rc = SQLITE_ERROR; } } /* ** 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. |
︙ | ︙ | |||
280 281 282 283 284 285 286 | }else{ z[j++] = z[i]; } } z[j] = 0; } void sqlite3DequoteExpr(Expr *p){ | < < < < < < < < < < < < < < < < < < < < < < < | 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 | }else{ z[j++] = z[i]; } } z[j] = 0; } void sqlite3DequoteExpr(Expr *p){ assert( sqlite3Isquote(p->u.zToken[0]) ); p->flags |= p->u.zToken[0]=='"' ? EP_Quoted|EP_DblQuoted : EP_Quoted; sqlite3Dequote(p->u.zToken); } /* ** Generate a Token object from a string */ void sqlite3TokenInit(Token *p, char *z){ p->z = z; p->n = sqlite3Strlen30(z); } |
︙ | ︙ | |||
339 340 341 342 343 344 345 | }else if( zRight==0 ){ return 1; } return sqlite3StrICmp(zLeft, zRight); } int sqlite3StrICmp(const char *zLeft, const char *zRight){ unsigned char *a, *b; | | < < < < < | | < < < < < < < < < < < < < < | | | | | | | | | | 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 | }else if( zRight==0 ){ return 1; } return sqlite3StrICmp(zLeft, zRight); } int sqlite3StrICmp(const char *zLeft, const char *zRight){ unsigned char *a, *b; int c; a = (unsigned char *)zLeft; b = (unsigned char *)zRight; for(;;){ c = (int)UpperToLower[*a] - (int)UpperToLower[*b]; if( c || *a==0 ) 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 10 to the E-th power. Examples: E==1 results in 10. ** E==2 results in 100. E==50 results in 1.0e50. ** ** This routine only works for values of E between 1 and 341. */ static LONGDOUBLE_TYPE sqlite3Pow10(int E){ #if defined(_MSC_VER) static const LONGDOUBLE_TYPE x[] = { 1.0e+001, 1.0e+002, 1.0e+004, 1.0e+008, 1.0e+016, 1.0e+032, 1.0e+064, 1.0e+128, 1.0e+256 }; LONGDOUBLE_TYPE r = 1.0; int i; assert( E>=0 && E<=307 ); for(i=0; E!=0; i++, E >>=1){ if( E & 1 ) r *= x[i]; } |
︙ | ︙ | |||
429 430 431 432 433 434 435 | ** 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 | | < < < < < < < | < < < | | | < < < < < | | | > | | | | < < < < | < | 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 | ** 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. 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. */ int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){ #ifndef SQLITE_OMIT_FLOATING_POINT int incr; const char *zEnd = z + length; /* sign * significand * (10 ^ (esign * exponent)) */ int sign = 1; /* sign of significand */ i64 s = 0; /* significand */ int d = 0; /* adjust exponent for shifting decimal point */ int esign = 1; /* sign of exponent */ int e = 0; /* exponent */ int eValid = 1; /* True exponent is either not used or is well-formed */ double result; int nDigits = 0; int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */ assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); *pResult = 0.0; /* Default return value, in case of an error */ if( enc==SQLITE_UTF8 ){ incr = 1; }else{ int i; incr = 2; assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 ); for(i=3-enc; i<length && z[i]==0; i+=2){} nonNum = i<length; zEnd = &z[i^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<((LARGEST_INT64-9)/10) ){ s = s*10 + (*z - '0'); z+=incr; nDigits++; } /* skip non-significant significand digits ** (increase exponent by d to shift decimal left) */ while( z<zEnd && sqlite3Isdigit(*z) ){ z+=incr; nDigits++; d++; } if( z>=zEnd ) goto do_atof_calc; /* if decimal point is present */ if( *z=='.' ){ z+=incr; /* 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--; } z+=incr; nDigits++; } } if( z>=zEnd ) goto do_atof_calc; /* if exponent is present */ if( *z=='e' || *z=='E' ){ z+=incr; eValid = 0; /* 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 */ |
︙ | ︙ | |||
632 633 634 635 636 637 638 | } } /* store the result */ *pResult = result; /* return true if number and no extra non-whitespace chracters after */ | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 | } } /* store the result */ *pResult = result; /* return true if number and no extra non-whitespace chracters after */ return z==zEnd && nDigits>0 && eValid && nonNum==0; #else return !sqlite3Atoi64(z, pResult, length, enc); #endif /* SQLITE_OMIT_FLOATING_POINT */ } /* ** Compare the 19-character string zNum against the text representation ** 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. ** |
︙ | ︙ | |||
712 713 714 715 716 717 718 | /* ** Convert zNum to a 64-bit signed integer. zNum must be decimal. This ** routine does *not* accept hexadecimal notation. ** ** Returns: ** | < | 616 617 618 619 620 621 622 623 624 625 626 627 628 629 | /* ** 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 |
︙ | ︙ | |||
737 738 739 740 741 742 743 | 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; | < | 640 641 642 643 644 645 646 647 648 649 650 651 652 653 | 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; |
︙ | ︙ | |||
773 774 775 776 777 778 779 | *pNum = neg ? SMALLEST_INT64 : LARGEST_INT64; }else if( neg ){ *pNum = -(i64)u; }else{ *pNum = (i64)u; } rc = 0; | | < | > | 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 | *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 */ || 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; |
︙ | ︙ | |||
916 917 918 919 920 921 922 | /* ** 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; | | < < < < < < < < < < < < < < < < < < | 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 | /* ** 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; if( z ) sqlite3GetInt32(z, &x); return x; } /* ** 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 ** C = xxxxxxxx 8 bits of data |
︙ | ︙ | |||
1024 1025 1026 1027 1028 1029 1030 | /* ** 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; | < | > > > > | > > > > > > > > | | | < | 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 | /* ** 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; a = *p; /* a: p0 (unmasked) */ if (!(a&0x80)) { *v = a; return 1; } p++; b = *p; /* b: p1 (unmasked) */ if (!(b&0x80)) { a &= 0x7f; a = a<<7; a |= b; *v = a; 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)) ); p++; a = a<<14; a |= *p; /* a: p0<<14 | p2 (unmasked) */ if (!(a&0x80)) { a &= SLOT_2_0; b &= 0x7f; b = b<<7; |
︙ | ︙ | |||
1240 1241 1242 1243 1244 1245 1246 | ** routine. */ #if 1 { u64 v64; u8 n; | > | | 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 | ** routine. */ #if 1 { u64 v64; u8 n; p -= 2; n = sqlite3GetVarint(p, &v64); assert( n>3 && n<=9 ); if( (v64 & SQLITE_MAX_U32)!=v64 ){ *v = 0xffffffff; }else{ *v = (u32)v64; } return n; |
︙ | ︙ | |||
1367 1368 1369 1370 1371 1372 1373 | #endif #ifdef SQLITE_EBCDIC h += 9*(1&~(h>>4)); #endif return (u8)(h & 0xf); } | | | | 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 | #endif #ifdef SQLITE_EBCDIC h += 9*(1&~(h>>4)); #endif return (u8)(h & 0xf); } #if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) /* ** 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 || SQLITE_HAS_CODEC */ /* ** 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){ |
︙ | ︙ | |||
1417 1418 1419 1420 1421 1422 1423 | ** ** 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){ | | | | | | | | | | 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 | ** ** 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){ u32 magic; if( db==0 ){ logBadConnection("NULL"); return 0; } magic = db->magic; if( magic!=SQLITE_MAGIC_OPEN ){ if( sqlite3SafetyCheckSickOrOk(db) ){ testcase( sqlite3GlobalConfig.xLog!=0 ); logBadConnection("unopened"); } return 0; }else{ return 1; } } int sqlite3SafetyCheckSickOrOk(sqlite3 *db){ u32 magic; magic = db->magic; if( magic!=SQLITE_MAGIC_SICK && magic!=SQLITE_MAGIC_OPEN && magic!=SQLITE_MAGIC_BUSY ){ testcase( sqlite3GlobalConfig.xLog!=0 ); logBadConnection("invalid"); return 0; }else{ return 1; } } |
︙ | ︙ | |||
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 | while( x>255 ){ y += 40; x >>= 4; } /*OPTIMIZATION-IF-TRUE*/ while( x>15 ){ y += 10; x >>= 1; } #endif } return a[x&7] + y - 10; } /* ** Convert a double into a LogEst ** In other words, compute an approximation for 10*log2(x). */ LogEst sqlite3LogEstFromDouble(double x){ u64 a; LogEst e; assert( sizeof(x)==8 && sizeof(a)==8 ); if( x<=1 ) return 0; if( x<=2000000000 ) return sqlite3LogEst((u64)x); memcpy(&a, &x, 8); e = (a>>52) - 1022; return e*10; } /* ** Convert a LogEst into an integer. */ u64 sqlite3LogEstToInt(LogEst x){ u64 n; n = x%10; x /= 10; if( n>=5 ) n -= 2; else if( n>=1 ) n -= 1; if( x>60 ) return (u64)LARGEST_INT64; return x>=3 ? (n+8)<<(x-3) : (n+8)>>(3-x); } /* ** Add a new name/number pair to a VList. This might require that the ** VList object be reallocated, so return the new VList. If an OOM ** error occurs, the original VList returned and the ** db->mallocFailed flag is set. ** | > > > > > > > > > > > > > > > > | 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 | while( x>255 ){ y += 40; x >>= 4; } /*OPTIMIZATION-IF-TRUE*/ while( x>15 ){ y += 10; x >>= 1; } #endif } return a[x&7] + y - 10; } #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Convert a double into a LogEst ** In other words, compute an approximation for 10*log2(x). */ LogEst sqlite3LogEstFromDouble(double x){ u64 a; LogEst e; assert( sizeof(x)==8 && sizeof(a)==8 ); if( x<=1 ) return 0; if( x<=2000000000 ) return sqlite3LogEst((u64)x); memcpy(&a, &x, 8); e = (a>>52) - 1022; return e*10; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \ defined(SQLITE_ENABLE_STAT3_OR_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_STAT3_OR_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 */ /* ** Add a new name/number pair to a VList. This might require that the ** VList object be reallocated, so return the new VList. If an OOM ** error occurs, the original VList returned and the ** db->mallocFailed flag is set. ** |
︙ | ︙ | |||
1733 1734 1735 1736 1737 1738 1739 | do{ const char *z = (const char*)&pIn[i+2]; if( strncmp(z,zName,nName)==0 && z[nName]==0 ) return pIn[i]; i += pIn[i+1]; }while( i<mx ); return 0; } | < < < < < < < < < | 1644 1645 1646 1647 1648 1649 1650 | do{ const char *z = (const char*)&pIn[i+2]; if( strncmp(z,zName,nName)==0 && z[nName]==0 ) return pIn[i]; i += pIn[i+1]; }while( i<mx ); return 0; } |
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_master.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 | ** 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; | < | 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | ** 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 |
︙ | ︙ | |||
147 148 149 150 151 152 153 | 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 */ | | | < | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | 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 */ int saved_nChange; /* Saved value of db->nChange */ int 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"); |
︙ | ︙ | |||
229 230 231 232 233 234 235 | 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; | | | | | > | > > > > > < > | | < < | 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 | 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 = sqlite3BtreeGetOptimalReserve(pMain); /* A VACUUM cannot change the pagesize of an encrypted database. */ #ifdef SQLITE_HAS_CODEC if( db->nextPagesize ){ extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); int nKey; char *zKey; sqlite3CodecGetKey(db, iDb, (void**)&zKey, &nKey); if( nKey ) db->nextPagesize = 0; } #endif 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 ){ db->nextPagesize = 0; } if( sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain), nRes, 0) || (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes, 0)) || NEVER(db->mallocFailed) ){ |
︙ | ︙ | |||
276 277 278 279 280 281 282 | #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, | | | | | | | | 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 | #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_master" " 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_master" " 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_master " "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 SQLITE_MASTER table. */ rc = execSqlF(db, pzErrMsg, "INSERT INTO vacuum_db.sqlite_master" " SELECT*FROM \"%w\".sqlite_master" " 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 |
︙ | ︙ | |||
343 344 345 346 347 348 349 | 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 */ }; | | | | 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 | BTREE_SCHEMA_VERSION, 1, /* Add one to the old schema cookie */ BTREE_DEFAULT_CACHE_SIZE, 0, /* Preserve the default page cache size */ BTREE_TEXT_ENCODING, 0, /* Preserve the text encoding */ BTREE_USER_VERSION, 0, /* Preserve the user version */ BTREE_APPLICATION_ID, 0, /* Preserve the application id */ }; assert( 1==sqlite3BtreeIsInTrans(pTemp) ); assert( pOut!=0 || 1==sqlite3BtreeIsInTrans(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]); |
︙ | ︙ | |||
370 371 372 373 374 375 376 | sqlite3BtreeSetAutoVacuum(pMain, sqlite3BtreeGetAutoVacuum(pTemp)); } #endif } assert( rc==SQLITE_OK ); if( pOut==0 ){ | < | | 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 | sqlite3BtreeSetAutoVacuum(pMain, sqlite3BtreeGetAutoVacuum(pTemp)); } #endif } assert( rc==SQLITE_OK ); if( pOut==0 ){ rc = sqlite3BtreeSetPageSize(pMain, sqlite3BtreeGetPageSize(pTemp), nRes,1); } end_of_vacuum: /* 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, -1, 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. |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
113 114 115 116 117 118 119 | */ #if defined(SQLITE_TEST) && !defined(SQLITE_UNTESTABLE) # define UPDATE_MAX_BLOBSIZE(P) updateMaxBlobsize(P) #else # define UPDATE_MAX_BLOBSIZE(P) #endif | < < < < < < < < < < < < < < < < < < < < < < < | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | */ #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. ** ** M is the type of branch. I is the direction taken for this instance of ** the branch. |
︙ | ︙ | |||
214 215 216 217 218 219 220 221 222 223 224 225 226 227 | 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. ** | > > > > > > > > | 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | if( (mNever&0x08)!=0 && (I&0x05)!=0) I |= 0x05; /*NO_TEST*/ } sqlite3GlobalConfig.xVdbeBranch(sqlite3GlobalConfig.pVdbeBranchArg, iSrcLine&0xffffff, I, M); } #endif /* ** Convert the given register into a string if it isn't one ** already. Return non-zero if a malloc() fails. */ #define Stringify(P, enc) \ if(((P)->flags&(MEM_Str|MEM_Blob))==0 && sqlite3VdbeMemStringify(P,enc,0)) \ { goto no_mem; } /* ** 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. ** |
︙ | ︙ | |||
240 241 242 243 244 245 246 247 248 249 250 251 252 253 | ** Allocate VdbeCursor number iCur. Return a pointer to it. Return NULL ** if we run out of memory. */ static VdbeCursor *allocateCursor( Vdbe *p, /* The virtual machine */ int iCur, /* Index of the new VdbeCursor */ int nField, /* Number of fields in the table or index */ u8 eCurType /* Type of the new cursor */ ){ /* Find the memory cell that will be used to store the blob of memory ** required for this VdbeCursor structure. It is convenient to use a ** vdbe memory cell to manage the memory allocation required for a ** VdbeCursor structure for the following reasons: ** | > | 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | ** Allocate VdbeCursor number iCur. Return a pointer to it. Return NULL ** if we run out of memory. */ static VdbeCursor *allocateCursor( Vdbe *p, /* The virtual machine */ int iCur, /* Index of the new VdbeCursor */ int nField, /* Number of fields in the table or index */ int iDb, /* Database the cursor belongs to, or -1 */ u8 eCurType /* Type of the new cursor */ ){ /* Find the memory cell that will be used to store the blob of memory ** required for this VdbeCursor structure. It is convenient to use a ** vdbe memory cell to manage the memory allocation required for a ** VdbeCursor structure for the following reasons: ** |
︙ | ︙ | |||
265 266 267 268 269 270 271 | ** Cursor 2 is at Mem[p->nMem-2]. And so forth. */ Mem *pMem = iCur>0 ? &p->aMem[p->nMem-iCur] : p->aMem; int nByte; VdbeCursor *pCx = 0; nByte = | | > > > > > | < | < < < < < < < < < < < < < < < < < < | | | > | | | | | | > < < < < < < < < < < < < < < < < > < | | | | | 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 | ** Cursor 2 is at Mem[p->nMem-2]. And so forth. */ Mem *pMem = iCur>0 ? &p->aMem[p->nMem-iCur] : p->aMem; int nByte; VdbeCursor *pCx = 0; nByte = ROUND8(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField + (eCurType==CURTYPE_BTREE?sqlite3BtreeCursorSize():0); assert( iCur>=0 && iCur<p->nCursor ); if( p->apCsr[iCur] ){ /*OPTIMIZATION-IF-FALSE*/ /* Before calling sqlite3VdbeFreeCursor(), ensure the isEphemeral flag ** is clear. Otherwise, if this is an ephemeral cursor created by ** OP_OpenDup, the cursor will not be closed and will still be part ** of a BtShared.pCursor list. */ p->apCsr[iCur]->isEphemeral = 0; sqlite3VdbeFreeCursor(p, p->apCsr[iCur]); p->apCsr[iCur] = 0; } if( SQLITE_OK==sqlite3VdbeMemClearAndResize(pMem, nByte) ){ p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z; 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; } /* ** 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; i64 iValue; u8 enc = pRec->enc; assert( (pRec->flags & (MEM_Str|MEM_Int|MEM_Real))==MEM_Str ); if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return; if( 0==sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){ pRec->u.i = iValue; 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 |
︙ | ︙ | |||
370 371 372 373 374 375 376 | ** SQLITE_AFF_NUMERIC: ** Try to convert pRec to an integer representation or a ** floating-point representation if an integer representation ** is not possible. Note that the integer representation is ** always preferred, even if the affinity is REAL, because ** an integer representation is more space efficient on disk. ** | < < < < < | | | | < < < | | 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 | ** SQLITE_AFF_NUMERIC: ** Try to convert pRec to an integer representation or a ** floating-point representation if an integer representation ** is not possible. Note that the integer representation is ** 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 */ ){ if( affinity>=SQLITE_AFF_NUMERIC ){ assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL || affinity==SQLITE_AFF_NUMERIC ); if( (pRec->flags & MEM_Int)==0 ){ /*OPTIMIZATION-IF-FALSE*/ if( (pRec->flags & MEM_Real)==0 ){ if( pRec->flags & MEM_Str ) applyNumericAffinity(pRec,1); }else{ sqlite3VdbeIntegerAffinity(pRec); } } }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)) ){ sqlite3VdbeMemStringify(pRec, enc, 1); } } pRec->flags &= ~(MEM_Real|MEM_Int); } } /* ** 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 |
︙ | ︙ | |||
449 450 451 452 453 454 455 | /* ** 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){ | < < | | < < < | < < < | < < | | < < < | < < < | | < < | > | > > > > | > | | > < | < > > < > | > > | | | | | | > | > > | | | > > > | > > | > > < < | < | < | | | < < < < < < < < < < < < < < < < < < < < > > > > > > > > > > > | 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 | /* ** 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){ assert( (pMem->flags & (MEM_Int|MEM_Real))==0 ); assert( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ); ExpandBlob(pMem); if( sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc)==0 ){ return 0; } if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==0 ){ 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) ){ return pMem->flags & (MEM_Int|MEM_Real); } if( pMem->flags & (MEM_Str|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, char *zBuf){ char *zCsr = zBuf; 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'; } *(zCsr++) = c; sqlite3_snprintf(100, zCsr, "%d[", pMem->n); zCsr += sqlite3Strlen30(zCsr); for(i=0; i<16 && i<pMem->n; i++){ sqlite3_snprintf(100, zCsr, "%02X", ((int)pMem->z[i] & 0xFF)); zCsr += sqlite3Strlen30(zCsr); } for(i=0; i<16 && i<pMem->n; i++){ char z = pMem->z[i]; if( z<32 || z>126 ) *zCsr++ = '.'; else *zCsr++ = z; } *(zCsr++) = ']'; if( f & MEM_Zero ){ sqlite3_snprintf(100, zCsr,"+%dz",pMem->u.nZero); zCsr += sqlite3Strlen30(zCsr); } *zCsr = '\0'; }else if( f & MEM_Str ){ int j, k; zBuf[0] = ' '; if( f & MEM_Dyn ){ zBuf[1] = 'z'; assert( (f & (MEM_Static|MEM_Ephem))==0 ); }else if( f & MEM_Static ){ zBuf[1] = 't'; assert( (f & (MEM_Dyn|MEM_Ephem))==0 ); }else if( f & MEM_Ephem ){ zBuf[1] = 'e'; assert( (f & (MEM_Static|MEM_Dyn))==0 ); }else{ zBuf[1] = 's'; } k = 2; sqlite3_snprintf(100, &zBuf[k], "%d", pMem->n); k += sqlite3Strlen30(&zBuf[k]); zBuf[k++] = '['; for(j=0; j<15 && j<pMem->n; j++){ u8 c = pMem->z[j]; if( c>=0x20 && c<0x7f ){ zBuf[k++] = c; }else{ zBuf[k++] = '.'; } } zBuf[k++] = ']'; sqlite3_snprintf(100,&zBuf[k], encnames[pMem->enc]); k += sqlite3Strlen30(&zBuf[k]); zBuf[k++] = 0; } } #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_Int ){ printf(" i:%lld", p->u.i); #ifndef SQLITE_OMIT_FLOATING_POINT }else if( p->flags & MEM_Real ){ printf(" r:%g", p->u.r); #endif }else if( sqlite3VdbeMemIsRowSet(p) ){ printf(" (rowset)"); }else{ char zBuf[200]; sqlite3VdbeMemPrettyPrint(p, zBuf); printf(" %s", zBuf); } if( p->flags & MEM_Subtype ) printf(" subtype=0x%02x", p->eSubtype); } static void registerTrace(int iReg, Mem *p){ printf("REG[%d] = ", iReg); memTracePrint(p); printf("\n"); sqlite3VdbeCheckMemInvariants(p); } #endif #ifdef SQLITE_DEBUG # define REGISTER_TRACE(R,M) if(db->flags&SQLITE_VdbeTrace)registerTrace(R,M) #else # define REGISTER_TRACE(R,M) #endif #ifdef VDBE_PROFILE /* ** hwtime.h contains inline assembler code for implementing ** high-performance timing routines. */ #include "hwtime.h" #endif #ifndef NDEBUG /* ** This function is only called from within an assert() expression. It ** checks that the sqlite3.nTransaction variable is correctly set to ** the number of non-transaction savepoints currently in the |
︙ | ︙ | |||
663 664 665 666 667 668 669 | return out2PrereleaseWithClear(pOut); }else{ pOut->flags = MEM_Int; return pOut; } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > > < | | | | | < | < | < < > | | 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 | 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 */ ){ Op *aOp = p->aOp; /* Copy of p->aOp */ Op *pOp = aOp; /* Current operation */ #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) Op *pOrigOp; /* Value of pOp at the top of the loop */ #endif #ifdef SQLITE_DEBUG 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 */ unsigned nVmStep = 0; /* Number of virtual machine steps */ #ifndef SQLITE_OMIT_PROGRESS_CALLBACK unsigned 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->magic==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 = 0xffffffff; } #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 ); assert( p->bIsReader || p->readOnly!=0 ); p->iCurrentTime = 0; assert( p->explain==0 ); p->pResultSet = 0; db->busyHandler.nBusy = 0; if( 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; |
︙ | ︙ | |||
793 794 795 796 797 798 799 | #endif for(pOp=&aOp[p->pc]; 1; pOp++){ /* Errors are detected by individual opcodes, with an immediate ** jumps to abort_due_to_error. */ assert( rc==SQLITE_OK ); assert( pOp>=aOp && pOp<&aOp[p->nOp]); | < < < < | | | | > > < | 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 | #endif for(pOp=&aOp[p->pc]; 1; pOp++){ /* Errors are detected by individual opcodes, with an immediate ** jumps to abort_due_to_error. */ assert( rc==SQLITE_OK ); assert( pOp>=aOp && pOp<&aOp[p->nOp]); #ifdef VDBE_PROFILE start = sqlite3NProfileCnt ? sqlite3NProfileCnt : sqlite3Hwtime(); #endif nVmStep++; #ifdef SQLITE_ENABLE_STMT_SCANSTATUS if( p->anExec ) p->anExec[(int)(pOp-aOp)]++; #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. */ |
︙ | ︙ | |||
862 863 864 865 866 867 868 | if( (opProperty & OPFLG_OUT3)!=0 ){ assert( pOp->p3>0 ); assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); memAboutToChange(p, &aMem[pOp->p3]); } } #endif | | | 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 | if( (opProperty & OPFLG_OUT3)!=0 ){ assert( pOp->p3>0 ); assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); memAboutToChange(p, &aMem[pOp->p3]); } } #endif #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) pOrigOp = pOp; #endif switch( pOp->opcode ){ /***************************************************************************** ** What follows is a massive switch statement where each case implements a |
︙ | ︙ | |||
916 917 918 919 920 921 922 | ** ** 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 */ | < < < < < < < < < < < < < < | | | 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 | ** ** 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: if( 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 = 0xffffffff; rc = SQLITE_INTERRUPT; goto abort_due_to_error; } } #endif break; |
︙ | ︙ | |||
979 980 981 982 983 984 985 | assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); pIn1 = &aMem[pOp->p1]; assert( VdbeMemDynamic(pIn1)==0 ); memAboutToChange(p, pIn1); pIn1->flags = MEM_Int; pIn1->u.i = (int)(pOp-aOp); REGISTER_TRACE(pOp->p1, pIn1); | > > > | > > | | < < < < < < < < < | < < < < < < < < | < | < < < > | 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 | assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); pIn1 = &aMem[pOp->p1]; assert( VdbeMemDynamic(pIn1)==0 ); memAboutToChange(p, pIn1); pIn1->flags = MEM_Int; pIn1->u.i = (int)(pOp-aOp); REGISTER_TRACE(pOp->p1, pIn1); /* Most jump operations do a goto to this spot in order to update ** the pOp pointer. */ jump_to_p2: pOp = &aOp[pOp->p2 - 1]; break; } /* Opcode: Return P1 * * * * ** ** Jump to the next instruction after the address in register P1. After ** the jump, register P1 becomes undefined. */ case OP_Return: { /* in1 */ pIn1 = &aMem[pOp->p1]; assert( pIn1->flags==MEM_Int ); pOp = &aOp[pIn1->u.i]; pIn1->flags = MEM_Undefined; break; } /* Opcode: InitCoroutine P1 P2 P3 * * ** ** Set up register P1 so that it will Yield to the coroutine ** located at address P3. |
︙ | ︙ | |||
1034 1035 1036 1037 1038 1039 1040 | assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); assert( pOp->p2>=0 && pOp->p2<p->nOp ); assert( pOp->p3>=0 && pOp->p3<p->nOp ); pOut = &aMem[pOp->p1]; assert( !VdbeMemDynamic(pOut) ); pOut->u.i = pOp->p3 - 1; pOut->flags = MEM_Int; | < < < < | < < < | 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 | assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) ); assert( pOp->p2>=0 && pOp->p2<p->nOp ); assert( pOp->p3>=0 && pOp->p3<p->nOp ); pOut = &aMem[pOp->p1]; assert( !VdbeMemDynamic(pOut) ); pOut->u.i = pOp->p3 - 1; pOut->flags = MEM_Int; if( pOp->p2 ) goto jump_to_p2; break; } /* Opcode: EndCoroutine P1 * * * * ** ** The instruction at the address in register P1 is a Yield. ** Jump to the P2 parameter of that Yield. |
︙ | ︙ | |||
1106 1107 1108 1109 1110 1111 1112 | 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 */ | < | 967 968 969 970 971 972 973 974 975 976 977 978 979 980 | 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. ** |
︙ | ︙ | |||
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 | ** every program. So a jump past the last instruction of the program ** is the same as executing Halt. */ case OP_Halt: { VdbeFrame *pFrame; int pcx; #ifdef SQLITE_DEBUG if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); } #endif | > < < < < < < | | 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 | ** every program. So a jump past the last instruction of the program ** is the same as executing Halt. */ case OP_Halt: { VdbeFrame *pFrame; int pcx; pcx = (int)(pOp - aOp); #ifdef SQLITE_DEBUG if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); } #endif if( pOp->p1==SQLITE_OK && p->pFrame ){ /* Halt the sub-program. Return control to the parent frame. */ pFrame = p->pFrame; p->pFrame = pFrame->pParent; p->nFrame--; sqlite3VdbeSetChanges(db, p->nChange); pcx = sqlite3VdbeFrameRestore(pFrame); if( pOp->p2==OE_Ignore ){ |
︙ | ︙ | |||
1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 | aOp = p->aOp; aMem = p->aMem; pOp = &aOp[pcx]; break; } p->rc = pOp->p1; p->errorAction = (u8)pOp->p2; assert( pOp->p5<=4 ); if( p->rc ){ if( pOp->p5 ){ static const char * const azType[] = { "NOT NULL", "UNIQUE", "CHECK", "FOREIGN KEY" }; testcase( pOp->p5==1 ); testcase( pOp->p5==2 ); testcase( pOp->p5==3 ); testcase( pOp->p5==4 ); sqlite3VdbeError(p, "%s constraint failed", azType[pOp->p5-1]); if( pOp->p4.z ){ p->zErrMsg = sqlite3MPrintf(db, "%z: %s", p->zErrMsg, pOp->p4.z); } }else{ sqlite3VdbeError(p, "%s", pOp->p4.z); } | > < | 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 | aOp = p->aOp; aMem = p->aMem; pOp = &aOp[pcx]; break; } p->rc = pOp->p1; p->errorAction = (u8)pOp->p2; p->pc = pcx; assert( pOp->p5<=4 ); if( p->rc ){ if( pOp->p5 ){ static const char * const azType[] = { "NOT NULL", "UNIQUE", "CHECK", "FOREIGN KEY" }; testcase( pOp->p5==1 ); testcase( pOp->p5==2 ); testcase( pOp->p5==3 ); testcase( pOp->p5==4 ); sqlite3VdbeError(p, "%s constraint failed", azType[pOp->p5-1]); if( pOp->p4.z ){ p->zErrMsg = sqlite3MPrintf(db, "%z: %s", p->zErrMsg, pOp->p4.z); } }else{ sqlite3VdbeError(p, "%s", pOp->p4.z); } sqlite3_log(pOp->p1, "abort at %d in [%s]: %s", pcx, p->zSql, p->zErrMsg); } rc = sqlite3VdbeHalt(p); assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR ); if( rc==SQLITE_BUSY ){ p->rc = SQLITE_BUSY; }else{ |
︙ | ︙ | |||
1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 | ** 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; | > | 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 | ** 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->opcode = OP_String; 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; |
︙ | ︙ | |||
1279 1280 1281 1282 1283 1284 1285 | pOp->p4.z = pOut->z; pOp->p1 = pOut->n; } #endif if( pOp->p1>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } | < < | 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 | pOp->p4.z = pOut->z; pOp->p1 = pOut->n; } #endif if( pOp->p1>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } assert( rc==SQLITE_OK ); /* Fall through to the next case, OP_String */ } /* 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. ** |
︙ | ︙ | |||
1316 1317 1318 1319 1320 1321 1322 | assert( pIn3->flags & MEM_Int ); if( pIn3->u.i==pOp->p5 ) pOut->flags = MEM_Blob|MEM_Static|MEM_Term; } #endif break; } | < < < < < < < < < < < < < < < < < < < < < < < | 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 | assert( pIn3->flags & MEM_Int ); if( pIn3->u.i==pOp->p5 ) pOut->flags = MEM_Blob|MEM_Static|MEM_Term; } #endif break; } /* Opcode: Null P1 P2 P3 * * ** Synopsis: r[P2..P3]=NULL ** ** Write a NULL into registers P2. If P3 greater than P2, then also write ** NULL into register P3 and every register in between P2 and P3. If P3 ** is less than P2 (typically P3 is zero) then only register P2 is ** set to NULL. ** ** If the P1 value is non-zero, then also set the MEM_Cleared flag so that ** NULL values will not compare equal even if SQLITE_NULLEQ is set on ** OP_Ne or OP_Eq. */ case OP_Null: { /* out2 */ int cnt; u16 nullFlag; pOut = out2Prerelease(p, pOp); cnt = pOp->p3-pOp->p2; assert( pOp->p3<=(p->nMem+1 - p->nCursor) ); pOut->flags = nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null; |
︙ | ︙ | |||
1392 1393 1394 1395 1396 1397 1398 | break; } /* Opcode: Blob P1 P2 * P4 * ** Synopsis: r[P2]=P4 (len=P1) ** ** P4 points to a blob of data P1 bytes long. Store this | | < < < < < | < | 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 | break; } /* Opcode: Blob P1 P2 * P4 * ** Synopsis: r[P2]=P4 (len=P1) ** ** P4 points to a blob of data P1 bytes long. Store this ** blob in register P2. */ case OP_Blob: { /* out2 */ assert( pOp->p1 <= SQLITE_MAX_LENGTH ); pOut = out2Prerelease(p, pOp); sqlite3VdbeMemSetStr(pOut, pOp->p4.z, pOp->p1, 0, 0); pOut->enc = encoding; UPDATE_MAX_BLOBSIZE(pOut); break; } /* Opcode: Variable P1 P2 * P4 * ** Synopsis: r[P2]=parameter(P1,P4) |
︙ | ︙ | |||
1464 1465 1466 1467 1468 1469 1470 | 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 | | < < < | < < | < < < < < < < < | 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 | 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 if( pOut->pScopyFrom>=&aMem[p1] && pOut->pScopyFrom<pOut ){ pOut->pScopyFrom += pOp->p2 - p1; } #endif Deephemeralize(pOut); REGISTER_TRACE(p2++, pOut); pIn1++; pOut++; }while( --n ); break; } /* Opcode: Copy P1 P2 P3 * * ** Synopsis: r[P2@P3+1]=r[P1@P3+1] ** ** Make a copy of registers P1..P1+P3 into registers P2..P2+P3. ** ** This instruction makes a deep copy of the value. A duplicate ** is made of any string or blob constant. See also OP_SCopy. */ case OP_Copy: { int n; n = pOp->p3; pIn1 = &aMem[pOp->p1]; pOut = &aMem[pOp->p2]; assert( pOut!=pIn1 ); while( 1 ){ memAboutToChange(p, pOut); sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem); Deephemeralize(pOut); #ifdef SQLITE_DEBUG pOut->pScopyFrom = 0; #endif REGISTER_TRACE(pOp->p2+pOp->p3-n, pOut); if( (n--)==0 ) break; pOut++; pIn1++; |
︙ | ︙ | |||
1560 1561 1562 1563 1564 1565 1566 | pIn1 = &aMem[pOp->p1]; assert( (pIn1->flags & MEM_Int)!=0 ); pOut = &aMem[pOp->p2]; sqlite3VdbeMemSetInt64(pOut, pIn1->u.i); break; } | < < < < < < < < < < < < < < < < < < > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < | > > > > | < | | > > > > | < < < < < < | < < > | > > > | < < < < < < | < < < < | | < < < | < < < < < < < < < < | 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 | 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 ); assert( pOp->p1>0 ); assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 ); /* If this statement has violated immediate foreign key constraints, do ** not return the number of rows modified. And do not RELEASE the statement ** transaction. It needs to be rolled back. */ if( SQLITE_OK!=(rc = sqlite3VdbeCheckFk(p, 0)) ){ assert( db->flags&SQLITE_CountRows ); assert( p->usesStmtJournal ); goto abort_due_to_error; } /* If the SQLITE_CountRows flag is set in sqlite3.flags mask, then ** DML statements invoke this opcode to return the number of rows ** modified to the user. This is the only way that a VM that ** opens a statement transaction may invoke this opcode. ** ** In case this is such a statement, close any statement transaction ** opened by this VM before returning control to the user. This is to ** ensure that statement-transactions are always nested, not overlapping. ** If the open statement-transaction is not closed here, then the user ** may step another VM that opens its own statement transaction. This ** may lead to overlapping statement transactions. ** ** The statement transaction is never a top-level transaction. Hence ** the RELEASE call below can never fail. */ assert( p->iStatement==0 || db->flags&SQLITE_CountRows ); rc = sqlite3VdbeCloseStatement(p, SAVEPOINT_RELEASE); assert( rc==SQLITE_OK ); /* 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]); } if( db->mallocFailed ) goto no_mem; if( db->mTrace & SQLITE_TRACE_ROW ){ db->xTrace(SQLITE_TRACE_ROW, db->pTraceArg, p, 0); } /* Return SQLITE_ROW */ p->pc = (int)(pOp - aOp) + 1; rc = SQLITE_ROW; goto vdbe_return; } /* Opcode: Concat P1 P2 P3 * * ** Synopsis: r[P3]=r[P2]+r[P1] ** ** Add the text in register P1 onto the end of the text in ** register P2 and store the result in register P3. ** If either the P1 or P2 text are NULL then store NULL in P3. ** ** 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; pIn1 = &aMem[pOp->p1]; pIn2 = &aMem[pOp->p2]; pOut = &aMem[pOp->p3]; assert( pIn1!=pOut ); if( (pIn1->flags | pIn2->flags) & MEM_Null ){ sqlite3VdbeMemSetNull(pOut); break; } if( ExpandBlob(pIn1) || ExpandBlob(pIn2) ) goto no_mem; Stringify(pIn1, encoding); Stringify(pIn2, encoding); nByte = pIn1->n + pIn2->n; if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } if( sqlite3VdbeMemGrow(pOut, (int)nByte+2, pOut==pIn2) ){ goto no_mem; } MemSetTypeFlag(pOut, MEM_Str); if( pOut!=pIn2 ){ memcpy(pOut->z, pIn2->z, pIn2->n); } memcpy(&pOut->z[pIn2->n], pIn1->z, pIn1->n); pOut->z[nByte]=0; pOut->z[nByte+1] = 0; pOut->flags |= MEM_Term; pOut->n = (int)nByte; pOut->enc = encoding; UPDATE_MAX_BLOBSIZE(pOut); break; |
︙ | ︙ | |||
1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 | ** 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 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]; | > > | | > < > | | < < | 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 | ** 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 */ char bIntint; /* Started out as two integer operands */ 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; bIntint = 1; 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; iB /= iA; break; } default: { if( iA==0 ) goto arithmetic_result_is_null; if( iA==-1 ) iA = 1; iB %= iA; break; } } pOut->u.i = iB; MemSetTypeFlag(pOut, MEM_Int); }else if( (flags & MEM_Null)!=0 ){ goto arithmetic_result_is_null; }else{ bIntint = 0; 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; |
︙ | ︙ | |||
1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 | 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; | > > > | 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 | MemSetTypeFlag(pOut, MEM_Int); #else if( sqlite3IsNaN(rB) ){ goto arithmetic_result_is_null; } pOut->u.r = rB; MemSetTypeFlag(pOut, MEM_Real); if( ((type1|type2)&MEM_Real)==0 && !bIntint ){ sqlite3VdbeIntegerAffinity(pOut); } #endif } break; arithmetic_result_is_null: sqlite3VdbeMemSetNull(pOut); break; |
︙ | ︙ | |||
1973 1974 1975 1976 1977 1978 1979 | ** 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]; | < | < < | 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 | ** 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 ){ sqlite3VdbeMemRealify(pIn1); } break; } #endif #ifndef SQLITE_OMIT_CAST /* Opcode: Cast P1 P2 * * * |
︙ | ︙ | |||
2009 2010 2011 2012 2013 2014 2015 | 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); | < | < < > | > | 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 | 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); sqlite3VdbeMemCast(pIn1, pOp->p2, encoding); UPDATE_MAX_BLOBSIZE(pIn1); if( rc ) goto abort_due_to_error; 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. Or if the SQLITE_STOREP2 flag is set in P5, then ** store the result of comparison in register 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 |
︙ | ︙ | |||
2048 2049 2050 2051 2052 2053 2054 | ** ** 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. ** | | | > > > > > | > | 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 | ** ** 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. ** ** If both SQLITE_STOREP2 and SQLITE_KEEPNULL flags are set then the ** content of r[P2] is only changed if the new value is NULL or 0 (false). ** In other words, a prior r[P2] value will not be overwritten by 1 (true). */ /* 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. ** ** If both SQLITE_STOREP2 and SQLITE_KEEPNULL flags are set then the ** content of r[P2] is only changed if the new value is NULL or 1 (true). ** In other words, a prior r[P2] value will not be overwritten by 0 (false). */ /* 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. Or if the SQLITE_STOREP2 flag is set in P5 store ** the result of comparison (0 or 1 or NULL) into register 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 |
︙ | ︙ | |||
2085 2086 2087 2088 2089 2090 2091 | ** 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. | < < < | 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 | ** 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. |
︙ | ︙ | |||
2125 2126 2127 2128 2129 2130 2131 | 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; | < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 | 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. */ |
︙ | ︙ | |||
2174 2175 2176 2177 2178 2179 2180 | 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. */ | > > > > > > > | | | | < < > | < | | > > > > > | > > > > > > > > | | < | | < | | > | > | > | < < < < > > > > > | > > > > > > > > | < < > > > > | | | < < < < < < < < < < < < < > > > > > > > | < < < < < < < > | | | > > > > > > > > > | > > | | | | > | 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 | 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. */ if( pOp->p5 & SQLITE_STOREP2 ){ pOut = &aMem[pOp->p2]; iCompare = 1; /* Operands are not equal */ memAboutToChange(p, pOut); MemSetTypeFlag(pOut, MEM_Null); REGISTER_TRACE(pOp->p2, pOut); }else{ VdbeBranchTaken(2,3); if( pOp->p5 & SQLITE_JUMPIFNULL ){ goto jump_to_p2; } } break; } }else{ /* Neither operand is NULL. Do a comparison. */ affinity = pOp->p5 & SQLITE_AFF_MASK; if( affinity>=SQLITE_AFF_NUMERIC ){ if( (flags1 | flags3)&MEM_Str ){ if( (flags1 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn1,0); assert( flags3==pIn3->flags ); /* testcase( flags3!=pIn3->flags ); ** this used to be possible with pIn1==pIn3, but not since ** the column cache was removed. The following assignment ** is essentially a no-op. But, it provides defense-in-depth ** in case our analysis is incorrect, so it is left in. */ flags3 = pIn3->flags; } if( (flags3 & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn3,0); } } /* Handle the common case of integer comparison here, as an ** optimization, to avoid a call to sqlite3MemCompare() */ if( (pIn1->flags & pIn3->flags & MEM_Int)!=0 ){ if( pIn3->u.i > pIn1->u.i ){ res = +1; goto compare_op; } if( pIn3->u.i < pIn1->u.i ){ res = -1; goto compare_op; } res = 0; goto compare_op; } }else if( affinity==SQLITE_AFF_TEXT ){ if( (flags1 & MEM_Str)==0 && (flags1 & (MEM_Int|MEM_Real))!=0 ){ testcase( pIn1->flags & MEM_Int ); testcase( pIn1->flags & MEM_Real ); sqlite3VdbeMemStringify(pIn1, encoding, 1); testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) ); flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask); assert( pIn1!=pIn3 ); } if( (flags3 & MEM_Str)==0 && (flags3 & (MEM_Int|MEM_Real))!=0 ){ testcase( pIn3->flags & MEM_Int ); testcase( pIn3->flags & MEM_Real ); 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); } compare_op: /* 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 ){ /* ne, eq, gt, le, lt, ge */ static const unsigned char aLTb[] = { 1, 0, 0, 1, 1, 0 }; res2 = aLTb[pOp->opcode - OP_Ne]; }else if( res==0 ){ static const unsigned char aEQb[] = { 0, 1, 0, 1, 0, 1 }; res2 = aEQb[pOp->opcode - OP_Ne]; }else{ static const unsigned char aGTb[] = { 1, 0, 1, 0, 0, 1 }; res2 = aGTb[pOp->opcode - OP_Ne]; } /* Undo any changes made by applyAffinity() to the input registers. */ assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) ); pIn1->flags = flags1; assert( (pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn) ); pIn3->flags = flags3; if( pOp->p5 & SQLITE_STOREP2 ){ pOut = &aMem[pOp->p2]; iCompare = res; if( (pOp->p5 & SQLITE_KEEPNULL)!=0 ){ /* The KEEPNULL flag prevents OP_Eq from overwriting a NULL with 1 ** and prevents OP_Ne from overwriting NULL with 0. This flag ** is only used in contexts where either: ** (1) op==OP_Eq && (r[P2]==NULL || r[P2]==0) ** (2) op==OP_Ne && (r[P2]==NULL || r[P2]==1) ** Therefore it is not necessary to check the content of r[P2] for ** NULL. */ assert( pOp->opcode==OP_Ne || pOp->opcode==OP_Eq ); assert( res2==0 || res2==1 ); testcase( res2==0 && pOp->opcode==OP_Eq ); testcase( res2==1 && pOp->opcode==OP_Eq ); testcase( res2==0 && pOp->opcode==OP_Ne ); testcase( res2==1 && pOp->opcode==OP_Ne ); if( (pOp->opcode==OP_Eq)==res2 ) break; } memAboutToChange(p, pOut); MemSetTypeFlag(pOut, MEM_Int); pOut->u.i = res2; REGISTER_TRACE(pOp->p2, pOut); }else{ VdbeBranchTaken(res2!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3); if( res2 ){ goto jump_to_p2; } } break; } /* Opcode: ElseNotEq * P2 * * * ** ** This opcode must immediately follow an OP_Lt or OP_Gt comparison operator. ** If result of an OP_Eq comparison on the same two operands ** would have be NULL or false (0), then then jump to P2. ** If the result of an OP_Eq comparison on the two previous operands ** would have been true (1), then fall through. */ case OP_ElseNotEq: { /* same as TK_ESCAPE, jump */ assert( pOp>aOp ); assert( pOp[-1].opcode==OP_Lt || pOp[-1].opcode==OP_Gt ); assert( pOp[-1].p5 & SQLITE_STOREP2 ); 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 ** instruction. The permutation is stored in the P4 operand. ** ** The permutation is only valid until the next OP_Compare that has ** the OPFLAG_PERMUTE bit set in P5. Typically the OP_Permutation should ** occur immediately prior to the OP_Compare. ** ** The first integer in the P4 integer array is the length of the array ** and does not become part of the permutation. */ case OP_Permutation: { assert( pOp->p4type==P4_INTARRAY ); assert( pOp->p4.ai ); |
︙ | ︙ | |||
2320 2321 2322 2323 2324 2325 2326 | ** P4 is a KeyInfo structure that defines collating sequences and sort ** orders for the comparison. The permutation applies to registers ** only. The KeyInfo elements are used sequentially. ** ** The comparison is a sort comparison, so NULLs compare equal, ** NULLs are less than numbers, numbers are less than strings, ** and strings are less than blobs. | < < | | | | | < < < < < < < < < < < | 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 | ** P4 is a KeyInfo structure that defines collating sequences and sort ** orders for the comparison. The permutation applies to registers ** only. The KeyInfo elements are used sequentially. ** ** The comparison is a sort comparison, so NULLs compare equal, ** NULLs are less than numbers, numbers are less than strings, ** and strings are less than blobs. */ case OP_Compare: { int n; int i; int p1; int p2; const KeyInfo *pKeyInfo; int idx; CollSeq *pColl; /* Collating sequence to use on this term */ int bRev; /* True for DESCENDING sort order */ int *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]>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] : 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->aSortOrder[i]; iCompare = sqlite3MemCompare(&aMem[p1+idx], &aMem[p2+idx], pColl); if( iCompare ){ if( bRev ) iCompare = -iCompare; break; } } break; } /* Opcode: Jump P1 P2 P3 * * ** ** Jump to the instruction at address P1, P2, or P3 depending on whether ** in the most recent OP_Compare instruction the P1 vector was less than ** equal to, or greater than the P2 vector, respectively. */ case OP_Jump: { /* jump */ if( iCompare<0 ){ VdbeBranchTaken(0,4); pOp = &aOp[pOp->p1 - 1]; }else if( iCompare==0 ){ VdbeBranchTaken(1,4); pOp = &aOp[pOp->p2 - 1]; }else{ VdbeBranchTaken(2,4); pOp = &aOp[pOp->p3 - 1]; } |
︙ | ︙ | |||
2595 2596 2597 2598 2599 2600 2601 | VdbeBranchTaken( (pIn1->flags & MEM_Null)!=0, 2); if( (pIn1->flags & MEM_Null)!=0 ){ goto jump_to_p2; } break; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 | 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 */ pIn1 = &aMem[pOp->p1]; |
︙ | ︙ | |||
2721 2722 2723 2724 2725 2726 2727 | /* Opcode: IfNullRow P1 P2 P3 * * ** Synopsis: if P1.nullRow then r[P3]=NULL, goto P2 ** ** Check the cursor P1 to see if it is currently pointing at a NULL row. ** If it is, then set register P3 to NULL and jump immediately to P2. ** If P1 is not on a NULL row, then fall through without making any ** changes. | < < < | | | 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 | /* Opcode: IfNullRow P1 P2 P3 * * ** Synopsis: if P1.nullRow then r[P3]=NULL, goto P2 ** ** Check the cursor P1 to see if it is currently pointing at a NULL row. ** If it is, then set register P3 to NULL and jump immediately to P2. ** If P1 is not on a NULL row, then fall through without making any ** changes. */ case OP_IfNullRow: { /* jump */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( p->apCsr[pOp->p1]!=0 ); if( p->apCsr[pOp->p1]->nullRow ){ sqlite3VdbeMemSetNull(aMem + pOp->p3); goto jump_to_p2; } break; } #ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC |
︙ | ︙ | |||
2756 2757 2758 2759 2760 2761 2762 | ** -DSQLITE_ENABLE_OFFSET_SQL_FUNC option. */ case OP_Offset: { /* out3 */ VdbeCursor *pC; /* The VDBE cursor */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; pOut = &p->aMem[pOp->p3]; | | < < < < < < < | < | | | | | > > | > | | | | | < < | > > > > > | > > > > | < < | > < < < < < < < < < < < < < < < < < > > | > < | | < | < | 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 | ** -DSQLITE_ENABLE_OFFSET_SQL_FUNC option. */ case OP_Offset: { /* out3 */ VdbeCursor *pC; /* The VDBE cursor */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; pOut = &p->aMem[pOp->p3]; if( NEVER(pC==0) || pC->eCurType!=CURTYPE_BTREE ){ sqlite3VdbeMemSetNull(pOut); }else{ sqlite3VdbeMemSetInt64(pOut, sqlite3BtreeOffset(pC->uc.pCursor)); } break; } #endif /* SQLITE_ENABLE_OFFSET_SQL_FUNC */ /* Opcode: Column P1 P2 P3 P4 P5 ** Synopsis: r[P3]=PX ** ** Interpret the data that cursor P1 points to as a structure built using ** the MakeRecord instruction. (See the MakeRecord opcode for additional ** information about the format of the data.) Extract the P2-th column ** from this record. If there are less that (P2+1) ** values in the record, extract a NULL. ** ** 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_CLEARCACHE bit is set on P5 and P1 is a pseudo-table cursor, ** then the cache of the cursor is reset prior to extracting the column. ** The first OP_Column against a pseudo-table after the value of the content ** register has changed should have this bit set. ** ** 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: { int 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 */ pC = p->apCsr[pOp->p1]; p2 = 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( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( pC!=0 ); assert( p2<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 ){ if( pC->eCurType==CURTYPE_PSEUDO ){ /* For the special case of as pseudo-cursor, the seekResult field ** identifies the register that holds the record */ assert( pC->seekResult>0 ); pReg = &aMem[pC->seekResult]; assert( pReg->flags & MEM_Blob ); assert( memIsValid(pReg) ); pC->payloadSize = pC->szRow = pReg->n; pC->aRow = (u8*)pReg->z; }else{ sqlite3VdbeMemSetNull(pDest); goto op_column_out; } }else{ pCrsr = pC->uc.pCursor; assert( pC->eCurType==CURTYPE_BTREE ); assert( pCrsr ); assert( sqlite3BtreeCursorIsValid(pCrsr) ); pC->payloadSize = sqlite3BtreePayloadSize(pCrsr); pC->aRow = sqlite3BtreePayloadFetch(pCrsr, &pC->szRow); assert( pC->szRow<=pC->payloadSize ); assert( pC->szRow<=65536 ); /* Maximum page size is 64KiB */ if( pC->payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } } pC->cacheStatus = p->cacheCtr; pC->iHdrOffset = getVarint32(pC->aRow, aOffset[0]); pC->nHdrParsed = 0; if( pC->szRow<aOffset[0] ){ /*OPTIMIZATION-IF-FALSE*/ /* pC->aRow does not have to hold the entire row, but it does at least ** need to cover the header of the record. If pC->aRow does not contain ** the complete header, then set it to zero, forcing the header to be ** dynamically allocated. */ pC->aRow = 0; |
︙ | ︙ | |||
2914 2915 2916 2917 2918 2919 2920 | ** database file. */ zData = pC->aRow; assert( pC->nHdrParsed<=p2 ); /* Conditional skipped */ testcase( aOffset[0]==0 ); goto op_column_read_header; } | < < < < | | 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 | ** database file. */ zData = pC->aRow; assert( pC->nHdrParsed<=p2 ); /* Conditional skipped */ testcase( aOffset[0]==0 ); goto op_column_read_header; } } /* Make sure at least the first p2+1 entries of the header have been ** parsed and valid information is in aOffset[] and pC->aType[]. */ if( pC->nHdrParsed<=p2 ){ /* 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 = sqlite3VdbeMemFromBtree(pC->uc.pCursor, 0, 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. */ |
︙ | ︙ | |||
2955 2956 2957 2958 2959 2960 2961 | offset64 += sqlite3VdbeOneByteSerialTypeLen(t); }else{ zHdr += sqlite3GetVarint32(zHdr, &t); pC->aType[i] = t; offset64 += sqlite3VdbeSerialTypeLen(t); } aOffset[++i] = (u32)(offset64 & 0xffffffff); | | | 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 | offset64 += sqlite3VdbeOneByteSerialTypeLen(t); }else{ zHdr += sqlite3GetVarint32(zHdr, &t); pC->aType[i] = t; offset64 += sqlite3VdbeSerialTypeLen(t); } aOffset[++i] = (u32)(offset64 & 0xffffffff); }while( 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)) |
︙ | ︙ | |||
2986 2987 2988 2989 2990 2991 2992 | } /* If after trying to extract new entries from the header, nHdrParsed is ** still not up to p2, that means that the record has fewer than p2 ** columns. So the result will be either the default value or a NULL. */ if( pC->nHdrParsed<=p2 ){ | < < < < < | 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 | } /* If after trying to extract new entries from the header, nHdrParsed is ** still not up to p2, that means that the record has fewer than p2 ** columns. So the result will be either the default value or a NULL. */ if( pC->nHdrParsed<=p2 ){ if( pOp->p4type==P4_MEM ){ sqlite3VdbeMemShallowCopy(pDest, pOp->p4.pMem, MEM_Static); }else{ sqlite3VdbeMemSetNull(pDest); } goto op_column_out; } }else{ t = pC->aType[p2]; } /* Extract the content for the p2+1-th column. Control can only ** reach this point if aOffset[p2], aOffset[p2+1], and pC->aType[p2] are ** all valid. */ assert( p2<pC->nHdrParsed ); assert( rc==SQLITE_OK ); assert( sqlite3VdbeCheckMemInvariants(pDest) ); if( VdbeMemDynamic(pDest) ){ sqlite3VdbeMemSetNull(pDest); } assert( t==pC->aType[p2] ); if( pC->szRow>=aOffset[p2+1] ){ /* This is the common case where the desired content fits on the original ** page - where the content is not on an overflow page */ zData = pC->aRow + aOffset[p2]; if( t<12 ){ sqlite3VdbeSerialGet(zData, t, pDest); }else{ /* If the column value is a string, we need a persistent value, not ** a MEM_Ephem value. This branch is a fast short-cut that is equivalent ** to calling sqlite3VdbeSerialGet() and sqlite3VdbeDeephemeralize(). */ static const u16 aFlag[] = { MEM_Blob, MEM_Str|MEM_Term }; pDest->n = len = (t-12)/2; pDest->enc = encoding; if( pDest->szMalloc < len+2 ){ pDest->flags = MEM_Null; if( sqlite3VdbeMemGrow(pDest, len+2, 0) ) goto no_mem; }else{ pDest->z = pDest->zMalloc; } memcpy(pDest->z, zData, len); pDest->z[len] = 0; |
︙ | ︙ | |||
3054 3055 3056 3057 3058 3059 3060 | ** 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 | | < < > | < | 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 | ** 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 up to 16. So 16 bytes of bogus content is supplied. */ static u8 aZero[16]; /* This is the bogus content */ sqlite3VdbeSerialGet(aZero, 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; } } |
︙ | ︙ | |||
3083 3084 3085 3086 3087 3088 3089 | break; }else{ rc = SQLITE_CORRUPT_BKPT; goto abort_due_to_error; } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | | < < < < < < < < < < < < < < < < < < < < < < > < < < < < < < < < < < > > > > < < | 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 | 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]; do{ assert( pIn1 <= &p->aMem[(p->nMem+1 - p->nCursor)] ); assert( memIsValid(pIn1) ); applyAffinity(pIn1, *(zAffinity++), encoding); pIn1++; }while( zAffinity[0] ); 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. */ case OP_MakeRecord: { u8 *zNewRecord; /* A buffer to hold the data for the new record */ 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 */ int i; /* Space used in zNewRecord[] header */ int j; /* Space used in zNewRecord[] content */ u32 len; /* Length of a field */ /* 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 | ** ------------------------------------------------------------------------ |
︙ | ︙ | |||
3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 | nZero = 0; /* Number of zero bytes at the end of the record */ nField = pOp->p1; zAffinity = pOp->p4.z; assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=(p->nMem+1 - p->nCursor)+1 ); pData0 = &aMem[nField]; nField = pOp->p2; pLast = &pData0[nField-1]; /* Identify the output register */ assert( pOp->p3<pOp->p1 || pOp->p3>=pOp->p1+pOp->p2 ); pOut = &aMem[pOp->p3]; memAboutToChange(p, pOut); /* Apply the requested affinity to all inputs */ assert( pData0<=pLast ); if( zAffinity ){ pRec = pData0; do{ | > | < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < | | > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | < | | > | | | > > | | < | 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 | nZero = 0; /* Number of zero bytes at the end of the record */ nField = pOp->p1; zAffinity = pOp->p4.z; assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=(p->nMem+1 - p->nCursor)+1 ); pData0 = &aMem[nField]; nField = pOp->p2; pLast = &pData0[nField-1]; file_format = p->minWriteFileFormat; /* Identify the output register */ assert( pOp->p3<pOp->p1 || pOp->p3>=pOp->p1+pOp->p2 ); pOut = &aMem[pOp->p3]; memAboutToChange(p, pOut); /* Apply the requested affinity to all inputs */ assert( pData0<=pLast ); if( zAffinity ){ pRec = pData0; do{ applyAffinity(pRec++, *(zAffinity++), encoding); 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. */ pRec = pLast; do{ assert( memIsValid(pRec) ); serial_type = sqlite3VdbeSerialType(pRec, file_format, &len); if( pRec->flags & MEM_Zero ){ if( serial_type==0 ){ /* Values with MEM_Null and MEM_Zero are created by xColumn virtual ** table methods that never invoke sqlite3_result_xxxxx() while ** computing an unchanging column value in an UPDATE statement. ** Give such values a special internal-use-only serial-type of 10 ** so that they can be passed through to xUpdate and have ** a true sqlite3_value_nochange(). */ assert( pOp->p5==OPFLAG_NOCHNG_MAGIC || CORRUPT_DB ); serial_type = 10; }else if( nData ){ if( sqlite3VdbeMemExpandBlob(pRec) ) goto no_mem; }else{ nZero += pRec->u.nZero; len -= pRec->u.nZero; } } nData += len; testcase( serial_type==127 ); testcase( serial_type==128 ); nHdr += serial_type<=127 ? 1 : sqlite3VarintLen(serial_type); pRec->uTemp = serial_type; if( pRec==pData0 ) break; pRec--; }while(1); /* EVIDENCE-OF: R-22564-11647 The header begins with a single varint ** which determines the total number of bytes in the header. The varint ** value is the size of the header in bytes including the size varint |
︙ | ︙ | |||
3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 | 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; } | > > > > > > > > > > > > > > > > > > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | | < < < < > < < < | | | < < > > | < | | 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 | if( nByte+nZero>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } if( sqlite3VdbeMemClearAndResize(pOut, (int)nByte) ){ goto no_mem; } } zNewRecord = (u8 *)pOut->z; /* Write the record */ i = putVarint32(zNewRecord, nHdr); j = 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. */ i += putVarint32(&zNewRecord[i], serial_type); /* serial type */ /* EVIDENCE-OF: R-64536-51728 The values for each column in the record ** immediately follow the header. */ j += sqlite3VdbeSerialPut(&zNewRecord[j], pRec, serial_type); /* content */ }while( (++pRec)<=pLast ); assert( i==nHdr ); assert( j==nByte ); assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); pOut->n = (int)nByte; pOut->flags = MEM_Blob; if( nZero ){ pOut->u.nZero = nZero; pOut->flags |= MEM_Zero; } REGISTER_TRACE(pOp->p3, pOut); UPDATE_MAX_BLOBSIZE(pOut); break; } /* Opcode: Count P1 P2 * * * ** Synopsis: r[P2]=count() ** ** Store the number of entries (an integer value) in the table or index ** opened by cursor P1 in register P2 */ #ifndef SQLITE_OMIT_BTREECOUNT 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 ); nEntry = 0; /* Not needed. Only used to silence a warning. */ rc = sqlite3BtreeCount(pCrsr, &nEntry); if( rc ) goto abort_due_to_error; pOut = out2Prerelease(p, pOp); pOut->u.i = nEntry; break; } #endif /* 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, P1==0. To release (commit) an ** existing savepoint, P1==1, or to rollback an existing savepoint P1==2. */ case OP_Savepoint: { int p1; /* Value of P1 operand */ char *zName; /* Name of savepoint */ int nName; Savepoint *pNew; Savepoint *pSavepoint; |
︙ | ︙ | |||
3671 3672 3673 3674 3675 3676 3677 | pNew->pNext = db->pSavepoint; db->pSavepoint = pNew; pNew->nDeferredCons = db->nDeferredCons; pNew->nDeferredImmCons = db->nDeferredImmCons; } } }else{ | < | 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 | 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); |
︙ | ︙ | |||
3711 3712 3713 3714 3715 3716 3717 | db->autoCommit = 1; if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){ p->pc = (int)(pOp - aOp); db->autoCommit = 0; p->rc = rc = SQLITE_BUSY; goto vdbe_return; } | < < < < | < > < < | 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 | db->autoCommit = 1; if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){ p->pc = (int)(pOp - aOp); db->autoCommit = 0; p->rc = rc = SQLITE_BUSY; goto vdbe_return; } db->isTransactionSavepoint = 0; rc = p->rc; }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{ 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; } } /* 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); |
︙ | ︙ | |||
3767 3768 3769 3770 3771 3772 3773 | assert( pSavepoint==db->pSavepoint ); db->pSavepoint = pSavepoint->pNext; sqlite3DbFree(db, pSavepoint); if( !isTransaction ){ db->nSavepoint--; } }else{ | < < < < | | 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 | 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; } } } if( rc ) goto abort_due_to_error; break; } /* Opcode: AutoCommit P1 P2 * * * ** ** Set the database auto-commit flag to P1 (1 or 0). If P2 is true, roll ** back any currently active btree transactions. If there are any active |
︙ | ︙ | |||
3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 | } if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){ p->pc = (int)(pOp - aOp); db->autoCommit = (u8)(1-desiredAutoCommit); p->rc = rc = SQLITE_BUSY; goto vdbe_return; } 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; } | > | | < | 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 | } if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){ p->pc = (int)(pOp - aOp); db->autoCommit = (u8)(1-desiredAutoCommit); p->rc = rc = SQLITE_BUSY; goto vdbe_return; } assert( db->nStatement==0 ); 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; } break; } /* 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. ** ** 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 |
︙ | ︙ | |||
3886 3887 3888 3889 3890 3891 3892 | ** if the schema generation counter in P4 differs from the current ** generation counter, then an SQLITE_SCHEMA error is raised and execution ** halts. The sqlite3_step() wrapper function might then reprepare the ** statement and rerun it from the beginning. */ case OP_Transaction: { Btree *pBt; | < < < | < < | < < < < < | < | < | < | | > | 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 | ** if the schema generation counter in P4 differs from the current ** generation counter, then an SQLITE_SCHEMA error is raised and execution ** halts. The sqlite3_step() wrapper function might then reprepare the ** statement and rerun it from the beginning. */ 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) ); if( pOp->p2 && (db->flags & SQLITE_QueryOnly)!=0 ){ rc = SQLITE_READONLY; 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( pOp->p2 && p->usesStmtJournal && (db->autoCommit==0 || db->nVdbeRead>1) ){ assert( sqlite3BtreeIsInTrans(pBt) ); 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( 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. */ sqlite3DbFree(db, p->zErrMsg); |
︙ | ︙ | |||
3975 3976 3977 3978 3979 3980 3981 | ** a v-table method. */ if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){ sqlite3ResetOneSchema(db, pOp->p1); } p->expired = 1; rc = SQLITE_SCHEMA; | < < < < < | 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 | ** a v-table method. */ if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){ sqlite3ResetOneSchema(db, pOp->p1); } p->expired = 1; rc = SQLITE_SCHEMA; } if( rc ) goto abort_due_to_error; break; } /* Opcode: ReadCookie P1 P2 P3 * * ** |
︙ | ︙ | |||
4016 4017 4018 4019 4020 4021 4022 | sqlite3BtreeGetMeta(db->aDb[iDb].pBt, iCookie, (u32 *)&iMeta); pOut = out2Prerelease(p, pOp); pOut->u.i = iMeta; break; } | | < < < < < | < | 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 | sqlite3BtreeGetMeta(db->aDb[iDb].pBt, iCookie, (u32 *)&iMeta); pOut = out2Prerelease(p, pOp); pOut->u.i = iMeta; break; } /* Opcode: SetCookie P1 P2 P3 * * ** ** 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. */ 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) ); /* 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; 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 ** schema is changed. Ticket #1644 */ |
︙ | ︙ | |||
4078 4079 4080 4081 4082 4083 4084 | ** 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 | | | 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 | ** 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_IdxGT) ** </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 |
︙ | ︙ | |||
4108 4109 4110 4111 4112 4113 4114 | ** 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 | | | 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 | ** 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_IdxGT) ** </ul> ** ** See also: OP_OpenRead, OP_OpenWrite */ /* Opcode: OpenWrite P1 P2 P3 P4 P5 ** Synopsis: root=P2 iDb=P3 ** |
︙ | ︙ | |||
4132 4133 4134 4135 4136 4137 4138 | ** 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 | | | | < < | | | | 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 | ** 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_IdxGT) ** <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; int 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 */ 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 = 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 ){ 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<=(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 |
︙ | ︙ | |||
4226 4227 4228 4229 4230 4231 4232 | nField = pKeyInfo->nAllField; }else if( pOp->p4type==P4_INT32 ){ nField = pOp->p4.i; } assert( pOp->p1>=0 ); assert( nField>=0 ); testcase( nField==0 ); /* Table with INTEGER PRIMARY KEY and nothing else */ | | < > > | < | | < < < | | < < < < | | < < < < < < < < < | | < | > | > | | | > | | | | | | | | | | | | | | | | | | | | | | | | | | < < < < | 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 | nField = pKeyInfo->nAllField; }else if( pOp->p4type==P4_INT32 ){ nField = pOp->p4.i; } assert( pOp->p1>=0 ); assert( nField>=0 ); testcase( nField==0 ); /* Table with INTEGER PRIMARY KEY and nothing else */ pCur = allocateCursor(p, pOp->p1, nField, iDb, CURTYPE_BTREE); if( pCur==0 ) goto no_mem; pCur->nullRow = 1; pCur->isOrdered = 1; pCur->pgnoRoot = p2; #ifdef SQLITE_DEBUG pCur->wrFlag = wrFlag; #endif rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->uc.pCursor); pCur->pKeyInfo = pKeyInfo; /* Set the VdbeCursor.isTable variable. Previous versions of ** SQLite used to check if the root-page flags were sane at this point ** and report database corruption if they were not, but this check has ** 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 ); #ifdef SQLITE_ENABLE_CURSOR_HINTS testcase( pOp->p2 & OPFLAG_SEEKEQ ); #endif 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->pBtx!=0 ); /* 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; rc = sqlite3BtreeCursor(pOrig->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 * 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. */ /* 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 ** indices in joins. */ case OP_OpenAutoindex: case OP_OpenEphemeral: { VdbeCursor *pCx; KeyInfo *pKeyInfo; static const int vfsFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE | SQLITE_OPEN_TRANSIENT_DB; assert( pOp->p1>=0 ); assert( pOp->p2>=0 ); pCx = p->apCsr[pOp->p1]; if( pCx ){ /* If the ephermeral table is already open, 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; if( pCx->pBtx ){ 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, (int*)&pCx->pgnoRoot, BTREE_BLOBKEY | pOp->p5); if( rc==SQLITE_OK ){ assert( pCx->pgnoRoot==MASTER_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 = MASTER_ROOT; rc = sqlite3BtreeCursor(pCx->pBtx, MASTER_ROOT, BTREE_WRCSR, 0, pCx->uc.pCursor); pCx->isTable = 1; } } pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED); } if( rc ) goto abort_due_to_error; pCx->nullRow = 1; break; } /* Opcode: SorterOpen P1 P2 P3 P4 * |
︙ | ︙ | |||
4415 4416 4417 4418 4419 4420 4421 | ** key is sufficient to produce the required results. */ case OP_SorterOpen: { VdbeCursor *pCx; assert( pOp->p1>=0 ); assert( pOp->p2>=0 ); | | | 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 | ** key is sufficient to produce the required results. */ case OP_SorterOpen: { VdbeCursor *pCx; assert( pOp->p1>=0 ); assert( pOp->p2>=0 ); pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, CURTYPE_SORTER); if( pCx==0 ) goto no_mem; pCx->pKeyInfo = pOp->p4.pKeyInfo; assert( pCx->pKeyInfo->db==db ); assert( pCx->pKeyInfo->enc==ENC(db) ); rc = sqlite3VdbeSorterInit(db, pOp->p3, pCx); if( rc ) goto abort_due_to_error; break; |
︙ | ︙ | |||
4464 4465 4466 4467 4468 4469 4470 | ** the pseudo-table. */ case OP_OpenPseudo: { VdbeCursor *pCx; assert( pOp->p1>=0 ); assert( pOp->p3>=0 ); | | | | 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 | ** the pseudo-table. */ case OP_OpenPseudo: { VdbeCursor *pCx; assert( pOp->p1>=0 ); assert( pOp->p3>=0 ); pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, CURTYPE_PSEUDO); if( pCx==0 ) goto no_mem; pCx->nullRow = 1; pCx->seekResult = pOp->p2; pCx->isTable = 1; /* Give this pseudo-cursor a fake BtCursor pointer so that pCx ** can be safely passed to sqlite3VdbeCursorMoveto(). This avoids a test ** for pCx->eCurType==CURTYPE_BTREE inside of sqlite3VdbeCursorMoveto() ** which is a performance optimization */ pCx->uc.pCursor = sqlite3BtreeFakeValidCursor(); assert( pOp->p5==0 ); break; } /* Opcode: Close P1 * * * * ** ** Close a cursor previously opened as P1. If P1 is not ** currently open, this instruction is a no-op. */ case OP_Close: { assert( pOp->p1>=0 && pOp->p1<p->nCursor ); sqlite3VdbeFreeCursor(p, p->apCsr[pOp->p1]); p->apCsr[pOp->p1] = 0; break; } #ifdef SQLITE_ENABLE_COLUMN_USED_MASK |
︙ | ︙ | |||
4523 4524 4525 4526 4527 4528 4529 | ** 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 | | | | | | < < | | 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 | ** 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 always land on a record that equally equals the key, or ** else jump immediately to P2. When the cursor is OPFLAG_SEEKEQ, this ** opcode must be followed by an IdxLE opcode with the same arguments. ** The IdxLE opcode will be skipped if this opcode succeeds, but the ** IdxLE opcode will be used on subsequent loop iterations. ** ** 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. ** |
︙ | ︙ | |||
4590 4591 4592 4593 4594 4595 4596 | ** 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 | | | | | < < | | | | | 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 | ** 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 always land on a record that equally equals the key, or ** else jump immediately to P2. When the cursor is OPFLAG_SEEKEQ, this ** opcode must be followed by an IdxGE 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. ** ** 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 */ int res; /* Comparison result */ int oc; /* Opcode */ VdbeCursor *pC; /* The cursor to seek */ UnpackedRecord r; /* The key to seek for */ int nField; /* Number of columns or fields in the key */ i64 iKey; /* The rowid we are to seek to */ int eqOnly; /* Only interested in == results */ |
︙ | ︙ | |||
4629 4630 4631 4632 4633 4634 4635 | oc = pOp->opcode; eqOnly = 0; pC->nullRow = 0; #ifdef SQLITE_DEBUG pC->seekOp = pOp->opcode; #endif | < < < | < | | < < | < | < > > | < | < < < | < < | | | | | | | < < < | 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 | oc = pOp->opcode; eqOnly = 0; pC->nullRow = 0; #ifdef SQLITE_DEBUG pC->seekOp = pOp->opcode; #endif if( pC->isTable ){ /* The 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]; if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn3, 0); } iKey = sqlite3VdbeIntValue(pIn3); /* If the P3 value could not be converted into an integer without ** loss of information, then special processing is required... */ if( (pIn3->flags & MEM_Int)==0 ){ if( (pIn3->flags & MEM_Real)==0 ){ /* If the P3 value cannot be converted into any kind of a number, ** then the seek is not possible, so jump to P2 */ VdbeBranchTaken(1,2); goto jump_to_p2; break; } /* 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( pIn3->u.r<(double)iKey ){ 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( pIn3->u.r>(double)iKey ){ 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 = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, 0, (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 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[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; |
︙ | ︙ | |||
4732 4733 4734 4735 4736 4737 4738 | assert( oc!=OP_SeekGT || r.default_rc==-1 ); assert( oc!=OP_SeekLE || r.default_rc==-1 ); assert( oc!=OP_SeekGE || r.default_rc==+1 ); assert( oc!=OP_SeekLT || r.default_rc==+1 ); r.aMem = &aMem[pOp->p3]; #ifdef SQLITE_DEBUG | < < < | < < < | > > | 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 | assert( oc!=OP_SeekGT || r.default_rc==-1 ); assert( oc!=OP_SeekLE || r.default_rc==-1 ); assert( oc!=OP_SeekGE || r.default_rc==+1 ); 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 = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, &r, 0, 0, &res); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } if( eqOnly && r.eqSeen==0 ){ assert( res!=0 ); goto seek_not_found; } } pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; #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); |
︙ | ︙ | |||
4801 4802 4803 4804 4805 4806 4807 | assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT ); pOp++; /* Skip the OP_IdxLt or OP_IdxGT that follows */ } break; } | | | | | < | | | < < < < < < < < < < < | | > | | < < < < < | | < < < < < | | < | | | | < < | < | | | < < < < < < < < < | | | < | | < | | | | 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 | 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 point 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 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 n; 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 ); 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; } n = pOp->p1; assert( n>=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 - n); } #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 - n); } #endif VdbeBranchTaken(2,3); goto jump_to_p2; break; } if( n<=0 ){ #ifdef SQLITE_DEBUG if( db->flags&SQLITE_VdbeTrace ){ printf("... fall through after %d steps\n", pOp->p1); } #endif VdbeBranchTaken(0,3); break; } n--; 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; |
︙ | ︙ | |||
4991 4992 4993 4994 4995 4996 4997 | ** 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. */ | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | ** 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 ){ pC->seekHit = pOp->p2; }else if( pC->seekHit>pOp->p3 ){ pC->seekHit = pOp->p3; } 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 |
︙ | ︙ | |||
5123 5124 5125 5126 5127 5128 5129 | ** ** This operation leaves the cursor in a state where it cannot be ** advanced in either direction. In other words, the Next and Prev ** opcodes do not work after this operation. ** ** See also: NotFound, Found, NotExists */ | | < < < < < < | | | > > > | | < < > | | > < | < | | | > | > > > > > | | > > | > > > > > | < | | < < < < < < < < < < < < < | < < | 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 | ** ** This operation leaves the cursor in a state where it cannot be ** advanced in either direction. In other words, the Next and Prev ** opcodes do not work after this operation. ** ** 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 ); if( pC->seekHit>=pOp->p4.i ) break; /* Fall through into OP_NotFound */ } case OP_NoConflict: /* jump, in3 */ case OP_NotFound: /* jump, in3 */ case OP_Found: { /* jump, in3 */ int alreadyExists; int takeJump; int ii; VdbeCursor *pC; int res; UnpackedRecord *pFree; UnpackedRecord *pIdxKey; UnpackedRecord r; #ifdef SQLITE_TEST if( pOp->opcode!=OP_NoConflict ) sqlite3_found_count++; #endif assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( pOp->p4type==P4_INT32 ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); #ifdef SQLITE_DEBUG pC->seekOp = pOp->opcode; #endif pIn3 = &aMem[pOp->p3]; assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->uc.pCursor!=0 ); assert( pC->isTable==0 ); if( pOp->p4.i>0 ){ r.pKeyInfo = pC->pKeyInfo; r.nField = (u16)pOp->p4.i; r.aMem = pIn3; #ifdef SQLITE_DEBUG for(ii=0; ii<r.nField; ii++){ assert( memIsValid(&r.aMem[ii]) ); assert( (r.aMem[ii].flags & MEM_Zero)==0 || r.aMem[ii].n==0 ); if( ii ) REGISTER_TRACE(pOp->p3+ii, &r.aMem[ii]); } #endif pIdxKey = &r; pFree = 0; }else{ assert( pIn3->flags & MEM_Blob ); rc = ExpandBlob(pIn3); assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); if( rc ) goto no_mem; pFree = pIdxKey = sqlite3VdbeAllocUnpackedRecord(pC->pKeyInfo); if( pIdxKey==0 ) goto no_mem; sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey); } pIdxKey->default_rc = 0; takeJump = 0; if( pOp->opcode==OP_NoConflict ){ /* For the OP_NoConflict opcode, take the jump if any of the ** input fields are NULL, since any key with a NULL will not ** conflict */ for(ii=0; ii<pIdxKey->nField; ii++){ if( pIdxKey->aMem[ii].flags & MEM_Null ){ takeJump = 1; break; } } } rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, pIdxKey, 0, 0, &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] ** |
︙ | ︙ | |||
5269 5270 5271 5272 5273 5274 5275 | ** ** This opcode leaves the cursor in a state where it cannot be advanced ** in either direction. In other words, the Next and Prev opcodes will ** not work following this opcode. ** ** See also: Found, NotFound, NoConflict, SeekRowid */ | | < < < < | | < < < > | > | > | | | | < | < < > | | 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 | ** ** This opcode leaves the cursor in a state where it cannot be advanced ** in either direction. In other words, the Next and Prev opcodes will ** not work following this opcode. ** ** See also: Found, NotFound, NoConflict, SeekRowid */ case OP_SeekRowid: { /* jump, in3 */ VdbeCursor *pC; BtCursor *pCrsr; int res; u64 iKey; pIn3 = &aMem[pOp->p3]; if( (pIn3->flags & MEM_Int)==0 ){ /* Make sure pIn3->u.i contains a valid integer representation of ** the key value, but do not change the datatype of the register, as ** other parts of the perpared statement might be depending on the ** current datatype. */ u16 origFlags = pIn3->flags; int isNotInt; applyAffinity(pIn3, SQLITE_AFF_NUMERIC, encoding); isNotInt = (pIn3->flags & MEM_Int)==0; pIn3->flags = origFlags; if( isNotInt ) goto jump_to_p2; } /* Fall through into OP_NotExists */ 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 ); 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; iKey = pIn3->u.i; rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, 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; |
︙ | ︙ | |||
5368 5369 5370 5371 5372 5373 5374 | ** 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 */ | < < | 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 | ** 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 ); |
︙ | ︙ | |||
5467 5468 5469 5470 5471 5472 5473 | ** 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 */ | | | 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 | ** 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 = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, 0, (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; |
︙ | ︙ | |||
5537 5538 5539 5540 5541 5542 5543 | 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 ); | < | | < | < | < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | pData = &aMem[pOp->p2]; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( memIsValid(pData) ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->uc.pCursor!=0 ); 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; /* Not needed. Silence a compiler warning. */ } #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* Invoke the pre-update hook, if any */ if( pTab ){ if( db->xPreUpdateCallback && !(pOp->p5 & OPFLAG_ISUPDATE) ){ sqlite3VdbePreUpdateHook(p, pC, SQLITE_INSERT, zDb, pTab, x.nKey,pOp->p2); } if( db->xUpdateCallback==0 || pTab->aCol==0 ){ /* Prevent post-update hook from running in cases when it should not */ pTab = 0; } } if( pOp->p5 & OPFLAG_ISNOOP ) break; #endif if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey; assert( pData->flags & (MEM_Blob|MEM_Str) ); 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)), seekResult ); pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; /* Invoke the update-hook if required. */ if( rc ) goto abort_due_to_error; if( pTab ){ assert( db->xUpdateCallback!=0 ); assert( pTab->aCol!=0 ); db->xUpdateCallback(db->pUpdateArg, (pOp->p5 & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_INSERT, zDb, pTab->zName, x.nKey); } break; } /* Opcode: Delete P1 P2 P3 P4 P5 ** ** Delete the record at which the P1 cursor is currently pointing. ** ** 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 ** record in the table. If it is left pointing at the next record, then |
︙ | ︙ | |||
5687 5688 5689 5690 5691 5692 5693 | assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->uc.pCursor!=0 ); assert( pC->deferredMoveto==0 ); sqlite3VdbeIncrWriteCounter(p, pC); #ifdef SQLITE_DEBUG | | < < < < | | | < | | | 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 | 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 ){ /* 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( 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; /* Not needed. Silence a compiler warning. */ pTab = 0; /* Not needed. Silence a compiler warning. */ } #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* Invoke the pre-update-hook if required. */ if( db->xPreUpdateCallback && pOp->p4.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 ); } if( opflags & OPFLAG_ISNOOP ) break; #endif /* Only flags that can be set are SAVEPOISTION and AUXDELETE */ assert( (pOp->p5 & ~(OPFLAG_SAVEPOSITION|OPFLAG_AUXDELETE))==0 ); |
︙ | ︙ | |||
5762 5763 5764 5765 5766 5767 5768 | 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++; | | | 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 | 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 && HasRowid(pTab) ){ db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, pTab->zName, pC->movetoTarget); assert( pC->iDb>=0 ); } } break; |
︙ | ︙ | |||
5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 | ** 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 ); | > > > > | | | | 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 | ** 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) ); #if 0 /* Not required due to the previous to assert() statements */ rc = sqlite3VdbeCursorMoveto(pC); if( rc!=SQLITE_OK ) goto abort_due_to_error; #endif n = sqlite3BtreePayloadSize(pCrsr); if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } testcase( n==0 ); rc = sqlite3VdbeMemFromBtree(pCrsr, 0, n, pOut); if( rc ) goto abort_due_to_error; if( !pOp->p3 ) Deephemeralize(pOut); UPDATE_MAX_BLOBSIZE(pOut); REGISTER_TRACE(pOp->p2, pOut); break; } /* Opcode: Rowid P1 P2 * * * ** Synopsis: r[P2]=rowid ** ** Store in register P2 an integer which is the key of the table entry that ** P1 is currently point to. ** ** P1 can be either an ordinary table or a virtual table. There used to ** be a separate OP_VRowid opcode for use with virtual tables, but this ** one opcode now works for both table types. */ case OP_Rowid: { /* out2 */ VdbeCursor *pC; i64 v; sqlite3_vtab *pVtab; const sqlite3_module *pModule; pOut = out2Prerelease(p, pOp); assert( pOp->p1>=0 && pOp->p1<p->nCursor ); |
︙ | ︙ | |||
5967 5968 5969 5970 5971 5972 5973 | } /* Opcode: NullRow P1 * * * * ** ** Move the cursor P1 to a null row. Any OP_Column operations ** that occur while the cursor is on the null row will always ** write a NULL. | < < < | < < < < < < < < < | 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 | } /* Opcode: NullRow P1 * * * * ** ** Move the cursor P1 to a null row. Any OP_Column operations ** that occur while the cursor is on the null row will always ** write a NULL. */ case OP_NullRow: { VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); pC->nullRow = 1; pC->cacheStatus = CACHE_STALE; if( pC->eCurType==CURTYPE_BTREE ){ assert( pC->uc.pCursor!=0 ); sqlite3BtreeClearCursor(pC->uc.pCursor); } #ifdef SQLITE_DEBUG |
︙ | ︙ | |||
6020 6021 6022 6023 6024 6025 6026 | ** If P2 is 0 or if the table or index is not empty, fall through ** to the following instruction. ** ** 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. */ | | | | 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 | ** If P2 is 0 or if the table or index is not empty, fall through ** to the following instruction. ** ** 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. */ case OP_SeekEnd: case OP_Last: { /* jump */ VdbeCursor *pC; BtCursor *pCrsr; int res; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); |
︙ | ︙ | |||
6112 6113 6114 6115 6116 6117 6118 | case OP_Sort: { /* jump */ #ifdef SQLITE_TEST sqlite3_sort_count++; sqlite3_search_count--; #endif p->aCounter[SQLITE_STMTSTATUS_SORT]++; /* Fall through into OP_Rewind */ | < < < < | < < | | | < | > > > | > > > < | > | < < | < < | < < < > > | < < < < < < | | | > > | | > | 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 | case OP_Sort: { /* jump */ #ifdef SQLITE_TEST sqlite3_sort_count++; sqlite3_search_count--; #endif p->aCounter[SQLITE_STMTSTATUS_SORT]++; /* Fall through into OP_Rewind */ } /* 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); if( res ) goto jump_to_p2; break; } /* Opcode: Next P1 P2 P3 P4 P5 ** ** Advance cursor P1 so that it points to the next key/data pair in its ** table or index. If there are no more key/value pairs then fall through ** to the following instruction. But if the cursor advance was successful, ** jump immediately to P2. ** ** The Next opcode is only valid following an SeekGT, SeekGE, or ** OP_Rewind opcode used to position the cursor. Next is not allowed ** to follow SeekLT, SeekLE, or OP_Last. ** ** The P1 cursor must be for a real table, not a pseudo-table. P1 must have ** been opened prior to this opcode or the program will segfault. ** ** The P3 value is a hint to the btree implementation. If P3==1, that ** means P1 is an SQL index and that this instruction could have been ** omitted if that index had been unique. P3 is usually 0. P3 is ** always either 0 or 1. ** ** P4 is always of type P4_ADVANCE. The function pointer points to ** sqlite3BtreeNext(). ** ** If P5 is positive and the jump is taken, then event counter ** number P5-1 in the prepared statement is incremented. ** ** See also: Prev */ /* Opcode: Prev P1 P2 P3 P4 P5 ** ** Back up cursor P1 so that it points to the previous key/data pair in its ** table or index. If there is no previous key/value pairs then fall through ** to the following instruction. But if the cursor backup was successful, ** jump immediately to P2. ** ** ** The Prev opcode is only valid following an SeekLT, SeekLE, or ** OP_Last opcode used to position the cursor. Prev is not allowed ** to follow SeekGT, SeekGE, or OP_Rewind. ** ** The P1 cursor must be for a real table, not a pseudo-table. If P1 is ** not open then the behavior is undefined. ** ** The P3 value is a hint to the btree implementation. If P3==1, that ** means P1 is an SQL index and that this instruction could have been ** omitted if that index had been unique. P3 is usually 0. P3 is ** always either 0 or 1. ** ** P4 is always of type P4_ADVANCE. The function pointer points to ** sqlite3BtreePrevious(). ** ** If P5 is positive and the jump is taken, then event counter ** number P5-1 in the prepared statement is incremented. */ /* Opcode: SorterNext P1 P2 * * P5 ** ** This opcode works just like OP_Next except that P1 must be a ** sorter object for which the OP_SorterSort opcode has been ** invoked. This opcode advances the cursor to the next sorted ** record, or jumps to P2 if there are no more sorted records. */ case OP_SorterNext: { /* jump */ VdbeCursor *pC; pC = p->apCsr[pOp->p1]; assert( isSorter(pC) ); rc = sqlite3VdbeSorterNext(db, pC); goto next_tail; case OP_Prev: /* jump */ case OP_Next: /* jump */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( pOp->p5<ArraySize(p->aCounter) ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->deferredMoveto==0 ); assert( pC->eCurType==CURTYPE_BTREE ); 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); assert( pOp->opcode!=OP_Prev || pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE || pC->seekOp==OP_Last || 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 ){ pC->nullRow = 0; p->aCounter[pOp->p5]++; #ifdef SQLITE_TEST |
︙ | ︙ | |||
6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 | ** 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 ); | > > > > > > > > | | | > > > | | | | | | | | | | < < | < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < > | < < < | 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 | ** 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. */ /* 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 */ 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)==(pOp->opcode==OP_SorterInsert) ); pIn2 = &aMem[pOp->p2]; assert( pIn2->flags & MEM_Blob ); if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; assert( pC->eCurType==CURTYPE_BTREE || pOp->opcode==OP_SorterInsert ); assert( pC->isTable==0 ); rc = ExpandBlob(pIn2); if( rc ) goto abort_due_to_error; if( pOp->opcode==OP_SorterInsert ){ rc = sqlite3VdbeSorterWrite(pC, pIn2); }else{ 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)), ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0) ); assert( pC->deferredMoveto==0 ); pC->cacheStatus = CACHE_STALE; } if( rc) goto abort_due_to_error; break; } /* Opcode: IdxDelete P1 P2 P3 * * ** 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. */ 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 ); assert( pOp->p5==0 ); r.pKeyInfo = pC->pKeyInfo; r.nField = (u16)pOp->p3; r.default_rc = 0; r.aMem = &aMem[pOp->p2]; rc = sqlite3BtreeMovetoUnpacked(pCrsr, &r, 0, 0, &res); if( rc ) goto abort_due_to_error; if( res==0 ){ rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE); if( rc ) goto abort_due_to_error; } assert( pC->deferredMoveto==0 ); pC->cacheStatus = CACHE_STALE; pC->seekResult = 0; break; } |
︙ | ︙ | |||
6433 6434 6435 6436 6437 6438 6439 | ** ** Write into register P2 an integer which is the last entry in the record at ** the end of the index key pointed to by cursor P1. This integer should be ** the rowid of the table entry to which this index entry points. ** ** See also: Rowid, MakeRecord. */ | | | | | | | | | < < | < | | | | | | | | | | | > | 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 | ** ** Write into register P2 an integer which is the last entry in the record at ** the end of the index key pointed to by cursor P1. This integer should be ** the rowid of the table entry to which this index entry points. ** ** See also: Rowid, MakeRecord. */ case OP_DeferredSeek: case OP_IdxRowid: { /* out2 */ VdbeCursor *pC; /* The P1 index cursor */ VdbeCursor *pTabCur; /* The P2 table cursor (OP_DeferredSeek only) */ i64 rowid; /* Rowid that P1 current points to */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); assert( pC->uc.pCursor!=0 ); assert( pC->isTable==0 ); assert( pC->deferredMoveto==0 ); assert( !pC->nullRow || pOp->opcode==OP_IdxRowid ); /* The IdxRowid and Seek opcodes are combined because of the commonality ** of sqlite3VdbeCursorRestore() and sqlite3VdbeIdxRowid(). */ rc = sqlite3VdbeCursorRestore(pC); /* sqlite3VbeCursorRestore() can only fail if the record has been deleted ** out from under the cursor. That will never happens for an IdxRowid ** or Seek opcode */ if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error; if( !pC->nullRow ){ rowid = 0; /* Not needed. Only used to silence a warning. */ rc = sqlite3VdbeIdxRowid(db, pC->uc.pCursor, &rowid); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } if( pOp->opcode==OP_DeferredSeek ){ assert( pOp->p3>=0 && pOp->p3<p->nCursor ); pTabCur = p->apCsr[pOp->p3]; assert( pTabCur!=0 ); assert( pTabCur->eCurType==CURTYPE_BTREE ); 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; } /* 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 P5 ** 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 P5 ** 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 P5 ** 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 P5 ** 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 or equal to the key value then jump ** to P2. Otherwise fall through to the next instruction. */ case OP_IdxLE: /* jump */ case OP_IdxGT: /* jump */ case OP_IdxLT: /* jump */ case OP_IdxGE: { /* jump */ VdbeCursor *pC; int res; UnpackedRecord r; 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->p5==0 || pOp->p5==1 ); 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{ |
︙ | ︙ | |||
6605 6606 6607 6608 6609 6610 6611 | /* 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); | | | | 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 | /* 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 = sqlite3VdbeMemFromBtree(pCur, 0, (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; |
︙ | ︙ | |||
6696 6697 6698 6699 6700 6701 6702 | ** 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. ** | | > | | | | | > > | 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 | ** 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 table referred to must be an ** intkey table (an SQL table, not an index). In this case 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: { int nChange; sqlite3VdbeIncrWriteCounter(p, 0); nChange = 0; assert( p->readOnly==0 ); assert( DbMaskTest(p->btreeMask, pOp->p2) ); rc = sqlite3BtreeClearTable( db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &nChange : 0) ); 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; } |
︙ | ︙ | |||
6758 6759 6760 6761 6762 6763 6764 | ** 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 */ | | | 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 | ** 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 */ int 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 ); |
︙ | ︙ | |||
6791 6792 6793 6794 6795 6796 6797 | db->nSqlExec--; if( rc ) goto abort_due_to_error; break; } /* Opcode: ParseSchema P1 * * P4 * ** | | | | < < | | < | | | 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 | db->nSqlExec--; if( rc ) goto abort_due_to_error; break; } /* Opcode: ParseSchema P1 * * P4 * ** ** Read and parse all entries from the SQLITE_MASTER 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 *zMaster; 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) ); #ifndef SQLITE_OMIT_ALTERTABLE if( pOp->p4.z==0 ){ sqlite3SchemaClear(db->aDb[iDb].pSchema); db->mDbFlags &= ~DBFLAG_SchemaKnownOk; rc = sqlite3InitOne(db, iDb, &p->zErrMsg, INITFLAG_AlterTable); db->mDbFlags |= DBFLAG_SchemaChange; p->expired = 0; }else #endif { zMaster = MASTER_NAME; initData.db = db; initData.iDb = iDb; initData.pzErrMsg = &p->zErrMsg; initData.mInitFlags = 0; zSql = sqlite3MPrintf(db, "SELECT*FROM\"%w\".%s WHERE %s ORDER BY rowid", db->aDb[iDb].zDbSName, zMaster, 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_master table is corrupt. */ rc = SQLITE_CORRUPT_BKPT; } sqlite3DbFreeNN(db, zSql); db->init.busy = 0; } } if( rc ){ |
︙ | ︙ | |||
6949 6950 6951 6952 6953 6954 6955 | ** 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.) */ | | | | | | < | | | 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 | ** 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.) */ int *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]==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->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); break; } #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 |
︙ | ︙ | |||
7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 | pFrame->aMem = p->aMem; pFrame->nMem = p->nMem; pFrame->apCsr = p->apCsr; pFrame->nCursor = p->nCursor; pFrame->aOp = p->aOp; pFrame->nOp = p->nOp; pFrame->token = pProgram->token; #ifdef SQLITE_DEBUG pFrame->iFrameMagic = SQLITE_FRAME_MAGIC; #endif pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem]; for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){ pMem->flags = MEM_Undefined; | > > > | 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 | pFrame->aMem = p->aMem; pFrame->nMem = p->nMem; pFrame->apCsr = p->apCsr; pFrame->nCursor = p->nCursor; pFrame->aOp = p->aOp; pFrame->nOp = p->nOp; pFrame->token = pProgram->token; #ifdef SQLITE_ENABLE_STMT_SCANSTATUS pFrame->anExec = p->anExec; #endif #ifdef SQLITE_DEBUG pFrame->iFrameMagic = SQLITE_FRAME_MAGIC; #endif pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem]; for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){ pMem->flags = MEM_Undefined; |
︙ | ︙ | |||
7213 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 | p->nMem = pFrame->nChildMem; p->nCursor = (u16)pFrame->nChildCsr; 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_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 */ | > > > | | 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 | p->nMem = pFrame->nChildMem; p->nCursor = (u16)pFrame->nChildCsr; 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 */ aMem[i].flags |= MEM_Undefined; /* Cause a fault if this reg is reused */ } } #endif pOp = &aOp[-1]; goto check_for_interrupt; } |
︙ | ︙ | |||
7352 7353 7354 7355 7356 7357 7358 | break; } /* Opcode: OffsetLimit P1 P2 P3 * * ** Synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) ** ** This opcode performs a commonly used computation associated with | | | 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 | break; } /* Opcode: OffsetLimit P1 P2 P3 * * ** Synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) ** ** This opcode performs a commonly used computation associated with ** LIMIT and OFFSET process. r[P1] holds the limit counter. r[P3] ** holds the offset counter. The opcode computes the combined value ** of the LIMIT and OFFSET and stores that value in r[P2]. The r[P2] ** value computed is the total number of rows that will need to be ** visited in order to complete the query. ** ** If r[P3] is zero or negative, that means there is no OFFSET ** and r[P2] is set to be the value of the LIMIT, r[P1]. |
︙ | ︙ | |||
7484 7485 7486 7487 7488 7489 7490 | pCtx->pOut = (Mem*)&(pCtx->argv[n]); sqlite3VdbeMemInit(pCtx->pOut, db, MEM_Null); pCtx->pFunc = pOp->p4.pFunc; pCtx->iOp = (int)(pOp - aOp); pCtx->pVdbe = p; pCtx->skipFlag = 0; pCtx->isError = 0; | < < | 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 | pCtx->pOut = (Mem*)&(pCtx->argv[n]); sqlite3VdbeMemInit(pCtx->pOut, db, MEM_Null); pCtx->pFunc = pOp->p4.pFunc; pCtx->iOp = (int)(pOp - aOp); pCtx->pVdbe = p; pCtx->skipFlag = 0; pCtx->isError = 0; pCtx->argc = n; pOp->p4type = P4_FUNCCTX; pOp->p4.pCtx = pCtx; /* 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 ); |
︙ | ︙ | |||
7614 7615 7616 7617 7618 7619 7620 7621 7622 7623 7624 7625 7626 7627 | if( rc ){ sqlite3VdbeError(p, "%s", sqlite3_value_text(pMem)); goto abort_due_to_error; } sqlite3VdbeChangeEncoding(pMem, encoding); UPDATE_MAX_BLOBSIZE(pMem); break; } #ifndef SQLITE_OMIT_WAL /* Opcode: Checkpoint P1 P2 P3 * * ** ** Checkpoint database P1. This is a no-op if P1 is not currently in | > > > | 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 | if( rc ){ sqlite3VdbeError(p, "%s", sqlite3_value_text(pMem)); goto abort_due_to_error; } sqlite3VdbeChangeEncoding(pMem, encoding); UPDATE_MAX_BLOBSIZE(pMem); if( sqlite3VdbeMemTooBig(pMem) ){ goto too_big; } break; } #ifndef SQLITE_OMIT_WAL /* Opcode: Checkpoint P1 P2 P3 * * ** ** Checkpoint database P1. This is a no-op if P1 is not currently in |
︙ | ︙ | |||
7693 7694 7695 7696 7697 7698 7699 | 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; | < | 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 | 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 |
︙ | ︙ | |||
7740 7741 7742 7743 7744 7745 7746 | ** 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. */ | | | 6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 | ** 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( sqlite3BtreeIsInTrans(pBt)==0 ); if( rc==SQLITE_OK ){ rc = sqlite3BtreeSetVersion(pBt, (eNew==PAGER_JOURNALMODE_WAL ? 2 : 1)); } } } #endif /* ifndef SQLITE_OMIT_WAL */ |
︙ | ︙ | |||
7831 7832 7833 7834 7835 7836 7837 | sqlite3ExpirePreparedStatements(db, pOp->p2); }else{ p->expired = pOp->p2+1; } break; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 | 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. ** |
︙ | ︙ | |||
7969 7970 7971 7972 7973 7974 7975 | #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VOpen P1 * * P4 * ** ** P4 is a pointer to a virtual table object, an sqlite3_vtab structure. ** P1 is a cursor number. This opcode opens a cursor to the virtual ** table and stores that cursor in P1. */ | | | 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104 7105 | #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VOpen P1 * * P4 * ** ** P4 is a pointer to a virtual table object, an sqlite3_vtab structure. ** P1 is a cursor number. This opcode opens a cursor to the virtual ** table and stores that cursor in P1. */ case OP_VOpen: { VdbeCursor *pCur; sqlite3_vtab_cursor *pVCur; sqlite3_vtab *pVtab; const sqlite3_module *pModule; assert( p->bIsReader ); pCur = 0; |
︙ | ︙ | |||
7992 7993 7994 7995 7996 7997 7998 | sqlite3VtabImportErrmsg(p, pVtab); if( rc ) goto abort_due_to_error; /* Initialize sqlite3_vtab_cursor base class */ pVCur->pVtab = pVtab; /* Initialize vdbe cursor object */ | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | sqlite3VtabImportErrmsg(p, pVtab); if( rc ) goto abort_due_to_error; /* Initialize sqlite3_vtab_cursor base class */ pVCur->pVtab = pVtab; /* Initialize vdbe cursor object */ pCur = allocateCursor(p, pOp->p1, 0, -1, CURTYPE_VTAB); if( pCur ){ pCur->uc.pVCur = pVCur; pVtab->nRef++; }else{ assert( db->mallocFailed ); pModule->xClose(pVCur); goto no_mem; } break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VFilter P1 P2 P3 P4 * ** Synopsis: iplan=r[P3] zplan='P4' ** ** P1 is a cursor opened using VOpen. P2 is an address to jump to if ** the filtered result set is empty. |
︙ | ︙ | |||
8053 8054 8055 8056 8057 8058 8059 | ** P3. Register P3+1 stores the argc parameter to be passed to the ** xFilter method. Registers P3+2..P3+1+argc are the argc ** additional parameters which are passed to ** xFilter as argv. Register P3+2 becomes argv[0] when passed to xFilter. ** ** A jump is made to P2 if the result set after filtering would be empty. */ | | < > | 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 | ** P3. Register P3+1 stores the argc parameter to be passed to the ** xFilter method. Registers P3+2..P3+1+argc are the argc ** additional parameters which are passed to ** xFilter as argv. Register P3+2 becomes argv[0] when passed to xFilter. ** ** A jump is made to P2 if the result set after filtering would be empty. */ case OP_VFilter: { /* jump */ int nArg; int iQuery; const sqlite3_module *pModule; Mem *pQuery; Mem *pArgc; sqlite3_vtab_cursor *pVCur; sqlite3_vtab *pVtab; VdbeCursor *pCur; int res; int i; 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 */ res = 0; 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; |
︙ | ︙ | |||
8113 8114 8115 8116 8117 8118 8119 | ** an unchanging column during an UPDATE operation, then the P5 ** value is OPFLAG_NOCHNG. This will cause the sqlite3_vtab_nochange() ** function to return true inside the xColumn method of the virtual ** table implementation. The P5 column might also contain other ** bits (OPFLAG_LENGTHARG or OPFLAG_TYPEOFARG) but those bits are ** unused by OP_VColumn. */ | | | < < | > > > | > < | 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 | ** an unchanging column during an UPDATE operation, then the P5 ** value is OPFLAG_NOCHNG. This will cause the sqlite3_vtab_nochange() ** function to return true inside the xColumn method of the virtual ** table implementation. The P5 column might also contain other ** bits (OPFLAG_LENGTHARG or OPFLAG_TYPEOFARG) but those bits are ** unused by OP_VColumn. */ 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; testcase( (pOp->p5 & OPFLAG_NOCHNG)==0 && 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); } rc = pModule->xColumn(pCur->uc.pVCur, &sContext, pOp->p2); sqlite3VtabImportErrmsg(p, pVtab); if( sContext.isError>0 ){ sqlite3VdbeError(p, "%s", sqlite3_value_text(pDest)); rc = sContext.isError; } sqlite3VdbeChangeEncoding(pDest, encoding); REGISTER_TRACE(pOp->p3, pDest); UPDATE_MAX_BLOBSIZE(pDest); if( sqlite3VdbeMemTooBig(pDest) ){ goto too_big; } if( rc ) goto abort_due_to_error; break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VNext P1 P2 * * * ** ** Advance virtual table P1 to the next row in its result set and ** jump to instruction P2. Or, if the virtual table has reached ** the end of its result set, then fall through to the next instruction. */ case OP_VNext: { /* jump */ sqlite3_vtab *pVtab; const sqlite3_module *pModule; int res; VdbeCursor *pCur; res = 0; pCur = p->apCsr[pOp->p1]; assert( pCur->eCurType==CURTYPE_VTAB ); if( pCur->nullRow ){ break; } pVtab = pCur->uc.pVCur->pVtab; pModule = pVtab->pModule; assert( pModule->xNext ); |
︙ | ︙ | |||
8268 8269 8270 8271 8272 8273 8274 | ** 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; | | | 7363 7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 7374 7375 7376 7377 | ** 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; 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 ); |
︙ | ︙ | |||
8357 8358 8359 8360 8361 8362 8363 | if( newMax < (unsigned)pOp->p3 ) newMax = (unsigned)pOp->p3; } pOut->u.i = sqlite3BtreeMaxPageCount(pBt, newMax); break; } #endif | | | | | < < | | | | | | | < < | | | < < | > | | > > > > > > > > > > > > > > > > > > > > > > > > > < < < | 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 | if( newMax < (unsigned)pOp->p3 ) newMax = (unsigned)pOp->p3; } pOut->u.i = sqlite3BtreeMaxPageCount(pBt, newMax); break; } #endif /* Opcode: Function0 P1 P2 P3 P4 P5 ** Synopsis: r[P3]=func(r[P2@P5]) ** ** Invoke a user function (P4 is a pointer to a FuncDef object that ** defines the function) with P5 arguments taken from register P2 and ** successors. 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: Function, AggStep, AggFinal */ /* Opcode: Function P1 P2 P3 P4 P5 ** Synopsis: r[P3]=func(r[P2@P5]) ** ** Invoke a user function (P4 is a pointer to an sqlite3_context object that ** contains a pointer to the function to be run) with P5 arguments taken ** from register P2 and successors. 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. ** ** SQL functions are initially coded as OP_Function0 with P4 pointing ** to a FuncDef object. But on first evaluation, the P4 operand is ** automatically converted into an sqlite3_context object and the operation ** changed to this OP_Function opcode. In this way, the initialization of ** the sqlite3_context object occurs only once, rather than once for each ** evaluation of the function. ** ** See also: Function0, AggStep, AggFinal */ case OP_PureFunc0: /* group */ case OP_Function0: { /* group */ int n; sqlite3_context *pCtx; assert( pOp->p4type==P4_FUNCDEF ); n = pOp->p5; assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) ); assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem+1 - p->nCursor)+1) ); assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n ); pCtx = sqlite3DbMallocRawNN(db, sizeof(*pCtx) + (n-1)*sizeof(sqlite3_value*)); if( pCtx==0 ) goto no_mem; pCtx->pOut = 0; pCtx->pFunc = pOp->p4.pFunc; pCtx->iOp = (int)(pOp - aOp); pCtx->pVdbe = p; pCtx->isError = 0; pCtx->argc = n; pOp->p4type = P4_FUNCCTX; pOp->p4.pCtx = pCtx; assert( OP_PureFunc == OP_PureFunc0+2 ); assert( OP_Function == OP_Function0+2 ); pOp->opcode += 2; /* Fall through into OP_Function */ } 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->pOut = pOut; for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i]; } 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]); } |
︙ | ︙ | |||
8446 8447 8448 8449 8450 8451 8452 | rc = pCtx->isError; } sqlite3VdbeDeleteAuxData(db, &p->pAuxData, pCtx->iOp, pOp->p1); pCtx->isError = 0; if( rc ) goto abort_due_to_error; } | > | | < | | > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 7558 7559 7560 7561 7562 7563 7564 7565 7566 7567 7568 7569 7570 7571 7572 7573 7574 7575 7576 7577 7578 7579 | rc = pCtx->isError; } sqlite3VdbeDeleteAuxData(db, &p->pAuxData, pCtx->iOp, pOp->p1); pCtx->isError = 0; if( rc ) goto abort_due_to_error; } /* Copy the result of the function into register P3 */ if( pOut->flags & (MEM_Str|MEM_Blob) ){ sqlite3VdbeChangeEncoding(pOut, encoding); if( sqlite3VdbeMemTooBig(pOut) ) goto too_big; } REGISTER_TRACE(pOp->p3, pOut); UPDATE_MAX_BLOBSIZE(pOut); break; } /* Opcode: Trace P1 P2 * P4 * ** ** Write P4 on the statement trace output if statement tracing is ** enabled. |
︙ | ︙ | |||
8586 8587 8588 8589 8590 8591 8592 | assert( pOp->p4.z==0 || strncmp(pOp->p4.z, "-" "- ", 3)==0 ); /* OP_Init is always instruction 0 */ assert( pOp==p->aOp || pOp->opcode==OP_Trace ); #ifndef SQLITE_OMIT_TRACE if( (db->mTrace & (SQLITE_TRACE_STMT|SQLITE_TRACE_LEGACY))!=0 | | > | | | | 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 7643 7644 7645 7646 7647 | assert( pOp->p4.z==0 || strncmp(pOp->p4.z, "-" "- ", 3)==0 ); /* OP_Init is always instruction 0 */ assert( pOp==p->aOp || pOp->opcode==OP_Trace ); #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 ){ void (*x)(void*,const char*) = (void(*)(void*,const char*))db->xTrace; char *z = sqlite3VdbeExpandSql(p, zTrace); x(db->pTraceArg, z); sqlite3_free(z); }else #endif if( db->nVdbeExec>1 ){ char *z = sqlite3MPrintf(db, "-- %s", zTrace); (void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, z); sqlite3DbFree(db, z); }else{ (void)db->xTrace(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++){ |
︙ | ︙ | |||
8674 8675 8676 8677 8678 8679 8680 | */ case OP_Abortable: { sqlite3VdbeAssertAbortable(p); break; } #endif | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 7706 7707 7708 7709 7710 7711 7712 7713 7714 7715 7716 7717 7718 7719 | */ case OP_Abortable: { sqlite3VdbeAssertAbortable(p); break; } #endif /* Opcode: Noop * * * * * ** ** Do nothing. This instruction is often useful as a jump ** destination. */ /* ** The magic Explain opcode are only inserted when explain==2 (which |
︙ | ︙ | |||
8748 8749 8750 8751 8752 8753 8754 | ** The cases of the switch statement above this line should all be indented ** by 6 spaces. But the left-most 6 spaces have been removed to improve the ** readability. From this point on down, the normal indentation rules are ** restored. *****************************************************************************/ } | | > | | < | < > < < < < < < | < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < | < | < | 7731 7732 7733 7734 7735 7736 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 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 | ** The cases of the switch statement above this line should all be indented ** by 6 spaces. But the left-most 6 spaces have been removed to improve the ** readability. From this point on down, the normal indentation rules are ** restored. *****************************************************************************/ } #ifdef VDBE_PROFILE { u64 endTime = sqlite3NProfileCnt ? sqlite3NProfileCnt : sqlite3Hwtime(); if( endTime>start ) pOrigOp->cycles += endTime - start; pOrigOp->cnt++; } #endif /* The following code adds nothing to the actual functionality ** of the program. It is only here for testing and debugging. ** On the other hand, it does burn CPU cycles every time through ** the evaluator loop. So we can leave it out when NDEBUG is defined. */ #ifndef NDEBUG assert( pOp>=&aOp[-1] && pOp<&aOp[p->nOp-1] ); #ifdef SQLITE_DEBUG if( db->flags & SQLITE_VdbeTrace ){ u8 opProperty = sqlite3OpcodeProperty[pOrigOp->opcode]; 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: if( db->mallocFailed ) rc = SQLITE_NOMEM_BKPT; assert( rc ); 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); 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 = 0xffffffff; 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; /* Jump to here if a string or blob larger than SQLITE_MAX_LENGTH ** is encountered. |
︙ | ︙ | |||
8880 8881 8882 8883 8884 8885 8886 | 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: | | | > > | 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835 7836 | 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( db->u1.isInterrupted ); rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT; p->rc = rc; sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc)); 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 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | 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 */ int *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; #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS char *zComment; /* Comment to improve readability */ #endif #ifdef VDBE_PROFILE u32 cnt; /* Number of times this instruction was executed */ u64 cycles; /* Total time spent executing this instruction */ #endif #ifdef SQLITE_VDBE_COVERAGE u32 iSrcLine; /* Source-code line that generated this opcode ** with flags in the upper 8 bits */ #endif }; typedef struct VdbeOp VdbeOp; /* ** A sub-routine used to implement a trigger program. */ |
︙ | ︙ | |||
109 110 111 112 113 114 115 | */ #define P4_NOTUSED 0 /* The P4 parameter is not used */ #define P4_TRANSIENT 0 /* P4 is a pointer to a transient string */ #define P4_STATIC (-1) /* Pointer to a static string */ #define P4_COLLSEQ (-2) /* P4 is a pointer to a CollSeq structure */ #define P4_INT32 (-3) /* P4 is a 32-bit signed integer */ #define P4_SUBPROGRAM (-4) /* P4 is a pointer to a SubProgram structure */ | > | | | | | | | | | | | | > | 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 | */ #define P4_NOTUSED 0 /* The P4 parameter is not used */ #define P4_TRANSIENT 0 /* P4 is a pointer to a transient string */ #define P4_STATIC (-1) /* Pointer to a static string */ #define P4_COLLSEQ (-2) /* P4 is a pointer to a CollSeq structure */ #define P4_INT32 (-3) /* P4 is a 32-bit signed integer */ #define P4_SUBPROGRAM (-4) /* P4 is a pointer to a SubProgram structure */ #define P4_ADVANCE (-5) /* P4 is a pointer to BtreeNext() or BtreePrev() */ #define P4_TABLE (-6) /* P4 is a pointer to a Table structure */ /* Above do not own any resources. Must free those below */ #define P4_FREE_IF_LE (-7) #define P4_DYNAMIC (-7) /* Pointer to memory from sqliteMalloc() */ #define P4_FUNCDEF (-8) /* P4 is a pointer to a FuncDef structure */ #define P4_KEYINFO (-9) /* P4 is a pointer to a KeyInfo structure */ #define P4_EXPR (-10) /* P4 is a pointer to an Expr tree */ #define P4_MEM (-11) /* P4 is a pointer to a Mem* structure */ #define P4_VTAB (-12) /* P4 is a pointer to an sqlite3_vtab structure */ #define P4_REAL (-13) /* P4 is a 64-bit floating point value */ #define P4_INT64 (-14) /* P4 is a 64-bit signed integer */ #define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */ #define P4_FUNCCTX (-16) /* P4 is a pointer to an sqlite3_context object */ #define P4_DYNBLOB (-17) /* Pointer to memory from sqliteMalloc() */ /* Error message codes for OP_Halt */ #define P5_ConstraintNotNull 1 #define P5_ConstraintUnique 2 #define P5_ConstraintCheck 3 #define P5_ConstraintFK 4 |
︙ | ︙ | |||
172 173 174 175 176 177 178 | #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*); | < < < < | < < < < < < | | | | | < < < < < < < < > | 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 | #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*); 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); 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) #endif #if defined(SQLITE_DEBUG) void sqlite3VdbeVerifyAbortable(Vdbe *p, int); #else # define sqlite3VdbeVerifyAbortable(A,B) #endif VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno); #ifndef SQLITE_OMIT_EXPLAIN void sqlite3VdbeExplain(Parse*,u8,const char*,...); void sqlite3VdbeExplainPop(Parse*); int sqlite3VdbeExplainParent(Parse*); # 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*); void sqlite3VdbeChangeOpcode(Vdbe*, u32 addr, u8); void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1); void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2); void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3); void sqlite3VdbeChangeP5(Vdbe*, u16 P5); void sqlite3VdbeJumpHere(Vdbe*, int addr); int sqlite3VdbeChangeToNoop(Vdbe*, int addr); int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op); 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); int sqlite3VdbeCurrentAddr(Vdbe*); #ifdef SQLITE_DEBUG int sqlite3VdbeAssertMayAbort(Vdbe *, int); #endif |
︙ | ︙ | |||
288 289 290 291 292 293 294 295 | 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 *); | > < > < < < | 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 | 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*); #ifndef SQLITE_OMIT_TRIGGER void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *); #endif int sqlite3NotPureFunc(sqlite3_context*); /* 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. |
︙ | ︙ | |||
387 388 389 390 391 392 393 | # define VdbeCoverageNeverNullIf(v,x) # define VdbeCoverageEqNe(v) # define VDBE_OFFSET_LINENO(x) 0 #endif #ifdef SQLITE_ENABLE_STMT_SCANSTATUS void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const char*); | < < | < < | 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 | # define VdbeCoverageNeverNullIf(v,x) # define VdbeCoverageEqNe(v) # define VDBE_OFFSET_LINENO(x) 0 #endif #ifdef SQLITE_ENABLE_STMT_SCANSTATUS void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const char*); #else # define sqlite3VdbeScanStatus(a,b,c,d,e) #endif #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) void sqlite3VdbePrintOp(FILE*, int, VdbeOp*); #endif #endif /* SQLITE_VDBE_H */ |
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 | #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) # define VDBE_DISPLAY_P4 1 #else # define VDBE_DISPLAY_P4 0 #endif /* ** SQL is translated into a sequence of instructions to be |
︙ | ︙ | |||
71 72 73 74 75 76 77 | ** * A sorter ** * A virtual table ** * A one-row "pseudotable" stored in a single register */ typedef struct VdbeCursor VdbeCursor; struct VdbeCursor { u8 eCurType; /* One of the CURTYPE_* values above */ | | < < | < < > | 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 | ** * A sorter ** * A virtual table ** * A one-row "pseudotable" stored in a single register */ typedef struct VdbeCursor VdbeCursor; struct VdbeCursor { u8 eCurType; /* One of the CURTYPE_* values above */ i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */ u8 nullRow; /* True if pointing to a row with no data */ u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */ u8 isTable; /* True for rowid tables. False for indexes */ #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 */ u16 seekHit; /* See the OP_SeekHit and OP_IfNoHope opcodes */ Btree *pBtx; /* Separate file holding temporary table */ i64 seqCount; /* Sequence counter */ int *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 |
︙ | ︙ | |||
130 131 132 133 134 135 136 | /* 2*nField extra array elements allocated for aType[], beyond the one ** static element declared in the structure. nField total array slots for ** aType[] and nField+1 array slots for aOffset[] */ u32 aType[1]; /* Type values record decode. MUST BE LAST */ }; | < < < < < | 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | /* 2*nField extra array elements allocated for aType[], beyond the one ** static element declared in the structure. nField total array slots for ** aType[] and nField+1 array slots for aOffset[] */ u32 aType[1]; /* Type values record decode. MUST BE LAST */ }; /* ** A value for VdbeCursor.cacheStatus that means the cache is always invalid. */ #define CACHE_STALE 0 /* |
︙ | ︙ | |||
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | ** set to NULL if the currently executing frame is the main program. */ typedef struct VdbeFrame VdbeFrame; struct VdbeFrame { Vdbe *v; /* VM this frame belongs to */ VdbeFrame *pParent; /* Parent of this frame, or NULL if parent is main */ Op *aOp; /* Program instructions for parent frame */ Mem *aMem; /* Array of memory cells for parent frame */ VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */ u8 *aOnce; /* Bitmask used by OP_Once */ void *token; /* Copy of SubProgram.token */ i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */ AuxData *pAuxData; /* Linked list of auxdata allocations */ #if SQLITE_DEBUG u32 iFrameMagic; /* magic number for sanity checking */ #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 */ | > | | | 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 | ** set to NULL if the currently executing frame is the main program. */ typedef struct VdbeFrame VdbeFrame; struct VdbeFrame { Vdbe *v; /* VM this frame belongs to */ VdbeFrame *pParent; /* Parent of this frame, or NULL if parent is main */ Op *aOp; /* Program instructions for parent frame */ i64 *anExec; /* Event counters from parent frame */ Mem *aMem; /* Array of memory cells for parent frame */ VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */ u8 *aOnce; /* Bitmask used by OP_Once */ void *token; /* Copy of SubProgram.token */ i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */ AuxData *pAuxData; /* Linked list of auxdata allocations */ #if SQLITE_DEBUG u32 iFrameMagic; /* magic number for sanity checking */ #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 */ int nChange; /* Statement changes (Vdbe.nChange) */ int 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 |
︙ | ︙ | |||
208 209 210 211 212 213 214 | union MemValue { double r; /* Real value used when MEM_Real is set in flags */ i64 i; /* Integer value used when MEM_Int is set in flags */ int nZero; /* Extra zero bytes when MEM_Zero and MEM_Blob set */ const char *zPType; /* Pointer type when MEM_Term|MEM_Subtype|MEM_Null */ FuncDef *pDef; /* Used only when flags==MEM_Agg */ } u; | < < > > | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | | > < < < | | > > > | > | | | | > > > > > > < | | < < < < | | 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 | union MemValue { double r; /* Real value used when MEM_Real is set in flags */ i64 i; /* Integer value used when MEM_Int is set in flags */ int nZero; /* Extra zero bytes when MEM_Zero and MEM_Blob set */ const char *zPType; /* Pointer type when MEM_Term|MEM_Subtype|MEM_Null */ FuncDef *pDef; /* Used only when flags==MEM_Agg */ } u; u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */ u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */ u8 eSubtype; /* Subtype for this value */ int n; /* Number of characters in string value, excluding '\0' */ char *z; /* String or BLOB value */ /* ShallowCopy only needs to copy the information above */ char *zMalloc; /* Space to hold MEM_Str or MEM_Blob if szMalloc>0 */ int szMalloc; /* Size of the zMalloc allocation */ u32 uTemp; /* Transient storage for serial_type in OP_MakeRecord */ sqlite3 *db; /* The associated database connection */ void (*xDel)(void*);/* Destructor for Mem.z - only valid if MEM_Dyn */ #ifdef SQLITE_DEBUG Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */ u16 mScopyFlags; /* flags value immediately after the shallow copy */ #endif }; /* ** Size of struct Mem not including the Mem.zMalloc member or anything that ** follows. */ #define MEMCELLSIZE offsetof(Mem,zMalloc) /* One or more of the following flags are set to indicate the validOK ** representations of the value stored in the Mem struct. ** ** If the MEM_Null flag is set, then the value is an SQL NULL value. ** For a pointer type created using sqlite3_bind_pointer() or ** sqlite3_result_pointer() the MEM_Term and MEM_Subtype flags are also set. ** ** If the MEM_Str flag is set then Mem.z points at a string representation. ** Usually this is encoded in the same unicode encoding as the main ** database (see below for exceptions). If the MEM_Term flag is also ** set, then the string is nul terminated. The MEM_Int and MEM_Real ** 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_AffMask 0x001f /* Mask of affinity bits */ #define MEM_FromBind 0x0020 /* Value originates from sqlite3_bind() */ /* Available 0x0040 */ #define MEM_Undefined 0x0080 /* Value is undefined */ #define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */ #define MEM_TypeMask 0xc1df /* 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 */ #define MEM_Term 0x0200 /* String in Mem.z is zero terminated */ #define MEM_Dyn 0x0400 /* Need to call Mem.xDel() on Mem.z */ #define MEM_Static 0x0800 /* Mem.z points to a static string */ #define MEM_Ephem 0x1000 /* Mem.z points to an ephemeral string */ #define MEM_Agg 0x2000 /* Mem.z points to an agg function context */ #define MEM_Zero 0x4000 /* Mem.i contains count of 0s appended to blob */ #define MEM_Subtype 0x8000 /* Mem.eSubtype is valid */ #ifdef SQLITE_OMIT_INCRBLOB #undef MEM_Zero #define MEM_Zero 0x0000 #endif /* Return TRUE if Mem X contains dynamically allocated content - anything ** that needs to be deallocated to avoid a leak. */ #define VdbeMemDynamic(X) \ (((X)->flags&(MEM_Agg|MEM_Dyn))!=0) /* ** 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_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 /* ** Each auxiliary data pointer stored by a user defined function ** implementation calling sqlite3_set_auxdata() is stored in an instance ** of this structure. All such structures associated with a single VM ** are stored in a linked list headed at Vdbe.pAuxData. All are destroyed |
︙ | ︙ | |||
369 370 371 372 373 374 375 | struct sqlite3_context { Mem *pOut; /* The return value is stored here */ FuncDef *pFunc; /* Pointer to function information */ Mem *pMem; /* Memory cell used to store aggregate context */ Vdbe *pVdbe; /* The VM that owns this context */ int iOp; /* Instruction number of OP_Function */ int isError; /* Error code returned by the function. */ | < < < < < < < < < < | 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 | struct sqlite3_context { Mem *pOut; /* The return value is stored here */ FuncDef *pFunc; /* Pointer to function information */ Mem *pMem; /* Memory cell used to store aggregate context */ Vdbe *pVdbe; /* The VM that owns this context */ int iOp; /* Instruction number of OP_Function */ int isError; /* Error code returned by the function. */ u8 skipFlag; /* Skip accumulator loading if true */ u8 argc; /* Number of arguments */ sqlite3_value *argv[1]; /* Argument set */ }; /* A bitfield type for use inside of structures. Always follow with :N where ** N is the number of bits. */ typedef unsigned bft; /* Bit Field Type */ /* The ScanStatus object holds a single value for the ** sqlite3_stmt_scanstatus() interface. */ typedef struct ScanStatus ScanStatus; struct ScanStatus { int addrExplain; /* OP_Explain for loop */ int addrLoop; /* Address of "loops" counter */ int addrVisit; /* Address of "rows visited" counter */ int iSelectID; /* The "Select-ID" for this loop */ LogEst nEst; /* Estimated output rows per loop */ char *zName; /* Name of table or index */ }; |
︙ | ︙ | |||
424 425 426 427 428 429 430 | ** state of the virtual machine. ** ** The "sqlite3_stmt" structure pointer that is returned by sqlite3_prepare() ** is really a pointer to an instance of this structure. */ struct Vdbe { sqlite3 *db; /* The database connection that owns this statement */ | | > | | < > > | > | | | | | > < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | | < < < | < < < < < < < | | < < < < < | | < < | | < < < | 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 | ** state of the virtual machine. ** ** The "sqlite3_stmt" structure pointer that is returned by sqlite3_prepare() ** 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 magic; /* Magic number for sanity checking */ 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 */ int 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 */ bft expired:2; /* 1: recompile VM immediately 2: when convenient */ bft explain:2; /* True if EXPLAIN present on SQL command */ bft doingRerun:1; /* True if rerunning after an auto-reprepare */ 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 */ u32 aCounter[7]; /* Counters used by sqlite3_stmt_status() */ char *zSql; /* Text of the SQL statement that generated this */ #ifdef SQLITE_ENABLE_NORMALIZE char *zNormSql; /* Normalization of the associated SQL statement */ DblquoteStr *pDblStr; /* List of double-quoted string literals */ #endif void *pFree; /* Free this when deleting the vdbe */ VdbeFrame *pFrame; /* Parent frame */ VdbeFrame *pDelFrame; /* List of frame objects to free on VM reset */ int nFrame; /* Number of frames in pFrame list */ u32 expmask; /* Binding to these vars invalidates VM */ SubProgram *pProgram; /* Linked list of all sub-programs used by VM */ AuxData *pAuxData; /* Linked list of auxdata allocations */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS i64 *anExec; /* Number of times each op has been executed */ int nScan; /* Entries in aScan[] */ ScanStatus *aScan; /* Scan definitions for sqlite3_stmt_scanstatus() */ #endif }; /* ** The following are allowed values for Vdbe.magic */ #define VDBE_MAGIC_INIT 0x16bceaa5 /* Building a VDBE program */ #define VDBE_MAGIC_RUN 0x2df20da3 /* VDBE is ready to execute */ #define VDBE_MAGIC_HALT 0x319c2973 /* VDBE has completed execution */ #define VDBE_MAGIC_RESET 0x48fa9f76 /* Reset and ready to run again */ #define VDBE_MAGIC_DEAD 0x5606c3c8 /* The VDBE has been deallocated */ /* ** Structure used to store the context required by the ** sqlite3_preupdate_*() API functions. */ struct PreUpdate { Vdbe *v; 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); int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor*); int sqlite3VdbeCursorMoveto(VdbeCursor**, int*); int sqlite3VdbeCursorRestore(VdbeCursor*); u32 sqlite3VdbeSerialTypeLen(u32); u8 sqlite3VdbeOneByteSerialTypeLen(u8); u32 sqlite3VdbeSerialType(Mem*, int, u32*); 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*); #ifndef 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*, int, 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*); void sqlite3VdbeMemSetZeroBlob(Mem*,int); #ifdef SQLITE_DEBUG int sqlite3VdbeMemIsRowSet(const Mem*); #endif int sqlite3VdbeMemSetRowSet(Mem*); int sqlite3VdbeMemMakeWriteable(Mem*); int sqlite3VdbeMemStringify(Mem*, u8, u8); i64 sqlite3VdbeIntValue(Mem*); int sqlite3VdbeMemIntegerify(Mem*); double sqlite3VdbeRealValue(Mem*); int sqlite3VdbeBooleanValue(Mem*, int ifNull); void sqlite3VdbeIntegerAffinity(Mem*); int sqlite3VdbeMemRealify(Mem*); int sqlite3VdbeMemNumerify(Mem*); void sqlite3VdbeMemCast(Mem*,u8,u8); int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,Mem*); void sqlite3VdbeMemRelease(Mem *p); int sqlite3VdbeMemFinalize(Mem*, FuncDef*); #ifndef SQLITE_OMIT_WINDOWFUNC int sqlite3VdbeMemAggValue(Mem*, Mem*, FuncDef*); #endif #ifndef SQLITE_OMIT_EXPLAIN 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); #endif int sqlite3VdbeTransferError(Vdbe *p); int sqlite3VdbeSorterInit(sqlite3 *, int, VdbeCursor *); void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *); void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *); int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *); int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *); int sqlite3VdbeSorterRewind(const VdbeCursor *, int *); int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *); int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *); #ifdef SQLITE_DEBUG void sqlite3VdbeIncrWriteCounter(Vdbe*, VdbeCursor*); void sqlite3VdbeAssertAbortable(Vdbe*); #else # define sqlite3VdbeIncrWriteCounter(V,C) # define sqlite3VdbeAssertAbortable(V) #endif |
︙ | ︙ | |||
688 689 690 691 692 693 694 | int sqlite3VdbeCheckFk(Vdbe *, int); #else # define sqlite3VdbeCheckFk(p,i) 0 #endif #ifdef SQLITE_DEBUG void sqlite3VdbePrintSql(Vdbe*); | | | 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 | int sqlite3VdbeCheckFk(Vdbe *, int); #else # define sqlite3VdbeCheckFk(p,i) 0 #endif #ifdef SQLITE_DEBUG void sqlite3VdbePrintSql(Vdbe*); void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf); #endif #ifndef SQLITE_OMIT_UTF16 int sqlite3VdbeMemTranslate(Mem*, u8); int sqlite3VdbeMemHandleBom(Mem *pMem); #endif #ifndef SQLITE_OMIT_INCRBLOB |
︙ | ︙ |
Changes to src/vdbeapi.c.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ************************************************************************* ** ** This file contains code use to implement APIs that are part of the ** VDBE. */ #include "sqliteInt.h" #include "vdbeInt.h" | < | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ************************************************************************* ** ** This file contains code use to implement APIs that are part of the ** VDBE. */ #include "sqliteInt.h" #include "vdbeInt.h" #ifndef SQLITE_OMIT_DEPRECATED /* ** Return TRUE (non-zero) of the statement supplied as an argument needs ** to be recompiled. A statement needs to be recompiled whenever the ** execution environment changes in a way that would alter the program ** that sqlite3_prepare() generates. For example, if new functions or |
︙ | ︙ | |||
70 71 72 73 74 75 76 | 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 ){ | | | 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | 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->xTrace(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. */ |
︙ | ︙ | |||
105 106 107 108 109 110 111 | rc = SQLITE_OK; }else{ Vdbe *v = (Vdbe*)pStmt; sqlite3 *db = v->db; if( vdbeSafety(v) ) return SQLITE_MISUSE_BKPT; sqlite3_mutex_enter(db->mutex); checkProfileCallback(db, v); | < | < | 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | rc = SQLITE_OK; }else{ Vdbe *v = (Vdbe*)pStmt; sqlite3 *db = v->db; if( vdbeSafety(v) ) return SQLITE_MISUSE_BKPT; sqlite3_mutex_enter(db->mutex); checkProfileCallback(db, v); rc = sqlite3VdbeFinalize(v); rc = sqlite3ApiExit(db, rc); sqlite3LeaveMutexAndCloseZombie(db); } return rc; } /* |
︙ | ︙ | |||
233 234 235 236 237 238 239 | #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 | #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 */ SQLITE_NULL, /* 0x01 */ SQLITE_TEXT, /* 0x02 */ SQLITE_NULL, /* 0x03 */ SQLITE_INTEGER, /* 0x04 */ SQLITE_NULL, /* 0x05 */ SQLITE_INTEGER, /* 0x06 */ SQLITE_NULL, /* 0x07 */ SQLITE_FLOAT, /* 0x08 */ SQLITE_NULL, /* 0x09 */ SQLITE_FLOAT, /* 0x0a */ SQLITE_NULL, /* 0x0b */ SQLITE_INTEGER, /* 0x0c */ SQLITE_NULL, /* 0x0d */ SQLITE_INTEGER, /* 0x0e */ SQLITE_NULL, /* 0x0f */ SQLITE_BLOB, /* 0x10 */ SQLITE_NULL, /* 0x11 */ SQLITE_TEXT, /* 0x12 */ SQLITE_NULL, /* 0x13 */ SQLITE_INTEGER, /* 0x14 */ SQLITE_NULL, /* 0x15 */ SQLITE_INTEGER, /* 0x16 */ SQLITE_NULL, /* 0x17 */ SQLITE_FLOAT, /* 0x18 */ SQLITE_NULL, /* 0x19 */ SQLITE_FLOAT, /* 0x1a */ SQLITE_NULL, /* 0x1b */ SQLITE_INTEGER, /* 0x1c */ SQLITE_NULL, /* 0x1d */ SQLITE_INTEGER, /* 0x1e */ SQLITE_NULL, /* 0x1f */ }; return aType[pVal->flags&MEM_AffMask]; } /* Return true if a parameter to xUpdate represents an unchanged column */ int sqlite3_value_nochange(sqlite3_value *pVal){ return (pVal->flags&(MEM_Null|MEM_Zero))==(MEM_Null|MEM_Zero); } /* Return true if a parameter value originated from an sqlite3_bind() */ |
︙ | ︙ | |||
347 348 349 350 351 352 353 | if( pNew->flags&(MEM_Str|MEM_Blob) ){ pNew->flags &= ~(MEM_Static|MEM_Dyn); pNew->flags |= MEM_Ephem; if( sqlite3VdbeMemMakeWriteable(pNew)!=SQLITE_OK ){ sqlite3ValueFree(pNew); pNew = 0; } | < < < | | < < < < < < < < < < < < < < | | | 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 | if( pNew->flags&(MEM_Str|MEM_Blob) ){ pNew->flags &= ~(MEM_Static|MEM_Dyn); pNew->flags |= MEM_Ephem; if( sqlite3VdbeMemMakeWriteable(pNew)!=SQLITE_OK ){ sqlite3ValueFree(pNew); pNew = 0; } } return pNew; } /* Destroy an sqlite3_value object previously obtained from ** sqlite3_value_dup(). */ void sqlite3_value_free(sqlite3_value *pOld){ sqlite3ValueFree(pOld); } /**************************** 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 but if the string or blob is too large, it ** then sets the error code to SQLITE_TOOBIG ** ** 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 */ ){ if( sqlite3VdbeMemSetStr(pCtx->pOut, z, n, enc, xDel)==SQLITE_TOOBIG ){ sqlite3_result_error_toobig(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); } if( pCtx ) sqlite3_result_error_toobig(pCtx); return SQLITE_TOOBIG; } void sqlite3_result_blob( sqlite3_context *pCtx, const void *z, int n, void (*xDel)(void *) |
︙ | ︙ | |||
502 503 504 505 506 507 508 | const char *z, sqlite3_uint64 n, void (*xDel)(void *), unsigned char enc ){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); assert( xDel!=SQLITE_DYNAMIC ); | < | < < | | | < | < < < | < | > < < < < < | | < < < < < < < < < < < < < < < | 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 | const char *z, sqlite3_uint64 n, void (*xDel)(void *), unsigned char enc ){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); assert( xDel!=SQLITE_DYNAMIC ); if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE; if( n>0x7fffffff ){ (void)invokeValueDestructor(z, xDel, pCtx); }else{ setResultStrOrError(pCtx, z, (int)n, enc, xDel); } } #ifndef SQLITE_OMIT_UTF16 void sqlite3_result_text16( sqlite3_context *pCtx, const void *z, int n, void (*xDel)(void *) ){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n, SQLITE_UTF16NATIVE, xDel); } void sqlite3_result_text16be( sqlite3_context *pCtx, const void *z, int n, void (*xDel)(void *) ){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n, SQLITE_UTF16BE, xDel); } void sqlite3_result_text16le( sqlite3_context *pCtx, const void *z, int n, void (*xDel)(void *) ){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); setResultStrOrError(pCtx, z, n, SQLITE_UTF16LE, xDel); } #endif /* SQLITE_OMIT_UTF16 */ void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemCopy(pCtx->pOut, pValue); } void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetZeroBlob(pCtx->pOut, n); } 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 ){ sqlite3VdbeMemSetStr(pCtx->pOut, sqlite3ErrStr(errCode), -1, SQLITE_UTF8, SQLITE_STATIC); } } /* Force an SQLITE_TOOBIG error. */ void sqlite3_result_error_toobig(sqlite3_context *pCtx){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); pCtx->isError = SQLITE_TOOBIG; sqlite3VdbeMemSetStr(pCtx->pOut, "string or blob too big", -1, SQLITE_UTF8, SQLITE_STATIC); } /* An SQLITE_NOMEM error. */ void sqlite3_result_error_nomem(sqlite3_context *pCtx){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetNull(pCtx->pOut); pCtx->isError = SQLITE_NOMEM_BKPT; sqlite3OomFault(pCtx->pOut->db); } /* ** This function is called after a transaction has been committed. It ** invokes callbacks registered with sqlite3_wal_hook() as required. */ static int doWalCallbacks(sqlite3 *db){ int rc = SQLITE_OK; |
︙ | ︙ | |||
648 649 650 651 652 653 654 655 | ** outer sqlite3_step() wrapper procedure. */ static int sqlite3Step(Vdbe *p){ sqlite3 *db; int rc; assert(p); db = p->db; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > | | | | < < < < < < < < | | | | | | | | | | | | | | | | | | | | | | | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < | < < < < < < < > | | | > > > | > > > > > > > > > > > > | 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 | ** outer sqlite3_step() wrapper procedure. */ static int sqlite3Step(Vdbe *p){ sqlite3 *db; int rc; assert(p); if( p->magic!=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. ** ** Nevertheless, some published applications that were originally written ** for version 3.6.23 or earlier do in fact depend on SQLITE_MISUSE ** returns, and those were broken by the automatic-reset change. As a ** a work-around, the SQLITE_OMIT_AUTORESET compile-time restores the ** legacy behavior of returning SQLITE_MISUSE for cases where the ** previous sqlite3_step() returned something other than a SQLITE_LOCKED ** or SQLITE_BUSY error. */ #ifdef SQLITE_OMIT_AUTORESET if( (rc = p->rc&0xff)==SQLITE_BUSY || rc==SQLITE_LOCKED ){ sqlite3_reset((sqlite3_stmt*)p); }else{ return SQLITE_MISUSE_BKPT; } #else sqlite3_reset((sqlite3_stmt*)p); #endif } /* Check that malloc() has not failed. If it has, return early. */ db = p->db; if( db->mallocFailed ){ 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 ){ db->u1.isInterrupted = 0; } assert( db->nVdbeWrite>0 || db->autoCommit==0 || (db->nDeferredCons==0 && db->nDeferredImmCons==0) ); #ifndef SQLITE_OMIT_TRACE if( (db->mTrace & (SQLITE_TRACE_PROFILE|SQLITE_TRACE_XPROFILE))!=0 && !db->init.busy && p->zSql ){ sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime); }else{ assert( p->startTime==0 ); } #endif db->nVdbeActive++; if( p->readOnly==0 ) db->nVdbeWrite++; if( p->bIsReader ) db->nVdbeRead++; p->pc = 0; } #ifdef SQLITE_DEBUG p->rcApp = SQLITE_OK; #endif #ifndef SQLITE_OMIT_EXPLAIN if( p->explain ){ rc = sqlite3VdbeList(p); }else #endif /* SQLITE_OMIT_EXPLAIN */ { db->nVdbeExec++; rc = sqlite3VdbeExec(p); db->nVdbeExec--; } if( rc!=SQLITE_ROW ){ #ifndef SQLITE_OMIT_TRACE /* If the statement completed successfully, invoke the profile callback */ checkProfileCallback(db, p); #endif 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: /* At this point local variable rc holds the value that should be ** returned if this statement was compiled using the legacy ** sqlite3_prepare() interface. According to the docs, this can only ** be one of the values in the first assert() below. Variable p->rc ** contains the value that would be returned if sqlite3_finalize() ** were called on statement p. */ assert( rc==SQLITE_ROW || rc==SQLITE_DONE || rc==SQLITE_ERROR || (rc&0xff)==SQLITE_BUSY || rc==SQLITE_MISUSE ); assert( (p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE) || p->rc==p->rcApp ); if( rc!=SQLITE_ROW && 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); } return (rc&db->errMask); } /* ** This is the top-level implementation of sqlite3_step(). Call ** sqlite3Step() to do most of the work. If a schema error occurs, ** call sqlite3Reprepare() and try again. */ int sqlite3_step(sqlite3_stmt *pStmt){ int rc = SQLITE_OK; /* Result from sqlite3Step() */ Vdbe *v = (Vdbe*)pStmt; /* the prepared statement */ int cnt = 0; /* Counter to prevent infinite loop of reprepares */ sqlite3 *db; /* The database connection */ if( vdbeSafetyNotNull(v) ){ return SQLITE_MISUSE_BKPT; } db = v->db; sqlite3_mutex_enter(db->mutex); v->doingRerun = 0; while( (rc = sqlite3Step(v))==SQLITE_SCHEMA && cnt++ < SQLITE_MAX_SCHEMA_RETRY ){ int savedPc = v->pc; rc = sqlite3Reprepare(v); if( rc!=SQLITE_OK ){ /* This case occurs after failing to recompile an sql statement. ** The error message from the SQL compiler has already been loaded |
︙ | ︙ | |||
821 822 823 824 825 826 827 | } else { v->zErrMsg = 0; v->rc = rc = SQLITE_NOMEM_BKPT; } break; } sqlite3_reset(pStmt); | | < < < < < < | 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 | } else { v->zErrMsg = 0; v->rc = rc = SQLITE_NOMEM_BKPT; } break; } sqlite3_reset(pStmt); if( savedPc>=0 ) v->doingRerun = 1; assert( v->expired==0 ); } sqlite3_mutex_leave(db->mutex); return rc; } |
︙ | ︙ | |||
878 879 880 881 882 883 884 885 | ** value, as a signal to the xUpdate routine that the column is unchanged. */ int sqlite3_vtab_nochange(sqlite3_context *p){ assert( p ); return sqlite3_value_nochange(p->pOut); } /* | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 | ** value, as a signal to the xUpdate routine that the column is unchanged. */ int sqlite3_vtab_nochange(sqlite3_context *p){ assert( p ); return sqlite3_value_nochange(p->pOut); } /* ** Return the current time for a statement. If the current time ** is requested more than once within the same run of a single prepared ** statement, the exact same time is returned for each invocation regardless ** of the amount of time that elapses between invocations. In other words, ** the time returned is always the time of the first call. */ sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *p){ int rc; #ifndef SQLITE_ENABLE_STAT3_OR_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 ){ |
︙ | ︙ | |||
1034 1035 1036 1037 1038 1039 1040 | ** 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) ); | | | 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 | ** 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_STAT3_OR_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; |
︙ | ︙ | |||
1068 1069 1070 1071 1072 1073 1074 | void *pAux, void (*xDelete)(void*) ){ AuxData *pAuxData; Vdbe *pVdbe = pCtx->pVdbe; assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); | | | 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 | void *pAux, void (*xDelete)(void*) ){ AuxData *pAuxData; Vdbe *pVdbe = pCtx->pVdbe; assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); #ifdef SQLITE_ENABLE_STAT3_OR_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) ){ |
︙ | ︙ | |||
1131 1132 1133 1134 1135 1136 1137 | /* ** Return the number of values available from the current row of the ** currently executing statement pStmt. */ int sqlite3_data_count(sqlite3_stmt *pStmt){ Vdbe *pVm = (Vdbe *)pStmt; | | | 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 | /* ** Return the number of values available from the current row of the ** currently executing statement pStmt. */ int sqlite3_data_count(sqlite3_stmt *pStmt){ Vdbe *pVm = (Vdbe *)pStmt; if( pVm==0 || pVm->pResultSet==0 ) return 0; return pVm->nResColumn; } /* ** Return a pointer to static memory containing an SQL NULL value. */ static const Mem *columnNullValue(void){ |
︙ | ︙ | |||
1154 1155 1156 1157 1158 1159 1160 | ** __attribute__((aligned(8))) macro. */ static const Mem nullMem #if defined(SQLITE_DEBUG) && defined(__GNUC__) __attribute__((aligned(8))) #endif = { /* .u = */ {0}, | < < | > > | | 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 | ** __attribute__((aligned(8))) macro. */ static const Mem nullMem #if defined(SQLITE_DEBUG) && defined(__GNUC__) __attribute__((aligned(8))) #endif = { /* .u = */ {0}, /* .flags = */ (u16)MEM_Null, /* .enc = */ (u8)0, /* .eSubtype = */ (u8)0, /* .n = */ (int)0, /* .z = */ (char*)0, /* .zMalloc = */ (char*)0, /* .szMalloc = */ (int)0, /* .uTemp = */ (u32)0, /* .db = */ (sqlite3*)0, /* .xDel = */ (void(*)(void*))0, #ifdef SQLITE_DEBUG /* .pScopyFrom = */ (Mem*)0, /* .mScopyFlags= */ 0, #endif }; return &nullMem; |
︙ | ︙ | |||
1186 1187 1188 1189 1190 1191 1192 | Vdbe *pVm; Mem *pOut; pVm = (Vdbe *)pStmt; if( pVm==0 ) return (Mem*)columnNullValue(); assert( pVm->db ); sqlite3_mutex_enter(pVm->db->mutex); | | | | 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 | Vdbe *pVm; Mem *pOut; pVm = (Vdbe *)pStmt; if( pVm==0 ) return (Mem*)columnNullValue(); assert( pVm->db ); sqlite3_mutex_enter(pVm->db->mutex); if( pVm->pResultSet!=0 && i<pVm->nResColumn && i>=0 ){ pOut = &pVm->pResultSet[i]; }else{ sqlite3Error(pVm->db, SQLITE_RANGE); pOut = (Mem*)columnNullValue(); } return pOut; } |
︙ | ︙ | |||
1453 1454 1455 1456 1457 1458 1459 | ** ** A successful evaluation of this routine acquires the mutex on p. ** the mutex is released if any kind of error occurs. ** ** The error code stored in database p->db is overwritten with the return ** value in any case. */ | | | | > | | | | 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 | ** ** A successful evaluation of this routine acquires the mutex on p. ** the mutex is released if any kind of error occurs. ** ** The error code stored in database p->db is overwritten with the return ** value in any case. */ static int vdbeUnbind(Vdbe *p, int i){ Mem *pVar; if( vdbeSafetyNotNull(p) ){ return SQLITE_MISUSE_BKPT; } sqlite3_mutex_enter(p->db->mutex); if( p->magic!=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-48440-37595 If the specific value bound to 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 */ int 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; rc = vdbeUnbind(p, i); if( rc==SQLITE_OK ){ if( zData!=0 ){ pVar = &p->aVar[i-1]; rc = sqlite3VdbeMemSetStr(pVar, zData, nData, encoding, xDel); if( rc==SQLITE_OK && encoding!=0 ){ rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db)); } |
︙ | ︙ | |||
1551 1552 1553 1554 1555 1556 1557 | sqlite3_stmt *pStmt, int i, const void *zData, sqlite3_uint64 nData, void (*xDel)(void*) ){ assert( xDel!=SQLITE_DYNAMIC ); | > > > | > | | | | | 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 | sqlite3_stmt *pStmt, int i, const void *zData, sqlite3_uint64 nData, void (*xDel)(void*) ){ assert( xDel!=SQLITE_DYNAMIC ); if( nData>0x7fffffff ){ return invokeValueDestructor(zData, xDel, 0); }else{ return bindText(pStmt, i, zData, (int)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); sqlite3_mutex_leave(p->db->mutex); } return rc; } int sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){ return sqlite3_bind_int64(p, i, (i64)iValue); } int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){ int rc; Vdbe *p = (Vdbe *)pStmt; rc = vdbeUnbind(p, i); if( rc==SQLITE_OK ){ sqlite3VdbeMemSetInt64(&p->aVar[i-1], iValue); sqlite3_mutex_leave(p->db->mutex); } return rc; } int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){ int rc; Vdbe *p = (Vdbe*)pStmt; rc = vdbeUnbind(p, i); if( rc==SQLITE_OK ){ sqlite3_mutex_leave(p->db->mutex); } return rc; } int sqlite3_bind_pointer( sqlite3_stmt *pStmt, int i, void *pPtr, const char *zPTtype, void (*xDestructor)(void*) ){ int rc; Vdbe *p = (Vdbe*)pStmt; rc = vdbeUnbind(p, i); if( rc==SQLITE_OK ){ sqlite3VdbeMemSetPointer(&p->aVar[i-1], pPtr, zPTtype, xDestructor); sqlite3_mutex_leave(p->db->mutex); }else if( xDestructor ){ xDestructor(pPtr); } return rc; |
︙ | ︙ | |||
1621 1622 1623 1624 1625 1626 1627 | int i, const char *zData, sqlite3_uint64 nData, void (*xDel)(void*), unsigned char enc ){ assert( xDel!=SQLITE_DYNAMIC ); | | > > | < | | < | < < | 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 | int i, const char *zData, sqlite3_uint64 nData, void (*xDel)(void*), unsigned char enc ){ assert( xDel!=SQLITE_DYNAMIC ); if( nData>0x7fffffff ){ return invokeValueDestructor(zData, xDel, 0); }else{ if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE; return bindText(pStmt, i, zData, (int)nData, xDel, enc); } } #ifndef SQLITE_OMIT_UTF16 int sqlite3_bind_text16( sqlite3_stmt *pStmt, int i, const void *zData, int nData, void (*xDel)(void*) ){ return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE); } #endif /* SQLITE_OMIT_UTF16 */ int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){ int rc; switch( sqlite3_value_type((sqlite3_value*)pValue) ){ case SQLITE_INTEGER: { rc = sqlite3_bind_int64(pStmt, i, pValue->u.i); break; } case SQLITE_FLOAT: { rc = sqlite3_bind_double(pStmt, i, pValue->u.r); break; } case SQLITE_BLOB: { if( pValue->flags & MEM_Zero ){ rc = sqlite3_bind_zeroblob(pStmt, i, pValue->u.nZero); }else{ rc = sqlite3_bind_blob(pStmt, i, pValue->z, pValue->n,SQLITE_TRANSIENT); |
︙ | ︙ | |||
1675 1676 1677 1678 1679 1680 1681 | } } return rc; } int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){ int rc; Vdbe *p = (Vdbe *)pStmt; | | < < < < | 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 | } } 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; |
︙ | ︙ | |||
1814 1815 1816 1817 1818 1819 1820 | } /* ** Return true if the prepared statement is in need of being reset. */ int sqlite3_stmt_busy(sqlite3_stmt *pStmt){ Vdbe *v = (Vdbe*)pStmt; | | | | 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 | } /* ** 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->magic==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. */ sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){ sqlite3_stmt *pNext; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(pDb) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif sqlite3_mutex_enter(pDb->mutex); if( pStmt==0 ){ pNext = (sqlite3_stmt*)pDb->pVdbe; }else{ pNext = (sqlite3_stmt*)((Vdbe*)pStmt)->pNext; } sqlite3_mutex_leave(pDb->mutex); return pNext; } /* ** Return the value of a status counter for a prepared statement |
︙ | ︙ | |||
1860 1861 1862 1863 1864 1865 1866 | } #endif if( op==SQLITE_STMTSTATUS_MEMUSED ){ sqlite3 *db = pVdbe->db; sqlite3_mutex_enter(db->mutex); v = 0; db->pnBytesFreed = (int*)&v; | < < | > < | 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 | } #endif if( op==SQLITE_STMTSTATUS_MEMUSED ){ sqlite3 *db = pVdbe->db; sqlite3_mutex_enter(db->mutex); v = 0; db->pnBytesFreed = (int*)&v; sqlite3VdbeClearObject(db, pVdbe); sqlite3DbFree(db, pVdbe); db->pnBytesFreed = 0; sqlite3_mutex_leave(db->mutex); }else{ v = pVdbe->aCounter[op]; if( resetFlag ) pVdbe->aCounter[op] = 0; } return (int)v; } |
︙ | ︙ | |||
1959 1960 1961 1962 1963 1964 1965 | /* 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 ){ | | < | 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 | /* 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 = sqlite3ColumnOfIndex(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; 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; |
︙ | ︙ | |||
1993 1994 1995 1996 1997 1998 1999 | 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 ){ | < | < | 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 | 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 ){ sqlite3VdbeMemRealify(pMem); } } preupdate_old_out: sqlite3Error(db, rc); return sqlite3ApiExit(db, rc); |
︙ | ︙ | |||
2035 2036 2037 2038 2039 2040 2041 | */ int sqlite3_preupdate_depth(sqlite3 *db){ PreUpdate *p = db->pPreUpdate; return (p ? p->v->nFrame : 0); } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ | < < < < < < < < < < < | | 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 | */ 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 ){ iIdx = sqlite3ColumnOfIndex(p->pPk, iIdx); } if( iIdx>=p->pCsr->nField || iIdx<0 ){ rc = SQLITE_RANGE; goto preupdate_new_out; } if( p->op==SQLITE_INSERT ){ |
︙ | ︙ | |||
2126 2127 2128 2129 2130 2131 2132 | } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS /* ** Return status data for a single loop within query pStmt. */ | | | < < < < < < < < < < < < < | < < < | < < < < < < < < < < < < < < < < | < < < < | < | 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 | } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS /* ** Return status data for a single loop within query pStmt. */ int sqlite3_stmt_scanstatus( sqlite3_stmt *pStmt, /* Prepared statement being queried */ int idx, /* Index of loop to report on */ int iScanStatusOp, /* Which metric to return */ void *pOut /* OUT: Write the answer here */ ){ Vdbe *p = (Vdbe*)pStmt; ScanStatus *pScan; if( idx<0 || idx>=p->nScan ) return 1; pScan = &p->aScan[idx]; switch( iScanStatusOp ){ case SQLITE_SCANSTAT_NLOOP: { *(sqlite3_int64*)pOut = p->anExec[pScan->addrLoop]; break; } case SQLITE_SCANSTAT_NVISIT: { *(sqlite3_int64*)pOut = p->anExec[pScan->addrVisit]; break; } case SQLITE_SCANSTAT_EST: { double r = 1.0; LogEst x = pScan->nEst; while( x<100 ){ x += 10; |
︙ | ︙ | |||
2212 2213 2214 2215 2216 2217 2218 | if( pScan->addrExplain ){ *(int*)pOut = p->aOp[ pScan->addrExplain ].p1; }else{ *(int*)pOut = -1; } break; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < | < | 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 | if( pScan->addrExplain ){ *(int*)pOut = p->aOp[ pScan->addrExplain ].p1; }else{ *(int*)pOut = -1; } break; } default: { return 1; } } return 0; } /* ** Zero all counters associated with the sqlite3_stmt_scanstatus() data. */ void sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){ Vdbe *p = (Vdbe*)pStmt; memset(p->anExec, 0, p->nOp * sizeof(i64)); } #endif /* SQLITE_ENABLE_STMT_SCANSTATUS */ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ************************************************************************* ** 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" | < < < < | | | | < < < < < < < | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | ************************************************************************* ** This 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; p->magic = 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; } /* ** Change the error string stored in Vdbe.zErrMsg */ void sqlite3VdbeError(Vdbe *p, const char *zFormat, ...){ va_list ap; sqlite3DbFree(p->db, p->zErrMsg); va_start(ap, zFormat); |
︙ | ︙ | |||
111 112 113 114 115 116 117 | if( strcmp(zId, pStr->z)==0 ) return 1; } return 0; } #endif /* | | < < < < < < < | | | | | | | | | 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 | if( strcmp(zId, pStr->z)==0 ) return 1; } return 0; } #endif /* ** Swap all content between two VDBE structures. */ void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){ Vdbe tmp, *pTmp; char *zTmp; assert( pA->db==pB->db ); tmp = *pA; *pA = *pB; *pB = tmp; pTmp = pA->pNext; pA->pNext = pB->pNext; pB->pNext = pTmp; pTmp = pA->pPrev; pA->pPrev = pB->pPrev; pB->pPrev = pTmp; zTmp = pA->zSql; pA->zSql = pB->zSql; pB->zSql = zTmp; #if 0 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)); |
︙ | ︙ | |||
183 184 185 186 187 188 189 | /* 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; } | | | < < < < < < < | < < | 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 | /* 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". */ static void test_addop_breakpoint(void){ static int n = 0; n++; } #endif /* ** Add a new instruction to the list of instructions current in the ** VDBE. Return the address of the new instruction. |
︙ | ︙ | |||
241 242 243 244 245 246 247 | 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; | | < < < < < < | > > > > | 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 | 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->magic==VDBE_MAGIC_INIT ); assert( op>=0 && op<0xff ); if( p->nOpAlloc<=i ){ return growOp3(p, op, p1, p2, p3); } p->nOp++; pOp = &p->aOp[i]; 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(); } #endif #ifdef VDBE_PROFILE pOp->cycles = 0; pOp->cnt = 0; #endif #ifdef SQLITE_VDBE_COVERAGE pOp->iSrcLine = 0; #endif return i; } int sqlite3VdbeAddOp0(Vdbe *p, int op){ |
︙ | ︙ | |||
346 347 348 349 350 351 352 | int p4type /* P4 operand type */ ){ int addr = sqlite3VdbeAddOp3(p, op, p1, p2, p3); sqlite3VdbeChangeP4(p, addr, zP4, p4type); return addr; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 317 318 319 320 321 322 323 324 325 326 327 328 329 330 | 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 */ int op, /* The new opcode */ |
︙ | ︙ | |||
432 433 434 435 436 437 438 | void sqlite3ExplainBreakpoint(const char *z1, const char *z2){ (void)z1; (void)z2; } #endif /* | | | < | | | < < | < < | 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 | void sqlite3ExplainBreakpoint(const char *z1, const char *z2){ (void)z1; (void)z2; } #endif /* ** Add a new OP_ 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){ int j; sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC); for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j); } /* ** Add an opcode that includes the p4 value as an integer. */ int sqlite3VdbeAddOp4Int( Vdbe *p, /* Add the opcode to this VM */ |
︙ | ︙ | |||
570 571 572 573 574 575 576 | 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 | < < < | | | < < < | < < < | 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 | 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->magic==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. */ void sqlite3VdbeRunOnlyOnce(Vdbe *p){ p->runOnlyOnce = 1; } /* ** Mark the VDBE as one that can only be run multiple times. */ void sqlite3VdbeReusable(Vdbe *p){ p->runOnlyOnce = 0; } #ifdef SQLITE_DEBUG /* sqlite3AssertMayAbort() logic */ /* ** The following type and function are used to iterate through all opcodes ** in a Vdbe main program and each of the sub-programs (triggers) it may |
︙ | ︙ | |||
696 697 698 699 700 701 702 | ** 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 | < < < < < < | < < < < < < < < | < | 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 | ** 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_VDestroy || (opcode==OP_Function0 && pOp->p4.pFunc->funcFlags&SQLITE_FUNC_INTERNAL) || ((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( 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) ); } #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. |
︙ | ︙ | |||
803 804 805 806 807 808 809 | ** ** (2) Compute the maximum number of arguments used by any SQL function ** and store that value in *pMaxFuncArgs. ** ** (3) Update the Vdbe.readOnly and Vdbe.bIsReader flags to accurately ** indicate what the prepared statement actually does. ** | | | | | | > > > > > > > > > > > > > | > > < | < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 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 | ** ** (2) Compute the maximum number of arguments used by any SQL function ** and store that value in *pMaxFuncArgs. ** ** (3) Update the Vdbe.readOnly and Vdbe.bIsReader flags to accurately ** indicate what the prepared statement actually does. ** ** (4) Initialize the p4.xAdvance pointer on opcodes that use it. ** ** (5) Reclaim the memory allocated for storing labels. ** ** This routine will only function correctly if the mkopcodeh.tcl generator ** script numbers the opcodes correctly. Changes to this routine must be ** coordinated with changes to mkopcodeh.tcl. */ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ int nMaxArgs = *pMaxFuncArgs; Op *pOp; Parse *pParse = p->pParse; int *aLabel = pParse->aLabel; p->readOnly = 1; p->bIsReader = 0; pOp = &p->aOp[p->nOp-1]; while(1){ /* Only JUMP opcodes and the short list of special opcodes in the switch ** below need to be considered. The mkopcodeh.tcl generator script groups ** all these opcodes together near the front of the opcode list. Skip ** any opcode that does not need processing by virtual of the fact that ** it is larger than SQLITE_MX_JUMP_OPCODE, as a performance optimization. */ 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; /* fall thru */ } case OP_AutoCommit: case OP_Savepoint: { p->bIsReader = 1; break; } #ifndef SQLITE_OMIT_WAL case OP_Checkpoint: #endif case OP_Vacuum: case OP_JournalMode: { p->readOnly = 0; p->bIsReader = 1; break; } case OP_Next: case OP_SorterNext: { pOp->p4.xAdvance = sqlite3BtreeNext; pOp->p4type = P4_ADVANCE; /* The code generator never codes any of these opcodes as a jump ** to a label. They are always coded as a jump backwards to a ** known address */ assert( pOp->p2>=0 ); break; } case OP_Prev: { pOp->p4.xAdvance = sqlite3BtreePrevious; pOp->p4type = P4_ADVANCE; /* The code generator never codes any of these opcodes as a jump ** to a label. They are always coded as a jump backwards to a ** known address */ assert( pOp->p2>=0 ); break; } #ifndef SQLITE_OMIT_VIRTUALTABLE case OP_VUpdate: { if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2; break; } 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 ); 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 ** have non-negative values for P2. */ assert( (sqlite3OpcodeProperty[pOp->opcode]&OPFLG_JUMP)==0 || pOp->p2>=0); } if( pOp==p->aOp ) break; pOp--; } sqlite3DbFree(p->db, pParse->aLabel); pParse->aLabel = 0; pParse->nLabel = 0; *pMaxFuncArgs = nMaxArgs; assert( p->bIsReader!=0 || DbMaskAllZero(p->btreeMask) ); } /* ** Return the address of the next instruction to be inserted. */ int sqlite3VdbeCurrentAddr(Vdbe *p){ assert( p->magic==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 |
︙ | ︙ | |||
1071 1072 1073 1074 1075 1076 1077 | 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 ); | | | 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 | 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->magic==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; |
︙ | ︙ | |||
1123 1124 1125 1126 1127 1128 1129 | 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++]; | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > > | < | > | | 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 | 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, u32 addr, u8 iNewOpcode){ sqlite3VdbeGetOp(p,addr)->opcode = iNewOpcode; } void sqlite3VdbeChangeP1(Vdbe *p, u32 addr, int val){ sqlite3VdbeGetOp(p,addr)->p1 = val; } void sqlite3VdbeChangeP2(Vdbe *p, u32 addr, int val){ sqlite3VdbeGetOp(p,addr)->p2 = val; } void sqlite3VdbeChangeP3(Vdbe *p, u32 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); } /* ** 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); } } static void vdbeFreeOpArray(sqlite3 *, Op *, int); /* ** 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; } case P4_REAL: case P4_INT64: case P4_DYNAMIC: case P4_DYNBLOB: case P4_INTARRAY: { sqlite3DbFree(db, p4); break; } case P4_KEYINFO: { if( db->pnBytesFreed==0 ) sqlite3KeyInfoUnref((KeyInfo*)p4); break; } #ifdef SQLITE_ENABLE_CURSOR_HINTS |
︙ | ︙ | |||
1337 1338 1339 1340 1341 1342 1343 | /* ** Free the space allocated for aOp and any p4 values allocated for the ** opcodes contained within. If aOp is not NULL it is assumed to contain ** nOp entries. */ static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){ | < < | < > < < | < < < < < < < | 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 | /* ** Free the space allocated for aOp and any p4 values allocated for the ** opcodes contained within. If aOp is not NULL it is assumed to contain ** nOp entries. */ static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){ if( aOp ){ Op *pOp; for(pOp=&aOp[nOp-1]; pOp>=aOp; pOp--){ if( pOp->p4type <= P4_FREE_IF_LE ) freeP4(db, pOp->p4type, pOp->p4.p); #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS sqlite3DbFree(db, pOp->zComment); #endif } sqlite3DbFreeNN(db, aOp); } } /* ** Link the SubProgram object passed as the second argument into the linked ** 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; assert( addr>=0 && addr<p->nOp ); |
︙ | ︙ | |||
1396 1397 1398 1399 1400 1401 1402 | 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; } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 | 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. ** |
︙ | ︙ | |||
1473 1474 1475 1476 1477 1478 1479 | } } void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){ Op *pOp; sqlite3 *db; assert( p!=0 ); db = p->db; | | | 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 | } } void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){ Op *pOp; sqlite3 *db; assert( p!=0 ); db = p->db; assert( p->magic==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 ); |
︙ | ︙ | |||
1518 1519 1520 1521 1522 1523 1524 | void sqlite3VdbeAppendP4(Vdbe *p, void *pP4, int n){ VdbeOp *pOp; assert( n!=P4_INT32 && n!=P4_VTAB ); assert( n<=0 ); if( p->db->mallocFailed ){ freeP4(p->db, n, pP4); }else{ | | | 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 | void sqlite3VdbeAppendP4(Vdbe *p, void *pP4, int n){ VdbeOp *pOp; assert( n!=P4_INT32 && n!=P4_VTAB ); assert( n<=0 ); if( p->db->mallocFailed ){ freeP4(p->db, n, pP4); }else{ assert( pP4!=0 ); assert( p->nOp>0 ); pOp = &p->aOp[p->nOp-1]; assert( pOp->p4type==P4_NOTUSED ); pOp->p4type = n; pOp->p4.p = pP4; } } |
︙ | ︙ | |||
1549 1550 1551 1552 1553 1554 1555 | ** 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 ); | | | 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 | ** 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 ); 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, ...){ |
︙ | ︙ | |||
1580 1581 1582 1583 1584 1585 1586 | #endif /* NDEBUG */ #ifdef SQLITE_VDBE_COVERAGE /* ** Set the value if the iSrcLine field for the previously coded instruction. */ void sqlite3VdbeSetLineNumber(Vdbe *v, int iLine){ | | | | | > > > < < < < < < | 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 | #endif /* NDEBUG */ #ifdef SQLITE_VDBE_COVERAGE /* ** Set the value if the iSrcLine field for the previously coded instruction. */ void sqlite3VdbeSetLineNumber(Vdbe *v, int iLine){ sqlite3VdbeGetOp(v,-1)->iSrcLine = iLine; } #endif /* SQLITE_VDBE_COVERAGE */ /* ** Return the opcode for a given address. If the address is -1, then ** return the most recently inserted opcode. ** ** If a memory allocation error has occurred prior to the calling of this ** routine, then a pointer to a dummy VdbeOp will be returned. That opcode ** is readable but not writable, though it is cast to a writable value. ** The return of a dummy opcode allows the call to continue functioning ** after an OOM fault without having to check to see if the return from ** this routine is a valid pointer. But because the dummy.opcode is 0, ** 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->magic==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{ return &p->aOp[addr]; } } #if defined(SQLITE_ENABLE_EXPLAIN_COMMENTS) /* ** Return an integer value for one of the parameters to the opcode pOp ** determined by character c. */ static int translateP(char c, const Op *pOp){ if( c=='1' ) return pOp->p1; |
︙ | ︙ | |||
1642 1643 1644 1645 1646 1647 1648 | ** 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 */ | | < | > > | < < < | > > > | > | | < | | < < > > | | < < < < < < < < < < < < < < < < | | | | < > < > | | > > | > | < < > > | | < | 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 | ** 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 */ static int displayComment( const Op *pOp, /* The opcode to be commented */ const char *zP4, /* Previously obtained value for P4 */ char *zTemp, /* Write result here */ int nTemp /* Space available in zTemp[] */ ){ const char *zOpName; const char *zSynopsis; int nOpName; int ii, jj; char zAlt[50]; 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 ){ if( pOp->p5 & SQLITE_STOREP2 ){ sqlite3_snprintf(sizeof(zAlt), zAlt, "r[P2] = (%s)", zSynopsis+3); }else{ sqlite3_snprintf(sizeof(zAlt), zAlt, "if %s goto P2", zSynopsis+3); } zSynopsis = zAlt; } for(ii=jj=0; jj<nTemp-1 && (c = zSynopsis[ii])!=0; ii++){ if( c=='P' ){ c = zSynopsis[++ii]; if( c=='4' ){ sqlite3_snprintf(nTemp-jj, zTemp+jj, "%s", zP4); }else if( c=='X' ){ sqlite3_snprintf(nTemp-jj, zTemp+jj, "%s", pOp->zComment); seenCom = 1; }else{ int v1 = translateP(c, pOp); int v2; sqlite3_snprintf(nTemp-jj, zTemp+jj, "%d", v1); if( strncmp(zSynopsis+ii+1, "@P", 2)==0 ){ ii += 3; jj += sqlite3Strlen30(zTemp+jj); v2 = translateP(zSynopsis[ii], pOp); if( strncmp(zSynopsis+ii+1,"+1",2)==0 ){ ii += 2; v2++; } if( v2>1 ){ sqlite3_snprintf(nTemp-jj, zTemp+jj, "..%d", v1+v2-1); } }else if( strncmp(zSynopsis+ii+1, "..P3", 4)==0 && pOp->p3==0 ){ ii += 4; } } jj += sqlite3Strlen30(zTemp+jj); }else{ zTemp[jj++] = c; } } if( !seenCom && jj<nTemp-5 && pOp->zComment ){ sqlite3_snprintf(nTemp-jj, zTemp+jj, "; %s", pOp->zComment); jj += sqlite3Strlen30(zTemp+jj); } if( jj<nTemp ) zTemp[jj] = 0; }else if( pOp->zComment ){ sqlite3_snprintf(nTemp, zTemp, "%s", pOp->zComment); jj = sqlite3Strlen30(zTemp); }else{ zTemp[0] = 0; jj = 0; } return jj; } #endif /* SQLITE_DEBUG */ #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: 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"); |
︙ | ︙ | |||
1807 1808 1809 1810 1811 1812 1813 | #if VDBE_DISPLAY_P4 /* ** Compute a string that describes the P4 parameter for an opcode. ** Use zTemp for any required temporary buffer space. */ | | | | | | | | < < < < | < > > | | | | | > | > > > > > | > > > | | < < < | > > | 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 | #if VDBE_DISPLAY_P4 /* ** Compute a string that describes the P4 parameter for an opcode. ** Use zTemp for any required temporary buffer space. */ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ char *zP4 = zTemp; StrAccum x; assert( nTemp>=20 ); sqlite3StrAccumInit(&x, 0, zTemp, nTemp, 0); switch( pOp->p4type ){ case P4_KEYINFO: { int j; KeyInfo *pKeyInfo = pOp->p4.pKeyInfo; assert( pKeyInfo->aSortOrder!=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", pKeyInfo->aSortOrder[j] ? "-" : "", 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: { CollSeq *pColl = pOp->p4.pColl; sqlite3_str_appendf(&x, "(%.20s)", pColl->zName); break; } case P4_FUNCDEF: { FuncDef *pDef = pOp->p4.pFunc; sqlite3_str_appendf(&x, "%s(%d)", pDef->zName, pDef->nArg); break; } #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) case P4_FUNCCTX: { FuncDef *pDef = pOp->p4.pCtx->pFunc; sqlite3_str_appendf(&x, "%s(%d)", pDef->zName, pDef->nArg); break; } #endif 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 ){ 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: { int i; int *ai = pOp->p4.ai; int 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, ",%d", ai[i]); } zTemp[0] = '['; sqlite3_str_append(&x, "]", 1); break; } case P4_SUBPROGRAM: { sqlite3_str_appendf(&x, "program"); break; } case P4_DYNBLOB: case P4_ADVANCE: { zTemp[0] = 0; break; } case P4_TABLE: { sqlite3_str_appendf(&x, "%s", pOp->p4.pTab->zName); break; } default: { zP4 = pOp->p4.z; if( zP4==0 ){ zP4 = zTemp; zTemp[0] = 0; } } } sqlite3StrAccumFinish(&x); assert( zP4!=0 ); return zP4; } #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 |
︙ | ︙ | |||
2006 2007 2008 2009 2010 2011 2012 | #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; | | | < < | | | | < | < < < < < < < < < < < < < < < | | | < | | | < | < < < < < | 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 | #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 zPtr[50]; char zCom[100]; static const char *zFormat1 = "%4d %-13s %4d %4d %4d %-13s %.2X %s\n"; if( pOut==0 ) pOut = stdout; zP4 = displayP4(pOp, zPtr, sizeof(zPtr)); #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS displayComment(pOp, zP4, zCom, sizeof(zCom)); #else zCom[0] = 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, pOp->p5, zCom ); fflush(pOut); } #endif /* ** Initialize an array of N Mem element. */ static void initMemArray(Mem *p, int N, sqlite3 *db, u16 flags){ while( (N--)>0 ){ p->db = db; p->flags = flags; p->szMalloc = 0; #ifdef SQLITE_DEBUG p->pScopyFrom = 0; #endif p++; } } /* ** Release an array of N Mem elements */ static void releaseMemArray(Mem *p, int N){ if( p && N ){ Mem *pEnd = &p[N]; sqlite3 *db = p->db; if( db->pnBytesFreed ){ do{ |
︙ | ︙ | |||
2098 2099 2100 2101 2102 2103 2104 2105 | ** 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) ){ | > < < | < | < | < < | 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 | ** 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 ); testcase( p->xDel==sqlite3VdbeFrameMemDel ); if( p->flags&(MEM_Agg|MEM_Dyn) ){ sqlite3VdbeMemRelease(p); }else if( p->szMalloc ){ sqlite3DbFreeNN(db, p->zMalloc); p->szMalloc = 0; } p->flags = MEM_Undefined; }while( (++p)<pEnd ); } } #ifdef SQLITE_DEBUG /* ** Verify that pFrame is a valid VdbeFrame pointer. Return true if it is |
︙ | ︙ | |||
2144 2145 2146 2147 2148 2149 2150 | void sqlite3VdbeFrameMemDel(void *pArg){ VdbeFrame *pFrame = (VdbeFrame*)pArg; assert( sqlite3VdbeFrameIsValid(pFrame) ); pFrame->pParent = pFrame->v->pDelFrame; pFrame->v->pDelFrame = pFrame; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 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 | 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){ int i; Mem *aMem = VdbeFrameMem(p); VdbeCursor **apCsr = (VdbeCursor **)&aMem[p->nChildMem]; assert( sqlite3VdbeFrameIsValid(p) ); for(i=0; i<p->nChildCsr; i++){ sqlite3VdbeFreeCursor(p->v, apCsr[i]); } releaseMemArray(aMem, p->nChildMem); sqlite3VdbeDeleteAuxData(p->v->db, &p->pAuxData, -1, 0); sqlite3DbFree(p->v->db, p); } #ifndef SQLITE_OMIT_EXPLAIN |
︙ | ︙ | |||
2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 | ** ** 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); | > > > < | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > | | > | | > > > > > > > > > > > > | > > > | > > > > > > > > > > > > < | | | > > > | > > > > > > > | > > > | > > > | > > > | > > > > > > > > > | | | > | | > | > > > > | | | > | > | > | > > > < > > | | < | < < < < | | < | 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 | ** ** 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 */ ){ 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 */ 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 *pOp = 0; assert( p->explain ); assert( p->magic==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; } /* 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( 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]; if( pSub->flags&MEM_Blob ){ /* On the first call to sqlite3_step(), pSub will hold a 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; } } while(1){ /* Loop exits via break */ i = p->pc++; if( i>=nRow ){ p->rc = SQLITE_OK; rc = SQLITE_DONE; break; } if( i<p->nOp ){ /* The output line number is small enough that we are still in the ** main program. */ pOp = &p->aOp[i]; }else{ /* We are currently listing subprograms. Figure out which one and ** pick up the appropriate opcode. */ int j; i -= p->nOp; for(j=0; i>=apSub[j]->nOp; j++){ i -= apSub[j]->nOp; } pOp = &apSub[j]->aOp[i]; } /* 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( bListSubprogs && pOp->p4type==P4_SUBPROGRAM ){ int nByte = (nSub+1)*sizeof(SubProgram*); int j; for(j=0; j<nSub; j++){ if( apSub[j]==pOp->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++] = pOp->p4.pProgram; pSub->flags |= MEM_Blob; pSub->n = nSub*sizeof(SubProgram*); nRow += pOp->p4.pProgram->nOp; } } if( p->explain<2 ) break; if( pOp->opcode==OP_Explain ) break; if( pOp->opcode==OP_Init && p->pc>1 ) break; } if( rc==SQLITE_OK ){ if( db->u1.isInterrupted ){ p->rc = SQLITE_INTERRUPT; rc = SQLITE_ERROR; sqlite3VdbeError(p, sqlite3ErrStr(p->rc)); }else{ char *zP4; if( p->explain==1 ){ pMem->flags = MEM_Int; pMem->u.i = i; /* Program counter */ pMem++; pMem->flags = MEM_Static|MEM_Str|MEM_Term; pMem->z = (char*)sqlite3OpcodeName(pOp->opcode); /* Opcode */ assert( pMem->z!=0 ); pMem->n = sqlite3Strlen30(pMem->z); pMem->enc = SQLITE_UTF8; pMem++; } pMem->flags = MEM_Int; pMem->u.i = pOp->p1; /* P1 */ pMem++; pMem->flags = MEM_Int; pMem->u.i = pOp->p2; /* P2 */ pMem++; pMem->flags = MEM_Int; pMem->u.i = pOp->p3; /* P3 */ pMem++; if( sqlite3VdbeMemClearAndResize(pMem, 100) ){ /* P4 */ assert( p->db->mallocFailed ); return SQLITE_ERROR; } pMem->flags = MEM_Str|MEM_Term; zP4 = displayP4(pOp, pMem->z, pMem->szMalloc); if( zP4!=pMem->z ){ pMem->n = 0; sqlite3VdbeMemSetStr(pMem, zP4, -1, SQLITE_UTF8, 0); }else{ assert( pMem->z!=0 ); pMem->n = sqlite3Strlen30(pMem->z); pMem->enc = SQLITE_UTF8; } pMem++; if( p->explain==1 ){ if( sqlite3VdbeMemClearAndResize(pMem, 4) ){ assert( p->db->mallocFailed ); return SQLITE_ERROR; } pMem->flags = MEM_Str|MEM_Term; pMem->n = 2; sqlite3_snprintf(3, pMem->z, "%.2x", pOp->p5); /* P5 */ pMem->enc = SQLITE_UTF8; pMem++; #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS if( sqlite3VdbeMemClearAndResize(pMem, 500) ){ assert( p->db->mallocFailed ); return SQLITE_ERROR; } pMem->flags = MEM_Str|MEM_Term; pMem->n = displayComment(pOp, zP4, pMem->z, 500); pMem->enc = SQLITE_UTF8; #else pMem->flags = MEM_Null; /* Comment */ #endif } p->nResColumn = 8 - 4*(p->explain-1); p->pResultSet = &p->aMem[1]; p->rc = SQLITE_OK; rc = SQLITE_ROW; } } return rc; } #endif /* SQLITE_OMIT_EXPLAIN */ #ifdef SQLITE_DEBUG |
︙ | ︙ | |||
2463 2464 2465 2466 2467 2468 2469 | ** 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 */ | | | | | < < > | | | | 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 | ** 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]; }else{ p->nNeeded += nByte; } } assert( EIGHT_BYTE_ALIGNMENT(pBuf) ); return pBuf; } /* ** Rewind the VDBE back to the beginning in preparation for ** running it. */ void sqlite3VdbeRewind(Vdbe *p){ #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) int i; #endif assert( p!=0 ); assert( p->magic==VDBE_MAGIC_INIT || p->magic==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->magic = VDBE_MAGIC_RUN; #ifdef SQLITE_DEBUG for(i=0; i<p->nMem; i++){ assert( p->aMem[i].db==p->db ); } #endif p->pc = -1; p->rc = SQLITE_OK; p->errorAction = OE_Abort; p->nChange = 0; p->cacheCtr = 1; p->minWriteFileFormat = 255; p->iStatement = 0; p->nFkConstraint = 0; #ifdef VDBE_PROFILE for(i=0; i<p->nOp; i++){ p->aOp[i].cnt = 0; p->aOp[i].cycles = 0; } #endif } /* ** Prepare a virtual machine for execution for the first time after ** creating the virtual machine. This involves things such |
︙ | ︙ | |||
2552 2553 2554 2555 2556 2557 2558 | 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 ); | | < < | | < < < < < | < < < < < < < < < < < < < < > > > > > > > > > > > > | > | < > > > > > > | | > > | | | | | | > > > > | 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 | 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->magic==VDBE_MAGIC_INIT ); assert( pParse==p->pParse ); db = p->db; assert( db->mallocFailed==0 ); nVar = pParse->nVar; nMem = pParse->nMem; nCursor = pParse->nTab; nArg = pParse->nMaxArg; /* Each cursor uses a memory cell. The first cursor (cursor 0) can ** use aMem[0] which is not otherwise used by the VDBE program. Allocate ** space at the end of aMem[] for cursors 1 and greater. ** See also: allocateCursor(). */ nMem += nCursor; if( nCursor==0 && nMem>0 ) nMem++; /* Space for aMem[0] even if not used */ /* Figure out how much reusable memory is available at the end of the ** opcode array. This extra memory will be reallocated for other elements ** of the prepared statement. */ n = ROUND8(sizeof(Op)*p->nOp); /* Bytes of opcode memory used */ x.pSpace = &((u8*)p->aOp)[n]; /* Unused opcode memory */ 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 && nMem<10 ){ nMem = 10; } 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 } } p->pVList = pParse->pVList; pParse->pVList = 0; p->explain = pParse->explain; if( db->mallocFailed ){ p->nVar = 0; p->nCursor = 0; p->nMem = 0; }else{ p->nCursor = nCursor; p->nVar = (ynVar)nVar; initMemArray(p->aVar, nVar, db, MEM_Null); p->nMem = nMem; initMemArray(p->aMem, nMem, db, MEM_Undefined); memset(p->apCsr, 0, nCursor*sizeof(VdbeCursor*)); #ifdef SQLITE_ENABLE_STMT_SCANSTATUS memset(p->anExec, 0, p->nOp*sizeof(i64)); #endif } sqlite3VdbeRewind(p); } /* ** Close a VDBE cursor and release all the resources that cursor ** 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: { if( pCx->isEphemeral ){ if( pCx->pBtx ) sqlite3BtreeClose(pCx->pBtx); /* The pCx->pCursor will be close automatically, if it exists, by ** the call above. */ }else{ 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 ); pVCur->pVtab->nRef--; pModule->xClose(pVCur); break; } #endif } } /* ** Close all cursors in the current frame. */ static void closeCursorsInFrame(Vdbe *p){ if( p->apCsr ){ int i; for(i=0; i<p->nCursor; i++){ VdbeCursor *pC = p->apCsr[i]; if( pC ){ sqlite3VdbeFreeCursor(p, pC); p->apCsr[i] = 0; } } } } /* ** Copy the values stored in the VdbeFrame structure to its Vdbe. This ** is used, for example, when a trigger sub-program is halted to restore ** control to the main program. */ int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){ Vdbe *v = pFrame->v; closeCursorsInFrame(v); #ifdef SQLITE_ENABLE_STMT_SCANSTATUS v->anExec = pFrame->anExec; #endif v->aOp = pFrame->aOp; v->nOp = pFrame->nOp; v->aMem = pFrame->aMem; v->nMem = pFrame->nMem; v->apCsr = pFrame->apCsr; v->nCursor = pFrame->nCursor; v->db->lastRowid = pFrame->lastRowid; |
︙ | ︙ | |||
2735 2736 2737 2738 2739 2740 2741 | for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent); sqlite3VdbeFrameRestore(pFrame); p->pFrame = 0; p->nFrame = 0; } assert( p->nFrame==0 ); closeCursorsInFrame(p); | > | > | 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 | for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent); sqlite3VdbeFrameRestore(pFrame); p->pFrame = 0; p->nFrame = 0; } assert( p->nFrame==0 ); closeCursorsInFrame(p); if( p->aMem ){ releaseMemArray(p->aMem, p->nMem); } while( p->pDelFrame ){ VdbeFrame *pDel = p->pDelFrame; p->pDelFrame = pDel->pParent; sqlite3VdbeFrameDelete(pDel); } /* Delete any auxdata allocations made by the VM */ |
︙ | ︙ | |||
2804 2805 2806 2807 2808 2809 2810 | 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 | | | | | | | | | 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 | 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 master 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 ** master-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 master 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 master 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( sqlite3BtreeIsInTrans(pBt) ){ /* Whether or not a database might need a master journal depends upon ** its journal mode (among other things). This matrix determines which ** journal modes use a master journal and which do not */ static const u8 aMJNeeded[] = { /* DELETE */ 1, /* PERSIST */ 1, /* OFF */ 0, /* TRUNCATE */ 1, /* MEMORY */ 0, /* WAL */ 0 |
︙ | ︙ | |||
2878 2879 2880 2881 2882 2883 2884 | 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 | | | 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 | 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 ** master-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)) |
︙ | ︙ | |||
2912 2913 2914 2915 2916 2917 2918 | } if( rc==SQLITE_OK ){ sqlite3VtabCommit(db); } } /* The complex case - There is a multi-file write-transaction active. | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 | } if( rc==SQLITE_OK ){ sqlite3VtabCommit(db); } } /* The complex case - There is a multi-file write-transaction active. ** This requires a master journal file to ensure the transaction is ** committed atomically. */ #ifndef SQLITE_OMIT_DISKIO else{ sqlite3_vfs *pVfs = db->pVfs; char *zMaster = 0; /* File-name for the master journal */ char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt); sqlite3_file *pMaster = 0; i64 offset = 0; int res; int retryCount = 0; int nMainFile; /* Select a master journal file name */ nMainFile = sqlite3Strlen30(zMainFile); zMaster = sqlite3MPrintf(db, "%s-mjXXXXXX9XXz", zMainFile); if( zMaster==0 ) return SQLITE_NOMEM_BKPT; do { u32 iRandom; if( retryCount ){ if( retryCount>100 ){ sqlite3_log(SQLITE_FULL, "MJ delete: %s", zMaster); sqlite3OsDelete(pVfs, zMaster, 0); break; }else if( retryCount==1 ){ sqlite3_log(SQLITE_FULL, "MJ collide: %s", zMaster); } } retryCount++; sqlite3_randomness(sizeof(iRandom), &iRandom); sqlite3_snprintf(13, &zMaster[nMainFile], "-mj%06X9%02X", (iRandom>>8)&0xffffff, iRandom&0xff); /* The antipenultimate character of the master journal name must ** be "9" to avoid name collisions when using 8+3 filenames. */ assert( zMaster[sqlite3Strlen30(zMaster)-3]=='9' ); sqlite3FileSuffix3(zMainFile, zMaster); rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res); }while( rc==SQLITE_OK && res ); if( rc==SQLITE_OK ){ /* Open the master journal. */ rc = sqlite3OsOpenMalloc(pVfs, zMaster, &pMaster, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE| SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_MASTER_JOURNAL, 0 ); } if( rc!=SQLITE_OK ){ sqlite3DbFree(db, zMaster); return rc; } /* Write the name of each database file in the transaction into the new ** master journal file. If an error occurs at this point close ** and delete the master journal file. All the individual journal files ** still have 'null' as the master 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( sqlite3BtreeIsInTrans(pBt) ){ char const *zFile = sqlite3BtreeGetJournalname(pBt); if( zFile==0 ){ continue; /* Ignore TEMP and :memory: databases */ } assert( zFile[0]!=0 ); rc = sqlite3OsWrite(pMaster, zFile, sqlite3Strlen30(zFile)+1, offset); offset += sqlite3Strlen30(zFile)+1; if( rc!=SQLITE_OK ){ sqlite3OsCloseFree(pMaster); sqlite3OsDelete(pVfs, zMaster, 0); sqlite3DbFree(db, zMaster); return rc; } } } /* Sync the master journal file. If the IOCAP_SEQUENTIAL device ** flag is set this is not required. */ if( 0==(sqlite3OsDeviceCharacteristics(pMaster)&SQLITE_IOCAP_SEQUENTIAL) && SQLITE_OK!=(rc = sqlite3OsSync(pMaster, SQLITE_SYNC_NORMAL)) ){ sqlite3OsCloseFree(pMaster); sqlite3OsDelete(pVfs, zMaster, 0); sqlite3DbFree(db, zMaster); return rc; } /* Sync all the db files involved in the transaction. The same call ** sets the master journal pointer in each individual journal. If ** an error occurs here, do not delete the master journal file. ** ** If the error occurs during the first call to ** sqlite3BtreeCommitPhaseOne(), then there is a chance that the ** master journal file will be orphaned. But we cannot delete it, ** in case the master 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, zMaster); } } sqlite3OsCloseFree(pMaster); assert( rc!=SQLITE_BUSY ); if( rc!=SQLITE_OK ){ sqlite3DbFree(db, zMaster); return rc; } /* Delete the master journal file. This commits the transaction. After ** doing this the directory is synced again before any individual ** transaction files are deleted. */ rc = sqlite3OsDelete(pVfs, zMaster, 1); sqlite3DbFree(db, zMaster); zMaster = 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 |
︙ | ︙ | |||
3082 3083 3084 3085 3086 3087 3088 | p = db->pVdbe; while( p ){ if( sqlite3_stmt_busy((sqlite3_stmt*)p) ){ cnt++; if( p->readOnly==0 ) nWrite++; if( p->bIsReader ) nRead++; } | | | 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 | p = db->pVdbe; while( p ){ if( sqlite3_stmt_busy((sqlite3_stmt*)p) ){ cnt++; if( p->readOnly==0 ) nWrite++; if( p->bIsReader ) nRead++; } p = p->pNext; } assert( cnt==db->nVdbeActive ); assert( nWrite==db->nVdbeWrite ); assert( nRead==db->nVdbeRead ); } #else #define checkActiveVdbeCnt(x) |
︙ | ︙ | |||
3175 3176 3177 3178 3179 3180 3181 | sqlite3 *db = p->db; if( (deferred && (db->nDeferredCons+db->nDeferredImmCons)>0) || (!deferred && p->nFkConstraint>0) ){ p->rc = SQLITE_CONSTRAINT_FOREIGNKEY; p->errorAction = OE_Abort; sqlite3VdbeError(p, "FOREIGN KEY constraint failed"); | < | | | | | 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 | sqlite3 *db = p->db; if( (deferred && (db->nDeferredCons+db->nDeferredImmCons)>0) || (!deferred && p->nFkConstraint>0) ){ p->rc = SQLITE_CONSTRAINT_FOREIGNKEY; p->errorAction = OE_Abort; sqlite3VdbeError(p, "FOREIGN KEY constraint failed"); return SQLITE_ERROR; } return SQLITE_OK; } #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 state of a VM from ** SQLITE_MAGIC_RUN to SQLITE_MAGIC_HALT. It is harmless to ** call this on a VM that is in the SQLITE_MAGIC_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 */ |
︙ | ︙ | |||
3215 3216 3217 3218 3219 3220 3221 | ** 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. */ | | > > | < | | < | < < < < | 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 | ** 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->magic!=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 */ mrc = p->rc & 0xff; isSpecialError = mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR || mrc==SQLITE_INTERRUPT || mrc==SQLITE_FULL; 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 |
︙ | ︙ | |||
3271 3272 3273 3274 3275 3276 3277 | db->autoCommit = 1; p->nChange = 0; } } } /* Check for immediate foreign key violations. */ | | | 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 | db->autoCommit = 1; p->nChange = 0; } } } /* Check for immediate foreign key violations. */ if( p->rc==SQLITE_OK ){ 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 |
︙ | ︙ | |||
3293 3294 3295 3296 3297 3298 3299 | rc = sqlite3VdbeCheckFk(p, 1); if( rc!=SQLITE_OK ){ if( NEVER(p->readOnly) ){ sqlite3VdbeLeave(p); return SQLITE_ERROR; } rc = SQLITE_CONSTRAINT_FOREIGNKEY; | < < < | 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 | 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); } |
︙ | ︙ | |||
3372 3373 3374 3375 3376 3377 3378 | } /* Release the locks */ sqlite3VdbeLeave(p); } /* We have successfully halted and closed the VM. Record this fact. */ | > | | | | | | > | | 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 | } /* Release the locks */ sqlite3VdbeLeave(p); } /* We have successfully halted and closed the VM. Record this fact. */ if( p->pc>=0 ){ 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->magic = 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() |
︙ | ︙ | |||
3427 3428 3429 3430 3431 3432 3433 | sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, SQLITE_TRANSIENT); sqlite3EndBenignMalloc(); db->bBenignMalloc--; }else if( db->pErr ){ sqlite3ValueSetNull(db->pErr); } db->errCode = rc; | < | 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 | sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, SQLITE_TRANSIENT); sqlite3EndBenignMalloc(); db->bBenignMalloc--; }else if( db->pErr ){ sqlite3ValueSetNull(db->pErr); } db->errCode = rc; return rc; } #ifdef SQLITE_ENABLE_SQLLOG /* ** If an SQLITE_CONFIG_SQLLOG hook is registered and the VM has been run, ** invoke it. |
︙ | ︙ | |||
3460 3461 3462 3463 3464 3465 3466 | ** Clean up a VDBE after execution but do not delete the VDBE just yet. ** Write any error messages into *pzErrMsg. Return the result code. ** ** After this routine is run, the VDBE should be ready to be executed ** again. ** ** To look at it another way, this routine resets the state of the | | | | < | > | > > > > | < < | | < | | 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 | ** Clean up a VDBE after execution but do not delete the VDBE just yet. ** Write any error messages into *pzErrMsg. Return the result code. ** ** After this routine is run, the VDBE should be ready to be executed ** again. ** ** To look at it another way, this routine resets the state of the ** virtual machine from VDBE_MAGIC_RUN or VDBE_MAGIC_HALT back to ** VDBE_MAGIC_INIT. */ int sqlite3VdbeReset(Vdbe *p){ #if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) int i; #endif sqlite3 *db; db = p->db; /* If the VM did not run to completion or if it encountered an ** error, then it might not have been halted properly. So halt ** it now. */ sqlite3VdbeHalt(p); /* 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); sqlite3VdbeTransferError(p); 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 sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = 0; p->pResultSet = 0; #ifdef SQLITE_DEBUG p->nWrite = 0; #endif /* Save profiling information from this VDBE run. */ #ifdef VDBE_PROFILE |
︙ | ︙ | |||
3533 3534 3535 3536 3537 3538 3539 | putc(c, out); pc = c; } if( pc!='\n' ) fprintf(out, "\n"); } for(i=0; i<p->nOp; i++){ char zHdr[100]; | < < | | | > < < < | | 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 | putc(c, out); pc = c; } if( pc!='\n' ) fprintf(out, "\n"); } for(i=0; i<p->nOp; i++){ char zHdr[100]; sqlite3_snprintf(sizeof(zHdr), zHdr, "%6u %12llu %8llu ", p->aOp[i].cnt, p->aOp[i].cycles, p->aOp[i].cnt>0 ? p->aOp[i].cycles/p->aOp[i].cnt : 0 ); fprintf(out, "%s", zHdr); sqlite3VdbePrintOp(out, i, &p->aOp[i]); } fclose(out); } } #endif p->magic = 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->magic==VDBE_MAGIC_RUN || p->magic==VDBE_MAGIC_HALT ){ rc = sqlite3VdbeReset(p); assert( (rc & p->db->errMask)==rc ); } sqlite3VdbeDelete(p); return rc; } |
︙ | ︙ | |||
3611 3612 3613 3614 3615 3616 3617 | ** Free all memory associated with the Vdbe passed as the second argument, ** except for object itself, which is preserved. ** ** The difference between this function and sqlite3VdbeDelete() is that ** VdbeDelete() also unlinks the Vdbe from the list of VMs associated with ** the database connection and frees the object itself. */ | | < < | < < | | | > | | 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 | ** Free all memory associated with the Vdbe passed as the second argument, ** except for object itself, which is preserved. ** ** The difference between this function and sqlite3VdbeDelete() is that ** VdbeDelete() also unlinks the Vdbe from the list of VMs associated with ** the database connection and frees the object itself. */ void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){ SubProgram *pSub, *pNext; 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->magic!=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); #ifdef SQLITE_ENABLE_NORMALIZE sqlite3DbFree(db, p->zNormSql); { DblquoteStr *pThis, *pNext; for(pThis=p->pDblStr; pThis; pThis=pNext){ pNext = pThis->pNextStr; sqlite3DbFree(db, pThis); |
︙ | ︙ | |||
3660 3661 3662 3663 3664 3665 3666 | ** Delete an entire VDBE. */ void sqlite3VdbeDelete(Vdbe *p){ sqlite3 *db; assert( p!=0 ); db = p->db; | < < | | > | | | > > > > | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > | | 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 | ** Delete an entire VDBE. */ void sqlite3VdbeDelete(Vdbe *p){ sqlite3 *db; assert( p!=0 ); db = p->db; assert( sqlite3_mutex_held(db->mutex) ); sqlite3VdbeClearObject(db, p); if( p->pPrev ){ p->pPrev->pNext = p->pNext; }else{ assert( db->pVdbe==p ); db->pVdbe = p->pNext; } if( p->pNext ){ p->pNext->pPrev = p->pPrev; } p->magic = 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 = sqlite3BtreeMovetoUnpacked(p->uc.pCursor, 0, 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; return SQLITE_OK; } /* ** Something has moved cursor "p" out of place. Maybe the row it was ** pointed to was deleted out from under it. Or maybe the btree was ** rebalanced. Whatever the cause, try to restore "p" to the place it ** is supposed to be pointing. If the row was deleted out from under the ** cursor, set the cursor to point to a NULL row. */ static int SQLITE_NOINLINE handleMovedCursor(VdbeCursor *p){ int isDifferentRow, rc; assert( p->eCurType==CURTYPE_BTREE ); assert( p->uc.pCursor!=0 ); assert( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ); rc = sqlite3BtreeCursorRestore(p->uc.pCursor, &isDifferentRow); p->cacheStatus = CACHE_STALE; if( isDifferentRow ) p->nullRow = 1; return rc; } /* ** Check to ensure that the cursor is valid. Restore the cursor ** if need be. Return any I/O error from the restore operation. */ int sqlite3VdbeCursorRestore(VdbeCursor *p){ assert( p->eCurType==CURTYPE_BTREE ); if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){ return handleMovedCursor(p); } return SQLITE_OK; } /* ** Make sure the cursor p is ready to read or write the row to which it ** was last positioned. Return an error code if an OOM fault or I/O error ** prevents us from positioning the cursor to its correct position. ** ** If a MoveTo operation is pending on the given cursor, then do that ** 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, int *piCol){ VdbeCursor *p = *pp; assert( p->eCurType==CURTYPE_BTREE || p->eCurType==CURTYPE_PSEUDO ); if( p->deferredMoveto ){ int iMap; if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 ){ *pp = p->pAltCursor; *piCol = iMap - 1; return SQLITE_OK; } return sqlite3VdbeFinishMoveto(p); } if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){ return handleMovedCursor(p); } return SQLITE_OK; } /* ** The following functions: ** ** sqlite3VdbeSerialType() ** sqlite3VdbeSerialTypeLen() ** sqlite3VdbeSerialLen() ** sqlite3VdbeSerialPut() ** sqlite3VdbeSerialGet() ** ** encapsulate the code that serializes values for storage in SQLite ** data and index records. Each serialized value consists of a ** 'serial-type' and a blob of data. The serial type is an 8-byte unsigned ** integer, stored as a varint. ** |
︙ | ︙ | |||
3769 3770 3771 3772 3773 3774 3775 | ** 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. */ | < < < < < < < < < | < < < < < < < < < < < < | | 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 | ** 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; } if( flags&MEM_Int ){ /* 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; 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; 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)); } /* ** 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, /* 10 */ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, /* 20 */ 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, /* 30 */ 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, /* 40 */ 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, /* 50 */ 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, |
︙ | ︙ | |||
3914 3915 3916 3917 3918 3919 3920 | ** the necessary byte swapping is carried out using a 64-bit integer ** rather than a 64-bit float. Frank assures us that the code here ** works for him. We, the developers, have no way to independently ** verify this, but Frank seems to know what he is talking about ** so we trust him. */ #ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT | | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | 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 | ** the necessary byte swapping is carried out using a 64-bit integer ** rather than a 64-bit float. Frank assures us that the code here ** works for him. We, the developers, have no way to independently ** verify this, but Frank seems to know what he is talking about ** so we trust him. */ #ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT static u64 floatSwap(u64 in){ union { u64 r; u32 i[2]; } u; u32 t; u.r = in; t = u.i[0]; u.i[0] = u.i[1]; u.i[1] = t; return u.r; } # define swapMixedEndianFloat(X) X = floatSwap(X) #else # define swapMixedEndianFloat(X) #endif /* ** Write the serialized data blob for the value stored in pMem into ** buf. It is assumed that the caller has allocated sufficient space. ** Return the number of bytes written. ** ** nBuf is the amount of space left in buf[]. The caller is responsible ** for allocating enough space to buf[] to hold the entire field, exclusive ** of the pMem->u.nZero bytes for a MEM_Zero value. ** ** Return the number of bytes actually written into buf[]. The number ** of bytes in the zero-filled tail is included in the return value only ** if those bytes were zeroed in buf[]. */ u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){ u32 len; /* Integer and Real */ if( serial_type<=7 && serial_type>0 ){ u64 v; u32 i; if( serial_type==7 ){ assert( sizeof(v)==sizeof(pMem->u.r) ); memcpy(&v, &pMem->u.r, sizeof(v)); swapMixedEndianFloat(v); }else{ v = pMem->u.i; } len = i = sqlite3SmallTypeSizes[serial_type]; assert( i>0 ); do{ buf[--i] = (u8)(v&0xFF); v >>= 8; }while( i ); return len; } /* String or blob */ if( serial_type>=12 ){ assert( pMem->n + ((pMem->flags & MEM_Zero)?pMem->u.nZero:0) == (int)sqlite3VdbeSerialTypeLen(serial_type) ); len = pMem->n; if( len>0 ) memcpy(buf, pMem->z, len); return len; } /* NULL or constants 0 or 1 */ return 0; } /* Input "x" is a sequence of unsigned characters that represent a ** big-endian integer. Return the equivalent native integer */ #define ONE_BYTE_INT(x) ((i8)(x)[0]) #define TWO_BYTE_INT(x) (256*(i8)((x)[0])|(x)[1]) #define THREE_BYTE_INT(x) (65536*(i8)((x)[0])|((x)[1]<<8)|(x)[2]) #define FOUR_BYTE_UINT(x) (((u32)(x)[0]<<24)|((x)[1]<<16)|((x)[2]<<8)|(x)[3]) #define FOUR_BYTE_INT(x) (16777216*(i8)((x)[0])|((x)[1]<<16)|((x)[2]<<8)|(x)[3]) /* ** Deserialize the data blob pointed to by buf as serial type serial_type ** 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 SQLITE_NOINLINE 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; |
︙ | ︙ | |||
3980 3981 3982 3983 3984 3985 3986 | 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)); | | > | | | | | | | | | < | | | | | | | 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 | 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 = sqlite3IsNaN(pMem->u.r) ? 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 */ ){ switch( serial_type ){ case 10: { /* Internal use only: NULL with virtual table ** UPDATE no-change flag set */ pMem->flags = MEM_Null|MEM_Zero; pMem->n = 0; pMem->u.nZero = 0; break; } case 11: /* Reserved for future use */ case 0: { /* Null */ /* EVIDENCE-OF: R-24078-09375 Value is a NULL. */ pMem->flags = MEM_Null; break; } case 1: { /* EVIDENCE-OF: R-44885-25196 Value is an 8-bit twos-complement ** integer. */ pMem->u.i = ONE_BYTE_INT(buf); pMem->flags = MEM_Int; testcase( pMem->u.i<0 ); return 1; } case 2: { /* 2-byte signed integer */ /* EVIDENCE-OF: R-49794-35026 Value is a big-endian 16-bit ** twos-complement integer. */ pMem->u.i = TWO_BYTE_INT(buf); pMem->flags = MEM_Int; testcase( pMem->u.i<0 ); return 2; } case 3: { /* 3-byte signed integer */ /* EVIDENCE-OF: R-37839-54301 Value is a big-endian 24-bit ** twos-complement integer. */ pMem->u.i = THREE_BYTE_INT(buf); pMem->flags = MEM_Int; testcase( pMem->u.i<0 ); return 3; } case 4: { /* 4-byte signed integer */ /* EVIDENCE-OF: R-01849-26079 Value is a big-endian 32-bit ** twos-complement integer. */ pMem->u.i = FOUR_BYTE_INT(buf); #ifdef __HP_cc /* Work around a sign-extension bug in the HP compiler for HP/UX */ if( buf[0]&0x80 ) pMem->u.i |= 0xffffffff80000000LL; #endif pMem->flags = MEM_Int; testcase( pMem->u.i<0 ); return 4; } case 5: { /* 6-byte signed integer */ /* EVIDENCE-OF: R-50385-09674 Value is a big-endian 48-bit ** twos-complement integer. */ pMem->u.i = FOUR_BYTE_UINT(buf+2) + (((i64)1)<<32)*TWO_BYTE_INT(buf); pMem->flags = MEM_Int; testcase( pMem->u.i<0 ); return 6; } case 6: /* 8-byte signed integer */ case 7: { /* IEEE floating point */ /* These use local variables, so do them in a separate routine ** to avoid having to move the frame pointer in the common case */ return serialGet(buf,serial_type,pMem); } case 8: /* Integer 0 */ case 9: { /* Integer 1 */ /* EVIDENCE-OF: R-12976-22893 Value is the integer 0. */ /* EVIDENCE-OF: R-18143-12121 Value is the integer 1. */ pMem->u.i = serial_type-8; pMem->flags = MEM_Int; return 0; } default: { /* EVIDENCE-OF: R-14606-31564 Value is a BLOB that is (N-12)/2 bytes in ** length. ** EVIDENCE-OF: R-28401-00140 Value is a string in the text encoding and ** (N-13)/2 bytes in length. */ static const u16 aFlag[] = { MEM_Blob|MEM_Ephem, MEM_Str|MEM_Ephem }; pMem->z = (char *)buf; pMem->n = (serial_type-12)/2; pMem->flags = aFlag[serial_type&1]; return pMem->n; } } return 0; } /* ** This routine is used to allocate sufficient space for an UnpackedRecord ** structure large enough to be used with sqlite3VdbeRecordUnpack() if ** the first argument is a pointer to KeyInfo structure pKeyInfo. ** ** The space is either allocated using sqlite3DbMallocRaw() or from within ** the unaligned buffer passed via the second and third arguments (presumably ** stack space). If the former, then *ppFree is set to a pointer that should ** be eventually freed by the caller using sqlite3DbFree(). Or, if the ** allocation comes from the pSpace/szSpace buffer, *ppFree is set to NULL ** before returning. ** ** If an OOM error occurs, NULL is returned. */ UnpackedRecord *sqlite3VdbeAllocUnpackedRecord( KeyInfo *pKeyInfo /* Description of the record */ ){ 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->aSortOrder!=0 ); p->pKeyInfo = pKeyInfo; p->nField = pKeyInfo->nKeyField + 1; return p; } /* ** Given the nKey-byte encoding of a record in pKey[], populate the |
︙ | ︙ | |||
4136 4137 4138 4139 4140 4141 4142 | 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; | | < | 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 | 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 |
︙ | ︙ | |||
4198 4199 4200 4201 4202 4203 4204 | */ /* 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 ); | | | 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 | */ /* 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->aSortOrder!=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 ); |
︙ | ︙ | |||
4221 4222 4223 4224 4225 4226 4227 | && d1+(u64)sqlite3VdbeSerialTypeLen(serial_type1)>(u64)nKey1 ){ break; } /* Extract the values to be compared. */ | | < < < < < < | | 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 | && 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->aSortOrder[i] ){ rc = -rc; /* Invert the result for DESC sort order. */ } goto debugCompareEnd; } i++; }while( idx1<szHdr1 && i<pPKey2->nField ); |
︙ | ︙ | |||
4333 4334 4335 4336 4337 4338 4339 | v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc); if( (v1==0 || v2==0) ){ if( prcErr ) *prcErr = SQLITE_NOMEM_BKPT; rc = 0; }else{ rc = pColl->xCmp(pColl->pUser, c1.n, v1, c2.n, v2); } | | | | 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 | v2 = sqlite3ValueText((sqlite3_value*)&c2, pColl->enc); if( (v1==0 || v2==0) ){ if( prcErr ) *prcErr = SQLITE_NOMEM_BKPT; rc = 0; }else{ rc = pColl->xCmp(pColl->pUser, c1.n, v1, c2.n, v2); } sqlite3VdbeMemRelease(&c1); sqlite3VdbeMemRelease(&c2); return rc; } } /* ** The input pBlob is guaranteed to be a Blob that is not marked ** with MEM_Zero. Return true if it could be a zero-blob. |
︙ | ︙ | |||
4389 4390 4391 4392 4393 4394 4395 | } /* ** 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). */ | | < < < | | | 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 | } /* ** 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). */ static int sqlite3IntFloatCompare(i64 i, double r){ if( sizeof(LONGDOUBLE_TYPE)>8 ){ LONGDOUBLE_TYPE x = (LONGDOUBLE_TYPE)i; if( x<r ) return -1; if( x>r ) return +1; return 0; }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; |
︙ | ︙ | |||
4440 4441 4442 4443 4444 4445 4446 | */ if( combined_flags&MEM_Null ){ return (f2&MEM_Null) - (f1&MEM_Null); } /* At least one of the two values is a number */ | | < < < | < < < | < < < < < < | < | 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 | */ 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) ){ if( (f1 & f2 & MEM_Int)!=0 ){ 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)!=0 ){ if( (f2&MEM_Real)!=0 ){ return sqlite3IntFloatCompare(pMem1->u.i, pMem2->u.r); }else{ return -1; } } if( (f1&MEM_Real)!=0 ){ if( (f2&MEM_Int)!=0 ){ return -sqlite3IntFloatCompare(pMem2->u.i, pMem1->u.r); }else{ return -1; } } return +1; } |
︙ | ︙ | |||
4595 4596 4597 4598 4599 4600 4601 | const unsigned char *aKey1 = (const unsigned char *)pKey1; Mem mem1; /* If bSkip is true, then the caller has already determined that the first ** two elements in the keys are equal. Fix the various stack variables so ** that this routine begins comparing at the second field. */ if( bSkip ){ | | < < < | < < | < < < | < > < | < | | 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 | const unsigned char *aKey1 = (const unsigned char *)pKey1; Mem mem1; /* If bSkip is true, then the caller has already determined that the first ** two elements in the keys are equal. Fix the various stack variables so ** that this routine begins comparing at the second field. */ if( bSkip ){ u32 s1; idx1 = 1 + getVarint32(&aKey1[1], s1); 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->aSortOrder!=0 ); assert( pPKey2->pKeyInfo->nKeyField>0 ); assert( idx1<=szHdr1 || CORRUPT_DB ); do{ u32 serial_type; /* RHS is an integer */ if( pRhs->flags & MEM_Int ){ 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 ){ sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1); rc = -sqlite3IntFloatCompare(pRhs->u.i, mem1.u.r); }else{ i64 lhs = vdbeRecordDecodeInt(serial_type, &aKey1[d1]); |
︙ | ︙ | |||
4660 4661 4662 4663 4664 4665 4666 | else if( pRhs->flags & MEM_Real ){ serial_type = aKey1[idx1]; if( serial_type>=10 ){ /* Serial types 12 or greater are strings and blobs (greater than ** numbers). Types 10 and 11 are currently "reserved for future ** use", so it doesn't really matter what the results of comparing ** them to numberic values are. */ | | | | 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 | else if( pRhs->flags & MEM_Real ){ serial_type = aKey1[idx1]; if( serial_type>=10 ){ /* Serial types 12 or greater are strings and blobs (greater than ** numbers). Types 10 and 11 are currently "reserved for future ** use", so it doesn't really matter what the results of comparing ** them to numberic values are. */ rc = +1; }else if( serial_type==0 ){ rc = -1; }else{ sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1); if( serial_type==7 ){ if( mem1.u.r<pRhs->u.r ){ rc = -1; }else if( mem1.u.r>pRhs->u.r ){ rc = +1; } }else{ rc = sqlite3IntFloatCompare(mem1.u.i, pRhs->u.r); } } } /* RHS is a string */ else if( pRhs->flags & MEM_Str ){ getVarint32(&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; |
︙ | ︙ | |||
4713 4714 4715 4716 4717 4718 4719 | } } } /* RHS is a blob */ else if( pRhs->flags & MEM_Blob ){ assert( (pRhs->flags & MEM_Zero)==0 || pRhs->n==0 ); | | | 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 | } } } /* RHS is a blob */ else if( pRhs->flags & MEM_Blob ){ assert( (pRhs->flags & MEM_Zero)==0 || pRhs->n==0 ); getVarint32(&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 ); |
︙ | ︙ | |||
4741 4742 4743 4744 4745 4746 4747 | } } } /* RHS is null */ else{ serial_type = aKey1[idx1]; | | | < < < < < | < < | < < < < | 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 | } } } /* RHS is null */ else{ serial_type = aKey1[idx1]; rc = (serial_type!=0); } if( rc!=0 ){ if( pPKey2->pKeyInfo->aSortOrder[i] ){ rc = -rc; } assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, rc) ); assert( mem1.szMalloc==0 ); /* See comment below */ return rc; } i++; if( i==pPKey2->nField ) break; pRhs++; d1 += sqlite3VdbeSerialTypeLen(serial_type); idx1 += sqlite3VarintLen(serial_type); }while( idx1<(unsigned)szHdr1 && d1<=(unsigned)nKey1 ); /* No memory allocation is ever used on mem1. Prove this using ** the following assert(). If the assert() fails, it indicates a ** memory leak and a need to call sqlite3VdbeMemRelease(&mem1). */ assert( mem1.szMalloc==0 ); /* rc==0 here means that one or both of the keys ran out of fields and |
︙ | ︙ | |||
4871 4872 4873 4874 4875 4876 4877 | case 0: case 7: return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2); default: return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2); } | < | | 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 | case 0: case 7: return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2); default: return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2); } v = pPKey2->aMem[0].u.i; if( v>lhs ){ res = pPKey2->r1; }else if( v<lhs ){ res = pPKey2->r2; }else if( pPKey2->nField>1 ){ /* The first fields of the two keys are equal. Compare the trailing ** fields. */ |
︙ | ︙ | |||
4907 4908 4909 4910 4911 4912 4913 | UnpackedRecord *pPKey2 /* Right key */ ){ const u8 *aKey1 = (const u8*)pKey1; int serial_type; int res; assert( pPKey2->aMem[0].flags & MEM_Str ); | < < < | < < < < < < | | | < < < < | > > > > | 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 | UnpackedRecord *pPKey2 /* Right key */ ){ const u8 *aKey1 = (const u8*)pKey1; int serial_type; int res; assert( pPKey2->aMem[0].flags & MEM_Str ); vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo); getVarint32(&aKey1[1], 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 = 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; } }else if( res>0 ){ res = pPKey2->r2; }else{ res = pPKey2->r1; } } assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, res) || CORRUPT_DB || pPKey2->pKeyInfo->db->mallocFailed ); |
︙ | ︙ | |||
4984 4985 4986 4987 4988 4989 4990 | ** 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; | | < < < < < | < < < | 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 | ** 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->aSortOrder[0] ){ 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_Null|MEM_Blob))==0 && p->pKeyInfo->aColl[0]==0 ){ assert( flags & MEM_Str ); return vdbeRecordCompareString; } } return sqlite3VdbeRecordCompare; } |
︙ | ︙ | |||
5041 5042 5043 5044 5045 5046 5047 | */ 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); | | | | | | | | 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 | */ 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 = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, &m); if( rc ){ return rc; } /* The index entry must begin with a header size */ (void)getVarint32((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. */ (void)getVarint32((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 ); testcase( typeRowid==9 ); if( unlikely(typeRowid<1 || typeRowid>9 || typeRowid==7) ){ goto idx_rowid_corruption; } lenRowid = sqlite3SmallTypeSizes[typeRowid]; testcase( (u32)m.n==szHdr+lenRowid ); if( unlikely((u32)m.n<szHdr+lenRowid) ){ goto idx_rowid_corruption; } /* Fetch the integer off the end of the index record */ sqlite3VdbeSerialGet((u8*)&m.z[m.n-lenRowid], typeRowid, &v); *rowid = v.u.i; sqlite3VdbeMemRelease(&m); return SQLITE_OK; /* Jump here if database corruption is detected after m has been ** allocated. Free the m object and return SQLITE_CORRUPT. */ idx_rowid_corruption: testcase( m.szMalloc!=0 ); sqlite3VdbeMemRelease(&m); return SQLITE_CORRUPT_BKPT; } /* ** Compare the key of the index entry that cursor pC is pointing to against ** the key string in pUnpacked. Write into *pRes a number ** that is negative, zero, or positive if pC is less than, equal to, |
︙ | ︙ | |||
5123 5124 5125 5126 5127 5128 5129 | /* 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); | | | | | 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 | /* 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 = sqlite3VdbeMemFromBtree(pCur, 0, (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, int 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 |
︙ | ︙ | |||
5170 5171 5172 5173 5174 5175 5176 | ** ** Internally, this function just sets the Vdbe.expired flag on all ** prepared statements. The flag is set to 1 for an immediate expiration ** and set to 2 for an advisory expiration. */ void sqlite3ExpirePreparedStatements(sqlite3 *db, int iCode){ Vdbe *p; | | | 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 | ** ** Internally, this function just sets the Vdbe.expired flag on all ** prepared statements. The flag is set to 1 for an immediate expiration ** and set to 2 for an advisory expiration. */ void sqlite3ExpirePreparedStatements(sqlite3 *db, int iCode){ Vdbe *p; for(p = db->pVdbe; p; p=p->pNext){ p->expired = iCode+1; } } /* ** Return the database associated with the Vdbe. */ |
︙ | ︙ | |||
5239 5240 5241 5242 5243 5244 5245 | ** ** 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){ | < | < | < < < < < < < < < < < | > | | 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 | ** ** 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){ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 if( pCtx->pVdbe==0 ) return 1; #endif if( pCtx->pVdbe->aOp[pCtx->iOp].opcode==OP_PureFunc ){ sqlite3_result_error(pCtx, "non-deterministic function in index expression or CHECK constraint", -1); return 0; } return 1; } #ifndef SQLITE_OMIT_VIRTUALTABLE /* |
︙ | ︙ | |||
5291 5292 5293 5294 5295 5296 5297 | ** with the memory cells in the p->aMem[] array. Also free the UnpackedRecord ** structure itself, using sqlite3DbFree(). ** ** This function is used to free UnpackedRecord structures allocated by ** the vdbeUnpackRecord() function found in vdbeapi.c. */ static void vdbeFreeUnpacked(sqlite3 *db, int nField, UnpackedRecord *p){ | < | | | < < < | < | | 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 | ** with the memory cells in the p->aMem[] array. Also free the UnpackedRecord ** structure itself, using sqlite3DbFree(). ** ** This function is used to free UnpackedRecord structures allocated by ** the vdbeUnpackRecord() function found in vdbeapi.c. */ static void vdbeFreeUnpacked(sqlite3 *db, int nField, UnpackedRecord *p){ if( p ){ int i; for(i=0; i<nField; i++){ Mem *pMem = &p->aMem[i]; if( pMem->zMalloc ) sqlite3VdbeMemRelease(pMem); } sqlite3DbFreeNN(db, p); } } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* ** Invoke the pre-update hook. If this is an UPDATE or DELETE pre-update call, ** then cursor passed as the second argument should point to the row about ** to be update or deleted. If the application calls sqlite3_preupdate_old(), ** the required value will be read from the row the cursor points to. */ 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 */ ){ 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->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.aSortOrder = (u8*)&fakeSortOrder; preupdate.iKey1 = iKey1; preupdate.iKey2 = iKey2; preupdate.pTab = pTab; 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); if( preupdate.aNew ){ int i; for(i=0; i<pCsr->nField; i++){ sqlite3VdbeMemRelease(&preupdate.aNew[i]); } sqlite3DbFreeNN(db, preupdate.aNew); } } #endif /* SQLITE_ENABLE_PREUPDATE_HOOK */ |
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 | 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 = 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; |
︙ | ︙ | |||
148 149 150 151 152 153 154 | } #endif wrFlag = !!wrFlag; /* wrFlag = (wrFlag ? 1 : 0); */ sqlite3_mutex_enter(db->mutex); pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob)); | < > | > | | | 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 | } #endif wrFlag = !!wrFlag; /* wrFlag = (wrFlag ? 1 : 0); */ sqlite3_mutex_enter(db->mutex); pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob)); do { memset(&sParse, 0, sizeof(Parse)); if( !pBlob ) goto blob_open_out; sParse.db = db; sqlite3DbFree(db, zErr); zErr = 0; sqlite3BtreeEnterAll(db); pTab = sqlite3LocateTable(&sParse, 0, zTable, zDb); if( pTab && IsVirtual(pTab) ){ pTab = 0; 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 && pTab->pSelect ){ 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].zName, zColumn)==0 ){ break; } } if( iCol==pTab->nCol ){ sqlite3DbFree(db, zErr); zErr = sqlite3MPrintf(db, "no such column: \"%s\"", zColumn); rc = SQLITE_ERROR; |
︙ | ︙ | |||
210 211 212 213 214 215 216 | #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; | < | | 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 | #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; for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){ int j; for(j=0; j<pFKey->nCol; j++){ if( pFKey->aCol[j].iFrom==iCol ){ zFault = "foreign key"; } } } |
︙ | ︙ | |||
327 328 329 330 331 332 333 | pBlob->iCol = iCol; pBlob->db = db; sqlite3BtreeLeaveAll(db); if( db->mallocFailed ){ goto blob_open_out; } rc = blobSeekToRow(pBlob, iRow, &zErr); | | < < | < > < | 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 | pBlob->iCol = iCol; pBlob->db = db; sqlite3BtreeLeaveAll(db); if( db->mallocFailed ){ goto blob_open_out; } rc = blobSeekToRow(pBlob, iRow, &zErr); } while( (++nAttempt)<SQLITE_MAX_SCHEMA_RETRY && rc==SQLITE_SCHEMA ); blob_open_out: if( rc==SQLITE_OK && db->mallocFailed==0 ){ *ppBlob = (sqlite3_blob *)pBlob; }else{ if( pBlob && pBlob->pStmt ) sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt); sqlite3DbFree(db, pBlob); } sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr); sqlite3DbFree(db, zErr); sqlite3ParserReset(&sParse); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; } /* ** Close a blob handle that was previously created using ** sqlite3_blob_open(). */ 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); rc = sqlite3_finalize(p->pStmt); sqlite3DbFree(db, p); sqlite3_mutex_leave(db->mutex); }else{ rc = SQLITE_OK; } return rc; } /* |
︙ | ︙ | |||
420 421 422 423 424 425 426 | ** 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); | < < | | 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 | ** 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( v, v->apCsr[0], SQLITE_DELETE, p->zDb, p->pTab, iKey, -1 ); } #endif rc = xCall(p->pCsr, iOffset+p->iOffset, n, z); sqlite3BtreeLeaveCursor(p->pCsr); if( rc==SQLITE_ABORT ){ |
︙ | ︙ | |||
494 495 496 497 498 499 500 | 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; | < | 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 ); } |
︙ | ︙ |
Changes to src/vdbemem.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** 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" | < < < < < | | | 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 | ** 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 ); /* Cannot be both MEM_Int and MEM_Real at the same time */ assert( (p->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real) ); if( p->flags & MEM_Null ){ /* Cannot be both MEM_Null and some other type */ assert( (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob|MEM_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 |
︙ | ︙ | |||
71 72 73 74 75 76 77 | }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 | < < | | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | }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->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 |
︙ | ︙ | |||
95 96 97 98 99 100 101 | ((p->flags&MEM_Static)!=0 ? 1 : 0) == 1 ); } return 1; } #endif | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | < > | < | < < < | < < < > < < < | 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 | ((p->flags&MEM_Static)!=0 ? 1 : 0) == 1 ); } return 1; } #endif #ifdef SQLITE_DEBUG /* ** Check that string value of pMem agrees with its integer or real value. ** ** 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 sqlite3VdbeMemConsistentDualRep(Mem *p){ char zBuf[100]; char *z; int i, j, incr; if( (p->flags & MEM_Str)==0 ) return 1; if( (p->flags & (MEM_Int|MEM_Real))==0 ) return 1; if( p->flags & MEM_Int ){ sqlite3_snprintf(sizeof(zBuf),zBuf,"%lld",p->u.i); }else{ sqlite3_snprintf(sizeof(zBuf),zBuf,"%!.15g",p->u.r); } z = p->z; i = j = 0; incr = 1; if( p->enc!=SQLITE_UTF8 ){ incr = 2; if( p->enc==SQLITE_UTF16BE ) z++; } |
︙ | ︙ | |||
199 200 201 202 203 204 205 | ** 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 | < | < < < < | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | ** 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) ); #ifdef SQLITE_OMIT_UTF16 return SQLITE_ERROR; #else |
︙ | ︙ | |||
245 246 247 248 249 250 251 | /* 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 | < < | < | < < < < < | 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | /* 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->szMalloc==sqlite3DbMallocSize(pMem->db, pMem->zMalloc) ); if( pMem->szMalloc>0 && bPreserve && pMem->z==pMem->zMalloc ){ pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n); bPreserve = 0; }else{ if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc); pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n); } if( pMem->zMalloc==0 ){ sqlite3VdbeMemSetNull(pMem); |
︙ | ︙ | |||
291 292 293 294 295 296 297 | /* ** 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 | | | | < < < < < | < < | 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 | /* ** 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, 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); return SQLITE_OK; } /* ** It is already known that pMem contains an unterminated string. ** Add the zero terminator. */ static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){ if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){ return SQLITE_NOMEM_BKPT; } pMem->z[pMem->n] = 0; pMem->z[pMem->n+1] = 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->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; |
︙ | ︙ | |||
361 362 363 364 365 366 367 | /* ** 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; | < < < < | | | | | > < | | | > > > > > > > | > > > > | | < < | < > < | > > > < | 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 | /* ** 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->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; } 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->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. Numbers ** are converted using sqlite3_snprintf(). Converting a BLOB to a string ** is a no-op. ** ** Existing representations MEM_Int and MEM_Real 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){ int fg = pMem->flags; const int nByte = 32; assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( !(fg&MEM_Zero) ); assert( !(fg&(MEM_Str|MEM_Blob)) ); assert( fg&(MEM_Int|MEM_Real) ); assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); if( sqlite3VdbeMemClearAndResize(pMem, nByte) ){ pMem->enc = 0; return SQLITE_NOMEM_BKPT; } /* For a Real or Integer, use sqlite3_snprintf() to produce the UTF-8 ** string representation of the value. Then, if the required encoding ** is UTF-16le or UTF-16be do a translation. ** ** FIX ME: It would be better if sqlite3_snprintf() could do UTF-16. */ if( fg & MEM_Int ){ sqlite3_snprintf(nByte, pMem->z, "%lld", pMem->u.i); }else{ assert( fg & MEM_Real ); sqlite3_snprintf(nByte, pMem->z, "%!.15g", pMem->u.r); } 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); 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( 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; ctx.pOut = &t; ctx.pMem = pMem; ctx.pFunc = pFunc; pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */ assert( (pMem->flags & MEM_Dyn)==0 ); if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc); memcpy(pMem, &t, sizeof(t)); return ctx.isError; } /* ** Memory cell pAccum contains the context of an aggregate function. ** This routine calls the xValue method for that function and stores ** the results in memory cell pMem. ** ** 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; Mem t; 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)); memset(&t, 0, sizeof(t)); t.flags = MEM_Null; t.db = pAccum->db; sqlite3VdbeMemSetNull(pOut); ctx.pOut = pOut; ctx.pMem = pAccum; ctx.pFunc = pFunc; pFunc->xValue(&ctx); return ctx.isError; } #endif /* SQLITE_OMIT_WINDOWFUNC */ /* ** If the memory cell contains a value that must be freed by |
︙ | ︙ | |||
562 563 564 565 566 567 568 | void sqlite3VdbeMemRelease(Mem *p){ assert( sqlite3VdbeCheckMemInvariants(p) ); if( VdbeMemDynamic(p) || p->szMalloc ){ vdbeMemClear(p); } } | < < < < < < < < | 500 501 502 503 504 505 506 507 508 509 510 511 512 513 | void sqlite3VdbeMemRelease(Mem *p){ assert( sqlite3VdbeCheckMemInvariants(p) ); if( VdbeMemDynamic(p) || p->szMalloc ){ vdbeMemClear(p); } } /* ** Convert a 64-bit IEEE double into a 64-bit signed integer. ** If the double is out of range of a 64-bit signed integer then ** return the closest available 64-bit signed integer. */ static SQLITE_NOINLINE i64 doubleToInt64(double r){ #ifdef SQLITE_OMIT_FLOATING_POINT |
︙ | ︙ | |||
611 612 613 614 615 616 617 | ** a floating-point then the value returned is the integer part. ** If pMem is a string or blob, then we make an attempt to convert ** it into an integer and return that. If pMem represents an ** an SQL-NULL value, return 0. ** ** If pMem represents a string value, its encoding might be changed. */ | | | < < | | > < | < | < | | | | < < < | | | | | | | | | | | | | | < < < < < | < | < < < < < < < < < < < | < < < < < | < > > > > > | < | < | | | | | | > | | | | 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 | ** a floating-point then the value returned is the integer part. ** If pMem is a string or blob, then we make an attempt to convert ** it into an integer and return that. If pMem represents an ** an SQL-NULL value, return 0. ** ** If pMem represents a string value, its encoding might be changed. */ 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; if( flags & MEM_Int ){ return pMem->u.i; }else if( flags & MEM_Real ){ return doubleToInt64(pMem->u.r); }else if( flags & (MEM_Str|MEM_Blob) ){ assert( pMem->z || pMem->n==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->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 ){ 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){ if( pMem->flags & MEM_Int ) 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->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); /* Only mark the value as an integer if ** ** (1) the round-trip conversion real->int->real is a no-op, and ** (2) The integer is neither the largest nor the smallest ** possible integer (ticket #3922) ** ** The second and third terms in the following conditional enforces ** the second condition under the assumption that addition overflow causes ** values to wrap around. */ if( pMem->u.r==ix && ix>SMALLEST_INT64 && ix<LARGEST_INT64 ){ pMem->u.i = ix; MemSetTypeFlag(pMem, MEM_Int); } } /* ** 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. */ static int sqlite3RealSameAsInt(double r1, sqlite3_int64 i){ double r2 = (double)i; return memcmp(&r1, &r2, sizeof(r1))==0; } /* ** Convert pMem so that it has types MEM_Real or MEM_Int or both. ** Invalidate any prior representations. ** ** Every effort is made to force the conversion, even if the input ** is a string that does not look completely like a number. Convert ** as much of the string as we can and ignore the rest. */ int sqlite3VdbeMemNumerify(Mem *pMem){ if( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ){ int rc; assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); rc = sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc); if( rc==0 ){ MemSetTypeFlag(pMem, MEM_Int); }else{ i64 i = pMem->u.i; sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc); if( rc==1 && sqlite3RealSameAsInt(pMem->u.r, i) ){ pMem->u.i = i; MemSetTypeFlag(pMem, MEM_Int); }else{ MemSetTypeFlag(pMem, MEM_Real); } } } assert( (pMem->flags & (MEM_Int|MEM_Real|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. */ void sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){ if( pMem->flags & MEM_Null ) return; 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{ |
︙ | ︙ | |||
833 834 835 836 837 838 839 | } 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 ); | | | < < | 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 | } 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_Blob|MEM_Zero); break; } } } /* ** Initialize bulk memory to be a consistent Mem object. ** ** The minimum amount of initialization feasible is performed. */ |
︙ | ︙ | |||
881 882 883 884 885 886 887 | sqlite3VdbeMemSetNull((Mem*)p); } /* ** Delete any previous value and set the value to be a BLOB of length ** n containing all zeros. */ | < < < < < < < < < < < < < < < < | 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){ |
︙ | ︙ | |||
945 946 947 948 949 950 951 | void sqlite3VdbeMemSetPointer( Mem *pMem, void *pPtr, const char *zPType, void (*xDestructor)(void*) ){ assert( pMem->flags==MEM_Null ); | < | 831 832 833 834 835 836 837 838 839 840 841 842 843 844 | void sqlite3VdbeMemSetPointer( Mem *pMem, void *pPtr, const char *zPType, void (*xDestructor)(void*) ){ assert( pMem->flags==MEM_Null ); pMem->u.zPType = zPType ? zPType : ""; pMem->z = pPtr; pMem->flags = MEM_Null|MEM_Dyn|MEM_Subtype|MEM_Term; pMem->eSubtype = 'p'; pMem->xDel = xDestructor ? xDestructor : sqlite3NoopDestructor; } |
︙ | ︙ | |||
1021 1022 1023 1024 1025 1026 1027 | #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. ** | | | | < < < < < | | | > > > > | 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 | #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 make sure shallow ** copies are not misused. */ void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){ int i; Mem *pX; for(i=0, pX=pVdbe->aMem; i<pVdbe->nMem; i++, pX++){ if( pX->pScopyFrom==pMem ){ /* If pX is marked as a shallow copy of pMem, then 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. */ u16 mFlags = pMem->flags & pX->flags & pX->mScopyFlags; assert( (mFlags&MEM_Int)==0 || pMem->u.i==pX->u.i ); assert( (mFlags&MEM_Real)==0 || pMem->u.r==pX->u.r ); assert( (mFlags&MEM_Str)==0 || (pMem->n==pX->n && pMem->z==pX->z) ); assert( (mFlags&MEM_Blob)==0 || sqlite3BlobCompare(pMem,pX)==0 ); /* 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). */ |
︙ | ︙ | |||
1128 1129 1130 1131 1132 1133 1134 | ** pointer copied. ** ** If the string is too large (if it exceeds the SQLITE_LIMIT_LENGTH ** size limit) then no memory allocation occurs. If the string can be ** 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. | < < < < < < < | | | < < > | | < < < < < < < < < < < < < < < < | > > > | | | > > > | | 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 | ** pointer copied. ** ** If the string is too large (if it exceeds the SQLITE_LIMIT_LENGTH ** size limit) then no memory allocation occurs. If the string can be ** 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 */ int n, /* Bytes in string, or negative */ u8 enc, /* Encoding of z. 0 for BLOBs */ void (*xDel)(void*) /* Destructor function */ ){ int 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->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 = 0x7fffffff & (int)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 ){ u32 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 = nByte; pMem->flags = flags; pMem->enc = (enc==0 ? SQLITE_UTF8 : enc); #ifndef SQLITE_OMIT_UTF16 if( pMem->enc!=SQLITE_UTF8 && sqlite3VdbeMemHandleBom(pMem) ){ return SQLITE_NOMEM_BKPT; } #endif if( nByte>iLimit ){ return 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. */ static SQLITE_NOINLINE int vdbeMemFromBtreeResize( 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; |
︙ | ︙ | |||
1269 1270 1271 1272 1273 1274 1275 | pMem->n = (int)amt; }else{ sqlite3VdbeMemRelease(pMem); } } return rc; } | | > > | | | > | | 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 | pMem->n = (int)amt; }else{ sqlite3VdbeMemRelease(pMem); } } return rc; } 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. */ ){ char *zData; /* Data from the btree layer */ 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) ); zData = (char *)sqlite3BtreePayloadFetch(pCur, &available); assert( zData!=0 ); if( offset+amt<=available ){ pMem->z = &zData[offset]; pMem->flags = MEM_Blob|MEM_Ephem; pMem->n = (int)amt; }else{ rc = vdbeMemFromBtreeResize(pCur, offset, amt, pMem); } return rc; } /* ** The pVal argument is known to be a value other than NULL. |
︙ | ︙ | |||
1327 1328 1329 1330 1331 1332 1333 | }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) ){ | | | 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 | }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( sqlite3VdbeMemConsistentDualRep(pVal) ); return pVal->z; }else{ return 0; } } /* This function is only available internally, it is not part of the |
︙ | ︙ | |||
1350 1351 1352 1353 1354 1355 1356 | */ 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 ){ | | | 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 | */ 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( sqlite3VdbeMemConsistentDualRep(pVal) ); return pVal->z; } if( pVal->flags&MEM_Null ){ return 0; } return valueToText(pVal, enc); } |
︙ | ︙ | |||
1394 1395 1396 1397 1398 1399 1400 | ** 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){ | | | 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 | ** 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_STAT3_OR_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 */ |
︙ | ︙ | |||
1430 1431 1432 1433 1434 1435 1436 | } pRec->nField = p->iVal+1; return &pRec->aMem[p->iVal]; } #else UNUSED_PARAMETER(p); | | | 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 | } pRec->nField = p->iVal+1; return &pRec->aMem[p->iVal]; } #else UNUSED_PARAMETER(p); #endif /* defined(SQLITE_ENABLE_STAT3_OR_STAT4) */ return sqlite3ValueNew(db); } /* ** The expression object indicated by the second argument is guaranteed ** to be a scalar SQL function. If ** |
︙ | ︙ | |||
1454 1455 1456 1457 1458 1459 1460 | ** 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. */ | | | < < | 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 | ** 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_STAT3_OR_STAT4 static int valueFromFunction( sqlite3 *db, /* The database connection */ 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 ); pList = p->x.pList; if( pList ) nVal = pList->nExpr; 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; } |
︙ | ︙ | |||
1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 | pVal = valueNew(db, pCtx); if( pVal==0 ){ rc = SQLITE_NOMEM_BKPT; goto value_from_function_out; } memset(&ctx, 0, sizeof(ctx)); ctx.pOut = pVal; ctx.pFunc = pFunc; | > < < < < < < > < | | > > > > < < | | | | 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 | pVal = valueNew(db, pCtx); if( pVal==0 ){ rc = SQLITE_NOMEM_BKPT; goto value_from_function_out; } assert( pCtx->pParse->rc==SQLITE_OK ); memset(&ctx, 0, sizeof(ctx)); ctx.pOut = pVal; ctx.pFunc = pFunc; pFunc->xSFunc(&ctx, nVal, apVal); if( ctx.isError ){ rc = ctx.isError; sqlite3ErrorMsg(pCtx->pParse, "%s", sqlite3_value_text(pVal)); }else{ sqlite3ValueApplyAffinity(pVal, aff, SQLITE_UTF8); assert( rc==SQLITE_OK ); rc = sqlite3VdbeChangeEncoding(pVal, enc); if( rc==SQLITE_OK && sqlite3VdbeMemTooBig(pVal) ){ rc = SQLITE_TOOBIG; pCtx->pParse->nErr++; } } pCtx->pParse->rc = rc; value_from_function_out: if( rc!=SQLITE_OK ){ pVal = 0; } if( apVal ){ for(i=0; i<nVal; i++){ sqlite3ValueFree(apVal[i]); } sqlite3DbFreeNN(db, apVal); } *ppVal = pVal; return rc; } #else # define valueFromFunction(a,b,c,d,e,f) SQLITE_OK #endif /* defined(SQLITE_ENABLE_STAT3_OR_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 */ 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_STAT3_OR_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 = 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; } /* Handle negative integers in a single step. This is needed in the ** case when the value is -9223372036854775808. */ |
︙ | ︙ | |||
1620 1621 1622 1623 1624 1625 1626 | 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); } | < | < < < < < < < < < | < | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | 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); } if( pVal->flags & (MEM_Int|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 ){ pVal->u.r = -(double)SMALLEST_INT64; 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( 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_STAT3_OR_STAT4 else if( op==TK_FUNCTION && pCtx!=0 ){ rc = valueFromFunction(db, pExpr, enc, affinity, &pVal, pCtx); } #endif else if( op==TK_TRUEFALSE ){ 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_STAT3_OR_STAT4 if( pCtx==0 || pCtx->pParse->nErr==0 ) #endif sqlite3OomFault(db); sqlite3DbFree(db, zVal); assert( *ppVal==0 ); #ifdef SQLITE_ENABLE_STAT3_OR_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 */ 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_STAT3_OR_STAT4 /* ** The implementation of the sqlite_record() function. This function accepts ** a single argument of any type. The return value is a formatted database ** record (a blob) containing the argument value. ** ** This is used to convert the value stored in the 'sample' column of the ** sqlite_stat3 table to the record format SQLite uses internally. */ static void recordFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const int file_format = 1; u32 iSerial; /* Serial type */ int nSerial; /* Bytes of space for iSerial as varint */ u32 nVal; /* Bytes of space required for argv[0] */ int nRet; sqlite3 *db; u8 *aRet; UNUSED_PARAMETER( argc ); iSerial = sqlite3VdbeSerialType(argv[0], file_format, &nVal); nSerial = sqlite3VarintLen(iSerial); db = sqlite3_context_db_handle(context); nRet = 1 + nSerial + nVal; aRet = sqlite3DbMallocRawNN(db, nRet); if( aRet==0 ){ sqlite3_result_error_nomem(context); }else{ aRet[0] = nSerial+1; putVarint32(&aRet[1], iSerial); sqlite3VdbeSerialPut(&aRet[1+nSerial], argv[0], iSerial); sqlite3_result_blob(context, aRet, nRet, SQLITE_TRANSIENT); sqlite3DbFreeNN(db, aRet); } } /* ** Register built-in functions used to help read ANALYZE data. */ void sqlite3AnalyzeFunctions(void){ static FuncDef aAnalyzeTableFuncs[] = { FUNCTION(sqlite_record, 1, 0, 0, recordFunc), }; sqlite3InsertBuiltinFuncs(aAnalyzeTableFuncs, ArraySize(aAnalyzeTableFuncs)); } /* ** 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. ** |
︙ | ︙ | |||
1973 1974 1975 1976 1977 1978 1979 | } int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){ Mem *p = (Mem*)pVal; assert( (p->flags & MEM_Null)==0 || (p->flags & (MEM_Str|MEM_Blob))==0 ); if( (p->flags & MEM_Str)!=0 && pVal->enc==enc ){ return p->n; } | < < < | 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 | } int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){ Mem *p = (Mem*)pVal; assert( (p->flags & MEM_Null)==0 || (p->flags & (MEM_Str|MEM_Blob))==0 ); if( (p->flags & MEM_Str)!=0 && pVal->enc==enc ){ return p->n; } if( (p->flags & MEM_Blob)!=0 ){ if( p->flags & MEM_Zero ){ return p->n + p->u.nZero; }else{ return p->n; } } if( p->flags & MEM_Null ) return 0; return valueBytes(pVal, enc); } |
Changes to src/vdbesort.c.
︙ | ︙ | |||
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 | 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; getVarint32(&p1[1], n1); getVarint32(&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{ if( pTask->pSorter->pKeyInfo->aSortOrder[0] ){ res = res * -1; } } return res; } |
︙ | ︙ | |||
894 895 896 897 898 899 900 | if( res==0 ){ if( pTask->pSorter->pKeyInfo->nKeyField>1 ){ res = vdbeSorterCompareTail( pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2 ); } | | < | 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 | if( res==0 ){ if( pTask->pSorter->pKeyInfo->nKeyField>1 ){ res = vdbeSorterCompareTail( pTask, pbKey2Cached, pKey1, nKey1, pKey2, nKey2 ); } }else if( pTask->pSorter->pKeyInfo->aSortOrder[0] ){ res = res * -1; } return res; } /* |
︙ | ︙ | |||
956 957 958 959 960 961 962 | ** to exceed the maximum merge count */ #if SQLITE_MAX_WORKER_THREADS>=SORTER_MAX_MERGE_COUNT if( nWorker>=SORTER_MAX_MERGE_COUNT ){ nWorker = SORTER_MAX_MERGE_COUNT-1; } #endif | | < < < | < | 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 | ** to exceed the maximum merge count */ #if SQLITE_MAX_WORKER_THREADS>=SORTER_MAX_MERGE_COUNT if( nWorker>=SORTER_MAX_MERGE_COUNT ){ nWorker = SORTER_MAX_MERGE_COUNT-1; } #endif assert( pCsr->pKeyInfo && pCsr->pBtx==0 ); assert( pCsr->eCurType==CURTYPE_SORTER ); szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nKeyField-1)*sizeof(CollSeq*); 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; } pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(db->aDb[0].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; |
︙ | ︙ | |||
1014 1015 1016 1017 1018 1019 1020 | 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) | < | 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; } |
︙ | ︙ | |||
1070 1071 1072 1073 1074 1075 1076 | 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){ | | < | | 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 | 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; sqlite3OsCurrentTimeInt64(sqlite3_vfs_find(0), &t); fprintf(stderr, "%lld:X %s\n", t, zEvent); } static void vdbeSorterPopulateDebug( SortSubtask *pTask, const char *zEvent ){ i64 t; |
︙ | ︙ | |||
1286 1287 1288 1289 1290 1291 1292 | 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); | | | 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 | 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); sqlite3OsUnfetch(pFd, 0, p); } } #else # define vdbeSorterExtendFile(x,y,z) #endif /* |
︙ | ︙ | |||
1397 1398 1399 1400 1401 1402 1403 1404 1405 | /* ** 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; | > < | > > > > | 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 | /* ** 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 **aSlot; SorterRecord *p; int rc; rc = vdbeSortAllocUnpacked(pTask); if( rc!=SQLITE_OK ) return rc; p = pList->pList; pTask->xCompare = vdbeSorterGetCompare(pTask->pSorter); aSlot = (SorterRecord **)sqlite3MallocZero(64 * sizeof(SorterRecord *)); if( !aSlot ){ return SQLITE_NOMEM_BKPT; } while( p ){ SorterRecord *pNext; if( pList->aMemory ){ if( (u8*)p==pList->aMemory ){ pNext = 0; }else{ |
︙ | ︙ | |||
1431 1432 1433 1434 1435 1436 1437 | aSlot[i] = 0; } aSlot[i] = p; p = pNext; } p = 0; | | > | 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 | aSlot[i] = 0; } aSlot[i] = p; p = pNext; } p = 0; for(i=0; i<64; i++){ if( aSlot[i]==0 ) continue; p = p ? vdbeSorterMerge(pTask, p, aSlot[i]) : aSlot[i]; } pList->pList = p; sqlite3_free(aSlot); assert( pTask->pUnpacked->errCode==SQLITE_OK || pTask->pUnpacked->errCode==SQLITE_NOMEM ); return pTask->pUnpacked->errCode; } /* |
︙ | ︙ | |||
1727 1728 1729 1730 1731 1732 1733 | 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 */ | | | < < < | 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 | 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 = pTask->list.aMemory; void *pCtx = (void*)pTask; assert( pTask->pThread==0 && pTask->bDone==0 ); assert( pTask->list.pList==0 ); assert( pTask->list.aMemory==0 || pSorter->list.aMemory!=0 ); 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); |
︙ | ︙ | |||
1774 1775 1776 1777 1778 1779 1780 | 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; | | | 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 | 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; getVarint32((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; } |
︙ | ︙ | |||
2004 2005 2006 2007 2008 2009 2010 | 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; } | < | 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 | 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. */ |
︙ | ︙ |
Changes to src/vdbetrace.c.
︙ | ︙ | |||
80 81 82 83 84 85 86 87 88 | 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; | > | > | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | 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 char zBase[100]; /* Initial working space */ db = p->db; sqlite3StrAccumInit(&out, 0, zBase, sizeof(zBase), 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)); |
︙ | ︙ | |||
119 120 121 122 123 124 125 | testcase( zRawSql[0]=='$' ); testcase( zRawSql[0]=='@' ); testcase( zRawSql[0]=='#' ); idx = sqlite3VdbeParameterIndex(p, zRawSql, nToken); assert( idx>0 ); } zRawSql += nToken; | | | | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | testcase( zRawSql[0]=='$' ); testcase( zRawSql[0]=='@' ); testcase( zRawSql[0]=='#' ); idx = sqlite3VdbeParameterIndex(p, zRawSql, nToken); assert( idx>0 ); } zRawSql += nToken; nextIndex = idx + 1; 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 ){ 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); |
︙ | ︙ |
Deleted src/vdbevtab.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/vtab.c.
︙ | ︙ | |||
28 29 30 31 32 33 34 | 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. | < < < < < < < < < | | | | < | > | < < | | | < < < > > > | > | 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 | 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; int nName = sqlite3Strlen30(zName); pMod = (Module *)sqlite3Malloc(sizeof(Module) + nName + 1); if( pMod==0 ){ sqlite3OomFault(db); }else{ Module *pDel; char *zCopy = (char *)(&pMod[1]); memcpy(zCopy, zName, nName+1); pMod->zName = zCopy; pMod->pModule = pModule; pMod->pAux = pAux; pMod->xDestroy = xDestroy; pMod->pEpoTab = 0; pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod); assert( pDel==0 || pDel==pMod ); if( pDel ){ sqlite3OomFault(db); sqlite3DbFree(db, pDel); pMod = 0; } } 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); if( sqlite3HashFind(&db->aModule, zName) ){ rc = SQLITE_MISUSE_BKPT; }else{ (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; } |
︙ | ︙ | |||
129 130 131 132 133 134 135 | ){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) || zName==0 ) return SQLITE_MISUSE_BKPT; #endif return createModule(db, zName, pModule, pAux, xDestroy); } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | ){ #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, ** the disconnect is deferred until all locks have been removed. |
︙ | ︙ | |||
188 189 190 191 192 193 194 | ** 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) ); | | | < < | | | < < | < | | | 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 | ** 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->pVTable; 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->magic==SQLITE_MAGIC_OPEN || db->magic==SQLITE_MAGIC_ZOMBIE ); pVTab->nRef--; if( pVTab->nRef==0 ){ sqlite3_vtab *p = pVTab->pVtab; if( p ){ p->pModule->xDisconnect(p); } sqlite3DbFree(db, pVTab); } } /* ** Table p is a virtual table. This function moves all elements in the ** p->pVTable 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->pVTable list. */ static VTable *vtabDisconnectAll(sqlite3 *db, Table *p){ VTable *pRet = 0; VTable *pVTable = p->pVTable; p->pVTable = 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->pVTable 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->pVTable = pRet; pRet->pNext = 0; }else{ pVTable->pNext = db2->pDisconnect; db2->pDisconnect = pVTable; } pVTable = pNext; } |
︙ | ︙ | |||
272 273 274 275 276 277 278 | void sqlite3VtabDisconnect(sqlite3 *db, Table *p){ VTable **ppVTab; assert( IsVirtual(p) ); assert( sqlite3BtreeHoldsAllMutexes(db) ); assert( sqlite3_mutex_held(db->mutex) ); | | | 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 | void sqlite3VtabDisconnect(sqlite3 *db, Table *p){ VTable **ppVTab; assert( IsVirtual(p) ); assert( sqlite3BtreeHoldsAllMutexes(db) ); assert( sqlite3_mutex_held(db->mutex) ); for(ppVTab=&p->pVTable; *ppVTab; ppVTab=&(*ppVTab)->pNext){ if( (*ppVTab)->db==db ){ VTable *pVTab = *ppVTab; *ppVTab = pVTab->pNext; sqlite3VtabUnlock(pVTab); break; } } |
︙ | ︙ | |||
305 306 307 308 309 310 311 312 313 314 315 316 | ** 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 ){ | > < | 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 | ** 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; db->pDisconnect = 0; assert( sqlite3BtreeHoldsAllMutexes(db) ); assert( sqlite3_mutex_held(db->mutex) ); if( p ){ sqlite3ExpirePreparedStatements(db, 0); do { VTable *pNext = p->pNext; sqlite3VtabUnlock(p); p = pNext; }while( p ); } |
︙ | ︙ | |||
335 336 337 338 339 340 341 | ** 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){ | < < | | | | | | | < < < | | | | | 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 | ** 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); if( p->azModuleArg ){ int i; for(i=0; i<p->nModuleArg; i++){ if( i!=1 ) sqlite3DbFree(db, p->azModuleArg[i]); } sqlite3DbFree(db, p->azModuleArg); } } /* ** Add a new module argument to pTable->azModuleArg[]. ** 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 = sizeof(char *)*(2+pTable->nModuleArg); char **azModuleArg; sqlite3 *db = pParse->db; if( pTable->nModuleArg+3>=db->aLimit[SQLITE_LIMIT_COLUMN] ){ sqlite3ErrorMsg(pParse, "too many columns on %s", pTable->zName); } azModuleArg = sqlite3DbRealloc(db, pTable->azModuleArg, nBytes); if( azModuleArg==0 ){ sqlite3DbFree(db, zArg); }else{ int i = pTable->nModuleArg++; azModuleArg[i] = zArg; azModuleArg[i+1] = 0; pTable->azModuleArg = 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. |
︙ | ︙ | |||
393 394 395 396 397 398 399 | 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 ); | < | | | | | 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 | 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; assert( pTable->nModuleArg==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_master table, has already been made by sqlite3StartTable(). ** The second call, to obtain permission to create the table, is made now. */ if( pTable->azModuleArg ){ 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->azModuleArg[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 |
︙ | ︙ | |||
446 447 448 449 450 451 452 | ** 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; | < | | | < < | | | | > | | < > | | | > > > > | < | 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 | ** 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; addArgumentToVtab(pParse); pParse->sArg.z = 0; if( pTab->nModuleArg<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_master) then ** do additional initialization work and store the statement text ** in the sqlite_master table. */ if( !db->init.busy ){ char *zStmt; char *zWhere; int iDb; int iReg; Vdbe *v; /* 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 ** SQLITE_MASTER 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_master table tht was created for this vtab ** by sqlite3StartTable(). */ iDb = sqlite3SchemaToIndex(db, pTab->pSchema); sqlite3NestedParse(pParse, "UPDATE %Q.%s " "SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q " "WHERE rowid=#%d", db->aDb[iDb].zDbSName, MASTER_NAME, pTab->zName, pTab->zName, zStmt, pParse->regRowid ); sqlite3DbFree(db, zStmt); v = sqlite3GetVdbe(pParse); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddOp0(v, OP_Expire); zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName); sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere); iReg = ++pParse->nMem; sqlite3VdbeLoadString(v, iReg, pTab->zName); sqlite3VdbeAddOp2(v, OP_VCreate, iDb, iReg); } /* If we are rereading the sqlite_master table create the in-memory ** record of the table. The xConnect() method is not called until ** the first time the virtual table is used in an SQL statement. This ** allows a schema that contains virtual tables to be loaded before ** the required virtual table implementations are registered. */ else { Table *pOld; Schema *pSchema = pTab->pSchema; const char *zName = pTab->zName; assert( sqlite3SchemaMutexHeld(db, 0, pSchema) ); pOld = sqlite3HashInsert(&pSchema->tblHash, zName, pTab); if( pOld ){ sqlite3OomFault(db); assert( pTab==pOld ); /* Malloc must have failed inside HashInsert() */ return; } pParse->pNewTable = 0; |
︙ | ︙ | |||
560 561 562 563 564 565 566 | Module *pMod, int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**), char **pzErr ){ VtabCtx sCtx; VTable *pVTable; int rc; | | | < < < | 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 | 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 = (const char *const*)pTab->azModuleArg; int nArg = pTab->nModuleArg; char *zErr = 0; char *zModuleName; int iDb; VtabCtx *pCtx; /* 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; |
︙ | ︙ | |||
593 594 595 596 597 598 599 | if( !pVTable ){ sqlite3OomFault(db); sqlite3DbFree(db, zModuleName); return SQLITE_NOMEM_BKPT; } pVTable->db = db; pVTable->pMod = pMod; | < | | 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 | if( !pVTable ){ sqlite3OomFault(db); sqlite3DbFree(db, zModuleName); return SQLITE_NOMEM_BKPT; } pVTable->db = db; pVTable->pMod = pMod; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); pTab->azModuleArg[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; |
︙ | ︙ | |||
624 625 626 627 628 629 630 | } 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; | < | | | | | 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 | } 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; u8 oooHidden = 0; /* If everything went according to plan, link the new VTable structure ** into the linked list headed by pTab->pVTable. 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->pVTable; pTab->pVTable = 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++){ |
︙ | ︙ | |||
666 667 668 669 670 671 672 | 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; | < | 603 604 605 606 607 608 609 610 611 612 613 614 615 616 | 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; } } } } |
︙ | ︙ | |||
693 694 695 696 697 698 699 | int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ sqlite3 *db = pParse->db; const char *zMod; Module *pMod; int rc; assert( pTab ); | < | | | | 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 | int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ sqlite3 *db = pParse->db; const char *zMod; Module *pMod; int rc; assert( pTab ); if( !IsVirtual(pTab) || sqlite3GetVTable(db, pTab) ){ return SQLITE_OK; } /* Locate the required virtual table module */ zMod = pTab->azModuleArg[0]; pMod = (Module*)sqlite3HashFind(&db->aModule, zMod); if( !pMod ){ const char *zModule = pTab->azModuleArg[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); |
︙ | ︙ | |||
766 767 768 769 770 771 772 | 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); | | | | 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 | 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->pVTable ); /* Locate the required virtual table module */ zMod = pTab->azModuleArg[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 ){ |
︙ | ︙ | |||
804 805 806 807 808 809 810 811 | ** valid to call this function from within the xCreate() or xConnect() of a ** virtual table module. */ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ VtabCtx *pCtx; int rc = SQLITE_OK; Table *pTab; Parse sParse; | > < | | < < < < < < | | | > | < < | | 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 | ** valid to call this function from within the xCreate() or xConnect() of a ** virtual table module. */ 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 && !sParse.pNewTable->pSelect && !IsVirtual(sParse.pNewTable) ){ if( !pTab->aCol ){ Table *pNew = sParse.pNewTable; Index *pIdx; pTab->aCol = pNew->aCol; 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 |
︙ | ︙ | |||
867 868 869 870 871 872 873 | pTab->pIndex = pIdx; pNew->pIndex = 0; pIdx->pTable = pTab; } } pCtx->bDeclared = 1; }else{ | | < | | < < < | < | < | < | | < | 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 | pTab->pIndex = pIdx; pNew->pIndex = 0; pIdx->pTable = pTab; } } pCtx->bDeclared = 1; }else{ sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr); sqlite3DbFree(db, zErr); rc = SQLITE_ERROR; } 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); if( pTab!=0 && ALWAYS(pTab->pVTable!=0) ){ VTable *p; int (*xDestroy)(sqlite3_vtab *); for(p=pTab->pVTable; p; p=p->pNext){ assert( p->pVtab ); if( p->pVtab->nRef>0 ){ return SQLITE_LOCKED; } } p = vtabDisconnectAll(db, pTab); xDestroy = p->pMod->pModule->xDestroy; assert( xDestroy!=0 ); /* Checked before the virtual table is created */ rc = xDestroy(p->pVtab); /* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */ if( rc==SQLITE_OK ){ assert( pTab->pVTable==p && p->pNext==0 ); p->pVtab = 0; pTab->pVTable = 0; sqlite3VtabUnlock(p); } } return rc; } /* ** This function invokes either the xRollback or xCommit method |
︙ | ︙ | |||
1135 1136 1137 1138 1139 1140 1141 | 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; | < | | 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 | 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; if( pMod->xFindFunction==0 ) return pDef; |
︙ | ︙ | |||
1198 1199 1200 1201 1202 1203 1204 | 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]); | | | | < | 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 | 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 = sqlite3_realloc64(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 the eponymous virtual table instance exists ** when this routine returns, and return zero if it does not exist. ** ** 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 |
︙ | ︙ | |||
1239 1240 1241 1242 1243 1244 1245 | pTab->zName = sqlite3DbStrDup(db, pMod->zName); if( pTab->zName==0 ){ sqlite3DbFree(db, pTab); return 0; } pMod->pEpoTab = pTab; pTab->nTabRef = 1; | < | < > | 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 | 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; assert( pTab->nModuleArg==0 ); pTab->iPKey = -1; 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 0; } return 1; } /* ** Erase the eponymous virtual table instance associated with ** virtual table module pMod, if it exists. |
︙ | ︙ | |||
1300 1301 1302 1303 1304 1305 1306 | ** 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; | < > > > | | | | | < < < < < < | | < < < < | | | | < | < | 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 | ** 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); va_start(ap, op); switch( op ){ case SQLITE_VTAB_CONSTRAINT_SUPPORT: { VtabCtx *p = db->pVtabCtx; if( !p ){ rc = SQLITE_MISUSE_BKPT; }else{ assert( p->pTab==0 || IsVirtual(p->pTab) ); p->pVTable->bConstraint = (u8)va_arg(ap, int); } 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 | ** 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. ** ** 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 |
︙ | ︙ | |||
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. | > > > > > > > > > > > > | 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 | #if defined(SQLITE_TEST) && defined(SQLITE_DEBUG) int sqlite3WalTrace = 0; # define WALTRACE(X) if(sqlite3WalTrace) sqlite3DebugPrintf X #else # define WALTRACE(X) #endif /* ** WAL mode depends on atomic aligned 32-bit loads and stores in a few ** places. The following macros try to make this explicit. */ #if GCC_VESRION>=5004000 # define AtomicLoad(PTR) __atomic_load_n((PTR),__ATOMIC_RELAXED) # define AtomicStore(PTR,VAL) __atomic_store_n((PTR),(VAL),__ATOMIC_RELAXED) #else # define AtomicLoad(PTR) (*(PTR)) # define AtomicStore(PTR,VAL) (*(PTR) = (VAL)) #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. |
︙ | ︙ | |||
396 397 398 399 400 401 402 | 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 | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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)) |
︙ | ︙ | |||
530 531 532 533 534 535 536 | 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 | < < < | 475 476 477 478 479 480 481 482 483 484 485 486 487 488 | 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 #define WAL_EXCLUSIVE_MODE 1 |
︙ | ︙ | |||
571 572 573 574 575 576 577 | ** 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 { | | | 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 | ** 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 { int 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] */ |
︙ | ︙ | |||
616 617 618 619 620 621 622 | ** 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. ** | | < | | < < < | | < < < < | | 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 | ** 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. ** ** If this call is successful, *ppPage is set to point to the wal-index ** page and SQLITE_OK is returned. If an error (an OOM or VFS error) occurs, ** then an SQLite error code is returned and *ppPage is set to 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 **)sqlite3_realloc64((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 ); testcase( pWal->apWiData[iPage]==0 && rc==SQLITE_OK ); if( (rc&0xff)==SQLITE_READONLY ){ pWal->readOnly |= WAL_SHM_RDONLY; if( rc==SQLITE_READONLY ){ rc = SQLITE_OK; } } } |
︙ | ︙ | |||
760 761 762 763 764 765 766 | }while( aData<aEnd ); } aOut[0] = s1; aOut[1] = s2; } | < < < < < < < < < < < < < < < < < | < | 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 | }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. */ static 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); 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 |
︙ | ︙ | |||
932 933 934 935 936 937 938 | 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")); | | | | 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 | 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!=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!=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, |
︙ | ︙ | |||
996 997 998 999 1000 1001 1002 | ** ** 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. ** | | | | < | < | 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 | ** ** 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[1] is the page number of the ** first frame indexed by the hash table, frame (pLoc->iZero+1). */ 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( rc==SQLITE_OK ){ 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; } pLoc->aPgno = &pLoc->aPgno[-1]; } 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)) ); return iHash; } /* ** Return the page number associated with frame iFrame in this WAL. */ static u32 walFramePgno(Wal *pWal, u32 iFrame){ |
︙ | ︙ | |||
1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 | ** actually needed. */ static void walCleanupHash(Wal *pWal){ WalHashLoc sLoc; /* Hash table location */ int iLimit = 0; /* Zero values greater than this */ int nByte; /* Number of bytes to zero in aPgno[] */ int i; /* Used to iterate through aHash[] */ assert( pWal->writeLock ); testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE-1 ); 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)] ); | > | | | < | | | | | 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 | ** actually needed. */ static void walCleanupHash(Wal *pWal){ WalHashLoc sLoc; /* Hash table location */ int iLimit = 0; /* Zero values greater than this */ int nByte; /* Number of bytes to zero in aPgno[] */ int i; /* Used to iterate through aHash[] */ int rc; /* Return code form walHashGet() */ assert( pWal->writeLock ); testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE-1 ); 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)] ); rc = walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &sLoc); if( NEVER(rc) ) 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+1]); memset((void *)&sLoc.aPgno[iLimit+1], 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=1; j<=iLimit; j++){ for(iKey=walHash(sLoc.aPgno[j]);sLoc.aHash[iKey];iKey=walNextHash(iKey)){ if( sLoc.aHash[iKey]==j ) break; } assert( sLoc.aHash[iKey]==j ); } } #endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */ } /* |
︙ | ︙ | |||
1147 1148 1149 1150 1151 1152 1153 | 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 ){ | | | | | | | | | | | > | 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 | 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[1]); memset((void*)&sLoc.aPgno[1], 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] ){ walCleanupHash(pWal); assert( !sLoc.aPgno[idx] ); } /* 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] = iPage; 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=1; i<=idx; i++){ for(iKey=walHash(sLoc.aPgno[i]); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){ if( sLoc.aHash[iKey]==i ) break; } assert( sLoc.aHash[iKey]==i ); } } #endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */ } return rc; } /* ** Recover the wal-index by reading the write-ahead log file. |
︙ | ︙ | |||
1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 | */ 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 */ | > > > > > > < > > < < | 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 | */ 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==SQLITE_OK ){ rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1); if( rc!=SQLITE_OK ){ walUnlockExclusive(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 */ 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 iFrame; /* Index of last frame read */ i64 iOffset; /* Next offset to read from log file */ 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 */ /* Read in the WAL header. */ rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0); if( rc!=SQLITE_OK ){ goto recovery_error; } |
︙ | ︙ | |||
1304 1305 1306 1307 1308 1309 1310 | if( version!=WAL_MAX_VERSION ){ rc = SQLITE_CANTOPEN_BKPT; goto finished; } /* Malloc a buffer to read frames into. */ szFrame = szPage + WAL_FRAME_HDRSIZE; | | < | < < < < < < < < < < | < < | | | > | | | | | | | | | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | < < < | < < < < < < < < > | 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 | 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); if( !aFrame ){ rc = SQLITE_NOMEM_BKPT; goto recovery_error; } aData = &aFrame[WAL_FRAME_HDRSIZE]; /* Read all frames from the log file. */ iFrame = 0; for(iOffset=WAL_HDRSIZE; (iOffset+szFrame)<=nSize; iOffset+=szFrame){ u32 pgno; /* Database page number for frame */ u32 nTruncate; /* dbsize field from frame header */ /* Read and decode the next log frame. */ iFrame++; 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( 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]; } } 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 readers, writers and ** checkpointers. */ pInfo = walCkptInfo(pWal); pInfo->nBackfill = 0; pInfo->nBackfillAttempted = pWal->hdr.mxFrame; pInfo->aReadMark[0] = 0; for(i=1; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED; if( pWal->hdr.mxFrame ) pInfo->aReadMark[1] = pWal->hdr.mxFrame; /* 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); walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1); return rc; } /* ** Close an open wal-index. */ static void walIndexClose(Wal *pWal, int isDelete){ |
︙ | ︙ | |||
1481 1482 1483 1484 1485 1486 1487 | int rc; /* Return Code */ Wal *pRet; /* Object to allocate and return */ int flags; /* Flags passed to OsOpen() */ assert( zWalName && zWalName[0] ); assert( pDbFd ); | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > | 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 | 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. */ assert( 120==WALINDEX_LOCK_OFFSET ); assert( 136==WALINDEX_HDR_SIZE ); #ifdef WIN_SHM_BASE assert( WIN_SHM_BASE==WALINDEX_LOCK_OFFSET ); #endif #ifdef UNIX_SHM_BASE assert( UNIX_SHM_BASE==WALINDEX_LOCK_OFFSET ); #endif |
︙ | ︙ | |||
1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 | 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++; | > | 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 | 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 */ sLoc.aPgno++; 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++; |
︙ | ︙ | |||
1846 1847 1848 1849 1850 1851 1852 | if( rc!=SQLITE_OK ){ walIteratorFree(p); p = 0; } *pp = p; return rc; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | 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. */ |
︙ | ︙ | |||
1990 1991 1992 1993 1994 1995 1996 | 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); | | | 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 | 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); 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 ); } /* |
︙ | ︙ | |||
2065 2066 2067 2068 2069 2070 2071 | ** 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++){ | > > > > > > > > | | < | < < < < < < < < | | | < | < | | 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 | ** 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++){ /* Thread-sanitizer reports that the following is an unsafe read, ** as some other thread may be in the process of updating the value ** of the aReadMark[] slot. The assumption here is that if that is ** happening, the other client may only be increasing the value, ** not decreasing it. So assuming either that either the "old" or ** "new" version of the value is read, and not some arbitrary value ** that would never be written by a real client, things are still ** safe. */ u32 y = 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 ){ pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED); 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 */ rc = sqlite3OsFileSize(pWal->pDbFd, &nSize); if( rc==SQLITE_OK && nSize<nReq ){ sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq); } } /* Iterate through the contents of the WAL, copying data to the db file */ while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){ i64 iOffset; assert( walFramePgno(pWal, iFrame)==iDbpage ); if( 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; } /* 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 ){ pInfo->nBackfill = mxSafeFrame; } } /* Release the reader lock held while backfilling */ walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1); } |
︙ | ︙ | |||
2312 2313 2314 2315 2316 2317 2318 | ** 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. */ | | < | < < < < < | | 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 | ** 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 int walIndexTryHdr(Wal *pWal, int *pChanged){ u32 aCksum[2]; /* Checksum on the header content */ WalIndexHdr h1, h2; /* Two copies of the header content */ WalIndexHdr volatile *aHdr; /* Header in shared memory */ /* The first page of the wal-index must be mapped at this point. */ assert( pWal->nWiData>0 && pWal->apWiData[0] ); /* Read the header. This might happen concurrently with a write to the ** same area of shared memory on a different CPU in a SMP, ** meaning it is possible that an inconsistent snapshot is read ** from the file. If this happens, return non-zero. ** ** There are two copies of the header at the beginning of the wal-index. ** When reading, read [0] first then [1]. Writes are in the reverse order. ** Memory barriers are used to prevent the compiler or the hardware from ** reordering the reads and writes. */ aHdr = walIndexHdr(pWal); memcpy(&h1, (void *)&aHdr[0], sizeof(h1)); walShmBarrier(pWal); memcpy(&h2, (void *)&aHdr[1], sizeof(h2)); if( memcmp(&h1, &h2, sizeof(h1))!=0 ){ return 1; /* Dirty read */ } if( h1.isInit==0 ){ |
︙ | ︙ | |||
2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 | ** 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; } | > < < | | | | | | | | | | | | | < | | < < | 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 | ** 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. */ assert( badHdr==0 || pWal->writeLock==0 ); 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 if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){ 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; } } 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. */ |
︙ | ︙ | |||
2599 2600 2601 2602 2603 2604 2605 | ** Return WAL_RETRY which will cause the in-memory WAL-index to be ** rebuilt. */ rc = WAL_RETRY; goto begin_unreliable_shm_out; } /* Allocate a buffer to read frames into */ | < < | | | 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 | ** Return WAL_RETRY which will cause the in-memory WAL-index to be ** rebuilt. */ rc = WAL_RETRY; goto begin_unreliable_shm_out; } /* Allocate a buffer to read frames into */ szFrame = pWal->hdr.szPage + WAL_FRAME_HDRSIZE; aFrame = (u8 *)sqlite3_malloc64(szFrame); if( aFrame==0 ){ rc = SQLITE_NOMEM_BKPT; goto begin_unreliable_shm_out; } aData = &aFrame[WAL_FRAME_HDRSIZE]; /* Check to see if a complete transaction has been appended to the ** wal file since the heap-memory wal-index was created. If so, the ** heap-memory wal-index is discarded and WAL_RETRY returned to ** the caller. */ aSaveCksum[0] = pWal->hdr.aFrameCksum[0]; aSaveCksum[1] = pWal->hdr.aFrameCksum[1]; for(iOffset=walFrameOffset(pWal->hdr.mxFrame+1, pWal->hdr.szPage); iOffset+szFrame<=szWal; iOffset+=szFrame ){ u32 pgno; /* Database page number for frame */ u32 nTruncate; /* dbsize field from frame header */ /* Read and decode the next log frame. */ |
︙ | ︙ | |||
2784 2785 2786 2787 2788 2789 2790 | return walBeginShmUnreliable(pWal, pChanged); } } assert( pWal->nWiData>0 ); assert( pWal->apWiData[0]!=0 ); pInfo = walCkptInfo(pWal); | | | 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 | return walBeginShmUnreliable(pWal, pChanged); } } assert( pWal->nWiData>0 ); assert( pWal->apWiData[0]!=0 ); pInfo = walCkptInfo(pWal); if( !useWal && 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. */ |
︙ | ︙ | |||
2846 2847 2848 2849 2850 2851 2852 | } 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 ){ | | < | 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 | } 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 ){ mxReadMark = AtomicStore(pInfo->aReadMark+i,mxFrame); mxI = i; walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1); break; }else if( rc!=SQLITE_BUSY ){ return rc; } } |
︙ | ︙ | |||
2951 2952 2953 2954 2955 2956 2957 | 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; | | < | | 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 | 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>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; pgno = sLoc.aPgno[i-sLoc.iZero]; 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 ){ |
︙ | ︙ | |||
3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 | ** 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; | > < < < < < < | | < < < < < < < < < < < < < < < < < < | 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 | ** 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; if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){ bChanged = 1; } #endif do{ rc = walTryBeginRead(pWal, pChanged, 0, ++cnt); }while( rc==WAL_RETRY ); testcase( (rc&0xff)==SQLITE_BUSY ); |
︙ | ︙ | |||
3068 3069 3070 3071 3072 3073 3074 | ** 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 ); | > > > > > > > > > > > > > > > | | | | | | | | | | | | | | | < < < < < | > | > > < < < < < < < | 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 | ** 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 ); /* 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. ** ** TODO: Does the aReadMark[] lock prevent a checkpointer from doing ** this already? */ rc = walLockShared(pWal, WAL_CKPT_LOCK); if( rc==SQLITE_OK ){ /* 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; } /* Release the shared CKPT lock obtained above. */ walUnlockShared(pWal, WAL_CKPT_LOCK); pWal->minFrame = 1; } if( rc!=SQLITE_OK ){ sqlite3WalEndReadTransaction(pWal); } } } #endif return rc; } /* ** Finish with a read transaction. All this does is release the ** read-lock. |
︙ | ︙ | |||
3183 3184 3185 3186 3187 3188 3189 | */ 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 */ | < | < | | > < | 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 | */ 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; for(iKey=walHash(pgno); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){ u32 iFrame = sLoc.aHash[iKey] + sLoc.iZero; if( iFrame<=iLast && iFrame>=pWal->minFrame && sLoc.aPgno[sLoc.aHash[iKey]]==pgno ){ assert( iFrame>iRead || CORRUPT_DB ); iRead = iFrame; } if( (nCollide--)==0 ){ return SQLITE_CORRUPT_BKPT; } } 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 |
︙ | ︙ | |||
3276 3277 3278 3279 3280 3281 3282 | ** 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; | < < < < < < < < < < | 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 | ** 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; /* Cannot start a write transaction without first holding a read ** transaction. */ assert( pWal->readLock>=0 ); assert( pWal->writeLock==0 && pWal->iReCksum==0 ); if( pWal->readOnly ){ return SQLITE_READONLY; |
︙ | ︙ | |||
3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 | 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; } | > > > > | 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 | 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 */ #if defined(SQLITE_HAS_CODEC) if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM_BKPT; #else pData = pPage->pData; #endif 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; } |
︙ | ︙ | |||
3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 | 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; } } | > > > > | 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 | 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; } #if defined(SQLITE_HAS_CODEC) if( (pData = sqlite3PagerCodec(p))==0 ) return SQLITE_NOMEM; #else pData = p->pData; #endif rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOff); if( rc ) return rc; p->flags &= ~PGHDR_WAL_APPEND; continue; } } |
︙ | ︙ | |||
3764 3765 3766 3767 3768 3769 3770 | bSync = (w.iSyncPoint==iOffset); testcase( bSync ); while( iOffset<w.iSyncPoint ){ rc = walWriteOneFrame(&w, pLast, nTruncate, iOffset); if( rc ) return rc; iOffset += szFrame; nExtra++; | < | 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 | 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)); } } |
︙ | ︙ | |||
3797 3798 3799 3800 3801 3802 3803 | */ 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); } | < | 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 | */ 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 ){ |
︙ | ︙ | |||
3862 3863 3864 3865 3866 3867 3868 | /* 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)); | < < < < < | > > | | | | | | < | | | > | | | | | | | | | | | | | | | | | | | | | < < < < | 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 | /* 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 ** "checkpoint" lock on the database file. */ rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1); if( rc ){ /* 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. */ testcase( rc==SQLITE_BUSY ); testcase( xBusy!=0 ); return rc; } 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, xBusy, 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 ){ rc = walIndexReadHdr(pWal, &isChanged); if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){ sqlite3OsUnfetch(pWal->pDbFd, 0, 0); } } /* Copy data from the log to the database file. */ if( rc==SQLITE_OK ){ |
︙ | ︙ | |||
3939 3940 3941 3942 3943 3944 3945 | ** 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)); } | < < < < | | < < < < | 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 | ** 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); walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1); pWal->ckptLock = 0; WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok")); 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. |
︙ | ︙ | |||
4068 4069 4070 4071 4072 4073 4074 | } return rc; } /* Try to open on pSnapshot when the next read-transaction starts */ | | < < < | 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 | } 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.
︙ | ︙ | |||
142 143 144 145 146 147 148 | */ int sqlite3WalFramesize(Wal *pWal); #endif /* Return the sqlite3_file object for the WAL file */ sqlite3_file *sqlite3WalFile(Wal *pWal); | < < < < < | 142 143 144 145 146 147 148 149 150 | */ int sqlite3WalFramesize(Wal *pWal); #endif /* Return the sqlite3_file object for the WAL file */ sqlite3_file *sqlite3WalFile(Wal *pWal); #endif /* ifndef SQLITE_OMIT_WAL */ #endif /* SQLITE_WAL_H */ |
Changes to src/walker.c.
︙ | ︙ | |||
18 19 20 21 22 23 24 | #if !defined(SQLITE_OMIT_WINDOWFUNC) /* ** Walk all expressions linked into the list of Window objects passed ** as the second argument. */ | | < | < | < | < < < < < < | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | #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){ Window *pWin; for(pWin=pList; pWin; pWin=pWin->pNextWin){ if( sqlite3WalkExprList(pWalker, pWin->pOrderBy) ) return WRC_Abort; if( sqlite3WalkExprList(pWalker, pWin->pPartition) ) return WRC_Abort; if( sqlite3WalkExpr(pWalker, pWin->pFilter) ) return WRC_Abort; } return WRC_Continue; } #endif /* ** Walk an expression tree. Invoke the callback once for each node |
︙ | ︙ | |||
65 66 67 68 69 70 71 | 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)) ){ | < > < < | < | | | | | | < | 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 | 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)) ){ if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort; assert( pExpr->x.pList==0 || pExpr->pRight==0 ); if( pExpr->pRight ){ pExpr = pExpr->pRight; continue; }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){ 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) ) return WRC_Abort; } #endif } break; } return WRC_Continue; } int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){ return pExpr ? walkExpr(pWalker,pExpr) : WRC_Continue; |
︙ | ︙ | |||
108 109 110 111 112 113 114 | for(i=p->nExpr, pItem=p->a; i>0; i--, pItem++){ if( sqlite3WalkExpr(pWalker, pItem->pExpr) ) return WRC_Abort; } } return WRC_Continue; } | < < < < < < < < < < | < > | < | < < < < < < | > | | | | | | | | | | < | | 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 | 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; #if !defined(SQLITE_OMIT_WINDOWFUNC) && !defined(SQLITE_OMIT_ALTERTABLE) { Parse *pParse = pWalker->pParse; if( pParse && IN_RENAME_OBJECT ){ int rc = walkWindowList(pWalker, p->pWinDefn); assert( rc==WRC_Continue ); 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; struct SrcList_item *pItem; pSrc = p->pSrc; assert( pSrc!=0 ); 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 |
︙ | ︙ | |||
214 215 216 217 218 219 220 | if( pWalker->xSelectCallback2 ){ pWalker->xSelectCallback2(pWalker, p); } p = p->pPrior; }while( p!=0 ); return WRC_Continue; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 184 185 186 187 188 189 190 | if( pWalker->xSelectCallback2 ){ pWalker->xSelectCallback2(pWalker, p); } p = p->pPrior; }while( p!=0 ); return WRC_Continue; } |
Changes to src/where.c.
︙ | ︙ | |||
26 27 28 29 30 31 32 | ** ** This object is not an API and can be changed from one release to the ** next. As long as allocateIndexInfo() and sqlite3_vtab_collation() ** agree on the structure, all will be well. */ typedef struct HiddenIndexInfo HiddenIndexInfo; struct HiddenIndexInfo { | | | < < < < < < > > > > > > | | < < < < | | 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 | ** ** This object is not an API and can be changed from one release to the ** next. As long as allocateIndexInfo() and sqlite3_vtab_collation() ** agree on the structure, all will be well. */ typedef struct HiddenIndexInfo HiddenIndexInfo; struct HiddenIndexInfo { WhereClause *pWC; /* The Where clause being analyzed */ Parse *pParse; /* The parsing context */ }; /* Forward declaration of methods */ static int whereLoopResize(sqlite3*, WhereLoop*, int); /* Test variable that can be set to enable WHERE tracing */ #if defined(SQLITE_TEST) || defined(SQLITE_DEBUG) /***/ int sqlite3WhereTrace = 0; #endif /* ** 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 TRUE if the WHERE clause returns rows in ORDER BY order. ** Return FALSE if the output needs to be sorted. */ int sqlite3WhereIsOrdered(WhereInfo *pWInfo){ return pWInfo->nOBSat; } /* ** In the ORDER BY LIMIT optimization, if the inner-most loop is known ** to emit rows in increasing order, and if the last row emitted by the ** inner-most loop did not fit within the sorter, then we can skip all ** subsequent rows for the current iteration of the inner loop (because they |
︙ | ︙ | |||
98 99 100 101 102 103 104 | if( !pWInfo->bOrderedInnerLoop ){ /* The ORDER BY LIMIT optimization does not apply. Jump to the ** continuation of the inner-most loop. */ return pWInfo->iContinue; } pInner = &pWInfo->a[pWInfo->nLevel-1]; assert( pInner->addrNxt!=0 ); | < < < < < < < < < < < < < < < < < < < < < < < | < < < | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | if( !pWInfo->bOrderedInnerLoop ){ /* The ORDER BY LIMIT optimization does not apply. Jump to the ** 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){ |
︙ | ︙ | |||
146 147 148 149 150 151 152 | */ int sqlite3WhereBreakLabel(WhereInfo *pWInfo){ return pWInfo->iBreak; } /* ** Return ONEPASS_OFF (0) if an UPDATE or DELETE statement is unable to | | | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | */ int sqlite3WhereBreakLabel(WhereInfo *pWInfo){ return pWInfo->iBreak; } /* ** Return ONEPASS_OFF (0) if an UPDATE or DELETE statement is unable to ** operate directly on the rowis 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 |
︙ | ︙ | |||
236 237 238 239 240 241 242 | /* ** Return the bitmask for the given cursor number. Return 0 if ** iCursor is not in the set. */ Bitmask sqlite3WhereGetMask(WhereMaskSet *pMaskSet, int iCursor){ int i; assert( pMaskSet->n<=(int)sizeof(Bitmask)*8 ); | < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | 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 | /* ** Return the bitmask for the given cursor number. Return 0 if ** iCursor is not in the set. */ Bitmask sqlite3WhereGetMask(WhereMaskSet *pMaskSet, int iCursor){ int i; assert( pMaskSet->n<=(int)sizeof(Bitmask)*8 ); for(i=0; i<pMaskSet->n; i++){ if( pMaskSet->ix[i]==iCursor ){ return MASKBIT(i); } } return 0; } /* ** Create a new mask for cursor iCursor. ** ** There is one cursor per table in the FROM clause. The number of ** tables in the FROM clause is limited by a test early in the ** 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 && pTerm->u.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 = sqlite3ExprSkipCollate(pTerm->pExpr->pRight))->op==TK_COLUMN ){ int j; for(j=0; j<pScan->nEquiv; j++){ if( pScan->aiCur[j]==pX->iTable && pScan->aiColumn[j]==pX->iColumn ){ break; } |
︙ | ︙ | |||
355 356 357 358 359 360 361 | CollSeq *pColl; Parse *pParse = pWC->pWInfo->pParse; pX = pTerm->pExpr; if( !sqlite3IndexAffinityOk(pX, pScan->idxaff) ){ continue; } assert(pX->pLeft); | | > | < < < < < < < < < < < < < | 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 | CollSeq *pColl; Parse *pParse = pWC->pWInfo->pParse; pX = pTerm->pExpr; if( !sqlite3IndexAffinityOk(pX, pScan->idxaff) ){ continue; } assert(pX->pLeft); pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight); 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)->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; return pTerm; } } } pWC = pWC->pOuter; k = 0; }while( pWC!=0 ); |
︙ | ︙ | |||
450 451 452 453 454 455 456 | pScan->k = 0; pScan->aiCur[0] = iCur; pScan->nEquiv = 1; pScan->iEquiv = 1; if( pIdx ){ int j = iColumn; iColumn = pIdx->aiColumn[j]; | > > > > > | < < < < < | 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 | 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); } |
︙ | ︙ | |||
538 539 540 541 542 543 544 | 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++){ | | < | | 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 | 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 = sqlite3ExprSkipCollate(pList->a[i].pExpr); if( p->op==TK_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; } |
︙ | ︙ | |||
603 604 605 606 607 608 609 | 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++){ | | < < | < | 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 | 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 = sqlite3ExprSkipCollate(pDistinct->a[i].pExpr); if( p->op==TK_COLUMN && 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; 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 ){ |
︙ | ︙ | |||
655 656 657 658 659 660 661 | /* ** 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. ** | | | | | | < > > | | < | > > < | | < | | < | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | < | > | > > > | < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | 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 | /* ** 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 bIncrRowid parameter is 0, then any OP_Rowid instructions on ** cursor iTabCur are transformed into OP_Null. Or, if bIncrRowid is non-zero, ** then each OP_Rowid is transformed into an instruction to increment the ** value stored in its output register. */ 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 bIncrRowid /* If non-zero, transform OP_rowid to OP_AddImm(1) */ ){ 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 ){ if( bIncrRowid ){ /* Increment the value stored in the P2 operand of the OP_Rowid. */ pOp->opcode = OP_AddImm; pOp->p1 = pOp->p2; pOp->p2 = 1; }else{ pOp->opcode = OP_Null; pOp->p1 = 0; pOp->p3 = 0; } } } } /* ** 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 TRACE_IDX_INPUTS(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 TRACE_IDX_OUTPUTS(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 TRACE_IDX_INPUTS(A) #define TRACE_IDX_OUTPUTS(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 */ struct SrcList_item *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; if( pTerm->u.leftColumn<0 ) return 0; aff = pSrc->pTab->aCol[pTerm->u.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 */ struct SrcList_item *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 */ Vdbe *v; /* Prepared statement under construction */ |
︙ | ︙ | |||
891 892 893 894 895 896 897 | 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 */ | | < < < | | | > | > | < | | < < < | | | | 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 | 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 */ struct SrcList_item *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 ); addrInit = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); /* Count the number of columns that will be added to the index ** and used to match WHERE clause constraints */ nKeyCol = 0; pTable = pSrc->pTab; pWCEnd = &pWC->a[pWC->nTerm]; pLoop = pLevel->pWLoop; idxCols = 0; for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){ Expr *pExpr = pTerm->pExpr; 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->db, pPartial, sqlite3ExprDup(pParse->db, pExpr, 0)); } if( termCanDriveIndex(pTerm, pSrc, notReady) ){ int iCol = pTerm->u.leftColumn; Bitmask 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].zName); 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 ); 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 |
︙ | ︙ | |||
979 980 981 982 983 984 985 | 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) ){ | | < < < | | | < | 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 | 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 = pTerm->u.leftColumn; Bitmask 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.leftColumn; pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight); pIdx->azColl[n] = pColl ? pColl->zName : sqlite3StrBINARY; n++; } } } assert( (u32)n==pLoop->u.btree.nEq ); |
︙ | ︙ | |||
1020 1021 1022 1023 1024 1025 1026 | } } assert( n==nKeyCol ); pIdx->aiColumn[n] = XN_ROWID; pIdx->azColl[n] = sqlite3StrBINARY; /* Create the automatic index */ | < < < < < | 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 | } } assert( n==nKeyCol ); pIdx->aiColumn[n] = XN_ROWID; pIdx->azColl[n] = sqlite3StrBINARY; /* Create the automatic index */ assert( pLevel->iIdxCur>=0 ); pLevel->iIdxCur = pParse->nTab++; sqlite3VdbeAddOp2(v, OP_OpenAutoindex, pLevel->iIdxCur, nKeyCol+1); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); VdbeComment((v, "for %s", pTable->zName)); /* Fill the automatic index with content */ pTabItem = &pWC->pWInfo->pTabList->a[pLevel->iFrom]; if( pTabItem->fg.viaCoroutine ){ int regYield = pTabItem->regReturn; addrCounter = sqlite3VdbeAddOp2(v, OP_Integer, 0, 0); sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub); |
︙ | ︙ | |||
1052 1053 1054 1055 1056 1057 1058 | sqlite3ExprIfFalse(pParse, pPartial, iContinue, SQLITE_JUMPIFNULL); pLoop->wsFlags |= WHERE_PARTIALIDX; } regRecord = sqlite3GetTempReg(pParse); regBase = sqlite3GenerateIndexKey( pParse, pIdx, pLevel->iTabCur, regRecord, 0, 0, 0, 0 ); | < < < < < < | < > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | > < < < < | < < < < | | < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < | < < < < | < < < < < | < > > > > > > | > > | | | > > < < > > > > > > > > | > > > > > > > > > > > > > > > | | < < < < < | 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 | 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 ); translateColumnToCopy(pParse, addrTop, pLevel->iTabCur, pTabItem->regResult, 1); 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: sqlite3ExprDelete(pParse->db, pPartial); } #endif /* SQLITE_OMIT_AUTOMATIC_INDEX */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Allocate and populate an sqlite3_index_info structure. It is the ** 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 */ struct SrcList_item *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; struct sqlite3_index_constraint_usage *pUsage; struct HiddenIndexInfo *pHidden; WhereTerm *pTerm; int nOrderBy; sqlite3_index_info *pIdxInfo; u16 mNoOmit = 0; /* Count the number of possible WHERE clause constraints referring ** to this virtual table */ for(i=nTerm=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){ 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_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->u.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( 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; } /* Initialize the structure. The sqlite3_index_info structure contains ** many fields that are declared "const" to prevent xBestIndex from ** changing them. We have to do some funky casting in order to ** initialize those fields. */ 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]; *(int*)&pIdxInfo->nConstraint = nTerm; *(int*)&pIdxInfo->nOrderBy = nOrderBy; *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint = pIdxCons; *(struct sqlite3_index_orderby**)&pIdxInfo->aOrderBy = pIdxOrderBy; *(struct sqlite3_index_constraint_usage**)&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; if( (pSrc->fg.jointype & JT_LEFT)!=0 && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) && (pTerm->eOperator & (WO_IS|WO_ISNULL)) ){ /* An "IS" term in the WHERE clause where the virtual table is the rhs ** of a LEFT JOIN. Do not pass this term to the virtual table ** implementation, as this can lead to incorrect results from SQL such ** as: ** ** "LEFT JOIN vtab WHERE vtab.col IS NULL" */ testcase( pTerm->eOperator & WO_ISNULL ); testcase( pTerm->eOperator & WO_IS ); continue; } assert( pTerm->u.leftColumn>=(-1) ); pIdxCons[j].iColumn = pTerm->u.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 ){ pIdxCons[j].op = SQLITE_INDEX_CONSTRAINT_ISNULL; }else{ pIdxCons[j].op = SQLITE_INDEX_CONSTRAINT_IS; |
︙ | ︙ | |||
1383 1384 1385 1386 1387 1388 1389 | 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) ){ | < | < < | < < < < | | < < < < < < < < < < < < < < < < < < < < | < < | | | 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 | 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) ){ if( i<16 ) mNoOmit |= (1 << i); if( op==WO_LT ) pIdxCons[j].op = WO_LE; if( op==WO_GT ) pIdxCons[j].op = WO_GE; } } j++; } for(i=0; i<nOrderBy; i++){ Expr *pExpr = pOrderBy->a[i].pExpr; pIdxOrderBy[i].iColumn = pExpr->iColumn; pIdxOrderBy[i].desc = pOrderBy->a[i].sortOrder; } *pmNoOmit = mNoOmit; return pIdxInfo; } /* ** The table object reference passed as the second argument to this function ** must represent a virtual table. This function invokes the xBestIndex() ** method of the virtual table with the sqlite3_index_info object that ** comes in as the 3rd argument to this function. ** ** If an error occurs, pParse is populated with an error message and an ** appropriate error code is returned. A return of SQLITE_CONSTRAINT from ** xBestIndex is not considered an error. SQLITE_CONSTRAINT indicates that ** the current configuration of "unusable" flags in sqlite3_index_info can ** not result in a valid plan. ** ** Whether or not an error is returned, it is the responsibility of the ** 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; TRACE_IDX_INPUTS(p); rc = pVtab->pModule->xBestIndex(pVtab, p); TRACE_IDX_OUTPUTS(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_STAT3_OR_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 ** |
︙ | ︙ | |||
1505 1506 1507 1508 1509 1510 1511 | tRowcnt iLower = 0; /* anLt[] + anEq[] of largest sample pRec is > */ #ifndef SQLITE_DEBUG UNUSED_PARAMETER( pParse ); #endif assert( pRec!=0 ); assert( pIdx->nSample>0 ); | | | 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 | tRowcnt iLower = 0; /* anLt[] + anEq[] of largest sample pRec is > */ #ifndef SQLITE_DEBUG UNUSED_PARAMETER( pParse ); #endif assert( pRec!=0 ); assert( pIdx->nSample>0 ); assert( pRec->nField>0 && pRec->nField<=pIdx->nSampleCol ); /* Do a binary search to find the first sample greater than or equal ** to pRec. If pRec contains a single field, the set of samples to search ** is simply the aSample[] array. If the samples in aSample[] contain more ** than one fields, all fields following the first are ignored. ** ** If pRec contains N fields, where N is more than one, then as well as the |
︙ | ︙ | |||
1551 1552 1553 1554 1555 1556 1557 | ** equal to the previous sample in the array. For example, in the above, ** sample 2 is the first sample of a block of N samples, so at first it ** appears that it should be 1 field in size. However, that would make it ** smaller than sample 1, so the binary search would not work. As a result, ** it is extended to two fields. The duplicates that this creates do not ** cause any problems. */ | | | 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 | ** equal to the previous sample in the array. For example, in the above, ** sample 2 is the first sample of a block of N samples, so at first it ** appears that it should be 1 field in size. However, that would make it ** smaller than sample 1, so the binary search would not work. As a result, ** it is extended to two fields. The duplicates that this creates do not ** cause any problems. */ nField = pRec->nField; iCol = 0; iSample = pIdx->nSample * nField; do{ int iSamp; /* Index in aSample[] of test sample */ int n; /* Number of fields in test sample */ iTest = (iMin+iSample)/2; |
︙ | ︙ | |||
1617 1618 1619 1620 1621 1622 1623 | /* if i==0 and iCol==0, then record pRec is smaller than all samples ** in the aSample[] array. Otherwise, if (iCol>0) then pRec must ** be greater than or equal to the (iCol) field prefix of sample i. ** If (i>0), then pRec must also be greater than sample (i-1). */ if( iCol>0 ){ pRec->nField = iCol; assert( sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)<=0 | | | | 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 | /* if i==0 and iCol==0, then record pRec is smaller than all samples ** in the aSample[] array. Otherwise, if (iCol>0) then pRec must ** be greater than or equal to the (iCol) field prefix of sample i. ** If (i>0), then pRec must also be greater than sample (i-1). */ if( iCol>0 ){ pRec->nField = iCol; assert( sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)<=0 || pParse->db->mallocFailed ); } if( i>0 ){ pRec->nField = nField; assert( sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec)<0 || pParse->db->mallocFailed ); } } } #endif /* ifdef SQLITE_DEBUG */ if( res==0 ){ /* Record pRec is equal to sample i */ |
︙ | ︙ | |||
1662 1663 1664 1665 1666 1667 1668 | aStat[1] = pIdx->aAvgEq[nField-1]; } /* Restore the pRec->nField value before returning. */ pRec->nField = nField; return i; } | | | 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 | aStat[1] = pIdx->aAvgEq[nField-1]; } /* Restore the pRec->nField value before returning. */ pRec->nField = nField; return i; } #endif /* SQLITE_ENABLE_STAT3_OR_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. ** |
︙ | ︙ | |||
1688 1689 1690 1691 1692 1693 1694 | nRet -= 20; assert( 20==sqlite3LogEst(4) ); } } return nRet; } | | < | | 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 | nRet -= 20; assert( 20==sqlite3LogEst(4) ); } } return nRet; } #ifdef SQLITE_ENABLE_STAT3_OR_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; } return pIdx->zColAff[iCol]; } #endif #ifdef SQLITE_ENABLE_STAT3_OR_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 ?; ** |
︙ | ︙ | |||
1795 1796 1797 1798 1799 1800 1801 | ** method (assume that the scan visits 1/64 of the rows) for estimating ** the number of rows visited. Otherwise, estimate the number of rows ** using the method described in the header comment for this function. */ if( nDiff!=1 || pUpper==0 || pLower==0 ){ int nAdjust = (sqlite3LogEst(p->nSample) - sqlite3LogEst(nDiff)); pLoop->nOut -= nAdjust; *pbDone = 1; | | | | 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 | ** method (assume that the scan visits 1/64 of the rows) for estimating ** the number of rows visited. Otherwise, estimate the number of rows ** using the method described in the header comment for this function. */ if( nDiff!=1 || pUpper==0 || pLower==0 ){ int nAdjust = (sqlite3LogEst(p->nSample) - sqlite3LogEst(nDiff)); pLoop->nOut -= nAdjust; *pbDone = 1; WHERETRACE(0x10, ("range skip-scan regions: %u..%u adjust=%d est=%d\n", nLower, nUpper, nAdjust*-1, pLoop->nOut)); } }else{ assert( *pbDone==0 ); } sqlite3ValueFree(p1); sqlite3ValueFree(p2); sqlite3ValueFree(pVal); return rc; } #endif /* SQLITE_ENABLE_STAT3_OR_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): |
︙ | ︙ | |||
1862 1863 1864 1865 1866 1867 1868 | 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; | | | | | 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 | 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_STAT3_OR_STAT4 Index *p = pLoop->u.btree.pIndex; int nEq = pLoop->u.btree.nEq; if( p->nSample>0 && nEq<p->nSampleCol && OptimizationEnabled(pParse->db, SQLITE_Stat34) ){ if( nEq==pBuilder->nRecValid ){ UnpackedRecord *pRec = pBuilder->pRec; tRowcnt a[2]; int nBtm = pLoop->u.btree.nBtm; int nTop = pLoop->u.btree.nTop; |
︙ | ︙ | |||
1965 1966 1967 1968 1969 1970 1971 | 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 | | | | 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 | 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 STAT3/4 tables. */ if( iLwrIdx==iUprIdx ) nNew -= 20; assert( 20==sqlite3LogEst(4) ); }else{ nNew = 10; assert( 10==sqlite3LogEst(2) ); } if( nNew<nOut ){ nOut = nNew; } WHERETRACE(0x10, ("STAT4 range scan: %u..%u est=%d\n", (u32)iLower, (u32)iUpper, nOut)); } }else{ int bDone = 0; rc = whereRangeSkipScanEst(pParse, pLower, pUpper, pLoop, &bDone); if( bDone ) return rc; } |
︙ | ︙ | |||
2006 2007 2008 2009 2010 2011 2012 | } nOut -= (pLower!=0) + (pUpper!=0); if( nNew<10 ) nNew = 10; if( nNew<nOut ) nOut = nNew; #if defined(WHERETRACE_ENABLED) if( pLoop->nOut>nOut ){ | | | | | 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 | } nOut -= (pLower!=0) + (pUpper!=0); if( nNew<10 ) nNew = 10; if( nNew<nOut ) nOut = nNew; #if defined(WHERETRACE_ENABLED) if( pLoop->nOut>nOut ){ WHERETRACE(0x10,("Range scan lowers nOut from %d to %d\n", pLoop->nOut, nOut)); } #endif pLoop->nOut = (LogEst)nOut; return rc; } #ifdef SQLITE_ENABLE_STAT3_OR_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_stat3 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. ** |
︙ | ︙ | |||
2071 2072 2073 2074 2075 2076 2077 | rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, 1, nEq-1, &bOk); pBuilder->pRec = pRec; if( rc!=SQLITE_OK ) return rc; if( bOk==0 ) return SQLITE_NOTFOUND; pBuilder->nRecValid = nEq; whereKeyStats(pParse, p, pRec, 0, a); | | | | | 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 | rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, 1, nEq-1, &bOk); pBuilder->pRec = pRec; if( rc!=SQLITE_OK ) return rc; if( bOk==0 ) return SQLITE_NOTFOUND; pBuilder->nRecValid = nEq; 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_STAT3_OR_STAT4 */ #ifdef SQLITE_ENABLE_STAT3_OR_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) ** |
︙ | ︙ | |||
2121 2122 2123 2124 2125 2126 2127 | nRowEst += nEst; pBuilder->nRecValid = nRecValid; } if( rc==SQLITE_OK ){ if( nRowEst > nRow0 ) nRowEst = nRow0; *pnRow = nRowEst; | | | | | | | < < | | | | < < < < | < | | | < | < | | | | 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 | nRowEst += nEst; pBuilder->nRecValid = nRecValid; } if( rc==SQLITE_OK ){ 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_STAT3_OR_STAT4 */ #ifdef WHERETRACE_ENABLED /* ** Print the content of a WhereTerm object */ static void whereTermPrint(WhereTerm *pTerm, int iTerm){ if( pTerm==0 ){ sqlite3DebugPrintf("TERM-%-3d NULL\n", iTerm); }else{ char zType[4]; char zLeft[50]; memcpy(zType, "...", 4); 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->eOperator & WO_SINGLE ){ sqlite3_snprintf(sizeof(zLeft),zLeft,"left={%d:%d}", pTerm->leftCursor, pTerm->u.leftColumn); }else if( (pTerm->eOperator & WO_OR)!=0 && pTerm->u.pOrInfo!=0 ){ sqlite3_snprintf(sizeof(zLeft),zLeft,"indexable=0x%lld", pTerm->u.pOrInfo->indexable); }else{ sqlite3_snprintf(sizeof(zLeft),zLeft,"left=%d", pTerm->leftCursor); } sqlite3DebugPrintf( "TERM-%-3d %p %s %-12s prob=%-3d op=0x%03x wtFlags=0x%04x", iTerm, pTerm, zType, zLeft, pTerm->truthProb, pTerm->eOperator, pTerm->wtFlags); if( pTerm->iField ){ sqlite3DebugPrintf(" iField=%d\n", pTerm->iField); }else{ 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++){ whereTermPrint(&pWC->a[i], i); } } #endif #ifdef WHERETRACE_ENABLED /* ** Print a WhereLoop object for debugging purposes */ static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){ WhereInfo *pWInfo = pWC->pWInfo; int nb = 1+(pWInfo->pTabList->nSrc+3)/4; struct SrcList_item *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 ){ |
︙ | ︙ | |||
2216 2217 2218 2219 2220 2221 2222 | sqlite3DebugPrintf(".%-16s %2d", zName, p->u.btree.nEq); }else{ sqlite3DebugPrintf("%20s",""); } }else{ char *z; if( p->u.vtab.idxStr ){ | | | | | | | 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 | 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++){ whereTermPrint(p->aLTerm[i], i); } } } #endif /* ** Convert bulk memory into a valid WhereLoop that can be passed |
︙ | ︙ | |||
2268 2269 2270 2271 2272 2273 2274 | sqlite3DbFreeNN(db, p->u.btree.pIndex); p->u.btree.pIndex = 0; } } } /* | | < | < < < < | < | 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 | sqlite3DbFreeNN(db, p->u.btree.pIndex); p->u.btree.pIndex = 0; } } } /* ** Deallocate internal memory used by a WhereLoop object */ static void whereLoopClear(sqlite3 *db, WhereLoop *p){ if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFreeNN(db, p->aLTerm); whereLoopClearUnion(db, p); whereLoopInit(p); } /* ** Increase the memory allocation for pLoop->aLTerm[] to be at least n. */ static int whereLoopResize(sqlite3 *db, WhereLoop *p, int n){ WhereTerm **paNew; |
︙ | ︙ | |||
2303 2304 2305 2306 2307 2308 2309 | } /* ** Transfer content from the second pLoop into the first. */ static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){ whereLoopClearUnion(db, pTo); | < | < | < | > < > > > > > > < < < < < | | < | 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 | } /* ** 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->u, 0, sizeof(pTo->u)); 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 ){ pFrom->u.btree.pIndex = 0; } return SQLITE_OK; } /* ** Delete a WhereLoop object */ static void whereLoopDelete(sqlite3 *db, WhereLoop *p){ whereLoopClear(db, p); sqlite3DbFreeNN(db, p); } /* ** 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) ){ sqlite3DbFree(db, pLevel->u.in.aInLoop); } } sqlite3WhereClauseClear(&pWInfo->sWC); while( pWInfo->pLoops ){ WhereLoop *p = pWInfo->pLoops; pWInfo->pLoops = p->pNextLoop; whereLoopDelete(db, p); } sqlite3DbFreeNN(db, pWInfo); } /* ** Return TRUE if all of the following are true: ** ** (1) X has the same or lower cost that 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 |
︙ | ︙ | |||
2375 2376 2377 2378 2379 2380 2381 | 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 */ } | < > > > > | | | < < | | | < < | | | 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 | 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; if( pX->rRun >= pY->rRun ){ if( pX->rRun > pY->rRun ) return 0; /* X costs more than Y */ if( pX->nOut > pY->nOut ) return 0; /* X costs more than Y */ } 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 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, p->rRun, p->nOut-1)); pTemplate->rRun = p->rRun; pTemplate->nOut = p->nOut - 1; }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, p->rRun, p->nOut+1)); pTemplate->rRun = p->rRun; pTemplate->nOut = p->nOut + 1; } } } /* ** Search the list of WhereLoops in *ppPrev looking for one that can be ** replaced by pTemplate. |
︙ | ︙ | |||
2548 2549 2550 2551 2552 2553 2554 | if( pBuilder->iPlanLimit==0 ){ WHERETRACE(0xffffffff,("=== query planner search limit reached ===\n")); if( pBuilder->pOrSet ) pBuilder->pOrSet->n = 0; return SQLITE_DONE; } pBuilder->iPlanLimit--; | < < | > | | | | 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 | 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); whereLoopPrint(pTemplate, pBuilder->pWC); } #endif } return SQLITE_OK; } /* Look for an existing WhereLoop to replace with pTemplate */ whereLoopAdjustCost(pWInfo->pLoops, 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: "); whereLoopPrint(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: "); whereLoopPrint(p, pBuilder->pWC); sqlite3DebugPrintf(" with: "); }else{ sqlite3DebugPrintf(" add: "); } whereLoopPrint(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); |
︙ | ︙ | |||
2626 2627 2628 2629 2630 2631 2632 | if( ppTail==0 ) break; pToDel = *ppTail; if( pToDel==0 ) break; *ppTail = pToDel->pNextLoop; #if WHERETRACE_ENABLED /* 0x8 */ if( sqlite3WhereTrace & 0x8 ){ sqlite3DebugPrintf(" delete: "); | | | 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 | if( ppTail==0 ) break; pToDel = *ppTail; if( pToDel==0 ) break; *ppTail = pToDel->pNextLoop; #if WHERETRACE_ENABLED /* 0x8 */ if( sqlite3WhereTrace & 0x8 ){ sqlite3DebugPrintf(" delete: "); whereLoopPrint(pToDel, pBuilder->pWC); } #endif whereLoopDelete(db, pToDel); } } rc = whereLoopXfer(db, p, pTemplate); if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ |
︙ | ︙ | |||
2678 2679 2680 2681 2682 2683 2684 | 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); | | | < | | < < < < < < < < < < < < < < < < < < | < < < | < < < | < < | 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 | 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, k; 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++){ 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) ){ Expr *pRight = pTerm->pExpr->pRight; testcase( pTerm->pExpr->op==TK_IS ); if( sqlite3ExprIsInteger(pRight, &k) && k>=(-1) && k<=1 ){ k = 10; }else{ k = 20; } if( iReduce<k ) iReduce = k; } } } } if( pLoop->nOut > nRow-iReduce ) pLoop->nOut = nRow - iReduce; } /* ** Term pTerm is a vector range comparison operation. The first comparison ** in the vector can be optimized using column nEq of the index. This ** function returns the total number of vector elements that can be used ** as part of the range comparison. |
︙ | ︙ | |||
2778 2779 2780 2781 2782 2783 2784 | 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 */ | < < < | | | | 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 | 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 = pTerm->pExpr->pLeft->x.pList->a[i].pExpr; Expr *pRhs = pTerm->pExpr->pRight; if( pRhs->flags & EP_xIsSelect ){ 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 |
︙ | ︙ | |||
2837 2838 2839 2840 2841 2842 2843 | ** 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 */ | | | 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 | ** 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 */ struct SrcList_item *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 */ |
︙ | ︙ | |||
2862 2863 2864 2865 2866 2867 2868 | LogEst saved_nOut; /* Original value of pNew->nOut */ 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; | | < < < | | < < < | > > > | | > | | < | < < < | > > | | 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 | LogEst saved_nOut; /* Original value of pNew->nOut */ 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\n", pProbe->pTable->zName,pProbe->zName, pNew->u.btree.nEq)); 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 ); 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_STAT3_OR_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; /* 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 */ if( (pSrc->fg.jointype & JT_LEFT)!=0 && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) ){ continue; } if( IsUniqueIndex(pProbe) && saved_nEq==pProbe->nKeyCol-1 ){ pBuilder->bldFlags |= SQLITE_BLDF_UNIQUE; }else{ pBuilder->bldFlags |= SQLITE_BLDF_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( ExprHasProperty(pExpr, EP_xIsSelect) ){ /* "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); assert( nIn>0 ); /* RHS always has 2 or more terms... The parser ** changes "x IN (?)" into "x=?". */ } if( pProbe->hasStat1 && rLogSize>=10 ){ LogEst M, logK, safetyMargin; /* 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. ** |
︙ | ︙ | |||
2988 2989 2990 2991 2992 2993 2994 | ** 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); | | | < | < | < < < < < | < | < < < < < < | | | | | > > | | | | | | | | | | | | | | | | | | | | > > | | | < | | | | | < < < < < < < < < < < < < < < < < < < < < | 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 | ** 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); safetyMargin = 10; /* TUNING: extra weight for indexed IN */ if( M + logK + safetyMargin < nIn + rLogSize ){ WHERETRACE(0x40, ("Scan preferred over IN operator on column %d of \"%s\" (%d<%d)\n", saved_nEq, pProbe->zName, M+logK+10, nIn+rLogSize)); pNew->wsFlags |= WHERE_IN_SEEKSCAN; }else{ WHERETRACE(0x40, ("IN operator preferred on column %d of \"%s\" (%d>=%d)\n", saved_nEq, pProbe->zName, M+logK+10, nIn+rLogSize)); } } 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; } } }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 contraints 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; pNew->wsFlags |= WHERE_TOP_LIMIT; pNew->u.btree.nTop = 1; } }else{ assert( eOp & (WO_LT|WO_LE) ); testcase( eOp & WO_LT ); testcase( eOp & WO_LE ); pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT; pNew->u.btree.nTop = whereRangeVectorLen( pParse, pSrc->iCursor, pProbe, saved_nEq, pTerm ); pTop = pTerm; pBtm = (pNew->wsFlags & WHERE_BTM_LIMIT)!=0 ? pNew->aLTerm[pNew->nLTerm-2] : 0; } /* 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 stat3/stat4 data. Or, if there is no stat3/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_STAT3_OR_STAT4 tRowcnt nOut = 0; if( nInMul==0 && pProbe->nSample && pNew->u.btree.nEq<=pProbe->nSampleCol && ((eOp & WO_IN)==0 || !ExprHasProperty(pTerm->pExpr, EP_xIsSelect)) && OptimizationEnabled(db, SQLITE_Stat34) ){ 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( pNew->nOut>saved_nOut ) pNew->nOut = saved_nOut; pNew->nOut -= nIn; } } if( nOut==0 ) #endif { |
︙ | ︙ | |||
3148 3149 3150 3151 3152 3153 3154 | } } /* 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. */ | < < < < < < < < | < | < < < < < | | 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 | } } /* 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); nOutUnadjusted = pNew->nOut; pNew->rRun += nInMul + nIn; pNew->nOut += nInMul + nIn; whereLoopOutputAdjust(pBuilder->pWC, pNew, rSize); rc = whereLoopInsert(pBuilder, pNew); if( pNew->wsFlags & WHERE_COLUMN_RANGE ){ 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; #ifdef SQLITE_ENABLE_STAT3_OR_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; |
︙ | ︙ | |||
3213 3214 3215 3216 3217 3218 3219 | ** 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 | < < | 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 | ** 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++; |
︙ | ︙ | |||
3262 3263 3264 3265 3266 3267 3268 | 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++){ | | < | < < < < < < < < | | < | | < | < < < < < < < < < < < < < < < < < < < < < < < < | < < < | | | | < | < < < | | | | | | | | | | < < < < < < | < < | > < < | < | < | < < < < | | | | | < | | | | | | | | | < < < > < < < < < < < | | 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 | ExprList *pOB; ExprList *aColExpr; int ii, jj; if( pIndex->bUnordered ) return 0; if( (pOB = pBuilder->pWInfo->pOrderBy)==0 ) return 0; for(ii=0; ii<pOB->nExpr; ii++){ Expr *pExpr = sqlite3ExprSkipCollate(pOB->a[ii].pExpr); if( pExpr->op==TK_COLUMN && pExpr->iTable==iCursor ){ if( pExpr->iColumn<0 ) return 1; for(jj=0; jj<pIndex->nKeyCol; jj++){ if( pExpr->iColumn==pIndex->aiColumn[jj] ) return 1; } }else if( (aColExpr = pIndex->aColExpr)!=0 ){ for(jj=0; jj<pIndex->nKeyCol; jj++){ if( pIndex->aiColumn[jj]!=XN_EXPR ) continue; if( 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, WhereClause *pWC, Expr *pWhere){ int i; WhereTerm *pTerm; Parse *pParse = pWC->pWInfo->pParse; while( pWhere->op==TK_AND ){ if( !whereUsablePartialIndex(iTab,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 = pTerm->pExpr; if( (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->iRightJoinTable==iTab) && sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, iTab) ){ return 1; } } return 0; } /* ** Structure passed to the whereIsCoveringIndex Walker callback. */ struct CoveringIndexCheck { Index *pIdx; /* The index */ int iTabCur; /* Cursor number for the corresponding table */ }; /* ** Information passed in is pWalk->u.pCovIdxCk. Call is pCk. ** ** If the Expr node references the table with cursor pCk->iTabCur, then ** make sure that column is covered by the index pCk->pIdx. We know that ** all columns less than 63 (really BMS-1) are covered, so we don't need ** to check them. But we do need to check any column at 63 or greater. ** ** If the index does not cover the column, then set pWalk->eCode to ** non-zero and return WRC_Abort to stop the search. ** ** If this node does not disprove that the index can be a covering index, ** then just return WRC_Continue, to continue the search. */ static int whereIsCoveringIndexWalkCallback(Walker *pWalk, Expr *pExpr){ int i; /* Loop counter */ const Index *pIdx; /* The index of interest */ const i16 *aiColumn; /* Columns contained in the index */ u16 nColumn; /* Number of columns in the index */ if( pExpr->op!=TK_COLUMN && pExpr->op!=TK_AGG_COLUMN ) return WRC_Continue; if( pExpr->iColumn<(BMS-1) ) return WRC_Continue; if( pExpr->iTable!=pWalk->u.pCovIdxCk->iTabCur ) return WRC_Continue; pIdx = pWalk->u.pCovIdxCk->pIdx; aiColumn = pIdx->aiColumn; nColumn = pIdx->nColumn; for(i=0; i<nColumn; i++){ if( aiColumn[i]==pExpr->iColumn ) return WRC_Continue; } pWalk->eCode = 1; return WRC_Abort; } /* ** pIdx is an index that covers all of the low-number columns used by ** pWInfo->pSelect (columns from 0 through 62). But there are columns ** in pWInfo->pSelect beyond 62. This routine tries to answer the question ** of whether pIdx covers *all* columns in the query. ** ** Return 0 if pIdx is a covering index. Return non-zero if pIdx is ** not a covering index or if we are unable to determine if pIdx is a ** covering index. ** ** This routine is an optimization. It is always safe to return non-zero. ** But returning zero when non-zero should have been returned can lead to ** incorrect bytecode and assertion faults. */ static SQLITE_NOINLINE u32 whereIsCoveringIndex( WhereInfo *pWInfo, /* The WHERE clause context */ Index *pIdx, /* Index that is being tested */ int iTabCur /* Cursor for the table being indexed */ ){ int i; struct CoveringIndexCheck ck; Walker w; if( pWInfo->pSelect==0 ){ /* We don't have access to the full query, so we cannot check to see ** if pIdx is covering. Assume it is not. */ return 1; } for(i=0; i<pIdx->nColumn; i++){ if( pIdx->aiColumn[i]>=BMS-1 ) break; } if( i>=pIdx->nColumn ){ /* pIdx does not index any columns greater than 62, but we know from ** colMask that columns greater than 62 are used, so this is not a ** covering index */ return 1; } ck.pIdx = pIdx; ck.iTabCur = iTabCur; memset(&w, 0, sizeof(w)); w.xExprCallback = whereIsCoveringIndexWalkCallback; w.xSelectCallback = sqlite3SelectWalkNoop; w.u.pCovIdxCk = &ck; w.eCode = 0; sqlite3WalkSelect(&w, pWInfo->pSelect); return w.eCode; } /* ** Add all WhereLoop objects for a single table of the join where the table ** is identified by pBuilder->pNew->iTab. That table is guaranteed to be ** a b-tree table, not a virtual table. ** |
︙ | ︙ | |||
3504 3505 3506 3507 3508 3509 3510 | ){ 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 */ | | > | < | | > | | < < < | | < | | < < < | 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 | ){ 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 */ struct SrcList_item *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 */ LogEst rLogSize; /* Logarithm of the 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->pIBIndex ){ /* An INDEXED BY clause specifies a particular index to use */ pProbe = pSrc->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; rLogSize = estLog(rSize); #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->pIBIndex==0 /* Has no INDEXED BY clause */ && !pSrc->fg.notIndexed /* Has no NOT INDEXED clause */ && HasRowid(pTab) /* Not WITHOUT ROWID table. (FIXME: Why not?) */ && !pSrc->fg.isCorrelated /* Not a correlated subquery */ && !pSrc->fg.isRecursive /* Not a recursive common table expression. */ ){ /* Generate auto-index WhereLoops */ WhereTerm *pTerm; WhereTerm *pWCEnd = pWC->a + pWC->nTerm; for(pTerm=pWC->a; rc==SQLITE_OK && pTerm<pWCEnd; pTerm++){ 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( pTab->pSelect==0 && (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 ** is more than the usual guess of 10 rows, since we have no way ** of knowing how selective the index will ultimately be. It would ** not be unreasonable to make this value much larger. */ pNew->nOut = 43; assert( 43==sqlite3LogEst(20) ); pNew->rRun = sqlite3LogEstAdd(rLogSize,pNew->nOut); pNew->wsFlags = WHERE_AUTO_INDEX; pNew->prereq = mPrereq | pTerm->prereqRight; rc = whereLoopInsert(pBuilder, pNew); } } } #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->pIBIndex ? 0 : pProbe->pNext), iSortIdx++ ){ if( pProbe->pPartIdxWhere!=0 && !whereUsablePartialIndex(pSrc->iCursor, 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 */ |
︙ | ︙ | |||
3661 3662 3663 3664 3665 3666 3667 | ** better. */ #ifdef SQLITE_ENABLE_STAT4 pNew->rRun = rSize + 16 - 2*((pTab->tabFlags & TF_HasStat4)!=0); #else pNew->rRun = rSize + 16; #endif | < < < < > < | | < < < < < < < < < < < < < < < < < | < < < < < | < < | 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 | ** 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; if( m==TOPBIT ){ m = whereIsCoveringIndex(pWInfo, pProbe, pSrc->iCursor); } pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED; } /* Full scan via index */ if( b || !HasRowid(pTab) || pProbe->pPartIdxWhere!=0 || ( m==0 && pProbe->bUnordered==0 && (pProbe->szIdxRow<pTab->szTabRow) && (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 && sqlite3GlobalConfig.bUseCis && OptimizationEnabled(pWInfo->pParse->db, SQLITE_CoverIdxScan) ) |
︙ | ︙ | |||
3754 3755 3756 3757 3758 3759 3760 | } } pNew->rRun = sqlite3LogEstAdd(pNew->rRun, nLookup); } ApplyCostMultiplier(pNew->rRun, pTab->costMult); whereLoopOutputAdjust(pWC, pNew, rSize); | < < < < < < | < | | | < < < < < < < < < | 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 | } } pNew->rRun = sqlite3LogEstAdd(pNew->rRun, nLookup); } ApplyCostMultiplier(pNew->rRun, pTab->costMult); whereLoopOutputAdjust(pWC, pNew, rSize); rc = whereLoopInsert(pBuilder, pNew); pNew->nOut = rSize; if( rc ) break; } } pBuilder->bldFlags = 0; rc = whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 0); if( pBuilder->bldFlags==SQLITE_BLDF_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_STAT3_OR_STAT4 sqlite3Stat4ProbeFree(pBuilder->pRec); pBuilder->nRecValid = 0; pBuilder->pRec = 0; #endif } return rc; } #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Argument pIdxInfo is already populated with all constraints that may ** be used by the virtual table identified by pBuilder->pNew->iTab. This ** function marks a subset of those constraints usable, invokes the ** xBestIndex method and adds the returned plan to pBuilder. ** ** A constraint is marked usable if: |
︙ | ︙ | |||
3823 3824 3825 3826 3827 3828 3829 | static int whereLoopAddVirtualOne( WhereLoopBuilder *pBuilder, Bitmask mPrereq, /* Mask of tables that must be used. */ Bitmask mUsable, /* Mask of usable tables */ u16 mExclude, /* Exclude terms using these operators */ sqlite3_index_info *pIdxInfo, /* Populated object for xBestIndex */ u16 mNoOmit, /* Do not omit these constraints */ | | < < | < < | | | | 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 | static int whereLoopAddVirtualOne( WhereLoopBuilder *pBuilder, Bitmask mPrereq, /* Mask of tables that must be used. */ Bitmask mUsable, /* Mask of usable tables */ u16 mExclude, /* Exclude terms using these operators */ sqlite3_index_info *pIdxInfo, /* Populated object for xBestIndex */ u16 mNoOmit, /* Do not omit these constraints */ int *pbIn /* OUT: True if plan uses an IN(...) op */ ){ WhereClause *pWC = pBuilder->pWC; 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; struct SrcList_item *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 ** arguments mUsable and mExclude. */ pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; for(i=0; i<nConstraint; i++, pIdxCons++){ WhereTerm *pTerm = &pWC->a[pIdxCons->iTermOffset]; pIdxCons->usable = 0; if( (pTerm->prereqRight & mUsable)==pTerm->prereqRight && (pTerm->eOperator & mExclude)==0 ){ pIdxCons->usable = 1; } } /* Initialize the output fields of the sqlite3_index_info structure */ memset(pUsage, 0, sizeof(pUsage[0])*nConstraint); assert( pIdxInfo->needToFreeIdxStr==0 ); pIdxInfo->idxStr = 0; pIdxInfo->idxNum = 0; pIdxInfo->orderByConsumed = 0; pIdxInfo->estimatedCost = SQLITE_BIG_DBL / (double)2; pIdxInfo->estimatedRows = 25; pIdxInfo->idxFlags = 0; pIdxInfo->colUsed = (sqlite3_int64)pSrc->colUsed; /* Invoke the virtual table xBestIndex() method */ rc = vtabBestIndex(pParse, pSrc->pTab, pIdxInfo); if( rc ){ if( rc==SQLITE_CONSTRAINT ){ /* If the xBestIndex method returns SQLITE_CONSTRAINT, that means ** that the particular combination of parameters provided is unusable. ** Make no entries in the loop table. */ WHERETRACE(0xffff, (" ^^^^--- non-viable plan rejected!\n")); return SQLITE_OK; } return rc; } mxTerm = -1; assert( pNew->nLSlot>=nConstraint ); for(i=0; i<nConstraint; i++) pNew->aLTerm[i] = 0; pNew->u.vtab.omitMask = 0; pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; for(i=0; i<nConstraint; i++, pIdxCons++){ int iTerm; if( (iTerm = pUsage[i].argvIndex - 1)>=0 ){ WhereTerm *pTerm; int j = pIdxCons->iTermOffset; if( iTerm>=nConstraint |
︙ | ︙ | |||
3912 3913 3914 3915 3916 3917 3918 | 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 ); | < < < | < < < < < < < < < | | < < < < < < < < < < < | | < < < < | 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 | 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( iTerm<16 && pUsage[i].omit ) pNew->u.vtab.omitMask |= 1<<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->u.vtab.omitMask &= ~mNoOmit; 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); |
︙ | ︙ | |||
3987 3988 3989 3990 3991 3992 3993 | pNew->wsFlags &= ~WHERE_ONEROW; } rc = whereLoopInsert(pBuilder, pNew); if( pNew->u.vtab.needFree ){ sqlite3_free(pNew->u.vtab.idxStr); pNew->u.vtab.needFree = 0; } | | | | < < | < < < | < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | pNew->wsFlags &= ~WHERE_ONEROW; } rc = whereLoopInsert(pBuilder, pNew); if( pNew->u.vtab.needFree ){ sqlite3_free(pNew->u.vtab.idxStr); pNew->u.vtab.needFree = 0; } WHERETRACE(0xffff, (" bIn=%d prereqIn=%04llx prereqOut=%04llx\n", *pbIn, (sqlite3_uint64)mPrereq, (sqlite3_uint64)(pNew->prereq & ~mPrereq))); return rc; } /* ** If this function is invoked from within an xBestIndex() callback, it ** returns a pointer to a buffer containing the name of the collation ** sequence associated with element iCons of the sqlite3_index_info.aConstraint ** array. Or, if iCons is out of range or there is no active xBestIndex ** call, return NULL. */ const char *sqlite3_vtab_collation(sqlite3_index_info *pIdxInfo, int iCons){ 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 = sqlite3BinaryCompareCollSeq(pHidden->pParse, pX->pLeft, pX->pRight); } zRet = (pC ? pC->zName : sqlite3StrBINARY); } return zRet; } /* ** Add all WhereLoop objects for a table of the join identified by ** pBuilder->pNew->iTab. That table is guaranteed to be a virtual table. ** ** If there are no LEFT or CROSS JOIN joins in the query, both mPrereq and ** mUnusable are set to 0. Otherwise, mPrereq is a mask of all FROM clause ** entries that occur before the virtual table in the FROM clause and are |
︙ | ︙ | |||
4149 4150 4151 4152 4153 4154 4155 | 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 */ | | < | > | | | < < < < < < < < | | | 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 | 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 */ struct SrcList_item *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; assert( (mPrereq & mUnusable)==0 ); pWInfo = pBuilder->pWInfo; pParse = pWInfo->pParse; pWC = pBuilder->pWC; pNew = pBuilder->pNew; pSrc = &pWInfo->pTabList->a[pNew->iTab]; assert( IsVirtual(pSrc->pTab) ); p = allocateIndexInfo(pParse, pWC, mUnusable, pSrc, pBuilder->pOrderBy, &mNoOmit); if( p==0 ) return SQLITE_NOMEM_BKPT; pNew->rSetup = 0; pNew->wsFlags = WHERE_VIRTUALTABLE; pNew->nLTerm = 0; pNew->u.vtab.needFree = 0; nConstraint = p->nConstraint; if( whereLoopResize(pParse->db, pNew, nConstraint) ){ sqlite3DbFree(pParse->db, p); return SQLITE_NOMEM_BKPT; } /* 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. */ if( bIn ){ WHERETRACE(0x40, (" VirtualOne: all usable w/o IN\n")); rc = whereLoopAddVirtualOne( pBuilder, mPrereq, ALLBITS, WO_IN, p, mNoOmit, &bIn); assert( bIn==0 ); mBestNoIn = pNew->prereq & ~mPrereq; if( mBestNoIn==0 ){ seenZero = 1; seenZeroNoIN = 1; } } |
︙ | ︙ | |||
4230 4231 4232 4233 4234 4235 4236 | pWC->a[p->aConstraint[i].iTermOffset].prereqRight & ~mPrereq ); if( mThis>mPrev && mThis<mNext ) mNext = mThis; } mPrev = mNext; if( mNext==ALLBITS ) break; if( mNext==mBest || mNext==mBestNoIn ) continue; | | | | | | | | | 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 | pWC->a[p->aConstraint[i].iTermOffset].prereqRight & ~mPrereq ); if( mThis>mPrev && mThis<mNext ) mNext = mThis; } mPrev = mNext; if( mNext==ALLBITS ) break; if( mNext==mBest || mNext==mBestNoIn ) continue; WHERETRACE(0x40, (" VirtualOne: mPrev=%04llx mNext=%04llx\n", (sqlite3_uint64)mPrev, (sqlite3_uint64)mNext)); rc = whereLoopAddVirtualOne( pBuilder, mPrereq, mNext|mPrereq, 0, p, mNoOmit, &bIn); if( pNew->prereq==mPrereq ){ seenZero = 1; if( bIn==0 ) seenZeroNoIN = 1; } } /* If the calls to xBestIndex() in the above loop did not find a plan ** that requires no source tables at all (i.e. one guaranteed to be ** usable), make a call here with all source tables disabled */ if( rc==SQLITE_OK && seenZero==0 ){ WHERETRACE(0x40, (" VirtualOne: all disabled\n")); rc = whereLoopAddVirtualOne( pBuilder, mPrereq, mPrereq, 0, p, mNoOmit, &bIn); if( bIn==0 ) seenZeroNoIN = 1; } /* If the calls to xBestIndex() have so far failed to find a plan ** that requires no source tables at all and does not use an IN(...) ** operator, make a final call to obtain one here. */ if( rc==SQLITE_OK && seenZeroNoIN==0 ){ WHERETRACE(0x40, (" VirtualOne: all disabled and w/o IN\n")); rc = whereLoopAddVirtualOne( pBuilder, mPrereq, mPrereq, WO_IN, p, mNoOmit, &bIn); } } if( p->needToFreeIdxStr ) sqlite3_free(p->idxStr); sqlite3DbFreeNN(pParse->db, p); WHERETRACE(0x800, ("END %s.addVirtual(), rc=%d\n", pSrc->pTab->zName, rc)); return rc; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ /* ** Add WhereLoop entries to handle OR terms. This works for either |
︙ | ︙ | |||
4285 4286 4287 4288 4289 4290 4291 | WhereLoop *pNew; WhereTerm *pTerm, *pWCEnd; int rc = SQLITE_OK; int iCur; WhereClause tempWC; WhereLoopBuilder sSubBuild; WhereOrSet sSum, sCur; | | < < < > | < | | < | | 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 | WhereLoop *pNew; WhereTerm *pTerm, *pWCEnd; int rc = SQLITE_OK; int iCur; WhereClause tempWC; WhereLoopBuilder sSubBuild; WhereOrSet sSum, sCur; struct SrcList_item *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; for(pTerm=pWC->a; pTerm<pWCEnd && rc==SQLITE_OK; pTerm++){ if( (pTerm->eOperator & WO_OR)!=0 && (pTerm->u.pOrInfo->indexable & pNew->maskSelf)!=0 ){ WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc; WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm]; WhereTerm *pOrTerm; int once = 1; int i, j; sSubBuild = *pBuilder; sSubBuild.pOrderBy = 0; sSubBuild.pOrSet = &sCur; WHERETRACE(0x200, ("Begin processing OR-clause %p\n", pTerm)); for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){ if( (pOrTerm->eOperator & WO_AND)!=0 ){ sSubBuild.pWC = &pOrTerm->u.pAndInfo->wc; }else if( pOrTerm->leftCursor==iCur ){ tempWC.pWInfo = pWC->pWInfo; tempWC.pOuter = pWC; tempWC.op = TK_AND; tempWC.nTerm = 1; tempWC.a = pOrTerm; sSubBuild.pWC = &tempWC; }else{ continue; } sCur.n = 0; #ifdef WHERETRACE_ENABLED WHERETRACE(0x200, ("OR-term %d of %p has %d subterms:\n", (int)(pOrTerm-pOrWC->a), pTerm, sSubBuild.pWC->nTerm)); if( sqlite3WhereTrace & 0x400 ){ sqlite3WhereClausePrint(sSubBuild.pWC); } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pItem->pTab) ){ rc = whereLoopAddVirtual(&sSubBuild, mPrereq, mUnusable); }else #endif { rc = whereLoopAddBtree(&sSubBuild, mPrereq); } if( rc==SQLITE_OK ){ rc = whereLoopAddOr(&sSubBuild, mPrereq, mUnusable); } assert( rc==SQLITE_OK || sCur.n==0 ); if( sCur.n==0 ){ sSum.n = 0; break; }else if( once ){ whereOrMove(&sSum, &sCur); once = 0; }else{ |
︙ | ︙ | |||
4389 4390 4391 4392 4393 4394 4395 | ** the planner may elect to "OR" together a full-table scan and an ** index lookup. And other similarly odd results. */ pNew->rRun = sSum.a[i].rRun + 1; pNew->nOut = sSum.a[i].nOut; pNew->prereq = sSum.a[i].prereq; rc = whereLoopInsert(pBuilder, pNew); } | | | | < < | | < < < < < < < | < | < < < < < < < | < < < < < | > | | | 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 | ** the planner may elect to "OR" together a full-table scan and an ** index lookup. And other similarly odd results. */ pNew->rRun = sSum.a[i].rRun + 1; pNew->nOut = sSum.a[i].nOut; pNew->prereq = sSum.a[i].prereq; rc = whereLoopInsert(pBuilder, pNew); } WHERETRACE(0x200, ("End processing OR-clause %p\n", pTerm)); } } return rc; } /* ** Add all WhereLoop objects for all tables */ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ WhereInfo *pWInfo = pBuilder->pWInfo; Bitmask mPrereq = 0; Bitmask mPrior = 0; int iTab; SrcList *pTabList = pWInfo->pTabList; struct SrcList_item *pItem; struct SrcList_item *pEnd = &pTabList->a[pWInfo->nLevel]; sqlite3 *db = pWInfo->pParse->db; int rc = SQLITE_OK; WhereLoop *pNew; u8 priorJointype = 0; /* 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|priorJointype) & (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; } priorJointype = pItem->fg.jointype; #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pItem->pTab) ){ struct SrcList_item *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 #endif /* SQLITE_OMIT_VIRTUALTABLE */ { |
︙ | ︙ | |||
4564 4565 4566 4567 4568 4569 4570 | 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; | < | < | < < < < | | | < | | < | | < < < < < < < | < | < < < | < < | < | 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 | 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 ) 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 ) obSat = obDone; break; }else{ pLoop->u.btree.nIdxCol = 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 = sqlite3ExprSkipCollate(pOrderBy->a[i].pExpr); if( pOBExpr->op!=TK_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 ); 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 ){ if( sqlite3ExprCollSeqMatch(pWInfo->pParse, pOrderBy->a[i].pExpr, pTerm->pExpr)==0 ){ 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)); isOrderDistinct = IsUniqueIndex(pIndex); } /* Loop through all columns of the index and deal with the ones ** that are not constrained by == or IN. */ rev = revSet = 0; 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). ** ** 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 ){ 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 |
︙ | ︙ | |||
4699 4700 4701 4702 4703 4704 4705 | } /* 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]; | | | | | | | | | | < < < < | < | | | < | < | < < < < | < < < < < < < | 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 | } /* 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]; 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 */ if( isOrderDistinct && iColumn>=0 && j>=pLoop->u.btree.nEq && pIndex->pTable->aCol[iColumn].notNull==0 ){ 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 = sqlite3ExprSkipCollate(pOrderBy->a[i].pExpr); testcase( wctrlFlags & WHERE_GROUPBY ); testcase( wctrlFlags & WHERE_DISTINCTBY ); if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0; if( iColumn>=XN_ROWID ){ if( pOBExpr->op!=TK_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; } pLoop->u.btree.nIdxCol = 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].sortOrder ) isMatch = 0; }else{ rev = revIdx ^ pOrderBy->a[i].sortOrder; if( rev ) *pRevMask |= MASKBIT(iLoop); revSet = 1; } } if( isMatch ){ if( iColumn==XN_ROWID ){ testcase( distinctColumns==0 ); distinctColumns = 1; } obSat |= MASKBIT(i); }else{ |
︙ | ︙ | |||
4814 4815 4816 4817 4818 4819 4820 | } } } } /* 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--){ | | | 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 | } } } } /* 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 = MASKBIT(i) - 1; if( (obSat&m)==m ) return i; } return 0; } return -1; } |
︙ | ︙ | |||
4847 4848 4849 4850 4851 4852 4853 | ** ** then ** ** SELECT * FROM t1 GROUP BY x,y ORDER BY x,y; -- IsSorted()==1 ** SELECT * FROM t1 GROUP BY y,x ORDER BY y,x; -- IsSorted()==0 */ int sqlite3WhereIsSorted(WhereInfo *pWInfo){ | | | 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 | ** ** then ** ** SELECT * FROM t1 GROUP BY x,y ORDER BY x,y; -- IsSorted()==1 ** SELECT * FROM t1 GROUP BY y,x ORDER BY y,x; -- IsSorted()==0 */ int sqlite3WhereIsSorted(WhereInfo *pWInfo){ assert( pWInfo->wctrlFlags & WHERE_GROUPBY ); assert( pWInfo->wctrlFlags & WHERE_SORTBYGROUP ); return pWInfo->sorted; } #ifdef WHERETRACE_ENABLED /* For debugging use only: */ static const char *wherePathName(WherePath *pPath, int nLoop, WhereLoop *pLast){ |
︙ | ︙ | |||
4870 4871 4872 4873 4874 4875 4876 | /* ** Return the cost of sorting nRow rows, assuming that the keys have ** nOrderby columns and that the first nSorted columns are already in ** order. */ static LogEst whereSortingCost( | | | | | | | | | < < < < < | < < < | | < < | | < < < | < | < < < | < < < < < | < < < < < | 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 | /* ** Return the cost of sorting nRow rows, assuming that the keys have ** nOrderby columns and that the first nSorted columns are already in ** order. */ static LogEst whereSortingCost( WhereInfo *pWInfo, LogEst nRow, int nOrderBy, int nSorted ){ /* TUNING: Estimated cost of a full external sort, where N is ** the number of rows to sort is: ** ** cost = (3.0 * N * log(N)). ** ** 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 */ if( (pWInfo->wctrlFlags & WHERE_USE_LIMIT)!=0 && pWInfo->iLimit<nRow ){ nRow = pWInfo->iLimit; } rSortCost += estLog(nRow); return rSortCost; } /* ** Given the list of WhereLoop objects at pWInfo->pLoops, this routine |
︙ | ︙ | |||
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 | ** Return SQLITE_OK on success or SQLITE_NOMEM of a memory allocation ** error occurs. */ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ int mxChoice; /* Maximum number of simultaneous paths tracked */ int nLoop; /* Number of terms in the join */ Parse *pParse; /* Parsing context */ int iLoop; /* Loop counter over the terms of the join */ int ii, jj; /* Loop counters */ int mxI = 0; /* Index of next entry to replace */ int nOrderBy; /* Number of ORDER BY clause terms */ LogEst mxCost = 0; /* Maximum cost of a set of paths */ LogEst mxUnsorted = 0; /* Maximum unsorted cost of a set of path */ int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */ WherePath *aFrom; /* All nFrom paths at the previous level */ WherePath *aTo; /* The nTo best paths at the current level */ WherePath *pFrom; /* An element of aFrom[] that we are working on */ WherePath *pTo; /* An element of aTo[] that we are working on */ WhereLoop *pWLoop; /* One of the WhereLoop objects */ WhereLoop **pX; /* Used to divy up the pSpace memory */ LogEst *aSortCost = 0; /* Sorting and partial sorting costs */ char *pSpace; /* Temporary memory used by this routine */ int nSpace; /* Bytes of space allocated at pSpace */ pParse = pWInfo->pParse; nLoop = pWInfo->nLevel; /* TUNING: For simple queries, only the best path is tracked. ** For 2-way joins, the 5 best paths are followed. ** For joins of 3 or more tables, track the 10 best paths */ mxChoice = (nLoop<=1) ? 1 : (nLoop==2 ? 5 : 10); assert( nLoop<=pWInfo->pTabList->nSrc ); WHERETRACE(0x002, ("---- begin solver. (nRowEst=%d)\n", nRowEst)); | > > | 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 | ** Return SQLITE_OK on success or SQLITE_NOMEM of a memory allocation ** error occurs. */ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){ int mxChoice; /* Maximum number of simultaneous paths tracked */ int nLoop; /* Number of terms in the join */ Parse *pParse; /* Parsing context */ sqlite3 *db; /* The database connection */ int iLoop; /* Loop counter over the terms of the join */ int ii, jj; /* Loop counters */ int mxI = 0; /* Index of next entry to replace */ int nOrderBy; /* Number of ORDER BY clause terms */ LogEst mxCost = 0; /* Maximum cost of a set of paths */ LogEst mxUnsorted = 0; /* Maximum unsorted cost of a set of path */ int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */ WherePath *aFrom; /* All nFrom paths at the previous level */ WherePath *aTo; /* The nTo best paths at the current level */ WherePath *pFrom; /* An element of aFrom[] that we are working on */ WherePath *pTo; /* An element of aTo[] that we are working on */ WhereLoop *pWLoop; /* One of the WhereLoop objects */ WhereLoop **pX; /* Used to divy up the pSpace memory */ LogEst *aSortCost = 0; /* Sorting and partial sorting costs */ char *pSpace; /* Temporary memory used by this routine */ int nSpace; /* Bytes of space allocated at pSpace */ pParse = pWInfo->pParse; db = pParse->db; nLoop = pWInfo->nLevel; /* TUNING: For simple queries, only the best path is tracked. ** For 2-way joins, the 5 best paths are followed. ** For joins of 3 or more tables, track the 10 best paths */ mxChoice = (nLoop<=1) ? 1 : (nLoop==2 ? 5 : 10); assert( nLoop<=pWInfo->pTabList->nSrc ); WHERETRACE(0x002, ("---- begin solver. (nRowEst=%d)\n", nRowEst)); |
︙ | ︙ | |||
4985 4986 4987 4988 4989 4990 4991 | }else{ nOrderBy = pWInfo->pOrderBy->nExpr; } /* Allocate and initialize space for aTo, aFrom and aSortCost[] */ nSpace = (sizeof(WherePath)+sizeof(WhereLoop*)*nLoop)*mxChoice*2; nSpace += sizeof(LogEst) * nOrderBy; | | | 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 | }else{ nOrderBy = pWInfo->pOrderBy->nExpr; } /* Allocate and initialize space for aTo, aFrom and aSortCost[] */ nSpace = (sizeof(WherePath)+sizeof(WhereLoop*)*nLoop)*mxChoice*2; nSpace += sizeof(LogEst) * nOrderBy; pSpace = sqlite3DbMallocRawNN(db, nSpace); if( pSpace==0 ) return SQLITE_NOMEM_BKPT; aTo = (WherePath*)pSpace; aFrom = aTo+mxChoice; memset(aFrom, 0, sizeof(aFrom[0])); pX = (WhereLoop**)(aFrom+mxChoice); for(ii=mxChoice*2, pFrom=aTo; ii>0; ii--, pFrom++, pX += nLoop){ pFrom->aLoop = pX; |
︙ | ︙ | |||
5035 5036 5037 5038 5039 5040 5041 | for(iLoop=0; iLoop<nLoop; iLoop++){ nTo = 0; for(ii=0, pFrom=aFrom; ii<nFrom; ii++, pFrom++){ for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){ LogEst nOut; /* Rows visited by (pFrom+pWLoop) */ LogEst rCost; /* Cost of path (pFrom+pWLoop) */ LogEst rUnsorted; /* Unsorted cost of (pFrom+pWLoop) */ | | | < < | | < < < < < < < | 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 | for(iLoop=0; iLoop<nLoop; iLoop++){ nTo = 0; for(ii=0, pFrom=aFrom; ii<nFrom; ii++, pFrom++){ for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){ LogEst nOut; /* Rows visited by (pFrom+pWLoop) */ LogEst rCost; /* Cost of path (pFrom+pWLoop) */ LogEst rUnsorted; /* Unsorted cost of (pFrom+pWLoop) */ i8 isOrdered = pFrom->isOrdered; /* isOrdered for (pFrom+pWLoop) */ Bitmask maskNew; /* Mask of src visited by (..) */ Bitmask revMask = 0; /* Mask of rev-order loops for (..) */ if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue; if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue; if( (pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 && pFrom->nRow<3 ){ /* Do not use an automatic index if the this loop is expected ** to run less than 1.25 times. It is tempting to also exclude ** automatic index usage on an outer loop, but sometimes an automatic ** index is useful in the outer loop of a correlated subquery. */ assert( 10==sqlite3LogEst(2) ); continue; } /* At this point, pWLoop is a candidate to be the next loop. ** Compute its cost */ rUnsorted = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow); rUnsorted = sqlite3LogEstAdd(rUnsorted, pFrom->rUnsorted); nOut = pFrom->nRow + pWLoop->nOut; maskNew = pFrom->maskLoop | pWLoop->maskSelf; if( isOrdered<0 ){ isOrdered = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags, iLoop, pWLoop, &revMask); }else{ revMask = pFrom->revLoop; } if( isOrdered>=0 && isOrdered<nOrderBy ){ if( aSortCost[isOrdered]==0 ){ aSortCost[isOrdered] = whereSortingCost( pWInfo, nRowEst, nOrderBy, isOrdered ); } /* TUNING: Add a small extra penalty (5) to sorting as an ** extra encouragment to the query planner to select a plan ** where the rows emerge in the correct order without any sorting ** required. */ rCost = sqlite3LogEstAdd(rUnsorted, aSortCost[isOrdered]) + 5; WHERETRACE(0x002, ("---- sort cost=%-3d (%d/%d) increases cost %3d to %-3d\n", aSortCost[isOrdered], (nOrderBy-isOrdered), nOrderBy, rUnsorted, rCost)); }else{ rCost = rUnsorted; rUnsorted -= 2; /* TUNING: Slight bias in favor of no-sort plans */ } /* Check to see if pWLoop should be added to the set of ** mxChoice best-so-far paths. ** ** First look for an existing path among best-so-far paths ** that covers the same set of loops and has the same isOrdered ** setting as the current path candidate. ** |
︙ | ︙ | |||
5243 5244 5245 5246 5247 5248 5249 | aTo = aFrom; aFrom = pFrom; nFrom = nTo; } if( nFrom==0 ){ sqlite3ErrorMsg(pParse, "no query solution"); | | | 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 | aTo = aFrom; aFrom = pFrom; nFrom = nTo; } if( nFrom==0 ){ sqlite3ErrorMsg(pParse, "no query solution"); sqlite3DbFreeNN(db, pSpace); return SQLITE_ERROR; } /* Find the lowest cost path. pFrom will be left pointing to that path */ pFrom = aFrom; for(ii=1; ii<nFrom; ii++){ if( pFrom->rCost>aFrom[ii].rCost ) pFrom = &aFrom[ii]; |
︙ | ︙ | |||
5274 5275 5276 5277 5278 5279 5280 | WHERE_DISTINCTBY, nLoop-1, pFrom->aLoop[nLoop-1], ¬Used); if( rc==pWInfo->pResultSet->nExpr ){ pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; } } pWInfo->bOrderedInnerLoop = 0; if( pWInfo->pOrderBy ){ | < > < < < < < < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < | < < < < | < | < | 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 | WHERE_DISTINCTBY, nLoop-1, pFrom->aLoop[nLoop-1], ¬Used); if( rc==pWInfo->pResultSet->nExpr ){ pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; } } pWInfo->bOrderedInnerLoop = 0; if( pWInfo->pOrderBy ){ if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){ if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){ pWInfo->eDistinct = WHERE_DISTINCT_ORDERED; } }else{ pWInfo->nOBSat = pFrom->isOrdered; pWInfo->revMask = pFrom->revLoop; if( pWInfo->nOBSat<=0 ){ pWInfo->nOBSat = 0; if( nLoop>0 ){ u32 wsFlags = pFrom->aLoop[nLoop-1]->wsFlags; if( (wsFlags & WHERE_ONEROW)==0 && (wsFlags&(WHERE_IPK|WHERE_COLUMN_IN))!=(WHERE_IPK|WHERE_COLUMN_IN) ){ Bitmask m = 0; int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy, pFrom, WHERE_ORDERBY_LIMIT, nLoop-1, pFrom->aLoop[nLoop-1], &m); testcase( wsFlags & WHERE_IPK ); 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, pFrom, 0, nLoop-1, pFrom->aLoop[nLoop-1], &revMask ); assert( pWInfo->sorted==0 ); if( nOrder==pWInfo->pOrderBy->nExpr ){ pWInfo->sorted = 1; pWInfo->revMask = revMask; } } } pWInfo->nRowOut = pFrom->nRow; /* Free temporary memory and return success */ sqlite3DbFreeNN(db, pSpace); return SQLITE_OK; } /* ** This routine implements a heuristic designed to improve query planning. ** This routine is called in between the first and second call to ** wherePathSolver(). Hence the name "Interstage" "Heuristic". ** ** The first call to wherePathSolver() (hereafter just "solver()") computes ** the best path without regard to the order of the outputs. The second call ** to the solver() builds upon the first call to try to find an alternative ** path that satisfies the ORDER BY clause. ** ** This routine looks at the results of the first solver() run, and for ** every FROM clause term in the resulting query plan that uses an equality ** constraint against an index, disable other WhereLoops for that same ** FROM clause term that would try to do a full-table scan. This prevents ** an index search from being converted into a full-table scan in order to ** satisfy an ORDER BY clause, since even though we might get slightly better ** performance using the full-scan without sorting if the output size ** estimates are very precise, we might also get severe performance ** degradation using the full-scan if the output size estimate is too large. ** It is better to err on the side of caution. ** ** Except, if the first solver() call generated a full-table scan in an outer ** loop then stop this analysis at the first full-scan, since the second ** solver() run might try to swap that full-scan for another in order to ** get the output into the correct order. In other words, we allow a ** rewrite like this: ** ** First Solver() Second Solver() ** |-- SCAN t1 |-- SCAN t2 ** |-- SEARCH t2 `-- SEARCH t1 ** `-- SORT USING B-TREE ** ** The purpose of this routine is to disallow rewrites such as: ** ** First Solver() Second Solver() ** |-- SEARCH t1 |-- SCAN t2 <--- bad! ** |-- SEARCH t2 `-- SEARCH t1 ** `-- SORT USING B-TREE ** ** See test cases in test/whereN.test for the real-world query that ** originally provoked this heuristic. */ static SQLITE_NOINLINE void whereInterstageHeuristic(WhereInfo *pWInfo){ int i; #ifdef WHERETRACE_ENABLED int once = 0; #endif for(i=0; i<pWInfo->nLevel; i++){ WhereLoop *p = pWInfo->a[i].pWLoop; if( p==0 ) break; if( (p->wsFlags & WHERE_VIRTUALTABLE)!=0 ) continue; if( (p->wsFlags & (WHERE_COLUMN_EQ|WHERE_COLUMN_NULL|WHERE_COLUMN_IN))!=0 ){ u8 iTab = p->iTab; WhereLoop *pLoop; for(pLoop=pWInfo->pLoops; pLoop; pLoop=pLoop->pNextLoop){ if( pLoop->iTab!=iTab ) continue; if( (pLoop->wsFlags & (WHERE_CONSTRAINT|WHERE_AUTO_INDEX))!=0 ){ /* Auto-index and index-constrained loops allowed to remain */ continue; } #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace & 0x80 ){ if( once==0 ){ sqlite3DebugPrintf("Loops disabled by interstage heuristic:\n"); once = 1; } whereLoopPrint(pLoop, &pWInfo->sWC); } #endif /* WHERETRACE_ENABLED */ pLoop->prereq = ALLBITS; /* Prevent 2nd solver() from using this one */ } }else{ break; } } } /* ** Most queries use only a single table (they are not joins) and have ** simple == constraints against indexed fields. This routine attempts ** to plan those simple cases using much less ceremony than the ** general-purpose query planner, and thereby yield faster sqlite3_prepare() ** times for the common case. ** ** 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; struct SrcList_item *pItem; WhereClause *pWC; WhereTerm *pTerm; WhereLoop *pLoop; int iCur; int j; Table *pTab; Index *pIdx; 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 = sqlite3WhereFindTerm(pWC, iCur, -1, 0, WO_EQ|WO_IS, 0); 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 = sqlite3WhereFindTerm(pWC, iCur, j, 0, opMask, pIdx); 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 ){ |
︙ | ︙ | |||
5418 5419 5420 5421 5422 5423 5424 | 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; } | < < < < < < | 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 | 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; } /* |
︙ | ︙ | |||
5458 5459 5460 5461 5462 5463 5464 | w.eCode = 1; w.xExprCallback = exprNodeIsDeterministic; w.xSelectCallback = sqlite3SelectWalkFail; sqlite3WalkExpr(&w, p); return w.eCode; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | < < < < < < < < < < | < < < < < < | | < < < | 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 | w.eCode = 1; w.xExprCallback = exprNodeIsDeterministic; w.xSelectCallback = sqlite3SelectWalkFail; sqlite3WalkExpr(&w, p); return w.eCode; } /* ** The index pIdx is used by a query and contains one or more expressions. ** In other words pIdx is an index on an expression. iIdxCur is the cursor ** number for the index and iDataCur is the cursor number for the corresponding ** table. ** ** This routine adds IndexedExpr entries to the Parse->pIdxExpr field for ** each of the expressions in the index so that the expression code generator ** will know to replace occurrences of the indexed expression with ** references to the corresponding column of the index. */ static SQLITE_NOINLINE void whereAddIndexedExpr( Parse *pParse, /* Add IndexedExpr entries to pParse->pIdxExpr */ Index *pIdx, /* The index-on-expression that contains the expressions */ int iIdxCur, /* Cursor number for pIdx */ struct SrcList_item *pTabItem /* The FROM clause entry for the table */ ){ int i; IndexedExpr *p; assert( pIdx->bHasExpr ); for(i=0; i<pIdx->nColumn; i++){ Expr *pExpr; int j = pIdx->aiColumn[i]; if( j==XN_EXPR ){ pExpr = pIdx->aColExpr->a[i].pExpr; }else{ continue; } if( sqlite3ExprIsConstant(pExpr) ) continue; p = sqlite3DbMallocRaw(pParse->db, sizeof(IndexedExpr)); if( p==0 ) break; p->pIENext = pParse->pIdxExpr; p->pExpr = sqlite3ExprDup(pParse->db, pExpr, 0); p->iDataCur = pTabItem->iCursor; p->iIdxCur = iIdxCur; p->iIdxCol = i; p->bMaybeNullRow = (pTabItem->fg.jointype & JT_LEFT)!=0; #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS p->zIdxName = pIdx->zName; #endif pParse->pIdxExpr = p; } } /* ** 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 |
︙ | ︙ | |||
5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 | /* Variable initialization */ db = pParse->db; memset(&sWLB, 0, sizeof(sWLB)); /* An ORDER/GROUP BY clause of more than 63 terms cannot be optimized */ testcase( pOrderBy && pOrderBy->nExpr==BMS-1 ); if( pOrderBy && pOrderBy->nExpr>=BMS ) pOrderBy = 0; /* The number of tables in the FROM clause is limited by the number of ** bits in a Bitmask */ testcase( pTabList->nSrc==BMS ); if( pTabList->nSrc>BMS ){ sqlite3ErrorMsg(pParse, "at most %d tables in a join", BMS); | > > > > > > > | 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 | /* Variable initialization */ db = pParse->db; memset(&sWLB, 0, sizeof(sWLB)); /* An ORDER/GROUP BY clause of more than 63 terms cannot be optimized */ testcase( pOrderBy && pOrderBy->nExpr==BMS-1 ); if( pOrderBy && pOrderBy->nExpr>=BMS ) pOrderBy = 0; sWLB.pOrderBy = pOrderBy; /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via ** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */ if( OptimizationDisabled(db, SQLITE_DistinctOpt) ){ wctrlFlags &= ~WHERE_WANT_DISTINCT; } /* The number of tables in the FROM clause is limited by the number of ** bits in a Bitmask */ testcase( pTabList->nSrc==BMS ); if( pTabList->nSrc>BMS ){ sqlite3ErrorMsg(pParse, "at most %d tables in a join", BMS); |
︙ | ︙ | |||
5853 5854 5855 5856 5857 5858 5859 | /* Allocate and initialize the WhereInfo structure that will become the ** return value. A single allocation is used to store the WhereInfo ** struct, the contents of WhereInfo.a[], the WhereClause structure ** and the WhereMaskSet structure. Since WhereClause contains an 8-byte ** field (type Bitmask) it must be aligned on an 8-byte boundary on ** some architectures. Hence the ROUND8() below. */ | | < < < < < < > | < < | 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 | /* Allocate and initialize the WhereInfo structure that will become the ** return value. A single allocation is used to store the WhereInfo ** struct, the contents of WhereInfo.a[], the WhereClause structure ** and the WhereMaskSet structure. Since WhereClause contains an 8-byte ** field (type Bitmask) it must be aligned on an 8-byte boundary on ** some architectures. Hence the ROUND8() below. */ nByteWInfo = ROUND8(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel)); pWInfo = sqlite3DbMallocRawNN(db, nByteWInfo + sizeof(WhereLoop)); if( db->mallocFailed ){ sqlite3DbFree(db, pWInfo); pWInfo = 0; goto whereBeginError; } 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; pWInfo->pSelect = pSelect; 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 */ pMaskSet = &pWInfo->sMaskSet; sWLB.pWInfo = pWInfo; sWLB.pWC = &pWInfo->sWC; sWLB.pNew = (WhereLoop*)(((char*)pWInfo)+nByteWInfo); assert( EIGHT_BYTE_ALIGNMENT(sWLB.pNew) ); whereLoopInit(sWLB.pNew); #ifdef SQLITE_DEBUG sWLB.pNew->cId = '*'; #endif /* Split the WHERE clause into separate subexpressions where each ** subexpression is separated by an AND operator. */ initMaskSet(pMaskSet); sqlite3WhereClauseInit(&pWInfo->sWC, pWInfo); sqlite3WhereSplit(&pWInfo->sWC, pWhere, TK_AND); /* Special case: No FROM clause */ if( nTabList==0 ){ if( pOrderBy ) pWInfo->nOBSat = pOrderBy->nExpr; if( wctrlFlags & WHERE_WANT_DISTINCT ){ pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; } ExplainQueryPlan((pParse, 0, "SCAN CONSTANT ROW")); }else{ /* Assign a bit from the bitmask to every term in the FROM clause. ** ** The N-th term of the FROM clause is assigned a bitmask of 1<<N. |
︙ | ︙ | |||
5942 5943 5944 5945 5946 5947 5948 | } } #endif } /* Analyze all of the subexpressions. */ sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC); | < < < | | < < < < < | | < < < < < < < < < | | < | < | < < < < < < < < | < < < > | > > > | > | < < < > > > > > > > > > > > | < | 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 | } } #endif } /* Analyze all of the subexpressions. */ sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC); if( db->mallocFailed ) goto whereBeginError; /* Special case: WHERE terms that do not refer to any tables in the join ** (constant expressions). Evaluate each such term, and jump over all the ** generated code if the result is not true. ** ** Do not do this if the expression contains non-deterministic functions ** that are not within a sub-select. This is not strictly required, but ** preserves SQLite's legacy behaviour in the following two cases: ** ** FROM ... WHERE random()>0; -- eval random() once per row ** FROM ... WHERE (SELECT random())>0; -- eval random() once overall */ for(ii=0; ii<sWLB.pWC->nTerm; ii++){ WhereTerm *pT = &sWLB.pWC->a[ii]; if( pT->wtFlags & TERM_VIRTUAL ) continue; if( pT->prereqAll==0 && (nTabList==0 || exprIsDeterministic(pT->pExpr)) ){ sqlite3ExprIfFalse(pParse, pT->pExpr, pWInfo->iBreak, SQLITE_JUMPIFNULL); pT->wtFlags |= TERM_CODED; } } if( wctrlFlags & WHERE_WANT_DISTINCT ){ if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pResultSet) ){ /* The DISTINCT marking is pointless. Ignore it. */ pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; }else if( pOrderBy==0 ){ /* Try to ORDER BY the result set to make distinct processing easier */ pWInfo->wctrlFlags |= WHERE_DISTINCTBY; pWInfo->pOrderBy = pResultSet; } } /* Construct the WhereLoop objects */ #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 ){ /* Display all terms of the WHERE clause */ sqlite3WhereClausePrint(sWLB.pWC); } #endif if( nTabList!=1 || whereShortCut(&sWLB)==0 ){ rc = whereLoopAddAll(&sWLB); if( rc ) goto whereBeginError; #ifdef WHERETRACE_ENABLED 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)]; whereLoopPrint(p, sWLB.pWC); } } #endif wherePathSolver(pWInfo, 0); if( db->mallocFailed ) goto whereBeginError; if( pWInfo->pOrderBy ){ whereInterstageHeuristic(pWInfo); wherePathSolver(pWInfo, pWInfo->nRowOut+1); if( db->mallocFailed ) goto whereBeginError; } /* TUNING: Assume that a DISTINCT clause on a subquery reduces ** the output size by a factor of 8 (LogEst -30). */ if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT)!=0 ){ WHERETRACE(0x0080,("nRowOut reduced from %d to %d due to DISTINCT\n", pWInfo->nRowOut, pWInfo->nRowOut-30)); pWInfo->nRowOut -= 30; } } if( pWInfo->pOrderBy==0 && (db->flags & SQLITE_ReverseOrder)!=0 ){ pWInfo->revMask = ALLBITS; } if( pParse->nErr || NEVER(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); } switch( pWInfo->eDistinct ){ |
︙ | ︙ | |||
6070 6071 6072 6073 6074 6075 6076 | case WHERE_DISTINCT_UNORDERED: { sqlite3DebugPrintf(" DISTINCT=unordered"); break; } } sqlite3DebugPrintf("\n"); for(ii=0; ii<pWInfo->nLevel; ii++){ | | | | | | | | | | > > > > > > > > > > > > > > > > > > > | < < | > | > | > > > > > > > > > > | < < < | < > > > > > | < > | | > > | < < > | > > | > > > > > > > > > | < | 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 | case WHERE_DISTINCT_UNORDERED: { sqlite3DebugPrintf(" DISTINCT=unordered"); break; } } sqlite3DebugPrintf("\n"); for(ii=0; ii<pWInfo->nLevel; ii++){ whereLoopPrint(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: ** ** 1) The query must not be an aggregate. ** 2) The table must be the RHS of a LEFT JOIN. ** 3) Either the query must be DISTINCT, or else the ON or USING clause ** must contain a constraint that limits the scan of the table to ** at most a single row. ** 4) The table must not be referenced by any part of the query apart ** from its own USING or ON clause. ** ** For example, given: ** ** 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 USING (t1.ipk=t2.ipk) ** LEFT JOIN t3 USING (t1.ipk=t3.ipk) ** ** or from: ** ** SELECT DISTINCT v1, v3 FROM t1 ** LEFT JOIN t2 ** LEFT JOIN t3 USING (t1.ipk=t3.ipk) */ notReady = ~(Bitmask)0; if( pWInfo->nLevel>=2 && pResultSet!=0 /* guarantees 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; struct SrcList_item *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; } if( (tabUsed & pLoop->maskSelf)!=0 ) continue; pEnd = sWLB.pWC->a + sWLB.pWC->nTerm; for(pTerm=sWLB.pWC->a; pTerm<pEnd; pTerm++){ if( (pTerm->prereqAll & pLoop->maskSelf)!=0 ){ if( !ExprHasProperty(pTerm->pExpr, EP_FromJoin) || pTerm->pExpr->iRightJoinTable!=pItem->iCursor ){ break; } } } if( pTerm<pEnd ) continue; WHERETRACE(0xffff, ("-> drop loop %c not used\n", pLoop->cId)); notReady &= ~pLoop->maskSelf; for(pTerm=sWLB.pWC->a; pTerm<pEnd; pTerm++){ if( (pTerm->prereqAll & pLoop->maskSelf)!=0 ){ pTerm->wtFlags |= TERM_CODED; } } if( i!=pWInfo->nLevel-1 ){ 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 |
︙ | ︙ | |||
6159 6160 6161 6162 6163 6164 6165 | /* 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 */ | | | | | < < | < < < < < < < | 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 | /* 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 */ struct SrcList_item *pTabItem; pTabItem = &pTabList->a[pLevel->iFrom]; pTab = pTabItem->pTab; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); pLoop = pLevel->pWLoop; if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ){ /* 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); }else if( IsVirtual(pTab) ){ /* noop */ }else #endif if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ){ int op = OP_OpenRead; if( pWInfo->eOnePass!=ONEPASS_OFF ){ 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 && HasRowid(pTab) ){ 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 |
︙ | ︙ | |||
6247 6248 6249 6250 6251 6252 6253 | op = OP_OpenWrite; pWInfo->aiCurOnePass[1] = iIndexCur; }else if( iAuxArg && (wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ){ iIndexCur = iAuxArg; op = OP_ReopenIdx; }else{ iIndexCur = pParse->nTab++; | | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | | < < < < > | 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 | op = OP_OpenWrite; pWInfo->aiCurOnePass[1] = iIndexCur; }else if( iAuxArg && (wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ){ iIndexCur = iAuxArg; op = OP_ReopenIdx; }else{ iIndexCur = pParse->nTab++; if( pIx->bHasExpr ){ whereAddIndexedExpr(pParse, pIx, iIndexCur, pTabItem); } } pLevel->iIdxCur = iIndexCur; 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_IN_SEEKSCAN)==0 && (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0 && pWInfo->eDistinct!=WHERE_DISTINCT_ORDERED ){ sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ); /* Hint to COMDB2 */ } VdbeComment((v, "%s", pIx->zName)); #ifdef SQLITE_ENABLE_COLUMN_USED_MASK { u64 colUsed = 0; int ii, jj; for(ii=0; ii<pIx->nColumn; ii++){ jj = pIx->aiColumn[ii]; if( jj<0 ) continue; if( jj>63 ) jj = 63; if( (pTabItem->colUsed & MASKBIT(jj))==0 ) continue; colUsed |= ((u64)1)<<(ii<63 ? ii : 63); } sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed, iIndexCur, 0, 0, (u8*)&colUsed, P4_INT64); } #endif /* SQLITE_ENABLE_COLUMN_USED_MASK */ } } if( iDb>=0 ) sqlite3CodeVerifySchema(pParse, iDb); } pWInfo->iTop = sqlite3VdbeCurrentAddr(v); if( db->mallocFailed ) goto whereBeginError; /* 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); notReady = sqlite3WhereCodeOneLoopStart(pParse,v,pWInfo,ii,pLevel,notReady); pWInfo->iContinue = pLevel->addrCont; if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_OR_SUBCLAUSE)==0 ){ |
︙ | ︙ | |||
6398 6399 6400 6401 6402 6403 6404 | VdbeOp *pOp ){ if( (db->flags & SQLITE_VdbeAddopTrace)==0 ) return; sqlite3VdbePrintOp(0, pc, pOp); } #endif | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < | 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 | VdbeOp *pOp ){ if( (db->flags & SQLITE_VdbeAddopTrace)==0 ) return; sqlite3VdbePrintOp(0, pc, pOp); } #endif /* ** Generate the end of the WHERE loop. See comments on ** sqlite3WhereBegin() for additional information. */ void sqlite3WhereEnd(WhereInfo *pWInfo){ 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.nIdxCol)>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); } pParse->nMem += n+1; op = pLevel->op==OP_Prev ? OP_SeekLT : OP_SeekGT; addrSeek = sqlite3VdbeAddOp4Int(v, op, pLevel->iIdxCur, 0, r1, n); VdbeCoverageIf(v, op==OP_SeekLT); VdbeCoverageIf(v, op==OP_SeekGT); sqlite3VdbeAddOp2(v, OP_Goto, 1, pLevel->p2); } #endif /* SQLITE_DISABLE_SKIPAHEAD_DISTINCT */ /* The common case: Advance to the next row */ 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); } if( pLoop->wsFlags & WHERE_IN_ABLE && 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--){ 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( bEarlyOut ){ sqlite3VdbeAddOp4Int(v, OP_IfNoHope, pLevel->iIdxCur, sqlite3VdbeCurrentAddr(v)+2, pIn->iBase, pIn->nPrefix); VdbeCoverage(v); } } 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); } } sqlite3VdbeResolveLabel(v, pLevel->addrBrk); if( pLevel->addrSkip ){ sqlite3VdbeGoto(v, pLevel->addrSkip); VdbeComment((v, "next skip-scan on %s", pLoop->u.btree.pIndex->zName)); sqlite3VdbeJumpHere(v, pLevel->addrSkip); sqlite3VdbeJumpHere(v, pLevel->addrSkip-2); } #ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS |
︙ | ︙ | |||
6568 6569 6570 6571 6572 6573 6574 | 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) | | < < < < < < > > > > > | < < < < < < < < < > > > > > > > > > > > > > > > > > > > > > > > | | < < < < < < < | < < < < < < < < | < < < < < < > | < | < < < < < < < < < < < < < | 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 | 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.pCovidx) ){ sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iIdxCur); } if( pLevel->op==OP_Return ){ sqlite3VdbeAddOp2(v, OP_Gosub, pLevel->p1, pLevel->addrFirst); }else{ sqlite3VdbeGoto(v, pLevel->addrFirst); } sqlite3VdbeJumpHere(v, addr); } VdbeModuleComment((v, "End WHERE-loop%d: %s", i, pWInfo->pTabList->a[pLevel->iFrom].pTab->zName)); } /* The "break" point is here, just past the end of the outer loop. ** 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; struct SrcList_item *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 && pTab->pSelect==0 && (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.pCovidx; } if( pIdx && !db->mallocFailed ){ if( pWInfo->eOnePass==ONEPASS_OFF || !HasRowid(pIdx->pTable) ){ last = iEnd; }else{ last = pWInfo->iEndWhere; } if( pIdx->bHasExpr ){ IndexedExpr *p = pParse->pIdxExpr; while( p ){ if( p->iIdxCur==pLevel->iIdxCur ){ p->iDataCur = -1; p->iIdxCur = -1; } p = p->pIENext; } } 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 ); } x = sqlite3ColumnOfIndex(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 */ pParse->nQueryLoop = pWInfo->savedNQueryLoop; whereInfoFree(db, pWInfo); return; } |
Changes to src/whereInt.h.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** ** 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 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 | ** ************************************************************************* ** ** 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. */ /* ** Trace output macros */ #if defined(SQLITE_TEST) || defined(SQLITE_DEBUG) /***/ extern int sqlite3WhereTrace; #endif #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 /* Forward references */ typedef struct WhereClause WhereClause; typedef struct WhereMaskSet WhereMaskSet; typedef struct WhereOrInfo WhereOrInfo; typedef struct WhereAndInfo WhereAndInfo; typedef struct WhereLevel WhereLevel; typedef struct WhereLoop WhereLoop; typedef struct WherePath WherePath; typedef struct WhereTerm WhereTerm; typedef struct WhereLoopBuilder WhereLoopBuilder; typedef struct WhereScan WhereScan; typedef struct WhereOrCost WhereOrCost; typedef struct WhereOrSet WhereOrSet; /* ** This object contains information needed to implement a single nested ** loop in WHERE clause. ** ** Contrast this object with WhereLoop. This object describes the ** implementation of the loop. WhereLoop describes the algorithm. |
︙ | ︙ | |||
76 77 78 79 80 81 82 | 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 */ | < < < < | | | 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 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 */ int p1, p2; /* Operands of the opcode used to ends 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 *pCovidx; /* 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 }; |
︙ | ︙ | |||
137 138 139 140 141 142 143 | 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 */ | | | < < | 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | 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 nIdxCol; /* Index column used for ORDER BY */ 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 */ char *idxStr; /* Index identifier string */ } vtab; } u; u32 wsFlags; /* WHERE_* flags describing the plan */ u16 nLTerm; /* Number of entries in aLTerm[] */ u16 nSkip; /* Number of NULL aLTerm[] entries */ /**** whereLoopXfer() copies fields above ***********************/ # define WHERE_LOOP_XFER_SZ offsetof(WhereLoop,nLSlot) |
︙ | ︙ | |||
270 271 272 273 274 275 276 277 | 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 { | > < | < < | | | | | | | > | > > > | | | | < < < < < < < < < < | > > > | 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 | 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>" */ int iField; /* Field in (?,?,?) IN (SELECT...) vector */ union { int leftColumn; /* Column number of X in "X <op> <expr>" */ 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 0x01 /* Need to call sqlite3ExprDelete(db, pExpr) */ #define TERM_VIRTUAL 0x02 /* Added by the optimizer. Do not code */ #define TERM_CODED 0x04 /* This term is already coded */ #define TERM_COPIED 0x08 /* Has a child */ #define TERM_ORINFO 0x10 /* Need to free the WhereTerm.u.pOrInfo object */ #define TERM_ANDINFO 0x20 /* Need to free the WhereTerm.u.pAndInfo obj */ #define TERM_OR_OK 0x40 /* Used during OR-clause processing */ #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 # define TERM_VNULL 0x80 /* Manufactured x>NULL or x<=NULL term */ #else # define TERM_VNULL 0x00 /* Disabled if not using stat3 */ #endif #define TERM_LIKEOPT 0x100 /* Virtual terms from the LIKE optimization */ #define TERM_LIKECOND 0x200 /* Conditionally this LIKE operator term */ #define TERM_LIKE 0x400 /* The original LIKE operator */ #define TERM_IS 0x800 /* Term.pExpr is an IS operator */ #define TERM_VARSELECT 0x1000 /* Term.pExpr contains a correlated sub-query */ /* ** 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 aEquiv[] */ unsigned char iEquiv; /* Next unused slot in aEquiv[] */ 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 */ }; /* ** An instance of the following structure holds all information about a ** WHERE clause. Mostly this is a container for one or more WhereTerms. |
︙ | ︙ | |||
343 344 345 346 347 348 349 | struct WhereClause { WhereInfo *pWInfo; /* WHERE clause processing context */ WhereClause *pOuter; /* Outer conjunction */ u8 op; /* Split operator. TK_AND or TK_OR */ u8 hasOr; /* True if any a[].eOperator is WO_OR */ int nTerm; /* Number of terms */ int nSlot; /* Number of entries in a[] */ | < | 321 322 323 324 325 326 327 328 329 330 331 332 333 334 | struct WhereClause { WhereInfo *pWInfo; /* WHERE clause processing context */ WhereClause *pOuter; /* Outer conjunction */ u8 op; /* Split operator. TK_AND or TK_OR */ u8 hasOr; /* True if any a[].eOperator is WO_OR */ int nTerm; /* Number of terms */ int nSlot; /* Number of entries in a[] */ WhereTerm *a; /* Each a[] describes a term of the WHERE cluase */ #if defined(SQLITE_SMALL_STACK) WhereTerm aStatic[1]; /* Initial static space for a[] */ #else WhereTerm aStatic[8]; /* Initial static space for a[] */ #endif }; |
︙ | ︙ | |||
374 375 376 377 378 379 380 | }; /* ** An instance of the following structure keeps track of a mapping ** between VDBE cursor numbers and bits of the bitmasks in WhereTerm. ** ** The VDBE cursor numbers are small integers contained in | | | 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 | }; /* ** An instance of the following structure keeps track of a mapping ** between VDBE cursor numbers and bits of the bitmasks in WhereTerm. ** ** The VDBE cursor numbers are small integers contained in ** SrcList_item.iCursor and Expr.iTable fields. For any given WHERE ** clause, the cursor numbers might not begin with 0 and they might ** contain gaps in the numbering sequence. But we want to make maximum ** use of the bits in our bitmasks. This structure provides a mapping ** from the sparse cursor numbers into consecutive integers beginning ** with 0. ** ** If WhereMaskSet.ix[A]==B it means that The A-th bit of a Bitmask |
︙ | ︙ | |||
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 | */ struct WhereMaskSet { int bVarSelect; /* Used by sqlite3WhereExprUsage() */ int n; /* Number of assigned cursor values */ int ix[BMS]; /* Cursor assigned to each bit */ }; /* ** This object is a convenience wrapper holding all information needed ** to construct WhereLoop objects for a particular query. */ struct WhereLoopBuilder { WhereInfo *pWInfo; /* Information about this WHERE */ WhereClause *pWC; /* WHERE clause terms */ WhereLoop *pNew; /* Template WhereLoop */ WhereOrSet *pOrSet; /* Record best loops here, if not NULL */ | > > > > > > | | < | | < < | 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 | */ struct WhereMaskSet { int bVarSelect; /* Used by sqlite3WhereExprUsage() */ int n; /* Number of assigned cursor values */ int ix[BMS]; /* Cursor assigned to each bit */ }; /* ** Initialize a WhereMaskSet object */ #define initMaskSet(P) (P)->n=0 /* ** This object is a convenience wrapper holding all information needed ** to construct WhereLoop objects for a particular query. */ 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_STAT3_OR_STAT4 UnpackedRecord *pRec; /* Probe for stat4 (if required) */ int nRecValid; /* Number of valid fields currently in pRec */ #endif unsigned int bldFlags; /* SQLITE_BLDF_* flags */ unsigned int iPlanLimit; /* Search limiter */ }; /* Allowed values for WhereLoopBuider.bldFlags */ #define SQLITE_BLDF_INDEXED 0x0001 /* An index is used */ #define SQLITE_BLDF_UNIQUE 0x0002 /* All keys of a UNIQUE index used */ /* 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. |
︙ | ︙ | |||
460 461 462 463 464 465 466 | ** 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 */ | < < > < > < | | > | < < < > < < < < < < < < < < < < < < < < | | 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 | ** 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 */ LogEst iLimit; /* LIMIT if wctrlFlags has WHERE_USE_LIMIT */ Select *pSelect; /* The entire SELECT statement containing WHERE */ 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() */ u8 nLevel; /* Number of nested loop */ i8 nOBSat; /* Number of ORDER BY terms satisfied by indices */ u8 sorted; /* True if really sorted (not just grouped) */ u8 eOnePass; /* ONEPASS_OFF, or _SINGLE, or _MULTI */ u8 bDeferredSeek; /* Uses OP_DeferredSeek */ u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */ u8 eDistinct; /* One of the WHERE_DISTINCT_* values */ u8 bOrderedInnerLoop; /* True if only the inner-most loop is ordered */ int iTop; /* The very beginning of the WHERE loop */ int iEndWhere; /* End of the WHERE clause itself */ WhereLoop *pLoops; /* List of all WhereLoop objects */ Bitmask revMask; /* Mask of ORDER BY terms that need reversing */ LogEst nRowOut; /* Estimated number of output rows */ 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); #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 */ Index *pIdx /* Must be compatible with this index, if not NULL */ ); /* wherecode.c: */ #ifndef SQLITE_OMIT_EXPLAIN int sqlite3WhereExplainOneScan( Parse *pParse, /* Parse context */ SrcList *pTabList, /* Table list this loop refers to */ WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ ); #else # define sqlite3WhereExplainOneScan(u,v,w,x) 0 #endif /* SQLITE_OMIT_EXPLAIN */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS void sqlite3WhereAddScanStatus( Vdbe *v, /* Vdbe to add scanstatus entry to */ SrcList *pSrclist, /* FROM clause pLvl reads data from */ 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*, struct SrcList_item*, WhereClause*); /* ** Bitmasks for the operators on WhereTerm objects. These are all |
︙ | ︙ | |||
593 594 595 596 597 598 599 | #define WO_AUX 0x0040 /* Op useful to virtual tables only */ #define WO_IS 0x0080 #define WO_ISNULL 0x0100 #define WO_OR 0x0200 /* Two or more OR-connected terms */ #define WO_AND 0x0400 /* Two or more AND-connected terms */ #define WO_EQUIV 0x0800 /* Of the form A==B, both columns */ #define WO_NOOP 0x1000 /* This term does not restrict search space */ | < | | 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 | #define WO_AUX 0x0040 /* Op useful to virtual tables only */ #define WO_IS 0x0080 #define WO_ISNULL 0x0100 #define WO_OR 0x0200 /* Two or more OR-connected terms */ #define WO_AND 0x0400 /* Two or more AND-connected terms */ #define WO_EQUIV 0x0800 /* Of the form A==B, both columns */ #define WO_NOOP 0x1000 /* This term does not restrict search space */ #define WO_ALL 0x1fff /* Mask of all possible WO_* values */ #define WO_SINGLE 0x01ff /* Mask of all non-compound WO_* values */ /* ** These are definitions of bits in the WhereLoop.wsFlags field. ** The particular combination of bits in each WhereLoop help to ** determine the algorithm that WhereLoop represents. */ |
︙ | ︙ | |||
623 624 625 626 627 628 629 | #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 */ | < < < < < < < | < | 583 584 585 586 587 588 589 590 591 | #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_IN_SEEKSCAN 0x00100000 /* Seek-scan optimization for IN */ /* 0x02000000 -- available for reuse */ |
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].zName; } /* ** 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 160 161 162 163 164 165 166 167 | u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ ){ int ret = 0; #if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS) if( sqlite3ParseToplevel(pParse)->explain==2 ) #endif { struct SrcList_item *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); sqlite3_str_appendall(&str, isSearch ? "SEARCH" : "SCAN"); if( pItem->pSelect ){ sqlite3_str_appendf(&str, " SUBQUERY %u", pItem->pSelect->selId); }else{ sqlite3_str_appendf(&str, " TABLE %s", pItem->zName); } if( pItem->zAlias ){ sqlite3_str_appendf(&str, " AS %s", pItem->zAlias); } 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) ); |
︙ | ︙ | |||
172 173 174 175 176 177 178 | } if( zFmt ){ sqlite3_str_append(&str, " USING ", 7); sqlite3_str_appendf(&str, zFmt, pIdx->zName); explainIndexRange(&str, pLoop); } }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){ | < < < < < < | < < | < | | | | > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < | 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 | } if( zFmt ){ sqlite3_str_append(&str, " USING ", 7); sqlite3_str_appendf(&str, zFmt, pIdx->zName); explainIndexRange(&str, pLoop); } }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){ const char *zRangeOp; if( flags&(WHERE_COLUMN_EQ|WHERE_COLUMN_IN) ){ zRangeOp = "="; }else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){ zRangeOp = ">? AND rowid<"; }else if( flags&WHERE_BTM_LIMIT ){ zRangeOp = ">"; }else{ assert( flags&WHERE_TOP_LIMIT); zRangeOp = "<"; } sqlite3_str_appendf(&str, " USING INTEGER PRIMARY KEY (rowid%s?)",zRangeOp); } #ifndef SQLITE_OMIT_VIRTUALTABLE else if( (flags & WHERE_VIRTUALTABLE)!=0 ){ sqlite3_str_appendf(&str, " VIRTUAL TABLE INDEX %d:%s", pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr); } #endif #ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS if( pLoop->nOut>=10 ){ 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 */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS /* ** Configure the VM passed as the first argument with an ** sqlite3_stmt_scanstatus() entry corresponding to the scan used to ** implement level pLvl. Argument pSrclist is a pointer to the FROM ** clause that the scan reads data from. ** ** If argument addrExplain is not 0, it must be the address of an ** OP_Explain instruction that describes the same loop. */ void sqlite3WhereAddScanStatus( Vdbe *v, /* Vdbe to add scanstatus entry to */ SrcList *pSrclist, /* FROM clause pLvl reads data from */ WhereLevel *pLvl, /* Level to add scanstatus() entry for */ int addrExplain /* Address of OP_Explain (or 0) */ ){ const char *zObj = 0; WhereLoop *pLoop = pLvl->pWLoop; if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 ){ zObj = pLoop->u.btree.pIndex->zName; }else{ zObj = pSrclist->a[pLvl->iFrom].zName; } sqlite3VdbeScanStatus( v, addrExplain, pLvl->addrBody, pLvl->addrVisit, pLoop->nOut, zObj ); } #endif /* ** Disable a term in the WHERE clause. Except, do not disable the term ** if it controls a LEFT OUTER JOIN and it did not originate in the ON |
︙ | ︙ | |||
361 362 363 364 365 366 367 | ** a conditional such that is only evaluated on the second pass of a ** LIKE-optimization loop, when scanning BLOBs instead of strings. */ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){ int nLoop = 0; assert( pTerm!=0 ); while( (pTerm->wtFlags & TERM_CODED)==0 | | < < < < < < | | | | | < | | | 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 | ** a conditional such that is only evaluated on the second pass of a ** LIKE-optimization loop, when scanning BLOBs instead of strings. */ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){ int nLoop = 0; assert( pTerm!=0 ); while( (pTerm->wtFlags & TERM_CODED)==0 && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin)) && (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. ** ** As an optimization, SQLITE_AFF_BLOB entries (which are no-ops) at the ** beginning and end of zAff are ignored. If all entries in zAff are ** SQLITE_AFF_BLOB, 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 entries at the beginning ** and end of the affinity string. */ 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); } |
︙ | ︙ | |||
485 486 487 488 489 490 491 | 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; | < < | < | | | | | | < < < < < < | | | < < | | | | < | | | | | < | < | | < | | | | | | | | | | > | | | | | | | | | | | | | | | | | < | 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 | 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 = sqlite3ExprDup(db, pX, 0); if( db->mallocFailed==0 ){ ExprList *pOrigRhs = pNew->x.pSelect->pEList; /* Original unmodified RHS */ ExprList *pOrigLhs = pNew->pLeft->x.pList; /* 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 */ for(i=iEq; i<pLoop->nLTerm; i++){ if( pLoop->aLTerm[i]->pExpr==pX ){ int iField = pLoop->aLTerm[i]->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; } } sqlite3ExprListDelete(db, pOrigRhs); sqlite3ExprListDelete(db, pOrigLhs); pNew->pLeft->x.pList = pLhs; pNew->x.pSelect->pEList = pRhs; if( pLhs && pLhs->nExpr==1 ){ /* Take care here not to generate a TK_VECTOR containing only a ** single value. Since the parser never creates such a vector, some ** of the subroutines do not handle this case. */ Expr *p = pLhs->a[0].pExpr; pLhs->a[0].pExpr = 0; sqlite3ExprDelete(db, pNew->pLeft); pNew->pLeft = p; } pSelect = pNew->x.pSelect; if( pSelect->pOrderBy ){ /* If the SELECT statement has an ORDER BY clause, zero the ** iOrderByCol variables. These are set to non-zero when an ** ORDER BY term exactly matches one of the terms of the ** result-set. Since the result-set of the SELECT statement may ** have been modified or reordered, these variables are no longer ** set correctly. Since setting them is just an optimization, ** it's easiest just to zero them here. */ ExprList *pOrderBy = pSelect->pOrderBy; for(i=0; i<pOrderBy->nExpr; i++){ pOrderBy->a[i].u.x.iOrderByCol = 0; } } #if 0 printf("For indexing, change the IN expr:\n"); sqlite3TreeViewExpr(0, pX, 0); printf("Into:\n"); sqlite3TreeViewExpr(0, pNew, 0); #endif } return pNew; } /* ** Generate code for a single equality term of the WHERE clause. An equality |
︙ | ︙ | |||
626 627 628 629 630 631 632 | } for(i=iEq;i<pLoop->nLTerm; i++){ assert( pLoop->aLTerm[i]!=0 ); if( pLoop->aLTerm[i]->pExpr==pX ) nEq++; } iTab = 0; | | < < | | > | | | | | | < < < < < | < > < | | | < | < < < < < < < < < < < < < < < < < | < < | 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 | } for(i=iEq;i<pLoop->nLTerm; i++){ assert( pLoop->aLTerm[i]!=0 ); if( pLoop->aLTerm[i]->pExpr==pX ) nEq++; } iTab = 0; if( (pX->flags & EP_xIsSelect)==0 || 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 && (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ){ pIn->iBase = iReg - i; pIn->nPrefix = i; }else{ pIn->nPrefix = 0; } }else{ pIn->eEndLoopOp = OP_Noop; } pIn++; } } if( iEq>0 && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0 ){ sqlite3VdbeAddOp3(v, OP_SeekHit, pLevel->iIdxCur, 0, iEq); } }else{ pLevel->u.in.nIn = 0; } sqlite3DbFree(pParse->db, aiMap); #endif } disableTerm(pLevel, pTerm); return iReg; } /* ** Generate code that will evaluate all == and IN constraints for an ** index scan. ** |
︙ | ︙ | |||
814 815 816 817 818 819 820 | pParse->nMem += nReg; zAff = sqlite3DbStrDup(pParse->db,sqlite3IndexAffinityStr(pParse->db,pIdx)); assert( zAff!=0 || pParse->db->mallocFailed ); if( nSkip ){ int iIdxCur = pLevel->iIdxCur; | < < | 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 | 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); VdbeCoverageIf(v, bRev==0); VdbeCoverageIf(v, bRev!=0); sqlite3VdbeJumpHere(v, j); for(j=0; j<nSkip; j++){ sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, j, regBase+j); |
︙ | ︙ | |||
850 851 852 853 854 855 856 | 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{ | | < < < | < | 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 | 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_SCopy, 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( zAff ){ if( sqlite3CompareAffinity(pRight, zAff[j])==SQLITE_AFF_BLOB ){ zAff[j] = SQLITE_AFF_BLOB; } if( sqlite3ExprNeedsNoAffinityChange(pRight, zAff[j]) ){ zAff[j] = SQLITE_AFF_BLOB; } } |
︙ | ︙ | |||
911 912 913 914 915 916 917 | Vdbe *v, /* prepared statement under construction */ WhereLevel *pLevel, /* The loop that contains the LIKE operator */ WhereTerm *pTerm /* The upper or lower bound just coded */ ){ if( pTerm->wtFlags & TERM_LIKEOPT ){ VdbeOp *pOp; assert( pLevel->iLikeRepCntr>0 ); | | | 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 | Vdbe *v, /* prepared statement under construction */ WhereLevel *pLevel, /* The loop that contains the LIKE operator */ WhereTerm *pTerm /* The upper or lower bound just coded */ ){ if( pTerm->wtFlags & TERM_LIKEOPT ){ VdbeOp *pOp; assert( pLevel->iLikeRepCntr>0 ); pOp = sqlite3VdbeGetOp(v, -1); assert( pOp!=0 ); assert( pOp->opcode==OP_String8 || pTerm->pWC->pWInfo->pParse->db->mallocFailed ); pOp->p3 = (int)(pLevel->iLikeRepCntr>>1); /* Register holding counter */ pOp->p5 = (u8)(pLevel->iLikeRepCntr&1); /* ASC or DESC */ } } |
︙ | ︙ | |||
946 947 948 949 950 951 952 | ** 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 | | | 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 | ** 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 && sqlite3ColumnOfIndex(pHint->pIdx, pExpr->iColumn)<0 ){ pWalker->eCode = 1; } return WRC_Continue; } /* |
︙ | ︙ | |||
1014 1015 1016 1017 1018 1019 1020 | 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; | | | | 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 | 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 = sqlite3ColumnOfIndex(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( struct SrcList_item *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; |
︙ | ︙ | |||
1061 1062 1063 1064 1065 1066 1067 | sHint.iTabCur = iCur; sHint.iIdxCur = pLevel->iIdxCur; sHint.pIdx = pLoop->u.btree.pIndex; memset(&sWalker, 0, sizeof(sWalker)); sWalker.pParse = pParse; sWalker.u.pCCurHint = &sHint; pWC = &pWInfo->sWC; | | | 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 | sHint.iTabCur = iCur; sHint.iIdxCur = pLevel->iIdxCur; sHint.pIdx = pLoop->u.btree.pIndex; memset(&sWalker, 0, sizeof(sWalker)); sWalker.pParse = pParse; sWalker.u.pCCurHint = &sHint; pWC = &pWInfo->sWC; for(i=0; i<pWC->nTerm; i++){ pTerm = &pWC->a[i]; if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( pTerm->prereqAll & pLevel->notReady ) continue; /* Any terms specified as part of the ON(...) clause for any LEFT ** JOIN for which the current table is not the rhs are omitted ** from the cursor-hint. |
︙ | ︙ | |||
1090 1091 1092 1093 1094 1095 1096 | ** ** WHERE 1 = (t2.c IS NULL) ** ** are also excluded. See codeCursorHintIsOrFunction() for details. */ if( pTabItem->fg.jointype & JT_LEFT ){ Expr *pExpr = pTerm->pExpr; | | | | | 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 | ** ** WHERE 1 = (t2.c IS NULL) ** ** are also excluded. See codeCursorHintIsOrFunction() for details. */ if( pTabItem->fg.jointype & JT_LEFT ){ Expr *pExpr = pTerm->pExpr; if( !ExprHasProperty(pExpr, EP_FromJoin) || pExpr->iRightJoinTable!=pTabItem->iCursor ){ sWalker.eCode = 0; sWalker.xExprCallback = codeCursorHintIsOrFunction; sqlite3WalkExpr(&sWalker, pTerm->pExpr); if( sWalker.eCode ) continue; } }else{ if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue; } /* All terms in pWLoop->aLTerm[] except pEndRange are used to initialize ** the cursor. These terms are not needed as hints for a pure range ** scan (that has no == terms) so omit them. */ if( pLoop->u.btree.nEq==0 && pTerm!=pEndRange ){ for(j=0; j<pLoop->nLTerm && pLoop->aLTerm[j]!=pTerm; j++){} |
︙ | ︙ | |||
1123 1124 1125 1126 1127 1128 1129 | 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 */ | | | 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 | 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(db, 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); |
︙ | ︙ | |||
1147 1148 1149 1150 1151 1152 1153 | ** function generates code to do a deferred seek of cursor iCur to the ** rowid stored in register iRowid. ** ** Normally, this is just: ** ** OP_DeferredSeek $iCur $iRowid ** | < < | < < | | | | | < < < < | | < | < < < | < < | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ** function generates code to do a deferred seek of cursor iCur to the ** rowid stored in register iRowid. ** ** Normally, this is just: ** ** OP_DeferredSeek $iCur $iRowid ** ** However, if the scan currently being coded is a branch of an OR-loop and ** the statement currently being coded is a SELECT, then P3 of OP_DeferredSeek ** is set to iIdxCur and P4 is set to point to an array of integers ** containing one entry for each column of the table cursor iCur is open ** on. For each table column, if the column is the i'th column of the ** index, then the corresponding array entry is set to (i+1). If the column ** does not appear in the index at all, the array entry is set to 0. */ static void codeDeferredSeek( WhereInfo *pWInfo, /* Where clause context */ Index *pIdx, /* Index scan is using */ int iCur, /* Cursor for IPK b-tree */ int iIdxCur /* Index cursor */ ){ 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; int *ai = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*(pTab->nCol+1)); if( ai ){ ai[0] = pTab->nCol; for(i=0; i<pIdx->nColumn-1; i++){ assert( pIdx->aiColumn[i]<pTab->nCol ); if( pIdx->aiColumn[i]>=0 ) ai[pIdx->aiColumn[i]+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( (p->flags & EP_xIsSelect) ){ 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; ExprList *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 ); 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 */ } IdxExprTrans; /* 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 ){ pExpr->op = TK_COLUMN; pExpr->iTable = pX->iIdxCur; pExpr->iColumn = pX->iIdxCol; pExpr->y.pTab = 0; return WRC_Prune; }else{ return WRC_Continue; } } /* ** 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. */ 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 */ Walker w; IdxExprTrans x; aColExpr = pIdx->aColExpr; if( aColExpr==0 ) return; /* Not an index on expressions */ memset(&w, 0, sizeof(w)); w.xExprCallback = whereIndexExprTransNode; w.u.pIdxTrans = &x; x.iTabCur = iTabCur; x.iIdxCur = iIdxCur; for(iIdxCol=0; iIdxCol<aColExpr->nExpr; iIdxCol++){ if( pIdx->aiColumn[iIdxCol]!=XN_EXPR ) continue; assert( aColExpr->a[iIdxCol].pExpr!=0 ); x.iIdxCol = iIdxCol; x.pIdxExpr = aColExpr->a[iIdxCol].pExpr; 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. |
︙ | ︙ | |||
1263 1264 1265 1266 1267 1268 1269 | pExpr = pTerm->pExpr; if( sqlite3ExprCompare(0, pExpr, pTruth, iTabCur)==0 ){ pTerm->wtFlags |= TERM_CODED; } } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < | | < < < > < < < < < < | | < < < < < < < < < < < < < < | | < < | < < < < | < | > > | | | < > | | < | | < | < | < < < | < < < < < | < | < < < | | | | | 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 | 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 */ struct SrcList_item *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)); /* 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 ); if( pLevel->iFrom>0 && (pTabItem[0].fg.jointype & JT_LEFT)!=0 ){ pLevel->iLeftJoin = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, pLevel->iLeftJoin); VdbeComment((v, "init LEFT JOIN no-match flag")); } /* Compute a safe address to jump to if we discover that the table for ** this loop is empty and can never contribute content. */ for(j=iLevel; j>0 && pWInfo->a[j].iLeftJoin==0; j--){} addrHalt = pWInfo->a[j].addrBrk; /* Special case of a FROM clause subquery implemented as a co-routine */ if( pTabItem->fg.viaCoroutine ){ int regYield = pTabItem->regReturn; sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub); pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk); VdbeCoverage(v); VdbeComment((v, "next row of %s", pTabItem->pTab->zName)); pLevel->op = OP_Goto; }else #ifndef SQLITE_OMIT_VIRTUALTABLE if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 ){ /* Case 1: The table is a virtual-table. Use the VFilter and VNext ** to access the data. */ int iReg; /* P3 Value for OP_VFilter */ int addrNotFound; int nConstraint = pLoop->nLTerm; int iIn; /* Counter for IN constraints */ iReg = sqlite3GetTempRange(pParse, nConstraint+2); addrNotFound = pLevel->addrBrk; for(j=0; j<nConstraint; j++){ int iTarget = iReg+j+2; pTerm = pLoop->aLTerm[j]; if( NEVER(pTerm==0) ) continue; if( pTerm->eOperator & WO_IN ){ codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget); addrNotFound = pLevel->addrNxt; }else{ Expr *pRight = pTerm->pExpr->pRight; codeExprOrVector(pParse, pRight, iTarget, 1); } } 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); iIn = pLevel->u.in.nIn; for(j=nConstraint-1; j>=0; j--){ pTerm = pLoop->aLTerm[j]; if( j<16 && (pLoop->u.vtab.omitMask>>j)&1 ){ disableTerm(pLevel, pTerm); }else if( (pTerm->eOperator & WO_IN)!=0 ){ 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 ); 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, 0); } pCompare->pLeft = 0; sqlite3ExprDelete(db, pCompare); } } } /* 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); */ |
︙ | ︙ | |||
1567 1568 1569 1570 1571 1572 1573 | 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; | < < < < < < < < > > > | 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 | 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; if( (pTerm->prereqAll & pLevel->notReady)==0 ){ pTerm->wtFlags |= TERM_CODED; } }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; |
︙ | ︙ | |||
1752 1753 1754 1755 1756 1757 1758 | 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 */ | | > > > > > > > > > > > > > > > > > > > > | 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 | 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 addrSeekScan = 0; /* Opcode of the OP_SeekScan, if any */ pIdx = pLoop->u.btree.pIndex; iIdxCur = pLevel->iIdxCur; assert( nEq>=pLoop->nSkip ); /* If this loop satisfies a sort order (pOrderBy) request that ** was passed to this function to implement a "SELECT min(x) ..." ** query, then the caller will only allow the loop to run for ** a single iteration. This means that the first row returned ** should not have a NULL value stored in 'x'. If column 'x' is ** the first one after the nEq equality constraints in the index, ** this requires some special handling. */ assert( pWInfo->pOrderBy==0 || pWInfo->pOrderBy->nExpr==1 || (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0 ); if( (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)!=0 && pWInfo->nOBSat>0 && (pIdx->nKeyCol>nEq) ){ assert( pLoop->nSkip==0 ); bSeekPastNull = 1; nExtraReg = 1; } /* 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++]; |
︙ | ︙ | |||
1799 1800 1801 1802 1803 1804 1805 | if( (j>=0 && pIdx->pTable->aCol[j].notNull==0) || j==XN_EXPR ){ bSeekPastNull = 1; } } } assert( pRangeEnd==0 || (pRangeEnd->wtFlags & TERM_VNULL)==0 ); | < < < < < < < < < < < < < < < < < < < < < < | > > < < < < < < | | 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 | 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). */ if( (nEq<pIdx->nKeyCol && bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC)) || (bRev && pIdx->nKeyCol==nEq) ){ SWAP(WhereTerm *, pRangeEnd, pRangeStart); SWAP(u8, bSeekPastNull, bStopAtNull); SWAP(u8, nBtm, nTop); } /* 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 = 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); |
︙ | ︙ | |||
1881 1882 1883 1884 1885 1886 1887 | if( sqlite3ExprIsVector(pRight)==0 ){ disableTerm(pLevel, pRangeStart); }else{ startEq = 1; } bSeekPastNull = 0; }else if( bSeekPastNull ){ | < < < < > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | if( sqlite3ExprIsVector(pRight)==0 ){ disableTerm(pLevel, pRangeStart); }else{ startEq = 1; } bSeekPastNull = 0; }else if( bSeekPastNull ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); nConstraint++; startEq = 0; start_constraints = 1; } 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{ op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev]; assert( op!=0 ); if( (pLoop->wsFlags & WHERE_IN_SEEKSCAN)!=0 && op==OP_SeekGE ){ /* 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 ); } /* Load the value for the inequality constraint at the end of the ** range (if any). */ nConstraint = nEq; if( pRangeEnd ){ Expr *pRight = pRangeEnd->pExpr->pRight; 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); |
︙ | ︙ | |||
1995 1996 1997 1998 1999 2000 2001 | if( sqlite3ExprIsVector(pRight)==0 ){ disableTerm(pLevel, pRangeEnd); }else{ endEq = 1; } }else if( bStopAtNull ){ | < | | < | | | < < < < < < < < < < < < < < < < < < < < < < < | | > > > > > > > > > > > > > > > | > > > | | | < < < | | | | < < < < < < | < | 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 | if( sqlite3ExprIsVector(pRight)==0 ){ disableTerm(pLevel, pRangeEnd); }else{ endEq = 1; } }else if( bStopAtNull ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); endEq = 0; nConstraint++; } sqlite3DbFree(db, zStartAff); sqlite3DbFree(db, zEndAff); /* Top of the loop body */ pLevel->p2 = sqlite3VdbeCurrentAddr(v); /* Check if the index cursor is past the end of the range. */ if( nConstraint ){ 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( (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 = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, iRowidReg+j); } sqlite3VdbeAddOp4Int(v, OP_NotFound, iCur, addrCont, iRowidReg, pPk->nKeyCol); VdbeCoverage(v); } /* 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. ** ** 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( pLevel->iLeftJoin==0 && (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 */ if( pIdx->pPartIdxWhere ){ whereApplyPartialIndexConstraints(pIdx->pPartIdxWhere, iCur, pWC); } /* 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; |
︙ | ︙ | |||
2174 2175 2176 2177 2178 2179 2180 | /* 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 */ | | | | 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 | /* 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 */ struct SrcList_item *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)); origSrc = pWInfo->pTabList->a; for(k=1; k<=nNotReady; k++){ |
︙ | ︙ | |||
2217 2218 2219 2220 2221 2222 2223 | sqlite3VdbeSetP4KeyInfo(pParse, pPk); } regRowid = ++pParse->nMem; } iRetInit = sqlite3VdbeAddOp2(v, OP_Integer, 0, regReturn); /* If the original WHERE clause is z of the form: (x1 OR x2 OR ...) AND y | | < < < < < < < < < < < < < < < | < < < > | | < | | < < < | < < | | | 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 | sqlite3VdbeSetP4KeyInfo(pParse, pPk); } regRowid = ++pParse->nMem; } iRetInit = sqlite3VdbeAddOp2(v, OP_Integer, 0, regReturn); /* If the original WHERE clause is z of the form: (x1 OR x2 OR ...) AND y ** Then for every term xN, evaluate as the subexpression: xN AND z ** That way, terms in y that are factored into the disjunction will ** be picked up by the recursive calls to sqlite3WhereBegin() below. ** ** Actually, each subexpression is converted to "xN AND w" where w is ** the "interesting" terms of z - terms that did not originate in the ** ON or USING clause of a LEFT JOIN, and terms that are usable as ** indices. ** ** This optimization also only applies if the (x1 OR x2 OR ...) term ** is not contained in the ON clause of a LEFT JOIN. ** See ticket http://www.sqlite.org/src/info/f2369304e4 */ if( pWC->nTerm>1 ){ int iTerm; for(iTerm=0; iTerm<pWC->nTerm; iTerm++){ Expr *pExpr = pWC->a[iTerm].pExpr; if( &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(db, 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 implementing 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 */ int jmp1 = 0; /* Address of jump operation */ assert( (pTabItem[0].fg.jointype & JT_LEFT)==0 || ExprHasProperty(pOrExpr, EP_FromJoin) ); 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, 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); |
︙ | ︙ | |||
2329 2330 2331 2332 2333 2334 2335 | 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]; | | | 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 | 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. |
︙ | ︙ | |||
2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 | 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); } | > > > > < < < < | < < < < < < < < | | 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 | pCov = pSubLoop->u.btree.pIndex; }else{ pCov = 0; } if( sqlite3WhereUsesDeferredSeek(pSubWInfo) ){ pWInfo->bDeferredSeek = 1; } if( sqlite3WhereUsesDeferredSeek(pSubWInfo) ){ pWInfo->bDeferredSeek = 1; } /* Finish the loop through table entries that match term pOrTerm. */ sqlite3WhereEnd(pSubWInfo); ExplainQueryPlanPop(pParse); } } } ExplainQueryPlanPop(pParse); pLevel->u.pCovidx = 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. |
︙ | ︙ | |||
2491 2492 2493 2494 2495 2496 2497 | testcase( pWInfo->untestedTerms==0 && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ); pWInfo->untestedTerms = 1; continue; } pE = pTerm->pExpr; assert( pE!=0 ); | < < < < < < | | < < < < < | | < | 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 | testcase( pWInfo->untestedTerms==0 && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)!=0 ); pWInfo->untestedTerms = 1; continue; } pE = pTerm->pExpr; assert( pE!=0 ); if( (pTabItem->fg.jointype&JT_LEFT) && !ExprHasProperty(pE,EP_FromJoin) ){ continue; } if( iLoop==1 && !sqlite3ExprCoveredByIndex(pE, pLevel->iTabCur, pIdx) ){ iNext = 2; continue; } if( iLoop<3 && (pTerm->wtFlags & TERM_VARSELECT) ){ if( iNext==0 ) iNext = 3; continue; |
︙ | ︙ | |||
2533 2534 2535 2536 2537 2538 2539 | 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 } | | < < < < | | < < < < < < | < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | 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)); } #endif sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL); if( skipLikeAddr ) sqlite3VdbeJumpHere(v, skipLikeAddr); pTerm->wtFlags |= TERM_CODED; } iLoop = iNext; }while( iLoop>0 ); /* Insert code to test for implied constraints based on transitivity ** of the "==" operator. ** ** Example: If the WHERE clause contains "t1.a=t2.b" and "t2.b=123" ** and we are coding the t1 loop and the t2 loop has not yet coded, ** then we cannot use the "t1.a=t2.b" constraint, but we can code ** the implied "t1.a=123" constraint. */ for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ Expr *pE, 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( pLevel->iLeftJoin ) continue; pE = pTerm->pExpr; assert( !ExprHasProperty(pE, EP_FromJoin) ); assert( (pTerm->prereqRight & pLevel->notReady)!=0 ); pAlt = sqlite3WhereFindTerm(pWC, iCur, pTerm->u.leftColumn, notReady, WO_EQ|WO_IN|WO_IS, 0); if( pAlt==0 ) continue; if( pAlt->wtFlags & (TERM_CODED) ) continue; if( (pAlt->eOperator & WO_IN) && (pAlt->pExpr->flags & EP_xIsSelect) && (pAlt->pExpr->x.pSelect->pEList->nExpr>1) ){ continue; } testcase( pAlt->eOperator & WO_EQ ); testcase( pAlt->eOperator & WO_IS ); testcase( pAlt->eOperator & WO_IN ); VdbeModuleComment((v, "begin transitive constraint")); sEAlt = *pAlt->pExpr; sEAlt.pLeft = pE->pLeft; sqlite3ExprIfFalse(pParse, &sEAlt, addrCont, SQLITE_JUMPIFNULL); } /* For a LEFT OUTER JOIN, generate code that will record the fact that ** at least one row of the right table has matched the left table. */ if( pLevel->iLeftJoin ){ pLevel->addrFirst = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin); VdbeComment((v, "record LEFT JOIN hit")); for(pTerm=pWC->a, j=0; j<pWC->nTerm; j++, pTerm++){ testcase( pTerm->wtFlags & TERM_VIRTUAL ); testcase( pTerm->wtFlags & TERM_CODED ); if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( (pTerm->prereqAll & pLevel->notReady)!=0 ){ assert( pWInfo->untestedTerms ); continue; } assert( pTerm->pExpr ); sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL); pTerm->wtFlags |= TERM_CODED; } } return pLevel->notReady; } |
Changes to src/whereexpr.c.
︙ | ︙ | |||
60 61 62 63 64 65 66 | static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){ WhereTerm *pTerm; int idx; testcase( wtFlags & TERM_VIRTUAL ); if( pWC->nTerm>=pWC->nSlot ){ WhereTerm *pOld = pWC->a; sqlite3 *db = pWC->pWInfo->pParse->db; | | > > > | < | | 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 | static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){ WhereTerm *pTerm; int idx; testcase( wtFlags & TERM_VIRTUAL ); if( pWC->nTerm>=pWC->nSlot ){ WhereTerm *pOld = pWC->a; sqlite3 *db = pWC->pWInfo->pParse->db; pWC->a = sqlite3DbMallocRawNN(db, sizeof(pWC->a[0])*pWC->nSlot*2 ); if( pWC->a==0 ){ if( wtFlags & TERM_DYNAMIC ){ sqlite3ExprDelete(db, p); } pWC->a = pOld; return 0; } memcpy(pWC->a, pOld, sizeof(pWC->a[0])*pWC->nTerm); if( pOld!=pWC->aStatic ){ sqlite3DbFree(db, pOld); } pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]); } pTerm = &pWC->a[idx = pWC->nTerm++]; if( p && ExprHasProperty(p, EP_Unlikely) ){ pTerm->truthProb = sqlite3LogEst(p->iTable) - 270; }else{ pTerm->truthProb = 1; } pTerm->pExpr = sqlite3ExprSkipCollate(p); pTerm->wtFlags = wtFlags; pTerm->pWC = pWC; pTerm->iParent = -1; memset(&pTerm->eOperator, 0, sizeof(WhereTerm) - offsetof(WhereTerm,eOperator)); return idx; } |
︙ | ︙ | |||
103 104 105 106 107 108 109 110 | 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 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | 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". ** ** If left/right precedence rules come into play when determining the ** collating sequence, then COLLATE operators are adjusted to ensure ** that the collating sequence does not change. For example: ** "Y collate NOCASE op X" becomes "X op Y" because any collation sequence on ** the left hand side of a comparison overrides any collation sequence ** attached to the right. For the same reason the EP_Collate flag ** is not commuted. */ static void exprCommute(Parse *pParse, Expr *pExpr){ u16 expRight = (pExpr->pRight->flags & EP_Collate); u16 expLeft = (pExpr->pLeft->flags & EP_Collate); assert( allowedOp(pExpr->op) && pExpr->op!=TK_IN ); if( expRight==expLeft ){ /* Either X and Y both have COLLATE operator or neither do */ if( expRight ){ /* Both X and Y have COLLATE operators. Make sure X is always ** used by clearing the EP_Collate flag from Y. */ pExpr->pRight->flags &= ~EP_Collate; }else if( sqlite3ExprCollSeq(pParse, pExpr->pLeft)!=0 ){ /* Neither X nor Y have COLLATE operators, but X has a non-default ** collating sequence. So add the EP_Collate marker on X to cause ** it to be searched first. */ pExpr->pLeft->flags |= EP_Collate; } } 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; } } /* ** Translate from TK_xx operator to WO_xx bitmask. */ static u16 operatorMask(int op){ u16 c; |
︙ | ︙ | |||
189 190 191 192 193 194 195 | if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, (char*)wc) ){ return 0; } #ifdef SQLITE_EBCDIC if( *pnoCase ) return 0; #endif | < < | | 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 | 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 ){ 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++; |
︙ | ︙ | |||
235 236 237 238 239 240 241 | /* 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; | < < | < > | < | > > | < < | > | | < < > > > > | | < < | | < < < < < < < < < < < < < < | 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 | /* 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 = 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; /* If the RHS begins with a digit or a minus sign, then the LHS must be ** an ordinary column (not a virtual table column) with TEXT affinity. ** Otherwise the LHS might be numeric and "lhs >= rhs" would be false ** even though "lhs LIKE rhs" is true. But if the RHS does not start ** with a digit or '-', then "lhs LIKE rhs" will always be false if ** the LHS is numeric and so the optimization still works. ** ** 2018-09-10 ticket c94369cae9b561b1f996d0054bfab11389f9d033 ** The RHS pattern must not be '/%' because the termination condition ** will then become "x<'0'" and if the affinity is numeric, will then ** be converted into "x<0", which is incorrect. */ if( sqlite3Isdigit(zNew[0]) || zNew[0]=='-' || (zNew[0]+1=='0' && iTo==1) ){ if( pLeft->op!=TK_COLUMN || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT || IsVirtual(pLeft->y.pTab) /* Value might be numeric */ ){ 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); 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 | { "like", SQLITE_INDEX_CONSTRAINT_LIKE }, { "regexp", SQLITE_INDEX_CONSTRAINT_REGEXP } }; ExprList *pList; Expr *pCol; /* Column reference */ int i; | < | < < | < < < | < < < | | | | | 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 | { "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; if( pCol->op==TK_COLUMN && IsVirtual(pCol->y.pTab) ){ for(i=0; i<ArraySize(aOp); i++){ 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; if( pCol->op==TK_COLUMN && IsVirtual(pCol->y.pTab) ){ 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 ); 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; if( pLeft->op==TK_COLUMN && IsVirtual(pLeft->y.pTab) ){ res++; } if( pRight && pRight->op==TK_COLUMN && IsVirtual(pRight->y.pTab) ){ 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; if( pExpr->op==TK_NOTNULL ) *peOp2 = SQLITE_INDEX_CONSTRAINT_ISNOTNULL; return res; } return 0; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ /* ** If the pBase expression originated in the ON or USING clause of ** a join, then transfer the appropriate markings over to derived. */ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){ if( pDerived ){ pDerived->flags |= pBase->flags & EP_FromJoin; pDerived->iRightJoinTable = pBase->iRightJoinTable; } } /* ** Mark term iChild as being a child of term iParent */ static void markTermAsChild(WhereClause *pWC, int iChild, int iParent){ |
︙ | ︙ | |||
517 518 519 520 521 522 523 | ){ 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 */ | < | 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; |
︙ | ︙ | |||
686 687 688 689 690 691 692 | WhereClause *pAndWC; WhereTerm *pAndTerm; int j; Bitmask b = 0; pOrTerm->u.pAndInfo = pAndInfo; pOrTerm->wtFlags |= TERM_ANDINFO; pOrTerm->eOperator = WO_AND; | < | 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 ){ |
︙ | ︙ | |||
729 730 731 732 733 734 735 | } /* ** Record the set of tables that satisfy case 3. The set might be ** empty. */ pOrInfo->indexable = indexable; | < < > > > | 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 | } /* ** Record the set of tables that satisfy case 3. The set might be ** empty. */ pOrInfo->indexable = indexable; if( indexable ){ pTerm->eOperator = WO_OR; pWC->hasOr = 1; }else{ pTerm->eOperator = WO_OR; } /* For a two-way OR, attempt to implementation case 2. */ if( indexable && pOrWc->nTerm==2 ){ int iOne = 0; WhereTerm *pOne; |
︙ | ︙ | |||
787 788 789 790 791 792 793 | ** and column is found but leave okToChngToIN false if not found. */ for(j=0; j<2 && !okToChngToIN; j++){ Expr *pLeft = 0; pOrTerm = pOrWc->a; for(i=pOrWc->nTerm-1; i>=0; i--, pOrTerm++){ assert( pOrTerm->eOperator & WO_EQ ); | | < | < | | | | < | | | | 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 | ** and column is found but leave okToChngToIN false if not found. */ for(j=0; j<2 && !okToChngToIN; j++){ Expr *pLeft = 0; pOrTerm = pOrWc->a; for(i=pOrWc->nTerm-1; i>=0; i--, pOrTerm++){ assert( pOrTerm->eOperator & WO_EQ ); pOrTerm->wtFlags &= ~TERM_OR_OK; if( pOrTerm->leftCursor==iCursor ){ /* This is the 2-bit case and we are on the second iteration and ** current term is from the first iteration. So skip this term. */ assert( j==1 ); continue; } if( (chngToIN & sqlite3WhereGetMask(&pWInfo->sMaskSet, pOrTerm->leftCursor))==0 ){ /* This term must be of the form t1.a==t2.b where t2 is in the ** chngToIN set but t1 is not. This term will be either preceded ** 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; } iColumn = pOrTerm->u.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 ); if( pOrTerm->leftCursor!=iCursor ){ pOrTerm->wtFlags &= ~TERM_OR_OK; }else if( pOrTerm->u.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 ** conversions are required on the right. (Ticket #2249) */ affRight = sqlite3ExprAffinity(pOrTerm->pExpr->pRight); affLeft = sqlite3ExprAffinity(pOrTerm->pExpr->pLeft); if( affRight!=0 && affRight!=affLeft ){ okToChngToIN = 0; }else{ pOrTerm->wtFlags |= TERM_OR_OK; } } } } /* At this point, okToChngToIN is true if original pTerm satisfies ** case 1. In that case, construct a new virtual term that is ** pTerm converted into an IN operator. */ if( okToChngToIN ){ Expr *pDup; /* A transient duplicate expression */ 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 ); assert( pOrTerm->u.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( !ExprHasProperty(pNew, EP_xIsSelect) ); 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 used again */ markTermAsChild(pWC, idxNew, idxTerm); }else{ sqlite3ExprListDelete(db, pList); } } } } |
︙ | ︙ | |||
911 912 913 914 915 916 917 | ** returned when it should not be, then incorrect answers might result. */ static int termIsEquivalence(Parse *pParse, Expr *pExpr){ char aff1, aff2; CollSeq *pColl; if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0; if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0; | | | | 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 | ** returned when it should not be, then incorrect answers might result. */ static int termIsEquivalence(Parse *pParse, Expr *pExpr){ char aff1, aff2; CollSeq *pColl; if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0; if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0; if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0; aff1 = sqlite3ExprAffinity(pExpr->pLeft); aff2 = sqlite3ExprAffinity(pExpr->pRight); if( aff1!=aff2 && (!sqlite3IsNumericAffinity(aff1) || !sqlite3IsNumericAffinity(aff2)) ){ return 0; } pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight); 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 |
︙ | ︙ | |||
942 943 944 945 946 947 948 | mask |= sqlite3WhereExprListUsage(pMaskSet, pS->pOrderBy); mask |= sqlite3WhereExprUsage(pMaskSet, pS->pWhere); mask |= sqlite3WhereExprUsage(pMaskSet, pS->pHaving); if( ALWAYS(pSrc!=0) ){ int i; for(i=0; i<pSrc->nSrc; i++){ mask |= exprSelectUsage(pMaskSet, pSrc->a[i].pSelect); | < | < | 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 | mask |= sqlite3WhereExprListUsage(pMaskSet, pS->pOrderBy); mask |= sqlite3WhereExprUsage(pMaskSet, pS->pWhere); mask |= sqlite3WhereExprUsage(pMaskSet, pS->pHaving); if( ALWAYS(pSrc!=0) ){ int i; for(i=0; i<pSrc->nSrc; i++){ mask |= exprSelectUsage(pMaskSet, pSrc->a[i].pSelect); mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].pOn); if( pSrc->a[i].fg.isTabFunc ){ mask |= sqlite3WhereExprListUsage(pMaskSet, pSrc->a[i].u1.pFuncArg); } } } pS = pS->pPrior; } |
︙ | ︙ | |||
970 971 972 973 974 975 976 977 | ** ** If pExpr is a TK_COLUMN column reference, then this routine always returns ** true even if that particular column is not indexed, because the column ** might be added to an automatic index later. */ static SQLITE_NOINLINE int exprMightBeIndexed2( SrcList *pFrom, /* The FROM clause */ int *aiCurCol, /* Write the referenced table cursor and column here */ | > | < | | | | | | | | < < | | | | | | < > < < < | | < < < | | < < < < < | 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 | ** ** If pExpr is a TK_COLUMN column reference, then this routine always returns ** true even if that particular column is not indexed, because the column ** might be added to an automatic index later. */ static SQLITE_NOINLINE int exprMightBeIndexed2( SrcList *pFrom, /* The FROM clause */ Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */ int *aiCurCol, /* Write the referenced table cursor and column here */ Expr *pExpr /* An operand of a comparison operator */ ){ Index *pIdx; int i; int iCur; for(i=0; mPrereq>1; i++, mPrereq>>=1){} iCur = pFrom->a[i].iCursor; for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( pIdx->aColExpr==0 ) continue; for(i=0; i<pIdx->nKeyCol; i++){ if( pIdx->aiColumn[i]!=XN_EXPR ) continue; assert( pIdx->bHasExpr ); if( sqlite3ExprCompareSkip(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){ aiCurCol[0] = iCur; aiCurCol[1] = XN_EXPR; return 1; } } } return 0; } static int exprMightBeIndexed( SrcList *pFrom, /* The FROM clause */ Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */ int *aiCurCol, /* Write the referenced table cursor & column here */ Expr *pExpr, /* An operand of a comparison operator */ int op /* The specific comparison operator */ ){ /* 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. ** |
︙ | ︙ | |||
1075 1076 1077 1078 1079 1080 1081 | sqlite3 *db = pParse->db; /* Database connection */ unsigned char eOp2 = 0; /* op2 value for LIKE/REGEXP/GLOB */ int nLeft; /* Number of elements on left side vector */ if( db->mallocFailed ){ return; } | < < < | > | < < < < < < < | < | < < | < < < < < | | | < | | | | | | < < < < < < < < < < < < < | < | | < | | < | | 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 *db = pParse->db; /* Database connection */ unsigned char eOp2 = 0; /* op2 value for LIKE/REGEXP/GLOB */ int nLeft; /* Number of elements on left side vector */ if( db->mallocFailed ){ return; } pTerm = &pWC->a[idxTerm]; pMaskSet = &pWInfo->sMaskSet; 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( ExprHasProperty(pExpr, EP_xIsSelect) ){ pTerm->prereqRight = exprSelectUsage(pMaskSet, pExpr->x.pSelect); }else{ pTerm->prereqRight = sqlite3WhereExprListUsage(pMaskSet, pExpr->x.pList); } }else if( op==TK_ISNULL ){ pTerm->prereqRight = 0; }else{ pTerm->prereqRight = sqlite3WhereExprUsage(pMaskSet, pExpr->pRight); } pMaskSet->bVarSelect = 0; prereqAll = sqlite3WhereExprUsageNN(pMaskSet, pExpr); if( pMaskSet->bVarSelect ) pTerm->wtFlags |= TERM_VARSELECT; if( ExprHasProperty(pExpr, EP_FromJoin) ){ Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->iRightJoinTable); prereqAll |= x; extraRight = x-1; /* ON clause terms may not be used with an index ** on left table of a LEFT JOIN. Ticket #3015 */ if( (prereqAll>>1)>=x ){ sqlite3ErrorMsg(pParse, "ON clause references tables to its right"); return; } } pTerm->prereqAll = prereqAll; pTerm->leftCursor = -1; pTerm->iParent = -1; 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->iField>0 ){ assert( op==TK_IN ); assert( pLeft->op==TK_VECTOR ); pLeft = pLeft->x.pList->a[pTerm->iField-1].pExpr; } if( exprMightBeIndexed(pSrc, prereqLeft, aiCurCol, pLeft, op) ){ pTerm->leftCursor = aiCurCol[0]; pTerm->u.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) ){ WhereTerm *pNew; Expr *pDup; u16 eExtraOp = 0; /* Extra bits for pNew->eOperator */ assert( pTerm->iField==0 ); if( pTerm->leftCursor>=0 ){ int idxNew; pDup = sqlite3ExprDup(db, pExpr, 0); if( db->mallocFailed ){ sqlite3ExprDelete(db, pDup); return; } |
︙ | ︙ | |||
1193 1194 1195 1196 1197 1198 1199 | pTerm->eOperator |= WO_EQUIV; eExtraOp = WO_EQUIV; } }else{ pDup = pExpr; pNew = pTerm; } | | < | < < < < < < < < < < < | < < | 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 | pTerm->eOperator |= WO_EQUIV; eExtraOp = WO_EQUIV; } }else{ pDup = pExpr; pNew = pTerm; } exprCommute(pParse, pDup); pNew->leftCursor = aiCurCol[0]; pNew->u.leftColumn = aiCurCol[1]; testcase( (prereqLeft | extraRight) != prereqLeft ); pNew->prereqRight = prereqLeft | extraRight; pNew->prereqAll = prereqAll; pNew->eOperator = (operatorMask(pDup->op) + eExtraOp) & opMask; } } #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 = pExpr->x.pList; int i; static const u8 ops[] = {TK_GE, TK_LE}; 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), |
︙ | ︙ | |||
1265 1266 1267 1268 1269 1270 1271 | */ else if( pExpr->op==TK_OR ){ assert( pWC->op==TK_AND ); exprAnalyzeOrTerm(pSrc, pWC, idxTerm); pTerm = &pWC->a[idxTerm]; } #endif /* SQLITE_OMIT_OR_OPTIMIZATION */ | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < | 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 | */ 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. */ if( 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; pLeft = pExpr->x.pList->a[1].pExpr; pStr2 = sqlite3ExprDup(db, pStr1, 0); /* 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; |
︙ | ︙ | |||
1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 | pNewExpr1 = sqlite3ExprDup(db, pLeft, 0); pNewExpr1 = sqlite3PExpr(pParse, TK_GE, sqlite3ExprAddCollateString(pParse,pNewExpr1,zCollSeqName), pStr1); transferJoinMarkings(pNewExpr1, pExpr); idxNew1 = whereClauseInsert(pWC, pNewExpr1, wtFlags); testcase( idxNew1==0 ); pNewExpr2 = sqlite3ExprDup(db, pLeft, 0); pNewExpr2 = sqlite3PExpr(pParse, TK_LT, sqlite3ExprAddCollateString(pParse,pNewExpr2,zCollSeqName), pStr2); transferJoinMarkings(pNewExpr2, pExpr); idxNew2 = whereClauseInsert(pWC, pNewExpr2, wtFlags); testcase( idxNew2==0 ); | > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | pNewExpr1 = sqlite3ExprDup(db, pLeft, 0); pNewExpr1 = sqlite3PExpr(pParse, TK_GE, sqlite3ExprAddCollateString(pParse,pNewExpr1,zCollSeqName), pStr1); transferJoinMarkings(pNewExpr1, pExpr); idxNew1 = whereClauseInsert(pWC, pNewExpr1, wtFlags); testcase( idxNew1==0 ); exprAnalyze(pSrc, pWC, idxNew1); pNewExpr2 = sqlite3ExprDup(db, pLeft, 0); pNewExpr2 = sqlite3PExpr(pParse, TK_LT, sqlite3ExprAddCollateString(pParse,pNewExpr2,zCollSeqName), pStr2); transferJoinMarkings(pNewExpr2, pExpr); idxNew2 = whereClauseInsert(pWC, pNewExpr2, wtFlags); testcase( idxNew2==0 ); exprAnalyze(pSrc, pWC, idxNew2); 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. */ 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); } idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew==0 ); pNewTerm = &pWC->a[idxNew]; pNewTerm->prereqRight = prereqExpr; pNewTerm->leftCursor = pLeft->iTable; pNewTerm->u.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 */ /* 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( pWC->op==TK_AND && (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) ){ int i; for(i=0; i<nLeft; i++){ int idxNew; Expr *pNew; Expr *pLeft = sqlite3ExprForVectorField(pParse, pExpr->pLeft, i); Expr *pRight = sqlite3ExprForVectorField(pParse, pExpr->pRight, i); 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.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 */ if( pWC->op==TK_AND && pExpr->op==TK_IN && pTerm->iField==0 && pExpr->pLeft->op==TK_VECTOR && pExpr->x.pSelect->pPrior==0 ){ int i; for(i=0; i<sqlite3ExprVectorSize(pExpr->pLeft); i++){ int idxNew; idxNew = whereClauseInsert(pWC, pExpr, TERM_VIRTUAL); pWC->a[idxNew].iField = i+1; exprAnalyze(pSrc, pWC, idxNew); markTermAsChild(pWC, idxNew, idxTerm); } } #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 /* When sqlite_stat3 histogram data is available an operator of 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. ** ** Note that the virtual term must be tagged with TERM_VNULL. */ if( pExpr->op==TK_NOTNULL && pExpr->pLeft->op==TK_COLUMN && pExpr->pLeft->iColumn>=0 && !ExprHasProperty(pExpr, EP_FromJoin) && OptimizationEnabled(db, SQLITE_Stat34) ){ 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.leftColumn = pLeft->iColumn; pNewTerm->eOperator = WO_GT; markTermAsChild(pWC, idxNew, idxTerm); pTerm = &pWC->a[idxTerm]; pTerm->wtFlags |= TERM_COPIED; pNewTerm->prereqAll = pTerm->prereqAll; } } #endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ /* 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; |
︙ | ︙ | |||
1531 1532 1533 1534 1535 1536 1537 | ** 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){ | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > | | < < < < < | | | < | < | < | | | | | < < > < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < > > > > > > | | < < < < < < < < < < < | 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 | ** 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 = sqlite3ExprSkipCollate(pExpr); pWC->op = op; if( pE2==0 ) return; if( pE2->op!=op ){ whereClauseInsert(pWC, pExpr, 0); }else{ sqlite3WhereSplit(pWC, pE2->pLeft, op); sqlite3WhereSplit(pWC, pE2->pRight, op); } } /* ** Initialize a preallocated WhereClause structure. */ void sqlite3WhereClauseInit( WhereClause *pWC, /* The WhereClause to be initialized */ WhereInfo *pWInfo /* The WHERE processing context */ ){ pWC->pWInfo = pWInfo; pWC->hasOr = 0; pWC->pOuter = 0; pWC->nTerm = 0; pWC->nSlot = ArraySize(pWC->aStatic); pWC->a = pWC->aStatic; } /* ** Deallocate a WhereClause structure. The WhereClause structure ** itself is not freed. This routine is the inverse of ** sqlite3WhereClauseInit(). */ void sqlite3WhereClauseClear(WhereClause *pWC){ int i; WhereTerm *a; sqlite3 *db = pWC->pWInfo->pParse->db; for(i=pWC->nTerm-1, a=pWC->a; i>=0; i--, a++){ if( a->wtFlags & TERM_DYNAMIC ){ sqlite3ExprDelete(db, a->pExpr); } if( a->wtFlags & TERM_ORINFO ){ whereOrInfoDelete(db, a->u.pOrInfo); }else if( a->wtFlags & TERM_ANDINFO ){ whereAndInfoDelete(db, a->u.pAndInfo); } } if( pWC->a!=pWC->aStatic ){ sqlite3DbFree(db, pWC->a); } } /* ** These routines walk (recursively) an expression tree and generate ** a bitmask indicating which tables are used in that expression ** tree. */ Bitmask sqlite3WhereExprUsageNN(WhereMaskSet *pMaskSet, Expr *p){ Bitmask mask; if( p->op==TK_COLUMN && !ExprHasProperty(p, EP_FixedCol) ){ return sqlite3WhereGetMask(pMaskSet, p->iTable); }else if( ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){ assert( p->op!=TK_IF_NULL_ROW ); 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( ExprHasProperty(p, EP_xIsSelect) ){ 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->y.pWin ){ mask |= sqlite3WhereExprListUsage(pMaskSet, p->y.pWin->pPartition); mask |= sqlite3WhereExprListUsage(pMaskSet, p->y.pWin->pOrderBy); } #endif return mask; } Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){ return p ? sqlite3WhereExprUsageNN(pMaskSet,p) : 0; } Bitmask sqlite3WhereExprListUsage(WhereMaskSet *pMaskSet, ExprList *pList){ int i; Bitmask mask = 0; if( pList ){ |
︙ | ︙ | |||
1820 1821 1822 1823 1824 1825 1826 | ** 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 */ | | < < < | | < < < | 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 | ** 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 */ struct SrcList_item *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; if( pItem->fg.isTabFunc==0 ) return; pTab = pItem->pTab; assert( pTab!=0 ); pArgs = pItem->u1.pFuncArg; if( pArgs==0 ) return; for(j=k=0; j<pArgs->nExpr; j++){ Expr *pRhs; while( k<pTab->nCol && (pTab->aCol[k].colFlags & COLFLAG_HIDDEN)==0 ){k++;} if( k>=pTab->nCol ){ sqlite3ErrorMsg(pParse, "too many arguments on %s() - max %d", 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); if( pItem->fg.jointype & JT_LEFT ){ sqlite3SetJoinExpr(pTerm, pItem->iCursor); } whereClauseInsert(pWC, pTerm, TERM_DYNAMIC); } } |
Changes to src/window.c.
︙ | ︙ | |||
577 578 579 580 581 582 583 | 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 | 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_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_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_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. |
︙ | ︙ | |||
720 721 722 723 724 725 726 | pWin->pStart = sqlite3Expr(db, TK_INTEGER, "1"); } break; } } } } | | < < < | 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 | 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; 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; /* 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 ){ |
︙ | ︙ | |||
779 780 781 782 783 784 785 | for(pWin=p->pWin; pWin; pWin=pWin->pNextWin){ if( pExpr->y.pWin==pWin ){ assert( pWin->pOwner==pExpr ); return WRC_Prune; } } } | | < < < < < < < < < < < < | < | < < | < < | | 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 | for(pWin=p->pWin; pWin; pWin=pWin->pNextWin){ if( pExpr->y.pWin==pWin ){ assert( pWin->pOwner==pExpr ); return WRC_Prune; } } } /* Fall through. */ case TK_AGG_FUNCTION: case TK_COLUMN: { Expr *pDup = sqlite3ExprDup(pParse->db, pExpr, 0); p->pSub = sqlite3ExprListAppend(pParse, p->pSub, pDup); if( p->pSub ){ 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 = p->pSub->nExpr-1; pExpr->iTable = p->pWin->iEphCsr; } break; } default: /* no-op */ break; } |
︙ | ︙ | |||
855 856 857 858 859 860 861 | ** appending the new one. */ static void selectWindowRewriteEList( Parse *pParse, Window *pWin, SrcList *pSrc, ExprList *pEList, /* Rewrite expressions in this list */ | < < < | < < | < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < | < < < < < < < < < < < < < < < < < < | | | < < < | | | | < < < < < < | < < < | < | < < < < < < < < < | < < < < < < | | < < < < < | > > > > > | < < < < | < < < < < < < < < < < < < < > | > > | 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 | ** 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 */ ExprList *pAppend /* List of values to append. Might be NULL */ ){ if( pAppend ){ int i; int nInit = pList ? pList->nExpr : 0; for(i=0; i<pAppend->nExpr; i++){ Expr *pDup = sqlite3ExprDup(pParse->db, pAppend->a[i].pExpr, 0); pList = sqlite3ExprListAppend(pParse, pList, pDup); if( pList ) pList->a[nInit+i].sortOrder = pAppend->a[i].sortOrder; } } return pList; } /* ** 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 ){ 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; /* Master window object */ Window *pWin; /* Window object iterator */ p->pSrc = 0; p->pWhere = 0; p->pGroupBy = 0; p->pHaving = 0; /* 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 = sqlite3ExprListDup(db, pMWin->pPartition, 0); pSort = exprListAppendList(pParse, pSort, pMWin->pOrderBy); if( pSort && p->pOrderBy ){ if( sqlite3ExprListCompare(pSort, p->pOrderBy, -1)==0 ){ sqlite3ExprListDelete(db, p->pOrderBy); p->pOrderBy = 0; } } /* 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, &pSublist); selectWindowRewriteEList(pParse, pMWin, pSrc, p->pOrderBy, &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); pSublist = exprListAppendList(pParse, pSublist, pMWin->pOrderBy); /* 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){ pWin->iArgCol = (pSublist ? pSublist->nExpr : 0); pSublist = exprListAppendList(pParse, pSublist, pWin->pOwner->x.pList); 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, sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[0], 0) ); } pSub = sqlite3SelectNew( pParse, pSublist, pSrc, pWhere, pGroupBy, pHaving, pSort, 0, 0 ); p->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); if( p->pSrc ){ p->pSrc->a[0].pSelect = pSub; sqlite3SrcListAssignCursors(pParse, p->pSrc); if( sqlite3ExpandSubquery(pParse, &p->pSrc->a[0]) ){ rc = SQLITE_NOMEM; }else{ pSub->selFlags |= SF_Expanded; p->selFlags &= ~SF_Aggregate; sqlite3SelectPrep(pParse, pSub, 0); } sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, pSublist->nExpr); 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); }else{ sqlite3SelectDelete(db, pSub); } if( db->mallocFailed ) rc = SQLITE_NOMEM; } return rc; } /* ** Free the Window object passed as the second argument. */ void sqlite3WindowDelete(sqlite3 *db, Window *p){ if( p ){ if( p->ppThis ){ *p->ppThis = p->pNextWin; if( p->pNextWin ) p->pNextWin->ppThis = p->ppThis; } 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); |
︙ | ︙ | |||
1306 1307 1308 1309 1310 1311 1312 | /* ** Attach window object pWin to expression p. */ void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){ if( p ){ assert( p->op==TK_FUNCTION ); | > > > | | | | | | | < | < < | < < < < < < < < < < < < < < < < < | | < | | | < < | < | | < < < < < < < | < < | < < < < < < < | < < < < < < < | 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 | /* ** Attach window object pWin to expression p. */ void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){ if( p ){ assert( p->op==TK_FUNCTION ); /* This routine is only called for the parser. If pWin was not ** allocated due to an OOM, then the parser would fail before ever ** invoking this routine */ if( ALWAYS(pWin) ){ p->y.pWin = pWin; ExprSetProperty(p, EP_WinFunc); pWin->pOwner = p; if( p->flags & EP_Distinct ){ sqlite3ErrorMsg(pParse, "DISTINCT is not supported for window functions"); } } }else{ sqlite3WindowDelete(pParse->db, pWin); } } /* ** Return 0 if the two window objects are identical, or non-zero otherwise. ** Identical window objects can be processed in a single scan. */ int sqlite3WindowCompare(Parse *pParse, Window *p1, Window *p2){ 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( sqlite3ExprListCompare(p1->pPartition, p2->pPartition, -1) ) return 1; if( sqlite3ExprListCompare(p1->pOrderBy, p2->pOrderBy, -1) ) return 1; 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, Window *pMWin){ Window *pWin; Vdbe *v = sqlite3GetVdbe(pParse); /* 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); |
︙ | ︙ | |||
1416 1417 1418 1419 1420 1421 1422 | 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){ | | < < < | | | | | | 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 | 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 = pWin->pOwner->x.pList; KeyInfo *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->aSortOrder[0]==0 ); pKeyInfo->aSortOrder[0] = 1; } 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 |
︙ | ︙ | |||
1500 1501 1502 1503 1504 1505 1506 | 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); | < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < | | < < < < < < | 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 | 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); 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){ ExprList *pList = pWin->pOwner->x.pList; return (pList ? pList->nExpr : 0); } /* ** 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. ** ** If argument csr is greater than or equal to 0, then argument reg is ** the first register in an array of registers guaranteed to be large ** enough to hold the array of arguments for each function. In this case ** the arguments are extracted from the current row of csr into the ** array of registers before invoking OP_AggStep or OP_AggInverse ** ** 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( Parse *pParse, 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 */ ){ Vdbe *v = sqlite3GetVdbe(pParse); Window *pWin; for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ FuncDef *pFunc = pWin->pFunc; int regArg; int nArg = windowArgCount(pWin); int i; 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); } } |
︙ | ︙ | |||
1704 1705 1706 1707 1708 1709 1710 | ); 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; | < | | < < < < < < < < < < < < < < < < < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | 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 | ); 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( nArg==0 || nArg==pWin->pOwner->x.pList->nExpr ); assert( 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( pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){ CollSeq *pColl; assert( nArg>0 ); 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( addrIf ) sqlite3VdbeJumpHere(v, addrIf); } } } typedef struct WindowCodeArg WindowCodeArg; typedef struct WindowCsrAndReg WindowCsrAndReg; struct WindowCsrAndReg { int csr; int reg; }; struct WindowCodeArg { Parse *pParse; Window *pMWin; Vdbe *pVdbe; int regGosub; int addrGosub; int regArg; int eDelete; WindowCsrAndReg start; WindowCsrAndReg current; WindowCsrAndReg end; }; /* ** 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 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 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 |
︙ | ︙ | |||
1816 1817 1818 1819 1820 1821 1822 | int regRowid = 0; /* AggStep rowid value */ int regPeer = 0; /* AggStep peer values */ int nPeer; int lblNext; int lblBrk; int addrNext; | | < < < < | 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 | int regRowid = 0; /* AggStep rowid value */ int regPeer = 0; /* AggStep peer values */ int nPeer; int lblNext; int lblBrk; int addrNext; int csr = pMWin->csrApp; nPeer = (pMWin->pOrderBy ? pMWin->pOrderBy->nExpr : 0); lblNext = sqlite3VdbeMakeLabel(pParse); lblBrk = sqlite3VdbeMakeLabel(pParse); regCRowid = sqlite3GetTempReg(pParse); regRowid = sqlite3GetTempReg(pParse); |
︙ | ︙ | |||
1876 1877 1878 1879 1880 1881 1882 | VdbeCoverageEqNe(v); }else{ sqlite3VdbeAddOp2(v, OP_Goto, 0, lblNext); } if( addrEq ) sqlite3VdbeJumpHere(v, addrEq); } | | < | 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 | VdbeCoverageEqNe(v); }else{ sqlite3VdbeAddOp2(v, OP_Goto, 0, lblNext); } if( addrEq ) sqlite3VdbeJumpHere(v, addrEq); } windowAggStep(pParse, 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); } /* ** 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 |
︙ | ︙ | |||
1918 1919 1920 1921 1922 1923 1924 | if( pMWin->regStartRowid ){ windowFullScan(p); }else{ Parse *pParse = p->pParse; Window *pWin; for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ | | < | 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 | if( pMWin->regStartRowid ){ windowFullScan(p); }else{ Parse *pParse = p->pParse; Window *pWin; for(pWin=pMWin; pWin; pWin=pWin->pNextWin){ FuncDef *pFunc = pWin->pFunc; 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); |
︙ | ︙ | |||
1990 1991 1992 1993 1994 1995 1996 | */ 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){ | | < | 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 | */ 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; 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); } |
︙ | ︙ | |||
2020 2021 2022 2023 2024 2025 2026 | ** 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){ | | | 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 | ** 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; } |
︙ | ︙ | |||
2068 2069 2070 2071 2072 2073 2074 | 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 | | < < < < < < < < < < < < | | | | | | | | < | | < | | < < < | < | | < < < < | < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < | < | < < < < < < | < < < < < < < < < < | < < < < < < < < < < < < < > < < > > | 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 | 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, it generates code equivalent to: ** ** if( csr1.peerVal + regVal >= csr2.peerVal ) goto lbl; ** ** A special type of arithmetic is used such that if csr.peerVal is not ** a numeric type (real or integer), then the result of the addition is ** a copy of csr1.peerVal. */ static void windowCodeRangeTest( WindowCodeArg *p, int op, /* OP_Ge or OP_Gt */ int csr1, int regVal, int csr2, int lbl ){ Parse *pParse = p->pParse; Vdbe *v = sqlite3GetVdbe(pParse); int reg1 = sqlite3GetTempReg(pParse); int reg2 = sqlite3GetTempReg(pParse); int arith = OP_Add; int addrGe; int regString = ++pParse->nMem; assert( op==OP_Ge || op==OP_Gt || op==OP_Le ); assert( p->pMWin->pOrderBy && p->pMWin->pOrderBy->nExpr==1 ); if( p->pMWin->pOrderBy->a[0].sortOrder ){ 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; } windowReadPeerValues(p, csr1, reg1); windowReadPeerValues(p, csr2, reg2); /* Check if the peer value for csr1 value is a text or blob by comparing ** it to the smallest possible string - ''. If it is, jump over the ** OP_Add or OP_Subtract operation and proceed directly to the comparison. */ sqlite3VdbeAddOp4(v, OP_String8, 0, regString, 0, "", P4_STATIC); addrGe = sqlite3VdbeAddOp3(v, OP_Ge, regString, 0, reg1); VdbeCoverage(v); sqlite3VdbeAddOp3(v, arith, regVal, reg1, reg1); sqlite3VdbeJumpHere(v, addrGe); sqlite3VdbeAddOp3(v, op, reg2, lbl, reg1); VdbeCoverage(v); sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); 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); } /* ** 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 addrIf = 0; int addrContinue = 0; int addrGoto = 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. */ |
︙ | ︙ | |||
2264 2265 2266 2267 2268 2269 2270 | } }else{ windowCodeRangeTest( p, OP_Gt, p->end.csr, regCountdown, p->current.csr, lblDone ); } }else{ | | < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | > > < | < < < < < < | 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 | } }else{ windowCodeRangeTest( p, OP_Gt, p->end.csr, regCountdown, p->current.csr, lblDone ); } }else{ addrIf = sqlite3VdbeAddOp3(v, OP_IfPos, regCountdown, 0, 1); VdbeCoverage(v); } } if( op==WINDOW_RETURN_ROW && pMWin->regStartRowid==0 ){ windowAggFinal(p, 0); } addrContinue = sqlite3VdbeCurrentAddr(v); 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(pParse, 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(pParse, 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 ){ addrGoto = sqlite3VdbeAddOp0(v, OP_Goto); } } 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); if( addrGoto ) sqlite3VdbeJumpHere(v, addrGoto); if( addrIf ) sqlite3VdbeJumpHere(v, addrIf); 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->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->pStart = sqlite3ExprDup(db, p->pStart, 0); pNew->pEnd = sqlite3ExprDup(db, p->pEnd, 0); pNew->pOwner = pOwner; } } return pNew; } /* ** Return a copy of the linked list of Window objects passed as the |
︙ | ︙ | |||
2716 2717 2718 2719 2720 2721 2722 | ** } ** Insert new row into eph table. ** if( first row of partition ){ ** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) ** regEnd = <expr2> ** regStart = <expr1> ** }else{ | | | 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 | ** } ** Insert new row into eph table. ** if( first row of partition ){ ** Rewind(csrEnd) ; Rewind(csrStart) ; Rewind(csrCurrent) ** regEnd = <expr2> ** regStart = <expr1> ** }else{ ** if( (csrEnd.key + regEnd) <= csrCurrent.key ){ ** AGGSTEP ** } ** while( (csrStart.key + regStart) < csrCurrent.key ){ ** AGGINVERSE ** } ** RETURN_ROW ** } |
︙ | ︙ | |||
2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 | 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 */ | > > > < < | 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 | 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 regStart = 0; /* Value of <expr> PRECEDING */ int regEnd = 0; /* Value of <expr> FOLLOWING */ int regNew; /* Array of registers holding new input row */ int regRecord; /* regNew array in record form */ int regRowid; /* Rowid for regRecord in eph table */ 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 */ 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 ); |
︙ | ︙ | |||
2862 2863 2864 2865 2866 2867 2868 | /* 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; | | | 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 | /* 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; 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; } |
︙ | ︙ | |||
2918 2919 2920 2921 2922 2923 2924 | 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 */ | | | | | | | | > | > | > | > | 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 | 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, regRowid); sqlite3VdbeAddOp3(v, OP_Insert, csrWrite, regRecord, regRowid); addrNe = sqlite3VdbeAddOp3(v, OP_Ne, pMWin->regOne, 0, 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->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); } |
︙ | ︙ | |||
3034 3035 3036 3037 3038 3039 3040 | /* Fall through */ if( pMWin->pPartition ){ addrInteger = sqlite3VdbeAddOp2(v, OP_Integer, 0, regFlushPart); sqlite3VdbeJumpHere(v, addrGosubFlush); } | < | 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 | /* Fall through */ if( pMWin->pPartition ){ addrInteger = sqlite3VdbeAddOp2(v, OP_Integer, 0, regFlushPart); sqlite3VdbeJumpHere(v, addrGosubFlush); } 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); |
︙ | ︙ |
Changes to test/affinity2.test.
︙ | ︙ | |||
10 11 12 13 14 15 16 | #*********************************************************************** # 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 | < | 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, |
︙ | ︙ | |||
55 56 57 58 59 60 61 | 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} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 54 55 56 57 58 59 60 61 | 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 |
Changes to test/affinity3.test.
︙ | ︙ | |||
26 27 28 29 30 31 32 | CREATE TABLE apr (id INT PRIMARY KEY, apr REAL); CREATE VIEW v1 AS SELECT c.id, i.apr FROM customer c LEFT JOIN apr i ON i.id=c.id; | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | CREATE TABLE apr (id INT PRIMARY KEY, apr REAL); CREATE VIEW v1 AS SELECT c.id, i.apr FROM customer c LEFT JOIN apr i ON i.id=c.id; CREATE VIEW v2 AS SELECT c.id, v1.apr FROM customer c LEFT JOIN v1 ON v1.id=c.id; INSERT INTO customer (id) VALUES (1); INSERT INTO apr (id, apr) VALUES (1, 12); INSERT INTO customer (id) VALUES (2); INSERT INTO apr (id, apr) VALUES (2, 12.01); } do_execsql_test affinity3-110 { PRAGMA automatic_index=ON; SELECT id, (apr / 100), typeof(apr) apr_type FROM v1; } {1 0.12 real 2 0.1201 real} do_execsql_test affinity3-120 { SELECT id, (apr / 100), typeof(apr) apr_type FROM v2; } {1 0.12 real 2 0.1201 real} do_execsql_test affinity3-130 { PRAGMA automatic_index=OFF; SELECT id, (apr / 100), typeof(apr) apr_type FROM v1; } {1 0.12 real 2 0.1201 real} do_execsql_test affinity3-140 { SELECT id, (apr / 100), typeof(apr) apr_type FROM v2; } {1 0.12 real 2 0.1201 real} # Ticket https://www.sqlite.org/src/info/7ffd1ca1d2ad4ecf (2017-01-16) # Incorrect affinity when using automatic indexes # do_execsql_test affinity3-200 { CREATE TABLE map_integer (id INT, name); INSERT INTO map_integer VALUES(1,'a'); |
︙ | ︙ | |||
103 104 105 106 107 108 109 | 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); | | | | | | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | 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); } {1 abc a 4 xyz e} do_execsql_test affinity3-260 { SELECT * FROM data JOIN mzed USING(id); } {1 abc a 4 xyz e} finish_test |
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 | # 2012 August 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 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); |
︙ | ︙ | |||
133 134 135 136 137 138 139 | (SELECT sum(value2==xyz) FROM t2) FROM (SELECT curr.value1 as xyz FROM t1 AS curr LEFT JOIN t1 AS other GROUP BY curr.id1); } } {1 1} | < < < < < < < < < < < | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | (SELECT sum(value2==xyz) FROM t2) FROM (SELECT curr.value1 as xyz FROM t1 AS curr LEFT JOIN t1 AS other GROUP BY curr.id1); } } {1 1} do_test aggnested-3.2 { db eval { DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t2; CREATE TABLE t1 ( id1 INTEGER, value1 INTEGER, |
︙ | ︙ | |||
240 241 242 243 244 245 246 | 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} | | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 228 229 230 231 232 233 234 235 236 237 | 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} 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 1 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 0 # 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 | } } {t3102a_rename t3102b_rename t3102c} # Ticket #3651 do_test alter-14.1 { catchsql { CREATE TABLE t3651(a UNIQUE); | < > | 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); 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 stat3 { lappend system_table_list 3 sqlite_stat3 } 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 | 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} } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
Changes to test/alter3.test.
︙ | ︙ | |||
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 { | > > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # #************************************************************************* # This file implements regression tests for SQLite library. The # focus of this script is testing that SQLite can handle a subtle # file format change that may be used in the future to implement # "ALTER TABLE ... ADD COLUMN". # # $Id: alter3.test,v 1.11 2008/03/19 00:21:31 drh Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable !altertable { |
︙ | ︙ | |||
48 49 50 51 52 53 54 | # 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 { | < > | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | # 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 { PRAGMA legacy_file_format=ON; 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 { |
︙ | ︙ | |||
110 111 112 113 114 115 116 | DROP TABLE t3; } } {} do_test alter3-2.1 { execsql { CREATE TABLE t1(a, b); | < | 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 { |
︙ | ︙ | |||
193 194 195 196 197 198 199 | } {11} } do_test alter3-4.1 { db close forcedelete test.db set ::DB [sqlite3 db test.db] | < > | 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | } {11} } do_test alter3-4.1 { db close forcedelete test.db set ::DB [sqlite3 db test.db] execsql { PRAGMA legacy_file_format=ON; 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 | } {} do_test alter3-8.2 { execsql { SELECT sql FROM sqlite_master WHERE name = 't4'; } } [list $::sql] | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 390 391 392 393 394 395 396 397 | } {} do_test alter3-8.2 { execsql { SELECT sql FROM sqlite_master WHERE name = 't4'; } } [list $::sql] finish_test |
Changes to test/alter4.test.
︙ | ︙ | |||
119 120 121 122 123 124 125 | DROP TABLE t3; } } {} do_test alter4-2.1 { execsql { CREATE TABLE temp.t1(a, b); | < | 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 { |
︙ | ︙ | |||
314 315 316 317 318 319 320 | 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); | | | | | | 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 | 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; } } {b 1 2 a 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; } } {b 1 2 a 1 2 b 3 4 a 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); |
︙ | ︙ | |||
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: | < > < | 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 | # 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 { PRAGMA legacy_file_format=on; 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); 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 | 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 {} {}} | < < < < < < < < < < < < < < < < < < < < < | 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 |
Changes to test/altercol.test.
︙ | ︙ | |||
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 { | > > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # #************************************************************************* # This file implements regression tests for SQLite library. The # focus of this script is testing that SQLite can handle a subtle # file format change that may be used in the future to implement # "ALTER TABLE ... RENAME COLUMN ... TO". # # $Id: alter4.test,v 1.1 2009/02/02 18:03:22 drh Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix altercol # If SQLITE_OMIT_ALTERTABLE is defined, omit this file. ifcapable !altertable { |
︙ | ︙ | |||
549 550 551 552 553 554 555 | DROP TRIGGER tr1; CREATE INDEX x1i ON x1(i); SELECT sql FROM sqlite_master WHERE name='x1i'; } {{CREATE INDEX x1i ON x1(i)}} sqlite3_db_config db DEFENSIVE 0 do_execsql_test 13.1.4 { | | < < < | < < | 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 | DROP TRIGGER tr1; CREATE INDEX x1i ON x1(i); SELECT sql FROM sqlite_master WHERE name='x1i'; } {{CREATE INDEX x1i ON x1(i)}} sqlite3_db_config db DEFENSIVE 0 do_execsql_test 13.1.4 { PRAGMA writable_schema = 1; UPDATE sqlite_master SET sql = 'CREATE INDEX x1i ON x1(j)' WHERE name='x1i'; } {} do_catchsql_test 13.1.5 { ALTER TABLE x1 RENAME COLUMN t TO ttt; } {1 {error in index x1i: no such column: j}} 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 {database disk image is malformed}} 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); } foreach {tn trigger error} { 1 { |
︙ | ︙ | |||
617 618 619 620 621 622 623 | ALTER TABLE x1 RENAME COLUMN t TO ttt; } "1 {error in trigger tr1: $error}" } #------------------------------------------------------------------------- # Passing invalid parameters directly to sqlite_rename_column(). # | | | 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 | 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 1 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)', |
︙ | ︙ | |||
640 641 642 643 644 645 646 | } {} do_execsql_test 14.2 { SELECT sqlite_rename_column(sql, type, object, db, tbl, icol, znew, bquote, 0) FROM ddd; } {{} {} {} {}} | | | 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 | } {} 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 0 # 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); |
︙ | ︙ | |||
803 804 805 806 807 808 809 | 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))}} | < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 800 801 802 803 804 805 806 807 808 809 | 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))}} finish_test |
Deleted test/altercorrupt.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/alterdropcol.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/alterdropcol2.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/alterfault.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 {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 {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.
︙ | ︙ | |||
21 22 23 24 25 26 27 | return } do_execsql_test 1.0 { CREATE TABLE t1(abcd, efgh); } faultsim_save_and_close | < < < < < | | | | 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 | return } do_execsql_test 1.0 { CREATE TABLE t1(abcd, efgh); } faultsim_save_and_close do_faultsim_test 1 -prep { faultsim_restore_and_reopen } -body { execsql { ALTER TABLE t1 RENAME abcd TO dcba } } -test { faultsim_test_result {0 {}} } catch {db close} forcedelete test.db sqlite3 db test.db do_execsql_test 2.0 { PRAGMA encoding = 'utf-16'; CREATE TABLE t1(abcd, efgh); } faultsim_save_and_close do_faultsim_test 2 -prep { faultsim_restore_and_reopen } -body { execsql { ALTER TABLE t1 RENAME abcd TO dcba } } -test { faultsim_test_result {0 {}} } reset_db do_execsql_test 3.0 { CREATE TABLE t1(abcd, efgh); CREATE VIEW v1 AS SELECT * FROM t1 WHERE abcd>efgh; } faultsim_save_and_close do_faultsim_test 3 -prep { faultsim_restore_and_reopen } -body { execsql { ALTER TABLE t1 RENAME abcd TO dcba } } -test { faultsim_test_result {0 {}} } reset_db do_execsql_test 4.0 { CREATE TABLE rr(a, b); CREATE VIEW vv AS SELECT * FROM rr; |
︙ | ︙ | |||
96 97 98 99 100 101 102 | faultsim_restore_and_reopen execsql { SELECT * FROM sqlite_master } } -body { execsql { ALTER TABLE rr RENAME a TO c; } } -test { | | < < < < < < < < < < < < < < < < < < < < < | 91 92 93 94 95 96 97 98 99 100 101 | 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 |
Deleted test/altermalloc3.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/alterqf.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 1 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 0 } #------------------------------------------------------------------------- # reset_db forcedelete test.db2 do_execsql_test 8.1 { |
︙ | ︙ | |||
536 537 538 539 540 541 542 | register_tcl_module db sqlite3_db_config db DEFENSIVE 1 do_execsql_test 16.0 { CREATE VIRTUAL TABLE y1 USING fts3; | < | 536 537 538 539 540 541 542 543 544 545 546 547 548 549 | register_tcl_module db sqlite3_db_config db DEFENSIVE 1 do_execsql_test 16.0 { CREATE VIRTUAL TABLE y1 USING fts3; } 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 { |
︙ | ︙ | |||
576 577 578 579 580 581 582 | } do_execsql_test 16.40 { SELECT * FROM z1_segments; } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 575 576 577 578 579 580 581 582 | } do_execsql_test 16.40 { SELECT * FROM z1_segments; } } finish_test |
Changes to test/altertab2.test.
︙ | ︙ | |||
334 335 336 337 338 339 340 | 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); } | | < < < < | < < | | < < < < < | 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 | 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.1 { CREATE TABLE t4(a, b); CREATE VIEW v4 AS SELECT * FROM t4 WHERE (a=1 AND 0) OR b=2; } do_execsql_test 8.2 { 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}} finish_test |
Changes to test/altertab3.test.
︙ | ︙ | |||
75 76 77 78 79 80 81 | 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' | | | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | 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 (bbb 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 |
︙ | ︙ | |||
138 139 140 141 142 143 144 | ); } do_execsql_test 6.1 { ALTER TABLE Table0 RENAME Col0 TO Col0; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 138 139 140 141 142 143 144 145 146 147 | ); } do_execsql_test 6.1 { ALTER TABLE Table0 RENAME Col0 TO Col0; } finish_test |
Deleted test/altertrig.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 352 | sqlite3 db test.db execsql { SELECT * FROM t4 WHERE x=1234; } } {} # Verify that DROP TABLE and DROP INDEX remove entries from the # sqlite_stat1, sqlite_stat3 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||stat3 { ifcapable stat4 {set stat sqlite_stat4} else {set stat sqlite_stat3} do_test analyze-5.1 { execsql " SELECT DISTINCT idx FROM $stat ORDER BY 1; SELECT DISTINCT tbl FROM $stat 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||stat3 { do_test analyze-5.3 { execsql " SELECT DISTINCT idx FROM $stat ORDER BY 1; SELECT DISTINCT tbl FROM $stat 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||stat3 { do_test analyze-5.5 { execsql " SELECT DISTINCT idx FROM $stat ORDER BY 1; SELECT DISTINCT tbl FROM $stat 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 | # instead of literal constant arguments. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix analyze3 ifcapable !stat4&&!stat3 { finish_test return } #---------------------------------------------------------------------- # Test Organization: # |
︙ | ︙ | |||
106 107 108 109 110 111 112 | execsql { INSERT INTO t1 VALUES($i+100, $i) } } execsql { COMMIT; ANALYZE; } | > | > > > | | | | | | | | 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 | execsql { INSERT INTO t1 VALUES($i+100, $i) } } execsql { COMMIT; ANALYZE; } ifcapable stat4 { execsql { SELECT count(*)>0 FROM sqlite_stat4; } } else { execsql { SELECT count(*)>0 FROM sqlite_stat3; } } } {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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE 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] |
︙ | ︙ | |||
203 204 205 206 207 208 209 | } {} 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 | | | | 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | } {} 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 TABLE 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 TABLE 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] |
︙ | ︙ | |||
255 256 257 258 259 260 261 | } {} 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 | | | | 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 | } {} 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 TABLE 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 TABLE 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] |
︙ | ︙ | |||
310 311 312 313 314 315 316 | 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%' | | | | 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 | 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 TABLE t1 USING INDEX i1 (b>? AND b<?)} do_eqp_test analyze3-2.3 { SELECT count(a) FROM t1 WHERE b LIKE '%a' } {SCAN TABLE 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 |
︙ | ︙ | |||
700 701 702 703 704 705 706 | } execsql COMMIT execsql ANALYZE } {} do_eqp_test analyze3-6-3 { SELECT * FROM t1 WHERE a = 5 AND c = 13; | | | | 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 | } execsql COMMIT execsql ANALYZE } {} do_eqp_test analyze3-6-3 { SELECT * FROM t1 WHERE a = 5 AND c = 13; } {SEARCH TABLE t1 USING INDEX i2 (c=?)} do_eqp_test analyze3-6-2 { SELECT * FROM t1 WHERE a = 5 AND b > 'w' AND c = 13; } {SEARCH TABLE 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.
︙ | ︙ | |||
16 17 18 19 20 21 22 | # # Also include test cases for collating sequences on indices. # set testdir [file dirname $argv0] source $testdir/tester.tcl | < < < < < < | | 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 | # # 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} } {/*SEARCH TABLE 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&&!stat3 { 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 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | 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; } ifcapable stat4 { db eval { SELECT DISTINCT lindex(test_decode(sample),0) FROM sqlite_stat4 WHERE idx='t1u' ORDER BY nlt; } } else { db eval { SELECT sample FROM sqlite_stat3 WHERE idx='t1u' ORDER BY nlt; } } } {alpha bravo charlie delta} do_test analyze5-1.1 { ifcapable stat4 { db eval { SELECT DISTINCT lower(lindex(test_decode(sample), 0)) FROM sqlite_stat4 WHERE idx='t1v' ORDER BY 1 } } else { db eval { SELECT lower(sample) FROM sqlite_stat3 WHERE idx='t1v' ORDER BY 1 } } } {alpha bravo charlie delta} ifcapable stat4 { 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} } else { do_test analyze5-1.2 { db eval {SELECT idx, count(*) FROM sqlite_stat3 GROUP BY 1 ORDER BY 1} } {t1t 4 t1u 4 t1v 4 t1w 4 t1x 4 t1y 2 t1z 4} } # 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&&!stat3 { 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 TABLE cat USING COVERING INDEX catx*SEARCH TABLE 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 TABLE cat USING COVERING INDEX catx `--SEARCH TABLE 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 TABLE t201 USING INDEX t201z (z=?)*/} do_test analyze6-2.2 { eqp {SELECT * FROM t201 WHERE y=5} } {/*SEARCH TABLE t201 USING INDEX sqlite_autoindex_t201_1 (y=?)*/} do_test analyze6-2.3 { eqp {SELECT * FROM t201 WHERE x=5} } {/*SEARCH TABLE 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 TABLE t201 USING INDEX t201z (z=?)*/} do_test analyze6-2.5 { eqp {SELECT * FROM t201 WHERE y=5} } {/*SEARCH TABLE t201 USING INDEX sqlite_autoindex_t201_1 (y=?)*/} do_test analyze6-2.6 { eqp {SELECT * FROM t201 WHERE x=5} } {/*SEARCH TABLE 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 TABLE t201 USING INDEX t201z (z=?)*/} do_test analyze6-2.8 { eqp {SELECT * FROM t201 WHERE y=5} } {/*SEARCH TABLE t201 USING INDEX sqlite_autoindex_t201_1 (y=?)*/} do_test analyze6-2.9 { eqp {SELECT * FROM t201 WHERE x=5} } {/*SEARCH TABLE 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 TABLE t1 USING INDEX t1a (a=?)*/} do_test analyze7-1.1 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=123;} } {/*SEARCH TABLE t1 USING INDEX t1b (b=?)*/} do_test analyze7-1.2 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;} } {/*SEARCH TABLE 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 TABLE t1 USING INDEX t1a (a=?)*/} do_test analyze7-2.1 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=123;} } {/*SEARCH TABLE t1 USING INDEX t1b (b=?)*/} do_test analyze7-2.2 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;} } {/*SEARCH TABLE 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 TABLE 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 TABLE t1 USING INDEX t1a (a=?)*/} do_test analyze7-3.1 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=123;} } {/*SEARCH TABLE t1 USING INDEX t1b (b=?)*/} do_test analyze7-3.2.1 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=?;} } {/*SEARCH TABLE t1 USING INDEX t1cd (c=?)*/} ifcapable stat4||stat3 { # 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 TABLE 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 TABLE t1 USING INDEX t1cd (c=?)*/} } do_test analyze7-3.3 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND b=123} } {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} ifcapable {!stat4 && !stat3} { do_test analyze7-3.4 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=123 AND b=123} } {/*SEARCH TABLE t1 USING INDEX t1b (b=?)*/} do_test analyze7-3.5 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND c=123} } {/*SEARCH TABLE 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 TABLE 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_stat3. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !stat4&&!stat3 { 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 TABLE t1 USING INDEX t1b (b=?)*/} do_test 1.2 { eqp {SELECT * FROM t1 WHERE a=99 AND b=55} } {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} do_test 1.3 { eqp {SELECT * FROM t1 WHERE a=101 AND b=55} } {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} do_test 1.4 { eqp {SELECT * FROM t1 WHERE a=100 AND b=56} } {/*SEARCH TABLE t1 USING INDEX t1b (b=?)*/} do_test 1.5 { eqp {SELECT * FROM t1 WHERE a=99 AND b=56} } {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} do_test 1.6 { eqp {SELECT * FROM t1 WHERE a=101 AND b=56} } {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} do_test 2.1 { eqp {SELECT * FROM t1 WHERE a=100 AND b BETWEEN 50 AND 54} } {/*SEARCH TABLE 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 TABLE 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 TABLE 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 TABLE t1 USING INDEX t1a (a=?)*/} do_test 3.4 { eqp {SELECT * FROM t1 WHERE a=100 AND c BETWEEN 800000 AND 900000} } {/*SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)*/} finish_test |
Changes to test/analyze9.test.
︙ | ︙ | |||
395 396 397 398 399 400 401 | CREATE INDEX i2 ON t1(e); } do_test 9.2 { execsql BEGIN; for {set i 0} {$i < 100} {incr i} { execsql "INSERT INTO t1 VALUES('x', 'y', 'z', $i, [expr $i/2])" } | | | 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 | CREATE INDEX i2 ON t1(e); } do_test 9.2 { execsql BEGIN; for {set i 0} {$i < 100} {incr i} { execsql "INSERT INTO t1 VALUES('x', 'y', 'z', $i, [expr $i/2])" } for {set i 0} {$i < 20} {incr i} { execsql "INSERT INTO t1 VALUES('x', 'y', 'z', 101, $i)" } for {set i 102} {$i < 200} {incr i} { execsql "INSERT INTO t1 VALUES('x', 'y', 'z', $i, [expr $i/2])" } execsql COMMIT execsql ANALYZE |
︙ | ︙ | |||
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 TABLE t1 USING INDEX i1/} do_eqp_test 13.2.2 { SELECT * FROM t1 WHERE a='abc' AND rowid<'15' AND b<12 } {/SEARCH TABLE t1 USING INDEX i1/} do_eqp_test 13.3.1 { SELECT * FROM t1 WHERE a='abc' AND rowid<100 AND b<12 } {/SEARCH TABLE t1 USING INDEX i2/} do_eqp_test 13.3.2 { SELECT * FROM t1 WHERE a='abc' AND rowid<'100' AND b<12 } {/SEARCH TABLE 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 TABLE t1 USING INDEX i1/} do_eqp_test 13.2.2 { SELECT * FROM t1 WHERE a='ott' AND b<'10' AND c=1 } {/SEARCH TABLE 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 TABLE 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 TABLE 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 TABLE t6 USING INDEX bb (b<?)} do_eqp_test 25.2.2 { SELECT * FROM t6 WHERE a<20 AND b<? } \ {SEARCH TABLE 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 TABLE 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 TABLE t6 USING INDEX aa (a<?)} do_eqp_test 25.4.2 { SELECT * FROM t6 WHERE a < 20 AND (b BETWEEN ? AND 60) } {SEARCH TABLE 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 TABLE 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 TABLE t1 USING INDEX i1 (x=? AND y>?)} finish_test |
Added test/analyzeA.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 | # 2013 August 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 automated tests used to verify that the current build # (which must be either ENABLE_STAT3 or ENABLE_STAT4) works with both stat3 # and stat4 data. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix analyzeA ifcapable !stat4&&!stat3 { finish_test return } # Populate the stat3 table according to the current contents of the db # proc populate_stat3 {{bDropTable 1}} { # Open a second connection on database "test.db" and run ANALYZE. If this # is an ENABLE_STAT3 build, this is all that is required to create and # populate the sqlite_stat3 table. # sqlite3 db2 test.db execsql { ANALYZE } # Now, if this is an ENABLE_STAT4 build, create and populate the # sqlite_stat3 table based on the stat4 data gathered by the ANALYZE # above. Then drop the sqlite_stat4 table. # ifcapable stat4 { db2 func lindex lindex execsql { PRAGMA writable_schema = on; CREATE TABLE sqlite_stat3(tbl,idx,neq,nlt,ndlt,sample); INSERT INTO sqlite_stat3 SELECT DISTINCT tbl, idx, lindex(neq,0), lindex(nlt,0), lindex(ndlt,0), test_extract(sample, 0) FROM sqlite_stat4; } db2 if {$bDropTable} { execsql {DROP TABLE sqlite_stat4} db2 } execsql { PRAGMA writable_schema = off } } # Modify the database schema cookie to ensure that the other connection # reloads the schema. # execsql { CREATE TABLE obscure_tbl_nm(x); DROP TABLE obscure_tbl_nm; } db2 db2 close } # Populate the stat4 table according to the current contents of the db # proc populate_stat4 {{bDropTable 1}} { sqlite3 db2 test.db execsql { ANALYZE } ifcapable stat3 { execsql { PRAGMA writable_schema = on; CREATE TABLE sqlite_stat4(tbl,idx,neq,nlt,ndlt,sample); INSERT INTO sqlite_stat4 SELECT tbl, idx, neq, nlt, ndlt, sqlite_record(sample) FROM sqlite_stat3; } db2 if {$bDropTable} { execsql {DROP TABLE sqlite_stat3} db2 } execsql { PRAGMA writable_schema = off } } # Modify the database schema cookie to ensure that the other connection # reloads the schema. # execsql { CREATE TABLE obscure_tbl_nm(x); DROP TABLE obscure_tbl_nm; } db2 db2 close } # Populate the stat4 table according to the current contents of the db. # Leave deceptive data in the stat3 table. This data should be ignored # in favour of that from the stat4 table. # proc populate_both {} { ifcapable stat4 { populate_stat3 0 } ifcapable stat3 { populate_stat4 0 } sqlite3 db2 test.db execsql { PRAGMA writable_schema = on; UPDATE sqlite_stat3 SET idx = CASE idx WHEN 't1b' THEN 't1c' ELSE 't1b' END; PRAGMA writable_schema = off; CREATE TABLE obscure_tbl_nm(x); DROP TABLE obscure_tbl_nm; } db2 db2 close } foreach {tn analyze_cmd} { 1 populate_stat4 2 populate_stat3 3 populate_both } { reset_db do_test 1.$tn.1 { execsql { CREATE TABLE t1(a INTEGER PRIMARY KEY, b INT, c INT) } for {set i 0} {$i < 100} {incr i} { set c [expr int(pow(1.1,$i)/100)] set b [expr 125 - int(pow(1.1,99-$i))/100] execsql {INSERT INTO t1 VALUES($i, $b, $c)} } } {} execsql { CREATE INDEX t1b ON t1(b) } execsql { CREATE INDEX t1c ON t1(c) } $analyze_cmd do_execsql_test 1.$tn.2.1 { SELECT count(*) FROM t1 WHERE b=31 } 1 do_execsql_test 1.$tn.2.2 { SELECT count(*) FROM t1 WHERE c=0 } 49 do_execsql_test 1.$tn.2.3 { SELECT count(*) FROM t1 WHERE b=125 } 49 do_execsql_test 1.$tn.2.4 { SELECT count(*) FROM t1 WHERE c=16 } 1 do_eqp_test 1.$tn.2.5 { SELECT * FROM t1 WHERE b = 31 AND c = 0; } {SEARCH TABLE t1 USING INDEX t1b (b=?)} do_eqp_test 1.$tn.2.6 { SELECT * FROM t1 WHERE b = 125 AND c = 16; } {SEARCH TABLE t1 USING INDEX t1c (c=?)} do_execsql_test 1.$tn.3.1 { SELECT count(*) FROM t1 WHERE b BETWEEN 0 AND 50 } {6} do_execsql_test 1.$tn.3.2 { SELECT count(*) FROM t1 WHERE c BETWEEN 0 AND 50 } {90} do_execsql_test 1.$tn.3.3 { SELECT count(*) FROM t1 WHERE b BETWEEN 75 AND 125 } {90} do_execsql_test 1.$tn.3.4 { SELECT count(*) FROM t1 WHERE c BETWEEN 75 AND 125 } {6} do_eqp_test 1.$tn.3.5 { SELECT * FROM t1 WHERE b BETWEEN 0 AND 50 AND c BETWEEN 0 AND 50 } {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)} do_eqp_test 1.$tn.3.6 { SELECT * FROM t1 WHERE b BETWEEN 75 AND 125 AND c BETWEEN 75 AND 125 } {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)} do_eqp_test 1.$tn.3.7 { SELECT * FROM t1 WHERE b BETWEEN +0 AND +50 AND c BETWEEN +0 AND +50 } {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)} do_eqp_test 1.$tn.3.8 { SELECT * FROM t1 WHERE b BETWEEN cast('0' AS int) AND cast('50.0' AS real) AND c BETWEEN cast('0' AS numeric) AND cast('50.0' AS real) } {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)} do_eqp_test 1.$tn.3.9 { SELECT * FROM t1 WHERE b BETWEEN +75 AND +125 AND c BETWEEN +75 AND +125 } {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)} do_eqp_test 1.$tn.3.10 { SELECT * FROM t1 WHERE b BETWEEN cast('75' AS int) AND cast('125.0' AS real) AND c BETWEEN cast('75' AS numeric) AND cast('125.0' AS real) } {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)} } finish_test |
Added test/analyzeB.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 | # 2013 August 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 automated tests used to verify that the sqlite_stat3 # functionality is working. The tests in this file are based on a subset # of the sqlite_stat4 tests in analyze9.test. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix analyzeB ifcapable !stat3 { finish_test return } do_execsql_test 1.0 { CREATE TABLE t1(a TEXT, b TEXT); INSERT INTO t1 VALUES('(0)', '(0)'); INSERT INTO t1 VALUES('(1)', '(1)'); INSERT INTO t1 VALUES('(2)', '(2)'); INSERT INTO t1 VALUES('(3)', '(3)'); INSERT INTO t1 VALUES('(4)', '(4)'); CREATE INDEX i1 ON t1(a, b); } {} do_execsql_test 1.1 { ANALYZE; } {} do_execsql_test 1.2 { SELECT tbl,idx,nEq,nLt,nDLt,quote(sample) FROM sqlite_stat3; } { t1 i1 1 0 0 '(0)' t1 i1 1 1 1 '(1)' t1 i1 1 2 2 '(2)' t1 i1 1 3 3 '(3)' t1 i1 1 4 4 '(4)' } if {[permutation] != "utf16"} { do_execsql_test 1.3 { SELECT tbl,idx,nEq,nLt,nDLt,quote(sample) FROM sqlite_stat3; } { t1 i1 1 0 0 '(0)' t1 i1 1 1 1 '(1)' t1 i1 1 2 2 '(2)' t1 i1 1 3 3 '(3)' t1 i1 1 4 4 '(4)' } } #------------------------------------------------------------------------- # This is really just to test SQL user function "test_decode". # reset_db do_execsql_test 2.1 { CREATE TABLE t1(a, b, c); INSERT INTO t1(a) VALUES('some text'); INSERT INTO t1(a) VALUES(14); INSERT INTO t1(a) VALUES(NULL); INSERT INTO t1(a) VALUES(22.0); INSERT INTO t1(a) VALUES(x'656667'); CREATE INDEX i1 ON t1(a, b, c); ANALYZE; SELECT quote(sample) FROM sqlite_stat3; } { NULL 14 22.0 {'some text'} X'656667' } #------------------------------------------------------------------------- # reset_db do_execsql_test 3.1 { CREATE TABLE t2(a, b); CREATE INDEX i2 ON t2(a, b); BEGIN; } do_test 3.2 { for {set i 0} {$i < 1000} {incr i} { set a [expr $i / 10] set b [expr int(rand() * 15.0)] execsql { INSERT INTO t2 VALUES($a, $b) } } execsql COMMIT } {} db func lindex lindex # Each value of "a" occurs exactly 10 times in the table. # do_execsql_test 3.3.1 { SELECT count(*) FROM t2 GROUP BY a; } [lrange [string repeat "10 " 100] 0 99] # The first element in the "nEq" list of all samples should therefore be 10. # do_execsql_test 3.3.2 { ANALYZE; SELECT nEq FROM sqlite_stat3; } [lrange [string repeat "10 " 100] 0 23] #------------------------------------------------------------------------- # do_execsql_test 3.4 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); INSERT INTO t1 VALUES(1, 1, 'one-a'); INSERT INTO t1 VALUES(11, 1, 'one-b'); INSERT INTO t1 VALUES(21, 1, 'one-c'); INSERT INTO t1 VALUES(31, 1, 'one-d'); INSERT INTO t1 VALUES(41, 1, 'one-e'); INSERT INTO t1 VALUES(51, 1, 'one-f'); INSERT INTO t1 VALUES(61, 1, 'one-g'); INSERT INTO t1 VALUES(71, 1, 'one-h'); INSERT INTO t1 VALUES(81, 1, 'one-i'); INSERT INTO t1 VALUES(91, 1, 'one-j'); INSERT INTO t1 SELECT a+1,2,'two' || substr(c,4) FROM t1; INSERT INTO t1 SELECT a+2,3,'three'||substr(c,4) FROM t1 WHERE c GLOB 'one-*'; INSERT INTO t1 SELECT a+3,4,'four'||substr(c,4) FROM t1 WHERE c GLOB 'one-*'; INSERT INTO t1 SELECT a+4,5,'five'||substr(c,4) FROM t1 WHERE c GLOB 'one-*'; INSERT INTO t1 SELECT a+5,6,'six'||substr(c,4) FROM t1 WHERE c GLOB 'one-*'; CREATE INDEX t1b ON t1(b); ANALYZE; SELECT c FROM t1 WHERE b=3 AND a BETWEEN 30 AND 60; } {three-d three-e three-f} #------------------------------------------------------------------------- # These tests verify that the sample selection for stat3 appears to be # working as designed. # reset_db db func lindex lindex db func lrange lrange do_execsql_test 4.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a, b, c); CREATE INDEX i1 ON t1(c, b, a); } proc insert_filler_rows_n {iStart args} { set A(-ncopy) 1 set A(-nval) 1 foreach {k v} $args { if {[info exists A($k)]==0} { error "no such option: $k" } set A($k) $v } if {[llength $args] % 2} { error "option requires an argument: [lindex $args end]" } for {set i 0} {$i < $A(-nval)} {incr i} { set iVal [expr $iStart+$i] for {set j 0} {$j < $A(-ncopy)} {incr j} { execsql { INSERT INTO t1 VALUES($iVal, $iVal, $iVal) } } } } do_test 4.1 { execsql { BEGIN } insert_filler_rows_n 0 -ncopy 10 -nval 19 insert_filler_rows_n 20 -ncopy 1 -nval 100 execsql { INSERT INTO t1(c, b, a) VALUES(200, 1, 'a'); INSERT INTO t1(c, b, a) VALUES(200, 1, 'b'); INSERT INTO t1(c, b, a) VALUES(200, 1, 'c'); INSERT INTO t1(c, b, a) VALUES(200, 2, 'e'); INSERT INTO t1(c, b, a) VALUES(200, 2, 'f'); INSERT INTO t1(c, b, a) VALUES(201, 3, 'g'); INSERT INTO t1(c, b, a) VALUES(201, 4, 'h'); ANALYZE; SELECT count(*) FROM sqlite_stat3; SELECT count(*) FROM t1; } } {24 297} do_execsql_test 4.2 { SELECT neq, nlt, ndlt, sample FROM sqlite_stat3 ORDER BY rowid LIMIT 16; } { 10 0 0 0 10 10 1 1 10 20 2 2 10 30 3 3 10 40 4 4 10 50 5 5 10 60 6 6 10 70 7 7 10 80 8 8 10 90 9 9 10 100 10 10 10 110 11 11 10 120 12 12 10 130 13 13 10 140 14 14 10 150 15 15 } do_execsql_test 4.3 { SELECT neq, nlt, ndlt, sample FROM sqlite_stat3 ORDER BY rowid DESC LIMIT 2; } { 2 295 120 201 5 290 119 200 } do_execsql_test 4.4 { SELECT count(DISTINCT c) FROM t1 WHERE c<201 } 120 do_execsql_test 4.5 { SELECT count(DISTINCT c) FROM t1 WHERE c<200 } 119 reset_db do_test 4.7 { execsql { BEGIN; CREATE TABLE t1(o,t INTEGER PRIMARY KEY); CREATE INDEX i1 ON t1(o); } for {set i 0} {$i<10000} {incr i [expr (($i<1000)?1:10)]} { execsql { INSERT INTO t1 VALUES('x', $i) } } execsql { COMMIT; ANALYZE; SELECT count(*) FROM sqlite_stat3; } } {1} do_execsql_test 4.8 { SELECT sample FROM sqlite_stat3; } {x} #------------------------------------------------------------------------- # The following would cause a crash at one point. # reset_db do_execsql_test 5.1 { PRAGMA encoding = 'utf-16'; CREATE TABLE t0(v); ANALYZE; } #------------------------------------------------------------------------- # This was also crashing (corrupt sqlite_stat3 table). # reset_db do_execsql_test 6.1 { CREATE TABLE t1(a, b); CREATE INDEX i1 ON t1(a); CREATE INDEX i2 ON t1(b); 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); ANALYZE; PRAGMA writable_schema = 1; CREATE TEMP TABLE x1 AS SELECT tbl,idx,neq,nlt,ndlt,sample FROM sqlite_stat3 ORDER BY (rowid%5), rowid; DELETE FROM sqlite_stat3; INSERT INTO sqlite_stat3 SELECT * FROM x1; PRAGMA writable_schema = 0; ANALYZE sqlite_master; } do_execsql_test 6.2 { SELECT * FROM t1 WHERE a = 'abc'; } #------------------------------------------------------------------------- # The following tests experiment with adding corrupted records to the # 'sample' column of the sqlite_stat3 table. # reset_db sqlite3_db_config_lookaside db 0 0 0 do_execsql_test 7.1 { CREATE TABLE t1(a, b); CREATE INDEX i1 ON t1(a, b); 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); ANALYZE; UPDATE sqlite_stat3 SET sample = X'' WHERE rowid = 1; ANALYZE sqlite_master; } do_execsql_test 7.2 { UPDATE sqlite_stat3 SET sample = X'FFFF'; ANALYZE sqlite_master; SELECT * FROM t1 WHERE a = 1; } {1 1} do_execsql_test 7.3 { ANALYZE; UPDATE sqlite_stat3 SET neq = '0 0 0'; ANALYZE sqlite_master; SELECT * FROM t1 WHERE a = 1; } {1 1} do_execsql_test 7.4 { ANALYZE; UPDATE sqlite_stat3 SET ndlt = '0 0 0'; ANALYZE sqlite_master; SELECT * FROM t1 WHERE a = 3; } {3 3} do_execsql_test 7.5 { ANALYZE; UPDATE sqlite_stat3 SET nlt = '0 0 0'; ANALYZE sqlite_master; SELECT * FROM t1 WHERE a = 5; } {5 5} #------------------------------------------------------------------------- # reset_db do_execsql_test 8.1 { CREATE TABLE t1(x TEXT); CREATE INDEX i1 ON t1(x); INSERT INTO t1 VALUES('1'); INSERT INTO t1 VALUES('2'); INSERT INTO t1 VALUES('3'); INSERT INTO t1 VALUES('4'); ANALYZE; } do_execsql_test 8.2 { SELECT * FROM t1 WHERE x = 3; } {3} #------------------------------------------------------------------------- # reset_db do_execsql_test 9.1 { CREATE TABLE t1(a, b, c, d, e); CREATE INDEX i1 ON t1(a, b, c, d); CREATE INDEX i2 ON t1(e); } do_test 9.2 { execsql BEGIN; for {set i 0} {$i < 100} {incr i} { execsql "INSERT INTO t1 VALUES('x', 'y', 'z', $i, [expr $i/2])" } for {set i 0} {$i < 20} {incr i} { execsql "INSERT INTO t1 VALUES('x', 'y', 'z', 101, $i)" } for {set i 102} {$i < 200} {incr i} { execsql "INSERT INTO t1 VALUES('x', 'y', 'z', $i, [expr $i/2])" } execsql COMMIT execsql ANALYZE } {} do_eqp_test 9.3.1 { SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=101 AND e=5; } {/t1 USING INDEX i1/} do_eqp_test 9.3.2 { SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=99 AND e=5; } {/t1 USING INDEX i1/} set value_d [expr 101] do_eqp_test 9.4.1 { SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=$value_d AND e=5 } {/t1 USING INDEX i1/} set value_d [expr 99] do_eqp_test 9.4.2 { SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=$value_d AND e=5 } {/t1 USING INDEX i1/} #------------------------------------------------------------------------- # Check that the planner takes stat3 data into account when considering # "IS NULL" and "IS NOT NULL" constraints. # do_execsql_test 10.1.1 { DROP TABLE IF EXISTS t3; CREATE TABLE t3(a, b); CREATE INDEX t3a ON t3(a); CREATE INDEX t3b ON t3(b); } do_test 10.1.2 { for {set i 1} {$i < 100} {incr i} { if {$i>90} { set a $i } else { set a NULL } set b [expr $i % 5] execsql "INSERT INTO t3 VALUES($a, $b)" } execsql ANALYZE } {} do_eqp_test 10.1.3 { SELECT * FROM t3 WHERE a IS NULL AND b = 2 } {/t3 USING INDEX t3b/} do_eqp_test 10.1.4 { SELECT * FROM t3 WHERE a IS NOT NULL AND b = 2 } {/t3 USING INDEX t3a/} #------------------------------------------------------------------------- # Check that stat3 data is used correctly with non-default collation # sequences. # foreach {tn schema} { 1 { CREATE TABLE t4(a COLLATE nocase, b); CREATE INDEX t4a ON t4(a); CREATE INDEX t4b ON t4(b); } 2 { CREATE TABLE t4(a, b); CREATE INDEX t4a ON t4(a COLLATE nocase); CREATE INDEX t4b ON t4(b); } } { drop_all_tables do_test 11.$tn.1 { execsql $schema } {} do_test 11.$tn.2 { for {set i 0} {$i < 100} {incr i} { if { ($i % 10)==0 } { set a ABC } else { set a DEF } set b [expr $i % 5] execsql { INSERT INTO t4 VALUES($a, $b) } } execsql ANALYZE } {} do_eqp_test 11.$tn.3 { SELECT * FROM t4 WHERE a = 'def' AND b = 3; } {/t4 USING INDEX t4b/} if {$tn==1} { set sql "SELECT * FROM t4 WHERE a = 'abc' AND b = 3;" do_eqp_test 11.$tn.4 $sql {/t4 USING INDEX t4a/} } else { set sql "SELECT * FROM t4 WHERE a = 'abc' COLLATE nocase AND b = 3;" do_eqp_test 11.$tn.5 $sql {/t4 USING INDEX t4a/} set sql "SELECT * FROM t4 WHERE a COLLATE nocase = 'abc' AND b = 3;" do_eqp_test 11.$tn.6 $sql {/t4 USING INDEX t4a/} } } #------------------------------------------------------------------------- # Test that nothing untoward happens if the stat3 table contains entries # for indexes that do not exist. Or NULL values in the idx column. # Or NULL values in any of the other columns. # drop_all_tables do_execsql_test 15.1 { CREATE TABLE x1(a, b, UNIQUE(a, b)); INSERT INTO x1 VALUES(1, 2); INSERT INTO x1 VALUES(3, 4); INSERT INTO x1 VALUES(5, 6); ANALYZE; INSERT INTO sqlite_stat3 VALUES(NULL, NULL, NULL, NULL, NULL, NULL); } db close sqlite3 db test.db do_execsql_test 15.2 { SELECT * FROM x1 } {1 2 3 4 5 6} do_execsql_test 15.3 { INSERT INTO sqlite_stat3 VALUES(42, 42, 42, 42, 42, 42); } db close sqlite3 db test.db do_execsql_test 15.4 { SELECT * FROM x1 } {1 2 3 4 5 6} do_execsql_test 15.5 { UPDATE sqlite_stat1 SET stat = NULL; } db close sqlite3 db test.db do_execsql_test 15.6 { SELECT * FROM x1 } {1 2 3 4 5 6} do_execsql_test 15.7 { ANALYZE; UPDATE sqlite_stat1 SET tbl = 'no such tbl'; } db close sqlite3 db test.db do_execsql_test 15.8 { SELECT * FROM x1 } {1 2 3 4 5 6} do_execsql_test 15.9 { ANALYZE; UPDATE sqlite_stat3 SET neq = NULL, nlt=NULL, ndlt=NULL; } db close sqlite3 db test.db do_execsql_test 15.10 { SELECT * FROM x1 } {1 2 3 4 5 6} # This is just for coverage.... do_execsql_test 15.11 { ANALYZE; UPDATE sqlite_stat1 SET stat = stat || ' unordered'; } db close sqlite3 db test.db do_execsql_test 15.12 { SELECT * FROM x1 } {1 2 3 4 5 6} #------------------------------------------------------------------------- # Test that allocations used for sqlite_stat3 samples are included in # the quantity returned by SQLITE_DBSTATUS_SCHEMA_USED. # set one [string repeat x 1000] set two [string repeat x 2000] do_test 16.1 { reset_db execsql { CREATE TABLE t1(a, UNIQUE(a)); INSERT INTO t1 VALUES($one); ANALYZE; } set nByte [lindex [sqlite3_db_status db SCHEMA_USED 0] 1] reset_db execsql { CREATE TABLE t1(a, UNIQUE(a)); INSERT INTO t1 VALUES($two); ANALYZE; } set nByte2 [lindex [sqlite3_db_status db SCHEMA_USED 0] 1] expr {$nByte2 > $nByte+950 && $nByte2 < $nByte+1050} } {1} #------------------------------------------------------------------------- # Test that stat3 data may be used with partial indexes. # do_test 17.1 { reset_db execsql { CREATE TABLE t1(a, b, c, d); CREATE INDEX i1 ON t1(a, b) WHERE d IS NOT NULL; INSERT INTO t1 VALUES(-1, -1, -1, NULL); INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1; INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1; INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1; INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1; INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1; INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1; } for {set i 0} {$i < 32} {incr i} { execsql { INSERT INTO t1 VALUES($i%2, $b, $i/2, 'abc') } } execsql {ANALYZE main.t1} } {} do_catchsql_test 17.1.2 { ANALYZE temp.t1; } {1 {no such table: temp.t1}} do_eqp_test 17.2 { SELECT * FROM t1 WHERE d IS NOT NULL AND a=0; } {/USING INDEX i1/} do_eqp_test 17.3 { SELECT * FROM t1 WHERE d IS NOT NULL AND a=0; } {/USING INDEX i1/} do_execsql_test 17.4 { CREATE INDEX i2 ON t1(c) WHERE d IS NOT NULL; ANALYZE main.i2; } do_eqp_test 17.5 { SELECT * FROM t1 WHERE d IS NOT NULL AND a=0; } {/USING INDEX i1/} do_eqp_test 17.6 { SELECT * FROM t1 WHERE d IS NOT NULL AND a=0 AND b=0 AND c=10; } {/USING INDEX i2/} #------------------------------------------------------------------------- # do_test 18.1 { reset_db execsql { CREATE TABLE t1(a, b); CREATE INDEX i1 ON t1(a, b); } for {set i 0} {$i < 9} {incr i} { execsql { INSERT INTO t1 VALUES($i, 0); INSERT INTO t1 VALUES($i, 0); INSERT INTO t1 VALUES($i, 0); INSERT INTO t1 VALUES($i, 0); INSERT INTO t1 VALUES($i, 0); INSERT INTO t1 VALUES($i, 0); INSERT INTO t1 VALUES($i, 0); INSERT INTO t1 VALUES($i, 0); INSERT INTO t1 VALUES($i, 0); INSERT INTO t1 VALUES($i, 0); INSERT INTO t1 VALUES($i, 0); INSERT INTO t1 VALUES($i, 0); INSERT INTO t1 VALUES($i, 0); INSERT INTO t1 VALUES($i, 0); INSERT INTO t1 VALUES($i, 0); } } execsql ANALYZE execsql { SELECT count(*) FROM sqlite_stat3 } } {9} #------------------------------------------------------------------------- # For coverage. # ifcapable view { do_test 19.1 { reset_db execsql { CREATE TABLE t1(x, y); CREATE INDEX i1 ON t1(x, y); CREATE VIEW v1 AS SELECT * FROM t1; ANALYZE; } } {} } ifcapable auth { proc authproc {op args} { if {$op == "SQLITE_ANALYZE"} { return "SQLITE_DENY" } return "SQLITE_OK" } do_test 19.2 { reset_db db auth authproc execsql { CREATE TABLE t1(x, y); CREATE VIEW v1 AS SELECT * FROM t1; } catchsql ANALYZE } {1 {not authorized}} } #------------------------------------------------------------------------- # reset_db proc r {args} { expr rand() } db func r r db func lrange lrange do_test 20.1 { execsql { CREATE TABLE t1(a,b,c,d); CREATE INDEX i1 ON t1(a,b,c,d); } for {set i 0} {$i < 16} {incr i} { execsql { INSERT INTO t1 VALUES($i, r(), r(), r()); INSERT INTO t1 VALUES($i, $i, r(), r()); INSERT INTO t1 VALUES($i, $i, $i, r()); INSERT INTO t1 VALUES($i, $i, $i, $i); INSERT INTO t1 VALUES($i, $i, $i, $i); INSERT INTO t1 VALUES($i, $i, $i, r()); INSERT INTO t1 VALUES($i, $i, r(), r()); INSERT INTO t1 VALUES($i, r(), r(), r()); } } } {} do_execsql_test 20.2 { ANALYZE } for {set i 0} {$i<16} {incr i} { set val $i do_execsql_test 20.3.$i { SELECT count(*) FROM sqlite_stat3 WHERE sample=$val } {1} } finish_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 TABLE 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 | ANALYZE sqlite_master; SELECT count(a) FROM t1; } {6} do_execsql_test 4.3 { EXPLAIN QUERY PLAN SELECT count(a) FROM t1; } {/.*INDEX t1ca.*/} | < < < < < < < < < < < < < < | 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; |
︙ | ︙ |
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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE t1/} do_execsql_test analyzeE-1.2 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 2900 AND 3000; } {/SEARCH TABLE t1 USING INDEX t1a/} do_execsql_test analyzeE-1.3 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 1700 AND 1750; } {/SEARCH TABLE t1 USING INDEX t1a/} do_execsql_test analyzeE-1.4 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 1 AND 500 } {/SEARCH TABLE t1 USING INDEX t1a/} do_execsql_test analyzeE-1.5 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 3000 AND 3000000 } {/SEARCH TABLE t1 USING INDEX t1a/} do_execsql_test analyzeE-1.6 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<500 } {/SEARCH TABLE t1 USING INDEX t1a/} do_execsql_test analyzeE-1.7 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>2500 } {/SEARCH TABLE t1 USING INDEX t1a/} do_execsql_test analyzeE-1.8 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>1900 } {/SEARCH TABLE t1 USING INDEX t1a/} do_execsql_test analyzeE-1.9 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>1100 } {/SCAN TABLE t1/} do_execsql_test analyzeE-1.10 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<1100 } {/SEARCH TABLE t1 USING INDEX t1a/} do_execsql_test analyzeE-1.11 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<1900 } {/SCAN TABLE 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 TABLE t1/} do_execsql_test analyzeE-2.2 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 2900 AND 3000; } {/SEARCH TABLE t1 USING INDEX t1a/} do_execsql_test analyzeE-2.3 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 1700 AND 1750; } {/SEARCH TABLE t1 USING INDEX t1a/} do_execsql_test analyzeE-2.4 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 1 AND 500 } {/SEARCH TABLE t1 USING INDEX t1a/} do_execsql_test analyzeE-2.5 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 3000 AND 3000000 } {/SEARCH TABLE t1 USING INDEX t1a/} do_execsql_test analyzeE-2.6 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<500 } {/SEARCH TABLE t1 USING INDEX t1a/} do_execsql_test analyzeE-2.7 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>2500 } {/SEARCH TABLE t1 USING INDEX t1a/} do_execsql_test analyzeE-2.8 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>1900 } {/SEARCH TABLE t1 USING INDEX t1a/} do_execsql_test analyzeE-2.9 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>1100 } {/SCAN TABLE t1/} do_execsql_test analyzeE-2.10 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<1100 } {/SEARCH TABLE t1 USING INDEX t1a/} do_execsql_test analyzeE-2.11 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<1900 } {/SCAN TABLE 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 TABLE t1/} do_execsql_test analyzeE-3.2 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 2900 AND 3000 AND c=123; } {/SEARCH TABLE 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 TABLE 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 TABLE 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 TABLE t1 USING INDEX t1ca/} do_execsql_test analyzeE-3.6 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<500 AND c=123 } {/SEARCH TABLE t1 USING INDEX t1ca/} do_execsql_test analyzeE-3.7 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>2500 AND c=123 } {/SEARCH TABLE t1 USING INDEX t1ca/} do_execsql_test analyzeE-3.8 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>1900 AND c=123 } {/SEARCH TABLE t1 USING INDEX t1ca/} do_execsql_test analyzeE-3.9 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>1100 AND c=123 } {/SCAN TABLE t1/} do_execsql_test analyzeE-3.10 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<1100 AND c=123 } {/SEARCH TABLE t1 USING INDEX t1ca/} do_execsql_test analyzeE-3.11 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<1900 AND c=123 } {/SCAN TABLE 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 TABLE t1/} do_execsql_test analyzeE-4.2 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a BETWEEN 2900 AND 3000 AND c=123; } {/SEARCH TABLE 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 TABLE 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 TABLE 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 TABLE t1 USING INDEX t1ca/} do_execsql_test analyzeE-4.6 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<500 AND c=123 } {/SEARCH TABLE t1 USING INDEX t1ca/} do_execsql_test analyzeE-4.7 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>2500 AND c=123 } {/SEARCH TABLE t1 USING INDEX t1ca/} do_execsql_test analyzeE-4.8 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>1900 AND c=123 } {/SEARCH TABLE t1 USING INDEX t1ca/} do_execsql_test analyzeE-4.9 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a>1100 AND c=123 } {/SCAN TABLE t1/} do_execsql_test analyzeE-4.10 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<1100 AND c=123 } {/SEARCH TABLE t1 USING INDEX t1ca/} do_execsql_test analyzeE-4.11 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a<1900 AND c=123 } {/SCAN TABLE 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 TABLE 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 TABLE 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 } |
︙ | ︙ |
Deleted test/analyzeG.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/atof1.test.
︙ | ︙ | |||
15 16 17 18 19 20 21 | set testdir [file dirname $argv0] source $testdir/tester.tcl if {$::longdouble_size<=8} { finish_test return } | < < < < | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | set testdir [file dirname $argv0] source $testdir/tester.tcl if {$::longdouble_size<=8} { finish_test return } expr srand(1) for {set i 1} {$i<20000} {incr i} { set pow [expr {int((rand()-0.5)*100)}] set x [expr {pow((rand()-0.5)*2*rand(),$pow)}] set xf [format %.32e $x] |
︙ | ︙ | |||
56 57 58 59 60 61 62 | db eval {SELECT CAST(quote($x) AS real) c} {} puts "OUT: $b [format %.32e $c]" } set y } {1} } | < < < < | < < < < < < < < < < < < < < < < < < < < | 52 53 54 55 56 57 58 59 60 | db eval {SELECT CAST(quote($x) AS real) c} {} puts "OUT: $b [format %.32e $c]" } set y } {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_master 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 170 171 172 173 | } } {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_test attach-1.15 { catchsql { 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_test attach-1.17 { catchsql { 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 {}} |
︙ | ︙ | |||
222 223 224 225 226 227 228 | } } {1 {no such database: db12}} do_test attach-1.26 { catchsql { DETACH main; } } {1 {cannot detach database main}} | < | 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}} |
︙ | ︙ | |||
906 907 908 909 910 911 912 | 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} | < < < < < < < < < < < < < < < | 909 910 911 912 913 914 915 916 | 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 |
Changes to test/attach2.test.
︙ | ︙ | |||
13 14 15 16 17 18 19 | # and related functionality. # # $Id: attach2.test,v 1.38 2007/12/13 21:54:11 drh Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl | < | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # and related functionality. # # $Id: attach2.test,v 1.38 2007/12/13 21:54:11 drh Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !attach { finish_test return } # Ticket #354 |
︙ | ︙ | |||
385 386 387 388 389 390 391 | catchsql { DETACH aux; } } {0 {}} db close | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 384 385 386 387 388 389 390 391 | catchsql { DETACH aux; } } {0 {}} db close finish_test |
Changes to test/attach4.test.
︙ | ︙ | |||
111 112 113 114 115 116 117 | } set L } $files db close foreach {name f} $files { forcedelete $f } | < < < < < < < < < < < < < < < < < < < | 111 112 113 114 115 116 117 118 | } set L } $files db close foreach {name f} $files { forcedelete $f } finish_test |
Changes to test/attachmalloc.test.
︙ | ︙ | |||
57 58 59 60 61 62 63 | } db2 close } -sqlbody { CREATE TABLE t1(d, e, f); ATTACH 'test2.db' AS db1; } | < | | | | | | | | | | | | | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | } db2 close } -sqlbody { CREATE TABLE t1(d, e, f); ATTACH 'test2.db' AS db1; } set enable_shared_cache [sqlite3_enable_shared_cache 1] sqlite3 dbaux test3.db dbaux eval {SELECT * FROM sqlite_master} do_malloc_test attachmalloc-3 -sqlbody { SELECT * FROM sqlite_master; ATTACH 'test3.db' AS three; } -cleanup { db eval { DETACH three } } dbaux close sqlite3_enable_shared_cache $enable_shared_cache 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 | set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY } return SQLITE_OK } catchsql {DROP INDEX i2} } {1 {not authorized}} do_test auth-1.206 { set ::authargs } {i2 t2 main {}} 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 |
︙ | ︙ | |||
2065 2066 2067 2068 2069 2070 2071 | do_test auth-1.301 { set x [execsql {SELECT sql FROM sqlite_master WHERE name='t5'}] regexp new_col_1 $x } {1} do_test auth-1.302 { set authargs } {main t5 {} {}} | < < < < < < < < < < < < < < < < < < < > < < < < < < < < < < < < < | 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 | do_test auth-1.301 { set x [execsql {SELECT sql FROM sqlite_master WHERE name='t5'}] regexp new_col_1 $x } {1} do_test auth-1.302 { set authargs } {main t5 {} {}} do_test auth-1.303 { proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_ALTER_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_IGNORE } return SQLITE_OK } catchsql { ALTER TABLE t5 ADD COLUMN new_col_2; } } {0 {}} do_test auth-1.304 { set x [execsql {SELECT sql FROM sqlite_master WHERE name='t5'}] regexp new_col_2 $x } {0} do_test auth-1.305 { set authargs } {main t5 {} {}} do_test auth-1.306 { proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_ALTER_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY } return SQLITE_OK } catchsql { ALTER TABLE t5 ADD COLUMN new_col_3 } } {1 {not authorized}} do_test auth-1.307 { set x [execsql {SELECT sql FROM temp.sqlite_master WHERE type='t5'}] regexp new_col_3 $x } {0} do_test auth-1.308 { set authargs } {main t5 {} {}} execsql {DROP TABLE t5} } ;# ifcapable altertable ifcapable {cte} { do_test auth-1.310 { proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_RECURSIVE"} { |
︙ | ︙ | |||
2186 2187 2188 2189 2190 2191 2192 | # MAIN: CREATE TABLE t4(a,b,c); # MAIN: CREATE INDEX t4i1 ON t4(a); # MAIN: CREATE INDEX t4i2 ON t4(b,a,c); # MAIN: CREATE TABLE sqlite_stat1(tbl,idx,stat); # MAIN: CREATE TABLE t1(a,b); # ifcapable altertable&&vtab { | | | | | | < < < < < < < < < < < < < < < | 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 | # MAIN: CREATE TABLE t4(a,b,c); # MAIN: CREATE INDEX t4i1 ON t4(a); # MAIN: CREATE INDEX t4i2 ON t4(b,a,c); # MAIN: CREATE TABLE sqlite_stat1(tbl,idx,stat); # MAIN: CREATE TABLE t1(a,b); # ifcapable altertable&&vtab { do_test 1.350 { proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_ALTER_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_OK } return SQLITE_OK } catchsql { ALTER TABLE t1 RENAME COLUMN b TO bcdefg; } } {0 {}} do_execsql_test auth-1.351 { SELECT name FROM pragma_table_info('t1') ORDER BY cid; } {a bcdefg} do_test auth-1.352 { set authargs } {main t1 {} {}} do_test 1.353 { proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_ALTER_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_IGNORE } return SQLITE_OK } catchsql { ALTER TABLE t1 RENAME COLUMN bcdefg TO b; } } {0 {}} do_execsql_test auth-1.354 { SELECT name FROM pragma_table_info('t1') ORDER BY cid; } {a bcdefg} do_test auth-1.355 { set authargs } {main t1 {} {}} do_test 1.356 { proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_ALTER_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] return SQLITE_DENY } return SQLITE_OK } catchsql { ALTER TABLE t1 RENAME COLUMN bcdefg TO b; } } {1 {not authorized}} do_execsql_test auth-1.356 { SELECT name FROM pragma_table_info('t1') ORDER BY cid; } {a bcdefg} do_test auth-1.357 { set authargs } {main t1 {} {}} } do_test auth-2.1 { proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_READ" && $arg1=="t3" && $arg2=="x"} { return SQLITE_DENY } return SQLITE_OK |
︙ | ︙ | |||
2506 2507 2508 2509 2510 2511 2512 | DROP TABLE v1chng; } } } ifcapable stat4 { set stat4 "sqlite_stat4 " } else { | > > > | > | 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 | DROP TABLE v1chng; } } } ifcapable stat4 { set stat4 "sqlite_stat4 " } else { ifcapable stat3 { set stat4 "sqlite_stat3 " } 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 | 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. # 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/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 TABLE t501 USING INTEGER PRIMARY KEY (rowid=?) `--LIST SUBQUERY xxxxxx `--SCAN TABLE 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 TABLE t501 `--CORRELATED LIST SUBQUERY xxxxxx `--SEARCH TABLE 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 TABLE t501 USING INTEGER PRIMARY KEY (rowid=?) `--CORRELATED LIST SUBQUERY xxxxxx `--SCAN TABLE 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 xxxxxx | |--SCAN TABLE sheep AS s | |--SEARCH TABLE flock_owner AS prev USING INDEX sqlite_autoindex_flock_owner_1 (flock_no=? AND owner_change_date<?) | `--CORRELATED SCALAR SUBQUERY xxxxxx | `--SEARCH TABLE flock_owner AS later USING COVERING INDEX sqlite_autoindex_flock_owner_1 (flock_no=? AND owner_change_date>? AND owner_change_date<?) |--SCAN TABLE sheep AS x USING INDEX sheep_reg_flock_index `--SEARCH SUBQUERY xxxxxx AS 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 TABLE 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 TABLE data .*SEARCH TABLE 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 TABLE data .*SEARCH TABLE 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. |
︙ | ︙ | |||
538 539 540 541 542 543 544 | INSERT INTO t11 VALUES(NULL); INSERT INTO t12 VALUES('notnull'); } do_execsql_test autoindex1-1020 { SELECT count(*) FROM t11 LEFT JOIN t12 WHERE t12.y IS t11.w; } 0 | | < | < < < < < < < < < < < < < < < | 538 539 540 541 542 543 544 545 546 547 548 | INSERT INTO t11 VALUES(NULL); INSERT INTO t12 VALUES('notnull'); } do_execsql_test autoindex1-1020 { SELECT count(*) FROM t11 LEFT JOIN t12 WHERE t12.y IS t11.w; } 0 finish_test |
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 TABLE v USING INDEX ve (e>?) # 0|1|0|SEARCH TABLE 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 TABLE v USING INDEX ve (e>?) `--SEARCH TABLE u USING AUTOMATIC COVERING INDEX (b=?) } finish_test |
Changes to test/autoindex4.test.
︙ | ︙ | |||
28 29 30 31 32 33 34 | do_execsql_test autoindex4-1.1 { SELECT *, '|' FROM t1, t2 WHERE a=234 AND x=555; } {} do_execsql_test autoindex4-1.2 { SELECT *, '|' FROM t1 LEFT JOIN t2 ON a=234 AND x=555; } {123 abc {} {} | 234 def {} {} | 234 ghi {} {} | 345 jkl {} {} |} | < < < < < < < < < | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | do_execsql_test autoindex4-1.1 { SELECT *, '|' FROM t1, t2 WHERE a=234 AND x=555; } {} do_execsql_test autoindex4-1.2 { SELECT *, '|' FROM t1 LEFT JOIN t2 ON a=234 AND x=555; } {123 abc {} {} | 234 def {} {} | 234 ghi {} {} | 345 jkl {} {} |} do_execsql_test autoindex4-1.3 { SELECT *, '|' FROM t1 LEFT JOIN t2 ON x=555 WHERE a=234; } {234 def {} {} | 234 ghi {} {} |} do_execsql_test autoindex4-1.4 { SELECT *, '|' FROM t1 LEFT JOIN t2 WHERE a=234 AND x=555; } {} do_execsql_test autoindex4-2.0 { CREATE TABLE t3(e,f); INSERT INTO t3 VALUES(123,654),(555,444),(234,987); SELECT (SELECT count(*) FROM t1, t2 WHERE a=e AND x=f), e, f, '|' |
︙ | ︙ | |||
74 75 76 77 78 79 80 | FROM Items LEFT JOIN A ON (A.Name = Items.ItemName and Items.ItemName = 'dummy') LEFT JOIN B ON (B.Name = Items.ItemName) WHERE Items.Name = 'Parent' ORDER BY Items.ItemName; } {Item1 Item2} do_execsql_test autoindex4-3.1 { | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | FROM Items LEFT JOIN A ON (A.Name = Items.ItemName and Items.ItemName = 'dummy') LEFT JOIN B ON (B.Name = Items.ItemName) WHERE Items.Name = 'Parent' ORDER BY Items.ItemName; } {Item1 Item2} do_execsql_test autoindex4-3.1 { CREATE INDEX Items_x1 ON Items(ItemName,Name) WHERE ItemName = 'dummy'; SELECT Items.ItemName FROM Items LEFT JOIN A ON (A.Name = Items.ItemName and Items.ItemName = 'dummy') LEFT JOIN B ON (B.Name = Items.ItemName) WHERE Items.Name = 'Parent' ORDER BY Items.ItemName; } {Item1 Item2} 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 | 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 SUBQUERY * 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; |
︙ | ︙ | |||
120 121 122 123 124 125 126 | SELECT 0, 0 WHERE 0; SELECT ( SELECT sum(z) FROM vvv WHERE x='aaa' ) FROM one; } {8.0} | < < < < < < < < < < < < < < < < < < | 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | SELECT 0, 0 WHERE 0; SELECT ( SELECT sum(z) FROM vvv WHERE x='aaa' ) FROM one; } {8.0} # 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 { |
︙ | ︙ |
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 21 | # 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 SELECT statement. # # $Id: autovacuum.test,v 1.29 2009/04/06 17:50:03 danielk1977 Exp $ 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} { |
︙ | ︙ |
Deleted test/autovacuum2.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/avfs.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/backup.test.
︙ | ︙ | |||
965 966 967 968 969 970 971 | do_test backup-10.$tn.6 { B finish } {SQLITE_OK} db2 close } | < < < < < < < < < | 965 966 967 968 969 970 971 972 | do_test backup-10.$tn.6 { B finish } {SQLITE_OK} db2 close } 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 | } {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 {restore failed: file is not a database} } 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] lappend 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 |
︙ | ︙ |
Deleted test/basexx1.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/bestindex1.test.
︙ | ︙ | |||
25 26 27 28 29 30 31 | proc vtab_command {method args} { switch -- $method { xConnect { return "CREATE TABLE t1(a, b, c)" } xBestIndex { | | < < < | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | proc vtab_command {method args} { switch -- $method { xConnect { 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..." |
︙ | ︙ | |||
50 51 52 53 54 55 56 | 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 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.0 { CREATE VIRTUAL TABLE x1 USING tcl(vtab_command); } {} do_eqp_test 1.1 { SELECT * FROM x1 WHERE a = 'abc' } {SCAN TABLE x1 VIRTUAL TABLE INDEX 555:eq!} do_eqp_test 1.2 { SELECT * FROM x1 WHERE a IN ('abc', 'def'); } {SCAN TABLE x1 VIRTUAL TABLE INDEX 555:eq!} #------------------------------------------------------------------------- # reset_db register_tcl_module db # Parameter $mode may be one of: # # "omit" - Implement filtering. Set the omit flag. # "use" - Implement filtering. Use the constraint, but do not set omit. # "use2" - Do not implement filtering. Use the constraint anyway. # # proc t1_vtab {mode method args} { switch -- $method { xConnect { return "CREATE TABLE t1(a, b)" } xBestIndex { set SQL_FILTER {SELECT * FROM t1x WHERE a='%1%'} set SQL_SCAN {SELECT * FROM t1x} set clist [lindex $args 0] set idx 0 for {set idx 0} {$idx < [llength $clist]} {incr idx} { array unset C array set C [lindex $clist $idx] if {$C(column)==0 && $C(op)=="eq" && $C(usable)} { switch -- $mode { "omit" { |
︙ | ︙ | |||
143 144 145 146 147 148 149 | 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 TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x WHERE a='%1%' `--USE TEMP B-TREE FOR ORDER BY } set plan(omit) { QUERY PLAN |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x WHERE a='%1%' `--USE TEMP B-TREE FOR ORDER BY } set plan(use2) { QUERY PLAN |--SCAN TABLE 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)] } |
︙ | ︙ | |||
179 180 181 182 183 184 185 | switch -- $method { xConnect { return "CREATE TABLE t1($G(cols))" } xBestIndex { | | < < < | 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | switch -- $method { xConnect { return "CREATE TABLE t1($G(cols))" } xBestIndex { set clist [lindex $args 0] #puts $clist set W [list] set U [list] set i 0 for {set idx 0} {$idx < [llength $clist]} {incr idx} { array set c [lindex $clist $idx] |
︙ | ︙ | |||
292 293 294 295 296 297 298 | proc vtab_command {method args} { switch -- $method { xConnect { return "CREATE TABLE t1(a, b, c, d)" } xBestIndex { | | < < < | < < | 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 | 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 {} } |
︙ | ︙ | |||
333 334 335 336 337 338 339 | [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} ] ] | < < < | 319 320 321 322 323 324 325 326 327 | [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} ] ] finish_test |
Changes to test/bestindex2.test.
︙ | ︙ | |||
43 44 45 46 47 48 49 | # proc vtab_cmd {tbl cols method args} { switch -- $method { xConnect { return "CREATE TABLE $tbl ([join $cols ,])" } xBestIndex { | < < | < | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | # proc vtab_cmd {tbl cols method args} { switch -- $method { xConnect { return "CREATE TABLE $tbl ([join $cols ,])" } xBestIndex { foreach {clist orderby mask} $args {} set cons [list] set used [list] for {set i 0} {$i < [llength $clist]} {incr i} { array unset C array set C [lindex $clist $i] |
︙ | ︙ | |||
88 89 90 91 92 93 94 | 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 TABLE t1 VIRTUAL TABLE INDEX 0:indexed(a=?)} do_eqp_test 1.2 { SELECT * FROM t1 WHERE a='abc' AND b='def' } {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:indexed(a=? AND b=?)} do_eqp_test 1.3 { SELECT * FROM t1 WHERE a='abc' AND a='def' } {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:indexed(a=?)} do_eqp_test 1.4 { SELECT * FROM t1,t2 WHERE c=a } { QUERY PLAN |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0: `--SCAN TABLE 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 TABLE t1 VIRTUAL TABLE INDEX 0: |--SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?) `--SCAN TABLE 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 TABLE t1 VIRTUAL TABLE INDEX 0: |--SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?) `--SCAN TABLE 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 TABLE x1 |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0: |--SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?) `--SCAN TABLE t3 VIRTUAL TABLE INDEX 0:indexed(e=?) } finish_test |
Changes to test/bestindex3.test.
︙ | ︙ | |||
30 31 32 33 34 35 36 | proc vtab_cmd {bOmit method args} { switch -- $method { xConnect { return "CREATE TABLE t1(a, b, c)" } xBestIndex { | < < | < | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | proc vtab_cmd {bOmit method args} { switch -- $method { xConnect { return "CREATE TABLE t1(a, b, c)" } xBestIndex { foreach {clist orderby mask} $args {} set ret [list] set use use if {$bOmit} {set use omit} for {set i 0} {$i < [llength $clist]} {incr i} { array unset C |
︙ | ︙ | |||
78 79 80 81 82 83 84 | 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 TABLE t1 VIRTUAL TABLE INDEX 0:a LIKE ?} do_eqp_test 1.2 { SELECT * FROM t1 WHERE a = 'abc'; } {SCAN TABLE 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 TABLE t1 VIRTUAL TABLE INDEX 0:a EQ ? `--INDEX 2 `--SCAN TABLE 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 TABLE t1 VIRTUAL TABLE INDEX 0:a LIKE ? `--INDEX 2 `--SCAN TABLE 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'); |
︙ | ︙ | |||
154 155 156 157 158 159 160 | 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 | | | | 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 TABLE t2 USING INDEX t2x (x>? AND x<?) `--INDEX 2 `--SEARCH TABLE 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.
︙ | ︙ | |||
44 45 46 47 48 49 50 | proc vtab_cmd {param method args} { switch -- $method { xConnect { return "CREATE TABLE t1(id TEXT, host TEXT, class TEXT)" } xBestIndex { | < < | < | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | proc vtab_cmd {param method args} { switch -- $method { xConnect { return "CREATE TABLE t1(id TEXT, host TEXT, class TEXT)" } xBestIndex { foreach {clist orderby mask} $args {} set ret [list] set use use for {set i 0} {$i < [llength $clist]} {incr i} { |
︙ | ︙ | |||
134 135 136 137 138 139 140 | proc vtab_command {method args} { switch -- $method { xConnect { return "CREATE TABLE t1(a, b, c, d HIDDEN)" } xBestIndex { | | < < < < | 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | proc vtab_command {method args} { switch -- $method { xConnect { return "CREATE TABLE t1(a, b, c, d HIDDEN)" } 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 [list omit 0 idxnum 555 rows 10 cost 100] } return [list cost 100000000] |
︙ | ︙ | |||
162 163 164 165 166 167 168 | 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 TABLE x1 VIRTUAL TABLE INDEX 0: `--SEARCH TABLE t1 USING COVERING INDEX sqlite_autoindex_t1_1 (x=?) } do_eqp_test 2.2 { SELECT * FROM t1, x1(t1.x) } { QUERY PLAN |--SCAN TABLE t1 `--SCAN TABLE x1 VIRTUAL TABLE INDEX 555: } finish_test |
Changes to test/bestindex5.test.
︙ | ︙ | |||
10 11 12 13 14 15 16 | #*********************************************************************** # Test the virtual table interface. In particular the xBestIndex # method. # set testdir [file dirname $argv0] source $testdir/tester.tcl | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #*********************************************************************** # Test the virtual table interface. In particular the xBestIndex # method. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix bestindex4 ifcapable !vtab { finish_test return } #------------------------------------------------------------------------- |
︙ | ︙ | |||
40 41 42 43 44 45 46 | switch -- $method { xConnect { return "CREATE TABLE t1(a, b, c)" } xBestIndex { | < < | < | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | switch -- $method { xConnect { return "CREATE TABLE t1(a, b, c)" } xBestIndex { foreach {clist orderby mask} $args {} set cost 1000000.0 set ret [list] set str [list] set v 0 for {set i 0} {$i < [llength $clist]} {incr i} { |
︙ | ︙ |
Changes to test/bestindex6.test.
︙ | ︙ | |||
24 25 26 27 28 29 30 | proc vtab_command {src method args} { switch -- $method { xConnect { return [db one {SELECT sql FROM sqlite_master where name = $src}] } xBestIndex { | | < < < < | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | proc vtab_command {src method args} { switch -- $method { xConnect { return [db one {SELECT sql FROM sqlite_master where name = $src}] } xBestIndex { set clist [lindex $args 0] set wlist 1 set iCons 0 set ret [list] foreach cons $clist { catch { array unset C } array set C $cons |
︙ | ︙ |
Deleted test/bestindex7.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/bestindex8.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/bestindex9.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/bestindexA.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 { TABLE (\w+ AS )?(\w+) USING.* INDEX (\w+)\y} \ $x all as tab idx]} { lappend data $tab $idx } elseif {[regexp { TABLE (\w+ AS )?(\w+)\y} $x all 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 | } {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 *} finish_test |
Changes to test/bigmmap.test.
︙ | ︙ | |||
48 49 50 51 52 53 54 | PRAGMA page_size = 4096; CREATE TABLE t0(a INTEGER PRIMARY KEY, b, c, UNIQUE(b, c)); WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 100 ) INSERT INTO t0 SELECT i, 't0', randomblob(800) FROM s; } for {set i 1} {$i < 8} {incr i} { | | < < < < | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | PRAGMA page_size = 4096; CREATE TABLE t0(a INTEGER PRIMARY KEY, b, c, UNIQUE(b, c)); WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 100 ) INSERT INTO t0 SELECT i, 't0', randomblob(800) FROM s; } for {set i 1} {$i < 8} {incr i} { fake_big_file [expr $i*1024] [get_pwd]/test.db hexio_write test.db 28 [format %.8x [expr ($i*1024*1024*1024/4096) - 5]] do_execsql_test 1.$i " CREATE TABLE t$i (a INTEGER PRIMARY KEY, b, c, UNIQUE(b, c)); WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s LIMIT 100 ) INSERT INTO t$i SELECT i, 't$i', randomblob(800) FROM s; " |
︙ | ︙ | |||
94 95 96 97 98 99 100 | 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 TABLE t$t AS o USING COVERING INDEX sqlite_autoindex_t${t}_1 `--CORRELATED SCALAR SUBQUERY `--SEARCH TABLE t$t AS i USING INTEGER PRIMARY KEY (rowid=?) "] } } finish_test |
Changes to test/bigsort.test.
︙ | ︙ | |||
20 21 22 23 24 25 26 | # loop if the product was also an integer multiple of 2^32, or # inefficiency otherwise. # # This test causes thrashing on machines with smaller amounts of # memory. Make sure the host has at least 8GB available before running # this test. # | < < < < < < < | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | # loop if the product was also an integer multiple of 2^32, or # inefficiency otherwise. # # This test causes thrashing on machines with smaller amounts of # memory. Make sure the host has at least 8GB available before running # this test. # if {[catch {exec free | grep Mem:} out] || [lindex $out 1]<8000000} { finish_test return } do_execsql_test 1.0 { PRAGMA page_size = 1024; CREATE TABLE t1(a, b); BEGIN; WITH data(x,y) AS ( SELECT 1, zeroblob(10000) |
︙ | ︙ |
Deleted test/bind2.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/bloom1.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/btree01.test.
︙ | ︙ | |||
124 125 126 127 128 129 130 | INSERT INTO t1(a,b) SELECT i, zeroblob(6500) FROM c; UPDATE t1 SET b=zeroblob(4000); UPDATE t1 SET b=zeroblob(65000) WHERE a=$::i; PRAGMA integrity_check; } } {ok} } | < < < < < < < < < < < < < < < < < < < < < < < < | 124 125 126 127 128 129 130 131 132 | INSERT INTO t1(a,b) SELECT i, zeroblob(6500) FROM c; UPDATE t1 SET b=zeroblob(4000); UPDATE t1 SET b=zeroblob(65000) WHERE a=$::i; PRAGMA integrity_check; } } {ok} } finish_test |
Changes to test/btreefault.test.
︙ | ︙ | |||
49 50 51 52 53 54 55 | } -body { execsql { PRAGMA incremental_vacuum = 10 } } -test { sqlite3_finalize $::STMT faultsim_test_result {0 {}} faultsim_integrity_check } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 49 50 51 52 53 54 55 56 57 | } -body { execsql { PRAGMA incremental_vacuum = 10 } } -test { sqlite3_finalize $::STMT faultsim_test_result {0 {}} faultsim_integrity_check } finish_test |
Deleted test/busy2.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/capi3c.test.
︙ | ︙ | |||
1265 1266 1267 1268 1269 1270 1271 | do_test capi3c-21.2 { sqlite3_extended_errcode $DB } {SQLITE_INTERRUPT} do_test capi3c-21.3 { sqlite3_finalize $STMT } {SQLITE_INTERRUPT} do_test capi3c-21.4 { | < | 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 | do_test capi3c-21.2 { sqlite3_extended_errcode $DB } {SQLITE_INTERRUPT} do_test capi3c-21.3 { sqlite3_finalize $STMT } {SQLITE_INTERRUPT} do_test capi3c-21.4 { set STMT [sqlite3_prepare $DB {SELECT * FROM t3} -1 TAIL] db progress 5 "expr 1" sqlite3_step $STMT } {SQLITE_ERROR} do_test capi3c-21.5 { sqlite3_errcode $DB } {SQLITE_ERROR} |
︙ | ︙ |
Changes to test/capi3d.test.
︙ | ︙ | |||
96 97 98 99 100 101 102 | do_test $testname [format { set DB [sqlite3_connection_pointer db] set STMT [sqlite3_prepare $DB {%s} -1 TAIL] set rc [sqlite3_stmt_readonly $STMT] sqlite3_finalize $STMT set rc } $sql] $truth | | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | do_test $testname [format { set DB [sqlite3_connection_pointer db] set STMT [sqlite3_prepare $DB {%s} -1 TAIL] set rc [sqlite3_stmt_readonly $STMT] sqlite3_finalize $STMT set rc } $sql] $truth } test_is_readonly capi3d-2.1 {SELECT * FROM sqlite_master} 1 test_is_readonly capi3d-2.2 {CREATE TABLE t1(x)} 0 db eval {CREATE TABLE t1(x)} test_is_readonly capi3d-2.3 {INSERT INTO t1 VALUES(5)} 0 test_is_readonly capi3d-2.4 {UPDATE t1 SET x=x+1 WHERE x<0} 0 test_is_readonly capi3d-2.5 {SELECT * FROM t1} 1 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] |
︙ | ︙ |
Deleted test/carray01.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 case-1.60 { execsql {SELECT CAST(null AS REAL)} } {{}} do_test case-1.61 { execsql {SELECT typeof(CAST(null AS REAL))} } {null} do_test case-1.62 { execsql {SELECT CAST(1 AS REAL)} } {1.0} do_test case-1.63 { execsql {SELECT typeof(CAST(1 AS REAL))} } {real} do_test case-1.64 { execsql {SELECT CAST('1' AS REAL)} } {1.0} do_test case-1.65 { execsql {SELECT typeof(CAST('1' AS REAL))} } {real} do_test case-1.66 { execsql {SELECT CAST('abc' AS REAL)} } {0.0} do_test case-1.67 { execsql {SELECT typeof(CAST('abc' AS REAL))} } {real} do_test case-1.68 { execsql {SELECT CAST(x'31' AS REAL)} } {1.0} do_test case-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 case-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 | } {-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 case-5.3 { SELECT CAST('123e+5' AS INTEGER); SELECT CAST('123e+5' AS NUMERIC); } {123 12300000.0} # The following does not have anything to do with the CAST operator, # but it does deal with affinity transformations. # do_execsql_test case-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} finish_test |
Deleted test/changes.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/changes2.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/check.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # 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 { finish_test return } | > < < | | | 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 | # 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 # # $Id: check.test,v 1.13 2009/06/05 17:09:12 drh Exp $ 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 { finish_test return } do_test check-1.1 { execsql { CREATE TABLE t1( x INTEGER CHECK( x<5 ), y REAL CHECK( y>x ) ); } } {} do_test check-1.2 { execsql { INSERT INTO t1 VALUES(3,4); SELECT * FROM t1; } } {3 4.0} do_test check-1.3 { catchsql { INSERT INTO t1 VALUES(6,7); } } {1 {CHECK constraint failed: t1}} 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: t1}} do_test check-1.6 { execsql { SELECT * FROM t1; } } {3 4.0} do_test check-1.7 { catchsql { |
︙ | ︙ | |||
85 86 87 88 89 90 91 | SELECT * FROM t1; } } {2 4.0} do_test check-1.12 { catchsql { UPDATE t1 SET x=7 WHERE x==2 } | | | < < < < < < < < < < < < < < < < < | | < | 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 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 | SELECT * FROM t1; } } {2 4.0} do_test check-1.12 { catchsql { UPDATE t1 SET x=7 WHERE x==2 } } {1 {CHECK constraint failed: t1}} 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: t1}} 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 { 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' ) ); } } {} do_test check-2.2 { execsql { INSERT INTO t2 VALUES(1,2.2,'three'); SELECT * FROM t2; } } {1 2.2 three} db close sqlite3 db test.db do_test check-2.3 { execsql { INSERT INTO t2 VALUES(NULL, NULL, NULL); SELECT * FROM t2; } } {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); } } {1 {CHECK constraint failed: three}} # 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: t2b}} 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; } } {} ifcapable subquery { do_test check-3.1 { catchsql { CREATE TABLE t3( |
︙ | ︙ | |||
271 272 273 274 275 276 277 | SELECT * FROM t3; } } {1 2 3} do_test check-3.9 { catchsql { INSERT INTO t3 VALUES(111,222,333); } | | | 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 | SELECT * FROM t3; } } {1 2 3} do_test check-3.9 { catchsql { INSERT INTO t3 VALUES(111,222,333); } } {1 {CHECK constraint failed: t3}} do_test check-4.1 { execsql { CREATE TABLE t4(x, y, CHECK ( x+y==11 OR x*y==12 |
︙ | ︙ | |||
313 314 315 316 317 318 319 | SELECT * FROM t4 } } {12 -22} do_test check-4.6 { catchsql { UPDATE t4 SET x=0, y=1; } | | < < < | 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 | SELECT * FROM t4 } } {12 -22} do_test check-4.6 { catchsql { UPDATE t4 SET x=0, y=1; } } {1 {CHECK constraint failed: t4}} do_test check-4.7 { execsql { SELECT * FROM t4; } } {12 -22} do_test check-4.8 { execsql { |
︙ | ︙ | |||
338 339 340 341 342 343 344 | 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; } | | < < < | 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 | 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: t4}} ifcapable vacuum { do_test check_4.10 { catchsql { VACUUM } } {0 {}} } |
︙ | ︙ | |||
392 393 394 395 396 397 398 | 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; } | | | | | 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 | 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: t1}} 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: t1}} 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: t1}} 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); } |
︙ | ︙ | |||
447 448 449 450 451 452 453 | # 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} | | | | 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 | # 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 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: t6}} do_test 7.4 { sqlite3 db2 test.db execsql { SELECT * FROM t6 } db2 } {9} do_test 7.5 { |
︙ | ︙ | |||
475 476 477 478 479 480 481 | 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 | | | 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 | 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: t6}} # 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 )); } {} |
︙ | ︙ | |||
514 515 516 517 518 519 520 | 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} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 489 490 491 492 493 494 495 496 | 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 |
Deleted test/checkfault.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/chunksize.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/close.test.
︙ | ︙ | |||
75 76 77 78 79 80 81 | } msg] $msg } {1 {(21) bad parameter or other API misuse}} do_test 1.4.4 { sqlite3_finalize $STMT } {SQLITE_OK} | < < < < < < < | 75 76 77 78 79 80 81 82 | } msg] $msg } {1 {(21) bad parameter or other API misuse}} do_test 1.4.4 { sqlite3_finalize $STMT } {SQLITE_OK} finish_test |
Changes to test/collate1.test.
︙ | ︙ | |||
334 335 336 337 338 339 340 | } {1 2} #------------------------------------------------------------------------- # Fix problems with handling collation sequences named '"""'. # | < | 334 335 336 337 338 339 340 341 342 343 344 345 346 347 | } {1 2} #------------------------------------------------------------------------- # Fix problems with handling collation sequences named '"""'. # do_execsql_test 6.1 { SELECT """"""""; } {\"\"\"} do_catchsql_test 6.2 { CREATE TABLE x1(a); SELECT a FROM x1 ORDER BY a COLLATE """"""""; |
︙ | ︙ | |||
397 398 399 400 401 402 403 | 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} | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
Changes to test/collate2.test.
︙ | ︙ | |||
680 681 682 683 684 685 686 | } } {aa aA Aa AA} do_test collate2-5.3 { execsql { SELECT collate2t1.b FROM collate2t2 NATURAL JOIN collate2t1; } } {aa} | | | | < < < < < < < < < < < < < < < < < < | 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 | } } {aa aA Aa AA} do_test collate2-5.3 { execsql { SELECT collate2t1.b FROM collate2t2 NATURAL JOIN collate2t1; } } {aa} do_test collate2-5.4 { execsql { SELECT collate2t2.b FROM collate2t1 LEFT OUTER JOIN collate2t2 USING (b) order by collate2t1.oid; } } {{} aa {} {} {} aa {} {} {} aa {} {} {} aa {} {} {}} do_test collate2-5.5 { execsql { SELECT collate2t1.b, collate2t2.b FROM collate2t2 LEFT OUTER JOIN collate2t1 USING (b); } } {aa aa} do_execsql_test 6.1 { CREATE TABLE t1(x); INSERT INTO t1 VALUES('b'); INSERT INTO t1 VALUES('B'); |
︙ | ︙ |
Changes to test/collate5.test.
︙ | ︙ | |||
15 16 17 18 19 20 21 | # GROUP BY clauses that use user-defined collation sequences. # # $Id: collate5.test,v 1.7 2008/09/16 11:58:20 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl | < < < | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | # GROUP BY clauses that use user-defined collation sequences. # # $Id: collate5.test,v 1.7 2008/09/16 11:58:20 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # # Tests are organised as follows: # collate5-1.* - DISTINCT # collate5-2.* - Compound SELECT # collate5-3.* - ORDER BY on compound SELECT # collate5-4.* - GROUP BY # Create the collation sequence 'TEXT', purely for asthetic reasons. The # test cases in this script could just as easily use BINARY. db collate TEXT [list string compare] # Mimic the SQLite 2 collation type NUMERIC. db collate numeric numeric_collate |
︙ | ︙ | |||
287 288 289 290 291 292 293 294 | } } {/[aA] 1(.0)? 2 [bB] 2 1 [bB] 3 1/} do_test collate5-4.3 { execsql { DROP TABLE collate5t1; } } {} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 284 285 286 287 288 289 290 291 292 | } } {/[aA] 1(.0)? 2 [bB] 2 1 [bB] 3 1/} do_test collate5-4.3 { execsql { DROP TABLE collate5t1; } } {} finish_test |
Deleted test/columncount.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/conflict.test.
︙ | ︙ | |||
809 810 811 812 813 814 815 | 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 | CREATE TABLE t13(a CHECK(a!=2)); BEGIN; REPLACE INTO t13 VALUES(1); } catchsql { REPLACE INTO t13 VALUES(2); } } {1 {CHECK constraint failed: t13}} 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}} 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: t13}} 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 | 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} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
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 0 0123456789] 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 16 17 18 | # #*********************************************************************** # 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 | > < | 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. # # $Id: corrupt4.test,v 1.1 2007/09/07 14:32:07 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # 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 # |
︙ | ︙ | |||
75 76 77 78 79 80 81 | db close sqlite3 db test.db catchsql { DROP TABLE t2 } } {1 {database disk image is malformed}} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 75 76 77 78 79 80 81 82 | db close sqlite3 db test.db catchsql { DROP TABLE t2 } } {1 {database disk image is malformed}} finish_test |
Changes to test/corruptC.test.
︙ | ︙ | |||
30 31 32 33 34 35 36 | # These tests deal with corrupt database files # database_may_be_corrupt # Construct a compact, dense database for testing. # do_test corruptC-1.1 { | < > | 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 { execsql { PRAGMA auto_vacuum = 0; PRAGMA legacy_file_format=1; 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/corruptE.test.
︙ | ︙ | |||
32 33 34 35 36 37 38 | finish_test return } # Construct a compact, dense database for testing. # do_test corruptE-1.1 { | < > | 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 { execsql { PRAGMA auto_vacuum = 0; PRAGMA legacy_file_format=1; 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/corruptL.test.
︙ | ︙ | |||
224 225 226 227 228 229 230 | | 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 { | | | 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | | 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; 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}} |
︙ | ︙ | |||
373 374 375 376 377 378 379 | | 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 }]} {} | < < < < < > | | 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 | | 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 }]} {} do_catchsql_test 4.1 { INSERT INTO t3 SELECT * FROM t2; } {1 {malformed database schema (t1)}} #------------------------------------------------------------------------- reset_db do_test 5.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 192512 pagesize 4096 filename crash-9ae5502296c949.db |
︙ | ︙ | |||
606 607 608 609 610 611 612 | | 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).... | | | 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 | | 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 c2 6c 65 74 31 74 31 02 .....sta.let1t1. | 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 |
︙ | ︙ | |||
633 634 635 636 637 638 639 | }]} {} do_catchsql_test 6.1 { BEGIN; INSERT INTO t1(b) VALUES(1); INSERT INTO t1(b) VALUES(2); COMMIT; | | | 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 | }]} {} do_catchsql_test 6.1 { BEGIN; INSERT INTO t1(b) VALUES(1); INSERT INTO t1(b) VALUES(2); COMMIT; } {1 {malformed database schema (t1)}} #------------------------------------------------------------------------- reset_db do_test 7.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 20480 pagesize 4096 filename crash-8391315d75edff.db |
︙ | ︙ | |||
834 835 836 837 838 839 840 | | 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 }]} {} | < < < | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 830 831 832 833 834 835 836 837 838 839 840 841 842 | | 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 }]} {} do_catchsql_test 8.1 { INSERT INTO t3 SELECT * FROM t2; } {1 {malformed database schema (t1)}} finish_test |
Changes to test/corruptM.test.
︙ | ︙ | |||
18 19 20 21 22 23 24 | source $testdir/tester.tcl set testprefix corruptM # These tests deal with corrupt database files # database_may_be_corrupt | < < < < < < < < < < > | | > > | | > > | | > > | | > > | | > > | | > > | | > > | | > > | | > > | | > > | | > > | | > > | | > | 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 | source $testdir/tester.tcl set testprefix corruptM # These tests deal with corrupt database files # database_may_be_corrupt 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 |} sqlite3 db2 test.db do_test corruptM-102 { catchsql { PRAGMA quick_check; } db2 } {1 {malformed database schema (t1)}} db2 close 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 |} sqlite3 db2 test.db do_test corruptM-111 { catchsql { PRAGMA quick_check; } db2 } {1 {malformed database schema (t1)}} db2 close 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 |} sqlite3 db2 test.db do_test corruptM-113 { catchsql { PRAGMA quick_check; } db2 } {1 {malformed database schema (t1)}} db2 close 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 |} sqlite3 db2 test.db do_test corruptM-114 { catchsql { PRAGMA quick_check; } db2 } {1 {malformed database schema (t9)}} db2 close 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 |} sqlite3 db2 test.db do_test corruptM-121 { catchsql { PRAGMA quick_check; SELECT * FROM t1, v2; } db2 } {0 {ok 111 222 333 15 22}} db2 close 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 |} sqlite3 db2 test.db do_test corruptM-131 { catchsql { PRAGMA quick_check; SELECT * FROM t1, v2; } db2 } {1 {malformed database schema (t1)}} db2 close 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 |} sqlite3 db2 test.db do_test corruptM-141 { catchsql { PRAGMA quick_check; SELECT * FROM t1, v2; } db2 } {1 {malformed database schema (i1)}} db2 close 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 |} sqlite3 db2 test.db do_test corruptM-151 { catchsql { PRAGMA quick_check; SELECT * FROM t1, v2; } db2 } {1 {malformed database schema (i1)}} db2 close 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 |} sqlite3 db2 test.db do_test corruptM-161 { catchsql { PRAGMA quick_check; SELECT * FROM t1, v2; } db2 } {1 {malformed database schema (i1)}} db2 close 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 |} sqlite3 db2 test.db do_test corruptM-171 { catchsql { PRAGMA quick_check; SELECT * FROM t1, v2; } db2 } {1 {malformed database schema (v2)}} db2 close 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 |} sqlite3 db2 test.db do_test corruptM-181 { catchsql { PRAGMA quick_check; SELECT * FROM t1, v2; } db2 } {1 {malformed database schema (v3)}} db2 close 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 |} sqlite3 db2 test.db do_test corruptM-191 { catchsql { PRAGMA quick_check; SELECT * FROM t1, v2; } db2 } {1 {malformed database schema (r1)}} db2 close 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 |} sqlite3 db2 test.db do_test corruptM-193 { catchsql { PRAGMA quick_check; SELECT * FROM t1, v2; } db2 } {1 {malformed database schema (r1)}} db2 close finish_test |
Deleted test/corruptN.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 TABLE t3 USING COVERING INDEX i3 `--SEARCH TABLE 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 TABLE 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 TABLE t5 USING INDEX t5b (b=?) | |--INDEX 2 | | `--SEARCH TABLE t5 USING INDEX t5c (c=?) | `--INDEX 3 | `--SEARCH TABLE 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 TABLE t1 USING INDEX i1 (a=?)} do_eqp_test 4.3 { SELECT * FROM t1 WHERE likelihood(a=?, 0.016) AND b BETWEEN ? AND ?; } {SEARCH TABLE 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 TABLE 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 TABLE 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 TABLE t3 USING INDEX t3i1 (b>? AND b<?) | `--INDEX 2 | `--SEARCH TABLE t3 USING INDEX t3i2 (c=?) `--USE TEMP B-TREE FOR ORDER BY } #------------------------------------------------------------------------- # reset_db do_execsql_test 7.1 { |
︙ | ︙ | |||
151 152 153 154 155 156 157 | 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 | | | | | | 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 | 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 TABLE t1 USING INDEX t1b (b>? AND b<?) | `--INDEX 2 | `--SEARCH TABLE 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 TABLE t1} do_eqp_test 7.4 { SELECT rowid FROM t1 WHERE (+b IS NULL AND c NOT NULL) OR c IS NULL } {SCAN TABLE t1} #------------------------------------------------------------------------- # reset_db do_execsql_test 8.1 { CREATE TABLE composer( cid INTEGER PRIMARY KEY, |
︙ | ︙ | |||
198 199 200 201 202 203 204 | 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 TABLE track |--SEARCH TABLE album USING INTEGER PRIMARY KEY (rowid=?) |--SEARCH TABLE composer USING INTEGER PRIMARY KEY (rowid=?) `--USE TEMP B-TREE FOR DISTINCT } #------------------------------------------------------------------------- # do_execsql_test 9.1 { CREATE TABLE t1( |
︙ | ︙ | |||
226 227 228 229 230 231 232 | 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 9 3 3 8 4 4 7 5 5 6 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 "] |
︙ | ︙ | |||
267 268 269 270 271 272 273 | 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 TABLE t6 USING INDEX t6i2 (c=?)} do_eqp_test 10.4 { SELECT rowid FROM t6 WHERE a=0 AND b='xyz' AND c=0 } {SEARCH TABLE t6 USING INDEX t6i2 (c=?)} do_eqp_test 10.5 { SELECT rowid FROM t6 WHERE likelihood(a=0, 0.1) AND c=0 } {SEARCH TABLE 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 TABLE t6 USING INDEX t6i1 (a=? AND b=?)} } finish_test |
Changes to test/count.test.
︙ | ︙ | |||
122 123 124 125 126 127 128 | } {1 {DISTINCT aggregates must have exactly one argument}} do_test count-2.7 { uses_op_count {SELECT count(*)+1 FROM t2} } {0} do_test count-2.8 { uses_op_count {SELECT count(*) FROM t2 WHERE a IS NOT NULL} } {0} | | | < < | < | 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | } {1 {DISTINCT aggregates must have exactly one argument}} do_test count-2.7 { uses_op_count {SELECT count(*)+1 FROM t2} } {0} do_test count-2.8 { uses_op_count {SELECT count(*) FROM t2 WHERE a IS NOT NULL} } {0} do_test count-2.9 { catchsql {SELECT count(*) FROM t2 HAVING count(*)>1} } {1 {a GROUP BY clause is required before HAVING}} do_test count-2.10 { uses_op_count {SELECT count(*) FROM (SELECT 1)} } {0} do_test count-2.11 { execsql { CREATE VIEW v1 AS SELECT 1 AS a } uses_op_count {SELECT count(*) FROM v1} } {0} |
︙ | ︙ | |||
194 195 196 197 198 199 200 201 | 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}} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
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 TABLE t1 USING COVERING INDEX i1} do_eqp_test 5.1.2 { SELECT * FROM t2 ORDER BY c1, c2; } {SCAN TABLE 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 | 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_MEMDEBUG..." finish_test return } db close for {set ii 0} {$ii < 10} {incr ii} { for {set jj 50} {$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] { 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 catch {db eval { CREATE UNIQUE INDEX i1 ON t1(a); }} msg # puts "$n $msg ac=[sqlite3_get_autocommit db]" # If the transaction is still active (it may not be if the malloc() # failure occurred in the OS layer), write to the database. Make sure # page 4 is among those written. # if {![sqlite3_get_autocommit db]} { db eval { DELETE FROM t1; -- This will put page 4 on the free list. INSERT INTO t1 VALUES('111111111', '2222222222', '33333333'); INSERT INTO t1 SELECT * FROM t1; -- 2 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/cse.test.
︙ | ︙ | |||
14 15 16 17 18 19 20 | # 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 | < | 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); } |
︙ | ︙ | |||
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 } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
Changes to test/csv01.test.
︙ | ︙ | |||
232 233 234 235 236 237 238 | 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 |} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 232 233 234 235 236 237 238 239 240 | 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/ctime.test.
︙ | ︙ | |||
77 78 79 80 81 82 83 | SELECT sqlite_compileoption_used($opt) } $res } } # SQLITE_THREADSAFE should pretty much always be defined # one way or the other, and it must have a value of 0 or 1. | < | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | SELECT sqlite_compileoption_used($opt) } $res } } # SQLITE_THREADSAFE should pretty much always be defined # one way or the other, and it must have a value of 0 or 1. do_test ctime-1.4.1 { catchsql { SELECT sqlite_compileoption_used('SQLITE_THREADSAFE'); } } {0 1} do_test ctime-1.4.2 { catchsql { |
︙ | ︙ |
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 } } {00 00} # 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 } } {00 00} # 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; } } {02 00} 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; } } {00} 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/date.test.
︙ | ︙ | |||
235 236 237 238 239 240 241 | datetest 5.10 {datetime('1994-04-16 14:00:00 Z')} {1994-04-16 14:00:00} datetest 5.11 {datetime('1994-04-16 14:00:00z ')} {1994-04-16 14:00:00} datetest 5.12 {datetime('1994-04-16 14:00:00 z ')} {1994-04-16 14:00:00} datetest 5.13 {datetime('1994-04-16 14:00:00Zulu')} NULL datetest 5.14 {datetime('1994-04-16 14:00:00Z +05:00')} NULL datetest 5.15 {datetime('1994-04-16 14:00:00 +05:00 Z')} NULL | | > > < < > > > > | < < > > > > < | < < > > > | > > | < > > > | > | < < | > > > > > > > > | | > | | > > > > | > > > | > > | > > | > > > | > > > > > | | > > > > | > > > | > > | > | > | < < < > > > > | > | < < < > > > | < > > > > > > > < | | > > > > > | > > > > > | > > > > > | < | < < < < > > > | | < > | 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 | datetest 5.10 {datetime('1994-04-16 14:00:00 Z')} {1994-04-16 14:00:00} datetest 5.11 {datetime('1994-04-16 14:00:00z ')} {1994-04-16 14:00:00} datetest 5.12 {datetime('1994-04-16 14:00:00 z ')} {1994-04-16 14:00:00} datetest 5.13 {datetime('1994-04-16 14:00:00Zulu')} NULL datetest 5.14 {datetime('1994-04-16 14:00:00Z +05:00')} NULL datetest 5.15 {datetime('1994-04-16 14:00:00 +05:00 Z')} NULL # localtime->utc and utc->localtime conversions. These tests only work # if the localtime is in the US Eastern Time (the time in Charlotte, NC # and in New York.) # # On non-Vista Windows platform, '2006-03-31' is treated incorrectly as being # in DST giving a 4 hour offset instead of 5. In 2007, DST was extended to # start three weeks earlier (second Sunday in March) and end one week # later (first Sunday in November). Older Windows systems apply this # new rule incorrectly to dates prior to 2007. # # It might be argued that this is masking a problem on non-Vista Windows # platform. A ticket has already been opened for this issue # (http://www.sqlite.org/cvstrac/tktview?tn=2322). This is just to prevent # more confusion/reports of the issue. # # $tzoffset_old should be 5 if DST is working correctly. set tzoffset_old [db one { SELECT CAST(24*(julianday('2006-03-31') - julianday('2006-03-31','localtime'))+0.5 AS INT) }] # $tzoffset_new should be 4 if DST is working correctly. set tzoffset_new [db one { SELECT CAST(24*(julianday('2007-03-31') - julianday('2007-03-31','localtime'))+0.5 AS INT) }] # Warn about possibly broken Windows DST implementations. if {$::tcl_platform(platform)=="windows" && $tzoffset_new==4 && $tzoffset_old==4} { puts "******************************************************************" puts "N.B.: The DST support provided by your current O/S seems to be" puts "suspect in that it is reporting incorrect DST values for dates" puts "prior to 2007. This is the known case for most (all?) non-Vista" puts "Windows versions. Please see ticket #2322 for more information." puts "******************************************************************" } if {$tzoffset_new==4} { datetest 6.1 {datetime('2000-10-29 05:59:00','localtime')}\ {2000-10-29 01:59:00} datetest 6.1.1 {datetime('2006-10-29 05:59:00','localtime')}\ {2006-10-29 01:59:00} datetest 6.1.2 {datetime('2007-11-04 05:59:00','localtime')}\ {2007-11-04 01:59:00} # If the new and old DST rules seem to be working correctly... if {$tzoffset_new==4 && $tzoffset_old==5} { datetest 6.2 {datetime('2000-10-29 06:00:00','localtime')}\ {2000-10-29 01:00:00} datetest 6.2.1 {datetime('2006-10-29 06:00:00','localtime')}\ {2006-10-29 01:00:00} } datetest 6.2.2 {datetime('2007-11-04 06:00:00','localtime')}\ {2007-11-04 01:00:00} # If the new and old DST rules seem to be working correctly... if {$tzoffset_new==4 && $tzoffset_old==5} { datetest 6.3 {datetime('2000-04-02 06:59:00','localtime')}\ {2000-04-02 01:59:00} datetest 6.3.1 {datetime('2006-04-02 06:59:00','localtime')}\ {2006-04-02 01:59:00} } datetest 6.3.2 {datetime('2007-03-11 07:00:00','localtime')}\ {2007-03-11 03:00:00} datetest 6.4 {datetime('2000-04-02 07:00:00','localtime')}\ {2000-04-02 03:00:00} datetest 6.4.1 {datetime('2006-04-02 07:00:00','localtime')}\ {2006-04-02 03:00:00} datetest 6.4.2 {datetime('2007-03-11 07:00:00','localtime')}\ {2007-03-11 03:00:00} datetest 6.5 {datetime('2000-10-29 01:59:00','utc')} {2000-10-29 05:59:00} datetest 6.5.1 {datetime('2006-10-29 01:59:00','utc')} {2006-10-29 05:59:00} datetest 6.5.2 {datetime('2007-11-04 01:59:00','utc')} {2007-11-04 05:59:00} # If the new and old DST rules seem to be working correctly... if {$tzoffset_new==4 && $tzoffset_old==5} { datetest 6.6 {datetime('2000-10-29 02:00:00','utc')} {2000-10-29 07:00:00} datetest 6.6.1 {datetime('2006-10-29 02:00:00','utc')} {2006-10-29 07:00:00} } datetest 6.6.2 {datetime('2007-11-04 02:00:00','utc')} {2007-11-04 07:00:00} # If the new and old DST rules seem to be working correctly... if {$tzoffset_new==4 && $tzoffset_old==5} { datetest 6.7 {datetime('2000-04-02 01:59:00','utc')} {2000-04-02 06:59:00} datetest 6.7.1 {datetime('2006-04-02 01:59:00','utc')} {2006-04-02 06:59:00} } datetest 6.7.2 {datetime('2007-03-11 01:59:00','utc')} {2007-03-11 06:59:00} datetest 6.8 {datetime('2000-04-02 02:00:00','utc')} {2000-04-02 06:00:00} datetest 6.8.1 {datetime('2006-04-02 02:00:00','utc')} {2006-04-02 06:00:00} datetest 6.8.2 {datetime('2007-03-11 02:00:00','utc')} {2007-03-11 06:00:00} # The 'utc' modifier is a no-op if the LHS is known to already be in UTC datetest 6.9.1 {datetime('2015-12-23 12:00:00','utc')} {2015-12-23 17:00:00} datetest 6.9.2 {datetime('2015-12-23 12:00:00z','utc')} {2015-12-23 12:00:00} datetest 6.9.3 {datetime('2015-12-23 12:00:00-03:00','utc')} \ {2015-12-23 15:00:00} datetest 6.9.4 {datetime('2015-12-23 12:00:00','utc','utc','utc')} \ {2015-12-23 17:00:00} datetest 6.10 {datetime('2000-01-01 12:00:00','localtime')} \ {2000-01-01 07:00:00} datetest 6.11 {datetime('1969-01-01 12:00:00','localtime')} \ {1969-01-01 07:00:00} datetest 6.12 {datetime('2039-01-01 12:00:00','localtime')} \ {2039-01-01 07:00:00} datetest 6.13 {datetime('2000-07-01 12:00:00','localtime')} \ {2000-07-01 08:00:00} datetest 6.14 {datetime('1969-07-01 12:00:00','localtime')} \ {1969-07-01 07:00:00} datetest 6.15 {datetime('2039-07-01 12:00:00','localtime')} \ {2039-07-01 07:00:00} set sqlite_current_time \ [db eval {SELECT strftime('%s','2000-07-01 12:34:56')}] datetest 6.16 {datetime('now','localtime')} {2000-07-01 08:34:56} datetest 6.17 {datetime('now','localtimex')} NULL datetest 6.18 {datetime('now','localtim')} NULL set sqlite_current_time 0 } # These two are a bit of a scam. They are added to ensure that 100% of # the date.c file is covered by testing, even when the time-zone # is not -0400 (the condition for running of the block of tests above). # datetest 6.19 {datetime('2039-07-01 12:00:00','localtime',null)} NULL datetest 6.20 {datetime('2039-07-01 12:00:00','utc',null)} NULL # Date-time functions that contain NULL arguments return a NULL # result. # datetest 7.1 {datetime(null)} NULL datetest 7.2 {datetime('now',null)} NULL datetest 7.3 {datetime('now','localtime',null)} NULL |
︙ | ︙ | |||
535 536 537 538 539 540 541 | datetest 17.2 {datetime(2457828)} {2017-03-15 12:00:00} datetest 17.3 {datetime(2457828,'start of day')} {2017-03-15 00:00:00} datetest 17.4 {datetime(2457828,'start of month')} {2017-03-01 00:00:00} datetest 17.5 {datetime(2457828,'start of year')} {2017-01-01 00:00:00} datetest 17.6 {datetime(37,'start of year')} NULL datetest 17.7 {datetime(38,'start of year')} {-4712-01-01 00:00:00} | < < | < | 603 604 605 606 607 608 609 610 611 612 | datetest 17.2 {datetime(2457828)} {2017-03-15 12:00:00} datetest 17.3 {datetime(2457828,'start of day')} {2017-03-15 00:00:00} datetest 17.4 {datetime(2457828,'start of month')} {2017-03-01 00:00:00} datetest 17.5 {datetime(2457828,'start of year')} {2017-01-01 00:00:00} datetest 17.6 {datetime(37,'start of year')} NULL datetest 17.7 {datetime(38,'start of year')} {-4712-01-01 00:00:00} finish_test |
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 | 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 function in index expression or 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: t1}} 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 function in index expression or CHECK constraint}} 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 function in index expression or CHECK constraint}} 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' |
︙ | ︙ | |||
87 88 89 90 91 92 93 | 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'; | | | | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | 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 function in index expression or CHECK constraint}} 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 function in index expression or CHECK constraint}} do_execsql_test date2-500 { CREATE TABLE mods(x); INSERT INTO mods(x) VALUES ('+10 days'), ('-10 days'), ('+10 hours'), |
︙ | ︙ | |||
124 125 126 127 128 129 130 | 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'); | | | < | < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | 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 function in index expression or CHECK constraint}} do_catchsql_test date2-520 { INSERT INTO t5(y,m) VALUES('2017-07-20','utc'); } {1 {non-deterministic function in index expression or CHECK constraint}} finish_test |
Deleted test/date3.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/dbdata.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/dbfuzz001.test.
︙ | ︙ | |||
357 358 359 360 361 362 363 | | 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 }] } {} | < < | 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 | | 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 }] } {} 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}} 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 | ** ** 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_DESERIALIZE \ ** -DSQLITE_ENABLE_DBSTAT_VTAB dbfuzz2.c sqlite3.c -ldl ** ./a.out dir */ #include <assert.h> #include <stdio.h> #include <stdlib.h> #include <string.h> |
︙ | ︙ | |||
49 50 51 52 53 54 55 | #include "sqlite3.h" /* ** This is the is the SQL that is run against the database. */ static const char *azSql[] = { "PRAGMA integrity_check;", | | | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | #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_master;", "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;", |
︙ | ︙ | |||
206 207 208 209 210 211 212 | #endif if( bVdbeDebug ){ sqlite3_exec(db, "PRAGMA vdbe_debug=ON", 0, 0, 0); } if( mxCb>0 ){ sqlite3_progress_handler(db, 10, progress_handler, 0); } | < < < | 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | #endif if( bVdbeDebug ){ sqlite3_exec(db, "PRAGMA vdbe_debug=ON", 0, 0, 0); } if( mxCb>0 ){ sqlite3_progress_handler(db, 10, progress_handler, 0); } for(i=0; i<sizeof(azSql)/sizeof(azSql[0]); i++){ if( eVerbosity>=1 ){ printf("%s\n", azSql[i]); fflush(stdout); } zErr = 0; nCb = 0; |
︙ | ︙ | |||
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 | } 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; } | > > > > < < < < < < < < < < < < | 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 | } mxCb = strtol(argv[++i], 0, 0); continue; } if( strcmp(z,"memtrace")==0 ){ sqlite3MemTraceActivate(stdout); continue; } if( strcmp(z,"mem")==0 ){ bVdbeDebug = 1; 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; } #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; |
︙ | ︙ | |||
383 384 385 386 387 388 389 | int nIn; pIn = readFile(argv[i], &nIn); if( pIn ){ LLVMFuzzerTestOneInput((const uint8_t*)pIn, (size_t)nIn); free(pIn); } } | < < | 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 | int nIn; pIn = readFile(argv[i], &nIn); if( pIn ){ LLVMFuzzerTestOneInput((const uint8_t*)pIn, (size_t)nIn); free(pIn); } } 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); } } return 0; } #endif /*STANDALONE*/ |
Changes to test/dbpage.test.
︙ | ︙ | |||
98 99 100 101 102 103 104 | UPDATE sqlite_dbpage SET data=(SELECT x FROM saved_content) WHERE pgno=2 AND schema='aux1'; } {} do_catchsql_test 270 { PRAGMA aux1.integrity_check; } {0 ok} | < < < < < < | 98 99 100 101 102 103 104 105 | UPDATE sqlite_dbpage SET data=(SELECT x FROM saved_content) WHERE pgno=2 AND schema='aux1'; } {} do_catchsql_test 270 { PRAGMA aux1.integrity_check; } {0 ok} finish_test |
Deleted test/dbpagefault.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
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||stat3 { set STAT3 1 } else { set STAT3 0 } #--------------------------------------------------------------------------- # Run the dbstatus-2 and dbstatus-3 tests with several of different |
︙ | ︙ |
Deleted test/decimal.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/default.test.
︙ | ︙ | |||
124 125 126 127 128 129 130 | 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}} | < < < < < < < < < | 124 125 126 127 128 129 130 131 | 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 |
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 | SELECT x FROM t1; } {1 3 5 7} #------------------------------------------------------------------------- # reset_db do_execsql_test 3.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 * FROM t1; } {2 4} #------------------------------------------------------------------------- # DELETE statement that uses the OR optimization # reset_db do_execsql_test 3.1 { CREATE TABLE t1(i INTEGER PRIMARY KEY, a, b); |
︙ | ︙ |
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 | 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} # 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]] |
︙ | ︙ | |||
296 297 298 299 300 301 302 | # the get_file_format command. # ifcapable legacyformat { do_test descidx1-6.1 { db close forcedelete test.db test.db-journal sqlite3 db test.db | | | | | | | < > | 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 | # the get_file_format command. # ifcapable legacyformat { do_test descidx1-6.1 { db close forcedelete test.db test.db-journal sqlite3 db test.db execsql {PRAGMA legacy_file_format} } {1} } else { do_test descidx1-6.1 { db close forcedelete test.db test.db-journal sqlite3 db test.db execsql {PRAGMA legacy_file_format} } {0} } do_test descidx1-6.2 { execsql {PRAGMA legacy_file_format=YES} execsql {PRAGMA 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 execsql {PRAGMA legacy_file_format=NO} execsql {PRAGMA 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 { execsql { PRAGMA legacy_file_format=ON; 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 | # 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} # 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 | # do_not_use_codec ifcapable !bloblit { finish_test return } db eval {PRAGMA legacy_file_format=OFF} # 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 62 | 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"} { lappend program1 $opcode } } db eval "EXPLAIN $sql2" { if {$opcode != "Noop"} { 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 != "08" && $p5!="00"} { error "p5 = $p5" } if {$p5 == "08"} { lappend ret hash } else { lappend ret btree } } } set ret |
︙ | ︙ | |||
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} { | > | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | 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)" 23 1 "SELECT DISTINCT rowid 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} { |
︙ | ︙ | |||
262 263 264 265 266 267 268 | } {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} | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 264 265 266 267 268 269 270 271 272 | } {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} finish_test |
Changes to test/distinct2.test.
︙ | ︙ | |||
225 226 227 228 229 230 231 | 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} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
Changes to test/distinctagg.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 | # 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 | < | | 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 | # 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 { SELECT b, count(distinct c) FROM t1 GROUP BY b ORDER 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; |
︙ | ︙ | |||
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}} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
Changes to test/e_blobbytes.test.
︙ | ︙ | |||
10 11 12 13 14 15 16 | #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix e_blobbytes | < < < < < | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #*********************************************************************** # 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 ) |
︙ | ︙ |
Changes to test/e_blobclose.test.
︙ | ︙ | |||
10 11 12 13 14 15 16 | #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix e_blobclose | < < < < < | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #*********************************************************************** # 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); INSERT INTO x1 VALUES(-1000, $dots); |
︙ | ︙ |
Changes to test/e_blobopen.test.
︙ | ︙ | |||
10 11 12 13 14 15 16 | #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix e_blobopen | < < < < < | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #*********************************************************************** # 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); CREATE TEMP TABLE t1(a INTEGER PRIMARY KEY, b TEXT, c BLOB); |
︙ | ︙ |
Changes to test/e_blobwrite.test.
︙ | ︙ | |||
10 11 12 13 14 15 16 | #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix e_blobwrite | < < < < < | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #*********************************************************************** # 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. # set dots [string repeat . 40] |
︙ | ︙ |
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-15996-49369 This function returns 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. # 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 | do_test 1.$tn.11 { db changes } 0 do_changes_test 1.$tn.12 COMMIT 0 } #-------------------------------------------------------------------------- # 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 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 | 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 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 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 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 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; |
︙ | ︙ | |||
489 490 491 492 493 494 495 | # table/index/view of the same name does fail. 1.7.2.* tests that creating # a table with the same name as a table/index/view in a different database # is Ok. # do_createtable_tests 1.7.1 -error { %s } { 1 "CREATE TABLE t1(a, b)" {{table t1 already exists}} 2 "CREATE TABLE i1(a, b)" {{there is already an index named i1}} | | | | 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 | # table/index/view of the same name does fail. 1.7.2.* tests that creating # a table with the same name as a table/index/view in a different database # is Ok. # do_createtable_tests 1.7.1 -error { %s } { 1 "CREATE TABLE t1(a, b)" {{table t1 already exists}} 2 "CREATE TABLE i1(a, b)" {{there is already an index named i1}} 3 "CREATE TABLE v1(a, b)" {{table v1 already exists}} 4 "CREATE TABLE auxa.tbl1(a, b)" {{table tbl1 already exists}} 5 "CREATE TABLE auxa.idx1(a, b)" {{there is already an index named idx1}} 6 "CREATE TABLE auxa.view1(a, b)" {{table view1 already exists}} } do_createtable_tests 1.7.2 { 1 "CREATE TABLE auxa.t1(a, b)" {} 2 "CREATE TABLE auxa.i1(a, b)" {} 3 "CREATE TABLE auxa.v1(a, b)" {} 4 "CREATE TABLE tbl1(a, b)" {} 5 "CREATE TABLE idx1(a, b)" {} |
︙ | ︙ | |||
1268 1269 1270 1271 1272 1273 1274 | 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)" {} } | | | | < | 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 | 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-35113-43214 Unless the column is an INTEGER PRIMARY KEY # or the table is a WITHOUT ROWID 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 |
︙ | ︙ | |||
1301 1302 1303 1304 1305 1306 1307 | 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}} | < < < < < < < < | 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 { |
︙ | ︙ | |||
1398 1399 1400 1401 1402 1403 1404 | # 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" | | | | | 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 | # 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 TABLE t1 USING INDEX sqlite_autoindex_t1_1 (b=?)*/} 2 "EXPLAIN QUERY PLAN SELECT * FROM t2 ORDER BY b, c" {/*SCAN TABLE t2 USING INDEX sqlite_autoindex_t2_1*/} 3 "EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE b=10 AND c>10" {/*SEARCH TABLE 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 |
︙ | ︙ | |||
1438 1439 1440 1441 1442 1443 1444 | 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} { | | | | | | | | | | | | 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 | 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)" {x1} 1b "INSERT INTO t1 VALUES('one', -4.0)" {t1} 2a "INSERT INTO x2 VALUES('abc', 1)" {x2} 2b "INSERT INTO t2 VALUES('abc', 1)" {t2} 3a "INSERT INTO x2 VALUES(0, 'abc')" {x2} 3b "INSERT INTO t2 VALUES(0, 'abc')" {t2} 4a "UPDATE t1 SET b=-1 WHERE rowid=1" {t1} 4b "UPDATE x1 SET b=-1 WHERE rowid=1" {x1} 4a "UPDATE x2 SET a='' WHERE rowid=1" {x2} 4b "UPDATE t2 SET a='' WHERE rowid=1" {t2} } # 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)" {} |
︙ | ︙ | |||
1644 1645 1646 1647 1648 1649 1650 | 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 | | | 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 | 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: t4}} 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-50239-29811 Once removed, the trigger definition is no # longer present in the sqlite_master (or sqlite_temp_master) 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 { list_all_data } $databasedata 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 { list_all_data } $databasedata 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 { list_all_data } $databasedata 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 { list_all_data } $databasedata do_execsql_test 3.4.0 { SELECT * FROM aux.v2 } {{a aux} {b aux}} do_execsql_test 3.4.1 { DROP VIEW aux.v2 } {} do_catchsql_test 3.4.2 { SELECT * FROM aux.v2 } {1 {no such table: aux.v2}} do_test 3.4.3 { list_all_views } {aux.v3} do_test 3.4.4 { list_all_data } $databasedata do_execsql_test 3.5.0 { SELECT * FROM v3 } {{a aux} {b aux}} do_execsql_test 3.5.1 { DROP VIEW v3 } {} do_catchsql_test 3.5.2 { SELECT * FROM v3 } {1 {no such table: v3}} do_test 3.5.3 { list_all_views } {} do_test 3.5.4 { list_all_data } $databasedata # 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" 1 2 "DROP VIEW IF EXISTS main.xx" 1 3 "DROP VIEW IF EXISTS temp.v2" 1 } 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. # # 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 # # 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. # # 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 267 268 269 270 271 272 273 274 275 276 277 278 279 280 | do_execsql_test e_expr-5.$tn "SELECT $a || $b" [list "${as}${bs}"] } #------------------------------------------------------------------------- # Test the % operator. # # EVIDENCE-OF: R-04223-04352 The operator % outputs the integer value of # its left operand modulo its right operand. # 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} #------------------------------------------------------------------------- # Test that the results of all binary operators are either numeric or # NULL, except for the || operator, which may evaluate to either a text # value or NULL. # # EVIDENCE-OF: R-20665-17792 The result of any binary operator is either # a numeric value or NULL, except for the || concatenation operator # which always evaluates to either NULL or a text value. # set literals { 1 'abc' 2 'hexadecimal' 3 '' 4 123 5 -123 6 0 7 123.4 8 0.0 9 -123.4 10 X'ABCDEF' 11 X'' 12 X'0000' 13 NULL |
︙ | ︙ | |||
361 362 363 364 365 366 367 | 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. # | | | 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 | 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. # # 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 |
︙ | ︙ | |||
853 854 855 856 857 858 859 | do_test e_expr-13.1.$tn { set ::xcount 0 set a [execsql "SELECT $expr"] list $::xcount $a } [list $nEval $res] } | | | 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 | do_test e_expr-13.1.$tn { set ::xcount 0 set a [execsql "SELECT $expr"] list $::xcount $a } [list $nEval $res] } # 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 |
︙ | ︙ | |||
1007 1008 1009 1010 1011 1012 1013 | 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. # | | < | | < | < | | < | < | 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 | 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.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.4 { SELECT 'ABCxyz' LIKE 'ABC%' } 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.7 { SELECT 'ABCxyz' LIKE 'ABC%' } 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 |
︙ | ︙ | |||
1133 1134 1135 1136 1137 1138 1139 | 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. # | | | 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 | 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-15199-61389 There are two basic 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; |
︙ | ︙ | |||
1229 1230 1231 1232 1233 1234 1235 | } {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 { | | | | | | 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 | } {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 } {B} do_execsql_test e_expr-21.4.2 { SELECT CASE WHEN 0 THEN 'A' WHEN NULL THEN 'B' ELSE 'C' END } {C} # 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 |
︙ | ︙ | |||
1638 1639 1640 1641 1642 1643 1644 | CAST(-9223372036854775809.0 AS INT) } integer -9223372036854775808 do_expr_test e_expr-31.2.4 { CAST(9223372036854775809.0 AS INT) } integer 9223372036854775807 | | | < < < | < < < | < < < < < < < < < < < < < < < < < < < < < < < < < | 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 | 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-09295-61337 Casting a TEXT or BLOB value into NUMERIC # first does a forced conversion into REAL but then further converts the # result into INTEGER if and only if the conversion from REAL to INTEGER # is lossless and reversible. # 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 # 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 |
︙ | ︙ | |||
1726 1727 1728 1729 1730 1731 1732 | SELECT typeof(CAST(x AS NUMERIC)), CAST(x AS NUMERIC)||'' FROM t1; } [list \ integer 9000000000000000001 \ integer 9000000000000000001 \ integer 9000000000000000001 \ integer 9000000000000000001 \ integer 9000000000000000001 \ | | | | | 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 | SELECT typeof(CAST(x AS NUMERIC)), CAST(x AS NUMERIC)||'' FROM t1; } [list \ integer 9000000000000000001 \ integer 9000000000000000001 \ integer 9000000000000000001 \ integer 9000000000000000001 \ integer 9000000000000000001 \ integer 9000000000000000001 \ integer 9223372036854775807 \ integer 9223372036854775807 \ integer 9223372036854775807 \ real 9.22337203685478e+18 \ real 9.22337203685478e+18 \ integer 9223372036854775807 \ integer 9223372036854775807 \ 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 |
︙ | ︙ | |||
1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 | } { 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'); } {} | > > > | 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 | } { 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. # # EVIDENCE-OF: R-15900-52156 In other words, an implied "LIMIT 1" is # added to the subquery, overriding an explicitly coded LIMIT. # 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'); } {} |
︙ | ︙ | |||
1946 1947 1948 1949 1950 1951 1952 | 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 { | | | | | | | | | | | | | | | | | | | | | | 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 | 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; } {false} do_execsql_test e_expr-37.2 { SELECT CASE WHEN 0.0 THEN 'true' ELSE 'false' END; } {false} do_execsql_test e_expr-37.3 { SELECT CASE WHEN 0 THEN 'true' ELSE 'false' END; } {false} do_execsql_test e_expr-37.4 { SELECT CASE WHEN 'engligh' THEN 'true' ELSE 'false' END; } {false} do_execsql_test e_expr-37.5 { SELECT CASE WHEN '0' THEN 'true' ELSE 'false' END; } {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; } {true} do_execsql_test e_expr-37.7 { SELECT CASE WHEN 1.0 THEN 'true' ELSE 'false' END; } {true} do_execsql_test e_expr-37.8 { SELECT CASE WHEN 0.1 THEN 'true' ELSE 'false' END; } {true} do_execsql_test e_expr-37.9 { SELECT CASE WHEN -0.1 THEN 'true' ELSE 'false' END; } {true} do_execsql_test e_expr-37.10 { SELECT CASE WHEN '1english' THEN 'true' ELSE 'false' END; } {true} finish_test |
Changes to test/e_fkey.test.
︙ | ︙ | |||
44 45 46 47 48 49 50 | } ########################################################################### ### SECTION 2: Enabling Foreign Key Support ########################################################################### #------------------------------------------------------------------------- | | | | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | } ########################################################################### ### SECTION 2: Enabling Foreign Key Support ########################################################################### #------------------------------------------------------------------------- # EVIDENCE-OF: R-33710-56344 In order to use foreign key constraints in # SQLite, the library must be compiled with neither # SQLITE_OMIT_FOREIGN_KEY or SQLITE_OMIT_TRIGGER defined. # ifcapable trigger&&foreignkey { do_test e_fkey-1 { execsql { PRAGMA foreign_keys = ON; CREATE TABLE p(i PRIMARY KEY); CREATE TABLE c(j REFERENCES p ON UPDATE CASCADE); |
︙ | ︙ | |||
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 TABLE artist} {SCAN TABLE track} } do_detail_test e_fkey-25.3 { PRAGMA foreign_keys = ON; EXPLAIN QUERY PLAN DELETE FROM artist WHERE 1; } { {SCAN TABLE artist} {SCAN TABLE 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 TABLE artist} {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?)} {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?)} } do_detail_test e_fkey-27.4 { EXPLAIN QUERY PLAN DELETE FROM artist } { {SCAN TABLE artist} {SEARCH TABLE 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-43054-54832 The "SET DEFAULT" actions are similar to # "SET NULL", except that each of the child key columns is set to # contain the columns 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 | # 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) } [list catchsql $zAlter] " [lindex {{0 {}} {1 {Cannot add a REFERENCES column with non-NULL default value}}} $isError] } 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-63827-54774 The text of the child CREATE TABLE # statement or statements stored in the sqlite_master table are modified # to reflect the new parent table name. # 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); |
︙ | ︙ | |||
2568 2569 2570 2571 2572 2573 2574 | 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)} \ ] | < | 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 |
︙ | ︙ | |||
2769 2770 2771 2772 2773 2774 2775 | # 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. # | < | | 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 | # 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 execsql { CREATE TABLE t1(a, b) } 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)}} |
︙ | ︙ | |||
2831 2832 2833 2834 2835 2836 2837 | DROP TABLE p; SELECT * FROM c; } } {x} do_test e_fkey-61.3.3 { execsql { PRAGMA foreign_keys = ON } } {} | < | 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 |
︙ | ︙ |
Changes to test/e_select.test.
︙ | ︙ | |||
92 93 94 95 96 97 98 | SELECT count(*) FROM t1 %JOIN% t2 USING (a) } {3} do_join_test e_select-0.1.3 { SELECT count(*) FROM t1 %JOIN% t2 } {9} do_catchsql_test e_select-0.1.4 { SELECT count(*) FROM t1, t2 ON (t1.a=t2.a) USING (a) | | | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | SELECT count(*) FROM t1 %JOIN% t2 USING (a) } {3} do_join_test e_select-0.1.3 { SELECT count(*) FROM t1 %JOIN% t2 } {9} do_catchsql_test e_select-0.1.4 { SELECT count(*) FROM t1, t2 ON (t1.a=t2.a) USING (a) } {1 {cannot have both ON and USING clauses in the same join}} do_catchsql_test e_select-0.1.5 { SELECT count(*) FROM t1, t2 USING (a) ON (t1.a=t2.a) } {1 {near "ON": syntax error}} # -- syntax diagram select-core # # 0: SELECT ... |
︙ | ︙ | |||
614 615 616 617 618 619 620 | {aa cc cc bb DD dd} 4b { SELECT * FROM (SELECT a COLLATE nocase, b FROM t6) AS x %JOIN% t5 ON (x.a=t5.a) } {aa cc AA cc bb DD BB dd} } { do_join_test e_select-1.7.$tn $select $res } | < | | | | 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 | {aa cc cc bb DD dd} 4b { SELECT * FROM (SELECT a COLLATE nocase, b FROM t6) AS x %JOIN% t5 ON (x.a=t5.a) } {aa cc AA cc bb DD BB dd} } { do_join_test e_select-1.7.$tn $select $res } # EVIDENCE-OF: R-42531-52874 If the join-operator is a "LEFT JOIN" or # "LEFT OUTER JOIN", then after the ON or USING filtering clauses have # been applied, an extra row is added to the output for each row in the # original left-hand input dataset that corresponds to no rows at all in # the composite dataset (if any). # do_execsql_test e_select-1.8.0 { CREATE TABLE t7(a, b, c); CREATE TABLE t8(a, d, e); INSERT INTO t7 VALUES('x', 'ex', 24); INSERT INTO t7 VALUES('y', 'why', 25); |
︙ | ︙ | |||
1001 1002 1003 1004 1005 1006 1007 | 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 | 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-07284-35990 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. 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 45 | 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-65438-26258 This function returns 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. # # 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); |
︙ | ︙ | |||
90 91 92 93 94 95 96 | 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(). | < | | | | | | | | | | | | | | | | | | < | 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 | 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(). 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 | 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 | < | 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 |
︙ | ︙ | |||
354 355 356 357 358 359 360 | 2 {file:test.db?cache=shared} {not an error} 3 {file:test.db?cache=yes} {no such cache mode: yes} 4 {file:test.db?cache=} {no such cache mode: } " { do_test 10.$tn { open_uri_error $uri } $error } | < | 353 354 355 356 357 358 359 360 361 362 363 364 365 366 | 2 {file:test.db?cache=shared} {not an error} 3 {file:test.db?cache=yes} {no such cache mode: yes} 4 {file:test.db?cache=} {no such cache mode: } " { do_test 10.$tn { open_uri_error $uri } $error } # EVIDENCE-OF: R-23027-03515 Setting it to "shared" is equivalent to # setting the SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed # to sqlite3_open_v2(). # # EVIDENCE-OF: R-49793-28525 Setting the cache parameter to "private" is # equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. # |
︙ | ︙ | |||
427 428 429 430 431 432 433 | do_test 11.$tn { sqlite3_errmsg $DB } $RES($isshared) sqlite3_close $DB db close } sqlite3_enable_shared_cache $orig | < | 425 426 427 428 429 430 431 432 433 434 435 436 437 438 | do_test 11.$tn { sqlite3_errmsg $DB } $RES($isshared) sqlite3_close $DB db close } sqlite3_enable_shared_cache $orig # EVIDENCE-OF: R-63472-46769 Specifying an unknown parameter in the # query component of a URI is not an error. # do_filepath_test 12.1 { parse_uri file://localhost/test.db?an=unknown¶meter=is&ok= } {/test.db {an unknown parameter is ok {}}} |
︙ | ︙ |
Changes to test/e_vacuum.test.
︙ | ︙ | |||
186 187 188 189 190 191 192 | execsql { PRAGMA auto_vacuum = FULL } execsql VACUUM execsql { PRAGMA page_size ; PRAGMA auto_vacuum } } {2048 1} } } | | | | 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | execsql { PRAGMA auto_vacuum = FULL } execsql VACUUM execsql { PRAGMA page_size ; PRAGMA auto_vacuum } } {2048 1} } } # EVIDENCE-OF: R-55119-57913 By default, VACUUM only works only on the # main database. forcedelete test.db2 create_db { PRAGMA auto_vacuum = NONE } do_execsql_test e_vacuum-2.1.1 { ATTACH 'test.db2' AS aux; PRAGMA aux.page_size = 1024; CREATE TABLE aux.t3 AS SELECT * FROM t1; DELETE FROM t3; |
︙ | ︙ |
Changes to test/e_wal.test.
︙ | ︙ | |||
11 12 13 14 15 16 17 | # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix e_wal db close | < | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix e_wal db close testvfs oldvfs -iversion 1 # EVIDENCE-OF: R-58297-14483 WAL databases can be created, read, and # written even if shared memory is unavailable as long as the # locking_mode is set to EXCLUSIVE before the first attempted access. # |
︙ | ︙ |
Changes to test/enc.test.
︙ | ︙ | |||
165 166 167 168 169 170 171 | do_test enc-11.2 { set cp200 "\u00C8" execsql { SELECT count(*) FROM ab WHERE a = $::cp200; } } {2} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
Changes to test/enc2.test.
︙ | ︙ | |||
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} { | > | 9 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 testing the SQLite routines used for converting between the # various suported unicode encodings (UTF-8, UTF-16, UTF-16le and # UTF-16be). # # $Id: enc2.test,v 1.29 2007/10/09 08:29:32 danielk1977 Exp $ 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 | db close sqlite3 db test.db db eval { SELECT name FROM sqlite_master } } {t1 t2} | < < < < < < < < < < < < < | 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 |
Changes to test/enc3.test.
︙ | ︙ | |||
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 of the proper handling of conversions # to the native text representation. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {utf16} { do_test enc3-1.1 { execsql { | > | 9 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 testing of the proper handling of conversions # to the native text representation. # # $Id: enc3.test,v 1.8 2008/01/22 01:48:09 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {utf16} { do_test enc3-1.1 { execsql { |
︙ | ︙ |
Changes to test/eqp.test.
︙ | ︙ | |||
42 43 44 45 46 47 48 | do_eqp_test 1.2 { SELECT * FROM t2, t1 WHERE t1.a=1 OR t1.b=2; } { QUERY PLAN |--MULTI-INDEX OR | |--INDEX 1 | | | | | | | | | | | | < < | < < < < < < < | | < < < < < < < < < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 | 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 TABLE t1 USING INDEX i1 (a=?) | `--INDEX 2 | `--SEARCH TABLE t1 USING INDEX i2 (b=?) `--SCAN TABLE t2 } do_eqp_test 1.3 { SELECT * FROM t2 CROSS JOIN t1 WHERE t1.a=1 OR t1.b=2; } { QUERY PLAN |--SCAN TABLE t2 `--MULTI-INDEX OR |--INDEX 1 | `--SEARCH TABLE t1 USING INDEX i1 (a=?) `--INDEX 2 `--SEARCH TABLE t1 USING INDEX i2 (b=?) } do_eqp_test 1.3 { SELECT a FROM t1 ORDER BY a } { QUERY PLAN `--SCAN TABLE t1 USING COVERING INDEX i1 } do_eqp_test 1.4 { SELECT a FROM t1 ORDER BY +a } { QUERY PLAN |--SCAN TABLE 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 TABLE t1 USING COVERING INDEX i1 (a=?) } do_eqp_test 1.6 { SELECT DISTINCT count(*) FROM t3 GROUP BY a; } { QUERY PLAN |--SCAN TABLE t3 |--USE TEMP B-TREE FOR GROUP BY `--USE TEMP B-TREE FOR DISTINCT } do_eqp_test 1.7 { SELECT * FROM t3 JOIN (SELECT 1) } { QUERY PLAN |--MATERIALIZE xxxxxx | `--SCAN CONSTANT ROW |--SCAN SUBQUERY xxxxxx `--SCAN TABLE t3 } do_eqp_test 1.8 { SELECT * FROM t3 JOIN (SELECT 1 UNION SELECT 2) } { QUERY PLAN |--MATERIALIZE xxxxxx | `--COMPOUND QUERY | |--LEFT-MOST SUBQUERY | | `--SCAN CONSTANT ROW | `--UNION USING TEMP B-TREE | `--SCAN CONSTANT ROW |--SCAN SUBQUERY xxxxxx `--SCAN TABLE t3 } do_eqp_test 1.9 { SELECT * FROM t3 JOIN (SELECT 1 EXCEPT SELECT a FROM t3 LIMIT 17) } { QUERY PLAN |--MATERIALIZE xxxxxx | `--COMPOUND QUERY | |--LEFT-MOST SUBQUERY | | `--SCAN CONSTANT ROW | `--EXCEPT USING TEMP B-TREE | `--SCAN TABLE t3 |--SCAN SUBQUERY xxxxxx `--SCAN TABLE t3 } do_eqp_test 1.10 { SELECT * FROM t3 JOIN (SELECT 1 INTERSECT SELECT a FROM t3 LIMIT 17) } { QUERY PLAN |--MATERIALIZE xxxxxx | `--COMPOUND QUERY | |--LEFT-MOST SUBQUERY | | `--SCAN CONSTANT ROW | `--INTERSECT USING TEMP B-TREE | `--SCAN TABLE t3 |--SCAN SUBQUERY xxxxxx `--SCAN TABLE t3 } do_eqp_test 1.11 { SELECT * FROM t3 JOIN (SELECT 1 UNION ALL SELECT a FROM t3 LIMIT 17) } { QUERY PLAN |--MATERIALIZE xxxxxx | `--COMPOUND QUERY | |--LEFT-MOST SUBQUERY | | `--SCAN CONSTANT ROW | `--UNION ALL | `--SCAN TABLE t3 |--SCAN SUBQUERY xxxxxx `--SCAN TABLE 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 TABLE 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 TABLE 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 TABLE t1 `--USE TEMP B-TREE FOR DISTINCT } det 2.2.4 "SELECT DISTINCT * FROM t1, t2" { QUERY PLAN |--SCAN TABLE t1 |--SCAN TABLE t2 `--USE TEMP B-TREE FOR DISTINCT } det 2.2.5 "SELECT DISTINCT * FROM t1, t2 ORDER BY t1.x" { QUERY PLAN |--SCAN TABLE t1 |--SCAN TABLE 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 TABLE t2 USING COVERING INDEX t2i1 `--SCAN TABLE t1 } det 2.3.1 "SELECT max(x) FROM t2" { QUERY PLAN `--SEARCH TABLE t2 USING COVERING INDEX t2i1 } det 2.3.2 "SELECT min(x) FROM t2" { QUERY PLAN `--SEARCH TABLE t2 USING COVERING INDEX t2i1 } det 2.3.3 "SELECT min(x), max(x) FROM t2" { QUERY PLAN `--SCAN TABLE t2 USING COVERING INDEX t2i1 } det 2.4.1 "SELECT * FROM t1 WHERE rowid=?" { QUERY PLAN `--SEARCH TABLE 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 TABLE t1 `--SCALAR SUBQUERY xxxxxx `--SCAN TABLE t1 AS sub } do_eqp_test 3.1.2 { SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub); } { QUERY PLAN |--SCAN TABLE t1 `--SCALAR SUBQUERY xxxxxx `--SCAN TABLE t1 AS sub } do_eqp_test 3.1.3 { SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub ORDER BY y); } { QUERY PLAN |--SCAN TABLE t1 `--SCALAR SUBQUERY xxxxxx |--SCAN TABLE t1 AS 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 TABLE t1 `--SCALAR SUBQUERY xxxxxx `--SCAN TABLE 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 xxxxxx | |--SCAN TABLE 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 xxxxxx | |--SCAN TABLE t1 | `--USE TEMP B-TREE FOR ORDER BY |--MATERIALIZE xxxxxx | `--SCAN TABLE t2 USING INDEX t2i1 |--SCAN SUBQUERY xxxxxx AS x1 |--SCAN SUBQUERY xxxxxx AS 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 TABLE t1 `--LIST SUBQUERY xxxxxx `--SCAN TABLE t2 } det 3.3.2 { SELECT * FROM t1 WHERE y IN (SELECT y FROM t2 WHERE t1.x!=t2.x) } { QUERY PLAN |--SCAN TABLE t1 `--CORRELATED LIST SUBQUERY xxxxxx `--SCAN TABLE t2 } det 3.3.3 { SELECT * FROM t1 WHERE EXISTS (SELECT y FROM t2 WHERE t1.x!=t2.x) } { QUERY PLAN |--SCAN TABLE t1 `--CORRELATED SCALAR SUBQUERY xxxxxx `--SCAN TABLE 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 TABLE t1 `--UNION ALL `--SCAN TABLE 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 TABLE t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT |--SCAN TABLE 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 TABLE t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT |--SCAN TABLE 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 TABLE t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT |--SCAN TABLE 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 TABLE t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT |--SCAN TABLE 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 TABLE t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT `--SCAN TABLE 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 TABLE t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT |--SCAN TABLE 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 TABLE t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT |--SCAN TABLE 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 TABLE t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT |--SCAN TABLE 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 TABLE t1 `--UNION USING TEMP B-TREE `--SCAN TABLE 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 TABLE t1 |--UNION USING TEMP B-TREE | `--SCAN TABLE t2 USING COVERING INDEX t2i1 `--UNION USING TEMP B-TREE `--SCAN TABLE 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 TABLE t1 | | `--USE TEMP B-TREE FOR ORDER BY | `--RIGHT | `--SCAN TABLE t2 USING COVERING INDEX t2i1 `--RIGHT |--SCAN TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE t1 USING COVERING INDEX i2 (a=? AND b>?) # 0|1|1|SCAN TABLE 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 TABLE t1 USING COVERING INDEX i2 (a=? AND b>?)} 0 1 1 {SCAN TABLE 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 TABLE t1 USING COVERING INDEX i2 (a=? AND b>?) # 0|1|0|SCAN TABLE t2 # det 5.5 "SELECT t1.a, t2.c FROM t2, t1 WHERE t1.a=1 AND t1.b>2" { 0 0 1 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?)} 0 1 0 {SCAN TABLE 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 TABLE t1 USING COVERING INDEX i2 (a=?) # 0|0|0|SEARCH TABLE 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 TABLE t1 USING COVERING INDEX i2 (a=?)} 0 0 0 {SEARCH TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE t2 # 0|0|0|EXECUTE SCALAR SUBQUERY 1 # 1|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) # 0|0|0|EXECUTE CORRELATED SCALAR SUBQUERY 2 # 2|0|0|SEARCH TABLE 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 TABLE t2 USING COVERING INDEX i4} 0 0 0 {EXECUTE SCALAR SUBQUERY 1} 1 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=?)} 0 0 0 {EXECUTE CORRELATED SCALAR SUBQUERY 2} 2 0 0 {SEARCH TABLE 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 TABLE 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 TABLE 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 TABLE t2 USING INDEX i4 (c=?) # 0|1|1|SCAN TABLE t1 # det 5.11 "SELECT a, b FROM (SELECT * FROM t2 WHERE c=1), t1" { 0 0 0 {SEARCH TABLE t2 USING INDEX i4 (c=?)} 0 1 1 {SCAN TABLE 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 TABLE t1 # 2|0|0|SCAN TABLE 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 TABLE t1 USING COVERING INDEX i2} 2 0 0 {SCAN TABLE 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 TABLE t1 USING COVERING INDEX i2 # 2|0|0|SCAN TABLE 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 TABLE t1 USING COVERING INDEX i1} 2 0 0 {SCAN TABLE 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 |
︙ | ︙ | |||
663 664 665 666 667 668 669 | 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 { | | | | | | | | | | | | | | | 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 | 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 TABLE t1 USING COVERING INDEX i2 2 0 0 SCAN TABLE 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 TABLE t1 } det 7.2 "SELECT count(*) FROM t2" { QUERY PLAN `--SCAN TABLE 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 TABLE t1 } det 7.5 "SELECT count(*) FROM t2" { QUERY PLAN `--SCAN TABLE 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 TABLE t2 } det 8.1.2 "SELECT * FROM t2 WHERE rowid=?" { QUERY PLAN `--SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?) } det 8.1.3 "SELECT count(*) FROM t2" { QUERY PLAN `--SCAN TABLE t2 } det 8.2.1 "SELECT * FROM t1" { QUERY PLAN `--SCAN TABLE t1 } det 8.2.2 "SELECT * FROM t1 WHERE b=?" { QUERY PLAN `--SEARCH TABLE t1 USING PRIMARY KEY (b=?) } det 8.2.3 "SELECT * FROM t1 WHERE b=? AND c=?" { QUERY PLAN `--SEARCH TABLE t1 USING PRIMARY KEY (b=? AND c=?) } det 8.2.4 "SELECT count(*) FROM t1" { QUERY PLAN `--SCAN TABLE 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 { |
︙ | ︙ | |||
830 831 832 833 834 835 836 | 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 | | | | | | | | 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 | 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 xxxxxx | |--SCAN TABLE forumpost AS x USING INDEX forumthread | |--USING ROWID SEARCH ON TABLE private FOR IN-OPERATOR | |--CORRELATED SCALAR SUBQUERY xxxxxx | | |--SEARCH TABLE forumpost USING COVERING INDEX forumthread (froot=?) | | `--USING ROWID SEARCH ON TABLE private FOR IN-OPERATOR | `--USE TEMP B-TREE FOR ORDER BY |--SCAN SUBQUERY xxxxxx |--SEARCH TABLE blob USING INTEGER PRIMARY KEY (rowid=?) |--SEARCH TABLE event USING INTEGER PRIMARY KEY (rowid=?) `--USE TEMP B-TREE FOR ORDER BY } finish_test |
Changes to test/eval.test.
︙ | ︙ | |||
77 78 79 80 81 82 83 | execsql { INSERT INTO t2 SELECT x, x+1 FROM t1 WHERE x<5; SELECT x, test_eval('UPDATE t2 SET y=y+100 WHERE x='||x), y FROM t2; } } {1 {} 102 2 {} 103 3 {} 104 4 {} 105} do_test eval-4.1 { | | | 77 78 79 80 81 82 83 84 85 86 87 | execsql { INSERT INTO t2 SELECT x, x+1 FROM t1 WHERE x<5; SELECT x, test_eval('UPDATE t2 SET y=y+100 WHERE x='||x), y FROM t2; } } {1 {} 102 2 {} 103 3 {} 104 4 {} 105} do_test eval-4.1 { execsql { SELECT test_eval('SELECT "abcdefghij"') } } {abcdefghij} finish_test |
Changes to test/exclusive.test.
︙ | ︙ | |||
507 508 509 510 511 512 513 | } {} do_execsql_test exclusive-6.5 { PRAGMA locking_mode = EXCLUSIVE; SELECT * FROM sqlite_master; } {exclusive} | < < < < < < < < < < < < < < < < < < < < < < < < | 507 508 509 510 511 512 513 514 515 516 | } {} do_execsql_test exclusive-6.5 { PRAGMA locking_mode = EXCLUSIVE; SELECT * FROM sqlite_master; } {exclusive} } ;# atomic_batch_write==0 finish_test |
Changes to test/expr.test.
︙ | ︙ | |||
177 178 179 180 181 182 183 | test_expr expr-1.109 {i1=0} {1/0} {{}} if {[working_64bit_int]} { test_expr expr-1.110 {i1=0} {-9223372036854775807/-1} 9223372036854775807 } test_expr expr-1.111 {i1=NULL, i2=8} {i1 IS i2} 0 | < < < < < < < < < < < < < < < < < < < < < < < < | 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 | test_expr expr-1.109 {i1=0} {1/0} {{}} if {[working_64bit_int]} { test_expr expr-1.110 {i1=0} {-9223372036854775807/-1} 9223372036854775807 } test_expr expr-1.111 {i1=NULL, i2=8} {i1 IS i2} 0 test_expr expr-1.112 {i1=NULL, i2=NULL} {i1 IS i2} 1 test_expr expr-1.113 {i1=6, i2=NULL} {i1 IS i2} 0 test_expr expr-1.114 {i1=6, i2=6} {i1 IS i2} 1 test_expr expr-1.115 {i1=NULL, i2=8} \ {CASE WHEN i1 IS i2 THEN 'yes' ELSE 'no' END} no test_expr expr-1.116 {i1=NULL, i2=NULL} \ {CASE WHEN i1 IS i2 THEN 'yes' ELSE 'no' END} yes test_expr expr-1.117 {i1=6, i2=NULL} \ {CASE WHEN i1 IS i2 THEN 'yes' ELSE 'no' END} no test_expr expr-1.118 {i1=8, i2=8} \ {CASE WHEN i1 IS i2 THEN 'yes' ELSE 'no' END} yes test_expr expr-1.119 {i1=NULL, i2=8} {i1 IS NOT i2} 1 test_expr expr-1.120 {i1=NULL, i2=NULL} {i1 IS NOT i2} 0 test_expr expr-1.121 {i1=6, i2=NULL} {i1 IS NOT i2} 1 test_expr expr-1.122 {i1=6, i2=6} {i1 IS NOT i2} 0 test_expr expr-1.123 {i1=NULL, i2=8} \ {CASE WHEN i1 IS NOT i2 THEN 'yes' ELSE 'no' END} yes test_expr expr-1.124 {i1=NULL, i2=NULL} \ {CASE WHEN i1 IS NOT i2 THEN 'yes' ELSE 'no' END} no test_expr expr-1.125 {i1=6, i2=NULL} \ {CASE WHEN i1 IS NOT i2 THEN 'yes' ELSE 'no' END} yes test_expr expr-1.126 {i1=8, i2=8} \ {CASE WHEN i1 IS NOT i2 THEN 'yes' ELSE 'no' END} no do_catchsql_test expr-1.127 { SELECT 1 IS #1; } {1 {near "#1": syntax error}} ifcapable floatingpoint {if {[working_64bit_int]} { test_expr expr-1.200\ |
︙ | ︙ | |||
990 991 992 993 994 995 996 | } {9.22337203685478e+18} do_realnum_test expr-13.7 { execsql { SELECT '9223372036854775807.0'+0 } } {9.22337203685478e+18} | < | 966 967 968 969 970 971 972 973 974 975 976 977 978 979 | } {9.22337203685478e+18} do_realnum_test expr-13.7 { execsql { SELECT '9223372036854775807.0'+0 } } {9.22337203685478e+18} do_execsql_test expr-13.8 { SELECT "" <= ''; } {1} do_execsql_test expr-13.9 { SELECT '' <= ""; } {1} |
︙ | ︙ | |||
1057 1058 1059 1060 1061 1062 1063 | do_execsql_test expr-15.$tn.6 { SELECT sum(CASE WHEN x THEN 0 ELSE 1 END) FROM t1 WHERE x } {0} } | < < < < < < < < < < < < < < < < < < < < | 1032 1033 1034 1035 1036 1037 1038 1039 | do_execsql_test expr-15.$tn.6 { SELECT sum(CASE WHEN x THEN 0 ELSE 1 END) FROM t1 WHERE x } {0} } finish_test |
Deleted test/expr2.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/exprfault.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/external_reader.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/filter1.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/filter2.tcl.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/filter2.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/filterfault.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/fkey1.test.
︙ | ︙ | |||
218 219 220 221 222 223 224 | } {1 {foreign key mismatch - "c1" referencing "p1"}} do_execsql_test 6.2 { CREATE UNIQUE INDEX p1x2 ON p1(x); INSERT INTO c1 VALUES(1); } {} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 218 219 220 221 222 223 224 225 226 | } {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 |
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: ef}} 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: ef}} 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 | 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); | < | 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 { |
︙ | ︙ | |||
984 985 986 987 988 989 990 | # 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 )} } | | | | 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 | # 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 1 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 0 # 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); |
︙ | ︙ | |||
1043 1044 1045 1046 1047 1048 1049 | # 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); | < | 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 { |
︙ | ︙ | |||
1068 1069 1070 1071 1072 1073 1074 | 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)}} | | | | 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 | 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 1 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 0 # 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); |
︙ | ︙ | |||
1128 1129 1130 1131 1132 1133 1134 | 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); | < | 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 { |
︙ | ︙ | |||
1153 1154 1155 1156 1157 1158 1159 | 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)}} | | | | 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 | 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 1 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 0 # 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-23918-17301 The foreign_key_check pragma checks the # database, or the table called "table-name", for foreign key # constraints that are violated and returns one row of output for each # violation. set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix fkey5 ifcapable {!foreignkey} { finish_test |
︙ | ︙ | |||
426 427 428 429 430 431 432 | 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"}} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 426 427 428 429 430 431 432 433 | 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 |
Changes to test/fkey7.test.
︙ | ︙ | |||
78 79 80 81 82 83 84 | INSERT INTO c4 VALUES(1), (2), (3); ANALYZE; INSERT INTO p4(id) VALUES(4); } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 78 79 80 81 82 83 84 85 | INSERT INTO c4 VALUES(1), (2), (3); ANALYZE; INSERT INTO p4(id) VALUES(4); } } finish_test |
Changes to test/fkey8.test.
︙ | ︙ | |||
192 193 194 195 196 197 198 199 | } 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); } | < < < < < < < < < < < < < < < < < < < | < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < | 192 193 194 195 196 197 198 199 200 201 | } 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); } 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 {"0x$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 | # 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} # 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/fts3aj.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 | # 2007 February 6 # # The author disclaims copyright to this source code. # #************************************************************************* # This file implements regression tests for SQLite library. This # tests creating fts3 tables in an attached database. # set testdir [file dirname $argv0] source $testdir/tester.tcl # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts3 { finish_test return } # Clean up anything left over from a previous pass. forcedelete test2.db forcedelete test2.db-journal sqlite3 db2 test2.db db eval { CREATE VIRTUAL TABLE t3 USING fts3(content); | > > | | | | | 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 | # 2007 February 6 # # The author disclaims copyright to this source code. # #************************************************************************* # This file implements regression tests for SQLite library. This # tests creating fts3 tables in an attached database. # # $Id: fts3aj.test,v 1.1 2007/08/20 17:38:42 shess Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts3 { finish_test return } # Clean up anything left over from a previous pass. forcedelete test2.db forcedelete test2.db-journal sqlite3 db2 test2.db db eval { CREATE VIRTUAL TABLE t3 USING fts3(content); INSERT INTO t3 (rowid, content) VALUES(1, "hello world"); } db2 eval { CREATE VIRTUAL TABLE t1 USING fts3(content); INSERT INTO t1 (rowid, content) VALUES(1, "hello world"); INSERT INTO t1 (rowid, content) VALUES(2, "hello there"); INSERT INTO t1 (rowid, content) VALUES(3, "cruel world"); } # This has always worked because the t1_* tables used by fts3 will be # the defaults. do_test fts3aj-1.1 { execsql { ATTACH DATABASE 'test2.db' AS two; |
︙ | ︙ | |||
50 51 52 53 54 55 56 | # 'two'. It appears to work fine because the tables end up being the # defaults, but obviously is badly broken if you hope to use things # other than in the exact same ATTACH setup. do_test fts3aj-1.2 { execsql { ATTACH DATABASE 'test2.db' AS two; CREATE VIRTUAL TABLE two.t2 USING fts3(content); | | | | | | | 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 | # 'two'. It appears to work fine because the tables end up being the # defaults, but obviously is badly broken if you hope to use things # other than in the exact same ATTACH setup. do_test fts3aj-1.2 { execsql { ATTACH DATABASE 'test2.db' AS two; CREATE VIRTUAL TABLE two.t2 USING fts3(content); INSERT INTO t2 (rowid, content) VALUES(1, "hello world"); INSERT INTO t2 (rowid, content) VALUES(2, "hello there"); INSERT INTO t2 (rowid, content) VALUES(3, "cruel world"); SELECT rowid FROM t2 WHERE t2 MATCH 'hello'; DETACH DATABASE two; } } {1 2} catch {db eval {DETACH DATABASE two}} # In older code, this broke because the fts3 code attempted to create # t3_* tables in database 'main', but they already existed. Normally # this wouldn't happen without t3 itself existing, in which case the # fts3 code would never be called in the first place. do_test fts3aj-1.3 { execsql { ATTACH DATABASE 'test2.db' AS two; CREATE VIRTUAL TABLE two.t3 USING fts3(content); INSERT INTO two.t3 (rowid, content) VALUES(2, "hello there"); INSERT INTO two.t3 (rowid, content) VALUES(3, "cruel world"); SELECT rowid FROM two.t3 WHERE t3 MATCH 'hello'; DETACH DATABASE two; } db2 } {2} catch {db eval {DETACH DATABASE two}} catch {db2 close} forcedelete test2.db finish_test |
Changes to test/fts3ak.test.
︙ | ︙ | |||
17 18 19 20 21 22 23 | ifcapable !fts3 { finish_test return } db eval { CREATE VIRTUAL TABLE t1 USING fts3(content); | | | | | | | | | | | | | | | 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 | ifcapable !fts3 { finish_test return } db eval { CREATE VIRTUAL TABLE t1 USING fts3(content); INSERT INTO t1 (rowid, content) VALUES(1, "hello world"); INSERT INTO t1 (rowid, content) VALUES(2, "hello there"); INSERT INTO t1 (rowid, content) VALUES(3, "cruel world"); } # Test that possibly-buffered inserts went through after commit. do_test fts3ak-1.1 { execsql { BEGIN TRANSACTION; INSERT INTO t1 (rowid, content) VALUES(4, "false world"); INSERT INTO t1 (rowid, content) VALUES(5, "false door"); COMMIT TRANSACTION; SELECT rowid FROM t1 WHERE t1 MATCH 'world'; } } {1 3 4} # Test that buffered inserts are seen by selects in the same # transaction. do_test fts3ak-1.2 { execsql { BEGIN TRANSACTION; INSERT INTO t1 (rowid, content) VALUES(6, "another world"); INSERT INTO t1 (rowid, content) VALUES(7, "another test"); SELECT rowid FROM t1 WHERE t1 MATCH 'world'; COMMIT TRANSACTION; } } {1 3 4 6} # Test that buffered inserts are seen within a transaction. This is # really the same test as 1.2. do_test fts3ak-1.3 { execsql { BEGIN TRANSACTION; INSERT INTO t1 (rowid, content) VALUES(8, "second world"); INSERT INTO t1 (rowid, content) VALUES(9, "second sight"); SELECT rowid FROM t1 WHERE t1 MATCH 'world'; ROLLBACK TRANSACTION; } } {1 3 4 6 8} # Double-check that the previous result doesn't persist past the # rollback! do_test fts3ak-1.4 { execsql { SELECT rowid FROM t1 WHERE t1 MATCH 'world'; } } {1 3 4 6} # Test it all together. do_test fts3ak-1.5 { execsql { BEGIN TRANSACTION; INSERT INTO t1 (rowid, content) VALUES(10, "second world"); INSERT INTO t1 (rowid, content) VALUES(11, "second sight"); ROLLBACK TRANSACTION; SELECT rowid FROM t1 WHERE t1 MATCH 'world'; } } {1 3 4 6} # Test that the obvious case works. do_test fts3ak-1.6 { execsql { BEGIN; INSERT INTO t1 (rowid, content) VALUES(12, "third world"); COMMIT; SELECT rowid FROM t1 WHERE t1 MATCH 'third'; } } {12} # This is exactly the same as the previous test, except that older # code loses the INSERT due to an SQLITE_SCHEMA error. do_test fts3ak-1.7 { execsql { BEGIN; INSERT INTO t1 (rowid, content) VALUES(13, "third dimension"); CREATE TABLE x (c); COMMIT; SELECT rowid FROM t1 WHERE t1 MATCH 'dimension'; } } {13} finish_test |
Changes to test/fts3atoken.test.
︙ | ︙ | |||
125 126 127 128 129 130 131 | typeof(fts3_tokenizer($blah2name)), typeof(fts3_tokenizer('blah2')), typeof(fts3_tokenizer($simplename)), typeof(fts3_tokenizer('simple')); } } {1 blob blob blob blob} | < < < < < < < < < < < < < < < < < < < < < < < | 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | typeof(fts3_tokenizer($blah2name)), typeof(fts3_tokenizer('blah2')), typeof(fts3_tokenizer($simplename)), typeof(fts3_tokenizer('simple')); } } {1 blob blob blob blob} #-------------------------------------------------------------------------- # 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'); |
︙ | ︙ |
Changes to test/fts3auto.test.
︙ | ︙ | |||
566 567 568 569 570 571 572 | 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*} | < < < < < < < | 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} { |
︙ | ︙ |
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 TABLE terms VIRTUAL TABLE INDEX 1:*/} do_execsql_test 2.1.1.2 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term='braid' } {/*SCAN TABLE 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 TABLE terms VIRTUAL TABLE INDEX 2:*/} do_execsql_test 2.2.1.2 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term>'brain' } {/*SCAN TABLE terms VIRTUAL TABLE INDEX 0:*/} do_execsql_test 2.2.1.3 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term<'brain' } {/*SCAN TABLE terms VIRTUAL TABLE INDEX 4:*/} do_execsql_test 2.2.1.4 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term<'brain' } {/*SCAN TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE x2 `--SCAN TABLE 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 TABLE x2 `--SCAN TABLE 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 TABLE terms VIRTUAL TABLE INDEX 0: `--SEARCH TABLE 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 TABLE terms VIRTUAL TABLE INDEX 0: `--SEARCH TABLE 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/fts3corrupt.test.
︙ | ︙ | |||
161 162 163 164 165 166 167 | 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 | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
Changes to test/fts3corrupt2.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 | 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 | < | 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" |
︙ | ︙ | |||
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 | > | 98 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.
︙ | ︙ | |||
22 23 24 25 26 27 28 | # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts3 { finish_test return } sqlite3_fts3_may_be_corrupt 1 | < < | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | # 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; INSERT INTO ft VALUES('aback'); INSERT INTO ft VALUES('abaft'); INSERT INTO ft VALUES('abandon'); |
︙ | ︙ | |||
1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 | | 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 | > | 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 | | 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 {}} # in 3.31.0: {0 {0 0}} #------------------------------------------------------------------------- reset_db do_test 14.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 28672 pagesize 4096 filename crash-f7b636a855e1d2.db |
︙ | ︙ | |||
2144 2145 2146 2147 2148 2149 2150 | | 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 { | | | 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 | | 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=on; 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}} |
︙ | ︙ | |||
2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 | | 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 | > | 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 | | 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 {}} # in 3.31.0: {0 0} #------------------------------------------------------------------------- reset_db do_test 19.0 { sqlite3 db {} db deserialize [decode_hexdb { | size 28672 pagesize 4096 filename crash-526ea445f41c02.db |
︙ | ︙ | |||
3047 3048 3049 3050 3051 3052 3053 | | 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 { | | | 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 | | 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=ON; 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 {} |
︙ | ︙ | |||
3249 3250 3251 3252 3253 3254 3255 | | 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 { | | | 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 | | 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=on; 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'); |
︙ | ︙ | |||
3473 3474 3475 3476 3477 3478 3479 | | 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 { | | | 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 | | 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=ON; SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'R*'; } {1 {database disk image is malformed}} #------------------------------------------------------------------------- reset_db do_test 22.0 { sqlite3 db {} |
︙ | ︙ | |||
3694 3695 3696 3697 3698 3699 3700 | | 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 { | | | 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 | | 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=on; 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 { |
︙ | ︙ | |||
3914 3915 3916 3917 3918 3919 3920 | | 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 { | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 | | 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=on; SELECT 'FyzLy'FROM t1 WHERE t1 MATCH 'j'; } {1 {database disk image is malformed}} finish_test |
Deleted test/fts3corrupt5.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/fts3corrupt6.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*' } {SQL logic error} # 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' } {SQL logic error} #-------------------------------------------------------------------------- # 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/fts3defer2.test.
︙ | ︙ | |||
157 158 159 160 161 162 163 | sqlite3_db_config db DEFENSIVE 0 execsql $sql do_execsql_test 2.4.$tn { SELECT docid, mit(matchinfo(t3, 'pcxnal')) FROM t3 WHERE t3 MATCH '"a b c"'; } {1 {1 1 1 4 4 11 912 6} 3 {1 1 1 4 4 11 912 6}} } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 157 158 159 160 161 162 163 164 165 | sqlite3_db_config db DEFENSIVE 0 execsql $sql do_execsql_test 2.4.$tn { SELECT docid, mit(matchinfo(t3, 'pcxnal')) FROM t3 WHERE t3 MATCH '"a b c"'; } {1 {1 1 1 4 4 11 912 6} 3 {1 1 1 4 4 11 912 6}} } finish_test |
Deleted test/fts3dropmod.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/fts3expr4.test.
︙ | ︙ | |||
46 47 48 49 50 51 52 | do_icu_expr_test 1.5 {(x OR y)} {OR {PHRASE 3 0 x} {PHRASE 3 0 y}} do_icu_expr_test 1.6 { "(x OR y)" } {PHRASE 3 0 ( x or y )} # In "col:word", if "col" is not the name of a column, the entire thing # is passed to the tokenizer. # do_icu_expr_test 1.7 {a:word} {PHRASE 0 0 word} | | < < < < < < < < < | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | do_icu_expr_test 1.5 {(x OR y)} {OR {PHRASE 3 0 x} {PHRASE 3 0 y}} do_icu_expr_test 1.6 { "(x OR y)" } {PHRASE 3 0 ( x or y )} # In "col:word", if "col" is not the name of a column, the entire thing # is passed to the tokenizer. # do_icu_expr_test 1.7 {a:word} {PHRASE 0 0 word} do_icu_expr_test 1.8 {d:word} {PHRASE 3 0 d:word} set sqlite_fts3_enable_parentheses 0 do_icu_expr_test 2.1 { f (e NEAR/2 a) } {AND {AND {AND {PHRASE 3 0 f} {PHRASE 3 0 (}} {NEAR/2 {PHRASE 3 0 e} {PHRASE 3 0 a}}} {PHRASE 3 0 )}} |
︙ | ︙ |
Changes to test/fts3expr5.test.
︙ | ︙ | |||
60 61 62 63 64 65 66 | 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 | > | 60 61 62 63 64 65 66 67 | 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 |
Deleted test/fts3f.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/fts3fault.test.
︙ | ︙ | |||
14 15 16 17 18 19 20 | source $testdir/tester.tcl set ::testprefix fts3fault # If SQLITE_ENABLE_FTS3 is not defined, omit this file. ifcapable !fts3 { finish_test ; return } | < < < < | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | source $testdir/tester.tcl set ::testprefix fts3fault # If SQLITE_ENABLE_FTS3 is not defined, omit this file. ifcapable !fts3 { finish_test ; return } # Test error handling in the sqlite3Fts3Init() function. This is the # function that registers the FTS3 module and various support functions # with SQLite. # do_faultsim_test 1 -body { sqlite3 db test.db expr 0 |
︙ | ︙ | |||
49 50 51 52 53 54 55 | BEGIN; INSERT INTO t1 VALUES('registers the FTS3 module'); INSERT INTO t1 VALUES('various support functions'); } } -body { execsql { ALTER TABLE t1 RENAME TO t2 } } -test { | | | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | BEGIN; INSERT INTO t1 VALUES('registers the FTS3 module'); INSERT INTO t1 VALUES('various support functions'); } } -body { execsql { ALTER TABLE t1 RENAME TO t2 } } -test { faultsim_test_result {0 {}} } # Test error handling in the special case where a single prefix query # matches terms that reside on a large range of leaf nodes. # do_test fts3fault-3.0 { sqlite3 db test.db |
︙ | ︙ | |||
194 195 196 197 198 199 200 | do_faultsim_test 8.2 -faults oom-t* -prep { faultsim_restore_and_reopen db func mit mit } -body { execsql { SELECT mit(matchinfo(t8, 's')) FROM t8 WHERE t8 MATCH 'a b c' } } -test { | | | 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | do_faultsim_test 8.2 -faults oom-t* -prep { faultsim_restore_and_reopen db func mit mit } -body { execsql { SELECT mit(matchinfo(t8, 's')) FROM t8 WHERE t8 MATCH 'a b c' } } -test { faultsim_test_result {0 3} } do_faultsim_test 8.3 -prep { faultsim_restore_and_reopen db func mit mit } -body { execsql { SELECT mit(matchinfo(t8, 'a')) FROM t8 WHERE t8 MATCH 'a b c' } } -test { |
︙ | ︙ |
Changes to test/fts3fault2.test.
︙ | ︙ | |||
211 212 213 214 215 216 217 | faultsim_restore_and_reopen } -body { execsql { INSERT INTO t8 VALUES('one two three') } } -test { faultsim_test_result {0 {}} } | < < < | | 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | faultsim_restore_and_reopen } -body { execsql { INSERT INTO t8 VALUES('one two three') } } -test { faultsim_test_result {0 {}} } do_faultsim_test 8.2 -faults oom* -prep { faultsim_restore_and_reopen } -body { execsql { ALTER TABLE t8 RENAME TO t8ii } } -test { faultsim_test_result {0 {}} } #------------------------------------------------------------------------- reset_db set chunkconfig [fts3_configure_incr_load 1 1] do_execsql_test 9.0 { PRAGMA page_size = 512; |
︙ | ︙ |
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 xxxxxx | `--SCAN TABLE ft4 VIRTUAL TABLE INDEX 3: |--SCAN TABLE t4 `--SEARCH SUBQUERY xxxxxx AS rr USING AUTOMATIC COVERING INDEX (docid=?) } finish_test |
Deleted test/fts3matchinfo2.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/fts3misc.test.
︙ | ︙ | |||
222 223 224 225 226 227 228 | 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} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
Changes to test/fts3offsets.test.
︙ | ︙ | |||
114 115 116 117 118 119 120 | 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)} } | < < < < < < < < < < < < | 114 115 116 117 118 119 120 121 122 123 | 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 |
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 TABLE t1 USING COVERING INDEX i1 `--SCAN TABLE 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 TABLE t1 USING COVERING INDEX i1 `--SCAN TABLE 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 TABLE t1 USING COVERING INDEX i1 `--SEARCH TABLE 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 TABLE t1 USING COVERING INDEX i1 `--SEARCH TABLE 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.
︙ | ︙ | |||
558 559 560 561 562 563 564 | do_test 4.3 { llength [db one { SELECT snippet(t4, '', '', '', 0, 150) FROM t4 WHERE t4 MATCH 'E' }] } {64} | < < < < < < < < < < < < < < < < < < < < < < < < < | 558 559 560 561 562 563 564 565 566 567 | do_test 4.3 { llength [db one { SELECT snippet(t4, '', '', '', 0, 150) FROM t4 WHERE t4 MATCH 'E' }] } {64} set sqlite_fts3_enable_parentheses 0 finish_test |
Deleted test/fts3snippet2.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/fts4aa.test.
︙ | ︙ | |||
186 187 188 189 190 191 192 | 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 } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
Changes to test/fts4content.test.
︙ | ︙ | |||
629 630 631 632 633 634 635 | # Test cases 11.* # reset_db do_catchsql_test 11.1 { CREATE VIRTUAL TABLE x1 USING fts4(content=x1); } {1 {vtable constructor called recursively: x1}} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
Changes to test/fts4langid.test.
︙ | ︙ | |||
485 486 487 488 489 490 491 | } {1 2 5} do_execsql_test 5.4.$lid.5 { SELECT count(*) FROM t6_segdir; SELECT count(*) FROM t6_segments; } {1 2} } | < < < < < < < < < < < < < < < | 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 |
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 | 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} } finish_test |
Changes to test/fts4merge4.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 | # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/fts3_common.tcl set ::testprefix fts4merge4 | | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/fts3_common.tcl set ::testprefix fts4merge4 ifcapable !fts3 { finish_test return } set ::enable_shared_cache [sqlite3_enable_shared_cache 1] do_execsql_test 1.1 { CREATE VIRTUAL TABLE t1 USING fts4 } |
︙ | ︙ |
Deleted test/fts4merge5.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/fts4min.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/fts4noti.test.
︙ | ︙ | |||
169 170 171 172 173 174 175 | # Check that if an indexed column name is a prefix of a notindexed column # name, the column is still correctly tokenized. This was a problem at one # point. do_execsql_test 6.1.1 { CREATE VIRTUAL TABLE t1 USING fts4( poiCategory, poiCategoryId, notindexed=poiCategoryId ); | | | | 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 | # Check that if an indexed column name is a prefix of a notindexed column # name, the column is still correctly tokenized. This was a problem at one # point. do_execsql_test 6.1.1 { CREATE VIRTUAL TABLE t1 USING fts4( poiCategory, poiCategoryId, notindexed=poiCategoryId ); INSERT INTO t1(poiCategory, poiCategoryId) values ("Restaurant", 6021); } do_execsql_test 6.1.2 { SELECT * FROM t1 WHERE t1 MATCH 'restaurant'; } { Restaurant 6021 } do_execsql_test 6.1.3 { SELECT * FROM t1 WHERE t1 MATCH 're*'; } { Restaurant 6021 } do_execsql_test 6.1.4 { SELECT * FROM t1 WHERE t1 MATCH '6021'; } {} do_execsql_test 6.1.5 { SELECT * FROM t1 WHERE t1 MATCH '60*'; } {} do_execsql_test 6.2.1 { DROP TABLE t1; CREATE VIRTUAL TABLE t1 USING fts4( poiCategory, poiCategoryId, notindexed=poiCategory ); INSERT INTO t1(poiCategory, poiCategoryId) values ("Restaurant", 6021); } do_execsql_test 6.2.2 { SELECT * FROM t1 WHERE t1 MATCH 'restaurant'; } {} do_execsql_test 6.2.3 { SELECT * FROM t1 WHERE t1 MATCH 're*'; |
︙ | ︙ |
Deleted test/fts4record.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/fts4rename.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/fts4unicode.test.
︙ | ︙ | |||
563 564 565 566 567 568 569 | "unicode61", "tokenchars=@.", "separators=1234567890" ); SELECT token FROM ft1 WHERE input = 'berlin@street123sydney.road'; } { berlin@street sydney.road } | < < < < < < < < < < < < < < < < < < | 563 564 565 566 567 568 569 570 | "unicode61", "tokenchars=@.", "separators=1234567890" ); SELECT token FROM ft1 WHERE input = 'berlin@street123sydney.road'; } { berlin@street sydney.road } finish_test |
Deleted test/fts4upfrom.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/func.test.
︙ | ︙ | |||
311 312 313 314 315 316 317 | } {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} | < < < | 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} |
︙ | ︙ | |||
1003 1004 1005 1006 1007 1008 1009 | do_test func-21.2 { catchsql { SELECT replace(1,2,3,4); } } {1 {wrong number of arguments to function replace()}} do_test func-21.3 { execsql { | | | | | | | | 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 | do_test func-21.2 { catchsql { SELECT replace(1,2,3,4); } } {1 {wrong number of arguments to function replace()}} do_test func-21.3 { execsql { SELECT typeof(replace("This is the main test string", NULL, "ALT")); } } {null} do_test func-21.4 { execsql { SELECT typeof(replace(NULL, "main", "ALT")); } } {null} do_test func-21.5 { execsql { SELECT typeof(replace("This is the main test string", "main", NULL)); } } {null} do_test func-21.6 { execsql { SELECT replace("This is the main test string", "main", "ALT"); } } {{This is the ALT test string}} do_test func-21.7 { execsql { SELECT replace("This is the main test string", "main", "larger-main"); } } {{This is the larger-main test string}} do_test func-21.8 { execsql { SELECT replace("aaaaaaa", "a", "0123456789"); } } {0123456789012345678901234567890123456789012345678901234567890123456789} ifcapable tclvar { do_test func-21.9 { # Attempt to exploit a buffer-overflow that at one time existed # in the REPLACE function. |
︙ | ︙ | |||
1107 1108 1109 1110 1111 1112 1113 | do_test func-22.21 { execsql {SELECT typeof(trim(NULL,'xyz'));} } {null} do_test func-22.22 { execsql {SELECT typeof(trim('hello',NULL));} } {null} | < < < < < < < | 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 | 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 { SELECT legacy_count() FROM t6; |
︙ | ︙ | |||
1311 1312 1313 1314 1315 1316 1317 | # the content of their argument. # do_test func-29.1 { db eval { CREATE TABLE t29(id INTEGER PRIMARY KEY, x, y); INSERT INTO t29 VALUES(1, 2, 3), (2, NULL, 4), (3, 4.5, 5); INSERT INTO t29 VALUES(4, randomblob(1000000), 6); | | | 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 | # the content of their argument. # do_test func-29.1 { db eval { CREATE TABLE t29(id INTEGER PRIMARY KEY, x, y); INSERT INTO t29 VALUES(1, 2, 3), (2, NULL, 4), (3, 4.5, 5); INSERT INTO t29 VALUES(4, randomblob(1000000), 6); INSERT INTO t29 VALUES(5, "hello", 7); } db close sqlite3 db test.db sqlite3_db_status db CACHE_MISS 1 db eval {SELECT typeof(x), length(x), typeof(y) FROM t29 ORDER BY id} } {integer 1 integer null {} integer real 3 integer blob 1000000 integer text 5 integer} do_test func-29.2 { |
︙ | ︙ | |||
1422 1423 1424 1425 1426 1427 1428 | 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} | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 | 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} finish_test |
Changes to test/func3.test.
︙ | ︙ | |||
149 150 151 152 153 154 155 | # 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)}] | < < < < < < < < < < < < < | 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} |
︙ | ︙ | |||
194 195 196 197 198 199 200 | # 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)}] | < < < < < < < < | 181 182 183 184 185 186 187 188 189 190 | # 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 |
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: t1}} do_test func4-3.3 { catchsql { INSERT INTO t1 (x) VALUES (NULL); } } {1 {CHECK constraint failed: t1}} do_test func4-3.4 { catchsql { INSERT INTO t1 (x) VALUES (''); } } {1 {CHECK constraint failed: t1}} do_test func4-3.5 { catchsql { INSERT INTO t1 (x) VALUES ('bad'); } } {1 {CHECK constraint failed: t1}} do_test func4-3.6 { catchsql { INSERT INTO t1 (x) VALUES ('1234bad'); } } {1 {CHECK constraint failed: t1}} do_test func4-3.7 { catchsql { INSERT INTO t1 (x) VALUES ('1234.56bad'); } } {1 {CHECK constraint failed: t1}} 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: t1}} 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: t1}} do_test func4-3.12 { catchsql { INSERT INTO t1 (x) VALUES (ZEROBLOB(4)); } } {1 {CHECK constraint failed: t1}} do_test func4-3.13 { catchsql { INSERT INTO t1 (x) VALUES (X''); } } {1 {CHECK constraint failed: t1}} do_test func4-3.14 { catchsql { INSERT INTO t1 (x) VALUES (X'1234'); } } {1 {CHECK constraint failed: t1}} do_test func4-3.15 { catchsql { INSERT INTO t1 (x) VALUES (X'12345678'); } } {1 {CHECK constraint failed: t1}} do_test func4-3.16 { catchsql { INSERT INTO t1 (x) VALUES ('1234.00'); } } {1 {CHECK constraint failed: t1}} 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'); } } {1 {CHECK constraint failed: t1}} if {$highPrecision(1)} { do_test func4-3.19 { catchsql { INSERT INTO t1 (x) VALUES (9223372036854775808); } } {1 {CHECK constraint failed: t1}} } do_execsql_test func4-3.20 { SELECT x FROM t1 ORDER BY x; } {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: t2}} do_test func4-4.3 { catchsql { INSERT INTO t2 (x) VALUES (NULL); } } {1 {CHECK constraint failed: t2}} do_test func4-4.4 { catchsql { INSERT INTO t2 (x) VALUES (''); } } {1 {CHECK constraint failed: t2}} do_test func4-4.5 { catchsql { INSERT INTO t2 (x) VALUES ('bad'); } } {1 {CHECK constraint failed: t2}} do_test func4-4.6 { catchsql { INSERT INTO t2 (x) VALUES ('1234bad'); } } {1 {CHECK constraint failed: t2}} do_test func4-4.7 { catchsql { INSERT INTO t2 (x) VALUES ('1234.56bad'); } } {1 {CHECK constraint failed: t2}} 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: t2}} do_test func4-4.13 { catchsql { INSERT INTO t2 (x) VALUES (X''); } } {1 {CHECK constraint failed: t2}} do_test func4-4.14 { catchsql { INSERT INTO t2 (x) VALUES (X'1234'); } } {1 {CHECK constraint failed: t2}} do_test func4-4.15 { catchsql { INSERT INTO t2 (x) VALUES (X'12345678'); } } {1 {CHECK constraint failed: t2}} 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 | } {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; } {} | < | | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | } {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 WHERE x+counter2('hello')=counter2('hello')+x ORDER BY +x; } {1 2 3 4 5 6 7 8} finish_test |
Changes to test/func6.test.
︙ | ︙ | |||
167 168 169 170 171 172 173 | } [concat $z100 $z100 $z100] # Test offsets in WITHOUT ROWID table t2. do_execsql_test func6-200 { SELECT offrec( sqlite_offset(y), x, y ) FROM t2 ORDER BY x } $z100 | < < < < < < < < < | 167 168 169 170 171 172 173 174 | } [concat $z100 $z100 $z100] # Test offsets in WITHOUT ROWID table t2. do_execsql_test func6-200 { SELECT offrec( sqlite_offset(y), x, y ) FROM t2 ORDER BY x } $z100 finish_test |
Deleted test/func7.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/fuzz-oss1.test.
︙ | ︙ | |||
325 326 327 328 329 330 331 | } # Taken from the gnome-shell project # db close forcedelete test.db sqlite3 db test.db | < < | 325 326 327 328 329 330 331 332 333 334 335 336 337 338 | } # Taken from the gnome-shell project # db close forcedelete test.db sqlite3 db test.db do_test fuzz-oss1-gnomeshell { db eval { CREATE TABLE Resource (ID INTEGER NOT NULL PRIMARY KEY, Uri TEXT NOT NULL, UNIQUE (Uri)); CREATE VIRTUAL TABLE fts USING fts4; CREATE TABLE "mfo:Action" (ID INTEGER NOT NULL PRIMARY KEY); CREATE TABLE "mfo:Enclosure" (ID INTEGER NOT NULL PRIMARY KEY, |
︙ | ︙ |
Changes to test/fuzz.test.
︙ | ︙ | |||
368 369 370 371 372 373 374 | integrity_check fuzz-7.3.integrity do_test fuzz-7.4 {execsql COMMIT} {} integrity_check fuzz-7.5.integrity #---------------------------------------------------------------- # Many CREATE and DROP TABLE statements: # | | | 368 369 370 371 372 373 374 375 376 377 378 379 | integrity_check fuzz-7.3.integrity do_test fuzz-7.4 {execsql COMMIT} {} integrity_check fuzz-7.5.integrity #---------------------------------------------------------------- # Many CREATE and DROP TABLE statements: # set E [list table duplicate {no such col} {ambiguous column name} {use DROP}] do_fuzzy_test fuzz-8.1 -template {[CreateOrDropTableOrView]} -errorlist $E close $::log finish_test |
Changes to test/fuzz_common.tcl.
︙ | ︙ | |||
359 360 361 362 363 364 365 | 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} | < | 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] |
︙ | ︙ |
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 22 | /* ** 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 an external fuzzer, such as American ** Fuzzy Lop (AFL) (http://lcamtuf.coredump.cx/afl/). ** ** 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 |
︙ | ︙ | |||
58 59 60 61 62 63 64 | ** 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. | < < < < < < < < < < < < < < < < > | | | > | | | | | 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 | ** 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 <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 #ifdef SQLITE_OSS_FUZZ # include <stddef.h> # if !defined(_MSC_VER) # include <stdint.h> # endif #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 */ }; |
︙ | ︙ | |||
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 */ | < < < < < < < < < < | > > | > | | < < < < < < < | < < | | 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 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; if( g.zTestName[0] ){ fprintf(stderr, "%s (%s): ", g.zArgv0, g.zTestName); }else{ fprintf(stderr, "%s: ", g.zArgv0); } va_start(ap, zFormat); vfprintf(stderr, zFormat, ap); va_end(ap); fprintf(stderr, "\n"); exit(1); } /* ** Timeout handler */ #ifdef __unix__ static void timeoutHandler(int NotUsed){ (void)NotUsed; fatalError("timeout\n"); } #endif /* ** Set the an alarm to go off after N seconds. Disable the alarm ** if N==0 */ |
︙ | ︙ | |||
223 224 225 226 227 228 229 | static int progressHandler(void *pVdbeLimitFlag){ if( *(int*)pVdbeLimitFlag ) fatalError("too many VDBE cycles"); return 1; } #endif /* | | | 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | static int progressHandler(void *pVdbeLimitFlag){ if( *(int*)pVdbeLimitFlag ) fatalError("too many VDBE cycles"); return 1; } #endif /* ** Reallocate memory. Show and 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; } |
︙ | ︙ | |||
306 307 308 309 310 311 312 | pNew->nRef = 0; pNew->sz = sz; pNew->a = safe_realloc(0, sz); if( sz>0 ) memcpy(pNew->a, pData, sz); return pNew; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | < | | 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 | 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; void *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 ); if( pBuf && 1==fread(pBuf, nIn, 1, in) ){ sqlite3_result_blob(context, pBuf, nIn, sqlite3_free); }else{ sqlite3_free(pBuf); } fclose(in); } /* |
︙ | ︙ | |||
551 552 553 554 555 556 557 | while( p ){ pNext = p->pNext; free(p); p = pNext; } } | | < < < < < | 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 | while( p ){ pNext = p->pNext; free(p); p = pNext; } } /* 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; } |
︙ | ︙ | |||
608 609 610 611 612 613 614 | /* Maximum number of progress handler callbacks */ static unsigned int mxProgressCb = 2000; /* Maximum string length in SQLite */ static int lengthLimit = 1000000; | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 | /* Maximum number of progress handler callbacks */ static unsigned int mxProgressCb = 2000; /* Maximum string length in SQLite */ static int lengthLimit = 1000000; /* Maximum byte-code program length in SQLite */ static int vdbeOpLimit = 25000; /* Maximum size of the in-memory database */ static sqlite3_int64 maxDbSize = 104857600; /* ** 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){ |
︙ | ︙ | |||
716 717 718 719 720 721 722 | *pK = 2*k; *pI += i; return 1; } /* ** Decode the text starting at zIn into a binary database file. | | | | | 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 | *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. Compute the binary database ** file contain 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; /* 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; |
︙ | ︙ | |||
777 778 779 780 781 782 783 | if( newSize>MX_FILE_SZ ){ if( j>=MX_FILE_SZ ){ sqlite3_free(a); return -1; } newSize = MX_FILE_SZ; } | | | > | < < | 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 | if( newSize>MX_FILE_SZ ){ if( j>=MX_FILE_SZ ){ sqlite3_free(a); return -1; } newSize = MX_FILE_SZ; } a = sqlite3_realloc64( a, newSize ); if( a==0 ){ fprintf(stderr, "Out of memory!\n"); exit(1); } 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; |
︙ | ︙ | |||
817 818 819 820 821 822 823 | ** 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; | < < < < < < < < < | | | | < | < < < < < < < < < < < < | | | | | | < < < < < < < | < < < | < < < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < | | 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 | ** 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; 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 and DETACH */ 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_strnicmp("vdbe_", zArg1, 5)==0 || sqlite3_stricmp("parser_trace", zArg1)==0 || sqlite3_stricmp("temp_store_directory", zArg1)==0 ){ return SQLITE_DENY; } }else if( (eCode==SQLITE_ATTACH || eCode==SQLITE_DETACH) && zArg1 && zArg1[0] ){ 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; |
︙ | ︙ | |||
1088 1089 1090 1091 1092 1093 1094 | } } /* End switch() */ } /* End for() */ printf("\n"); fflush(stdout); } /* End if( eVerbosity>=5 ) */ } /* End while( SQLITE_ROW */ | < < < < < < < < < < < < < < < < < < < < < < < < < | | < < < < < < < < | < < < < < < < < | < < < | < < < < < | 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 | } } /* 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, size_t nByte){ 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 in mutator: %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( 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 ) 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 + giTimeout; /* Now + giTimeout seconds */ 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( 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); |
︙ | ︙ | |||
1229 1230 1231 1232 1233 1234 1235 | /* 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 */ | | < < < < < < < < < < < < < < < < < < | | | < < | 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 | /* 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 */ sqlite3_randomness(0,0); 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 ){ 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); } return 0; } /* ** END of the dbsqlfuzz code ***************************************************************************/ |
︙ | ︙ | |||
1740 1741 1742 1743 1744 1745 1746 | "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" | < < | | | < < < < < | < | 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 | "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" " --load-sql ARGS... Load SQL scripts fron files into SOURCE-DB\n" " --load-db ARGS... Load template databases from files into SOURCE_DB\n" " --load-dbsql ARGS.. Load dbsqlfuzz outputs into the xsql table\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" " --sqlid N Use only SQL where sqlid=N\n" " --timeout N Abort if any single test needs more than N seconds\n" " -v|--verbose Increased output. Repeat for more output.\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 */ |
︙ | ︙ | |||
1786 1787 1788 1789 1790 1791 1792 | 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 */ | < < < | | < < < < | < < | 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 | 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 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 = 120; /* Default 120-second timeout */ int nMem = 0; /* Memory limit */ 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 nV; /* How much to increase verbosity with -vvvv */ sqlite3_initialize(); iBegin = timeOfDay(); #ifdef __unix__ signal(SIGALRM, timeoutHandler); #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++){ |
︙ | ︙ | |||
1856 1857 1858 1859 1860 1861 1862 | if( strcmp(z,"help")==0 ){ showHelp(); return 0; }else if( strcmp(z,"info")==0 ){ infoFlag = 1; }else | | | < < < | | | < > | < | < < < < < < < < < < < < < < < < < < < < | | < < < < < < < < < < | 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 | if( strcmp(z,"help")==0 ){ showHelp(); return 0; }else if( strcmp(z,"info")==0 ){ infoFlag = 1; }else if( strcmp(z,"limit-mem")==0 ){ #if !defined(SQLITE_ENABLE_MEMSYS3) && !defined(SQLITE_ENABLE_MEMSYS5) fatalError("the %s option requires -DSQLITE_ENABLE_MEMSYS5 or _MEMSYS3", argv[i]); #else if( i>=argc-1 ) fatalError("missing arguments on %s", argv[i]); nMem = integerValue(argv[++i]); #endif }else if( strcmp(z,"limit-vdbe")==0 ){ vdbeLimitFlag = 1; }else if( strcmp(z,"load-sql")==0 ){ zInsSql = "INSERT INTO xsql(sqltext)VALUES(CAST(readfile(?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(CAST(readfile(?1) AS text))"; 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 ){ nativeMalloc = 1; }else if( strcmp(z,"native-vfs")==0 ){ nativeFlag = 1; }else if( strcmp(z,"oss-fuzz")==0 ){ ossFuzz = 1; }else 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,"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,"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 { fatalError("unknown option: %s", argv[i]); } }else{ nSrcDb++; azSrcDb = safe_realloc(azSrcDb, nSrcDb*sizeof(azSrcDb[0])); azSrcDb[nSrcDb-1] = argv[i]; |
︙ | ︙ | |||
2007 2008 2009 2010 2011 2012 2013 | if( zInsSql ){ fatalError("cannot import into more than one database"); } } /* Process each source database separately */ for(iSrcDb=0; iSrcDb<nSrcDb; iSrcDb++){ | < < < < < < < < < | < | | 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 | 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 ){ fatalError("cannot open source database %s - %s", azSrcDb[iSrcDb], sqlite3_errmsg(db)); } /* Print the description, if there is one */ if( infoFlag ){ int n; zDbName = azSrcDb[iSrcDb]; i = (int)strlen(zDbName) - 1; |
︙ | ︙ | |||
2056 2057 2058 2059 2060 2061 2062 | && (n = sqlite3_column_int(pStmt,0))>0 ){ printf(" - %d scripts", n); } sqlite3_finalize(pStmt); printf("\n"); sqlite3_close(db); | < | 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 | && (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" |
︙ | ︙ | |||
2081 2082 2083 2084 2085 2086 2087 | 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)); } | < < < < < < < < < < < < < < < | | > > > > | > < < < < < < < < < < < < < < < | < | | | < | 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 | 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); } if( strcmp(zName, "limit-mem")==0 && !nativeMalloc ){ #if !defined(SQLITE_ENABLE_MEMSYS3) && !defined(SQLITE_ENABLE_MEMSYS5) fatalError("the limit-mem option requires -DSQLITE_ENABLE_MEMSYS5" " or _MEMSYS3"); #else nMemThisDb = sqlite3_column_int(pStmt,1); if( verboseFlag ) printf("Config: limit-mem=%d\n", nMemThisDb); #endif } } sqlite3_finalize(pStmt); } if( zInsSql ){ sqlite3_create_function(db, "readfile", 1, SQLITE_UTF8, 0, readfileFunc, 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++){ sqlite3_bind_text(pStmt, 1, argv[i], -1, SQLITE_STATIC); 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); |
︙ | ︙ | |||
2226 2227 2228 2229 2230 2231 2232 | g.pFirstDb->id = 1; g.pFirstDb->seq = 0; g.nDb = 1; sqlFuzz = 1; } /* Print the description, if there is one */ | | < | | | | | < | 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 | g.pFirstDb->id = 1; g.pFirstDb->seq = 0; g.nDb = 1; sqlFuzz = 1; } /* Print the description, if there is one */ if( !quietFlag ){ 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); |
︙ | ︙ | |||
2260 2261 2262 2263 2264 2265 2266 | 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(); | < | < | | | | | < < < < < < | < < < < < < < < < | < < < | < < < < < < < < < < < < < | < < < < < < < < < < < < | 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 | 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 && !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); } /* 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 ) printf("%s:", zDbName); for(pSql=g.pFirstSql; pSql; pSql=pSql->pNext){ if( isDbSql(pSql->a, pSql->sz) ){ sqlite3_snprintf(sizeof(g.zTestName), g.zTestName, "sqlid=%d",pSql->id); 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; } } runCombinedDbSqlInput(pSql->a, pSql->sz); nTest++; g.zTestName[0] = 0; 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( 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; } } 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"); #else |
︙ | ︙ | |||
2384 2385 2386 2387 2388 2389 2390 | 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); | | < < < < < < < < < < < < < < < < < | | < < < | 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 | 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); #ifndef SQLITE_OMIT_PROGRESS_CALLBACK if( sqlFuzz || vdbeLimitFlag ){ sqlite3_progress_handler(db, 100000, progressHandler, &vdbeLimitFlag); } #endif 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++; 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( !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 ){ 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
Changes to test/fuzzdata8.db.
cannot compute difference between binary files
Changes to test/fuzzerfault.test.
︙ | ︙ | |||
84 85 86 87 88 89 90 | 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}} } | < < < < < < < < < < < < < < < < < < < | 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 |
Deleted test/fuzzinvariants.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/gencol1.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 0" "SELECT a, sum(b) FROM t1 WHERE 0 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 | # 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} finish_test |
Changes to test/hook.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 | # SQLite library. # # The focus of the tests in this file is the following interface: # # sqlite_commit_hook (tests hook-1..hook-3 inclusive) # sqlite_update_hook (tests hook-4-*) # sqlite_rollback_hook (tests hook-5.*) | < | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # SQLite library. # # The focus of the tests in this file is the following interface: # # sqlite_commit_hook (tests hook-1..hook-3 inclusive) # sqlite_update_hook (tests hook-4-*) # sqlite_rollback_hook (tests hook-5.*) # # $Id: hook.test,v 1.15 2009/04/07 14:14:23 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix hook |
︙ | ︙ | |||
139 140 141 142 143 144 145 | 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 154 | catchsql { DROP TABLE t1; } unset -nocomplain ::update_hook set ::update_hook {} db update_hook [list lappend ::update_hook] # # EVIDENCE-OF: R-52223-27275 The update hook is not invoked when # internal system tables are modified (i.e. sqlite_master and # 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 } | < | | | | | | | | | | | | | | | | | | | | | | | | < | 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 | do_preupdate_test 7.4.2.3 { UPDATE t5 SET b = 5 WHERE a = 'a' } { DELETE main t5 1 1 a 1 } 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. # |
︙ | ︙ | |||
847 848 849 850 851 852 853 | 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. | < | | | | | | < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | 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 | 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. 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 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 |
︙ | ︙ | |||
960 961 962 963 964 965 966 | 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} }] } | < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 953 954 955 956 957 958 959 960 961 | preupdate {DELETE main sqlite_stat1 1 1} preupdate {DELETE main sqlite_stat1 2 2} preupdate {INSERT main sqlite_stat1 1 1} preupdate {INSERT main sqlite_stat1 2 2} }] } finish_test |
Changes to test/icu.test.
︙ | ︙ | |||
142 143 144 145 146 147 148 | 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)); } } | < < < < < < < < < < < < < < < < < < | 142 143 144 145 146 147 148 149 | do_catchsql_test icu-5.6 {SELECT 'abc' REGEXP, 1} {1 {near ",": syntax error}} do_malloc_test icu-6.10 -sqlbody { SELECT upper(char(0xfb04,0xdf,0xfb04,0xe8,0xfb04)); } } finish_test |
Changes to test/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 4503599627370497,-1075 7 2.2250738585072009e-308 9007199254740991,-1075 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.
︙ | ︙ | |||
277 278 279 280 281 282 283 | SELECT * FROM ta LEFT JOIN tb ON (ta.b=tb.b) WHERE ta.a IN (); } } {} do_test in-7.8.2 { db status step } {0} | | | < | 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 | SELECT * FROM ta LEFT JOIN tb ON (ta.b=tb.b) WHERE ta.a IN (); } } {} do_test in-7.8.2 { db status step } {0} do_test in-8.1 { execsql { SELECT b FROM t1 WHERE a IN ('hello','there') } } {world} do_test in-8.2 { execsql { SELECT b FROM t1 WHERE a IN ("hello",'there') } } {world} # Test constructs of the form: expr IN tablename # |
︙ | ︙ | |||
329 330 331 332 333 334 335 | 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: t5}} # Ticket #1821 # # Type affinity applied to the right-hand side of an IN operator. # do_test in-11.1 { execsql { |
︙ | ︙ | |||
730 731 732 733 734 735 736 737 | } {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; } {} | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 729 730 731 732 733 734 735 736 737 738 739 | } {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; } {} finish_test |
Changes to test/in4.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # # $Id: in4.test,v 1.4 2009/06/05 17:09:12 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl | < | 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); } } {} |
︙ | ︙ | |||
223 224 225 226 227 228 229 | 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} | < < < | | | | | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | 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} 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/} |
︙ | ︙ | |||
326 327 328 329 330 331 332 | 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); | | < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 | 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/} 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/} finish_test |
Changes to test/in5.test.
︙ | ︙ | |||
244 245 246 247 248 249 250 | 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} | < < < < < < < < < < < < < < < < < | 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 |
Changes to test/in6.test.
︙ | ︙ | |||
73 74 75 76 77 78 79 | 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 {}} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
Changes to test/incrblob3.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # # set testdir [file dirname $argv0] source $testdir/tester.tcl | < < < < < < | 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)); |
︙ | ︙ | |||
270 271 272 273 274 275 276 | sqlite3 db test.db sqlite3_db_config_lookaside db 0 0 0 list [catch {db incrblob blobs v 1} msg] $msg } {1 {database schema has changed}} db close tvfs delete | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 264 265 266 267 268 269 270 271 | sqlite3 db test.db sqlite3_db_config_lookaside db 0 0 0 list [catch {db incrblob blobs v 1} msg] $msg } {1 {database schema has changed}} db close tvfs delete finish_test |
Changes to test/incrblobfault.test.
︙ | ︙ | |||
10 11 12 13 14 15 16 | #*********************************************************************** # # set testdir [file dirname $argv0] source $testdir/tester.tcl | < < < < < | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #*********************************************************************** # # 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'); INSERT INTO blob SELECT NULL, v FROM blob; |
︙ | ︙ |
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 | db eval { SELECT a FROM t3 } { if {$a==3} { db eval COMMIT } lappend res $a } set res } {1 2 3 4} } finish_test |
Changes to test/index.test.
︙ | ︙ | |||
424 425 426 427 428 429 430 | ); INSERT INTO t5 VALUES(1,2,3); SELECT * FROM t5; } } {1 2.0 3} do_test index-13.2 { set ::idxlist [execsql { | | | 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 | ); INSERT INTO t5 VALUES(1,2,3); SELECT * FROM t5; } } {1 2.0 3} do_test index-13.2 { set ::idxlist [execsql { SELECT name FROM sqlite_master WHERE type="index" AND tbl_name="t5"; }] llength $::idxlist } {3} for {set i 0} {$i<[llength $::idxlist]} {incr i} { do_test index-13.3.$i { catchsql " DROP INDEX '[lindex $::idxlist $i]'; |
︙ | ︙ | |||
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 | 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}} 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; } } {/.* TABLE t2 USING INDEX t2a1 .*/} ifcapable stat4||stat3 { execsql ANALYZE do_test index6-2.3stat4 { execsql { EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE a IS NOT NULL; } } {/.* TABLE 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; } } {/.* TABLE 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 TABLE t8a `--SEARCH TABLE 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 | 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} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
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 TABLE 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 as 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; } } {/.* TABLE t2 USING COVERING INDEX t2a1 .*/} ifcapable stat4||stat3 { do_test index7-2.3stat4 { execsql { EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE a IS NOT NULL; } } {/.* TABLE 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; } } {/.* TABLE 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 | 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 TABLE 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}} 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 TABLE 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/index9.test.
︙ | ︙ | |||
30 31 32 33 34 35 36 | uplevel [list do_test $tn [list sqluses $sql] $objects] } do_execsql_test 1.0 { CREATE TABLE t1(x, y); CREATE INDEX t1x ON t1(x) WHERE y=45; } | < | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | uplevel [list do_test $tn [list sqluses $sql] $objects] } do_execsql_test 1.0 { CREATE TABLE t1(x, y); CREATE INDEX t1x ON t1(x) WHERE y=45; } set y [expr 45] do_sqluses_test 1.1 { SELECT * FROM t1 WHERE x=? AND y=$y } {t1 t1x} set y [expr 45.1] do_sqluses_test 1.2 { SELECT * FROM t1 WHERE x=? AND y=$y } {t1} set y [expr 44] do_sqluses_test 1.3 { SELECT * FROM t1 WHERE x=? AND y=$y } {t1} unset -nocomplain y |
︙ | ︙ |
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 TABLE t1 USING INDEX i1 (a=?)} do_eqp_test indexedby-1.3 { select * from t1 ; } {SCAN TABLE t1} do_eqp_test indexedby-1.4 { select * from t1, t2 WHERE c = 10; } { QUERY PLAN |--SEARCH TABLE t2 USING INDEX i3 (c=?) `--SCAN TABLE 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-62112-42456 If the query optimizer is unable to use the # index specified by the INDEX 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' } } {1 {no query solution}} 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 TABLE t1 USING INDEX/} do_eqp_test indexedby-3.1.1 { SELECT * FROM t1 NOT INDEXED WHERE a = 'one' AND b = 'two' } {SCAN TABLE t1} do_eqp_test indexedby-3.1.2 { SELECT * FROM t1 NOT INDEXED WHERE rowid=1 } {/SEARCH TABLE 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 TABLE t1 USING INDEX i1 (a=?)} do_eqp_test indexedby-3.3 { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' AND b = 'two' } {SEARCH TABLE t1 USING INDEX i2 (b=?)} do_test indexedby-3.4 { catchsql { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' } } {1 {no query solution}} do_test indexedby-3.5 { catchsql { SELECT * FROM t1 INDEXED BY i2 ORDER BY a } } {1 {no query solution}} 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 TABLE 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 TABLE 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 } } {1 {no query solution}} 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 TABLE t1 `--SEARCH TABLE t2 USING INDEX i3 (c=?) } do_eqp_test indexedby-4.2 { SELECT * FROM t1 INDEXED BY i1, t2 WHERE a = c } { QUERY PLAN |--SCAN TABLE t2 `--SEARCH TABLE t1 USING INDEX i1 (a=?) } do_test indexedby-4.3 { catchsql { SELECT * FROM t1 INDEXED BY i1, t2 INDEXED BY i3 WHERE a=c } } {1 {no query solution}} do_test indexedby-4.4 { catchsql { SELECT * FROM t2 INDEXED BY i3, t1 INDEXED BY i1 WHERE a=c } } {1 {no query solution}} # 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 TABLE t1 USING INDEX i1 (a>?)*/} do_execsql_test indexedby-5.2 { EXPLAIN QUERY PLAN SELECT * FROM v2 WHERE b = 10 } {/*SEARCH TABLE 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 } } {1 {no query solution}} 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 TABLE t1 USING INDEX i2 (b=?)} do_eqp_test indexedby-6.2 { SELECT * FROM t1 NOT INDEXED WHERE b = 10 ORDER BY rowid } {SCAN TABLE 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 TABLE t1 USING INDEX i1 (a=?)} do_eqp_test indexedby-7.2 { DELETE FROM t1 NOT INDEXED WHERE a = 5 } {SCAN TABLE t1} do_eqp_test indexedby-7.3 { DELETE FROM t1 INDEXED BY i1 WHERE a = 5 } {SEARCH TABLE t1 USING INDEX i1 (a=?)} do_eqp_test indexedby-7.4 { DELETE FROM t1 INDEXED BY i1 WHERE a = 5 AND b = 10 } {SEARCH TABLE t1 USING INDEX i1 (a=?)} do_eqp_test indexedby-7.5 { DELETE FROM t1 INDEXED BY i2 WHERE a = 5 AND b = 10 } {SEARCH TABLE t1 USING INDEX i2 (b=?)} do_test indexedby-7.6 { catchsql { DELETE FROM t1 INDEXED BY i2 WHERE a = 5} } {1 {no query solution}} # 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 TABLE t1 USING COVERING INDEX i1 (a=?)} do_eqp_test indexedby-8.2 { UPDATE t1 NOT INDEXED SET rowid=rowid+1 WHERE a = 5 } {SCAN TABLE t1} do_eqp_test indexedby-8.3 { UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 } {SEARCH TABLE 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 TABLE 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 TABLE t1 USING INDEX i2 (b=?)} do_test indexedby-8.6 { catchsql { UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5} } {1 {no query solution}} # 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) } } {1 {no query solution}} do_test indexedby-9.3 { catchsql { select * from maintable, joinme INDEXED by joinme_id_text_idx } } {1 {no query solution}} # 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 TABLE 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 TABLE 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 | } {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/} 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 TABLE t1 USING INDEX t1alen/} do_execsql_test indexexpr1-171 { SELECT length(a) FROM t1 ORDER BY length(a) DESC; } {52 38 29 27 25 20} do_execsql_test indexexpr1-171eqp { EXPLAIN QUERY PLAN SELECT length(a) FROM t1 ORDER BY length(a) DESC; } {/SCAN TABLE t1 USING INDEX t1alen/} do_execsql_test indexexpr1-200 { DROP TABLE t1; CREATE TABLE t1(id ANY PRIMARY KEY, a,b,c) WITHOUT ROWID; INSERT INTO t1(id,a,b,c) VALUES(1,'In_the_beginning_was_the_Word',1,1), (2,'and_the_Word_was_with_God',1,2), |
︙ | ︙ | |||
164 165 166 167 168 169 170 | } {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/} | < | | | | | | | | | | | | < | | 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 | } {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/} 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 function in index expression or CHECK constraint}} 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 { |
︙ | ︙ | |||
416 417 418 419 420 421 422 | REPLACE INTO t1500(a,b) VALUES(1,3); -- formerly caused assertion fault SELECT * FROM t1500; } {1 3} # 2018-01-03 OSSFuzz discovers another test case for the same problem # above. # | | | | | < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | REPLACE INTO t1500(a,b) VALUES(1,3); -- formerly caused assertion fault SELECT * FROM t1500; } {1 3} # 2018-01-03 OSSFuzz discovers another test case for the same problem # above. # do_execsql_test indexexpr-1510 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a PRIMARY KEY,b UNIQUE); REPLACE INTO t1 VALUES(2, 1); REPLACE INTO t1 SELECT 6,1; CREATE INDEX t1aa ON t1(a-a); REPLACE INTO t1 SELECT a, randomblob(a) FROM t1 } {} # 2018-01-31 https://www.sqlite.org/src/tktview/343634942dd54ab57b702411 # When an index on an expression depends on the string representation of # a numeric table column, trouble can arise since there are multiple # string that can map to the same numeric value. (Ex: 123, 0123, 000123). # do_execsql_test indexexpr-1600 { DROP TABLE IF EXISTS t1; CREATE TABLE t1 (a INTEGER, b); CREATE INDEX idx1 ON t1 (lower(a)); INSERT INTO t1 VALUES('0001234',3); PRAGMA integrity_check; } {ok} do_execsql_test indexexpr-1610 { 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; } {} 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 TABLE 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 TABLE 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 TABLE 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. # |
︙ | ︙ | |||
261 262 263 264 265 266 267 | } {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; | | | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 | } {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 TABLE 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 TABLE x1 USING INDEX x1i2 (<expr>=?)} 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 21 | # 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 INSERT statement. # # $Id: insert.test,v 1.31 2007/04/05 11:25:59 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Try to insert into a non-existant table. # do_test insert-1.1 { |
︙ | ︙ | |||
453 454 455 456 457 458 459 | 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} | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 454 455 456 457 458 459 460 461 462 463 | 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-99.0 finish_test |
Changes to test/insert4.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # 2007 January 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 file is testing the INSERT transfer optimization. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix insert4 ifcapable !view||!subquery { finish_test | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2007 January 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 file is testing the INSERT transfer optimization. # # $Id: insert4.test,v 1.10 2008/01/21 16:22:46 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix insert4 ifcapable !view||!subquery { finish_test |
︙ | ︙ | |||
29 30 31 32 33 34 35 | # proc xferopt_test {testname N} { do_test $testname {set ::sqlite3_xferopt_count} $N } # Create tables used for testing. # | < > | | 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. # execsql { PRAGMA legacy_file_format = 0; 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: t1}} xferopt_test insert4-1.2 0 do_test insert4-1.3 { execsql { SELECT * FROM t1; } } {} |
︙ | ︙ | |||
97 98 99 100 101 102 103 | 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: t1}} 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: t1}} 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. # |
︙ | ︙ | |||
311 312 313 314 315 316 317 | 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: t6b}} 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: t6b}} # Ticket [6284df89debdfa61db8073e062908af0c9b6118e] # Disable the xfer optimization if the destination table contains # a foreign key constraint # ifcapable foreignkey { do_test insert4-7.1 { |
︙ | ︙ | |||
593 594 595 596 597 598 599 | 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 | 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; |
︙ | ︙ |
Changes to test/instr.test.
︙ | ︙ | |||
253 254 255 256 257 258 259 | } 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 | < < < < < < < < < < < < < < < < < < < < < | 253 254 255 256 257 258 259 260 | } 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 |
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_text $::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 inability 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} msg] lappend rc $msg } {1 SQLITE_MISUSE} do_test intarray-1.2 { db eval { SELECT b FROM t1 WHERE a IN ia3 ORDER BY a } } {} |
︙ | ︙ |
Changes to test/interrupt.test.
︙ | ︙ | |||
90 91 92 93 94 95 96 | } $cksum ifcapable {vacuum && !default_autovacuum} { do_test interrupt-2.4 { expr {$::origsize>[file size test.db]} } 1 } ifcapable {explain} { | | < < < < < | < < < < < < < < < | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | } $cksum ifcapable {vacuum && !default_autovacuum} { do_test interrupt-2.4 { expr {$::origsize>[file size test.db]} } 1 } ifcapable {explain} { do_test interrupt-2.5 { set sql {EXPLAIN SELECT max(a,b), a, b FROM t1} execsql $sql set rc [catch {db eval $sql {sqlite3_interrupt $DB}} msg] lappend rc $msg } {1 interrupted} } integrity_check interrupt-2.6 # Ticket #594. If an interrupt occurs in the middle of a transaction # and that transaction is later rolled back, the internal schema tables do # not reset. # # UPDATE: Interrupting a DML statement in the middle of a transaction now # causes the transaction to roll back. Leaving the transaction open after |
︙ | ︙ |
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 TABLE 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'); |
︙ | ︙ |
Deleted test/intreal.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/io.test.
︙ | ︙ | |||
636 637 638 639 640 641 642 | # 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 | < < | 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 |
Changes to test/ioerr.test.
︙ | ︙ | |||
330 331 332 333 334 335 336 | 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} | < | 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; |
︙ | ︙ |
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: t2}} do_catchsql_test istrue-522 { INSERT INTO t2 VALUES(2,true,true,null,null); } {1 {CHECK constraint failed: t2}} do_catchsql_test istrue-523 { INSERT INTO t2 VALUES(2,true,false,true,null); } {1 {CHECK constraint failed: t2}} do_catchsql_test istrue-524 { INSERT INTO t2 VALUES(2,true,false,null,false); } {1 {CHECK constraint failed: t2}} 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 | 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} } 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} finish_test |
Changes to test/join.test.
︙ | ︙ | |||
246 247 248 249 250 251 252 | do_test join-2.1 { execsql { SELECT * FROM t1 NATURAL LEFT JOIN t2; } } {1 2 3 4 2 3 4 5 3 4 5 {}} | < < < < < < < < < < < < < | 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | do_test join-2.1 { execsql { SELECT * FROM t1 NATURAL LEFT JOIN t2; } } {1 2 3 4 2 3 4 5 3 4 5 {}} # ticket #3522 do_test join-2.1.1 { execsql2 { SELECT * FROM t1 NATURAL LEFT JOIN t2; } } {a 1 b 2 c 3 d 4 a 2 b 3 c 4 d 5 a 3 b 4 c 5 d {}} do_test join-2.1.2 { |
︙ | ︙ | |||
281 282 283 284 285 286 287 | } {b 2 c 3 d 4 b 3 c 4 d 5 b {} c {} d {}} do_test join-2.2 { execsql { SELECT * FROM t2 NATURAL LEFT OUTER JOIN t1; } } {1 2 3 {} 2 3 4 1 3 4 5 2} | < | | | < < | > | 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | } {b 2 c 3 d 4 b 3 c 4 d 5 b {} c {} d {}} do_test join-2.2 { execsql { SELECT * FROM t2 NATURAL LEFT OUTER JOIN t1; } } {1 2 3 {} 2 3 4 1 3 4 5 2} do_test join-2.3 { catchsql { SELECT * FROM t1 NATURAL RIGHT OUTER JOIN t2; } } {1 {RIGHT and FULL OUTER JOINs are not currently supported}} do_test join-2.4 { execsql { SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.d } } {1 2 3 {} {} {} 2 3 4 {} {} {} 3 4 5 1 2 3} do_test join-2.5 { execsql { |
︙ | ︙ | |||
318 319 320 321 322 323 324 | SELECT * FROM t1 NATURAL JOIN t2 USING(b); } } {1 {a NATURAL join may not have an ON or USING clause}} do_test join-3.3 { catchsql { SELECT * FROM t1 JOIN t2 ON t1.a=t2.b USING(b); } | | < < < | | | | | | | 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 | SELECT * FROM t1 NATURAL JOIN t2 USING(b); } } {1 {a NATURAL join may not have an ON or USING clause}} do_test join-3.3 { catchsql { SELECT * FROM t1 JOIN t2 ON t1.a=t2.b USING(b); } } {1 {cannot have both ON and USING clauses in the same join}} do_test join-3.4.1 { catchsql { SELECT * FROM t1 JOIN t2 USING(a); } } {1 {cannot join using column a - column not present in both tables}} do_test join-3.4.2 { catchsql { SELECT * FROM t1 JOIN t2 USING(d); } } {1 {cannot join using column d - column not present in both tables}} do_test join-3.5 { catchsql { SELECT * FROM t1 USING(a) } } {1 {a JOIN clause is required before USING}} do_test join-3.6 { catchsql { SELECT * FROM t1 JOIN t2 ON t3.a=t2.b; } } {1 {no such column: t3.a}} do_test join-3.7 { catchsql { SELECT * FROM t1 INNER OUTER JOIN t2; } } {1 {unknown or unsupported join type: INNER OUTER}} do_test join-3.8 { catchsql { SELECT * FROM t1 INNER OUTER CROSS JOIN t2; } } {1 {unknown or unsupported join type: INNER OUTER CROSS}} do_test join-3.9 { catchsql { SELECT * FROM t1 OUTER NATURAL INNER JOIN t2; } } {1 {unknown or unsupported join type: OUTER NATURAL INNER}} do_test join-3.10 { catchsql { SELECT * FROM t1 LEFT BOGUS JOIN t2; } } {1 {unknown or unsupported join type: LEFT BOGUS}} do_test join-3.11 { catchsql { SELECT * FROM t1 INNER BOGUS CROSS JOIN t2; } } {1 {unknown or unsupported join type: INNER BOGUS CROSS}} do_test join-3.12 { catchsql { SELECT * FROM t1 NATURAL AWK SED JOIN t2; } } {1 {unknown or unsupported join type: NATURAL AWK SED}} do_test join-4.1 { execsql { BEGIN; CREATE TABLE t5(a INTEGER PRIMARY KEY); CREATE TABLE t6(a INTEGER); INSERT INTO t6 VALUES(NULL); |
︙ | ︙ | |||
453 454 455 456 457 458 459 | usuarios left outer join centros on usuarios.idcentro = centros.id; } } {1 a xxx 2 b xxx 3 c {}} # A test for ticket #247. # do_test join-7.1 { | < | 435 436 437 438 439 440 441 442 443 444 445 446 447 448 | usuarios left outer join centros on usuarios.idcentro = centros.id; } } {1 a xxx 2 b xxx 3 c {}} # A test for ticket #247. # do_test join-7.1 { execsql { CREATE TABLE t7 (x, y); INSERT INTO t7 VALUES ("pa1", 1); INSERT INTO t7 VALUES ("pa2", NULL); INSERT INTO t7 VALUES ("pa3", NULL); INSERT INTO t7 VALUES ("pa4", 2); INSERT INTO t7 VALUES ("pa30", 131); |
︙ | ︙ | |||
758 759 760 761 762 763 764 | } {111 555 333} do_execsql_test join-14.4 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(c PRIMARY KEY, a TEXT(10000), b TEXT(10000)); SELECT * FROM (SELECT 111) LEFT JOIN (SELECT c+222 FROM t1) GROUP BY 1; } {111 {}} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 | } {111 555 333} do_execsql_test join-14.4 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(c PRIMARY KEY, a TEXT(10000), b TEXT(10000)); SELECT * FROM (SELECT 111) LEFT JOIN (SELECT c+222 FROM t1) GROUP BY 1; } {111 {}} do_execsql_test join-14.5 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(c PRIMARY KEY) WITHOUT ROWID; SELECT * FROM (SELECT 111) LEFT JOIN (SELECT c+222 FROM t1) GROUP BY 1; } {111 {}} # Verify the fix to ticket # https://www.sqlite.org/src/tktview/7fde638e94287d2c948cd9389 |
︙ | ︙ | |||
857 858 859 860 861 862 863 | 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 | 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.106 { 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.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; |
︙ | ︙ | |||
914 915 916 917 918 919 920 | 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 {}} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 860 861 862 863 864 865 866 867 | 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 {}} finish_test |
Changes to test/join2.test.
︙ | ︙ | |||
59 60 61 62 63 64 65 | } {1 11 111 1111 3 33 333 {}} do_test join2-1.6 { execsql { SELECT * FROM t1 NATURAL LEFT OUTER JOIN t2 NATURAL JOIN t3 } } {1 11 111 1111} | < < < < < < < < < < < < < < < | 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 | } {1 11 111 1111 3 33 333 {}} do_test join2-1.6 { execsql { SELECT * FROM t1 NATURAL LEFT OUTER JOIN t2 NATURAL JOIN t3 } } {1 11 111 1111} ifcapable subquery { do_test join2-1.7 { execsql { SELECT * FROM t1 NATURAL LEFT OUTER JOIN (t2 NATURAL JOIN t3) } } {1 11 111 1111 2 22 {} {} 3 33 {} {}} } #------------------------------------------------------------------------- # Check that ticket [25e335f802ddc] has been resolved. It should be an # error for the ON clause of a LEFT JOIN to refer to a table to its right. # do_execsql_test 2.0 { CREATE TABLE aa(a); CREATE TABLE bb(b); CREATE TABLE cc(c); INSERT INTO aa VALUES('one'); INSERT INTO bb VALUES('one'); INSERT INTO cc VALUES('one'); } do_catchsql_test 2.1 { SELECT * FROM aa LEFT JOIN cc ON (a=b) JOIN bb ON (b=coalesce(c,1)); } {1 {ON clause references tables to its right}} do_catchsql_test 2.2 { SELECT * FROM aa JOIN cc ON (a=b) JOIN bb ON (b=c); } {0 {one one one}} #------------------------------------------------------------------------- # Test that a problem causing where.c to overlook opportunities to # omit unnecessary tables from a LEFT JOIN when UNIQUE, NOT NULL column |
︙ | ︙ | |||
124 125 126 127 128 129 130 | 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 TABLE t1 `--SEARCH TABLE 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 TABLE t1 `--SEARCH TABLE 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 { |
︙ | ︙ | |||
172 173 174 175 176 177 178 | 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 TABLE c1 |--SEARCH TABLE c2 USING INTEGER PRIMARY KEY (rowid=?) `--SEARCH TABLE 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 TABLE c1 `--SEARCH TABLE 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); |
︙ | ︙ | |||
219 220 221 222 223 224 225 | 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 TABLE c1 |--SEARCH TABLE c2 USING INDEX sqlite_autoindex_c2_1 (k=?) `--SEARCH TABLE 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 TABLE c1 `--SEARCH TABLE 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; |
︙ | ︙ | |||
262 263 264 265 266 267 268 | 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 | 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 TABLE s1} do_eqp_test 5.2 { SELECT s1.a FROM s1 left join s3 using (a); } {SCAN TABLE 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 TABLE 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} finish_test |
Changes to test/join5.test.
︙ | ︙ | |||
273 274 275 276 277 278 279 | 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 | 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 TABLE t1 `--MULTI-INDEX OR |--INDEX 1 | `--SEARCH TABLE t2 USING INDEX t2xy (x=? AND y=?) `--INDEX 2 `--SEARCH TABLE 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 TABLE t3 `--SEARCH TABLE t4 USING INDEX t4xz (x=?) } finish_test |
Changes to test/join6.test.
︙ | ︙ | |||
143 144 145 146 147 148 149 | 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 | 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} } |
︙ | ︙ |
Deleted test/join7.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/join8.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/join9.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/joinA.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/joinB.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/joinC.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/joinD.test.
more than 10,000 changes
Deleted test/joinE.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/joinF.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/joinH.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/journal3.test.
︙ | ︙ | |||
34 35 36 37 38 39 40 | 1 00644 2 00666 3 00600 4 00755 } { db close #set effective [format %.5o [expr $permissions & ~$umask]] | < | | | 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 | 1 00644 2 00666 3 00600 4 00755 } { db close #set effective [format %.5o [expr $permissions & ~$umask]] 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 } $permissions 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 } $effective 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 | 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.4 { execsql { PRAGMA journal_mode = off; } } {off} do_test jrnlmode-1.5 { execsql { PRAGMA journal_mode; |
︙ | ︙ |
Changes to test/json101.test.
︙ | ︙ | |||
10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #*********************************************************************** # This file implements tests for JSON SQL functions extension to the # SQLite library. # set testdir [file dirname $argv0] source $testdir/tester.tcl do_execsql_test json101-1.1.00 { SELECT json_array(1,2.5,null,'hello'); } {[1,2.5,null,"hello"]} do_execsql_test json101-1.1.01 { SELECT json_array(1,'{"abc":2.5,"def":null,"ghi":hello}',99); -- the second term goes in as a string: | > > > > > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #*********************************************************************** # This file implements tests for JSON SQL functions extension to the # SQLite library. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !json1 { finish_test return } do_execsql_test json101-1.1.00 { SELECT json_array(1,2.5,null,'hello'); } {[1,2.5,null,"hello"]} do_execsql_test json101-1.1.01 { SELECT json_array(1,'{"abc":2.5,"def":null,"ghi":hello}',99); -- the second term goes in as a string: |
︙ | ︙ | |||
823 824 825 826 827 828 829 | 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} {$}} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 828 829 830 831 832 833 834 835 | 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 |
Changes to test/json102.test.
︙ | ︙ | |||
13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # # This file contains tests automatically generated from the json1 # documentation. # set testdir [file dirname $argv0] source $testdir/tester.tcl do_execsql_test json102-100 { SELECT json_object('ex','[52,3.14159]'); } {{{"ex":"[52,3.14159]"}}} do_execsql_test json102-110 { SELECT json_object('ex',json('[52,3.14159]')); } {{{"ex":[52,3.14159]}}} | > > > > > | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | # # This file contains tests automatically generated from the json1 # documentation. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !json1 { finish_test return } do_execsql_test json102-100 { SELECT json_object('ex','[52,3.14159]'); } {{{"ex":"[52,3.14159]"}}} do_execsql_test json102-110 { SELECT json_object('ex',json('[52,3.14159]')); } {{{"ex":[52,3.14159]}}} |
︙ | ︙ | |||
328 329 330 331 332 333 334 | # All control characters are escaped # do_execsql_test json102-1501 { WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<0x1f) SELECT sum(json_valid(json_quote('a'||char(x)||'z'))) FROM c ORDER BY x; } {31} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 333 334 335 336 337 338 339 340 | # All control characters are escaped # do_execsql_test json102-1501 { WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<0x1f) SELECT sum(json_valid(json_quote('a'||char(x)||'z'))) FROM c ORDER BY x; } {31} finish_test |
Changes to test/json103.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # #*********************************************************************** # This file implements tests for JSON aggregate SQL functions # set testdir [file dirname $argv0] source $testdir/tester.tcl do_execsql_test json103-100 { CREATE TABLE t1(a,b,c); WITH RECURSIVE c(x) AS (VALUES(1) UNION SELECT x+1 FROM c WHERE x<100) INSERT INTO t1(a,b,c) SELECT x, x%3, printf('n%d',x) FROM c; UPDATE t1 SET a='orange' WHERE rowid=39; UPDATE t1 SET a=32.5 WHERE rowid=31; | > > > > > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # #*********************************************************************** # This file implements tests for JSON aggregate SQL functions # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !json1 { finish_test return } do_execsql_test json103-100 { CREATE TABLE t1(a,b,c); WITH RECURSIVE c(x) AS (VALUES(1) UNION SELECT x+1 FROM c WHERE x<100) INSERT INTO t1(a,b,c) SELECT x, x%3, printf('n%d',x) FROM c; UPDATE t1 SET a='orange' WHERE rowid=39; UPDATE t1 SET a=32.5 WHERE rowid=31; |
︙ | ︙ |
Changes to test/json104.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # This file implements tests for json_patch(A,B) SQL function. # set testdir [file dirname $argv0] source $testdir/tester.tcl | | > > > > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # #*********************************************************************** # 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 do_execsql_test json104-100 { SELECT json_patch('{ "a": "b", "c": { "d": "e", |
︙ | ︙ | |||
116 117 118 119 120 121 122 | } {{{"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":{}}}}} | < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
Deleted test/json105.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_master 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 | # 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 | < | 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); } |
︙ | ︙ | |||
164 165 166 167 168 169 170 | 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 { | | | | | | | 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | 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 { TABLE (\w+ AS )?(\w+) USING COVERING INDEX (\w+)\y} \ $x all as tab idx]} { lappend data {} $idx } elseif {[regexp { TABLE (\w+ AS )?(\w+) USING.* INDEX (\w+)\y} \ $x all as tab idx]} { lappend data $tab $idx } elseif {[regexp { TABLE (\w+ AS )?(\w+)\y} $x all as tab]} { lappend data $tab * } } return $data } # Perform tests on the like optimization. |
︙ | ︙ | |||
722 723 724 725 726 727 728 | }] } {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' }] | | | 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 | }] } {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 TABLE 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 {}} |
︙ | ︙ | |||
1032 1033 1034 1035 1036 1037 1038 | # 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] | < | | < | | | 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 | # 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] puts -nonewline " ($x ms - want less than 1000) " expr {$x<1000} } {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] puts -nonewline " ($x ms - want less than 1000) " expr {$x<1000} } {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. # |
︙ | ︙ | |||
1093 1094 1095 1096 1097 1098 1099 1100 | 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/} } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
Changes to test/like2.test.
︙ | ︙ | |||
1001 1002 1003 1004 1005 1006 1007 | do_test like-2.126.2 { db eval "SELECT x FROM t2 WHERE y LIKE '~%'" } {126} do_test like-2.126.3 { db eval "SELECT x FROM t3 WHERE y LIKE 'abc~%'" } {126} | < < < < < < < < | 1001 1002 1003 1004 1005 1006 1007 1008 1009 | do_test like-2.126.2 { db eval "SELECT x FROM t2 WHERE y LIKE '~%'" } {126} do_test like-2.126.3 { db eval "SELECT x FROM t3 WHERE y LIKE 'abc~%'" } {126} 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 | 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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE t5b USING COVERING INDEX sqlite_autoindex_t5b_1 (x>? AND x<?) } # 2019-02-27 # Verify that the LIKE optimization works with an ESCAPE clause when # using PRAGMA case_sensitive_like=ON. # 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 TABLE t1 USING PRIMARY KEY (path>? AND path<?) } do_eqp_test like3-6.120 { SELECT * FROM t1 WHERE path LIKE 'a%' ESCAPE '_'; } { QUERY PLAN `--SEARCH TABLE 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 TABLE t2 USING INDEX t2path (path>? AND path<?) } do_eqp_test like3-6.220 { SELECT * FROM t2 WHERE path LIKE 'a%' ESCAPE '_'; } { QUERY PLAN `--SEARCH TABLE 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 TABLE t2 USING INDEX t2path2 (path>? AND path<?) } do_eqp_test like3-6.240 { SELECT * FROM t2 WHERE path LIKE 'a%' ESCAPE '_'; } { QUERY PLAN `--SEARCH TABLE t2 USING INDEX t2path2 (path>? AND path<?) } finish_test |
Changes to test/limit.test.
︙ | ︙ | |||
637 638 639 640 641 642 643 | 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 } {} | < < < < < < < < < < < < < < < < < < < < < < < | 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 |
Changes to test/mallocA.test.
︙ | ︙ | |||
91 92 93 94 95 96 97 98 99 100 101 102 103 104 | } -test { 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 { | > > > > > > > > > > > > > > > > > > | 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 | } -test { 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}] } ifcapable stat3 { do_test 6.3-prep { execsql { PRAGMA writable_schema = 1; CREATE TABLE sqlite_stat4 AS SELECT tbl, idx, neq, nlt, ndlt, sqlite_record(sample) AS sample FROM sqlite_stat3; } } {} do_faultsim_test 6.3 -faults oom* -body { execsql { ANALYZE sqlite_master; 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 { |
︙ | ︙ |
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 TABLE 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/malloc_common.tcl.
︙ | ︙ | |||
660 661 662 663 664 665 666 | set cksumsql "SELECT md5sum([join [concat rowid $V(*)] ,]) FROM $tbl" # Calculate the initial table checksum. set cksum1 [db one $cksumsql] if {$::DO_MALLOC_TEST } { set answers [list {1 {out of memory}} {0 {}}] | < | 660 661 662 663 664 665 666 667 668 669 670 671 672 673 | set cksumsql "SELECT md5sum([join [concat rowid $V(*)] ,]) FROM $tbl" # Calculate the initial table checksum. set cksum1 [db one $cksumsql] if {$::DO_MALLOC_TEST } { set answers [list {1 {out of memory}} {0 {}}] if {$::DO_MALLOC_TEST==1} { set modes {100000 persistent} } else { set modes {1 transient} } } else { set answers [list {0 {}}] |
︙ | ︙ |
Changes to test/malloctraceviewer.tcl.
︙ | ︙ | |||
43 44 45 46 47 48 49 | proc populate_text_widget {db} { $::O(text) configure -state normal set id [lindex [$::O(tree) selection] 0] set frame [lindex $id end] set line [$db one {SELECT line FROM frame WHERE frame = $frame}] if {$line ne ""} { | | | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | proc populate_text_widget {db} { $::O(text) configure -state normal set id [lindex [$::O(tree) selection] 0] set frame [lindex $id end] set line [$db one {SELECT line FROM frame WHERE frame = $frame}] if {$line ne ""} { foreach {file line} [split $line :] {} set content [$db one "SELECT content FROM file WHERE name = '$file'"] $::O(text) delete 0.0 end set iLine 1 foreach L [split $content "\n"] { if {$iLine == $line} { $::O(text) insert end "$L\n" highlight |
︙ | ︙ |
Changes to test/memdb1.test.
︙ | ︙ | |||
153 154 155 156 157 158 159 | } {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!} | < < < < < < < < < < | 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | } {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] |
︙ | ︙ | |||
191 192 193 194 195 196 197 | 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?"}} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | 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?"}} #------------------------------------------------------------------------- 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}} } finish_test |
Deleted test/memdb2.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/memjournal.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/memjournal2.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/memsubsys1.test.
︙ | ︙ | |||
170 171 172 173 174 175 176 | expr {$pg_used>=45 && $pg_used<=50} } 1 do_test memsubsys1-4.4 { set pg_ovfl [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0] 2] } 0 do_test memsubsys1-4.5 { set maxreq [lindex [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0] 2] | | | 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 | expr {$pg_used>=45 && $pg_used<=50} } 1 do_test memsubsys1-4.4 { set pg_ovfl [lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0] 2] } 0 do_test memsubsys1-4.5 { set maxreq [lindex [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0] 2] expr {$maxreq<7000} } 1 db close sqlite3_shutdown sqlite3_config_memstatus 1 sqlite3_config_lookaside 100 500 sqlite3_config serialized |
︙ | ︙ |
Changes to test/memsubsys2.test.
︙ | ︙ | |||
70 71 72 73 74 75 76 | sqlite3_memory_highwater 0 } $highwater # Test 2: Verify that the highwater mark increases after a large # allocation. # | < < < < | | | | | | | | | | | | < | 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 | sqlite3_memory_highwater 0 } $highwater # Test 2: Verify that the highwater mark increases after a large # allocation. # sqlite3_memory_highwater 1 set highwater [sqlite3_memory_highwater 0] do_test memsubsys2-2.1 { sqlite3_free [set x [sqlite3_malloc 100000]] expr {$x!="0"} } {1} do_test memsubsys2-2.2.1 { expr {[sqlite3_memory_highwater 0]>=[sqlite3_memory_used]+100000} } {1} do_test memsubsys2-2.2.2 { expr {[sqlite3_memory_highwater 0]>=$highwater+50000} } {1} # Test 3: Verify that turning of memstatus disables the statistics # tracking. # db close sqlite3_shutdown sqlite3_config_memstatus 0 |
︙ | ︙ |
Deleted test/merge1.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/minmax.test.
︙ | ︙ | |||
290 291 292 293 294 295 296 | } } {34 1234} # Ticket #658: Test the min()/max() optimization when the FROM clause # is a subquery. # ifcapable {compound && subquery} { | < < < < < | | | | | | 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 | } } {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 { SELECT max(rowid) FROM ( SELECT max(rowid) FROM t4 UNION SELECT max(rowid) FROM t5 ) } } {{}} do_test minmax-9.2 { execsql { SELECT max(rowid) FROM ( SELECT max(rowid) 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. |
︙ | ︙ | |||
642 643 644 645 646 647 648 | 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} | < | < < < < < < < < < | 637 638 639 640 641 642 643 644 645 646 | 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} finish_test |
Changes to test/minmax2.test.
︙ | ︙ | |||
17 18 19 20 21 22 23 | # # $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 { | < > | 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 { execsql { PRAGMA legacy_file_format=0; 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 | } } {34 1234} # Ticket #658: Test the min()/max() optimization when the FROM clause # is a subquery. # ifcapable {compound && subquery} { | < < < < < | | | | | | 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 | } } {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 { SELECT max(rowid) FROM ( SELECT max(rowid) FROM t4 UNION SELECT max(rowid) FROM t5 ) } } {{}} do_test minmax2-9.2 { execsql { SELECT max(rowid) FROM ( SELECT max(rowid) 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 | # # 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 | < | 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 { |
︙ | ︙ | |||
145 146 147 148 149 150 151 | } {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} | < < < < < < < < < < | < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 144 145 146 147 148 149 150 151 152 153 | } {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} finish_test |
Changes to test/misc1.test.
︙ | ︙ | |||
601 602 603 604 605 606 607 | SELECT * FROM t19; } {1 2 3} do_execsql_test misc1-19.2 { CREATE TABLE t19b AS SELECT 4 AS '', 5 AS '', 6 AS ''; SELECT * FROM t19b; } {4 5 6} | | < < < | | | | 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 | SELECT * FROM t19; } {1 2 3} do_execsql_test misc1-19.2 { CREATE TABLE t19b AS SELECT 4 AS '', 5 AS '', 6 AS ''; SELECT * FROM t19b; } {4 5 6} # 2015-05-20: CREATE TABLE AS should not store INT value is a TEXT # column. # do_execsql_test misc1-19.3 { CREATE TABLE t19c(x TEXT); CREATE TABLE t19d AS SELECT * FROM t19c UNION ALL SELECT 1234; SELECT x, typeof(x) FROM t19d; } {1234 text} # 2014-05-16: Tests for the SQLITE_TESTCTRL_FAULT_INSTALL feature. # unset -nocomplain fault_callbacks set fault_callbacks {} proc fault_callback {n} { lappend ::fault_callbacks $n return 0 } do_test misc1-19.1 { sqlite3_test_control_fault_install fault_callback set fault_callbacks } {0} do_test misc1-19.2 { sqlite3_test_control_fault_install set fault_callbacks } {0} # 2015-01-26: Valgrind-detected over-read. # Reported on sqlite-users@sqlite.org by Michal Zalewski. Found by afl-fuzz # presumably. |
︙ | ︙ | |||
651 652 653 654 655 656 657 | } {1 {near "#0": syntax error}} do_catchsql_test misc1-21.2 { VALUES(0,0x0MATCH#0; } {1 {near ";": syntax error}} # 2015-04-15 do_execsql_test misc1-22.1 { | | | 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 | } {1 {near "#0": syntax error}} do_catchsql_test misc1-21.2 { VALUES(0,0x0MATCH#0; } {1 {near ";": syntax error}} # 2015-04-15 do_execsql_test misc1-22.1 { SELECT ""+3 FROM (SELECT ""+5); } {3} # 2015-04-19: NULL pointer dereference on a corrupt schema # db close sqlite3 db :memory: sqlite3_db_config db DEFENSIVE 0 |
︙ | ︙ | |||
727 728 729 730 731 732 733 | 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 | 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. 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); |
︙ | ︙ |
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 | 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_test misc2-2.2 { execsql { SELECT rowid, * FROM (SELECT * FROM t1, t2); } } {{} 1 2 3 7 8 9} } ifcapable view { do_test misc2-2.3 { execsql { CREATE VIEW v1 AS SELECT * FROM t1, t2; SELECT rowid, * FROM v1; } } {{} 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.
︙ | ︙ | |||
276 277 278 279 280 281 282 | 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 TABLE abc AS t2 USING INTEGER PRIMARY KEY (rowid=?) } do_eqp_test misc7-14.2 { SELECT * FROM abc AS t2 WHERE a = 1; } { QUERY PLAN `--SEARCH TABLE abc AS 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 TABLE abc AS t2 USING INDEX sqlite_autoindex_abc_1 } } db close forcedelete test.db forcedelete test.db-journal sqlite3 db test.db |
︙ | ︙ | |||
451 452 453 454 455 456 457 | 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 | do_test misc7-17.4 { db close sqlite3 db test.db catchsql { SELECT count(*) FROM t3; } } {1 {database disk image is malformed}} } } # Ticket #2470 # 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_execsql_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; } {0 1 6 0 1 7} # 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_execsql_test misc8-4.3 { PRAGMA database_list; } {/0 icecube .* 2 aux2/} 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 { 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 | 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)) } } {} | < < < < < | 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 { |
︙ | ︙ | |||
268 269 270 271 272 273 274 | 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] | < < < < < < < < < < < < | 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} |
︙ | ︙ |
Changes to test/multiplex3.test.
︙ | ︙ | |||
78 79 80 81 82 83 84 | } do_test 1.0 { setup_and_save_db } {} do_faultsim_test 1 -prep { multiplex_restore_db sqlite3 db file:test.db?8_3_names=1 sqlite3_multiplex_control db main chunk_size [expr 256*1024] | < < | 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | } do_test 1.0 { setup_and_save_db } {} do_faultsim_test 1 -prep { multiplex_restore_db sqlite3 db file:test.db?8_3_names=1 sqlite3_multiplex_control db main chunk_size [expr 256*1024] } -body { execsql { UPDATE t1 SET a=randomblob(12), b=randomblob(1500) WHERE (rowid%32)=0 } } -test { faultsim_test_result {0 {}} if {$testrc!=0} { |
︙ | ︙ |
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_master' 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 120 121 122 123 124 125 126 127 | do_test mutex1-1.6 { sqlite3_initialize } {SQLITE_OK} do_test mutex1-1.7 { mutex_counters counters # list $counters(total) $counters(static_master) 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_master) } {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_master 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_master static_mem static_open static_prng static_pmem static_vfs1 static_vfs2 static_vfs3 } } { do_test mutex1.2.$mode.1 { catch {db close} sqlite3_shutdown sqlite3_config $mode } SQLITE_OK do_test mutex1.2.$mode.2 { sqlite3_initialize clear_mutex_counters sqlite3 db test.db -nomutex 0 -fullmutex 0 |
︙ | ︙ |
Changes to test/normalize.test.
︙ | ︙ | |||
343 344 345 346 347 348 349 | 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,?);}} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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]} { |
︙ | ︙ |
Changes to test/notify3.test.
︙ | ︙ | |||
104 105 106 107 108 109 110 | db2_loaded enable_extended_errors result error1 error2 } " 0 0 0 0 $err SQLITE_LOCKED SQLITE_LOCKED_SHAREDCACHE 1 0 0 1 $err SQLITE_LOCKED_SHAREDCACHE SQLITE_LOCKED_SHAREDCACHE | | | | 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | db2_loaded enable_extended_errors result error1 error2 } " 0 0 0 0 $err SQLITE_LOCKED SQLITE_LOCKED_SHAREDCACHE 1 0 0 1 $err SQLITE_LOCKED_SHAREDCACHE SQLITE_LOCKED_SHAREDCACHE 2 0 1 0 $err SQLITE_LOCKED SQLITE_LOCKED_SHAREDCACHE 3 0 1 1 $err SQLITE_LOCKED_SHAREDCACHE SQLITE_LOCKED_SHAREDCACHE 4 1 0 0 $err SQLITE_LOCKED SQLITE_LOCKED_SHAREDCACHE 5 1 0 1 $err SQLITE_LOCKED_SHAREDCACHE SQLITE_LOCKED_SHAREDCACHE 6 1 1 0 $noerr SQLITE_OK SQLITE_OK 7 1 1 1 $noerr SQLITE_OK SQLITE_OK " { do_test notify3-2.$tn.1 { |
︙ | ︙ |
Deleted test/notnull2.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/notnullfault.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/null.test.
︙ | ︙ | |||
292 293 294 295 296 297 298 | 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} | < < < < < < < | 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 |
Deleted test/nulls1.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/offset1.test.
︙ | ︙ | |||
152 153 154 155 156 157 158 | do_execsql_test offset1-1.4.9 { SELECT a, b FROM t1 UNION ALL SELECT * FROM (SELECT x, y FROM t2 ORDER BY y) LIMIT 9 OFFSET 1; } {2 b 3 c 4 d 5 e 6 w 7 x 8 y 9 z} | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 152 153 154 155 156 157 158 159 160 161 | do_execsql_test offset1-1.4.9 { SELECT a, b FROM t1 UNION ALL SELECT * FROM (SELECT x, y FROM t2 ORDER BY y) LIMIT 9 OFFSET 1; } {2 b 3 c 4 d 5 e 6 w 7 x 8 y 9 z} finish_test |
Changes to test/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 948 | 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 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 | > | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | ** 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 #define SQLITE_ENABLE_DESERIALIZE 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.
︙ | ︙ | |||
39 40 41 42 43 44 45 | INSERT INTO track VALUES (NULL, 1, 1, 'one-a'), (NULL, 2, 2, 'two-b'), (NULL, 3, 3, 'three-c'), (NULL, 1, 3, 'one-c'), (NULL, 2, 1, 'two-a'), (NULL, 3, 1, 'three-a'); | < | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | INSERT INTO track VALUES (NULL, 1, 1, 'one-a'), (NULL, 2, 2, 'two-b'), (NULL, 3, 3, 'three-c'), (NULL, 1, 3, 'one-c'), (NULL, 2, 1, 'two-a'), (NULL, 3, 1, 'three-a'); COMMIT; } } {} do_test 1.1a { db eval { SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn } |
︙ | ︙ | |||
177 178 179 180 181 182 183 | INSERT INTO track VALUES (1, 1, 'one-a'), (20, 2, 'two-b'), (3, 3, 'three-c'), (1, 3, 'one-c'), (20, 1, 'two-a'), (3, 1, 'three-a'); | < | 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | INSERT INTO track VALUES (1, 1, 'one-a'), (20, 2, 'two-b'), (3, 3, 'three-c'), (1, 3, 'one-c'), (20, 1, 'two-a'), (3, 1, 'three-a'); COMMIT; } } {} do_test 2.1a { db eval { SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn } |
︙ | ︙ | |||
325 326 327 328 329 330 331 | INSERT INTO track VALUES (NULL, 1, 1, 'one-a'), (NULL, 2, 2, 'two-b'), (NULL, 3, 3, 'three-c'), (NULL, 1, 3, 'one-c'), (NULL, 2, 1, 'two-a'), (NULL, 3, 1, 'three-a'); | < | 323 324 325 326 327 328 329 330 331 332 333 334 335 336 | INSERT INTO track VALUES (NULL, 1, 1, 'one-a'), (NULL, 2, 2, 'two-b'), (NULL, 3, 3, 'three-c'), (NULL, 1, 3, 'one-c'), (NULL, 2, 1, 'two-a'), (NULL, 3, 1, 'three-a'); COMMIT; } } {} do_test 3.1a { db eval { SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC } |
︙ | ︙ | |||
515 516 517 518 519 520 521 | 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 TABLE 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 ) |
︙ | ︙ | |||
557 558 559 560 561 562 563 | 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 ^} | < < < < | 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 |
Changes to test/orderby5.test.
︙ | ︙ | |||
122 123 124 125 126 127 128 | 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/} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
Deleted test/orderbyA.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/oserror.test.
︙ | ︙ | |||
48 49 50 51 52 53 54 | # # 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]} { | < < < | | | < < < < | < < < < < | < | | | | < | 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 | # # 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] list [catch { for {set i 0} {$i < 20000} {incr i} { sqlite3 dbh_$i test.db -readonly 1 } } msg] $msg } {1 {unable to open database file}} do_test 1.1.2 { catch { for {set i 0} {$i < 20000} {incr i} { dbh_$i close } } } {1} 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.
︙ | ︙ | |||
151 152 153 154 155 156 157 | #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); | < < < | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | #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); /* 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); |
︙ | ︙ |
Changes to test/pager1.test.
︙ | ︙ | |||
17 18 19 20 21 22 23 | source $testdir/wal_common.tcl set testprefix pager1 if {[atomic_batch_write test.db]} { finish_test return } | < < < < | 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 # |
︙ | ︙ | |||
276 277 278 279 280 281 282 | 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 | | | 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | 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: counter}} 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 |
︙ | ︙ | |||
1764 1765 1766 1767 1768 1769 1770 | db close tv delete #------------------------------------------------------------------------- # Test specal "PRAGMA journal_mode=OFF" test cases. # | < < < < < < | 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; |
︙ | ︙ | |||
1794 1795 1796 1797 1798 1799 1800 | 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; | < < < | 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 { |
︙ | ︙ | |||
1939 1940 1941 1942 1943 1944 1945 | 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 | < < | | | | | | | | | | | | | | < < | 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 | 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 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 do_test pager1-18.6 { faultsim_delete_and_reopen db func a_string a_string execsql { PRAGMA page_size = 1024; CREATE TABLE t1(x); |
︙ | ︙ | |||
2921 2922 2923 2924 2925 2926 2927 | } {0 3 0} do_test 43.3 { db eval { SELECT * FROM t3 } sqlite3_db_status db CACHE_MISS 0 } {0 1 0} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2904 2905 2906 2907 2908 2909 2910 2911 | } {0 3 0} do_test 43.3 { db eval { SELECT * FROM t3 } sqlite3_db_status db CACHE_MISS 0 } {0 1 0} finish_test |
Changes to test/pager2.test.
︙ | ︙ | |||
161 162 163 164 165 166 167 | sqlite3 db3 test.db db1 eval { CREATE TABLE t1(a, b) } db2 eval { INSERT INTO t1 VALUES(1, 2) } list [catch { db3 eval { INSERT INTO t1 VALUES(3, 4) } } msg] $msg } {1 {no such table: t1}} | < < | 161 162 163 164 165 166 167 168 | sqlite3 db3 test.db db1 eval { CREATE TABLE t1(a, b) } db2 eval { INSERT INTO t1 VALUES(1, 2) } list [catch { db3 eval { INSERT INTO t1 VALUES(3, 4) } } msg] $msg } {1 {no such table: t1}} finish_test |
Deleted test/pendingrace.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/permutations.test.
︙ | ︙ | |||
87 88 89 90 91 92 93 | set alltests [list] foreach f [glob $testdir/*.test] { lappend alltests [file tail $f] } foreach f [glob -nocomplain \ $testdir/../ext/rtree/*.test \ $testdir/../ext/fts5/test/*.test \ $testdir/../ext/expert/*.test \ $testdir/../ext/lsm1/test/*.test \ | < < < | < < < < < < < < < < < < < < | < < < < < < | | < < | 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 | set alltests [list] foreach f [glob $testdir/*.test] { lappend alltests [file tail $f] } foreach f [glob -nocomplain \ $testdir/../ext/rtree/*.test \ $testdir/../ext/fts5/test/*.test \ $testdir/../ext/expert/*.test \ $testdir/../ext/lsm1/test/*.test \ ] { lappend alltests $f } foreach f [glob -nocomplain $testdir/../ext/session/*.test] { lappend alltests $f } if {$::tcl_platform(platform)!="unix"} { set alltests [test_set $alltests -exclude crash.test crash2.test] } set alltests [test_set $alltests -exclude { all.test async.test quick.test veryquick.test memleak.test permutations.test soak.test fts3.test mallocAll.test rtree.test full.test extraquick.test session.test rbu.test }] set allquicktests [test_set $alltests -exclude { async2.test async3.test backup_ioerr.test corrupt.test corruptC.test crash.test crash2.test crash3.test crash4.test crash5.test crash6.test crash7.test delete3.test e_fts3.test fts3rnd.test fkey_malloc.test fuzz.test fuzz3.test fuzz_malloc.test in2.test loadext.test misc7.test mutex2.test notify2.test onefile.test pagerfault2.test savepoint4.test savepoint6.test select9.test speed1.test speed1p.test speed2.test speed3.test speed4.test speed4p.test sqllimits1.test tkt2686.test thread001.test thread002.test thread003.test thread004.test thread005.test trans2.test vacuum3.test incrvacuum_ioerr.test autovacuum_crash.test btree8.test shared_err.test 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)]} { foreach x [split $::env(QUICKTEST_OMIT) ,] { regsub -all \\y$x\\y $allquicktests {} allquicktests } } # 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)]} { |
︙ | ︙ | |||
188 189 190 191 192 193 194 | test_suite "veryquick" -prefix "" -description { "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* \ | | < < < < < < | 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | test_suite "veryquick" -prefix "" -description { "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 [ |
︙ | ︙ | |||
221 222 223 224 225 226 227 | ] test_suite "valgrind" -prefix "" -description { Run the "veryquick" test suite with a couple of multi-process tests (that fail under valgrind) omitted. } -files [ test_set $allquicktests -exclude *malloc* *ioerr* *fault* *_err* wal.test \ | < | | 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | ] test_suite "valgrind" -prefix "" -description { Run the "veryquick" test suite with a couple of multi-process tests (that fail under valgrind) omitted. } -files [ test_set $allquicktests -exclude *malloc* *ioerr* *fault* *_err* wal.test \ shell*.test crash8.test atof1.test selectG.test \ tkt-fc62af4523.test numindex1.test corruptK.test ] -initialize { set ::G(valgrind) 1 } -shutdown { unset -nocomplain ::G(valgrind) } |
︙ | ︙ | |||
483 484 485 486 487 488 489 | 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 | | | | 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 | 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 analyzeA.test analyze.test analyzeB.test mallocA.test } test_suite "coverage-sorter" -description { Coverage tests for file vdbesort.c. } -files { sort.test sortfault.test } |
︙ | ︙ | |||
652 653 654 655 656 657 658 | 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 | | | 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 | 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 analyzeA.test analyzeB.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 |
︙ | ︙ | |||
781 782 783 784 785 786 787 | 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 | < | 749 750 751 752 753 754 755 756 757 758 759 760 761 762 | 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 |
︙ | ︙ | |||
805 806 807 808 809 810 811 | # This test assumes a journal file is created on disk. delete_db.test # This test depends on a successful recovery from the pager error # state. Which is not possible with an in-memory journal fts5fault1.test | < < | 772 773 774 775 776 777 778 779 780 781 782 783 784 785 | # This test assumes a journal file is created on disk. delete_db.test # This test depends on a successful recovery from the pager error # state. Which is not possible with an in-memory journal fts5fault1.test }] ifcapable mem3 { test_suite "memsys3" -description { Run tests using the allocator in mem3.c. } -files [test_set $::allquicktests -exclude { autovacuum.test delete3.test manydb.test |
︙ | ︙ | |||
913 914 915 916 917 918 919 | sqlite3_shutdown install_mutex_counters 1 set ::disable_mutex_try 1 sqlite3_initialize autoinstall_test_functions } -shutdown { catch {db close} | < < | 878 879 880 881 882 883 884 885 886 887 888 889 890 891 | sqlite3_shutdown install_mutex_counters 1 set ::disable_mutex_try 1 sqlite3_initialize autoinstall_test_functions } -shutdown { catch {db close} sqlite3_shutdown install_mutex_counters 0 sqlite3_initialize autoinstall_test_functions } } |
︙ | ︙ | |||
999 1000 1001 1002 1003 1004 1005 | } -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 | | < | 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 | } -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 }] 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 |
︙ | ︙ | |||
1060 1061 1062 1063 1064 1065 1066 | ] -dbconfig { set ::sqlite3session_streams 1 } test_suite "rbu" -description { RBU tests. } -files [ | | | < | 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 | ] -dbconfig { set ::sqlite3session_streams 1 } test_suite "rbu" -description { RBU tests. } -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 ] -dbconfig { optimization_control $::dbhandle all 0 } test_suite "prepare" -description { Run tests with the db connection using sqlite3_prepare() instead of _v2(). } -dbconfig { |
︙ | ︙ | |||
1109 1110 1111 1112 1113 1114 1115 | catch {db close} sqlite3_shutdown sqlite3_config_sorterref -1 sqlite3_initialize autoinstall_test_functions } | < < < < < < < < < < | 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 | 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: # |
︙ | ︙ | |||
1148 1149 1150 1151 1152 1153 1154 | 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) | | < < < < < | < < < < < < < < < < < < > | 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 | 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) foreach file [lsort $options(-files)] { uplevel $options(-initialize) if {[file tail $file] == $file} { set file [file join $::testdir $file] } 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) |
︙ | ︙ | |||
1229 1230 1231 1232 1233 1234 1235 | # 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 { | < | < | 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 | # 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] } eval run_tests $suite $S $extra } } main $argv finish_test } |
Changes to test/pg_common.tcl.
︙ | ︙ | |||
14 15 16 17 18 19 20 | package require Pgtcl set db [pg_connect -conninfo "dbname=postgres user=postgres password=postgres"] sqlite3 sqlite "" proc execsql {sql} { | < < | 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] |
︙ | ︙ | |||
68 69 70 71 72 73 74 | set ret } proc execsql_test {tn sql} { set res [execsql $sql] set sql [string map {string_agg group_concat} $sql] | | | | 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | 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} { |
︙ | ︙ |
Changes to test/pragma.test.
︙ | ︙ | |||
383 384 385 386 387 388 389 | } } {{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 | } } {{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_test pragma-3.6 { execsql { PRAGMA integrity_check=xyz } } {{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.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 |
︙ | ︙ | |||
423 424 425 426 427 428 429 | } {ok} do_test pragma-3.8.1 { execsql {PRAGMA quick_check} } {ok} do_test pragma-3.8.2 { execsql {PRAGMA QUICK_CHECK} } {ok} | | < < < < < < | 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 | } {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.9 { 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_test pragma-3.10 { execsql { PRAGMA integrity_check=1 } } {{*** in database t2 *** Page 4 is never used}} do_test pragma-3.11 { |
︙ | ︙ | |||
528 529 530 531 532 533 534 | db eval {PRAGMA integrity_check} } {ok} } # Verify that PRAGMA integrity_check catches UNIQUE and NOT NULL # constraint violations. # | < | | | | | | | | | | | | | | | | | | | | | | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | db eval {PRAGMA integrity_check} } {ok} } # Verify that PRAGMA integrity_check catches UNIQUE and NOT NULL # constraint violations. # 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 { 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; CREATE INDEX t1a ON t1(a); CREATE INDEX t1bc ON t1(b,c); } db eval {PRAGMA integrity_check} { db eval {DELETE FROM t1} } } {} # Test modifying the cache_size of an attached database. ifcapable pager_pragmas&&attach { do_test pragma-4.1 { execsql { ATTACH 'test2.db' AS aux; pragma aux.cache_size; pragma aux.default_cache_size; |
︙ | ︙ | |||
870 871 872 873 874 875 876 | ); } 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} \ | | | 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 | ); } 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)); |
︙ | ︙ | |||
957 958 959 960 961 962 963 | } } {} do_test pragma-8.1.2 { execsql2 { PRAGMA schema_version; } } {schema_version 105} | < | > | < > | < | < > | > | 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 | } } {} do_test pragma-8.1.2 { execsql2 { PRAGMA schema_version; } } {schema_version 105} do_test pragma-8.1.3 { execsql { PRAGMA schema_version = 106; } } {} do_test pragma-8.1.4 { execsql { PRAGMA schema_version; } } 106 # Check that creating a table modifies the schema-version (this is really # to verify that the value being read is in fact the schema version). do_test pragma-8.1.5 { execsql { CREATE TABLE t4(a, b, c); |
︙ | ︙ | |||
1924 1925 1926 1927 1928 1929 1930 | 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); | < | | 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 | 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} } {t1 i1 i2 i2x 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} |
︙ | ︙ | |||
1955 1956 1957 1958 1959 1960 1961 | } {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...) | | | | | < < < < | 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 | } {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-40889-06838 The rank of the column within the table # being indexed, or -1 if the index-column is the rowid of the table # being indexed. # # (The third column of output from PRAGMA index_xinfo is...) # EVIDENCE-OF: R-22751-28901 The name of the column being indexed, or # NULL if the index-column is the rowid of the table being indexed. # # (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} # 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. |
︙ | ︙ | |||
2006 2007 2008 2009 2010 2011 2012 | # (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 { | < < | | | | | | | | < | 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 | # (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 |} 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.
︙ | ︙ | |||
251 252 253 254 255 256 257 | do_test pragma3-430 { db2 eval {PRAGMA data_version; SELECT * FROM t1;} } {3 111 222} db2 close } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 251 252 253 254 255 256 257 258 | do_test pragma3-430 { db2 eval {PRAGMA data_version; SELECT * FROM t1;} } {3 111 222} db2 close } } finish_test |
Changes to test/pragma4.test.
︙ | ︙ | |||
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" | > | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | 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" 17 "PRAGMA legacy_file_format = 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" |
︙ | ︙ | |||
116 117 118 119 120 121 122 | 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 | | < < < < < | < < | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | 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 } {} 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 { |
︙ | ︙ | |||
250 251 252 253 254 255 256 257 | 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}} | < < < < < < < < < < | 244 245 246 247 248 249 250 251 252 | 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 |
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 | # 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 enabled at build time by setting: # # -DSQLITE_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 } do_execsql_test 1.1 { SELECT * FROM pragma_function_list WHERE name='upper' AND builtin } {upper 1} do_execsql_test 1.2 { SELECT * 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 |
︙ | ︙ |
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 | } {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} 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 { |
︙ | ︙ | |||
3775 3776 3777 3778 3779 3780 3781 | expr {($nFail>0 && $z eq "") || ($nFail==$nBenign && $z eq $zSuccess)} } {1} if {$nFail == 0} break incr nTestNum } } | < < < < < < < | 3773 3774 3775 3776 3777 3778 3779 3780 | expr {($nFail>0 && $z eq "") || ($nFail==$nBenign && $z eq $zSuccess)} } {1} if {$nFail == 0} break incr nTestNum } } finish_test |
Changes to test/printf2.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 the printf() SQL function. # # | | < < < | | | | | | | | 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 | # 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 printf() SQL function. # # # EVIDENCE-OF: R-63057-40065 The printf(FORMAT,...) SQL function works # like the sqlite3_mprintf() C-language function and the printf() # function from the standard C library. # set testdir [file dirname $argv0] source $testdir/tester.tcl # EVIDENCE-OF: R-40086-60101 If the FORMAT argument is missing or NULL # then the result is NULL. # do_execsql_test printf2-1.1 { SELECT quote(printf()), quote(printf(NULL,1,2,3)); } {NULL NULL} do_execsql_test printf2-1.2 { SELECT printf('hello'); } {hello} do_execsql_test printf2-1.3 { SELECT printf('%d,%d,%d',55,-11,3421); } {55,-11,3421} do_execsql_test printf2-1.4 { SELECT printf('%d,%d,%d',55,'-11',3421); } {55,-11,3421} do_execsql_test printf2-1.5 { SELECT printf('%d,%d,%d,%d',55,'-11',3421); } {55,-11,3421,0} do_execsql_test printf2-1.6 { SELECT printf('%.2f',3.141592653); } {3.14} do_execsql_test printf2-1.7 { SELECT printf('%.*f',2,3.141592653); } {3.14} do_execsql_test printf2-1.8 { SELECT printf('%*.*f',5,2,3.141592653); } {{ 3.14}} do_execsql_test printf2-1.9 { SELECT printf('%d',314159.2653); } {314159} do_execsql_test printf2-1.10 { SELECT printf('%lld',314159.2653); } {314159} do_execsql_test printf2-1.11 { SELECT printf('%lld%n',314159.2653,'hi'); } {314159} do_execsql_test printf2-1.12 { SELECT printf('%n',0); } {{}} # EVIDENCE-OF: R-17002-27534 The %z format is interchangeable with %s. # do_execsql_test printf2-1.12 { SELECT printf('%.*z',5,'abcdefghijklmnop'); } {abcde} do_execsql_test printf2-1.13 { SELECT printf('%c','abcdefghijklmnop'); } {a} # EVIDENCE-OF: R-02347-27622 The %n format is silently ignored and does # not consume an argument. |
︙ | ︙ |
Changes to test/pushdown.test.
︙ | ︙ | |||
82 83 84 85 86 87 88 | SELECT * FROM u1 WHERE 123=( SELECT x FROM u2 WHERE x=a AND f('two') ) AND f('three')=123 } set L } {three} | < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 82 83 84 85 86 87 88 89 90 91 | SELECT * FROM u1 WHERE 123=( SELECT x FROM u2 WHERE x=a AND f('two') ) AND f('three')=123 } set L } {three} finish_test |
Deleted test/quickcheck.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/quote.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 | # 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 | < | 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 {}} |
︙ | ︙ | |||
81 82 83 84 85 86 87 | # do_test quote-1.6 { set r [catch { execsql {DROP TABLE '@abc'} } msg ] lappend r $msg } {0 {}} | | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 80 81 82 83 84 85 86 87 88 89 | # do_test quote-1.6 { set r [catch { execsql {DROP TABLE '@abc'} } msg ] lappend r $msg } {0 {}} finish_test |
Deleted test/recover.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/regexp1.test.
︙ | ︙ | |||
24 25 26 27 28 29 30 | 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} | < < < < < < < < < < < < < | < < < < < < < < < | < < < < < < < < < | 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 | 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} do_execsql_test regexp1-1.3 { SELECT x FROM t1 WHERE y REGEXP 'by|Christ' 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 { SELECT x FROM t1 WHERE y REGEXP 'shall x*y*z*all' 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 { |
︙ | ︙ | |||
234 235 236 237 238 239 240 241 | SELECT 'abc$¢€xyz' REGEXP '^abc[\u0024][\u00a2][\u20ac]xyz$', 'abc$¢€xyz' REGEXP '^abc[\u0024\u00A2\u20AC]{3}xyz$', 'abc$¢€xyz' REGEXP '^abc[\x24][\xa2\u20ac]+xyz$' } {1 1 1} do_execsql_test regexp1-2.22 { SELECT 'abc$¢€xyz' REGEXP '^abc[^\u0025-X][^ -\u007f][^\u20ab]xyz$' } {1} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 203 204 205 206 207 208 209 210 211 | SELECT 'abc$¢€xyz' REGEXP '^abc[\u0024][\u00a2][\u20ac]xyz$', 'abc$¢€xyz' REGEXP '^abc[\u0024\u00A2\u20AC]{3}xyz$', 'abc$¢€xyz' REGEXP '^abc[\x24][\xa2\u20ac]+xyz$' } {1 1 1} do_execsql_test regexp1-2.22 { SELECT 'abc$¢€xyz' REGEXP '^abc[^\u0025-X][^ -\u007f][^\u20ab]xyz$' } {1} finish_test |
Changes to test/regexp2.test.
︙ | ︙ | |||
116 117 118 119 120 121 122 | INSERT INTO t5 VALUES ('^a.*'), ('^b.*'), ('^c.*'); INSERT INTO t6 VALUES ('eab'), ('abc'), ('bcd'), ('cde'), ('dea'); DELETE FROM t5; SELECT * FROM t6; } {eab dea} | < < < < < < < < < < < < < < < < < < < < | 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 |
Changes to test/reindex.test.
︙ | ︙ | |||
11 12 13 14 15 16 17 | # 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 | < | 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 } |
︙ | ︙ | |||
164 165 166 167 168 169 170 171 | REINDEX; } db2 } {1 {no such collation sequence: c2}} do_test reindex-3.99 { db2 close } {} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
Added test/releasetest.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 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 | #!/usr/bin/tclsh # # Documentation for this script. This may be output to stderr # if the script is invoked incorrectly. See the [process_options] # proc below. # set ::USAGE_MESSAGE { This Tcl script is used to test the various configurations required before releasing a new version. Supported command line options (all optional) are: --buildonly (Just build testfixture - do not run) --config CONFIGNAME (Run only CONFIGNAME) --dryrun (Print what would have happened) -f|--force (Run even if uncommitted changes) --info (Show diagnostic info) --jobs N (Use N processes - default 1) --keep (Delete no files after each test run) --msvc (Use MSVC as the compiler) --platform PLATFORM (see below) --progress (Show progress messages) --quick (Run "veryquick.test" only) --veryquick (Run "make smoketest" only) --with-tcl=DIR (Use TCL build at DIR) The script determines the default value for --platform using the $tcl_platform(os) and $tcl_platform(machine) variables. Supported platforms are "Linux-x86", "Linux-x86_64", "Darwin-i386", "Darwin-x86_64", "Windows NT-intel", and "Windows NT-amd64". Every test begins with a fresh run of the configure script at the top of the SQLite source tree. } # Return a timestamp of the form HH:MM:SS # proc now {} { return [clock format [clock seconds] -format %H:%M:%S] } # 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 -DSQLITE_ENABLE_DESERIALIZE } "Sanitize" { CC=clang -fsanitize=undefined -DSQLITE_ENABLE_STAT4 --enable-session } "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 } "Fast-One" { -O6 -DSQLITE_ENABLE_FTS4=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_STAT4 -DSQLITE_ENABLE_RBU -DSQLITE_MAX_ATTACHED=125 -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 -DSQLITE_ENABLE_DESERIALIZE=1 --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_USLEEP=1 -DHAVE_USLEEP=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 if:os=="Darwin" -DSQLITE_ENABLE_LOCKING_STYLE=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 -DHAVE_USLEEP=1 } "Valgrind" { -DSQLITE_ENABLE_STAT4 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_HIDDEN_COLUMNS --enable-json1 } # The next group of configurations are used only by the # Failure-Detection platform. They are all the same, but we need # different names for them all so that they results appear in separate # subdirectories. # Fail0 {-O0} Fail2 {-O0} Fail3 {-O0} Fail4 {-O0} FuzzFail1 {-O0} FuzzFail2 {-O0} }] array set ::Platforms [strip_comments { Linux-x86_64 { "Check-Symbols" checksymbols "Fast-One" "fuzztest test" "Debug-One" "mptest 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" test "No-lookaside" test "Devkit" test "Apple" test "Sanitize" {QUICKTEST_OMIT=func4.test,nan.test test} "Device-One" fulltest "Default" "threadtest fulltest" "Valgrind" valgrindtest } Linux-i686 { "Devkit" test "Have-Not" test "Unlock-Notify" "QUICKTEST_INCLUDE=notify2.test test" "Device-One" test "Device-Two" test "Default" "threadtest fulltest" } Darwin-i386 { "Locking-Style" "mptest test" "Have-Not" test "Apple" "threadtest fulltest" } Darwin-x86_64 { "Locking-Style" "mptest test" "Have-Not" test "Apple" "threadtest fulltest" } "Windows NT-intel" { "Stdcall" test "Have-Not" test "Default" "mptest fulltestonly" } "Windows NT-amd64" { "Stdcall" test "Have-Not" 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 t} $value { if {0==[info exists ::Configs($v)]} { puts stderr "No such configuration: \"$v\"" exit -1 } } } # Output log. Disabled for slave interpreters. # if {[lindex $argv end]!="--slave"} { set LOG [open releasetest-out.txt w] proc PUTS {txt} { puts $txt puts $::LOG $txt flush $::LOG } proc PUTSNNL {txt} { puts -nonewline $txt puts -nonewline $::LOG $txt flush $::LOG } proc PUTSERR {txt} { puts stderr $txt puts $::LOG $txt flush $::LOG } puts $LOG "$argv0 $argv" set tm0 [clock format [clock seconds] -format {%Y-%m-%d %H:%M:%S} -gmt 1] puts $LOG "start-time: $tm0 UTC" } else { proc PUTS {txt} { puts $txt } proc PUTSNNL {txt} { puts -nonewline $txt } proc PUTSERR {txt} { puts stderr $txt } } # Open the file $logfile and look for a report on the number of errors # and the number of test cases run. Add these values to the global # $::NERRCASE and $::NTESTCASE variables. # # If any errors occur, then write into $errmsgVar the text of an appropriate # one-line error message to show on the output. # proc count_tests_and_errors {logfile rcVar errmsgVar} { if {$::DRYRUN} return upvar 1 $rcVar rc $errmsgVar errmsg 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 ::NERRCASE $nerr incr ::NTESTCASE $ntest set seen 1 if {$nerr>0} { set rc 1 set errmsg $line } } if {[regexp {runtime error: +(.*)} $line all msg]} { # skip over "value is outside range" errors if {[regexp {value .* is outside the range of representable} $line]} { # noop } else { incr ::NERRCASE if {$rc==0} { set rc 1 set errmsg $msg } } } if {[regexp {fatal error +(.*)} $line all msg]} { incr ::NERRCASE if {$rc==0} { set rc 1 set errmsg $msg } } if {[regexp {ERROR SUMMARY: (\d+) errors.*} $line all cnt] && $cnt>0} { incr ::NERRCASE if {$rc==0} { set rc 1 set errmsg $all } } if {[regexp {^VERSION: 3\.\d+.\d+} $line]} { set v [string range $line 9 end] if {$::SQLITE_VERSION eq ""} { set ::SQLITE_VERSION $v } elseif {$::SQLITE_VERSION ne $v} { set rc 1 set errmsg "version conflict: {$::SQLITE_VERSION} vs. {$v}" } } } close $fd if {$::BUILDONLY} { incr ::NTESTCASE if {$rc!=0} { set errmsg "Build failed" } } elseif {!$seen} { set rc 1 set errmsg "Test did not complete" if {[file readable core]} { append errmsg " - core file exists" } } } #-------------------------------------------------------------------------- # This command is invoked as the [main] routine for scripts run with the # "--slave" option. # # For each test (i.e. "configure && make test" execution), the master # process spawns a process with the --slave option. It writes two lines # to the slaves stdin. The first contains a single boolean value - the # value of ::TRACE to use in the slave script. The second line contains a # list in the same format as each element of the list passed to the # [run_all_test_suites] command in the master process. # # The slave then runs the "configure && make test" commands specified. It # exits successfully if the tests passes, or with a non-zero error code # otherwise. # proc run_slave_test {} { # Read global vars configuration from stdin. set V [gets stdin] foreach {::TRACE ::MSVC ::DRYRUN ::KEEPFILES} $V {} # Read the test-suite configuration from stdin. set T [gets stdin] foreach {title dir configOpts testtarget makeOpts cflags opts} $T {} # Create and switch to the test directory. set normaldir [file normalize $dir] set ::env(SQLITE_TMPDIR) $normaldir trace_cmd file mkdir $dir trace_cmd cd $dir catch {file delete core} catch {file delete test.log} # Run the "./configure && make" commands. set rc 0 set rc [catch [configureCommand $configOpts]] if {!$rc} { if {[info exists ::env(TCLSH_CMD)]} { set savedEnv(TCLSH_CMD) $::env(TCLSH_CMD) } else { unset -nocomplain savedEnv(TCLSH_CMD) } set ::env(TCLSH_CMD) [file nativename [info nameofexecutable]] # Create a file called "makecommand.sh" containing the text of # the make command line. catch { set cmd [makeCommand $testtarget $makeOpts $cflags $opts] set fd [open makecommand.sh w] foreach e $cmd { if {[string first " " $e]>=0} { puts -nonewline $fd "\"$e\"" } else { puts -nonewline $fd $e } puts -nonewline $fd " " } puts $fd "" close $fd } msg # Run the make command. set rc [catch {trace_cmd exec {*}$cmd >>& test.log} msg] if {[info exists savedEnv(TCLSH_CMD)]} { set ::env(TCLSH_CMD) $savedEnv(TCLSH_CMD) } else { unset -nocomplain ::env(TCLSH_CMD) } } # Clean up lots of extra files if --keep was not specified. if {$::KEEPFILES==0} { cleanup $normaldir } # Exis successfully if the test passed, or with a non-zero error code # otherwise. exit $rc } # This command is invoked in the master process each time a slave # file-descriptor is readable. # proc slave_fileevent {fd T tm1} { global G foreach {title dir configOpts testtarget makeOpts cflags opts} $T {} if {[eof $fd]} { fconfigure $fd -blocking 1 set rc [catch { close $fd }] set errmsg {} set logfile [file join $dir test.log] if {[file exists $logfile]} { count_tests_and_errors [file join $dir test.log] rc errmsg } elseif {$rc==0 && !$::DRYRUN} { set rc 1 set errmsg "no test.log file..." } if {!$::TRACE} { set tm2 [clock seconds] set hours [expr {($tm2-$tm1)/3600}] set minutes [expr {(($tm2-$tm1)/60)%60}] set seconds [expr {($tm2-$tm1)%60}] set tm [format (%02d:%02d:%02d) $hours $minutes $seconds] if {$rc} { set status FAIL incr ::NERR } else { set status Ok } set n [string length $title] if {$::PROGRESS_MSGS} { PUTS "finished: ${title}[string repeat . [expr {53-$n}]] $status $tm" } else { PUTS "${title}[string repeat . [expr {63-$n}]] $status $tm" } if {$errmsg!=""} {PUTS " $errmsg"} flush stdout } incr G(nJob) -1 } else { set line [gets $fd] if {[string trim $line] != ""} { puts "Trace : $title - \"$line\"" } } } #-------------------------------------------------------------------------- # The only argument passed to this function is a list of test-suites to # run. Each "test-suite" is itself a list consisting of the following # elements: # # * Test title (for display). # * The name of the directory to run the test in. # * The argument for [configureCommand] # * The first argument for [makeCommand] # * The second argument for [makeCommand] # * The third argument for [makeCommand] # proc run_all_test_suites {alltests} { global G set tests $alltests set G(nJob) 0 while {[llength $tests]>0 || $G(nJob)>0} { if {$G(nJob)>=$::JOBS || [llength $tests]==0} { vwait G(nJob) } if {[llength $tests]>0} { set T [lindex $tests 0] set tests [lrange $tests 1 end] foreach {title dir configOpts testtarget makeOpts cflags opts} $T {} if {$::PROGRESS_MSGS && !$::TRACE} { set n [string length $title] PUTS "starting: ${title} at [now]" flush stdout } # Run the job. # set tm1 [clock seconds] incr G(nJob) set script [file normalize [info script]] set fd [open "|[info nameofexecutable] $script --slave" r+] fconfigure $fd -blocking 0 fileevent $fd readable [list slave_fileevent $fd $T $tm1] puts $fd [list $::TRACE $::MSVC $::DRYRUN $::KEEPFILES] puts $fd [list {*}$T] flush $fd } } } proc add_test_suite {listvar name testtarget config} { upvar $listvar alltests # Tcl variable $opts is used to build up the value used to set the # OPTS Makefile variable. Variable $cflags holds the value for # CFLAGS. The makefile will pass OPTS to both gcc and lemon, but # CFLAGS is only passed to gcc. # set makeOpts "" set cflags [expr {$::MSVC ? "-Zi" : "-g"}] set opts "" set title ${name}($testtarget) set configOpts $::WITHTCL set skip 0 regsub -all {#[^\n]*\n} $config \n config foreach arg $config { if {$skip} { set skip 0 continue } if {[regexp {^-[UD]} $arg]} { lappend opts $arg } elseif {[regexp {^[A-Z]+=} $arg]} { lappend testtarget $arg } elseif {[regexp {^if:([a-z]+)(.*)} $arg all key tail]} { # Arguments of the form 'if:os=="Linux"' will cause the subsequent # argument to be skipped if the $tcl_platform(os) is not "Linux", for # example... set skip [expr !(\$::tcl_platform($key)$tail)] } elseif {[regexp {^--(enable|disable)-} $arg]} { if {$::MSVC} { if {$arg eq "--disable-amalgamation"} { lappend makeOpts USE_AMALGAMATION=0 continue } if {$arg eq "--disable-shared"} { lappend makeOpts USE_CRT_DLL=0 DYNAMIC_SHELL=0 continue } if {$arg eq "--enable-fts5"} { lappend opts -DSQLITE_ENABLE_FTS5 continue } if {$arg eq "--enable-json1"} { lappend opts -DSQLITE_ENABLE_JSON1 continue } if {$arg eq "--enable-shared"} { lappend makeOpts USE_CRT_DLL=1 DYNAMIC_SHELL=1 continue } } lappend configOpts $arg } else { if {$::MSVC} { if {$arg eq "-g"} { lappend cflags -Zi continue } if {[regexp -- {^-O(\d+)$} $arg all level]} then { lappend makeOpts OPTIMIZATIONS=$level continue } } lappend cflags $arg } } # Disable sync to make testing faster. # lappend opts -DSQLITE_NO_SYNC=1 # Some configurations already set HAVE_USLEEP; in that case, skip it. # if {[lsearch -regexp $opts {^-DHAVE_USLEEP(?:=|$)}]==-1} { lappend opts -DHAVE_USLEEP=1 } # Add the define for this platform. # if {$::tcl_platform(platform)=="windows"} { lappend opts -DSQLITE_OS_WIN=1 } else { lappend opts -DSQLITE_OS_UNIX=1 } # Set the sub-directory to use. # set dir [string tolower [string map {- _ " " _} $name]] # Join option lists into strings, using space as delimiter. # set makeOpts [join $makeOpts " "] set cflags [join $cflags " "] set opts [join $opts " "] lappend alltests [list \ $title $dir $configOpts $testtarget $makeOpts $cflags $opts] } # The following procedure returns the "configure" command to be exectued for # the current platform, which may be Windows (via MinGW, etc). # proc configureCommand {opts} { if {$::MSVC} return [list]; # This is not needed for MSVC. set result [list trace_cmd exec] if {$::tcl_platform(platform)=="windows"} { lappend result sh } lappend result $::SRCDIR/configure --enable-load-extension foreach x $opts {lappend result $x} lappend result >& test.log } # The following procedure returns the "make" command to be executed for the # specified targets, compiler flags, and options. # proc makeCommand { targets makeOpts cflags opts } { set result [list] if {$::MSVC} { set nmakeDir [file nativename $::SRCDIR] set nmakeFile [file nativename [file join $nmakeDir Makefile.msc]] lappend result nmake /f $nmakeFile TOP=$nmakeDir set tclDir [file nativename [file normalize \ [file dirname [file dirname [info nameofexecutable]]]]] lappend result "TCLDIR=$tclDir" if {[regexp {USE_STDCALL=1} $cflags]} { lappend result USE_STDCALL=1 } } else { lappend result make } foreach makeOpt $makeOpts { lappend result $makeOpt } lappend result clean foreach target $targets { lappend result $target } lappend result CFLAGS=$cflags OPTS=$opts } # The following procedure prints its arguments if ::TRACE is true. # And it executes the command of its arguments in the calling context # if ::DRYRUN is false. # proc trace_cmd {args} { if {$::TRACE} { PUTS $args } set res "" if {!$::DRYRUN} { set res [uplevel 1 $args] } return $res } # This proc processes the command line options passed to this script. # Currently the only option supported is "-makefile", default # "releasetest.mk". Set the ::MAKEFILE variable to the value of this # option. # proc process_options {argv} { set ::SRCDIR [file normalize [file dirname [file dirname $::argv0]]] set ::QUICK 0 set ::MSVC 0 set ::BUILDONLY 0 set ::DRYRUN 0 set ::TRACE 0 set ::JOBS 1 set ::PROGRESS_MSGS 0 set ::WITHTCL {} set ::FORCE 0 set ::KEEPFILES 0 ;# Keep extra files after test run set config {} set platform $::tcl_platform(os)-$::tcl_platform(machine) for {set i 0} {$i < [llength $argv]} {incr i} { set x [lindex $argv $i] if {[regexp {^--[a-z]} $x]} {set x [string range $x 1 end]} switch -glob -- $x { -slave { run_slave_test exit } # Undocumented legacy option: --srcdir DIRECTORY # # DIRECTORY is the root of the SQLite checkout. This sets the # SRCDIR global variable. But that variable is already set # automatically so there really is no reason to have this option. # -srcdir { incr i set ::SRCDIR [file normalize [lindex $argv $i]] } -platform { incr i set platform [lindex $argv $i] } -jobs { incr i set ::JOBS [lindex $argv $i] } -progress { set ::PROGRESS_MSGS 1 } -quick { set ::QUICK 1 } -veryquick { set ::QUICK 2 } -config { incr i set config [lindex $argv $i] } -msvc { set ::MSVC 1 } -buildonly { set ::BUILDONLY 1 } -dryrun { set ::DRYRUN 1 } -force - -f { set ::FORCE 1 } -trace { set ::TRACE 1 } -info { PUTS "Command-line Options:" PUTS " --srcdir $::SRCDIR" PUTS " --platform [list $platform]" PUTS " --config [list $config]" if {$::QUICK} { if {$::QUICK==1} {PUTS " --quick"} if {$::QUICK==2} {PUTS " --veryquick"} } if {$::MSVC} {PUTS " --msvc"} if {$::BUILDONLY} {PUTS " --buildonly"} if {$::DRYRUN} {PUTS " --dryrun"} if {$::TRACE} {PUTS " --trace"} PUTS "\nAvailable --platform options:" foreach y [lsort [array names ::Platforms]] { PUTS " [list $y]" } PUTS "\nAvailable --config options:" foreach y [lsort [array names ::Configs]] { PUTS " [list $y]" } exit } -g { lappend ::EXTRACONFIG [lindex $argv $i] } -keep { set ::KEEPFILES 1 } -with-tcl=* { set ::WITHTCL -$x } -D* - -O* - -enable-* - -disable-* - *=* { lappend ::EXTRACONFIG [lindex $argv $i] } default { PUTSERR "" PUTSERR [string trim $::USAGE_MESSAGE] exit -1 } } } if {0==[info exists ::Platforms($platform)]} { PUTS "Unknown platform: $platform" PUTSNNL "Set the -platform option to " set print [list] foreach p [array names ::Platforms] { lappend print "\"$p\"" } lset print end "or [lindex $print end]" PUTS "[join $print {, }]." exit } if {$config!=""} { if {[llength $config]==1} {lappend config fulltest} set ::CONFIGLIST $config } else { if {$::JOBS>1} { set ::CONFIGLIST {} foreach {target zConfig} [lreverse $::Platforms($platform)] { append ::CONFIGLIST [format " %-25s %s\n" \ [list $zConfig] [list $target]] } } else { set ::CONFIGLIST $::Platforms($platform) } } PUTS "Running the following test configurations for $platform:" PUTS " [string trim $::CONFIGLIST]" PUTSNNL "Flags:" if {$::PROGRESS_MSGS} {PUTSNNL " --progress"} if {$::DRYRUN} {PUTSNNL " --dryrun"} if {$::BUILDONLY} {PUTSNNL " --buildonly"} if {$::MSVC} {PUTSNNL " --msvc"} switch -- $::QUICK { 1 {PUTSNNL " --quick"} 2 {PUTSNNL " --veryquick"} } if {$::JOBS>1} {PUTSNNL " --jobs $::JOBS"} PUTS "" } # Check to see if there are uncommitted changes in the SQLite source # checkout. Exit if there are. Except: Do nothing if the --force # flag is used. Also, ignore this test if the fossil binary is # unavailable, or if the source tree is not a valid fossil checkout. # proc check_uncommitted {} { if {$::FORCE} return set pwd [pwd] cd $::SRCDIR if {[catch {exec fossil changes} res]==0 && [string trim $res]!=""} { puts "ERROR: The check-out contains uncommitted changes:" puts $res puts "Use the -f or --force options to override" exit 1 } cd $pwd } # A test run has just finished in directory $dir. This command deletes all # non-essential files from the directory. Specifically, everything except # # * The "testfixture" and "sqlite3" binaries, # * The "test-out.log" and "test.log" log files. # proc cleanup {dir} { set K(testfixture) 1 set K(testfixture.exe) 1 set K(sqlite3) 1 set K(sqlite3.exe) 1 set K(test-out.txt) 1 set K(test.log) 1 foreach f [glob -nocomplain [file join $dir *]] { set tail [file tail $f] if {[info exists K($tail)]==0} { file delete -force $f } } } # Main routine. # proc main {argv} { # Process any command line options. set ::EXTRACONFIG {} process_options $argv if {!$::DRYRUN} check_uncommitted PUTS [string repeat * 79] set ::NERR 0 set ::NTEST 0 set ::NTESTCASE 0 set ::NERRCASE 0 set ::SQLITE_VERSION {} set STARTTIME [clock seconds] foreach {zConfig target} $::CONFIGLIST { if {$::MSVC && ($zConfig eq "Sanitize" || "checksymbols" in $target || "valgrindtest" in $target)} { PUTS "Skipping $zConfig / $target for MSVC..." continue } if {$target ne "checksymbols"} { switch -- $::QUICK { 1 {set target quicktest} 2 {set target smoketest} } if {$::BUILDONLY} { set target testfixture if {$::tcl_platform(platform)=="windows"} { append target .exe } } } set config_options [concat $::Configs($zConfig) $::EXTRACONFIG] incr NTEST add_test_suite all $zConfig $target $config_options # If the configuration included the SQLITE_DEBUG option, then remove # it and run veryquick.test. If it did not include the SQLITE_DEBUG option # add it and run veryquick.test. if {$target!="checksymbols" && $target!="valgrindtest" && $target!="fuzzoomtest" && !$::BUILDONLY && $::QUICK<2} { set debug_idx [lsearch -glob $config_options -DSQLITE_DEBUG*] set xtarget $target regsub -all {fulltest[a-z]*} $xtarget test xtarget regsub -all {fuzzoomtest} $xtarget fuzztest xtarget if {$debug_idx < 0} { incr NTEST append config_options " -DSQLITE_DEBUG=1 -DSQLITE_EXTRA_IFNULLROW=1" add_test_suite all "${zConfig}_debug" $xtarget $config_options } else { incr NTEST regsub { *-DSQLITE_MEMDEBUG[^ ]* *} $config_options { } config_options regsub { *-DSQLITE_DEBUG[^ ]* *} $config_options { } config_options add_test_suite all "${zConfig}_ndebug" $xtarget $config_options } } } run_all_test_suites $all set elapsetime [expr {[clock seconds]-$STARTTIME}] set hr [expr {$elapsetime/3600}] set min [expr {($elapsetime/60)%60}] set sec [expr {$elapsetime%60}] set etime [format (%02d:%02d:%02d) $hr $min $sec] if {$::JOBS>1} {append etime " $::JOBS cores"} if {[catch {exec hostname} HNAME]==0} {append etime " on $HNAME"} PUTS [string repeat * 79] incr ::NERRCASE $::NERR PUTS "$::NERRCASE failures out of $::NTESTCASE tests in $etime" if {$::SQLITE_VERSION ne ""} { PUTS "SQLite $::SQLITE_VERSION" } } main $argv |
Changes to 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 | # This file contains Configuration data used by "wapptest.tcl" and # "releasetest.tcl". # # 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 -DSQLITE_ENABLE_DESERIALIZE } "Sanitize" { CC=clang -fsanitize=undefined -DSQLITE_ENABLE_STAT4 --enable-session } "Stdcall" { -DUSE_STDCALL=1 -O2 } "Have-Not" { # The "Have-Not" configuration sets all possible -UHAVE_feature options |
︙ | ︙ | |||
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | "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 } "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 | > | | < < < < < < < > > | > > > | | > < < | < < < < < < < | | | | < < | < | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | < < < < < | | < < | | | < < | | | | | | | | > | > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > | > > > > > | > > > > > > > | > > > | > > > > > > > > | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | "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 } "Fast-One" { -O6 -DSQLITE_ENABLE_FTS4=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_STAT4 -DSQLITE_ENABLE_RBU -DSQLITE_MAX_ATTACHED=125 -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 -DSQLITE_ENABLE_DESERIALIZE=1 --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_USLEEP=1 -DHAVE_USLEEP=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 if:os=="Darwin" -DSQLITE_ENABLE_LOCKING_STYLE=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 -DHAVE_USLEEP=1 } "Valgrind" { -DSQLITE_ENABLE_STAT4 -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_HIDDEN_COLUMNS --enable-json1 } # The next group of configurations are used only by the # Failure-Detection platform. They are all the same, but we need # different names for them all so that they results appear in separate # subdirectories. # Fail0 {-O0} Fail2 {-O0} Fail3 {-O0} Fail4 {-O0} FuzzFail1 {-O0} FuzzFail2 {-O0} }] array set ::Platforms [strip_comments { Linux-x86_64 { "Check-Symbols" checksymbols "Fast-One" "fuzztest test" "Debug-One" "mptest 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" test "No-lookaside" test "Devkit" test "Apple" test "Sanitize" {QUICKTEST_OMIT=func4.test,nan.test test} "Device-One" fulltest "Default" "threadtest fulltest" "Valgrind" valgrindtest } Linux-i686 { "Devkit" test "Have-Not" test "Unlock-Notify" "QUICKTEST_INCLUDE=notify2.test test" "Device-One" test "Device-Two" test "Default" "threadtest fulltest" } Darwin-i386 { "Locking-Style" "mptest test" "Have-Not" test "Apple" "threadtest fulltest" } Darwin-x86_64 { "Locking-Style" "mptest test" "Have-Not" test "Apple" "threadtest fulltest" } "Windows NT-intel" { "Stdcall" test "Have-Not" test "Default" "mptest fulltestonly" } "Windows NT-amd64" { "Stdcall" test "Have-Not" 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" } }] proc make_test_suite {msvc withtcl name testtarget config} { # Tcl variable $opts is used to build up the value used to set the # OPTS Makefile variable. Variable $cflags holds the value for # CFLAGS. The makefile will pass OPTS to both gcc and lemon, but # CFLAGS is only passed to gcc. # set makeOpts "" set cflags [expr {$msvc ? "-Zi" : "-g"}] set opts "" set title ${name}($testtarget) set configOpts $withtcl set skip 0 regsub -all {#[^\n]*\n} $config \n config foreach arg $config { if {$skip} { set skip 0 continue } if {[regexp {^-[UD]} $arg]} { lappend opts $arg } elseif {[regexp {^[A-Z]+=} $arg]} { lappend testtarget $arg } elseif {[regexp {^if:([a-z]+)(.*)} $arg all key tail]} { # Arguments of the form 'if:os=="Linux"' will cause the subsequent # argument to be skipped if the $tcl_platform(os) is not "Linux", for # example... set skip [expr !(\$::tcl_platform($key)$tail)] } elseif {[regexp {^--(enable|disable)-} $arg]} { if {$msvc} { if {$arg eq "--disable-amalgamation"} { lappend makeOpts USE_AMALGAMATION=0 continue } if {$arg eq "--disable-shared"} { lappend makeOpts USE_CRT_DLL=0 DYNAMIC_SHELL=0 continue } if {$arg eq "--enable-fts5"} { lappend opts -DSQLITE_ENABLE_FTS5 continue } if {$arg eq "--enable-json1"} { lappend opts -DSQLITE_ENABLE_JSON1 continue } if {$arg eq "--enable-shared"} { lappend makeOpts USE_CRT_DLL=1 DYNAMIC_SHELL=1 continue } } lappend configOpts $arg } else { if {$msvc} { if {$arg eq "-g"} { lappend cflags -Zi continue } if {[regexp -- {^-O(\d+)$} $arg all level]} then { lappend makeOpts OPTIMIZATIONS=$level continue } } lappend cflags $arg } } # Disable sync to make testing faster. # lappend opts -DSQLITE_NO_SYNC=1 # Some configurations already set HAVE_USLEEP; in that case, skip it. # if {[lsearch -regexp $opts {^-DHAVE_USLEEP(?:=|$)}]==-1} { lappend opts -DHAVE_USLEEP=1 } # Add the define for this platform. # if {$::tcl_platform(platform)=="windows"} { lappend opts -DSQLITE_OS_WIN=1 } else { lappend opts -DSQLITE_OS_UNIX=1 } # Set the sub-directory to use. # set dir [string tolower [string map {- _ " " _ "(" _ ")" _} $name]] # Join option lists into strings, using space as delimiter. # set makeOpts [join $makeOpts " "] set cflags [join $cflags " "] set opts [join $opts " "] return [list $title $dir $configOpts $testtarget $makeOpts $cflags $opts] } # Configuration verification: Check that each entry in the list of configs # specified for each platforms exists. # foreach {key value} [array get ::Platforms] { foreach {v t} $value { if {0==[info exists ::Configs($v)]} { puts stderr "No such configuration: \"$v\"" exit -1 } } } |
Changes to test/resetdb.test.
︙ | ︙ | |||
251 252 253 254 255 256 257 | } {0} do_execsql_test 740 { PRAGMA page_count; PRAGMA integrity_check; } {1 ok} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 251 252 253 254 255 256 257 258 | } {0} do_execsql_test 740 { PRAGMA page_count; PRAGMA integrity_check; } {1 ok} finish_test |
Deleted test/returning1.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/returningfault.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 TABLE 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 TABLE 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 |
︙ | ︙ |
Deleted test/round1.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/rowid.test.
︙ | ︙ | |||
14 15 16 17 18 19 20 | # # 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 | < | 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); |
︙ | ︙ | |||
656 657 658 659 660 661 662 | 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} | < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
︙ | ︙ | |||
741 742 743 744 745 746 747 748 | 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} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
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 TABLE xy USING INTEGER PRIMARY KEY (rowid=?)" 2 "SELECT * FROM xy WHERE (k, j) < (2, 3)" {1 1 1 2 2 2} "SCAN TABLE xy" 3 "SELECT * FROM xy WHERE (i, j) < (2, 3)" {1 1 1 2 2 2} "SEARCH TABLE 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 TABLE 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 TABLE 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 { |
︙ | ︙ | |||
256 257 258 259 260 261 262 | } {1 {row value misused}} # 2016-10-27: https://www.sqlite.org/src/tktview/fef4bb4bd9185ec8f # Incorrect result from a LEFT JOIN with a row-value constraint # do_execsql_test 12.1 { DROP TABLE IF EXISTS t1; | | | < < < < < < < < < < < < | 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 | } {1 {row value misused}} # 2016-10-27: https://www.sqlite.org/src/tktview/fef4bb4bd9185ec8f # Incorrect result from a LEFT JOIN with a row-value constraint # do_execsql_test 12.1 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(1,2); DROP TABLE IF EXISTS t2; CREATE TABLE t2(x,y); INSERT INTO t2 VALUES(3,4); SELECT *,'x' FROM t1 LEFT JOIN t2 ON (a,b)=(x,y); } {1 2 {} {} x} foreach {tn sql} { 0 "SELECT (1,2) AS x WHERE x=3" 1 "SELECT (1,2) BETWEEN 1 AND 2" 2 "SELECT 1 BETWEEN (1,2) AND 2" 3 "SELECT 2 BETWEEN 1 AND (1,2)" |
︙ | ︙ | |||
548 549 550 551 552 553 554 | do_execsql_test 19.35 { SELECT * FROM t1 WHERE (3,33)>=(a,b) ORDER BY a DESC; } {3 33 2 22 1 11} do_execsql_test 19.36 { SELECT * FROM t1 WHERE (3,32)>=(a,b) ORDER BY a DESC; } {2 22 1 11} | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | do_execsql_test 19.35 { SELECT * FROM t1 WHERE (3,33)>=(a,b) ORDER BY a DESC; } {3 33 2 22 1 11} do_execsql_test 19.36 { SELECT * FROM t1 WHERE (3,32)>=(a,b) ORDER BY a DESC; } {2 22 1 11} # 2018-02-18: Memory leak nexted row-value. Detected by OSSFuzz. # do_catchsql_test 20.1 { SELECT 1 WHERE (2,(2,0)) IS (2,(2,0)); } {0 1} # 2018-11-03: Ticket https://www.sqlite.org/src/info/1a84668dcfdebaf1 # Assertion fault when doing row-value operations on a primary key # containing duplicate columns. # 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 |
Changes to test/rowvalue3.test.
︙ | ︙ | |||
209 210 211 212 213 214 215 | DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t2; CREATE TABLE T1(a TEXT); INSERT INTO T1(a) VALUES ('aaa'); CREATE TABLE T2(a TEXT PRIMARY KEY,n INT); INSERT INTO T2(a, n) VALUES('aaa',0); SELECT * FROM T2 | | < | 209 210 211 212 213 214 215 216 217 218 219 220 | DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t2; CREATE TABLE T1(a TEXT); INSERT INTO T1(a) VALUES ('aaa'); CREATE TABLE T2(a TEXT PRIMARY KEY,n INT); INSERT INTO T2(a, n) VALUES('aaa',0); SELECT * FROM T2 WHERE (a,n) IN (SELECT T1.a, V.n FROM T1, (SELECT * FROM (SELECT 0 n)) V); } {aaa 0} 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 TABLE c1 USING INDEX c1cd (c=?)} do_eqp_test 3.1.2 { SELECT * FROM c1 WHERE a=1 AND b>'d' AND c=2 } \ {SEARCH TABLE c1 USING INDEX c1cd (c=?)} do_eqp_test 3.1.3 { SELECT * FROM c1 WHERE a=1 AND b>'l' AND c=2 } \ {SEARCH TABLE c1 USING INDEX c1ab (a=? AND b>?)} do_eqp_test 3.2.1 { SELECT * FROM c1 WHERE a=1 AND c>1 } \ {SEARCH TABLE c1 USING INDEX c1cd (c>?)} do_eqp_test 3.2.2 { SELECT * FROM c1 WHERE a=1 AND c>0 } \ {SEARCH TABLE c1 USING INDEX c1ab (a=?)} do_eqp_test 3.2.3 { SELECT * FROM c1 WHERE a=1 AND c>=1 } \ {SEARCH TABLE c1 USING INDEX c1ab (a=?)} do_eqp_test 3.2.4 { SELECT * FROM c1 WHERE a=1 AND (c, d)>(1, 'c') } \ {SEARCH TABLE c1 USING INDEX c1ab (a=?)} do_eqp_test 3.2.5 { SELECT * FROM c1 WHERE a=1 AND (c, d)>(1, 'o') } \ {SEARCH TABLE c1 USING INDEX c1cd ((c,d)>(?,?))} do_eqp_test 3.2.6 { SELECT * FROM c1 WHERE a=1 AND (c, +b)>(1, 'c') } \ {SEARCH TABLE 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 TABLE d2 USING INDEX d2ab (a=? AND b=?) |--LIST SUBQUERY xxxxxx | `--SCAN TABLE d1 `--LIST SUBQUERY xxxxxx `--SCAN TABLE 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 TABLE e1 USING INDEX e1ab ((a,b)>(?,?))} do_eqp_test 6.2 { SELECT * FROM e1 WHERE (a, b) < (?, ?) } {SEARCH TABLE e1 USING INDEX e1ab ((a,b)<(?,?))} do_eqp_test 6.3 { SELECT * FROM e1 WHERE c = ? AND (d, e) > (?, ?) } {SEARCH TABLE e1 USING INDEX e1cde (c=? AND (d,e)>(?,?))} do_eqp_test 6.4 { SELECT * FROM e1 WHERE c = ? AND (d, e) < (?, ?) } {SEARCH TABLE e1 USING INDEX e1cde (c=? AND (d,e)<(?,?))} do_eqp_test 6.5 { SELECT * FROM e1 WHERE (d, e) BETWEEN (?, ?) AND (?, ?) AND c = ? } {SEARCH TABLE 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/rowvalue5.test.
︙ | ︙ | |||
42 43 44 45 46 47 48 | set OP(lt) < set OP(ge) >= set OP(match) MATCH set OP(like) LIKE set OP(glob) GLOB set OP(regexp) REGEXP | | < < | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | set OP(lt) < set OP(ge) >= set OP(match) MATCH set OP(like) LIKE set OP(glob) GLOB set OP(regexp) REGEXP set clist [lindex $args 0] set ret [list] set elist [list] set i 0 foreach c $clist { array set C $c if {$C(usable)} { lappend ret omit $i |
︙ | ︙ |
Changes to test/rowvalue7.test.
︙ | ︙ | |||
51 52 53 54 55 56 57 | 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}} | < < < < < < < < < < | 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 |
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 | 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 } finish_test |
Deleted test/rowvalueA.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/rowvaluefault.test.
︙ | ︙ | |||
64 65 66 67 68 69 70 | execsql { SELECT fou FROM xyz WHERE (one, two, thr) BETWEEN ('B', 'B', 'B') AND ('C', 'C', 'C') } } -test { faultsim_test_result {0 {2 3}} } | < < < < < < < < < < < < < < < < < < | 64 65 66 67 68 69 70 71 | 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 |
Deleted test/rowvaluevtab.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/savepoint.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 | # $Id: savepoint.test,v 1.13 2009/07/18 08:30:45 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/lock_common.tcl source $testdir/malloc_common.tcl | < < | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # $Id: savepoint.test,v 1.13 2009/07/18 08:30:45 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/lock_common.tcl source $testdir/malloc_common.tcl #---------------------------------------------------------------------- # The following tests - savepoint-1.* - test that the SAVEPOINT, RELEASE # and ROLLBACK TO comands are correctly parsed, and that the auto-commit # flag is correctly set and unset as a result. # do_test savepoint-1.1 { wal_set_journal_mode |
︙ | ︙ |
Changes to test/scanstatus.test.
︙ | ︙ | |||
32 33 34 35 36 37 38 | proc do_scanstatus_test {tn res} { set stmt [db version -last-stmt-ptr] set idx 0 set ret [list] while {1} { set r [sqlite3_stmt_scanstatus $stmt $idx] if {[llength $r]==0} break | < | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 | proc do_scanstatus_test {tn res} { set stmt [db version -last-stmt-ptr] set idx 0 set ret [list] while {1} { set r [sqlite3_stmt_scanstatus $stmt $idx] if {[llength $r]==0} break lappend ret {*}$r incr idx } 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 TABLE t1} nLoop 2 nVisit 6 nEst 1048576.0 zName t2 zExplain {SCAN TABLE 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 TABLE t1} nLoop 2 nVisit 6 nEst 3.0 zName t2 zExplain {SCAN TABLE 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 TABLE t2 USING INTEGER PRIMARY KEY (rowid>?)} nLoop 2 nVisit 4 nEst 2.0 zName t1 zExplain {SCAN TABLE 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 TABLE t2 USING INTEGER PRIMARY KEY (rowid>?)} nLoop 4 nVisit 8 nEst 2.0 zName t1 zExplain {SCAN TABLE 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 TABLE t2 USING INTEGER PRIMARY KEY (rowid>?)} nLoop 0 nVisit 0 nEst 2.0 zName t1 zExplain {SCAN TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE a1 USING INDEX a1a (a=?)} nLoop 1 nVisit 1 nEst 10.0 zName a1bc zExplain {SEARCH TABLE 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 TABLE a1 USING INDEX a1a (a>? AND a<?)} nLoop 1 nVisit 21 nEst 16384.0 zName a1bc zExplain {SEARCH TABLE 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 TABLE a1 AS y USING COVERING INDEX a1bc (b>? AND b<?)} nLoop 10 nVisit 90 nEst 16384.0 zName a1a zExplain {SEARCH TABLE a1 AS 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 TABLE 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 TABLE 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 |
︙ | ︙ | |||
264 265 266 267 268 269 270 | 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 | | | | 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 | 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 TABLE p1 USING INDEX sqlite_autoindex_p1_1 (x=?)} nLoop 1 nVisit 3 nEst 262144.0 zName c1 zExplain {SCAN TABLE c1} } #------------------------------------------------------------------------- # Further tests of different scan types. # reset_db proc tochar {i} { |
︙ | ︙ | |||
309 310 311 312 313 314 315 | ANALYZE; } do_execsql_test 5.1.1 { SELECT count(*) FROM t1 WHERE a IN (SELECT b FROM t1 AS ii) } {2} | < | | | | | < | | | < | | | | | | | | | | | | | | | < | | | | | 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 | ANALYZE; } 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 TABLE t1 AS ii USING COVERING INDEX t1bc} nLoop 1 nVisit 2 nEst 8.0 zName sqlite_autoindex_t1_1 zExplain {SEARCH TABLE 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 TABLE t1 USING COVERING INDEX sqlite_autoindex_t1_1 (a=?)} } do_eqp_test 5.3.1 { SELECT count(*) FROM t2 WHERE y = 'j'; } {SEARCH TABLE 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 TABLE 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 TABLE t1 USING COVERING INDEX t1bc `--SEARCH TABLE 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 TABLE t1 USING COVERING INDEX t1bc} nLoop 10 nVisit 200 nEst 56.0 zName t2xy zExplain {SEARCH TABLE 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 TABLE t3 `--SEARCH TABLE 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 TABLE t3} nLoop 501 nVisit 200 nEst 20.0 zName auto-index zExplain {SEARCH TABLE t1 USING AUTOMATIC COVERING INDEX (c=?)} } #------------------------------------------------------------------------- # Virtual table scans # ifcapable fts3 { do_execsql_test 6.0 { |
︙ | ︙ | |||
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 | | | 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 TABLE ft1 VIRTUAL TABLE INDEX 3:} } } finish_test |
Deleted test/scanstatus2.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 | 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. # ifcapable auth { do_test schema-8.1 { set ::STMT [sqlite3_prepare $::DB {SELECT * FROM sqlite_master} -1 TAIL] db auth {} sqlite3_step $::STMT } {SQLITE_ERROR} do_test schema-8.3 { sqlite3_finalize $::STMT } {SQLITE_SCHEMA} } #--------------------------------------------------------------------- # 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.
︙ | ︙ | |||
12 13 14 15 16 17 18 | # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/malloc_common.tcl source $testdir/lock_common.tcl | < < < < < < | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/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. # |
︙ | ︙ |
Deleted test/seekscan1.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/select1.test.
︙ | ︙ | |||
541 542 543 544 545 546 547 | SELECT * FROM test1 a, test1 b LIMIT 1 } } {a.f1 11 a.f2 22 b.f1 11 b.f2 22} do_test select1-6.9.7 { set x [execsql2 { SELECT * FROM test1 a, (select 5, 6) LIMIT 1 }] | | | | | 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 | SELECT * FROM test1 a, test1 b LIMIT 1 } } {a.f1 11 a.f2 22 b.f1 11 b.f2 22} do_test select1-6.9.7 { set x [execsql2 { SELECT * FROM test1 a, (select 5, 6) LIMIT 1 }] regsub -all {subquery_[0-9a-fA-F_]+} $x {subquery} x set x } {a.f1 11 a.f2 22 subquery.5 5 subquery.6 6} do_test select1-6.9.8 { set x [execsql2 { SELECT * FROM test1 a, (select 5 AS x, 6 AS y) AS b LIMIT 1 }] regsub -all {subquery_[0-9a-fA-F]+_} $x {subquery} x set x } {a.f1 11 a.f2 22 b.x 5 b.y 6} do_test select1-6.9.9 { execsql2 { SELECT a.f1, b.f2 FROM test1 a, test1 b LIMIT 1 } } {test1.f1 11 test1.f2 22} |
︙ | ︙ | |||
1096 1097 1098 1099 1100 1101 1102 | 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} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1096 1097 1098 1099 1100 1101 1102 1103 | 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} finish_test |
Changes to test/select3.test.
︙ | ︙ | |||
114 115 116 117 118 119 120 | do_test select3-2.14 { catchsql { SELECT log, count(*) FROM t1 GROUP BY; } } {1 {near ";": syntax error}} # Cannot have a HAVING without a GROUP BY | | < < | | | < | < < < < | 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | do_test select3-2.14 { catchsql { SELECT log, count(*) FROM t1 GROUP BY; } } {1 {near ";": syntax error}} # Cannot have a HAVING without a GROUP BY # do_test select3-3.1 { set v [catch {execsql {SELECT log, count(*) FROM t1 HAVING log>=4}} msg] lappend v $msg } {1 {a GROUP BY clause is required before HAVING}} # Toss in some HAVING clauses # do_test select3-4.1 { execsql {SELECT log, count(*) FROM t1 GROUP BY log HAVING log>=4 ORDER BY log} } {4 8 5 15} do_test select3-4.2 { |
︙ | ︙ | |||
264 265 266 267 268 269 270 | } {real} do_test select3-8.2 { execsql { SELECT typeof(sum(a3)) FROM a GROUP BY a1; } } {real} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
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 | 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}} finish_test |
Changes to test/select5.test.
︙ | ︙ | |||
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 { | > | 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. # #*********************************************************************** # 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. # # $Id: select5.test,v 1.20 2008/08/21 14:15:59 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Build some test data # execsql { |
︙ | ︙ | |||
246 247 248 249 250 251 252 | } {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} | | | < < < < < < | | 247 248 249 250 251 252 253 254 255 256 257 | } {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} finish_test |
Changes to test/select6.test.
︙ | ︙ | |||
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 | > | 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. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing SELECT statements that contain # subqueries in their FROM clause. # # $Id: select6.test,v 1.29 2009/01/09 01:12:28 drh Exp $ 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 |
︙ | ︙ | |||
165 166 167 168 169 170 171 172 173 174 175 176 177 178 | do_test select6-3.2 { execsql { SELECT * FROM (SELECT a.q, a.p, b.r FROM (SELECT count(*) as p , b as q FROM t2 GROUP BY q) AS a, (SELECT max(a) as r, b as s FROM t2 GROUP BY s) as b WHERE a.q=b.s ORDER BY a.q) } } {1 1 1 2 2 3 3 4 7 4 8 15 5 5 20} do_test select6-3.3 { execsql { SELECT a,b,a+b FROM (SELECT avg(x) as 'a', avg(y) as 'b' FROM t1) } } {10.5 3.7 14.2} | > | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | do_test select6-3.2 { execsql { SELECT * FROM (SELECT a.q, a.p, b.r FROM (SELECT count(*) as p , b as q FROM t2 GROUP BY q) AS a, (SELECT max(a) as r, b as s FROM t2 GROUP BY s) as b WHERE a.q=b.s ORDER BY a.q) ORDER BY "a.q" } } {1 1 1 2 2 3 3 4 7 4 8 15 5 5 20} do_test select6-3.3 { execsql { SELECT a,b,a+b FROM (SELECT avg(x) as 'a', avg(y) as 'b' FROM t1) } } {10.5 3.7 14.2} |
︙ | ︙ | |||
607 608 609 610 611 612 613 | 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 ); } {{}} | < < | < < < < < < < < < < < < < < | 609 610 611 612 613 614 615 616 617 | 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 ); } {{}} 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 TABLE/} ;# 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 TABLE/} ;# 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 TABLE/} ;# 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 TABLE t5 USING INDEX i2 | `--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY `--RIGHT |--SCAN TABLE 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() |
︙ | ︙ | |||
1463 1464 1465 1466 1467 1468 1469 1470 | 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; } {} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1463 1464 1465 1466 1467 1468 1469 1470 1471 | 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; } {} finish_test |
Changes to test/selectC.test.
︙ | ︙ | |||
225 226 227 228 229 230 231 232 233 234 235 236 237 238 | insert into t_distinct_bug values ('1', '2', 'e'); insert into t_distinct_bug values ('1', '3', 'f'); } {} do_execsql_test selectC-4.2 { select a from (select distinct a, b from t_distinct_bug) } {1 1 1} do_execsql_test selectC-4.3 { select a, udf() from (select distinct a, b from t_distinct_bug) } {1 1 1 2 1 3} #------------------------------------------------------------------------- # Test that the problem in ticket #190c2507 has been fixed. | > > > > > | 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 | insert into t_distinct_bug values ('1', '2', 'e'); insert into t_distinct_bug values ('1', '3', 'f'); } {} do_execsql_test selectC-4.2 { select a from (select distinct a, b from t_distinct_bug) } {1 1 1} do_execsql_test selectC-4.2b { CREATE VIEW v42b AS SELECT DISTINCT a, b FROM t_distinct_bug; SELECT a FROM v42b; } {1 1 1} do_execsql_test selectC-4.3 { select a, udf() from (select distinct a, b from t_distinct_bug) } {1 1 1 2 1 3} #------------------------------------------------------------------------- # Test that the problem in ticket #190c2507 has been fixed. |
︙ | ︙ | |||
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 { | | > | | | 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 | 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 +2 } { a 21 b 21 a 22 b 22 a 23 b 23 a 24 b 24 a 25 b 25 a 301 b 301 a 302 b 302 a 303 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 SUBQUERY * AS x2 USING AUTOMATIC*/} finish_test |
Added test/server1.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 | # 2006 January 09 # # 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 server mode of SQLite. # # This file is derived from thread1.test # # $Id: server1.test,v 1.5 2007/08/29 18:20:17 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Skip this whole file if the server testing code is not enabled # if {[llength [info command client_step]]==0 || [sqlite3 -has-codec]} { finish_test return } # This test does not work on older PPC Macs due to problems in the # pthreads library. So skip it. # if {$tcl_platform(machine)=="Power Macintosh" && $tcl_platform(byteOrder)=="bigEndian"} { finish_test return } # The sample server implementation does not work right when memory # management is enabled. # ifcapable (memorymanage||mutex_noop) { finish_test return } # Create some data to work with # do_test server1-1.1 { execsql { CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(1,'abcdefgh'); INSERT INTO t1 SELECT a+1, b||b FROM t1; INSERT INTO t1 SELECT a+2, b||b FROM t1; INSERT INTO t1 SELECT a+4, b||b FROM t1; SELECT count(*), max(length(b)) FROM t1; } } {8 64} # Interleave two threads on read access. Then make sure a third # thread can write the database. In other words: # # read-lock A # read-lock B # unlock A # unlock B # write-lock C # do_test server1-1.2 { client_create A test.db client_create B test.db client_create C test.db client_compile A {SELECT a FROM t1} client_step A client_result A } SQLITE_ROW do_test server1-1.3 { client_argc A } 1 do_test server1-1.4 { client_argv A 0 } 1 do_test server1-1.5 { client_compile B {SELECT b FROM t1} client_step B client_result B } SQLITE_ROW do_test server1-1.6 { client_argc B } 1 do_test server1-1.7 { client_argv B 0 } abcdefgh do_test server1-1.8 { client_finalize A client_result A } SQLITE_OK do_test server1-1.9 { client_finalize B client_result B } SQLITE_OK do_test server1-1.10 { client_compile C {CREATE TABLE t2(x,y)} client_step C client_result C } SQLITE_DONE do_test server1-1.11 { client_finalize C client_result C } SQLITE_OK do_test server1-1.12 { catchsql {SELECT name FROM sqlite_master} execsql {SELECT name FROM sqlite_master} } {t1 t2} # Read from table t1. Do not finalize the statement. This # will leave the lock pending. # do_test server1-2.1 { client_halt * client_create A test.db client_compile A {SELECT a FROM t1} client_step A client_result A } SQLITE_ROW # Read from the same table from another thread. This is allows. # do_test server1-2.2 { client_create B test.db client_compile B {SELECT b FROM t1} client_step B client_result B } SQLITE_ROW # Write to a different table from another thread. This is allowed # because in server mode with a shared cache we have table-level locking. # do_test server1-2.3 { client_create C test.db client_compile C {INSERT INTO t2 VALUES(98,99)} client_step C client_result C client_finalize C client_result C } SQLITE_OK # But we cannot insert into table t1 because threads A and B have it locked. # do_test server1-2.4 { client_compile C {INSERT INTO t1 VALUES(98,99)} client_step C client_result C client_finalize C client_result C } SQLITE_LOCKED do_test server1-2.5 { client_finalize B client_wait B client_compile C {INSERT INTO t1 VALUES(98,99)} client_step C client_result C client_finalize C client_result C } SQLITE_LOCKED # Insert into t1 is successful after finishing the other two threads. do_test server1-2.6 { client_finalize A client_wait A client_compile C {INSERT INTO t1 VALUES(98,99)} client_step C client_result C client_finalize C client_result C } SQLITE_OK client_halt * sqlite3_enable_shared_cache 0 finish_test |
Changes to test/sessionfuzz.c.
︙ | ︙ | |||
694 695 696 697 698 699 700 | " 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> | < | < < < < < | 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){ |
︙ | ︙ |
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 173 174 | # Commit the connection 1 transaction. execsql { COMMIT; } } {} do_test shared-$av.2.1 { # Open connection db3 to the database. Use a different path to the same # file so that db3 does *not* share the same pager cache as db and db2 # (there should be two open file handles). if {$::tcl_platform(platform)=="unix"} { sqlite3 db3 ./test.db } 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 { |
︙ | ︙ | |||
794 795 796 797 798 799 800 | 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"} { | | | 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 | 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 ./test.db } 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 | # 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 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 $alternative_name } catchsql {select count(*) from sqlite_master} db3 } {1 {database is locked}} db1 close db2 close db3 close |
︙ | ︙ |
Changes to test/shared9.test.
︙ | ︙ | |||
15 16 17 18 19 20 21 | # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/lock_common.tcl set testprefix shared9 | | | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/lock_common.tcl set testprefix shared9 ifcapable !view||!trigger { finish_test return } db close set enable_shared_cache [sqlite3_enable_shared_cache 1] |
︙ | ︙ |
Changes to test/sharedA.test.
︙ | ︙ | |||
15 16 17 18 19 20 21 | set testdir [file dirname $argv0] source $testdir/tester.tcl if {[run_thread_tests]==0} { finish_test ; return } db close set ::testprefix sharedA | < < < < < | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | set testdir [file dirname $argv0] source $testdir/tester.tcl if {[run_thread_tests]==0} { finish_test ; return } db close set ::testprefix sharedA if {[atomic_batch_write test.db]} { finish_test return } set ::enable_shared_cache [sqlite3_enable_shared_cache 1] |
︙ | ︙ |
Changes to test/sharedB.test.
︙ | ︙ | |||
20 21 22 23 24 25 26 | set testdir [file dirname $argv0] source $testdir/tester.tcl if {[run_thread_tests]==0} { finish_test ; return } db close set ::testprefix sharedB | < < < < < | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | set testdir [file dirname $argv0] source $testdir/tester.tcl if {[run_thread_tests]==0} { finish_test ; return } db close set ::testprefix sharedB set ::enable_shared_cache [sqlite3_enable_shared_cache 1] #------------------------------------------------------------------------- # do_test 1.1 { sqlite3 db1 test.db sqlite3 db2 test.db |
︙ | ︙ |
Changes to test/shell1.test.
︙ | ︙ | |||
14 15 16 17 18 19 20 | # # 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. | < < | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | # # 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 #---------------------------------------------------------------------------- # Test cases shell1-1.*: Basic command line option handling. # |
︙ | ︙ | |||
49 50 51 52 53 54 55 | 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" | | < < < < | | 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 | 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: near "FOO": syntax error}} # -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 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: near "BAD": syntax error}} # -echo print commands before execution do_test shell1-1.4.1 { catchcmd "-echo test.db" "" } {0 {}} # -[no]header turn headers on or off |
︙ | ︙ | |||
201 202 203 204 205 206 207 | 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" | | | | 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | 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 column csv html insert line list quote tabs tcl}} do_test shell1-2.2.6 { catchcmd "test.db" ".mode \'insert FOO" } {1 {Error: mode should be one of: ascii column csv html insert line list quote 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" |
︙ | ︙ | |||
232 233 234 235 236 237 238 | 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" | | < | 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 | 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 column csv html insert line list quote 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}} 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 { |
︙ | ︙ | |||
300 301 302 303 304 305 306 | [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} | < | | | | | 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 | [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} 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" |
︙ | ︙ | |||
392 393 394 395 396 397 398 | [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" | | | > > > | | 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 | [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 {Usage: .import FILE TABLE}} do_test shell1-3.11.2 { catchcmd "test.db" ".import FOO" } {1 {Usage: .import FILE TABLE}} #do_test shell1-3.11.2 { # catchcmd "test.db" ".import FOO BAR" #} {1 {Error: no such table: BAR}} do_test shell1-3.11.3 { # too many arguments catchcmd "test.db" ".import FOO BAR BAD" } {1 {Usage: .import FILE TABLE}} # .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 {}} |
︙ | ︙ | |||
433 434 435 436 437 438 439 | # 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" | | | 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 | # 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 column csv html insert line list quote 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 { |
︙ | ︙ | |||
462 463 464 465 466 467 468 469 470 471 472 473 474 475 | do_test shell1-3.13.10 { catchcmd "test.db" ".mode tcl" } {0 {}} do_test shell1-3.13.11 { # extra arguments ignored catchcmd "test.db" ".mode tcl BAD" } {0 {}} # .nullvalue STRING Print STRING in place of NULL values do_test shell1-3.14.1 { catchcmd "test.db" ".nullvalue" } {1 {Usage: .nullvalue STRING}} do_test shell1-3.14.2 { catchcmd "test.db" ".nullvalue FOO" | > > > > > > > > > > > | 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 | do_test shell1-3.13.10 { catchcmd "test.db" ".mode tcl" } {0 {}} do_test shell1-3.13.11 { # 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 column csv html insert line list quote tabs tcl}} do_test shell1-3.13.13 { catchcmd "test.db" ".mode li" } {1 {Error: mode should be one of: ascii column csv html insert line list quote 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" } {1 {Usage: .nullvalue STRING}} do_test shell1-3.14.2 { catchcmd "test.db" ".nullvalue FOO" |
︙ | ︙ | |||
485 486 487 488 489 490 491 | } {0 {}} do_test shell1-3.15.2 { catchcmd "test.db" ".output FOO" } {0 {}} do_test shell1-3.15.3 { # too many arguments catchcmd "test.db" ".output FOO BAD" | | < < < < < < < | < < < < < < < | 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 | } {0 {}} do_test shell1-3.15.2 { catchcmd "test.db" ".output FOO" } {0 {}} do_test shell1-3.15.3 { # too many arguments catchcmd "test.db" ".output FOO BAD" } {1 {Usage: .output [-e|-x|FILE]}} # .output stdout Send output to the screen do_test shell1-3.16.1 { catchcmd "test.db" ".output stdout" } {0 {}} do_test shell1-3.16.2 { # too many arguments catchcmd "test.db" ".output stdout BAD" } {1 {Usage: .output [-e|-x|FILE]}} # .prompt MAIN CONTINUE Replace the standard prompts do_test shell1-3.17.1 { catchcmd "test.db" ".prompt" } {0 {}} do_test shell1-3.17.2 { catchcmd "test.db" ".prompt FOO" |
︙ | ︙ | |||
575 576 577 578 579 580 581 | } {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" | | < | | 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 | } {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? ?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; } catchcmd "test.db" ".schema" } {0 {CREATE TABLE t1(x); CREATE VIEW v2 AS SELECT x+1 AS y FROM t1 /* v2(y) */; CREATE VIEW v1 AS SELECT y+1 FROM v2 /* v1("y+1") */;}} db eval {DROP VIEW v1; DROP VIEW v2; DROP TABLE t1;} } # .separator STRING Change column separator used by output and .import do_test shell1-3.22.1 { catchcmd "test.db" ".separator" } {1 {Usage: .separator COL ?ROW?}} do_test shell1-3.22.2 { |
︙ | ︙ | |||
630 631 632 633 634 635 636 | # 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" | | | | 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 | # 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}} 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?}} # 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); |
︙ | ︙ | |||
702 703 704 705 706 707 708 | # 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 { | | | | 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 | # 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.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.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" |
︙ | ︙ | |||
1010 1011 1012 1013 1014 1015 1016 | "[" "]" "\\{" "\\}" ";" "$"} 7} | < < < < < < | 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 | "[" "]" "\\{" "\\}" ";" "$"} 7} # Test using arbitrary byte data with the shell via standard input/output. # do_test shell1-5.0 { # # NOTE: Skip NUL byte because it appears to be incompatible with command # shell argument parsing. # |
︙ | ︙ | |||
1165 1166 1167 1168 1169 1170 1171 | CREATE TABLE ___ (x TEXT PRIMARY KEY);}} do_test shell1-7.1.7 { catchcmd "test.db" ".schema \\\\_\\\\_\\\\_" } {0 {CREATE TABLE ___ (x TEXT PRIMARY KEY);}} } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1150 1151 1152 1153 1154 1155 1156 1157 | 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 |
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 { set rc [catch { eval exec $CLI \":memory:\" \"select+3\" \"select+4\" } msg] list $rc $msg } {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: too many levels of trigger recursion}} # 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 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 | 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 catchcmd "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; } } {0 {CREATE TABLE foo1(a); INSERT INTO foo1(a) VALUES(1); CREATE TABLE foo2(b); INSERT INTO foo2(b) VALUES(1); SELECT * FROM foo1; 1 SELECT * FROM foo2; 1 INSERT INTO foo1(a) VALUES(2); INSERT INTO foo2(b) VALUES(2); SELECT * FROM foo1; 1 2 SELECT * FROM foo2; 1 2 }} # 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 catchcmd "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); SELECT * FROM foo1; SELECT * FROM foo2; } } {0 {.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; a 1 SELECT * FROM foo2; b 1 INSERT INTO foo1(a) VALUES(2); INSERT INTO foo2(b) VALUES(2); SELECT * FROM foo1; a 1 2 SELECT * FROM foo2; b 1 2 }} finish_test |
Changes to test/shell3.test.
︙ | ︙ | |||
14 15 16 17 18 19 20 | # $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. | < | < | 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. |
︙ | ︙ | |||
64 65 66 67 68 69 70 | catchcmd "foo.db \"CREATE TABLE t1(a); DROP TABLE t1;\"" } {0 {}} do_test shell3-1.6 { catchcmd "foo.db" ".tables" } {0 {}} do_test shell3-1.7 { catchcmd "foo.db \"CREATE TABLE\"" | | | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | catchcmd "foo.db \"CREATE TABLE t1(a); DROP TABLE t1;\"" } {0 {}} do_test shell3-1.6 { catchcmd "foo.db" ".tables" } {0 {}} do_test shell3-1.7 { catchcmd "foo.db \"CREATE TABLE\"" } {1 {Error: incomplete input}} #---------------------------------------------------------------------------- # shell3-2.*: Basic tests for running SQL file from command line. # # Run SQL file from command line do_test shell3-2.1 { |
︙ | ︙ | |||
94 95 96 97 98 99 100 | catchcmd "foo.db" "CREATE TABLE t1(a); DROP TABLE t1;" } {0 {}} do_test shell3-2.6 { catchcmd "foo.db" ".tables" } {0 {}} do_test shell3-2.7 { catchcmd "foo.db" "CREATE TABLE" | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 92 93 94 95 96 97 98 99 100 101 | catchcmd "foo.db" "CREATE TABLE t1(a); DROP TABLE t1;" } {0 {}} do_test shell3-2.6 { catchcmd "foo.db" ".tables" } {0 {}} do_test shell3-2.7 { catchcmd "foo.db" "CREATE TABLE" } {1 {Error: near line 1: incomplete input}} finish_test |
Changes to test/shell4.test.
︙ | ︙ | |||
15 16 17 18 19 20 21 | # 2015-03-19: Added tests for .trace # Test plan: # # shell4-1.*: Basic tests specific to the "stats" command. # shell4-2.*: Basic tests for ".trace" # shell4-3.*: The ".read" command takes the shell out of interactive mode | < | < | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | # 2015-03-19: Added tests for .trace # Test plan: # # shell4-1.*: Basic tests specific to the "stats" command. # shell4-2.*: Basic tests for ".trace" # shell4-3.*: The ".read" command takes the shell out of interactive mode # 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 #---------------------------------------------------------------------------- # Test cases shell4-1.*: Tests specific to the "stats" command. # |
︙ | ︙ | |||
64 65 66 67 68 69 70 | } {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?}} # NB. whitespace is important do_test shell4-1.4.1 { set res [catchcmd "test.db" {.show}] list [regexp {stats: off} $res] } {1} |
︙ | ︙ | |||
120 121 122 123 124 125 126 | } {/^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;" | < < < < < < | | < < < < < < < | 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | } {/^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;}} } do_test shell4-3.1 { set fd [open t1.txt wb] puts $fd "SELECT 'squirrel';" close $fd exec $::CLI :memory: --interactive ".read t1.txt" } {squirrel} do_test shell4-3.2 { set fd [open t1.txt wb] puts $fd "SELECT 'pound: \302\243';" close $fd exec $::CLI :memory: --interactive ".read t1.txt" } {pound: £} finish_test |
Changes to test/shell5.test.
︙ | ︙ | |||
17 18 19 20 21 22 23 | # Test plan: # # shell5-1.*: Basic tests specific to the ".import" command. # set testdir [file dirname $argv0] source $testdir/tester.tcl | | | | > > > | | 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 | # Test plan: # # shell5-1.*: Basic tests specific to the ".import" command. # 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 #---------------------------------------------------------------------------- # 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 {Usage: .import FILE TABLE}} do_test shell5-1.1.2 { catchcmd "test.db" ".import FOO" } {1 {Usage: .import FILE TABLE}} #do_test shell5-1.1.2 { # catchcmd "test.db" ".import FOO BAR" #} {1 {Error: no such table: BAR}} do_test shell5-1.1.3 { # too many arguments catchcmd "test.db" ".import FOO BAR BAD" } {1 {Usage: .import FILE TABLE}} # .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" |
︙ | ︙ | |||
84 85 86 87 88 89 90 | } {1 {Error: cannot open "FOO"}} # empty import file do_test shell5-1.4.2 { forcedelete shell5.csv set in [open shell5.csv w] close $in | | < | | < | < | < | < | | | | 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 | } {1 {Error: cannot open "FOO"}} # empty import file do_test shell5-1.4.2 { forcedelete shell5.csv set in [open shell5.csv w] close $in set res [catchcmd "test.db" {.import shell5.csv t1 SELECT COUNT(*) FROM t1;}] } {0 0} # import file with 1 row, 1 column (expecting 2 cols) do_test shell5-1.4.3 { set in [open shell5.csv w] puts $in "1" close $in set res [catchcmd "test.db" {.import shell5.csv t1}] } {1 {shell5.csv:1: expected 2 columns but found 1 - filling the rest with NULL}} # import file with 1 row, 3 columns (expecting 2 cols) do_test shell5-1.4.4 { set in [open shell5.csv w] puts $in "1|2|3" close $in set res [catchcmd "test.db" {.import shell5.csv t1}] } {1 {shell5.csv:1: expected 2 columns but found 3 - extras ignored}} # import file with 1 row, 2 columns do_test shell5-1.4.5 { set in [open shell5.csv w] puts $in "1|2" close $in set res [catchcmd "test.db" {DELETE FROM t1; .import shell5.csv t1 SELECT COUNT(*) FROM t1;}] } {0 1} # import file with 2 rows, 2 columns # note we end up with 3 rows because of the 1 row # imported above. do_test shell5-1.4.6 { set in [open shell5.csv w] puts $in "2|3" puts $in "3|4" close $in set res [catchcmd "test.db" {.import shell5.csv t1 SELECT COUNT(*) FROM t1;}] } {0 3} # import file with 1 row, 2 columns, using a comma do_test shell5-1.4.7 { set in [open shell5.csv w] puts $in "4,5" close $in set res [catchcmd "test.db" {.separator , .import shell5.csv t1 SELECT COUNT(*) FROM t1;}] } {0 4} # import file with 1 row, 2 columns, text data do_test shell5-1.4.8.1 { set in [open shell5.csv w] puts $in "5|Now is the time for all good men to come to the aid of their country." close $in |
︙ | ︙ | |||
258 259 260 261 262 263 264 | } close $in set res [catchcmd "test.db" {.mode csv .import shell5.csv t3 SELECT COUNT(*) FROM t3;}] } [list 0 $rows] | | | 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | } close $in set res [catchcmd "test.db" {.mode csv .import shell5.csv t3 SELECT COUNT(*) FROM t3;}] } [list 0 $rows] # Inport from a pipe. (Unix only, as it requires "awk") if {$tcl_platform(platform)=="unix"} { do_test shell5-1.8 { forcedelete test.db catchcmd test.db {.mode csv .import "|awk 'END{print \"x,y\";for(i=1;i<=5;i++){print i \",this is \" i}}'" t1 SELECT * FROM t1;} } {0 {1,"this is 1" |
︙ | ︙ | |||
457 458 459 460 461 462 463 | .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} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 455 456 457 458 459 460 461 462 | .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 |
Changes to test/shell8.test.
︙ | ︙ | |||
15 16 17 18 19 20 21 | set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix shell8 ifcapable !vtab { finish_test; return } | | | 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 shell8 ifcapable !vtab { finish_test; return } set CLI [test_find_cli] # Check to make sure the shell has been compiled with ".archive" support. # if {[string match {*unknown command*} [catchcmd :memory: .archive]]} { finish_test; return } |
︙ | ︙ | |||
40 41 42 43 44 45 46 | file mkdir [file dirname $path] set fd [open $path w] puts -nonewline $fd $d close $fd } } | < < < < | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | file mkdir [file dirname $path] set fd [open $path w] puts -nonewline $fd $d close $fd } } proc dir_to_list {dirname {n -1}} { if {$n<0} {set n [llength [file split $dirname]]} set res [list] foreach f [glob -nocomplain $dirname/*] { set mtime [file mtime $f] if {$::tcl_platform(platform)!="windows"} { |
︙ | ︙ | |||
170 171 172 173 174 175 176 | after 2000 catchcmd test_ar.db $x1 dir_to_list ar1 } $expected } } | | < < < < < < | < < | < < < < < < < | 166 167 168 169 170 171 172 173 174 175 176 177 | after 2000 catchcmd test_ar.db $x1 dir_to_list ar1 } $expected } } finish_test finish_test |
Changes to test/shrink.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 | # This file contains test cases for sqlite3_db_release_memory and # the PRAGMA shrink_memory statement. # set testdir [file dirname $argv0] source $testdir/tester.tcl test_set_config_pagecache 0 0 | < < < < < < < | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | # This file contains test cases for sqlite3_db_release_memory and # the PRAGMA shrink_memory statement. # set testdir [file dirname $argv0] source $testdir/tester.tcl test_set_config_pagecache 0 0 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 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 | > | 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 | 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; DROP TABLE IF EXISTS sqlite_stat3; 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 |
︙ | ︙ | |||
337 338 339 340 341 342 343 | } {/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); | | | 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 | } {/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 TABLE 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); |
︙ | ︙ | |||
368 369 370 371 372 373 374 | 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; } {} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 369 370 371 372 373 374 375 376 | 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; } {} finish_test |
Changes to test/skipscan2.test.
︙ | ︙ | |||
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} | > | 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | 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; ALTER TABLE people RENAME TO old_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} |
︙ | ︙ | |||
194 195 196 197 198 199 200 | 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; | | | 195 196 197 198 199 200 201 202 203 204 205 206 | 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 TABLE t3 USING PRIMARY KEY (ANY(a) AND b=?)} finish_test |
Changes to test/skipscan5.test.
︙ | ︙ | |||
37 38 39 40 41 42 43 | } 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<?*/} | | | | | | | | 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 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 TABLE t1*/} 4 "b > 18 AND b < 25" {/*ANY(a) AND b>? AND b<?*/} 5 "b > 16" {/*ANY(a) AND b>?*/} 6 "b > 5" {/*SCAN TABLE t1*/} 7 "b < 15" {/*SCAN TABLE 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 TABLE t1*/} 13 "b > '18' AND b < '25'" {/*ANY(a) AND b>? AND b<?*/} 14 "b > '16'" {/*ANY(a) AND b>?*/} 15 "b > '5'" {/*SCAN TABLE t1*/} 16 "b < '15'" {/*SCAN TABLE 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 | 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 TABLE t2*/} 3 { c > 'q' } {/*ANY(a) AND ANY(b) AND c>?*/} 4 { c > 'e' } {/*SCAN TABLE t2*/} 5 { c < 'q' } {/*SCAN TABLE 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 TABLE t3*/} 3 "b < X'5555'" {/*SCAN TABLE t3*/} 4 "b > X'5555'" {/*ANY(a) AND b>?*/} 5 "b > 'zzz'" {/*ANY(a) AND b>?*/} 6 "b < 'zzz'" {/*SCAN TABLE 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 TABLE 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 TABLE t2 USING INDEX t2_a (a=?)} finish_test |
Changes to test/sort.test.
︙ | ︙ | |||
591 592 593 594 595 596 597 | } {1 {UNIQUE constraint failed: t1.b, t1.a, t1.c}} reset_db do_execsql_test 17.1 { SELECT * FROM sqlite_master ORDER BY sql; } {} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 591 592 593 594 595 596 597 598 | } {1 {UNIQUE constraint failed: t1.b, t1.a, t1.c}} reset_db do_execsql_test 17.1 { SELECT * FROM sqlite_master ORDER BY sql; } {} finish_test |
Changes to test/sort4.test.
1 2 3 4 5 6 7 8 9 10 | # 2014 May 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. # #*********************************************************************** | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # 2014 May 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. # # The tests in this file are brute force tests of the multi-threaded # sorter. # set testdir [file dirname $argv0] |
︙ | ︙ |
Changes to test/sorterref.test.
︙ | ︙ | |||
10 11 12 13 14 15 16 | #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix sorterref | < < < < < < | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #*********************************************************************** # 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'); } |
︙ | ︙ |
Changes to test/speed1.test.
︙ | ︙ | |||
10 11 12 13 14 15 16 | #************************************************************************* # This file implements regression tests for SQLite library. The # focus of this script is measuring executing speed. # # $Id: speed1.test,v 1.11 2009/04/09 01:23:49 drh Exp $ # | < < | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #************************************************************************* # This file implements regression tests for SQLite library. The # focus of this script is measuring executing speed. # # $Id: speed1.test,v 1.11 2009/04/09 01:23:49 drh Exp $ # sqlite3_shutdown #sqlite3_config_scratch 29000 1 set old_lookaside [sqlite3_config_lookaside 1000 300] #sqlite3_config_pagecache 1024 10000 set testdir [file dirname $argv0] source $testdir/tester.tcl speed_trial_init speed1 # Set a uniform random seed expr srand(0) set sqlout [open speed1.txt w] proc tracesql {sql} { |
︙ | ︙ |
Changes to test/speed1p.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 | # focus of this script is measuring executing speed. # # This is a copy of speed1.test modified to user prepared statements. # # $Id: speed1p.test,v 1.7 2009/04/09 01:23:49 drh Exp $ # | < < | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | # focus of this script is measuring executing speed. # # This is a copy of speed1.test modified to user prepared statements. # # $Id: speed1p.test,v 1.7 2009/04/09 01:23:49 drh Exp $ # sqlite3_shutdown #sqlite3_config_scratch 29000 1 set old_lookaside [sqlite3_config_lookaside 2048 300] #sqlite3_config_pagecache 1024 11000 set testdir [file dirname $argv0] source $testdir/tester.tcl speed_trial_init speed1 sqlite3_memdebug_vfs_oom_test 0 # Set a uniform random seed expr srand(0) |
︙ | ︙ |
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 | /* ** 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" " --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" " --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" " --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" " --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" " --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 /* 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 */ 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 */ int nResult; /* Size of the current result */ char zResult[3000]; /* Text of the current result */ } 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); } /* ** 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; |
︙ | ︙ | |||
372 373 374 375 376 377 378 | } /* Start a new test case */ #define NAMEWIDTH 60 static const char zDots[] = "......................................................................."; | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | } /* Start a new test case */ #define NAMEWIDTH 60 static const char zDots[] = "......................................................................."; void speedtest1_begin_test(int iTestNum, const char *zTestName, ...){ int n = (int)strlen(zTestName); char *zName; va_list ap; va_start(ap, zTestName); zName = sqlite3_vmprintf(zTestName, ap); va_end(ap); n = (int)strlen(zName); if( n>NAMEWIDTH ){ zName[NAMEWIDTH] = 0; n = NAMEWIDTH; } if( g.bSqlOnly ){ printf("/* %4d - %s%.*s */\n", iTestNum, zName, NAMEWIDTH-n, zDots); }else{ printf("%4d - %s%.*s ", iTestNum, zName, NAMEWIDTH-n, zDots); fflush(stdout); } 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--; } if( g.bExplain ) printf("EXPLAIN "); |
︙ | ︙ | |||
487 488 489 490 491 492 493 | va_start(ap, zFormat); zSql = sqlite3_vmprintf(zFormat, ap); va_end(ap); if( g.bSqlOnly ){ printSql(zSql); }else{ char *zErrMsg = 0; | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 | va_start(ap, zFormat); zSql = sqlite3_vmprintf(zFormat, ap); va_end(ap); if( g.bSqlOnly ){ printSql(zSql); }else{ char *zErrMsg = 0; 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); va_end(ap); |
︙ | ︙ | |||
560 561 562 563 564 565 566 | /* Run an SQL statement previously prepared */ void speedtest1_run(void){ int i, n, len; if( g.bSqlOnly ) return; assert( g.pStmt ); g.nResult = 0; | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 | /* Run an SQL statement previously prepared */ void speedtest1_run(void){ int i, n, len; if( g.bSqlOnly ) return; assert( g.pStmt ); 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; } } } |
︙ | ︙ | |||
736 737 738 739 740 741 742 | 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"); | | | | | | 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 | 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 t1(a INTEGER %s, b INTEGER %s, c TEXT %s);", isTemp(9), g.zNN, g.zNN, g.zNN); speedtest1_prepare("INSERT INTO t1 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 t2(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 t2 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(); |
︙ | ︙ | |||
797 798 799 800 801 802 803 | 0, groupStep, groupFinal); #endif n = 25; speedtest1_begin_test(130, "%d SELECTS, numeric BETWEEN, unindexed", n); speedtest1_exec("BEGIN"); speedtest1_prepare( | | | | 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 | 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 t1\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 t1\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); |
︙ | ︙ | |||
839 840 841 842 843 844 845 | speedtest1_end_test(); n = 10; speedtest1_begin_test(142, "%d SELECTS w/ORDER BY, unindexed", n); speedtest1_exec("BEGIN"); speedtest1_prepare( | | | | | | | | | | | 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 | 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 t1 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 t1 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 t1(b);"); speedtest1_exec("CREATE INDEX t1c ON t1(c);"); speedtest1_exec("CREATE UNIQUE INDEX t2b ON t2(b);"); speedtest1_exec("CREATE INDEX t2c ON t2(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 t1\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 t2\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 t1\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); } |
︙ | ︙ | |||
959 960 961 962 963 964 965 | " 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)"); | | | | | | | | | | | | 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 | " 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 t1"); speedtest1_exec("COMMIT"); speedtest1_end_test(); n = sz; speedtest1_begin_test(190, "DELETE and REFILL one table", n); speedtest1_exec("DELETE FROM t2;"); speedtest1_exec("INSERT INTO t2 SELECT * FROM t1;"); 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 t2 ADD COLUMN d DEFAULT 123"); speedtest1_exec("SELECT sum(d) FROM t2"); speedtest1_end_test(); n = sz/5; speedtest1_begin_test(230, "%d UPDATES, numeric BETWEEN, indexed", n); speedtest1_exec("BEGIN"); speedtest1_prepare( "UPDATE t2 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 t2 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 t2 SET d=b*4"); speedtest1_end_test(); speedtest1_begin_test(260, "Query added column after filling"); speedtest1_exec("SELECT sum(d) FROM t2"); speedtest1_end_test(); n = sz/5; speedtest1_begin_test(270, "%d DELETEs, numeric BETWEEN, indexed", n); speedtest1_exec("BEGIN"); speedtest1_prepare( "DELETE FROM t2 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(); |
︙ | ︙ | |||
1056 1057 1058 1059 1060 1061 1062 | speedtest1_run(); } speedtest1_exec("COMMIT"); speedtest1_end_test(); speedtest1_begin_test(290, "Refill two %d-row tables using REPLACE", sz); | | | | | | | | | | | | | | 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 | speedtest1_run(); } speedtest1_exec("COMMIT"); speedtest1_end_test(); speedtest1_begin_test(290, "Refill two %d-row tables using REPLACE", sz); speedtest1_exec("REPLACE INTO t2(a,b,c) SELECT a,b,c FROM t1"); speedtest1_exec("REPLACE INTO t3(a,b,c) SELECT a,b,c FROM t1"); speedtest1_end_test(); speedtest1_begin_test(300, "Refill a %d-row table using (b&1)==(a&1)", sz); speedtest1_exec("DELETE FROM t2;"); speedtest1_exec("INSERT INTO t2(a,b,c)\n" " SELECT a,b,c FROM t1 WHERE (b&1)==(a&1);"); speedtest1_exec("INSERT INTO t2(a,b,c)\n" " SELECT a,b,c FROM t1 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 t1.c FROM t1, t2, t3, t4\n" " WHERE t4.a BETWEEN ?1 AND ?2\n" " AND t3.a=t4.b\n" " AND t2.a=t3.b\n" " AND t1.c=t2.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 t2 WHERE 5+t2.b=t1.b) AND rowid<?1), max(c)\n" " FROM t1 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; |
︙ | ︙ | |||
1117 1118 1119 1120 1121 1122 1123 | sqlite3_bind_int(g.pStmt, 1, (sqlite3_int64)x1); sqlite3_bind_text(g.pStmt, 2, zNum, -1, SQLITE_STATIC); speedtest1_run(); } speedtest1_exec("COMMIT"); speedtest1_end_test(); speedtest1_begin_test(410, "%d SELECTS on an IPK", n); | < < < < < < < < < < < < | 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 | sqlite3_bind_int(g.pStmt, 1, (sqlite3_int64)x1); sqlite3_bind_text(g.pStmt, 2, zNum, -1, SQLITE_STATIC); speedtest1_run(); } speedtest1_exec("COMMIT"); speedtest1_end_test(); speedtest1_begin_test(410, "%d SELECTS on an IPK", n); speedtest1_prepare("SELECT b FROM t5 WHERE a=?1; -- %d times",n); for(i=1; i<=n; i++){ x1 = swizzle(i,maxb); sqlite3_bind_int(g.pStmt, 1, (sqlite3_int64)x1); speedtest1_run(); } speedtest1_end_test(); sz = n = g.szTest*700; zNum[0] = 0; maxb = roundup_allones(sz/3); speedtest1_begin_test(500, "%d REPLACE on TEXT PK", n); speedtest1_exec("BEGIN"); |
︙ | ︙ | |||
1156 1157 1158 1159 1160 1161 1162 | sqlite3_bind_int(g.pStmt, 2, i); sqlite3_bind_text(g.pStmt, 1, zNum, -1, SQLITE_STATIC); speedtest1_run(); } speedtest1_exec("COMMIT"); speedtest1_end_test(); speedtest1_begin_test(510, "%d SELECTS on a TEXT PK", n); | < < < < < < < | 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 | sqlite3_bind_int(g.pStmt, 2, i); sqlite3_bind_text(g.pStmt, 1, zNum, -1, SQLITE_STATIC); speedtest1_run(); } speedtest1_exec("COMMIT"); speedtest1_end_test(); speedtest1_begin_test(510, "%d SELECTS on a TEXT PK", n); speedtest1_prepare("SELECT b FROM t6 WHERE a=?1; -- %d times",n); for(i=1; i<=n; i++){ x1 = swizzle(i,maxb); speedtest1_numbername(x1, zNum, sizeof(zNum)); sqlite3_bind_text(g.pStmt, 1, zNum, -1, SQLITE_STATIC); speedtest1_run(); } speedtest1_end_test(); speedtest1_begin_test(520, "%d SELECT DISTINCT", n); speedtest1_exec("SELECT DISTINCT b FROM t5;"); speedtest1_exec("SELECT DISTINCT b FROM t6;"); speedtest1_end_test(); |
︙ | ︙ | |||
1330 1331 1332 1333 1334 1335 1336 | 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" | | | | | 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 | 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" " t1(x) AS (VALUES(2) UNION ALL SELECT x+2 FROM t1 WHERE x<%d),\n" " t2(y) AS (VALUES(3) UNION ALL SELECT y+3 FROM t2 WHERE y<%d)\n" "SELECT count(x), avg(x) FROM (\n" " SELECT x FROM t1 EXCEPT SELECT y FROM t2 ORDER BY 1\n" ");", nElem, nElem ); speedtest1_run(); speedtest1_end_test(); } |
︙ | ︙ | |||
1366 1367 1368 1369 1370 1371 1372 | 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"); | | | | | | | | < < < < < < < < < < < < < | 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 | 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 t1(a REAL %s, b REAL %s);", isTemp(1), g.zNN, g.zNN); speedtest1_prepare("INSERT INTO t1 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 t1 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 t1(a);"); speedtest1_exec("CREATE INDEX t1b ON t1(b);"); speedtest1_exec("CREATE INDEX t1ab ON t1(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 t1 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(); } #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. |
︙ | ︙ | |||
1506 1507 1508 1509 1510 1511 1512 | 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"); | | | | | 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 | 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 t1(id INTEGER PRIMARY KEY,x0,x1,y0,y1,z0,z1)"); speedtest1_exec("INSERT INTO t1 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 t1 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", |
︙ | ︙ | |||
1554 1555 1556 1557 1558 1559 1560 | 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"); | | | 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 | 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 t1 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", |
︙ | ︙ | |||
1650 1651 1652 1653 1654 1655 1656 | 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"); | | | 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 | 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 t1"); 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. |
︙ | ︙ | |||
1935 1936 1937 1938 1939 1940 1941 | char zNum[2000]; /* A number name */ const int NROW = 500*g.szTest; const int NROW2 = 100*g.szTest; speedtest1_exec( "BEGIN;" | | | | | | | | | | 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 | char zNum[2000]; /* A number name */ const int NROW = 500*g.szTest; const int NROW2 = 100*g.szTest; speedtest1_exec( "BEGIN;" "CREATE TABLE t1(rowid INTEGER PRIMARY KEY, i INTEGER, t TEXT);" "CREATE TABLE t2(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 t1;" "CREATE VIEW v2 AS SELECT rowid, i, t FROM t2;" "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 t1(t);" "CREATE INDEX i2 ON t2(t);" "CREATE INDEX i3 ON t3(t);" "COMMIT;" ); speedtest1_begin_test(100, "speed4p-join1"); speedtest1_prepare( "SELECT * FROM t1, t2, t3 WHERE t1.oid = t2.oid AND t2.oid = t3.oid" ); speedtest1_run(); speedtest1_end_test(); speedtest1_begin_test(110, "speed4p-join2"); speedtest1_prepare( "SELECT * FROM t1, t2, t3 WHERE t1.t = t2.t AND t2.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); |
︙ | ︙ | |||
2005 2006 2007 2008 2009 2010 2011 | speedtest1_run(); } } speedtest1_end_test(); speedtest1_begin_test(150, "speed4p-subselect1"); speedtest1_prepare("SELECT " | | | | | | 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 | speedtest1_run(); } } speedtest1_end_test(); speedtest1_begin_test(150, "speed4p-subselect1"); speedtest1_prepare("SELECT " "(SELECT t FROM t1 WHERE rowid = ?1)," "(SELECT t FROM t2 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 t1 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 t1"); 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);" |
︙ | ︙ | |||
2185 2186 2187 2188 2189 2190 2191 | } #endif #if SQLITE_VERSION_NUMBER<3006018 # define sqlite3_sourceid(X) "(before 3.6.18)" #endif | < < < < > < < < | < < < < < < < < < < < < < < | < < < > > | < < | | | | < < | < < | < | < < < < < < < < < < < < < < < < > | | > < < < < < < < | | | | < < < < < < < < < < < < < < | < < < < < < < < < | < | < < < < < < < < < < < < < < | < | < < < < < < | 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 | } #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){ int doAutovac = 0; /* True for --autovacuum */ int cacheSize = 0; /* Desired cache size. 0 means default */ int doExclusive = 0; /* True for --exclusive */ int nHeap = 0, mnHeap = 0; /* Heap size from --heap */ int doIncrvac = 0; /* True for --incrvacuum */ const char *zJMode = 0; /* Journal mode */ const char *zKey = 0; /* Encryption key */ int nLook = -1, szLook = 0; /* --lookaside configuration */ 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 */ const 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 */ /* Display the version of SQLite being tested */ printf("-- Speedtest1 for SQLite %s %.50s\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,"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]); i += 2; }else if( strcmp(z,"incrvacuum")==0 ){ doIncrvac = 1; }else if( strcmp(z,"journal")==0 ){ if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]); zJMode = argv[++i]; }else if( strcmp(z,"key")==0 ){ 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]); doPCache = 1; i += 2; }else if( strcmp(z,"primarykey")==0 ){ g.zPK = "PRIMARY KEY"; }else if( strcmp(z,"repeat")==0 ){ if( i>=argc-1 ) fatal_error("missing arguments on %s\n", argv[i]); g.nRepeat = integerValue(argv[i+1]); i += 1; }else if( strcmp(z,"reprepare")==0 ){ g.bReprepare = 1; #if SQLITE_VERSION_NUMBER>=3006000 }else if( strcmp(z,"serialized")==0 ){ sqlite3_config(SQLITE_CONFIG_SERIALIZED); }else if( strcmp(z,"singlethread")==0 ){ sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); #endif }else if( strcmp(z,"sqlonly")==0 ){ g.bSqlOnly = 1; }else if( strcmp(z,"shrink-memory")==0 ){ g.bMemShrink = 1; }else if( strcmp(z,"size")==0 ){ if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]); g.szTest = integerValue(argv[++i]); }else if( strcmp(z,"stats")==0 ){ showStats = 1; }else if( strcmp(z,"temp")==0 ){ if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]); i++; if( argv[i][0]<'0' || argv[i][0]>'9' || argv[i][1]!=0 ){ fatal_error("argument to --temp should be integer between 0 and 9"); } g.eTemp = argv[i][0] - '0'; }else if( strcmp(z,"testset")==0 ){ if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]); zTSet = argv[++i]; }else if( strcmp(z,"trace")==0 ){ doTrace = 1; }else if( strcmp(z,"threads")==0 ){ if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]); 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 ){ g.zWR = "WITHOUT ROWID"; g.zPK = "PRIMARY KEY"; }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]); } }else if( zDbName==0 ){ zDbName = argv[i]; }else{ fatal_error("surplus argument: %s\nUse \"%s -?\" for help\n", argv[i], argv[0]); } } if( zDbName!=0 ) unlink(zDbName); #if SQLITE_VERSION_NUMBER>=3006001 if( nHeap>0 ){ pHeap = malloc( nHeap ); if( pHeap==0 ) fatal_error("cannot allocate %d-byte heap\n", nHeap); rc = sqlite3_config(SQLITE_CONFIG_HEAP, pHeap, nHeap, mnHeap); if( rc ) fatal_error("heap configuration failed: %d\n", rc); } if( doPCache ){ if( nPCache>0 && szPCache>0 ){ pPCache = malloc( nPCache*(sqlite3_int64)szPCache ); if( pPCache==0 ) fatal_error("cannot allocate %lld-byte pcache\n", nPCache*(sqlite3_int64)szPCache); } 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 /* Open the database and the input file */ if( sqlite3_open(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 /* 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( mmapSize>0 ){ speedtest1_exec("PRAGMA mmap_size=%d", mmapSize); } speedtest1_exec("PRAGMA threads=%d", nThread); if( zKey ){ speedtest1_exec("PRAGMA key('%s')", zKey); } |
︙ | ︙ | |||
2509 2510 2511 2512 2513 2514 2515 | speedtest1_exec("PRAGMA locking_mode=EXCLUSIVE"); } if( zJMode ){ speedtest1_exec("PRAGMA journal_mode=%s", zJMode); } if( g.bExplain ) printf(".explain\n.echo on\n"); | < < < < < < < < < < < < | | | | | | | | | | | | | | | | | | | < < | < < < < < < < < < < < | < < < < < < < < < < < < < | 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 | speedtest1_exec("PRAGMA locking_mode=EXCLUSIVE"); } if( zJMode ){ speedtest1_exec("PRAGMA journal_mode=%s", zJMode); } if( g.bExplain ) printf(".explain\n.echo on\n"); if( strcmp(zTSet,"main")==0 ){ testset_main(); }else if( strcmp(zTSet,"debug1")==0 ){ testset_debug1(); }else if( strcmp(zTSet,"orm")==0 ){ testset_orm(); }else if( strcmp(zTSet,"cte")==0 ){ testset_cte(); }else if( strcmp(zTSet,"fp")==0 ){ testset_fp(); }else if( strcmp(zTSet,"trigger")==0 ){ testset_trigger(); }else if( strcmp(zTSet,"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", zTSet); } speedtest1_final(); if( showStats ){ sqlite3_exec(g.db, "PRAGMA compile_options", xCompileOptions, 0, 0); } /* Database connection statistics printed after both prepared statements |
︙ | ︙ | |||
2632 2633 2634 2635 2636 2637 2638 | #endif #ifdef __linux__ if( showStats ){ displayLinuxIoStats(stdout); } #endif | < < < < < < < < < < < < < | 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 | #endif #ifdef __linux__ if( showStats ){ displayLinuxIoStats(stdout); } #endif /* Release memory */ free( pLook ); free( pPCache ); free( pHeap ); return 0; } |
Changes to test/sqldiff1.test.
︙ | ︙ | |||
31 32 33 34 35 36 37 | 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'); | < < < < < < < < < | 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 |
Changes to test/sqllimits1.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 | # This file contains tests to verify that the limits defined in # sqlite source file limits.h are enforced. # # $Id: sqllimits1.test,v 1.33 2009/06/25 01:47:12 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl | < | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # This file contains tests to verify that the limits defined in # sqlite source file limits.h are enforced. # # $Id: sqllimits1.test,v 1.33 2009/06/25 01:47:12 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Verify that the default per-connection limits are the same as # the compile-time hard limits. # sqlite3 db2 :memory: do_test sqllimits1-1.1 { sqlite3_limit db SQLITE_LIMIT_LENGTH -1 |
︙ | ︙ | |||
290 291 292 293 294 295 296 | 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 | 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 { set ::str [string repeat %J 2100] catchsql { SELECT 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}} |
︙ | ︙ | |||
344 345 346 347 348 349 350 | } do_test sqllimits1-5.14.6 { catch {sqlite3_bind_text $::STMT 1 $::str1 $np1} res set res } {SQLITE_TOOBIG} ifcapable utf16 { do_test sqllimits1-5.14.7 { | | | 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 | } do_test sqllimits1-5.14.6 { catch {sqlite3_bind_text $::STMT 1 $::str1 $np1} res set res } {SQLITE_TOOBIG} ifcapable utf16 { do_test sqllimits1-5.14.7 { catch {sqlite3_bind_text16 $::STMT 1 $::str1 $np1} res set res } {SQLITE_TOOBIG} } do_test sqllimits1-5.14.8 { set n [expr {$np1-1}] catch {sqlite3_bind_text $::STMT 1 $::str1 $n} res set res |
︙ | ︙ | |||
375 376 377 378 379 380 381 | } } {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 { | | | | | 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 | } } {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'" } [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'" } [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-12}]] 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}} } |
︙ | ︙ | |||
866 867 868 869 870 871 872 | } } {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. # | < < < < < | | | | | | | | < > | | 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 | } } {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. # 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 ( |
︙ | ︙ | |||
907 908 909 910 911 912 913 | # 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}} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 895 896 897 898 899 900 901 902 | # 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 |
Deleted test/startup.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
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 | 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_execsql_test stat-0.1 { DROP TABLE dbstat; 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 |
︙ | ︙ | |||
57 58 59 60 61 62 63 | 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; | | | 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | 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_master / 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); |
︙ | ︙ | |||
83 84 85 86 87 88 89 | 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 | | | | | 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 | 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_master'; } } {sqlite_master / 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_master'; } [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 \ |
︙ | ︙ | |||
132 133 134 135 136 137 138 | 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 \ ] | < < < < < < < < | < < < < < < < < < | 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 | 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 FROM stat WHERE name != 'sqlite_master'; } [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-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 \ |
︙ | ︙ | |||
215 216 217 218 219 220 221 | 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 \ ] | < < < < < < < < < < | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | 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'); } { sqlite_master / 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_master / 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_master / 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_master / 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_master / 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_master / 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"}} 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 | execsql { SELECT 1 FROM sqlite_master LIMIT 1 } } -body { execsql { SELECT count(*) FROM sss } } -test { faultsim_test_result {0 8} } finish_test |
Deleted test/strict1.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/strict2.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/subquery.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2005 January 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 script is testing correlated subqueries # | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # 2005 January 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 script is testing correlated subqueries # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !subquery { finish_test return |
︙ | ︙ | |||
473 474 475 476 477 478 479 | INSERT INTO t4 VALUES('four',4); CREATE TABLE t5(a,b); INSERT INTO t5 VALUES(1,11); INSERT INTO t5 VALUES(2,22); INSERT INTO t5 VALUES(3,33); INSERT INTO t5 VALUES(4,44); SELECT b FROM t5 WHERE a IN | | | 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 | INSERT INTO t4 VALUES('four',4); CREATE TABLE t5(a,b); INSERT INTO t5 VALUES(1,11); INSERT INTO t5 VALUES(2,22); INSERT INTO t5 VALUES(3,33); INSERT INTO t5 VALUES(4,44); SELECT b FROM t5 WHERE a IN (SELECT callcnt(y)+0 FROM t4 WHERE x="two") } } {22} do_test subquery-5.2 { # This is the key test. The subquery should have only run once. If # The double-quoted identifier "two" were causing the subquery to be # processed as a correlated subquery, then it would have run 4 times. set callcnt |
︙ | ︙ | |||
590 591 592 593 594 595 596 | # do_execsql_test subquery-8.1 { CREATE TABLE t8(a TEXT, b INT); SELECT (SELECT 0 FROM (SELECT * FROM t1)) AS x WHERE x; SELECT (SELECT 0 FROM (SELECT * FROM (SELECT 0))) AS x WHERE x; } {} | | > > > > | | | | < < < < | > | | < | > > | | > > | > > > > > > | > > > > > > > > > > > > | 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 | # do_execsql_test subquery-8.1 { CREATE TABLE t8(a TEXT, b INT); SELECT (SELECT 0 FROM (SELECT * FROM t1)) AS x WHERE x; SELECT (SELECT 0 FROM (SELECT * FROM (SELECT 0))) AS x WHERE x; } {} # 2023-09-15 # Query planner performance regression reported by private email # on 2023-09-14, caused by VIEWSCAN optimization of check-in 609fbb94b8f01d67 # from 2022-09-01. # reset_db do_execsql_test subquery-10.1 { CREATE TABLE t1(aa TEXT, bb INT, cc TEXT); CREATE INDEX x11 on t1(bb); CREATE INDEX x12 on t1(aa); CREATE TABLE t2(aa TEXT, xx INT); ANALYZE sqlite_master; INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES('t1', 'x11', '156789 28'); INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES('t1', 'x12', '156789 1'); ANALYZE sqlite_master; } do_eqp_test subquery-10.2 { WITH v1(aa,cc,bb) AS (SELECT aa, cc, bb FROM t1 WHERE bb=12345), v2(aa,mx) AS (SELECT aa, max(xx) FROM t2 GROUP BY aa) SELECT * FROM v1 JOIN v2 ON v1.aa=v2.aa; } { QUERY PLAN |--MATERIALIZE xxxxxx | |--SCAN TABLE t2 | `--USE TEMP B-TREE FOR GROUP BY |--SEARCH TABLE t1 USING INDEX x11 (bb=?) `--SEARCH SUBQUERY xxxxxx USING AUTOMATIC COVERING INDEX (aa=?) } # ^^^^^^^^^^^^^ # Prior to the fix the incorrect (slow) plan caused by the # VIEWSCAN optimization was: # # QUERY PLAN # |--CO-ROUTINE v2 # | |--SCAN t2 # | `--USE TEMP B-TREE FOR GROUP BY # |--SCAN v2 # `--SEARCH t1 USING INDEX x12 (aa=?) # finish_test |
Changes to test/substr.test.
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 | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 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. # # $Id: substr.test,v 1.7 2009/02/03 13:10:54 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !tclvar { finish_test return |
︙ | ︙ | |||
34 35 36 37 38 39 40 | execsql { SELECT substr(t, $i1, $i2) FROM t1 } }] [list $result] set qstr '[string map {' ''} $string]' do_test substr-$id.2 [subst { execsql { | | | | 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 | execsql { SELECT substr(t, $i1, $i2) FROM t1 } }] [list $result] set qstr '[string map {' ''} $string]' do_test substr-$id.2 [subst { execsql { SELECT substr($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(substr(x'$hex', $i1, $i2)) } }] [list $hexresult] } # Basic SUBSTR functionality # substr-test 1.1 abcdefg 1 1 a |
︙ | ︙ | |||
88 89 90 91 92 93 94 | 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 { | | | 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | 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(substr('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 # |
︙ | ︙ | |||
144 145 146 147 148 149 150 | execsql { SELECT substr(t, $idx) FROM t1 } }] [list $result] set qstr '[string map {' ''} $string]' do_test substr-$id.2 [subst { execsql { | | | 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | execsql { SELECT substr(t, $idx) FROM t1 } }] [list $result] set qstr '[string map {' ''} $string]' do_test substr-$id.2 [subst { execsql { SELECT substr($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/subtype1.test.
︙ | ︙ | |||
23 24 25 26 27 28 29 | } {123} do_execsql_test subtype1-120 { SELECT typeof(test_setsubtype('hello',123)); } {text} do_execsql_test subtype1-130 { SELECT test_setsubtype('hello',123); } {hello} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 23 24 25 26 27 28 29 30 31 | } {123} do_execsql_test subtype1-120 { SELECT typeof(test_setsubtype('hello',123)); } {text} do_execsql_test subtype1-130 { SELECT test_setsubtype('hello',123); } {hello} finish_test |
Changes to test/swarmvtab.test.
︙ | ︙ | |||
205 206 207 208 209 210 211 | } db func fetch_db fetch_db do_catchsql_test 3.1 { CREATE VIRTUAL TABLE temp.xyz USING swarmvtab( 'VALUES | | | | | | | | 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 | } db func fetch_db fetch_db do_catchsql_test 3.1 { CREATE VIRTUAL TABLE temp.xyz USING swarmvtab( 'VALUES ("test.db1", "t1", 1, 10), ("test.db2", "t1", 11, 20) ', 'fetch_db_no_such_function' ); } {1 {sql error: no such function: fetch_db_no_such_function}} do_catchsql_test 3.2 { CREATE VIRTUAL TABLE temp.xyz USING swarmvtab( 'VALUES ("test.db1", "t1", 1, 10), ("test.db2", "t1", 11, 20) ', 'fetch_db' ); } {1 {fetch_db error!}} do_execsql_test 3.3.1 { ATTACH 'test.db1' AS aux; CREATE TABLE aux.t1(a INTEGER PRIMARY KEY, b); INSERT INTO aux.t1 VALUES(1, NULL); INSERT INTO aux.t1 VALUES(2, NULL); INSERT INTO aux.t1 VALUES(9, NULL); DETACH aux; CREATE VIRTUAL TABLE temp.xyz USING swarmvtab( 'VALUES ("test.db1", "t1", 1, 10), ("test.db2", "t1", 11, 20) ', 'fetch_db' ); } {} do_catchsql_test 3.3.2 { SELECT * FROM xyz } {1 {fetch_db error!}} |
︙ | ︙ |
Changes to test/swarmvtab3.test.
︙ | ︙ | |||
144 145 146 147 148 149 150 | catch { array unset ::dbcache } # Set up 100 databases with filenames "remote_test.dbN", where N is a # random integer between 0 and 1,000,000 # 0 and 99. do_test 2.1 { | < | < | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | catch { array unset ::dbcache } # Set up 100 databases with filenames "remote_test.dbN", where N is a # random integer between 0 and 1,000,000 # 0 and 99. do_test 2.1 { for {set i 0} {$i < 100} {incr i} { while 1 { set ctx [expr abs(int(rand() *1000000))] if {[info exists ::dbcache($ctx)]==0} break } set file test_remote.db$ctx forcedelete $file forcedelete test.db$i sqlite3 rrr $file rrr eval { CREATE TABLE t1(a INTEGER PRIMARY KEY, b); |
︙ | ︙ |
Changes to test/symlink.test.
︙ | ︙ | |||
33 34 35 36 37 38 39 | 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] | < < < < < < < < < < < < < < < < < < < | | 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | 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 { 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 |
︙ | ︙ | |||
202 203 204 205 206 207 208 209 | db close sqlite3 db w/test.db db eval { SELECT * FROM t1 } } {hello world} do_test 4.4.2 { list [file exists x/test.db-wal] [file exists w/test.db-wal] } {1 0} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 183 184 185 186 187 188 189 190 191 | db close sqlite3 db w/test.db db eval { SELECT * FROM t1 } } {hello world} do_test 4.4.2 { list [file exists x/test.db-wal] [file exists w/test.db-wal] } {1 0} finish_test |
Deleted test/symlink2.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 | 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 LIMIT 5; } {0 | 1 | 2 | 3 | 4 |} 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 { |
︙ | ︙ | |||
106 107 108 109 110 111 112 | } {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 { | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 100 101 102 103 104 105 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() 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. # do_execsql_test tabfunc01-4.1 { SELECT * FROM main.generate_series(1,4) } {1 2 3 4} do_execsql_test tabfunc01-4.2 { SELECT * FROM temp.generate_series(1,4) |
︙ | ︙ | |||
273 274 275 276 277 278 279 | 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 |} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | 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 |} # Free up memory allocations intarray_addr int64array_addr doublearray_addr textarray_addr finish_test |
Changes to test/tclsqlite.test.
︙ | ︙ | |||
21 22 23 24 25 26 27 | set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix tcl # Check the error messages generated by tclsqlite # | | | | 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 | 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? ?-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, 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 |
︙ | ︙ | |||
162 163 164 165 166 167 168 | 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" |
︙ | ︙ | |||
367 368 369 370 371 372 373 | 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 | 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} do_test tcl-9.11 { execsql {SELECT r1(100)} } {5050} } # Tests for the new transaction method # do_test tcl-10.1 { db transaction {} } {} |
︙ | ︙ | |||
786 787 788 789 790 791 792 | 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 | | | 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 | 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 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} |
︙ | ︙ | |||
844 845 846 847 848 849 850 | 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 {} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 843 844 845 846 847 848 849 850 | 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 {} 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 100 | } do_execsql_test 2.2 { SELECT b FROM t1 WHERE a = 10001; } "[int2str 1001][int2str 1001][int2str 1001]" finish_test |
Changes to test/temptable2.test.
1 2 3 4 5 6 7 8 9 10 | # 2016 March 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. # #*********************************************************************** | < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # 2016 March 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. # #*********************************************************************** set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix temptable2 do_execsql_test 1.1 { CREATE TEMP TABLE t1(a, b); |
︙ | ︙ |
Changes to test/tester.tcl.
︙ | ︙ | |||
85 86 87 88 89 90 91 | # 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 # | < < < | 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | # 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. # set tcl_precision 15 |
︙ | ︙ | |||
128 129 130 131 132 133 134 | 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) } | < | 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 } |
︙ | ︙ | |||
173 174 175 176 177 178 179 | 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. # | < < < < < < | | 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 | 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 \\ /] \ [string trim [exec -- $::env(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 |
︙ | ︙ | |||
394 395 396 397 398 399 400 | # 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 | < < < | 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 |
︙ | ︙ | |||
459 460 461 462 463 464 465 | puts -nonewline "Press RETURN to begin..." flush stdout gets stdin } {^-+soft-heap-limit=.+$} { foreach {dummy cmdlinearg(soft-heap-limit)} [split $a =] break } | < < < | 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)} { |
︙ | ︙ | |||
548 549 550 551 552 553 554 | lappend leftover $a } else { lappend leftover [file normalize $a] } } } } | < | 532 533 534 535 536 537 538 539 540 541 542 543 544 545 | lappend leftover $a } else { lappend leftover [file normalize $a] } } } } set testdir [file normalize $testdir] set cmdlinearg(TESTFIXTURE_HOME) [pwd] set cmdlinearg(INFO_SCRIPT) [file normalize [info script]] set argv0 [file normalize $argv0] if {$cmdlinearg(testdir)!=""} { file mkdir $cmdlinearg(testdir) cd $cmdlinearg(testdir) |
︙ | ︙ | |||
599 600 601 602 603 604 605 | } } # 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. # | | < | 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 | } } # 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_limit $cmdlinearg(soft-heap-limit) # Create a test database # proc reset_db {} { catch {db close} forcedelete test.db forcedelete test.db-journal |
︙ | ︙ | |||
789 790 791 792 793 794 795 | 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 { | < < < | 771 772 773 774 775 776 777 778 779 780 781 782 783 784 | 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]=="*"} { |
︙ | ︙ | |||
908 909 910 911 912 913 914 | # 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"} { | | | | 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 | # 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"} { # lreverse*2 as a hack to remove any unneeded {} after the string map lreverse [lreverse [string map {\\ /} [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 ] } |
︙ | ︙ | |||
1008 1009 1010 1011 1012 1013 1014 | set dx($id) $detail lappend cx($parent) $id } set a "\n QUERY PLAN\n" append a [append_graph " " dx cx 0] regsub -all { 0x[A-F0-9]+\y} $a { xxxxxx} a regsub -all {(MATERIALIZE|CO-ROUTINE|SUBQUERY) \d+\y} $a {\1 xxxxxx} a | < | 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 | set dx($id) $detail lappend cx($parent) $id } set a "\n QUERY PLAN\n" append a [append_graph " " dx cx 0] regsub -all { 0x[A-F0-9]+\y} $a { xxxxxx} a regsub -all {(MATERIALIZE|CO-ROUTINE|SUBQUERY) \d+\y} $a {\1 xxxxxx} a return $a } # Helper routine for [query_plan_graph SQL]: # # Output rows of the graph that are children of $level. # |
︙ | ︙ | |||
1059 1060 1061 1062 1063 1064 1065 | # exactly. # # If $res does not begin with "\s+QUERY PLAN\n" then take it is a string # that must be found somewhere in the query plan output. # proc do_eqp_test {name sql res} { if {[regexp {^\s+QUERY PLAN\n} $res]} { | < | < < < < < < < < | 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 | # exactly. # # If $res does not begin with "\s+QUERY PLAN\n" then take it is a string # that must be found somewhere in the query plan output. # proc do_eqp_test {name sql res} { if {[regexp {^\s+QUERY PLAN\n} $res]} { uplevel do_test $name [list [list query_plan_graph $sql]] [list $res] } else { if {[string index $res 0]!="/"} { set res "/*$res*/" } uplevel do_execsql_test $name [list "EXPLAIN QUERY PLAN $sql"] [list $res] } } |
︙ | ︙ | |||
1210 1211 1212 1213 1214 1215 1216 | 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);" } } } | | | | | | < < < < < < < < < < < < < < < < < < < < < < < | | < | 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 | 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);" } } } # Run this routine last # proc finish_test {} { catch {db close} catch {db1 close} catch {db2 close} catch {db3 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_limit 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] |
︙ | ︙ | |||
1315 1316 1317 1318 1319 1320 1321 | output2 "all of the test failures above might be a result from this defect" output2 "in your TCL build." output2 "******************************************************************" } if {$::cmdlinearg(binarylog)} { vfslog finalize binarylog } | < | | | < | 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 | output2 "all of the test failures above might be a result from this defect" output2 "in your TCL build." output2 "******************************************************************" } if {$::cmdlinearg(binarylog)} { vfslog finalize binarylog } if {$sqlite_open_file_count} { output2 "$sqlite_open_file_count files were left open" incr nErr } if {[lindex [sqlite3_status SQLITE_STATUS_MALLOC_COUNT 0] 1]>0 || [sqlite3_memory_used]>0} { output2 "Unfreed memory: [sqlite3_memory_used] bytes in\ [lindex [sqlite3_status SQLITE_STATUS_MALLOC_COUNT 0] 1] allocations" incr nErr ifcapable mem5||(mem3&&debug) { |
︙ | ︙ | |||
1555 1556 1557 1558 1559 1560 1561 | output2 [format {%-4d %s%s%-12.12s%s %-6d %-6d %-6d % -17s %s %s} \ $addr $I $col $opcode $D $p1 $p2 $p3 $p4 $p5 $comment ] } output2 "---- ------------ ------ ------ ------ ---------------- -- -" } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 | output2 [format {%-4d %s%s%-12.12s%s %-6d %-6d %-6d % -17s %s %s} \ $addr $I $col $opcode $D $p1 $p2 $p3 $p4 $p5 $comment ] } output2 "---- ------------ ------ ------ ------ ---------------- -- -" } # Show the VDBE program for an SQL statement but omit the Trace # opcode at the beginning. This procedure can be used to prove # that different SQL statements generate exactly the same VDBE code. # proc explain_no_trace {sql} { set tr [db eval "EXPLAIN $sql"] |
︙ | ︙ | |||
1771 1772 1773 1774 1775 1776 1777 | # $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] | < < < | 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 | # $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;}} |
︙ | ︙ | |||
1804 1805 1806 1807 1808 1809 1810 | if {[string length $sql]>0} { puts $f "db eval {" puts $f "$sql" puts $f "}" } close $f set r [catch { | | < < < | 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 | 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 } 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" } } lappend r $msg } # crash_on_write ?-devchar DEVCHAR? CRASHDELAY SQL # proc crash_on_write {args} { |
︙ | ︙ | |||
1980 1981 1982 1983 1984 1985 1986 | # 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 | < | | | | | | | | | | | | | | | < | 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 | # 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 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. # |
︙ | ︙ | |||
2220 2221 2222 2223 2224 2225 2226 | close $fd } set contents [string map {' ''} $contents] append sql "INSERT INTO ${database}.file VALUES('$f', '$contents');\n" } set escaped "BEGIN; ${tbl}${tbl2}${tbl3}${sql} ; COMMIT;" | | | | 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 | close $fd } set contents [string map {' ''} $contents] append sql "INSERT INTO ${database}.file VALUES('$f', '$contents');\n" } set escaped "BEGIN; ${tbl}${tbl2}${tbl3}${sql} ; COMMIT;" set escaped [string map [list "{" "\\{" "}" "\\}"] $escaped] set fd [open $filename w] puts $fd "set BUILTIN {" puts $fd $escaped puts $fd "}" puts $fd {set BUILTIN [string map [list "\\{" "{" "\\}" "}"] $BUILTIN]} set mtv [open $::testdir/malloctraceviewer.tcl] set txt [read $mtv] close $mtv puts $fd $txt close $fd } |
︙ | ︙ | |||
2501 2502 2503 2504 2505 2506 2507 | # proc test_restore_config_pagecache {} { catch {db close} catch {db2 close} catch {db3 close} sqlite3_shutdown | < | | < | 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 | # proc test_restore_config_pagecache {} { catch {db close} catch {db2 close} catch {db3 close} sqlite3_shutdown eval sqlite3_config_pagecache $::old_pagecache_config unset ::old_pagecache_config sqlite3_initialize autoinstall_test_functions sqlite3 db test.db } proc test_binary_name {nm} { if {$::tcl_platform(platform)=="windows"} { |
︙ | ︙ | |||
2529 2530 2531 2532 2533 2534 2535 | finish_test return "" } return $ret } # Find the name of the 'shell' executable (e.g. "sqlite3.exe") to use for | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 | finish_test return "" } return $ret } # Find the name of the 'shell' executable (e.g. "sqlite3.exe") to use for # the tests in shell[1-5].test. If no such executable can be found, invoke # [finish_test ; return] in the callers context. # proc test_find_cli {} { set prog [test_find_binary sqlite3] if {$prog==""} { return -code return } return $prog } # Find the name of the 'sqldiff' executable (e.g. "sqlite3.exe") to use for # the tests in sqldiff tests. If no such executable can be found, invoke # [finish_test ; return] in the callers context. # proc test_find_sqldiff {} { set prog [test_find_binary sqldiff] if {$prog==""} { return -code return } |
︙ | ︙ | |||
2602 2603 2604 2605 2606 2607 2608 | 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 | < < < | 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 | 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 |
Deleted test/testrunner.tcl.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/testrunner_data.tcl.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/thread001.test.
︙ | ︙ | |||
11 12 13 14 15 16 17 | # # $Id: thread001.test,v 1.10 2009/03/26 14:48:07 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl if {[run_thread_tests]==0} { finish_test ; return } | < | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # # $Id: thread001.test,v 1.10 2009/03/26 14:48:07 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl if {[run_thread_tests]==0} { finish_test ; return } set ::enable_shared_cache [sqlite3_enable_shared_cache] set ::NTHREAD 10 # Run this test three times: # |
︙ | ︙ |
Changes to test/thread002.test.
︙ | ︙ | |||
15 16 17 18 19 20 21 | # $Id: thread002.test,v 1.9 2009/03/26 14:48:07 danielk1977 Exp $ set testdir [file dirname $argv0] set do_not_use_codec 1 source $testdir/tester.tcl if {[run_thread_tests]==0} { finish_test ; return } | | | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | # $Id: thread002.test,v 1.9 2009/03/26 14:48:07 danielk1977 Exp $ set testdir [file dirname $argv0] set do_not_use_codec 1 source $testdir/tester.tcl if {[run_thread_tests]==0} { finish_test ; return } db close set ::enable_shared_cache [sqlite3_enable_shared_cache 1] set ::NTHREAD 10 do_test thread002.1 { |
︙ | ︙ |
Changes to test/threadtest3.c.
︙ | ︙ | |||
74 75 76 77 78 79 80 | ** End of test code/infrastructure interface macros. *************************************************************************/ #include <sqlite3.h> | < < < < < < < < < < < < < | | | | | | | | | < < < | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | ** End of test code/infrastructure interface macros. *************************************************************************/ #include <sqlite3.h> #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> #include "test_multiplex.h" /* Required to link test_multiplex.c */ #ifndef SQLITE_OMIT_WSD int sqlite3PendingByte = 0x40000000; #endif |
︙ | ︙ | |||
448 449 450 451 452 453 454 | Statement *pNext; /* Next statement in linked-list */ }; struct Thread { int iTid; /* Thread number within test */ void* pArg; /* Pointer argument passed by caller */ | < < < < < | 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 | Statement *pNext; /* Next statement in linked-list */ }; struct Thread { int iTid; /* Thread number within test */ void* pArg; /* Pointer argument passed by caller */ pthread_t tid; /* Thread id */ char *(*xProc)(int, void*); /* Thread main proc */ Thread *pNext; /* Next in this list of threads */ }; struct Threadset { int iMaxTid; /* Largest iTid value allocated so far */ Thread *pThread; /* Linked list of threads */ }; |
︙ | ︙ | |||
488 489 490 491 492 493 494 | 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; | < < < < | 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 | 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; pErr->zErr = (char *)sqlite3_malloc(512); strerror_r(iSys, pErr->zErr, 512); pErr->zErr[511] = '\0'; } static void sqlite_error( Error *pErr, Sqlite *pDb, const char *zFunc ){ |
︙ | ︙ | |||
533 534 535 536 537 538 539 | pErr->rc = SQLITE_OK; sqlite3_free(pErr->zErr); pErr->zErr = 0; } } static int busyhandler(void *pArg, int n){ | | | 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 | pErr->rc = SQLITE_OK; sqlite3_free(pErr->zErr); pErr->zErr = 0; } } static int busyhandler(void *pArg, int n){ usleep(10*1000); return 1; } static void opendb_x( Error *pErr, /* IN/OUT: Error code */ Sqlite *pDb, /* OUT: Database handle */ const char *zFile, /* Database file name */ |
︙ | ︙ | |||
770 771 772 773 774 775 776 | pErr->zErr = zErr; pErr->rc = 1; } } } } | < < < < < < < < | < < < < < < < < < < < | < < < < < < < < | < < < < < < < | | | 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 | pErr->zErr = zErr; pErr->rc = 1; } } } } static void *launch_thread_main(void *pArg){ Thread *p = (Thread *)pArg; return (void *)p->xProc(p->iTid, p->pArg); } 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; rc = pthread_create(&p->tid, NULL, launch_thread_main, (void *)p); 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){ void *ret; pNext = p->pNext; int rc; rc = pthread_join(p->tid, &ret); if( rc!=0 ){ if( pErr->rc==SQLITE_OK ) system_error(pErr, rc); }else{ printf("Thread %d says: %s\n", p->iTid, (ret==0 ? "..." : (char *)ret)); fflush(stdout); } sqlite3_free(p); } pThreads->pThread = 0; } static i64 filesize_x( Error *pErr, const char *zFile ){ i64 iRet = 0; if( pErr->rc==SQLITE_OK ){ struct stat sStat; if( stat(zFile, &sStat) ){ iRet = -1; }else{ iRet = sStat.st_size; } } return iRet; } |
︙ | ︙ | |||
891 892 893 894 895 896 897 | }else{ i64 iOff; char aBuf[1024]; int fd1; int fd2; unlink(zTo); | | | | 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 | }else{ i64 iOff; char aBuf[1024]; int fd1; int fd2; unlink(zTo); fd1 = open(zFrom, O_RDONLY); if( fd1<0 ){ system_error(pErr, errno); return; } fd2 = open(zTo, O_RDWR|O_CREAT|O_EXCL, 0644); if( fd2<0 ){ system_error(pErr, errno); close(fd1); return; } iOff = 0; |
︙ | ︙ | |||
1022 1023 1024 1025 1026 1027 1028 | 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) ){ | | | 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 | 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) ){ usleep(500*1000); 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); |
︙ | ︙ | |||
1470 1471 1472 1473 1474 1475 1476 | setstoptime(&err, nMs); sqlite3_enable_shared_cache(1); launch_thread(&err, &threads, dynamic_triggers_2, 0); launch_thread(&err, &threads, dynamic_triggers_2, 0); | | < | 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 | setstoptime(&err, nMs); sqlite3_enable_shared_cache(1); launch_thread(&err, &threads, dynamic_triggers_2, 0); launch_thread(&err, &threads, dynamic_triggers_2, 0); sleep(2); 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" 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[] = { |
︙ | ︙ | |||
1513 1514 1515 1516 1517 1518 1519 | { 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 }, | < | 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 | { 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 ){ |
︙ | ︙ |
Deleted test/threadtest5.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/tkt-18458b1a.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} {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 TABLE t2 USING COVERING INDEX t2x} do_eqp_test 2.2 { SELECT DISTINCT y FROM t2 } \ {SCAN TABLE t2 USING COVERING INDEX t2y} do_eqp_test 2.3 { SELECT DISTINCT x, y FROM t2 WHERE y=10 } \ {SEARCH TABLE t2 USING INDEX t2y (y=?)} do_eqp_test 2.4 { SELECT DISTINCT x, y FROM t2 WHERE x=10 } \ {SEARCH TABLE t2 USING INDEX t2x (x=?)} finish_test |
Changes to test/tkt-3a77c9714e.test.
|
| | | 1 2 3 4 5 6 7 8 | # 2011 December 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 | 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} 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 '1abc%';} } {/*SCAN TABLE 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 TABLE t2 USING COVERING INDEX (x=?)*/} do_test tkt-78e04-2.2 { execsql { DROP INDEX ""; EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE x=2; } } {/*SCAN TABLE t2*/} finish_test |
Changes to test/tkt-7bbfb7d442.test.
︙ | ︙ | |||
142 143 144 145 146 147 148 | } do_execsql_test 2.2 { SELECT SKU, DeliveredQty FROM InventoryControl WHERE SKU=31 } {31 10} do_execsql_test 2.3 { | | | 142 143 144 145 146 147 148 149 150 151 152 153 154 | } do_execsql_test 2.2 { SELECT SKU, DeliveredQty FROM InventoryControl WHERE SKU=31 } {31 10} do_execsql_test 2.3 { SELECT CASE WHEN DeliveredQty=10 THEN "TEST PASSED!" ELSE "TEST FAILED!" END FROM InventoryControl WHERE SKU=31; } {{TEST PASSED!}} finish_test |
Changes to test/tkt-80e031a00f.test.
︙ | ︙ | |||
20 21 22 23 24 25 26 | source $testdir/lock_common.tcl source $testdir/malloc_common.tcl # EVIDENCE-OF: R-52275-55503 When the right operand is an empty set, the # result of IN is false and the result of NOT IN is true, regardless of # the left operand and even if the left operand is NULL. # | | | | > | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | source $testdir/lock_common.tcl source $testdir/malloc_common.tcl # EVIDENCE-OF: R-52275-55503 When the right operand is an empty set, the # result of IN is false and the result of NOT IN is true, regardless of # the left operand and even if the left operand is NULL. # # EVIDENCE-OF: R-13595-45863 Note that SQLite allows the parenthesized # list of scalar values on the right-hand side of an IN or NOT IN # operator to be an empty list but most other SQL database database # engines and the SQL92 standard require the list to contain at least # one element. # do_execsql_test tkt-80e031a00f.1 {SELECT 1 IN ()} 0 do_execsql_test tkt-80e031a00f.1b {SELECT 1 IN (2)} 0 do_execsql_test tkt-80e031a00f.1c {SELECT 1 IN (2,3,4,5,6,7,8,9)} 0 do_execsql_test tkt-80e031a00f.2 {SELECT 1 NOT IN ()} 1 do_execsql_test tkt-80e031a00f.2b {SELECT 1 NOT IN (2)} 1 do_execsql_test tkt-80e031a00f.2c {SELECT 1 NOT IN (2,3,4,5,6,7,8,9)} 1 |
︙ | ︙ |
Changes to test/tkt-8454a207b9.test.
︙ | ︙ | |||
14 15 16 17 18 19 20 | # that a negative default value on an added text column actually comes # out negative. # set testdir [file dirname $argv0] source $testdir/tester.tcl | < < < < < < | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # 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; } |
︙ | ︙ |
Deleted test/tkt-99378177930f87bd.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/tkt-a7debbe0.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'; } {-9.22337203685478e+18} do_execsql_test 4.5 { SELECT '9223372036854775806x'+'1x'; } {9.22337203685478e+18} do_execsql_test 4.6 { SELECT '1234x'/'10y'; } {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 TABLE t1 USING COVERING INDEX i1} set tblscan {SCAN TABLE 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*$sort} 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&&!stat3 { 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 71 72 73 74 75 76 77 | 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; } ifcapable stat4 { 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; } } else { db eval { CREATE VIEW vvv AS SELECT tbl,idx,neq,nlt,ndlt,sample FROM sqlite_stat3; } } } {} 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.
︙ | ︙ | |||
11 12 13 14 15 16 17 | # Test that ticket f67b41381a has been resolved. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix tkt-f67b41381a | < < < < < | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # 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; SELECT * FROM t2; |
︙ | ︙ |
Changes to test/tkt-f7b4edec.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 | # # This file implements tests to verify that ticket # [f7b4edece25c994857dc139207f55a53c8319fae] 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 | # # This file implements tests to verify that ticket # [f7b4edece25c994857dc139207f55a53c8319fae] has been fixed. # set testdir [file dirname $argv0] source $testdir/tester.tcl # Open two database connections to the same database file in # shared cache mode. Create update hooks that will fire on # each connection. # db close set ::enable_shared_cache [sqlite3_enable_shared_cache 1] |
︙ | ︙ |
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 39 40 41 42 43 44 45 46 47 48 | # 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 # This is taken from shared.test. The Windows VFS expands # ./test.db (and test.db) to be the same thing so the path # matches and they share a cache. By changing the case # for Windows platform, we get around this and get a separate # connection. if {$::tcl_platform(platform)=="unix"} { sqlite3 db3 ./test.db } else { sqlite3 db3 TEST.DB } 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 | # # $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 { | < > | 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 { execsql { PRAGMA legacy_file_format=OFF; 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.
︙ | ︙ | |||
34 35 36 37 38 39 40 | } } {} # 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. # | < | | | | 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 | } } {} # 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 TABLE listhash USING INDEX ididx (id=?)} do_eqp_test tkt3442-1.3 { SELECT node FROM listhash WHERE id="5000" LIMIT 1; } {SEARCH TABLE 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 TABLE 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 16 17 18 19 20 21 22 23 24 25 26 27 | # #*********************************************************************** # 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 { | > > > > > | > | > > | | > | 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 | # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests to verify that ticket #3793 has been # fixed. # # $Id: tkt3793.test,v 1.2 2009/06/01 16:42:18 shane Exp $ 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 { # This is taken from shared.test. The Windows VFS expands # ./test.db (and test.db) to be the same thing so the path # matches and they share a cache. By changing the case # for Windows platform, we get around this and get a separate # connection. if {$::tcl_platform(platform)=="unix"} { sqlite3 db1 test.db sqlite3 db2 test.db } else { sqlite3 db1 TEST.DB sqlite3 db2 TEST.DB } 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.
︙ | ︙ | |||
80 81 82 83 84 85 86 | execsql { SELECT name FROM sqlite_temp_master; } } {} db2 close | < < < < < < < < < < < < < < < < | 80 81 82 83 84 85 86 87 | execsql { SELECT name FROM sqlite_temp_master; } } {} db2 close finish_test |
Changes to test/tkt3841.test.
︙ | ︙ | |||
18 19 20 21 22 23 24 | source $testdir/tester.tcl ifcapable !subquery { finish_test return } | < | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | source $testdir/tester.tcl ifcapable !subquery { finish_test return } do_test tkt3841.1 { execsql { CREATE TABLE table2 (key TEXT, x TEXT); CREATE TABLE list (key TEXT, value TEXT); INSERT INTO table2 VALUES ("a", "alist"); INSERT INTO table2 VALUES ("b", "blist"); |
︙ | ︙ |
Changes to test/tkt3935.test.
︙ | ︙ | |||
30 31 32 33 34 35 36 | do_test tkt3935.3 { execsql { SELECT j1.b FROM (t1 INNER JOIN t2 ON a=c) AS j1 } } {} do_test tkt3935.4 { catchsql { SELECT a FROM (t1) AS t ON b USING(a) } | | | | | 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 | do_test tkt3935.3 { execsql { SELECT j1.b FROM (t1 INNER JOIN t2 ON a=c) AS j1 } } {} do_test tkt3935.4 { catchsql { SELECT a FROM (t1) AS t ON b USING(a) } } {1 {a JOIN clause is required before ON}} do_test tkt3935.5 { catchsql { SELECT a FROM (t1) AS t ON b } } {1 {a JOIN clause is required before ON}} do_test tkt3935.6 { catchsql { SELECT a FROM (SELECT * FROM t1) AS t ON b USING(a) } } {1 {a JOIN clause is required before ON}} do_test tkt3935.7 { catchsql { SELECT a FROM (SELECT * FROM t1) AS t ON b } } {1 {a JOIN clause is required before ON}} do_test tkt3935.8 { catchsql { SELECT a FROM t1 AS t ON b } } {1 {a JOIN clause is required before ON}} do_test tkt3935.9 { catchsql { SELECT a FROM t1 AS t ON b USING(a) } } {1 {a JOIN clause is required before ON}} do_test tkt3935.10 { catchsql { SELECT a FROM t1 AS t USING(a) } } {1 {a JOIN clause is required before USING}} 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 TABLE part USING INDEX bootleg_pti *SEARCH TABLE lineitem USING INDEX lpki2*/} do_test tpch01-1.1b { set ::eqpres } {/.* customer .* nation AS n1 .*/} do_test tpch01-1.1c { set ::eqpres } {/.* supplier .* nation AS 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 TABLE orders USING INDEX odi (O_ORDERDATE>? AND O_ORDERDATE<?) |--SEARCH TABLE customer USING INDEX cpki (C_CUSTKEY=?) |--SEARCH TABLE nation USING INDEX npki (N_NATIONKEY=?) |--SEARCH TABLE 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 | do_test trace3-11.2 { set ::stmtlist(record) {} db trace_v2 trace_v2_record 8 db close set ::stmtlist(record) } {/^-?\d+$/} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
Changes to test/trans.test.
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. # | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 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. # # $Id: trans.test,v 1.41 2009/04/28 16:37:59 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Create several tables to work with. # |
︙ | ︙ | |||
34 35 36 37 38 39 40 | 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} | < < < < < < < < < < < < < < < < | 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 |
︙ | ︙ | |||
106 107 108 109 110 111 112 | do_test trans-3.1 { execsql { BEGIN; UPDATE one SET a = 0 WHERE 0; SELECT a FROM one ORDER BY a; } } {1 2 3} | < < < < < < < < < < | 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 { |
︙ | ︙ | |||
160 161 162 163 164 165 166 | catchsql { SELECT a FROM one ORDER BY a; } altdb } {0 {1 2 3}} do_test trans-3.10 { execsql {END TRANSACTION} } {} | < < < < | 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}} |
︙ | ︙ | |||
277 278 279 280 281 282 283 | 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} } {} | < < < < < < < < < | 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} } {} |
︙ | ︙ |
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 | 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 TABLE 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 TABLE c1 USING INDEX c1x/} finish_test |
Changes to test/trigger1.test.
︙ | ︙ | |||
764 765 766 767 768 769 770 | 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} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 764 765 766 767 768 769 770 771 | 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 |
Changes to test/trigger2.test.
︙ | ︙ | |||
45 46 47 48 49 50 51 | # trigger2-6.2[a-f]: UPDATE statements # # 7. & 8. Triggers on views fire correctly. # set testdir [file dirname $argv0] source $testdir/tester.tcl | < | 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 |
︙ | ︙ | |||
749 750 751 752 753 754 755 | CREATE TRIGGER trig1 INSTEAD OF DELETE ON v3 BEGIN SELECT 1; END; DELETE FROM v3 WHERE a = 1; } } {} | < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < | 748 749 750 751 752 753 754 755 756 757 758 759 | CREATE TRIGGER trig1 INSTEAD OF DELETE ON v3 BEGIN SELECT 1; END; DELETE FROM v3 WHERE a = 1; } } {} } ;# ifcapable view integrity_check trigger2-9.9 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 254 255 256 | END; CREATE TRIGGER tr3 INSTEAD OF INSERT ON v1 BEGIN INSERT INTO log VALUES('insert'); END; } do_execsql_test 4.2 { DELETE FROM v1 WHERE rowid=1; } {} do_execsql_test 4.3 { UPDATE v1 SET a=b WHERE rowid=2; } {} finish_test |
Changes to test/triggerC.test.
︙ | ︙ | |||
1068 1069 1070 1071 1072 1073 1074 | } do_catchsql_test 17.1 { INSERT INTO xyz VALUES('hello', 2, 3); } {1 {datatype mismatch}} finish_test | > | 1068 1069 1070 1071 1072 1073 1074 1075 | } 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 | 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; } | < < | 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] } #------------------------------------------------------------------------- |
︙ | ︙ |
Changes to test/triggerG.test.
︙ | ︙ | |||
70 71 72 73 74 75 76 | SELECT 0x2147483648e0e0099 AS y WHERE y; END; } do_catchsql_test 310 { INSERT INTO t4 VALUES(1); } {1 {hex literal too big: 0x2147483648e0e0099}} | < < < < < < < < < < < < < < < < | 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 |
Deleted test/triggerupfrom.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/trustschema1.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"); usleep(CHECKPOINT_STARVATION_READMS*1000); 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); usleep(CHECKPOINT_STARVATION_READMS*1000/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++; } |
︙ | ︙ |
Deleted test/tt3_shared.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
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_master;"); 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_master;"); 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 365 366 367 368 | 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 26 27 | ** */ 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; | > < | 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 */ opendb(&err, &db, "test.db", 0); i64 i = 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" |
︙ | ︙ |
Deleted test/unhex.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/unionall.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/unionall2.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/unionallfault.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
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 TABLE t1 USING INDEX i1} {SCAN TABLE t1*USE TEMP B-TREE FOR ORDER BY} 2 "SELECT * FROM t1 WHERE a > 100" {SEARCH TABLE t1 USING INDEX i1 (a>?)} {SCAN TABLE t1} 3 "SELECT * FROM t1 WHERE a = ? ORDER BY rowid" {SEARCH TABLE t1 USING INDEX i1 (a=?)} {SEARCH TABLE t1 USING INDEX i1 (a=?)*USE TEMP B-TREE FOR ORDER BY} 4 "SELECT max(a) FROM t1" {SEARCH TABLE t1 USING COVERING INDEX i1} {SEARCH TABLE t1} 5 "SELECT group_concat(b) FROM t1 GROUP BY a" {SCAN TABLE t1 USING INDEX i1} {SCAN TABLE t1*USE TEMP B-TREE FOR GROUP BY} 6 "SELECT * FROM t1 WHERE a = ?" {SEARCH TABLE t1 USING INDEX i1 (a=?)} {SEARCH TABLE t1 USING INDEX i1 (a=?)} 7 "SELECT count(*) FROM t1" {SCAN TABLE t1 USING COVERING INDEX i1} {SCAN TABLE 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 | } {1 {no such column: nosuchcol}} } ;# ifcapable {trigger} # Ticket [https://www.sqlite.org/src/tktview/43107840f1c02] on 2014-10-29 # An assertion fault on UPDATE # 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} finish_test |
Deleted test/upfrom1.tcl.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/upfrom1.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/upfrom2.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/upfrom3.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/upfrom4.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/upfromfault.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/upsert1.test.
︙ | ︙ | |||
206 207 208 209 210 211 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,2,33,44,5) ON CONFLICT(b) DO UPDATE SET c=excluded.c; SELECT * FROM t1; } {1 2 33 4 5} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
Changes to test/upsert2.test.
︙ | ︙ | |||
68 69 70 71 72 73 74 | # do_execsql_test upsert2-300 { DROP TABLE t1; CREATE TABLE t1(a INTEGER PRIMARY KEY, b int, c DEFAULT 0); CREATE TABLE record(x TEXT, y TEXT); CREATE TRIGGER r1 BEFORE INSERT ON t1 BEGIN INSERT INTO record(x,y) | | | | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | # do_execsql_test upsert2-300 { DROP TABLE t1; CREATE TABLE t1(a INTEGER PRIMARY KEY, b int, c DEFAULT 0); CREATE TABLE record(x TEXT, y TEXT); CREATE TRIGGER r1 BEFORE INSERT ON t1 BEGIN INSERT INTO record(x,y) VALUES('before-insert',printf('%d,%d,%d',new.a,new.b,new.c)); END; CREATE TRIGGER r2 AFTER INSERT ON t1 BEGIN INSERT INTO record(x,y) VALUES('after-insert',printf('%d,%d,%d',new.a,new.b,new.c)); END; CREATE TRIGGER r3 BEFORE UPDATE ON t1 BEGIN INSERT INTO record(x,y) VALUES('before-update',printf('%d,%d,%d/%d,%d,%d', old.a,old.b,old.c,new.a,new.b,new.c)); END; CREATE TRIGGER r4 AFTER UPDATE ON t1 BEGIN INSERT INTO record(x,y) VALUES('after-update',printf('%d,%d,%d/%d,%d,%d', old.a,old.b,old.c,new.a,new.b,new.c)); END; |
︙ | ︙ | |||
119 120 121 122 123 124 125 | # Trigger tests repeated for a WITHOUT ROWID table. # do_execsql_test upsert2-400 { DROP TABLE t1; CREATE TABLE t1(a INT PRIMARY KEY, b int, c DEFAULT 0) WITHOUT ROWID; CREATE TRIGGER r1 BEFORE INSERT ON t1 BEGIN INSERT INTO record(x,y) | | | | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | # Trigger tests repeated for a WITHOUT ROWID table. # do_execsql_test upsert2-400 { DROP TABLE t1; CREATE TABLE t1(a INT PRIMARY KEY, b int, c DEFAULT 0) WITHOUT ROWID; CREATE TRIGGER r1 BEFORE INSERT ON t1 BEGIN INSERT INTO record(x,y) VALUES('before-insert',printf('%d,%d,%d',new.a,new.b,new.c)); END; CREATE TRIGGER r2 AFTER INSERT ON t1 BEGIN INSERT INTO record(x,y) VALUES('after-insert',printf('%d,%d,%d',new.a,new.b,new.c)); END; CREATE TRIGGER r3 BEFORE UPDATE ON t1 BEGIN INSERT INTO record(x,y) VALUES('before-update',printf('%d,%d,%d/%d,%d,%d', old.a,old.b,old.c,new.a,new.b,new.c)); END; CREATE TRIGGER r4 AFTER UPDATE ON t1 BEGIN INSERT INTO record(x,y) VALUES('after-update',printf('%d,%d,%d/%d,%d,%d', old.a,old.b,old.c,new.a,new.b,new.c)); END; |
︙ | ︙ |
Deleted test/upsert5.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/uri.test.
︙ | ︙ | |||
190 191 192 193 194 195 196 | set A(1) {0 {}} set A(0) [list 1 "access mode not allowed: $mode"] do_test 4.1.$tn.3 { list [catch {sqlite3 db "file:test.db?mode=$mode" -readonly 1} msg] $msg } $A($readonly_ok) } | < | 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | set A(1) {0 {}} set A(0) [list 1 "access mode not allowed: $mode"] do_test 4.1.$tn.3 { list [catch {sqlite3 db "file:test.db?mode=$mode" -readonly 1} msg] $msg } $A($readonly_ok) } set orig [sqlite3_enable_shared_cache] foreach {tn options sc_default is_shared} { 1 "" 1 1 2 "cache=private" 1 0 3 "cache=shared" 1 1 4 "" 0 0 5 "cache=private" 0 0 |
︙ | ︙ | |||
220 221 222 223 224 225 226 | do_test 4.2.$tn { db2 eval {BEGIN; INSERT INTO t1 VALUES(1, 2);} catchsql { SELECT * FROM t1 } } $A($is_shared) db2 close } | < | 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | do_test 4.2.$tn { db2 eval {BEGIN; INSERT INTO t1 VALUES(1, 2);} catchsql { SELECT * FROM t1 } } $A($is_shared) db2 close } do_test 4.3.1 { list [catch {sqlite3 db "file:test.db?mode=rc"} msg] $msg } {1 {no such access mode: rc}} do_test 4.3.2 { list [catch {sqlite3 db "file:test.db?cache=public"} msg] $msg } {1 {no such cache mode: public}} |
︙ | ︙ |
Changes to test/utf16align.test.
︙ | ︙ | |||
28 29 30 31 32 33 34 | # Create a database with a UTF16 encoding. Put in lots of string # data of varying lengths. # do_test utf16align-1.0 { set unaligned_string_counter 0 add_alignment_test_collations [sqlite3_connection_pointer db] | < | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | # Create a database with a UTF16 encoding. Put in lots of string # data of varying lengths. # do_test utf16align-1.0 { set unaligned_string_counter 0 add_alignment_test_collations [sqlite3_connection_pointer db] execsql { PRAGMA encoding=UTF16; CREATE TABLE t1( id INTEGER PRIMARY KEY, spacer TEXT, a TEXT COLLATE utf16_aligned, b TEXT COLLATE utf16_unaligned |
︙ | ︙ |
Changes to test/vacuum-into.test.
︙ | ︙ | |||
95 96 97 98 99 100 101 102 | } 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 | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 95 96 97 98 99 100 101 102 103 | } 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 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.1 { 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 | # 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; ALTER TABLE t1 ADD COLUMN d; UPDATE t1 SET d = randomblob(1000); } file size test.db } {3072} do_test vacuum3-2.2 { execsql { PRAGMA page_size } } {1024} |
︙ | ︙ |
Deleted test/vacuum6.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/vacuummem.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 the VACUUM statement correctly # frees any memory used for a temporary cache. # | < | 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 the VACUUM statement correctly # frees any memory used for a temporary cache. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix vacuummem if {[permutation]=="memsubsys1"} { finish_test |
︙ | ︙ |
Changes to test/view.test.
︙ | ︙ | |||
34 35 36 37 38 39 40 | 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} | < < < < < < < < < < < < < < < < < < < < < < | 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 { |
︙ | ︙ | |||
644 645 646 647 648 649 650 651 652 653 654 655 656 657 | execsql { DROP TABLE IF EXISTS t1; DROP VIEW IF EXISTS v1; CREATE TABLE t1(c1); CREATE VIEW v1 AS SELECT c1 FROM (SELECT t1.c1 FROM t1); } } {} db close sqlite3 db :memory: do_execsql_test view-22.1 { CREATE VIEW x1 AS SELECT 123 AS '', 234 AS '', 345 AS ''; SELECT * FROM x1; } {123 234 345} | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | execsql { DROP TABLE IF EXISTS t1; DROP VIEW IF EXISTS v1; CREATE TABLE t1(c1); CREATE VIEW v1 AS SELECT c1 FROM (SELECT t1.c1 FROM t1); } } {} # Ticket [d58ccbb3f1b]: Prevent Table.nRef overflow. db close sqlite3 db :memory: do_test view-21.1 { catchsql { CREATE TABLE t1(x); INSERT INTO t1 VALUES(5); CREATE VIEW v1 AS SELECT x*2 FROM t1; CREATE VIEW v2 AS SELECT * FROM v1 UNION SELECT * FROM v1; CREATE VIEW v4 AS SELECT * FROM v2 UNION SELECT * FROM v2; CREATE VIEW v8 AS SELECT * FROM v4 UNION SELECT * FROM v4; CREATE VIEW v16 AS SELECT * FROM v8 UNION SELECT * FROM v8; CREATE VIEW v32 AS SELECT * FROM v16 UNION SELECT * FROM v16; CREATE VIEW v64 AS SELECT * FROM v32 UNION SELECT * FROM v32; CREATE VIEW v128 AS SELECT * FROM v64 UNION SELECT * FROM v64; CREATE VIEW v256 AS SELECT * FROM v128 UNION SELECT * FROM v128; CREATE VIEW v512 AS SELECT * FROM v256 UNION SELECT * FROM v256; CREATE VIEW v1024 AS SELECT * FROM v512 UNION SELECT * FROM v512; CREATE VIEW v2048 AS SELECT * FROM v1024 UNION SELECT * FROM v1024; CREATE VIEW v4096 AS SELECT * FROM v2048 UNION SELECT * FROM v2048; CREATE VIEW v8192 AS SELECT * FROM v4096 UNION SELECT * FROM v4096; CREATE VIEW v16384 AS SELECT * FROM v8192 UNION SELECT * FROM v8192; CREATE VIEW v32768 AS SELECT * FROM v16384 UNION SELECT * FROM v16384; SELECT * FROM v32768 UNION SELECT * FROM v32768; } } {1 {too many references to "v1": max 65535}} ifcapable progress { do_test view-21.2 { db progress 1000 {expr 1} catchsql { SELECT * FROM v32768; } } {1 interrupted} } db close sqlite3 db :memory: do_execsql_test view-22.1 { CREATE VIEW x1 AS SELECT 123 AS '', 234 AS '', 345 AS ''; SELECT * FROM x1; } {123 234 345} |
︙ | ︙ | |||
698 699 700 701 702 703 704 | SELECT * FROM v16 AS one, v16 AS two WHERE one.mx=1; } { 1 1 1 1 1 1 2 2 1 1 3 3 } | < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 711 712 713 714 715 716 717 718 719 | SELECT * FROM v16 AS one, v16 AS two WHERE one.mx=1; } { 1 1 1 1 1 1 2 2 1 1 3 3 } finish_test |
Deleted test/view2.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/view3.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/vt02.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/vtab1.test.
︙ | ︙ | |||
871 872 873 874 875 876 877 | } {31429} do_test vtab1.7-13 { execsql { SELECT rowid, a, b, c FROM real_abc } } {} | < < < < < < < < | 871 872 873 874 875 876 877 878 879 880 881 882 883 884 | } {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); } |
︙ | ︙ | |||
979 980 981 982 983 984 985 | } [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 "" | < | 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'} \ |
︙ | ︙ | |||
1308 1309 1310 1311 1312 1313 1314 | 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); } | < | | | | | | | | | | | | < < < | | | | | | < | | | < < < | | | 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 | 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); } 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 like ?} 8J%} 1.4 "SELECT a FROM e6 WHERE b LIKE '8j%'" {3 4} {xFilter {SELECT rowid, a, b FROM 't6' WHERE b like ?} 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.0 { PRAGMA case_sensitive_like = ON } foreach {tn sql res filter} { 2.1 "SELECT a FROM e6 WHERE b LIKE '8J%'" {3 4} {xFilter {SELECT rowid, a, b FROM 't6' WHERE b like ?} 8J%} 2.2 "SELECT a FROM e6 WHERE b LIKE '8j%'" {} {xFilter {SELECT rowid, a, b FROM 't6' WHERE b like ?} 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 an existing module may not be overridden. # 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_MISUSE do_test 19.3 { db2 close } {} #------------------------------------------------------------------------- # Test that the bug fixed by [b0c1ba655d69] really is fixed. # |
︙ | ︙ | |||
1553 1554 1555 1556 1557 1558 1559 1560 | CREATE VIRTUAL TABLE t5 USING fts3(); SAVEPOINT b; ROLLBACK TO a; SAVEPOINT c; RELEASE a; } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
Changes to test/vtab6.test.
︙ | ︙ | |||
219 220 221 222 223 224 225 | } } {1 2 3 4 2 3 4 5 3 4 5 {}} do_test vtab6-2.2 { execsql { SELECT * FROM t2 NATURAL LEFT OUTER JOIN t1; } } {1 2 3 {} 2 3 4 1 3 4 5 2} | | | | < > | | 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 | } } {1 2 3 4 2 3 4 5 3 4 5 {}} do_test vtab6-2.2 { execsql { SELECT * FROM t2 NATURAL LEFT OUTER JOIN t1; } } {1 2 3 {} 2 3 4 1 3 4 5 2} do_test vtab6-2.3 { catchsql { SELECT * FROM t1 NATURAL RIGHT OUTER JOIN t2; } } {1 {RIGHT and FULL OUTER JOINs are not currently supported}} do_test vtab6-2.4 { execsql { SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.d } } {1 2 3 {} {} {} 2 3 4 {} {} {} 3 4 5 1 2 3} do_test vtab6-2.4.1 { execsql { |
︙ | ︙ | |||
259 260 261 262 263 264 265 | SELECT * FROM t1 NATURAL JOIN t2 USING(b); } } {1 {a NATURAL join may not have an ON or USING clause}} do_test vtab6-3.3 { catchsql { SELECT * FROM t1 JOIN t2 ON t1.a=t2.b USING(b); } | | < < < | < | | 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 | SELECT * FROM t1 NATURAL JOIN t2 USING(b); } } {1 {a NATURAL join may not have an ON or USING clause}} do_test vtab6-3.3 { catchsql { SELECT * FROM t1 JOIN t2 ON t1.a=t2.b USING(b); } } {1 {cannot have both ON and USING clauses in the same join}} do_test vtab6-3.4 { catchsql { SELECT * FROM t1 JOIN t2 USING(a); } } {1 {cannot join using column a - column not present in both tables}} do_test vtab6-3.5 { catchsql { SELECT * FROM t1 USING(a) } } {1 {a JOIN clause is required before USING}} do_test vtab6-3.6 { catchsql { SELECT * FROM t1 JOIN t2 ON t3.a=t2.b; } } {1 {no such column: t3.a}} do_test vtab6-3.7 { catchsql { SELECT * FROM t1 INNER OUTER JOIN t2; } } {1 {unknown or unsupported join type: INNER OUTER}} do_test vtab6-3.7 { catchsql { SELECT * FROM t1 LEFT BOGUS JOIN t2; } } {1 {unknown or unsupported join type: LEFT BOGUS}} do_test vtab6-4.1 { execsql { BEGIN; INSERT INTO t6 VALUES(NULL); INSERT INTO t6 VALUES(NULL); INSERT INTO t6 SELECT * FROM t6; |
︙ | ︙ | |||
351 352 353 354 355 356 357 | SELECT * FROM t6, t5 WHERE t6.a>t5.a; } } {} # A test for ticket #247. # do_test vtab6-7.1 { | < | 347 348 349 350 351 352 353 354 355 356 357 358 359 360 | SELECT * FROM t6, t5 WHERE t6.a>t5.a; } } {} # A test for ticket #247. # do_test vtab6-7.1 { execsql { INSERT INTO t7 VALUES ("pa1", 1); INSERT INTO t7 VALUES ("pa2", NULL); INSERT INTO t7 VALUES ("pa3", NULL); INSERT INTO t7 VALUES ("pa4", 2); INSERT INTO t7 VALUES ("pa30", 131); INSERT INTO t7 VALUES ("pa31", 130); |
︙ | ︙ |
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 | 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); } foreach {tn sql expect} { 1 "SELECT * FROM e6 WHERE b LIKE '8abc'" { xBestIndex {SELECT rowid, a, b FROM 't6' WHERE b like ?} xFilter {SELECT rowid, a, b FROM 't6' WHERE b like ?} 8abc } 2 "SELECT * FROM e6 WHERE b GLOB '8abc'" { xBestIndex {SELECT rowid, a, b FROM 't6' WHERE b glob ?} xFilter {SELECT rowid, a, b FROM 't6' WHERE b glob ?} 8abc } } { 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.
︙ | ︙ | |||
118 119 120 121 122 123 124 | } {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'; } {} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 118 119 120 121 122 123 124 125 126 | } {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 |
Deleted test/vtabK.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/vtabdistinct.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/vtabrhs1.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/wal.test.
︙ | ︙ | |||
39 40 41 42 43 44 45 | 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 | < | 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] } # |
︙ | ︙ | |||
1510 1511 1512 1513 1514 1515 1516 1517 | 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 } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 | 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 |
Changes to test/wal2.test.
︙ | ︙ | |||
118 119 120 121 122 123 124 | } } {4 10} do_test wal2-1.1 { execsql { SELECT count(a), sum(a) FROM t1 } db2 } {4 10} set RECOVER [list \ | | < < < < | | 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | } } {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 4 lock exclusive} \ {1 2 unlock exclusive} {4 4 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} \ ] |
︙ | ︙ | |||
394 395 396 397 398 399 400 | # 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 | | < < < < < < < < | | 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 | # 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 {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] |
︙ | ︙ | |||
633 634 635 636 637 638 639 | testvfs tvfs tvfs script tvfs_cb sqlite3 db test.db -vfs tvfs set {} {} } {} set RECOVERY { | | < < < < | | 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 | testvfs tvfs tvfs script tvfs_cb sqlite3 db test.db -vfs tvfs set {} {} } {} set RECOVERY { {0 1 lock exclusive} {1 2 lock exclusive} {4 4 lock exclusive} {1 2 unlock exclusive} {4 4 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} |
︙ | ︙ |
Changes to test/wal3.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 the operation of the library in # "PRAGMA journal_mode=WAL" mode. # | < | 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 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/wal_common.tcl source $testdir/malloc_common.tcl ifcapable !wal {finish_test ; return } |
︙ | ︙ |
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 | 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 5 } [list {0 1 lock exclusive} {1 2 lock exclusive} {4 4 lock exclusive} \ {1 2 unlock exclusive} {4 4 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 5 } [list {0 1 lock exclusive} {1 2 lock exclusive} {4 4 lock exclusive} \ {1 2 unlock exclusive} {4 4 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" |
︙ | ︙ | |||
107 108 109 110 111 112 113 | return SQLITE_OK } do_test 1.5 { db close set ::locks [list] sqlite3 db test.db -vfs T catchsql { SELECT * FROM x } | | | 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | return SQLITE_OK } do_test 1.5 { db close set ::locks [list] sqlite3 db test.db -vfs T catchsql { SELECT * FROM x } } {1 {locking protocol}} db close T delete #------------------------------------------------------------------------- # do_test 2.1 { forcedelete test.db test.db-journal test.db wal |
︙ | ︙ | |||
166 167 168 169 170 171 172 | 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 | | | 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | 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 } {1 {locking protocol}} db close db2 close faultsim_restore_and_reopen sqlite3 db2 test.db T filter xShmLock |
︙ | ︙ | |||
188 189 190 191 192 193 194 | 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 | | | 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | 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 } {1 {locking protocol}} db close db2 close T delete finish_test |
Changes to test/walro2.test.
︙ | ︙ | |||
46 47 48 49 50 51 52 | # possible *-shm file (i.e. the greater of 32KB and the system page-size). # do_execsql_test 0.0 { PRAGMA journal_mode = wal; CREATE TABLE t1(x); } {wal} set MINSHMSZ [file size test.db-shm] | < < | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | 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 | # possible *-shm file (i.e. the greater of 32KB and the system page-size). # do_execsql_test 0.0 { PRAGMA journal_mode = wal; CREATE TABLE t1(x); } {wal} set MINSHMSZ [file size test.db-shm] foreach bZeroShm {0 1} { set TN [expr $bZeroShm+1] do_multiclient_test tn { # Close all connections and delete the database. # code1 { db close } code2 { db2 close } code3 { db3 close } forcedelete test.db # Do not run tests with the connections in the same process. # if {$tn==2} continue foreach c {code1 code2 code3} { $c { sqlite3_shutdown sqlite3_config_uri 1 } } do_test $TN.1.1 { code2 { sqlite3 db2 test.db } sql2 { CREATE TABLE t1(x, y); PRAGMA journal_mode = WAL; INSERT INTO t1 VALUES('a', 'b'); INSERT INTO t1 VALUES('c', 'd'); } file exists test.db-shm } {1} do_test $TN.1.2.1 { copy_to_test2 $bZeroShm code1 { sqlite3 db file:test.db2?readonly_shm=1 } sql1 { SELECT * FROM t1 } } {a b c d} do_test $TN.1.2.2 { sql1 { SELECT * FROM t1 } } {a b c d} do_test $TN.1.3.1 { code3 { sqlite3 db3 test.db2 } sql3 { SELECT * FROM t1 } } {a b c d} do_test $TN.1.3.2 { sql1 { SELECT * FROM t1 } } {a b c d} code1 { db close } code2 { db2 close } code3 { db3 close } do_test $TN.2.1 { code2 { sqlite3 db2 test.db } sql2 { INSERT INTO t1 VALUES('e', 'f'); INSERT INTO t1 VALUES('g', 'h'); } file exists test.db-shm } {1} do_test $TN.2.2 { copy_to_test2 $bZeroShm code1 { sqlite3 db file:test.db2?readonly_shm=1 } sql1 { BEGIN; SELECT * FROM t1; } } {a b c d e f g h} do_test $TN.2.3.1 { code3 { sqlite3 db3 test.db2 } sql3 { SELECT * FROM t1 } } {a b c d e f g h} do_test $TN.2.3.2 { sql3 { INSERT INTO t1 VALUES('i', 'j') } code3 { db3 close } sql1 { COMMIT } } {} do_test $TN.2.3.3 { sql1 { SELECT * FROM t1 } } {a b c d e f g h i j} #----------------------------------------------------------------------- # 3.1.*: That a readonly_shm connection can read a database file if both # the *-wal and *-shm files are zero bytes in size. # # 3.2.*: That it flushes the cache if, between transactions on a db with a # zero byte *-wal file, some other connection modifies the db, then # does "PRAGMA wal_checkpoint=truncate" to truncate the wal file # back to zero bytes in size. # # 3.3.*: That, if between transactions some other process wraps the wal # file, the readonly_shm client reruns recovery. # catch { code1 { db close } } catch { code2 { db2 close } } catch { code3 { db3 close } } do_test $TN.3.1.0 { list [file exists test.db-wal] [file exists test.db-shm] } {0 0} do_test $TN.3.1.1 { close [open test.db-wal w] close [open test.db-shm w] code1 { sqlite3 db file:test.db?readonly_shm=1 } sql1 { SELECT * FROM t1 } } {a b c d e f g h} do_test $TN.3.2.0 { list [file size test.db-wal] [file size test.db-shm] } {0 0} do_test $TN.3.2.1 { code2 { sqlite3 db2 test.db } sql2 { INSERT INTO t1 VALUES(1, 2) ; PRAGMA wal_checkpoint=truncate } code2 { db2 close } sql1 { SELECT * FROM t1 } } {a b c d e f g h 1 2} do_test $TN.3.2.2 { list [file size test.db-wal] [file size test.db-shm] } [list 0 $MINSHMSZ] do_test $TN.3.3.0 { code2 { sqlite3 db2 test.db } sql2 { INSERT INTO t1 VALUES(3, 4); INSERT INTO t1 VALUES(5, 6); INSERT INTO t1 VALUES(7, 8); INSERT INTO t1 VALUES(9, 10); } code2 { db2 close } code1 { db close } list [file size test.db-wal] [file size test.db-shm] } [list [wal_file_size 4 1024] $MINSHMSZ] do_test $TN.3.3.1 { code1 { sqlite3 db file:test.db?readonly_shm=1 } sql1 { SELECT * FROM t1 } } {a b c d e f g h 1 2 3 4 5 6 7 8 9 10} do_test $TN.3.3.2 { code2 { sqlite3 db2 test.db } sql2 { PRAGMA wal_checkpoint; DELETE FROM t1; INSERT INTO t1 VALUES('i', 'ii'); } code2 { db2 close } list [file size test.db-wal] [file size test.db-shm] } [list [wal_file_size 4 1024] $MINSHMSZ] do_test $TN.3.3.3 { sql1 { SELECT * FROM t1 } } {i ii} #----------------------------------------------------------------------- # # catch { code1 { db close } } catch { code2 { db2 close } } catch { code3 { db3 close } } do_test $TN.4.0 { code1 { forcedelete test.db } code1 { sqlite3 db test.db } sql1 { PRAGMA journal_mode = wal; CREATE TABLE t1(x); INSERT INTO t1 VALUES('hello'); INSERT INTO t1 VALUES('world'); } copy_to_test2 $bZeroShm code1 { db close } } {} do_test $TN.4.1.1 { code2 { sqlite3 db2 file:test.db2?readonly_shm=1 } sql2 { SELECT * FROM t1 } } {hello world} do_test $TN.4.1.2 { code3 { sqlite3 db3 test.db2 } sql3 { INSERT INTO t1 VALUES('!'); PRAGMA wal_checkpoint = truncate; } code3 { db3 close } } {} do_test $TN.4.1.3 { sql2 { SELECT * FROM t1 } } {hello world !} catch { code1 { db close } } catch { code2 { db2 close } } catch { code3 { db3 close } } do_test $TN.4.2.1 { code1 { sqlite3 db test.db } sql1 { INSERT INTO t1 VALUES('!'); INSERT INTO t1 VALUES('!'); PRAGMA cache_size = 10; CREATE TABLE t2(x); BEGIN; WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<500 ) INSERT INTO t2 SELECT randomblob(500) FROM s; SELECT count(*) FROM t2; } } {500} set sz [file size test.db-wal] do_test $TN.4.2.2.(sz=$sz) { expr {$sz>400000} } {1} do_test $TN.4.2.4 { file_control_persist_wal db 1; db close copy_to_test2 $bZeroShm code2 { sqlite3 db2 file:test.db2?readonly_shm=1 } sql2 { SELECT * FROM t1; SELECT count(*) FROM t2; } } {hello world ! ! 0} #----------------------------------------------------------------------- # # catch { code1 { db close } } catch { code2 { db2 close } } catch { code3 { db3 close } } do_test $TN.5.0 { code1 { forcedelete test.db } code1 { sqlite3 db test.db } sql1 { PRAGMA journal_mode = wal; CREATE TABLE t1(x); INSERT INTO t1 VALUES('hello'); INSERT INTO t1 VALUES('world'); INSERT INTO t1 VALUES('!'); INSERT INTO t1 VALUES('world'); INSERT INTO t1 VALUES('hello'); } copy_to_test2 $bZeroShm code1 { db close } } {} do_test $TN.5.1 { code2 { sqlite3 db2 file:test.db2?readonly_shm=1 } sql2 { SELECT * FROM t1; } } {hello world ! world hello} do_test $TN.5.2 { code1 { proc handle_read {op args} { if {$op=="xRead" && [file tail [lindex $args 0]]=="test.db2-wal"} { set ::res2 [sql2 { SELECT * FROM t1 }] } puts "$msg xRead $args" return "SQLITE_OK" } testvfs tvfs -fullshm 1 sqlite3 db file:test.db2?vfs=tvfs db eval { SELECT * FROM sqlite_master } tvfs filter xRead tvfs script handle_read } sql1 { PRAGMA wal_checkpoint = truncate; } code1 { set ::res2 } } {hello world ! world hello} do_test $TN.5.3 { code1 { db close } code1 { tvfs delete } } {} #----------------------------------------------------------------------- # # catch { code1 { db close } } catch { code2 { db2 close } } catch { code3 { db3 close } } do_test $TN.6.1 { code1 { forcedelete test.db } code1 { sqlite3 db test.db } sql1 { PRAGMA journal_mode = wal; CREATE TABLE t1(x); INSERT INTO t1 VALUES('hello'); INSERT INTO t1 VALUES('world'); INSERT INTO t1 VALUES('!'); INSERT INTO t1 VALUES('world'); INSERT INTO t1 VALUES('hello'); } copy_to_test2 $bZeroShm code1 { db close } } {} do_test $TN.6.2 { code1 { set ::nRem 5 proc handle_read {op args} { if {$op=="xRead" && [file tail [lindex $args 0]]=="test.db2-wal"} { incr ::nRem -1 if {$::nRem==0} { code2 { sqlite3 db2 test.db2 } sql2 { PRAGMA wal_checkpoint = truncate } } } return "SQLITE_OK" } testvfs tvfs -fullshm 1 tvfs filter xRead tvfs script handle_read sqlite3 db file:test.db2?readonly_shm=1&vfs=tvfs db eval { SELECT * FROM t1 } } } {hello world ! world hello} do_test $TN.6.3 { code1 { db close } code1 { tvfs delete } } {} } } ;# foreach bZeroShm finish_test |
Deleted test/walsetlk.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/walshared.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 | # focus of this file is testing the operation of the library in # "PRAGMA journal_mode=WAL" mode with shared-cache turned on. # set testdir [file dirname $argv0] source $testdir/tester.tcl | | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # focus of this file is testing the operation of the library in # "PRAGMA journal_mode=WAL" mode with shared-cache turned on. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !wal {finish_test ; return } db close set ::enable_shared_cache [sqlite3_enable_shared_cache 1] sqlite3 db test.db sqlite3 db2 test.db |
︙ | ︙ |
Changes to test/walvfs.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 the operation of the library in # "PRAGMA journal_mode=WAL" mode. # | < | 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 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 |
︙ | ︙ | |||
142 143 144 145 146 147 148 | } {1 interrupted} set ::cnt 2 proc xWrite {method file args} { if {[file tail $file]=="test.db"} { incr ::cnt -1 if {$::cnt==0} { | | < < | < < < < < | 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 | } {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 5 -repeat 0 catchsql { SELECT 'a big long string!' } sqlite3_interrupt db } } return SQLITE_OK } do_catchsql_test 3.2 { PRAGMA wal_checkpoint } {1 {out of memory}} #------------------------------------------------------------------------- # reset_db db close do_test 4.0 { sqlite3 db test.db -vfs tvfs |
︙ | ︙ | |||
391 392 393 394 395 396 397 | db2 close } {} do_execsql_test 8.3 { PRAGMA wal_checkpoint; SELECT count(*) FROM t1 } {0 5 5 21} | < | 383 384 385 386 387 388 389 390 391 392 393 394 395 396 | db2 close } {} do_execsql_test 8.3 { PRAGMA wal_checkpoint; SELECT count(*) FROM t1 } {0 5 5 21} tvfs2 delete #------------------------------------------------------------------------- reset_db db close sqlite3 db test.db -vfs tvfs do_execsql_test 9.0 { |
︙ | ︙ | |||
431 432 433 434 435 436 437 | catchsql { SELECT count(*) FROM t1 } db2 } {1 {disk I/O error}} db close db2 close tvfs delete finish_test | > | 422 423 424 425 426 427 428 429 | catchsql { SELECT count(*) FROM t1 } db2 } {1 {disk I/O error}} db close db2 close tvfs delete finish_test |
Changes to test/wapptest.tcl.
1 2 3 4 5 6 7 8 9 10 | #!/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. | > > > > < < | < < < < | > > > < < < < | < | < < < < < < < < | | > > | < > | > | < < < < < | | < < | 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 | #!/bin/sh # \ exec wapptclsh "$0" ${1+"$@"} # package required wapp source [file join [file dirname [info script]] wapp.tcl] # Read the data from the releasetest_data.tcl script. # source [file join [file dirname [info script]] releasetest_data.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) 0 set G(msvc) 0 set G(tcl) [::tcl::pkgconfig get libdir,install] set G(jobs) 3 set G(debug) 0 proc wapptest_init {} { global G set lSave [list platform test keep msvc tcl jobs debug] 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]]] # releasetest.tcl script set G(releaseTest) [file join [file dirname [info script]] releasetest.tcl] 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)" } # Check to see if there are uncommitted changes in the SQLite source # directory. Return true if there are, or false otherwise. # proc check_uncommitted {} { global G set ret 0 set pwd [pwd] cd $G(srcdir) if {[catch {exec fossil changes} res]==0 && [string trim $res]!=""} { set ret 1 } cd $pwd return $ret } proc generate_fossil_info {} { global G set pwd [pwd] cd $G(srcdir) if {[catch {exec fossil info} r1]} return if {[catch {exec fossil changes} r2]} return cd $pwd foreach line [split $r1 "\n"] { if {[regexp {^checkout: *(.*)$} $line -> co]} { wapp-trim { <br> %html($co) } } } |
︙ | ︙ | |||
111 112 113 114 115 116 117 | # 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] | < < | < < < < | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | # 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] foreach {config target} $::Platforms($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 |
︙ | ︙ | |||
145 146 147 148 149 150 151 152 153 154 155 156 157 158 | set target testfixture.exe } } } } lappend G(test_array) [dict create config $config target $target] } } } proc count_tests_and_errors {name logfile} { global G | > > > > > > > > > > > > > > > > | 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 | set target testfixture.exe } } } } lappend G(test_array) [dict create config $config target $target] set exclude [list checksymbols valgrindtest fuzzoomtest] if {$G(debug) && !($target in $exclude)} { set debug_idx [lsearch -glob $::Configs($config) -DSQLITE_DEBUG*] set xtarget $target regsub -all {fulltest[a-z]*} $xtarget test xtarget if {$debug_idx<0} { lappend G(test_array) [ dict create config $config-(Debug) target $xtarget ] } else { lappend G(test_array) [ dict create config $config-(NDebug) target $xtarget ] } } } } } proc count_tests_and_errors {name logfile} { global G |
︙ | ︙ | |||
166 167 168 169 170 171 172 | 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 | | | 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | 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 {value .* 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 } } |
︙ | ︙ | |||
210 211 212 213 214 215 216 | set G(test.$name.errmsg) "Test did not complete" if {[file readable core]} { append G(test.$name.errmsg) " - core file exists" } } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | set G(test.$name.errmsg) "Test did not complete" if {[file readable core]} { append G(test.$name.errmsg) " - core file exists" } } } 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) } } 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 } 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 |
︙ | ︙ | |||
394 395 396 397 398 399 400 | 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." | < < < < < < < > | > > > | > > > > > > > > > > > > > > > > > > > > > | 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 | 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." catch { append G(result) " SQLite version $G(sqlite_version)" } set G(state) "stopped" } 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 G(test.$name.start) [clock seconds] set fd [open "|[info nameofexecutable] $G(releaseTest) --slave" r+] set G(test.$name.channel) $fd fconfigure $fd -blocking 0 fileevent $fd readable [list slave_fileevent $name] puts $fd [list 0 $G(msvc) 0 $G(keep)] set wtcl "" if {$G(tcl)!=""} { set wtcl "--with-tcl=$G(tcl)" } # If this configuration is named <name>-(Debug) or <name>-(NDebug), # then add or remove the SQLITE_DEBUG option from the base # configuration before running the test. if {[regexp -- {(.*)-(\(.*\))} $name -> head tail]} { set opts $::Configs($head) if {$tail=="(Debug)"} { append opts " -DSQLITE_DEBUG=1 -DSQLITE_EXTRA_IFNULLROW=1" } else { regsub { *-DSQLITE_MEMDEBUG[^ ]* *} $opts { } opts regsub { *-DSQLITE_DEBUG[^ ]* *} $opts { } opts } } else { set opts $::Configs($name) } set L [make_test_suite $G(msvc) $wtcl $name $target $opts] puts $fd $L flush $fd set G(test.$name.log) [file join [lindex $L 1] test.log] incr nLaunch -1 } } } } proc generate_select_widget {label id lOpt opt} { |
︙ | ︙ | |||
464 465 466 467 468 469 470 | wapp-trim { </div> <div class="border" id=controls> <form action="control" method="post" name="control"> } # Build the "platform" select widget. | | | | 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 | wapp-trim { </div> <div class="border" id=controls> <form action="control" method="post" name="control"> } # Build the "platform" select widget. set lOpt [array names ::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 { |
︙ | ︙ | |||
552 553 554 555 556 557 558 | if {$G(test.$config.nError)>0} { set class "testfail" } else { set class "testdone" } set seconds [expr $G(test.$config.done) - $G(test.$config.start)] } | > > > > | | 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 | 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 min [format %.2d [expr ($seconds / 60) % 60]] set hr [format %.2d [expr $seconds / 3600]] set sec [format %.2d [expr $seconds % 60]] set seconds "$hr:$min:$sec" } wapp-trim { <tr class=%string($class)> <td class="nowrap"> %html($config) <td class="padleft nowrap"> %html($target) <td class="padleft nowrap"> %html($seconds) |
︙ | ︙ | |||
611 612 613 614 615 616 617 | 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. | | > < | 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 | 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. set_test_array set ::G(state) "running" } 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 } } } if {[wapp-param-exists control_reset]} { # A "reset app" command. set G(state) "config" wapptest_init } |
︙ | ︙ | |||
778 779 780 781 782 783 784 | wapp-trim { <pre> %html($data) </pre> } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < | | 665 666 667 668 669 670 671 672 673 674 | wapp-trim { <pre> %html($data) </pre> } } wapptest_init wapp-start $argv |
Changes to test/where.test.
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 use of indices in WHERE clases. # set testdir [file dirname $argv0] source $testdir/tester.tcl # Build some test data # do_test where-1.0 { | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 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 use of indices in WHERE clases. # # $Id: where.test,v 1.50 2008/11/03 09:06:06 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Build some test data # do_test where-1.0 { |
︙ | ︙ | |||
65 66 67 68 69 70 71 | 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 TABLE t1 USING INDEX i1w (w=?)*} do_eqp_test where-1.1.2b { SELECT x, y, w FROM t1 WHERE w IS 10 } {*SEARCH TABLE 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 TABLE 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 TABLE 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 { |
︙ | ︙ | |||
113 114 115 116 117 118 119 | 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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 { |
︙ | ︙ | |||
541 542 543 544 545 546 547 | execsql { CREATE TABLE t3(a,b,c); CREATE INDEX t3a ON t3(a); CREATE INDEX t3bc ON t3(b,c); CREATE INDEX t3acb ON t3(a,c,b); INSERT INTO t3 SELECT w, 101-w, y FROM t1; SELECT count(*), sum(a), sum(b), sum(c) FROM t3; | < | 542 543 544 545 546 547 548 549 550 551 552 553 554 555 | execsql { CREATE TABLE t3(a,b,c); CREATE INDEX t3a ON t3(a); CREATE INDEX t3bc ON t3(b,c); CREATE INDEX t3acb ON t3(a,c,b); INSERT INTO t3 SELECT w, 101-w, y FROM t1; SELECT count(*), sum(a), sum(b), sum(c) FROM t3; } } {100 5050 5050 348550} do_test where-6.2 { cksort { SELECT * FROM t3 ORDER BY a LIMIT 3 } } {1 100 4 2 99 9 3 98 16 nosort} |
︙ | ︙ | |||
1344 1345 1346 1347 1348 1349 1350 | # do_execsql_test where-18.1 { CREATE TABLE t181(a); CREATE TABLE t182(b,c); INSERT INTO t181 VALUES(1); SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY c IS NULL; } {1} | < < < < < < < < < | 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 | # do_execsql_test where-18.1 { CREATE TABLE t181(a); CREATE TABLE t182(b,c); INSERT INTO t181 VALUES(1); SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY c IS NULL; } {1} do_execsql_test where-18.2 { SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY +c; } {1} do_execsql_test where-18.3 { SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY c; } {1} do_execsql_test where-18.4 { INSERT INTO t181 VALUES(1),(1),(1),(1); SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY +c; } {1} do_execsql_test where-18.5 { INSERT INTO t181 VALUES(2); SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY c IS NULL, +a; } {1 2} do_execsql_test where-18.6 { INSERT INTO t181 VALUES(2); SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY +a, +c IS NULL; |
︙ | ︙ | |||
1501 1502 1503 1504 1505 1506 1507 | 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; | | | | 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 | 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_master SET rootpage = ( SELECT rootpage FROM sqlite_master 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}} |
︙ | ︙ | |||
1529 1530 1531 1532 1533 1534 1535 | 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; | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 | 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_master SET rootpage = ( SELECT rootpage FROM sqlite_master 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}} 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 | 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 { TABLE (\w+ AS )?(\w+) USING.* INDEX (\w+)\y} \ $x all as tab idx]} { lappend data $tab $idx } elseif {[regexp { TABLE (\w+ AS )?(\w+)\y} $x all as tab]} { lappend data $tab * } } return $data } |
︙ | ︙ | |||
751 752 753 754 755 756 757 | 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); | | | 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 | 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 TABLE t12 AS b .*SEARCH TABLE t12 AS 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 | # 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 { TABLE (\w+ AS )?(\w+) USING.* INDEX (\w+)\y} \ $x all as tab idx]} { lappend data $tab $idx } elseif {[regexp { TABLE (\w+ AS )?(\w+)\y} $x all as tab]} { lappend data $tab * } } return $data } |
︙ | ︙ | |||
238 239 240 241 242 243 244 | 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 | | | | | | | | | | | | | | | 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 | 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 TABLE t302 `--SEARCH TABLE 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 TABLE t302 `--SEARCH TABLE 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 TABLE t402} 0 1 0 {SCAN TABLE t400} 0 2 1 {SCAN TABLE t401} } do_execsql_test where3-4.1 { EXPLAIN QUERY PLAN SELECT * FROM t400, t401, t402 WHERE t401.r GLOB 'abc*'; } { 0 0 1 {SCAN TABLE t401} 0 1 0 {SCAN TABLE t400} 0 2 2 {SCAN TABLE t402} } do_execsql_test where3-4.2 { EXPLAIN QUERY PLAN SELECT * FROM t400, t401, t402 WHERE t400.c GLOB 'abc*'; } { 0 0 0 {SCAN TABLE t400} 0 1 1 {SCAN TABLE t401} 0 2 2 {SCAN TABLE t402} } } ;# endif # Verify that a performance regression encountered by firefox # has been fixed. # do_execsql_test where3-5.0 { |
︙ | ︙ | |||
319 320 321 322 323 324 325 | 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 | | | | | | | | | | 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 | 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 TABLE aaa USING INDEX aaa_333 (fk=?) |--SEARCH TABLE 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 TABLE aaa USING INDEX aaa_333 (fk=?) |--SEARCH TABLE aaa AS 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 TABLE aaa USING INDEX aaa_333 (fk=?) |--SEARCH TABLE 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 TABLE aaa USING INDEX aaa_333 (fk=?) |--SEARCH TABLE aaa AS 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.
︙ | ︙ | |||
23350 23351 23352 23353 23354 23355 23356 | AND (t301.c4 = 1407449685622784 OR t301.c8 = 1407424651264000) ORDER BY t302.c5 LIMIT 200; } { QUERY PLAN |--MULTI-INDEX OR | |--INDEX 1 | | | | < < < < < < < < < < < < < < < < < < < < < < < < | 23350 23351 23352 23353 23354 23355 23356 23357 23358 23359 23360 23361 23362 23363 23364 | AND (t301.c4 = 1407449685622784 OR t301.c8 = 1407424651264000) ORDER BY t302.c5 LIMIT 200; } { QUERY PLAN |--MULTI-INDEX OR | |--INDEX 1 | | `--SEARCH TABLE t301 USING COVERING INDEX t301_c4 (c4=?) | `--INDEX 2 | `--SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?) |--SEARCH TABLE 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 TABLE t1 USING INTEGER PRIMARY KEY (rowid=?) `--MULTI-INDEX OR |--INDEX 1 | `--SEARCH TABLE t2 USING INDEX t2d (d=?) `--INDEX 3 `--SEARCH TABLE 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 TABLE t1 USING INTEGER PRIMARY KEY (rowid=?) `--MULTI-INDEX OR |--INDEX 1 | `--SEARCH TABLE t2 USING INDEX t2d (d=?) `--INDEX 2 `--SEARCH TABLE 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 { |
︙ | ︙ | |||
422 423 424 425 426 427 428 | 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 } } {1 {no query solution}} 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 } } {1 {no query solution}} 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 } } {1 {no query solution}} # 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 TABLE t1 USING INDEX t1c (c=?) `--INDEX 2 `--SEARCH TABLE 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 TABLE 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 TABLE 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} |
︙ | ︙ | |||
772 773 774 775 776 777 778 | 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) } } {1 {no query solution}} 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) } } {1 {no query solution}} set solution_possible 0 ifcapable stat4||stat3 { 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 { |
︙ | ︙ | |||
814 815 816 817 818 819 820 | 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) } } {1 {no query solution}} 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) } } {1 {no query solution}} } ############################################################################ # 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) # |
︙ | ︙ | |||
855 856 857 858 859 860 861 862 863 864 865 866 867 868 | CREATE INDEX t5yd ON t5(y, d); 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} | > > > > > | 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 | CREATE INDEX t5yd ON t5(y, d); 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; } ifcapable stat3 { sqlite3 db2 test.db db2 eval { DROP TABLE IF EXISTS sqlite_stat3 } db2 close } } {} 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} |
︙ | ︙ | |||
978 979 980 981 982 983 984 | 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} | < < < < < < < | < < < < < < < < < < | 983 984 985 986 987 988 989 990 991 992 | 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} finish_test |
Changes to test/whereA.test.
︙ | ︙ | |||
176 177 178 179 180 181 182 | 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'; | | | 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | 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_master; 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 | } {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} | < < < < < < < < < < < < < < < < | 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); |
︙ | ︙ |
Changes to test/whereE.test.
︙ | ︙ | |||
14 15 16 17 18 19 20 | # set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix whereE | < < < < < < | 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 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; INSERT INTO t1 SELECT * FROM t1; |
︙ | ︙ | |||
49 50 51 52 53 54 55 | 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; | | | | | | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | 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 TABLE t1.*SEARCH TABLE t2.*/} do_execsql_test 1.2 { EXPLAIN QUERY PLAN SELECT x FROM t2, t1 WHERE a=z AND c=x; } {/.*SCAN TABLE t1.*SEARCH TABLE t2.*/} do_execsql_test 1.3 { ANALYZE; EXPLAIN QUERY PLAN SELECT x FROM t1, t2 WHERE a=z AND c=x; } {/.*SCAN TABLE t1.*SEARCH TABLE t2.*/} do_execsql_test 1.4 { EXPLAIN QUERY PLAN SELECT x FROM t2, t1 WHERE a=z AND c=x; } {/.*SCAN TABLE t1.*SEARCH TABLE 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 TABLE t2\y.*SEARCH TABLE 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 TABLE t2\y.*SEARCH TABLE 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 TABLE t2\y.*SEARCH TABLE 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 TABLE a.*SEARCH TABLE b USING INDEX .*b_1 .b1=..*/} do_eqp_test whereG-3.2 { SELECT * FROM a, b WHERE a1=b1 AND a2=5; } {/.*SCAN TABLE a.*SEARCH TABLE b USING INDEX .*b_1 .b1=..*/} do_eqp_test whereG-3.3 { SELECT * FROM a, b WHERE a2=5 AND b1=a1; } {/.*SCAN TABLE a.*SEARCH TABLE b USING INDEX .*b_1 .b1=..*/} do_eqp_test whereG-3.4 { SELECT * FROM a, b WHERE a2=5 AND a1=b1; } {/.*SCAN TABLE a.*SEARCH TABLE 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 TABLE t1 USING INDEX i1 (a>?)} do_eqp_test 5.1.3 { SELECT * FROM t1 WHERE likelihood(a>?, 0.9) } {SCAN TABLE t1} do_eqp_test 5.1.4 { SELECT * FROM t1 WHERE likely(a>?) } {SCAN TABLE 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 TABLE t1 USING INDEX i1 (ANY(a) AND b>?)} do_eqp_test 5.2.3 { SELECT * FROM t1 WHERE likelihood(b>?, 0.9) } {SCAN TABLE t1} do_eqp_test 5.2.4 { SELECT * FROM t1 WHERE likely(b>?) } {SCAN TABLE t1} ifcapable stat4 { do_eqp_test 5.3.1.stat4 { SELECT * FROM t1 WHERE a=? } {SCAN TABLE t1} } else { do_eqp_test 5.3.1 { SELECT * FROM t1 WHERE a=? } {SEARCH TABLE t1 USING INDEX i1} } do_eqp_test 5.3.2 { SELECT * FROM t1 WHERE likelihood(a=?, 0.9) } {SCAN TABLE t1} do_eqp_test 5.3.3 { SELECT * FROM t1 WHERE likely(a=?) } {SCAN TABLE 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); |
︙ | ︙ | |||
268 269 270 271 272 273 274 | 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 | 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} finish_test |
Changes to test/whereI.test.
︙ | ︙ | |||
28 29 30 31 32 33 34 | do_eqp_test 1.1 { SELECT a FROM t1 WHERE b='b' OR c='x' } { QUERY PLAN `--MULTI-INDEX OR |--INDEX 1 | | | | 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 TABLE t1 USING INDEX i1 (b=?) `--INDEX 2 `--SEARCH TABLE 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 { |
︙ | ︙ | |||
60 61 62 63 64 65 66 | do_eqp_test 2.1 { SELECT a FROM t2 WHERE b='b' OR c='x' } { QUERY PLAN `--MULTI-INDEX OR |--INDEX 1 | | | | 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 TABLE t2 USING INDEX i3 (b=?) `--INDEX 2 `--SEARCH TABLE 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 TABLE 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 TABLE 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 TABLE cx.*SEARCH TABLE px.*SEARCH TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 TABLE 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 58 | 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 |--MATERIALIZE xxxxxx | `--COMPOUND QUERY | |--LEFT-MOST SUBQUERY | | `--SEARCH TABLE t2 USING INDEX sqlite_autoindex_t2_1 (a=?) | `--UNION ALL | `--SEARCH TABLE t3 USING INDEX sqlite_autoindex_t3_1 (a=?) |--SCAN SUBQUERY xxxxxx `--SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_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 TABLE t1 USING INDEX sqlite_autoindex_t1_1 (a=?) |--SEARCH TABLE t2 USING INDEX sqlite_autoindex_t2_1 (a=?) `--SCAN TABLE 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 | 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; } {} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 118 119 120 121 122 123 124 125 | 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 |
Deleted test/whereM.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Added test/whereN.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 | # 2024-04-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. # #*********************************************************************** # Tests for the whereInterstageHeuristic() routine in the query planner. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix whereN # The following is a simplified and "sanitized" version of the original # real-world query that brought the problem to light. # # The issue is a slow query. The answer is correct, but it was taking too # much time, because it was doing a full table scan rather than an indexed # lookup. # # The problem was that the query planner was overestimating the number of # output rows. The estimated number of output rows is accurate if the # DSNAME parameter is "ds-one". In that case, a large fraction of the rows # in "violation" end up being output. The query planner correctly deduces # that it is faster to do a full table scan of the large "violation" table # to avoid the after-query sort that implements the ORDER BY clause. However, # if the DSNAME is "ds-two", then only a few rows (about 6) are generated, # and it is much much faster to do an indexed lookup of "violation" followed # by a sort operation to implement ORDER BY # # The problem, of course, is that the query planner has no way of knowing # in advance how many rows will be generated. The query planner tries to # estimate a worst case, which is a large number of output rows, and it picks # the best plan for that case. However, the plan choosen is very inefficient # when the number of output rows is small. # # The whereInterstageHeuristic() routine in the query planner attempts to # correct this by adjusting the query plan such that it avoids the very bad # query plan for a small number of rows, at the expense of a slightly less # efficient plan for a large number of rows. The large number of rows case # is perhaps 5% slower with the revised plan, but the small number of # rows case is around 100 times faster. That seems like a good tradeoff. # do_execsql_test 1.0 { CREATE TABLE datasource(dsid INT, name TEXT); INSERT INTO datasource VALUES(1,'ds-one'),(2,'ds-two'),(3,'ds-three'); CREATE INDEX ds1 ON datasource(name, dsid); CREATE TABLE rule(rid INT, team_id INT, dsid INT); WITH RECURSIVE c(n) AS (VALUES(1) UNION ALL SELECT n+1 FROM c WHERE n<9) INSERT INTO rule(rid,team_id,dsid) SELECT n, 1, 1 FROM c; WITH RECURSIVE c(n) AS (VALUES(10) UNION ALL SELECT n+1 FROM c WHERE n<24) INSERT INTO rule(rid,team_id,dsid) SELECT n, 2, 2 FROM c; CREATE INDEX rule2 ON rule(dsid, rid); CREATE TABLE violation(vid INT, rid INT, vx BLOB); /*** Uncomment to insert actual data WITH src(rid, cnt) AS (VALUES(1,3586),(2,1343),(3,6505),(5,76230), (6,740),(7,287794),(8,457),(12,1), (14,1),(16,1),(17,1),(18,1),(19,1)) INSERT INTO violation(vid, rid, vx) SELECT rid*1000000+value, rid, randomblob(15) FROM src, generate_series(1,cnt); ***/ CREATE INDEX v1 ON violation(rid, vid); CREATE INDEX v2 ON violation(vid); ANALYZE; DELETE FROM sqlite_stat1; DROP TABLE IF EXISTS sqlite_stat4; INSERT INTO sqlite_stat1 VALUES ('violation','v2','376661 1'), ('violation','v1','376661 28974 1'), ('rule','rule2','24 12 1'), ('datasource','ds1','3 1 1'); ANALYZE sqlite_master; } set DSNAME ds-two ;# Only a few rows. Change to "ds-one" for many rows. do_eqp_test 1.1 { SELECT count(*), length(group_concat(vx)) FROM ( SELECT V.* FROM datasource DS, rule R, violation V WHERE V.rid=R.rid AND R.dsid=DS.dsid AND DS.name=$DSNAME ORDER BY V.vid desc ); } { QUERY PLAN |--CO-ROUTINE xxxxxx | |--SEARCH TABLE datasource AS DS USING COVERING INDEX ds1 (name=?) | |--SEARCH TABLE rule AS R USING COVERING INDEX rule2 (dsid=?) | |--SEARCH TABLE violation AS V USING INDEX v1 (rid=?) | `--USE TEMP B-TREE FOR ORDER BY `--SCAN SUBQUERY xxxxxx } # ^^^^---- We want to see three SEARCH terms. No SCAN terms. # The ORDER BY is implemented by a separate sorter pass. finish_test |
Changes to test/wherefault.test.
︙ | ︙ | |||
52 53 54 55 56 57 58 | 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; } | < < < < < < < < < < < < < < < < < < < < < < < < | 52 53 54 55 56 57 58 59 | 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 |
Changes to test/wherelimit.test.
︙ | ︙ | |||
90 91 92 93 94 95 96 | 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} | < < < < < < < < | < < | | | | 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 | 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 execsql {DELETE FROM t1 ORDER BY x LIMIT 5 OFFSET 2} execsql {SELECT count(*) FROM t1} } {10} 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} } {5} 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} } {2} 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 { |
︙ | ︙ | |||
233 234 235 236 237 238 239 | } {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 { | | < < | 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 | } {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 LIMIT 5} 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 | do_execsql_test 4.1 { BEGIN; DELETE FROM x1 ORDER BY a LIMIT 2; SELECT a FROM x1; ROLLBACK; } {3 4 5 6} 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} 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} #------------------------------------------------------------------------- |
︙ | ︙ |
Changes to test/widetab1.test.
︙ | ︙ | |||
42 43 44 45 46 47 48 | FROM a LEFT JOIN b ON a.bn = b.bn AND CASE WHEN a.vb IS NOT NULL THEN 1 ELSE 0 END = b.iv WHERE pd BETWEEN 0 AND 10) GROUP BY dc; } { QUERY PLAN | | | | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | FROM a LEFT JOIN b ON a.bn = b.bn AND CASE WHEN a.vb IS NOT NULL THEN 1 ELSE 0 END = b.iv WHERE pd BETWEEN 0 AND 10) GROUP BY dc; } { QUERY PLAN |--SEARCH TABLE a USING COVERING INDEX a1 (pd>? AND pd<?) |--SEARCH TABLE b USING COVERING INDEX b1 (bn=? AND iv=?) `--USE TEMP B-TREE FOR GROUP BY } reset_db do_execsql_test 200 { CREATE TABLE t1( c00,c01,c02,c03,c04,c05,c06,c07,c08,c09, |
︙ | ︙ |
Added test/wild001.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 | # 2013-07-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 is a test case from content taken "from the wild". In this # particular instance, the query was provided with permission by # Elan Feingold on 2013-06-27. His message on the SQLite mailing list # on that date reads: # #------------------------------------------------------------------------------ # > Can you send (1) the schema (2) the query that is giving problems, and (3) # > the content of the sqlite_stat1 table after you have run ANALYZE? If you # > can combine all of the above into a script, that would be great! # > # > If you send (1..3) above and you give us written permission to include the # > query in our test suite, that would be off-the-chain terrific. # # Please find items 1..3 in this file: http://www.plexapp.com/elan/sqlite_bug.txt # # You have our permission to include the query in your test suite. # # Thanks for an amazing product. #----------------------------------------------------------------------------- # # This test case merely creates the schema and populates SQLITE_STAT1 and # SQLITE_STAT3 then runs an EXPLAIN QUERY PLAN to ensure that the right plan # is discovered. This test case may need to be adjusted for future revisions # of the query planner manage to select a better query plan. The query plan # shown here is known to be very fast with the original data. # # This test should work the same with and without SQLITE_ENABLE_STAT3 # ############################################################################### set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !stat3 { finish_test return } do_execsql_test wild001.01 { CREATE TABLE "items" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "secid" integer, "parent_id" integer, "metadata_type" integer, "guid" varchar(255), "media_item_count" integer, "title" varchar(255), "title_sort" varchar(255) COLLATE NOCASE, "original_title" varchar(255), "studio" varchar(255), "rating" float, "rating_count" integer, "tagline" varchar(255), "summary" text, "trivia" text, "quotes" text, "content_rating" varchar(255), "content_rating_age" integer, "index" integer, "absolute_index" integer, "duration" integer, "user_thumb_url" varchar(255), "user_art_url" varchar(255), "user_banner_url" varchar(255), "user_music_url" varchar(255), "user_fields" varchar(255), "tags_genre" varchar(255), "tags_collection" varchar(255), "tags_director" varchar(255), "tags_writer" varchar(255), "tags_star" varchar(255), "originally_available_at" datetime, "available_at" datetime, "expires_at" datetime, "refreshed_at" datetime, "year" integer, "added_at" datetime, "created_at" datetime, "updated_at" datetime, "deleted_at" datetime, "tags_country" varchar(255), "extra_data" varchar(255), "hash" varchar(255)); CREATE INDEX "i_secid" ON "items" ("secid" ); CREATE INDEX "i_parent_id" ON "items" ("parent_id" ); CREATE INDEX "i_created_at" ON "items" ("created_at" ); CREATE INDEX "i_index" ON "items" ("index" ); CREATE INDEX "i_title" ON "items" ("title" ); CREATE INDEX "i_title_sort" ON "items" ("title_sort" ); CREATE INDEX "i_guid" ON "items" ("guid" ); CREATE INDEX "i_metadata_type" ON "items" ("metadata_type" ); CREATE INDEX "i_deleted_at" ON "items" ("deleted_at" ); CREATE INDEX "i_secid_ex1" ON "items" ("secid", "metadata_type", "added_at" ); CREATE INDEX "i_hash" ON "items" ("hash" ); CREATE TABLE "settings" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "account_id" integer, "guid" varchar(255), "rating" float, "view_offset" integer, "view_count" integer, "last_viewed_at" datetime, "created_at" datetime, "updated_at" datetime); CREATE INDEX "s_account_id" ON "settings" ("account_id" ); CREATE INDEX "s_guid" ON "settings" ("guid" ); ANALYZE; INSERT INTO sqlite_stat1 VALUES('settings','s_guid','4740 1'); INSERT INTO sqlite_stat1 VALUES('settings','s_account_id','4740 4740'); INSERT INTO sqlite_stat1 VALUES('items','i_hash','27316 2'); INSERT INTO sqlite_stat1 VALUES('items','i_secid_ex1','27316 6829 4553 3'); INSERT INTO sqlite_stat1 VALUES('items','i_deleted_at','27316 27316'); INSERT INTO sqlite_stat1 VALUES('items','i_metadata_type','27316 6829'); INSERT INTO sqlite_stat1 VALUES('items','i_guid','27316 2'); INSERT INTO sqlite_stat1 VALUES('items','i_title_sort','27316 2'); INSERT INTO sqlite_stat1 VALUES('items','i_title','27316 2'); INSERT INTO sqlite_stat1 VALUES('items','i_index','27316 144'); INSERT INTO sqlite_stat1 VALUES('items','i_created_at','27316 2'); INSERT INTO sqlite_stat1 VALUES('items','i_parent_id','27316 15'); INSERT INTO sqlite_stat1 VALUES('items','i_secid','27316 6829'); INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,150,150,'com.plexapp.agents.thetvdb://153021/2/9?lang=en'); INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,198,198,'com.plexapp.agents.thetvdb://194031/1/10?lang=en'); INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,526,526,'com.plexapp.agents.thetvdb://71256/12/92?lang=en'); INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,923,923,'com.plexapp.agents.thetvdb://71256/15/16?lang=en'); INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,1008,1008,'com.plexapp.agents.thetvdb://71256/15/93?lang=en'); INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,1053,1053,'com.plexapp.agents.thetvdb://71256/16/21?lang=en'); INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,1068,1068,'com.plexapp.agents.thetvdb://71256/16/35?lang=en'); INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,1235,1235,'com.plexapp.agents.thetvdb://71256/17/44?lang=en'); INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,1255,1255,'com.plexapp.agents.thetvdb://71256/17/62?lang=en'); INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,1573,1573,'com.plexapp.agents.thetvdb://71663/20/9?lang=en'); INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,1580,1580,'com.plexapp.agents.thetvdb://71663/21/16?lang=en'); INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,2000,2000,'com.plexapp.agents.thetvdb://73141/9/8?lang=en'); INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,2107,2107,'com.plexapp.agents.thetvdb://73244/6/17?lang=en'); INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,2256,2256,'com.plexapp.agents.thetvdb://74845/4/7?lang=en'); INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,2408,2408,'com.plexapp.agents.thetvdb://75978/2/21?lang=en'); INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,2634,2634,'com.plexapp.agents.thetvdb://79126/1/1?lang=en'); INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,2962,2962,'com.plexapp.agents.thetvdb://79274/3/94?lang=en'); INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,3160,3160,'com.plexapp.agents.thetvdb://79274/5/129?lang=en'); INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,3161,3161,'com.plexapp.agents.thetvdb://79274/5/12?lang=en'); INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,3688,3688,'com.plexapp.agents.thetvdb://79274/8/62?lang=en'); INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,3714,3714,'com.plexapp.agents.thetvdb://79274/8/86?lang=en'); INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,4002,4002,'com.plexapp.agents.thetvdb://79590/13/17?lang=en'); INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,4215,4215,'com.plexapp.agents.thetvdb://80727/3/6?lang=en'); INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,4381,4381,'com.plexapp.agents.thetvdb://83462/3/24?lang=en'); INSERT INTO sqlite_stat3 VALUES('settings','s_account_id',4740,0,0,1); INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,1879,1879,'1113f632ccd52ec8b8d7ca3d6d56da4701e48018'); INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,2721,2721,'1936154b97bb5567163edaebc2806830ae419ccf'); INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,3035,3035,'1c122331d4b7bfa0dc2c003ab5fb4f7152b9987a'); INSERT INTO sqlite_stat3 VALUES('items','i_hash',2,3393,3393,'1f81bdbc9acc3321dc592b1a109ca075731b549a'); INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,6071,6070,'393cf7713efb4519c7a3d1d5403f0d945d15a16a'); INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,7462,7461,'4677dd37011f8bd9ae7fbbdd3af6dcd8a5b4ab2d'); INSERT INTO sqlite_stat3 VALUES('items','i_hash',2,8435,8434,'4ffa339485334e81a5e12e03a63b6508d76401cf'); INSERT INTO sqlite_stat3 VALUES('items','i_hash',2,8716,8714,'52a093852e6599dd5004857b7ff5b5b82c7cdb25'); INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,9107,9104,'561183e39f866d97ec728e9ff16ac4ad01466111'); INSERT INTO sqlite_stat3 VALUES('items','i_hash',2,10942,10939,'66e99b72e29610f49499ae09ee04a376210d1f08'); INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,12143,12139,'71f0602427e173dc2c551535f73fdb6885fe4302'); INSERT INTO sqlite_stat3 VALUES('items','i_hash',2,14962,14958,'8ca8e4dfba696019830c19ab8a32c7ece9d8534b'); INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,15179,15174,'8ebf1a5cf33f8ada1fc5853ac06ac4d7e074f825'); INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,15375,15370,'908bc211bebdf21c79d2d2b54ebaa442ac1f5cae'); INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,18215,18210,'ab29e4e18ec5a14fef95aa713d69e31c045a22c1'); INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,18615,18610,'ae84c008cc0c338bf4f28d798a88575746452f6d'); INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,18649,18644,'aec7c901353e115aa5307e94018ba7507bec3a45'); INSERT INTO sqlite_stat3 VALUES('items','i_hash',2,19517,19512,'b75025fbf2e9c504e3c1197ff1b69250402a31f8'); INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,21251,21245,'c7d32f0e3a8f3a0a3dbd00833833d2ccee62f0fd'); INSERT INTO sqlite_stat3 VALUES('items','i_hash',2,23616,23610,'dd5ff61479a9bd4100de802515d9dcf72d46f07a'); INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,24287,24280,'e3db00034301b7555419d4ef6f64769298d5845e'); INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,24949,24942,'ea336abd197ecd7013854a25a4f4eb9dea7927c6'); INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,25574,25567,'f018ea5182ec3f32768ca1c3cefbf3ad160ec20b'); INSERT INTO sqlite_stat3 VALUES('items','i_hash',2,26139,26132,'f53709a8d81c12cb0f4f8d58004a25dd063de67c'); INSERT INTO sqlite_stat3 VALUES('items','i_secid_ex1',25167,0,0,2); INSERT INTO sqlite_stat3 VALUES('items','i_secid_ex1',736,25167,1,3); INSERT INTO sqlite_stat3 VALUES('items','i_secid_ex1',15,25903,2,4); INSERT INTO sqlite_stat3 VALUES('items','i_secid_ex1',1398,25918,3,5); INSERT INTO sqlite_stat3 VALUES('items','i_deleted_at',27316,0,0,NULL); INSERT INTO sqlite_stat3 VALUES('items','i_metadata_type',2149,0,0,1); INSERT INTO sqlite_stat3 VALUES('items','i_metadata_type',411,2149,1,2); INSERT INTO sqlite_stat3 VALUES('items','i_metadata_type',1440,2560,2,3); INSERT INTO sqlite_stat3 VALUES('items','i_metadata_type',23316,4000,3,4); INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,215,215,'com.plexapp.agents.imdb://tt0065702?lang=en'); INSERT INTO sqlite_stat3 VALUES('items','i_guid',2,711,711,'com.plexapp.agents.imdb://tt0198781?lang=en'); INSERT INTO sqlite_stat3 VALUES('items','i_guid',2,987,986,'com.plexapp.agents.imdb://tt0454876?lang=en'); INSERT INTO sqlite_stat3 VALUES('items','i_guid',2,1004,1002,'com.plexapp.agents.imdb://tt0464154?lang=en'); INSERT INTO sqlite_stat3 VALUES('items','i_guid',2,1056,1053,'com.plexapp.agents.imdb://tt0499549?lang=en'); INSERT INTO sqlite_stat3 VALUES('items','i_guid',2,1120,1116,'com.plexapp.agents.imdb://tt0903624?lang=en'); INSERT INTO sqlite_stat3 VALUES('items','i_guid',2,1250,1245,'com.plexapp.agents.imdb://tt1268799?lang=en'); INSERT INTO sqlite_stat3 VALUES('items','i_guid',2,1270,1264,'com.plexapp.agents.imdb://tt1320261?lang=en'); INSERT INTO sqlite_stat3 VALUES('items','i_guid',2,1376,1369,'com.plexapp.agents.imdb://tt1772341?lang=en'); INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,3035,3027,'com.plexapp.agents.thetvdb://153021/3/14?lang=en'); INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,6071,6063,'com.plexapp.agents.thetvdb://71173/1/18?lang=en'); INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,6342,6334,'com.plexapp.agents.thetvdb://71256/13/4?lang=en'); INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,9107,9099,'com.plexapp.agents.thetvdb://72389/2/19?lang=en'); INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,11740,11732,'com.plexapp.agents.thetvdb://73893/2/13?lang=en'); INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,12143,12135,'com.plexapp.agents.thetvdb://73976/4/23?lang=en'); INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,15179,15171,'com.plexapp.agents.thetvdb://75897/16/12?lang=en'); INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,17408,17400,'com.plexapp.agents.thetvdb://76808/2/16?lang=en'); INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,17984,17976,'com.plexapp.agents.thetvdb://77068/1/16?lang=en'); INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,18215,18207,'com.plexapp.agents.thetvdb://77259/1/1?lang=en'); INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,21251,21243,'com.plexapp.agents.thetvdb://78957/8/2?lang=en'); INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,24287,24279,'com.plexapp.agents.thetvdb://80337/5/8?lang=en'); INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,25513,25505,'com.plexapp.agents.thetvdb://82226/6?lang=en'); INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,25548,25540,'com.plexapp.agents.thetvdb://82339/2/10?lang=en'); INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,26770,26762,'com.plexapp.agents.thetvdb://86901/1/3?lang=en'); INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',1524,0,0,''); INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',2,3034,1391,'Attack of the Giant Squid'); INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',51,4742,2895,'Brad Sherwood'); INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',11,4912,2996,'Brian Williams'); INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',39,5847,3857,'Chip Esten'); INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',1,6071,4015,'Chuck Versus the DeLorean'); INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',12,7625,5436,'Denny Siegel'); INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',30,8924,6618,'Episode 1'); INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',29,9015,6629,'Episode 2'); INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',32,9082,6643,'Episode 3'); INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',28,9135,6654,'Episode 4'); INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',26,9183,6665,'Episode 5'); INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',27,9229,6677,'Episode 6'); INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',22,9266,6688,'Episode 7'); INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',20,9298,6699,'Episode 8'); INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',55,11750,8817,'Greg Proops'); INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',1,12143,9120,'Hardware Jungle'); INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',33,14712,11435,'Kathy Greenwood'); INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',3,15179,11840,'Last Call'); INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',1,18215,14601,'Nature or Nurture?'); INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',12,18241,14623,'Neil DeGrasse Tyson'); INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',68,19918,16144,'Pilot'); INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',7,21251,17298,'Reza Aslan'); INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',1,24287,20035,'Technoviking'); INSERT INTO sqlite_stat3 VALUES('items','i_title',1524,0,0,''); INSERT INTO sqlite_stat3 VALUES('items','i_title',1,3035,1429,'Anderson Can''t Dance'); INSERT INTO sqlite_stat3 VALUES('items','i_title',51,4782,2991,'Brad Sherwood'); INSERT INTO sqlite_stat3 VALUES('items','i_title',11,4936,3079,'Brian Williams'); INSERT INTO sqlite_stat3 VALUES('items','i_title',39,5694,3783,'Chip Esten'); INSERT INTO sqlite_stat3 VALUES('items','i_title',1,6071,4100,'Clive Warren'); INSERT INTO sqlite_stat3 VALUES('items','i_title',12,7144,5078,'Denny Siegel'); INSERT INTO sqlite_stat3 VALUES('items','i_title',30,8249,6097,'Episode 1'); INSERT INTO sqlite_stat3 VALUES('items','i_title',29,8340,6108,'Episode 2'); INSERT INTO sqlite_stat3 VALUES('items','i_title',32,8407,6122,'Episode 3'); INSERT INTO sqlite_stat3 VALUES('items','i_title',28,8460,6133,'Episode 4'); INSERT INTO sqlite_stat3 VALUES('items','i_title',26,8508,6144,'Episode 5'); INSERT INTO sqlite_stat3 VALUES('items','i_title',27,8554,6156,'Episode 6'); INSERT INTO sqlite_stat3 VALUES('items','i_title',22,8591,6167,'Episode 7'); INSERT INTO sqlite_stat3 VALUES('items','i_title',20,8623,6178,'Episode 8'); INSERT INTO sqlite_stat3 VALUES('items','i_title',1,9107,6537,'Fat Albert and the Cosby Kids'); INSERT INTO sqlite_stat3 VALUES('items','i_title',55,10539,7843,'Greg Proops'); INSERT INTO sqlite_stat3 VALUES('items','i_title',1,12143,9276,'Iron Age Remains'); INSERT INTO sqlite_stat3 VALUES('items','i_title',33,13118,10143,'Kathy Greenwood'); INSERT INTO sqlite_stat3 VALUES('items','i_title',1,15179,11972,'Mink'); INSERT INTO sqlite_stat3 VALUES('items','i_title',68,17411,14035,'Pilot'); INSERT INTO sqlite_stat3 VALUES('items','i_title',2,18214,14727,'Reflections'); INSERT INTO sqlite_stat3 VALUES('items','i_title',4,21250,17481,'The Apartment'); INSERT INTO sqlite_stat3 VALUES('items','i_title',1,24287,20283,'The Simpsons Already Did It'); INSERT INTO sqlite_stat3 VALUES('items','i_index',4315,95,2,1); INSERT INTO sqlite_stat3 VALUES('items','i_index',1553,4410,3,2); INSERT INTO sqlite_stat3 VALUES('items','i_index',1485,5963,4,3); INSERT INTO sqlite_stat3 VALUES('items','i_index',1414,7448,5,4); INSERT INTO sqlite_stat3 VALUES('items','i_index',1367,8862,6,5); INSERT INTO sqlite_stat3 VALUES('items','i_index',1328,10229,7,6); INSERT INTO sqlite_stat3 VALUES('items','i_index',1161,11557,8,7); INSERT INTO sqlite_stat3 VALUES('items','i_index',1108,12718,9,8); INSERT INTO sqlite_stat3 VALUES('items','i_index',1033,13826,10,9); INSERT INTO sqlite_stat3 VALUES('items','i_index',1014,14859,11,10); INSERT INTO sqlite_stat3 VALUES('items','i_index',929,15873,12,11); INSERT INTO sqlite_stat3 VALUES('items','i_index',906,16802,13,12); INSERT INTO sqlite_stat3 VALUES('items','i_index',844,17708,14,13); INSERT INTO sqlite_stat3 VALUES('items','i_index',690,18552,15,14); INSERT INTO sqlite_stat3 VALUES('items','i_index',655,19242,16,15); INSERT INTO sqlite_stat3 VALUES('items','i_index',625,19897,17,16); INSERT INTO sqlite_stat3 VALUES('items','i_index',579,20522,18,17); INSERT INTO sqlite_stat3 VALUES('items','i_index',555,21101,19,18); INSERT INTO sqlite_stat3 VALUES('items','i_index',526,21656,20,19); INSERT INTO sqlite_stat3 VALUES('items','i_index',501,22182,21,20); INSERT INTO sqlite_stat3 VALUES('items','i_index',459,22683,22,21); INSERT INTO sqlite_stat3 VALUES('items','i_index',439,23142,23,22); INSERT INTO sqlite_stat3 VALUES('items','i_index',315,23581,24,23); INSERT INTO sqlite_stat3 VALUES('items','i_index',192,24177,26,25); INSERT INTO sqlite_stat3 VALUES('items','i_created_at',1851,0,0,NULL); INSERT INTO sqlite_stat3 VALUES('items','i_created_at',373,1857,2,'2011-10-22 14:54:39'); INSERT INTO sqlite_stat3 VALUES('items','i_created_at',595,2230,3,'2011-10-22 14:54:41'); INSERT INTO sqlite_stat3 VALUES('items','i_created_at',337,2825,4,'2011-10-22 14:54:43'); INSERT INTO sqlite_stat3 VALUES('items','i_created_at',361,3378,8,'2011-10-22 14:54:54'); INSERT INTO sqlite_stat3 VALUES('items','i_created_at',160,3739,9,'2011-10-22 14:54:56'); INSERT INTO sqlite_stat3 VALUES('items','i_created_at',315,4000,11,'2011-10-22 14:54:59'); INSERT INTO sqlite_stat3 VALUES('items','i_created_at',321,4334,13,'2011-10-22 14:55:02'); INSERT INTO sqlite_stat3 VALUES('items','i_created_at',1292,4723,16,'2011-10-22 14:55:06'); INSERT INTO sqlite_stat3 VALUES('items','i_created_at',161,6015,17,'2011-10-22 14:55:07'); INSERT INTO sqlite_stat3 VALUES('items','i_created_at',1,9107,2677,'2012-09-04 18:07:50'); INSERT INTO sqlite_stat3 VALUES('items','i_created_at',313,9717,3270,'2012-10-18 16:50:21'); INSERT INTO sqlite_stat3 VALUES('items','i_created_at',450,10030,3271,'2012-10-18 16:50:22'); INSERT INTO sqlite_stat3 VALUES('items','i_created_at',389,10668,3275,'2012-10-18 16:50:26'); INSERT INTO sqlite_stat3 VALUES('items','i_created_at',796,11057,3276,'2012-10-18 16:51:06'); INSERT INTO sqlite_stat3 VALUES('items','i_created_at',161,12041,3280,'2012-10-19 19:52:37'); INSERT INTO sqlite_stat3 VALUES('items','i_created_at',135,13281,4186,'2013-02-19 00:56:10'); INSERT INTO sqlite_stat3 VALUES('items','i_created_at',1063,13416,4187,'2013-02-19 00:56:11'); INSERT INTO sqlite_stat3 VALUES('items','i_created_at',797,14479,4188,'2013-02-19 00:56:13'); INSERT INTO sqlite_stat3 VALUES('items','i_created_at',147,15276,4189,'2013-02-19 00:56:15'); INSERT INTO sqlite_stat3 VALUES('items','i_created_at',346,15423,4190,'2013-02-19 00:56:16'); INSERT INTO sqlite_stat3 VALUES('items','i_created_at',1,18215,6436,'2013-05-05 14:09:54'); INSERT INTO sqlite_stat3 VALUES('items','i_created_at',2,21251,8122,'2013-05-24 15:25:45'); INSERT INTO sqlite_stat3 VALUES('items','i_created_at',1,24287,11116,'2013-05-26 14:17:39'); INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',2560,0,0,NULL); INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',18,3022,31,2350); INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',10,6068,285,8150); INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',158,6346,315,8949); INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',34,9094,562,18831); INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',20,12139,794,22838); INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',134,14033,886,24739); INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',159,14167,887,24740); INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',161,14326,888,24741); INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',161,14487,889,24742); INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',124,14648,890,24743); INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',157,14772,891,24744); INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',126,15043,894,24747); INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',40,15169,895,24748); INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',161,15243,898,24753); INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',138,15404,899,24754); INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',160,15542,900,24755); INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',161,15702,901,24756); INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',161,15863,902,24757); INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',124,16024,903,24758); INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',155,16148,904,24759); INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',26,18208,1043,29704); INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',2,21251,1282,32952); INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',13,24279,1583,36068); INSERT INTO sqlite_stat3 VALUES('items','i_secid',25167,0,0,2); INSERT INTO sqlite_stat3 VALUES('items','i_secid',736,25167,1,3); INSERT INTO sqlite_stat3 VALUES('items','i_secid',15,25903,2,4); INSERT INTO sqlite_stat3 VALUES('items','i_secid',1398,25918,3,5); ANALYZE sqlite_master; explain query plan select items.title from items join items as child on child.parent_id=items.id join items as grandchild on grandchild.parent_id=child.id join settings on settings.guid=grandchild.guid and settings.account_id=1 where items.metadata_type=2 and items.secid=2 and settings.last_viewed_at is not null group by items.id order by settings.last_viewed_at desc limit 10; } [list \ 0 0 3 {SEARCH TABLE settings USING INDEX s_account_id (account_id=?)} \ 0 1 2 {SEARCH TABLE items AS grandchild USING INDEX i_guid (guid=?)} \ 0 2 1 {SEARCH TABLE items AS child USING INTEGER PRIMARY KEY (rowid=?)} \ 0 3 0 {SEARCH TABLE items USING INTEGER PRIMARY KEY (rowid=?)} \ 0 0 0 {USE TEMP B-TREE FOR GROUP BY} \ 0 0 0 {USE TEMP B-TREE FOR ORDER BY}] finish_test |
Changes to test/win32lock.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 script is recovery from transient manditory locks # that sometimes appear on database files due to anti-virus software. # | < < | 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 script is recovery from transient manditory locks # that sometimes appear on database files due to anti-virus software. # if {$tcl_platform(platform)!="windows"} return set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix win32lock |
︙ | ︙ |
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 | set testprefix win32longpath do_test 1.0 { file_control_vfsname db } win32 db close set path [file nativename [get_pwd]] 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] make_win32_dir $longPath(1) set longPath(2) $longPath(1)\\[string repeat X 255] make_win32_dir $longPath(2) set longPath(3) $longPath(2)\\[string repeat Y 255] make_win32_dir $longPath(3) set fileName $longPath(3)\\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 { |
︙ | ︙ | |||
113 114 115 116 117 118 119 | COMMIT; } } {5 6 7 8 9 10 11 12} db3 close # puts " Database exists \{[exists_win32_path $fileName]\}" | < < < < < < < < < < < < | 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | 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 |
Changes to test/window1.test.
︙ | ︙ | |||
254 255 256 257 258 259 260 | } {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}} | < < < | 254 255 256 257 258 259 260 261 262 263 264 265 266 267 | } {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 |
︙ | ︙ | |||
371 372 373 374 375 376 377 | 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} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 368 369 370 371 372 373 374 375 376 377 378 379 380 381 | 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), |
︙ | ︙ | |||
1199 1200 1201 1202 1203 1204 1205 | 13 M cc NULL JM | 3 C cc 1 {} | 4 D cc 8.25 {} | 12 L cc 'xyZ' L | 11 K cc 'xyz' K | } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < | < < < < < | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < | < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 | 13 M cc NULL JM | 3 C cc 1 {} | 4 D cc 8.25 {} | 12 L cc 'xyZ' L | 11 K cc 'xyz' K | } #------------------------------------------------------------------------- # Test that the SQL in ticket [c8d3b9f0a75] - CVE-2020-13871 - does not # cause a problem for this version. # reset_db do_execsql_test 30.0 { CREATE TABLE a(b); } do_execsql_test 30.1 { SELECT(SELECT b FROM a GROUP BY b HAVING(NULL AND b IN((SELECT COUNT() OVER(ORDER BY b) = lead(b) OVER(ORDER BY 3.100000 * SUM(DISTINCT CASE WHEN b LIKE 'SM PACK' THEN b * b ELSE 0 END) / b))))) FROM a EXCEPT SELECT b FROM a ORDER BY b, b, b; } 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 | 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; } 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 | } {} 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} finish_test |
Changes to test/window4.tcl.
︙ | ︙ | |||
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 | execsql_test 11.4 { SELECT * FROM ( SELECT NTILE(256) OVER (ORDER BY total) - 1 AS nt FROM t8 ) sub; } finish_test |
Changes to test/window4.test.
︙ | ︙ | |||
1320 1321 1322 1323 1324 1325 1326 | do_execsql_test 11.4 { SELECT * FROM ( SELECT NTILE(256) OVER (ORDER BY total) - 1 AS nt FROM t8 ) sub; } {0 1 2} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1320 1321 1322 1323 1324 1325 1326 1327 | 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 |
Changes to test/window6.test.
︙ | ︙ | |||
144 145 146 147 148 149 150 | WINDOW win AS (ORDER BY x ROWS BETWEEN +2 FOLLOWING AND +3 FOLLOWING) } {1 0 0} #------------------------------------------------------------------------- # ifcapable !icu { | < | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | WINDOW win AS (ORDER BY x ROWS BETWEEN +2 FOLLOWING AND +3 FOLLOWING) } {1 0 0} #------------------------------------------------------------------------- # ifcapable !icu { do_execsql_test 6.0 { SELECT LIKE('!', '', '!') x WHERE x; } {} do_execsql_test 6.1 { SELECT LIKE("!","","!")""WHeRE""; } {} do_catchsql_test 6.2 { |
︙ | ︙ | |||
365 366 367 368 369 370 371 | } { fifteen fifteen ten fifteen.ten thirty fifteen.ten.thirty } finish_test | > | 364 365 366 367 368 369 370 371 | } { fifteen fifteen ten fifteen.ten thirty fifteen.ten.thirty } finish_test |
Changes to test/window7.test.
︙ | ︙ | |||
37 38 39 40 41 42 43 | (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; | | < | < < < < < < < < < < < | < < < < < < < < < < < | < < < < < < < < < < < < | < < < < < < < < < < < | < < < < < < < < < < < < | < < < < < < < < < < < < | < < < < < < < < < < < | < < < < < < < < < < < | 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 | (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 |
Changes to test/window8.tcl.
︙ | ︙ | |||
193 194 195 196 197 198 199 | } 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; } | < < < < | < | < < < < < < < < < < < < < < | < | < < < < < < < < < < < < < < < < < | 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 | } 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 DESC RANGE BETWEEN 5 FOLLOWING AND 10 FOLLOWING ) FROM t1 ORDER BY 1 NULLS FIRST; } 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.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 DESC NULLS LAST ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING ) FROM t1 ORDER BY 1 NULLS FIRST; } ========== 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), |
︙ | ︙ | |||
280 281 282 283 284 285 286 | 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 | < < < < < < < < < < < | 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | 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 } } { execsql_test 5.$tn.$tn2.1 " SELECT max(c) OVER win, min(c) OVER win, count(a) OVER win FROM t3 |
︙ | ︙ | |||
337 338 339 340 341 342 343 | execsql_test 6.2 { SELECT string_agg(a, '.') OVER ( ORDER BY b DESC NULLS LAST RANGE BETWEEN 7 PRECEDING AND 2 PRECEDING ) FROM t2 } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 289 290 291 292 293 294 295 296 297 298 299 | execsql_test 6.2 { SELECT string_agg(a, '.') OVER ( ORDER BY b DESC NULLS LAST RANGE BETWEEN 7 PRECEDING AND 2 PRECEDING ) FROM t2 } finish_test |
Changes to test/window8.test.
︙ | ︙ | |||
3518 3519 3520 3521 3522 3523 3524 | 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 | | < < < < < < | < < < < < < | | < < < < < < | | | | < < < < < < < < < < < < < < < < < < < < < < < < < | | 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 | 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 ; } {{} {} 6 6 6} do_execsql_test 4.2.2 { SELECT sum(b) OVER ( ORDER BY a DESC RANGE BETWEEN 5 FOLLOWING AND 10 FOLLOWING ) FROM t1 ORDER BY 1 ; } {{} {} 6 6 6} do_execsql_test 4.3.1 { SELECT sum(b) OVER ( ORDER BY a RANGE BETWEEN UNBOUNDED PRECEDING AND 10 FOLLOWING ) FROM t1 ORDER BY 1 ; } {6 6 6 15 15} do_execsql_test 4.4.1 { SELECT sum(b) OVER ( ORDER BY a ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING ) FROM t1 ORDER BY 1 ; } {3 6 9 9 12} do_execsql_test 4.4.2 { SELECT sum(b) OVER ( ORDER BY a DESC ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING ) FROM t1 ORDER BY 1 ; } {5 6 8 9 10} #========================================================================== 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 , 2 , 3 } {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 |
︙ | ︙ | |||
3626 3627 3628 3629 3630 3631 3632 | 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 ) | | | 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 | 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 , 2 , 3 } {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 |
︙ | ︙ | |||
3648 3649 3650 3651 3652 3653 3654 | 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 | | | | 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 | 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 RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 , 2 , 3 } {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 |
︙ | ︙ | |||
3672 3673 3674 3675 3676 3677 3678 | 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 | | | | 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 | 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 RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 , 2 , 3 } {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 |
︙ | ︙ | |||
3698 3699 3700 3701 3702 3703 3704 | 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 ) | | | 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 | 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 , 2 , 3 } {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 |
︙ | ︙ | |||
3722 3723 3724 3725 3726 3727 3728 | 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 ) | | | | | 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 | 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 , 2 , 3 } {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 GROUPS 6 PRECEDING EXCLUDE NO OTHERS ) ORDER BY 1 , 2 , 3 } {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 |
︙ | ︙ | |||
3765 3766 3767 3768 3769 3770 3771 | 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 | | | | 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 | 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 GROUPS 6 PRECEDING EXCLUDE NO OTHERS ) ORDER BY 1 , 2 , 3 } {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 |
︙ | ︙ | |||
3789 3790 3791 3792 3793 3794 3795 | 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 | | | | 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 | 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 RANGE BETWEEN 6 PRECEDING AND 7 FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 , 2 , 3 } {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 |
︙ | ︙ | |||
3812 3813 3814 3815 3816 3817 3818 | 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 | | | | | | 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 | 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 RANGE BETWEEN 6 PRECEDING AND 7 FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 , 2 , 3 } {{} 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 RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 , 2 , 3 } {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 |
︙ | ︙ | |||
3857 3858 3859 3860 3861 3862 3863 | 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 | | | | | | 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 | 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 RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 , 2 , 3 } {{} 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 , b , a ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 , 2 , 3 } {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 |
︙ | ︙ | |||
3903 3904 3905 3906 3907 3908 3909 | 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 | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < | 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 | 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 , b , a ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE NO OTHERS ) ORDER BY 1 , 2 , 3 } {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 |
︙ | ︙ | |||
4256 4257 4258 4259 4260 4261 4262 | 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 ) | | | 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 | 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 , 2 , 3 } {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 |
︙ | ︙ | |||
4279 4280 4281 4282 4283 4284 4285 | 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 ) | | | 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 | 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 , 2 , 3 } {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 |
︙ | ︙ | |||
4301 4302 4303 4304 4305 4306 4307 | 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 | | | | 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 | 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 RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 , 2 , 3 } {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 |
︙ | ︙ | |||
4325 4326 4327 4328 4329 4330 4331 | 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 | | | | 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 | 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 RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 , 2 , 3 } {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 |
︙ | ︙ | |||
4351 4352 4353 4354 4355 4356 4357 | 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 ) | | | 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 | 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 , 2 , 3 } {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 |
︙ | ︙ | |||
4375 4376 4377 4378 4379 4380 4381 | 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 ) | | | | | 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 | 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 , 2 , 3 } {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 GROUPS 6 PRECEDING EXCLUDE CURRENT ROW ) ORDER BY 1 , 2 , 3 } {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 |
︙ | ︙ | |||
4418 4419 4420 4421 4422 4423 4424 | 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 | | | | 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 | 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 GROUPS 6 PRECEDING EXCLUDE CURRENT ROW ) ORDER BY 1 , 2 , 3 } {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 |
︙ | ︙ | |||
4442 4443 4444 4445 4446 4447 4448 | 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 | | | | 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 | 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 RANGE BETWEEN 6 PRECEDING AND 7 FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 , 2 , 3 } {{} {} 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 |
︙ | ︙ | |||
4465 4466 4467 4468 4469 4470 4471 | 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 | | | | | | | | | | 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 | 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 RANGE BETWEEN 6 PRECEDING AND 7 FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 , 2 , 3 } {{} 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 RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 , 2 , 3 } {{} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 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 RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 , 2 , 3 } {{} 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 , b , a ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 , 2 , 3 } {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 |
︙ | ︙ | |||
4554 4555 4556 4557 4558 4559 4560 | 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 | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < | 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 | 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 , b , a ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW ) ORDER BY 1 , 2 , 3 } {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 |
︙ | ︙ | |||
4906 4907 4908 4909 4910 4911 4912 | 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 ) | | | | | | 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 | 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 , 2 , 3 } {{} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 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 , 2 , 3 } {{} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 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 RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE GROUP ) ORDER BY 1 , 2 , 3 } {{} {} 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 |
︙ | ︙ | |||
4970 4971 4972 4973 4974 4975 4976 | 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 | | | | 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 | 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 RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE GROUP ) ORDER BY 1 , 2 , 3 } {{} 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 |
︙ | ︙ | |||
4996 4997 4998 4999 5000 5001 5002 | 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 ) | | | 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 | 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 , 2 , 3 } {{} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 |
︙ | ︙ | |||
5018 5019 5020 5021 5022 5023 5024 | 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 ) | | | | | 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 | 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 , 2 , 3 } {{} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 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 GROUPS 6 PRECEDING EXCLUDE GROUP ) ORDER BY 1 , 2 , 3 } {{} {} 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 |
︙ | ︙ | |||
5060 5061 5062 5063 5064 5065 5066 | 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 | | | | 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 | 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 GROUPS 6 PRECEDING EXCLUDE GROUP ) ORDER BY 1 , 2 , 3 } {{} 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 |
︙ | ︙ | |||
5083 5084 5085 5086 5087 5088 5089 | 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 | | | | 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 | 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 RANGE BETWEEN 6 PRECEDING AND 7 FOLLOWING EXCLUDE GROUP ) ORDER BY 1 , 2 , 3 } {{} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 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 |
︙ | ︙ | |||
5106 5107 5108 5109 5110 5111 5112 | 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 | | | | | | | | | | 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 | 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 RANGE BETWEEN 6 PRECEDING AND 7 FOLLOWING EXCLUDE GROUP ) ORDER BY 1 , 2 , 3 } {{} 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 RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING EXCLUDE GROUP ) ORDER BY 1 , 2 , 3 } {{} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 0 {} {} 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 RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING EXCLUDE GROUP ) ORDER BY 1 , 2 , 3 } {{} 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 , b , a ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE GROUP ) ORDER BY 1 , 2 , 3 } {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 |
︙ | ︙ | |||
5194 5195 5196 5197 5198 5199 5200 | 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 | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < | 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 | 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 , b , a ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE GROUP ) ORDER BY 1 , 2 , 3 } {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 |
︙ | ︙ | |||
5536 5537 5538 5539 5540 5541 5542 | 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 ) | | | 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 | 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 , 2 , 3 } {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 |
︙ | ︙ | |||
5559 5560 5561 5562 5563 5564 5565 | 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 ) | | | | | 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 | 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 , 2 , 3 } {{} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 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 RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE TIES ) ORDER BY 1 , 2 , 3 } {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 |
︙ | ︙ | |||
5602 5603 5604 5605 5606 5607 5608 | 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 | | | | 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 | 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 RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING EXCLUDE TIES ) ORDER BY 1 , 2 , 3 } {{} 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 |
︙ | ︙ | |||
5628 5629 5630 5631 5632 5633 5634 | 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 ) | | | 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 | 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 , 2 , 3 } {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 |
︙ | ︙ | |||
5652 5653 5654 5655 5656 5657 5658 | 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 ) | | | | | 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 | 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 , 2 , 3 } {{} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 1 1 {} 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 GROUPS 6 PRECEDING EXCLUDE TIES ) ORDER BY 1 , 2 , 3 } {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 |
︙ | ︙ | |||
5694 5695 5696 5697 5698 5699 5700 | 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 | | | | 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 | 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 GROUPS 6 PRECEDING EXCLUDE TIES ) ORDER BY 1 , 2 , 3 } {{} 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 |
︙ | ︙ | |||
5718 5719 5720 5721 5722 5723 5724 | 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 | | | | 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 | 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 RANGE BETWEEN 6 PRECEDING AND 7 FOLLOWING EXCLUDE TIES ) ORDER BY 1 , 2 , 3 } {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 |
︙ | ︙ | |||
5741 5742 5743 5744 5745 5746 5747 | 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 | | | | | | 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 | 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 RANGE BETWEEN 6 PRECEDING AND 7 FOLLOWING EXCLUDE TIES ) ORDER BY 1 , 2 , 3 } {{} 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 RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING EXCLUDE TIES ) ORDER BY 1 , 2 , 3 } {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 |
︙ | ︙ | |||
5786 5787 5788 5789 5790 5791 5792 | 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 | | | | | | 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 | 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 RANGE BETWEEN 0 PRECEDING AND 0 FOLLOWING EXCLUDE TIES ) ORDER BY 1 , 2 , 3 } {{} 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 , b , a ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE TIES ) ORDER BY 1 , 2 , 3 } {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 |
︙ | ︙ | |||
5832 5833 5834 5835 5836 5837 5838 | 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 | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < | 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 | 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 , b , a ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE TIES ) ORDER BY 1 , 2 , 3 } {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 |
︙ | ︙ | |||
6187 6188 6189 6190 6191 6192 6193 | 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 ( | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 | 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 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 RANGE BETWEEN 7 PRECEDING AND 2 PRECEDING ) FROM t2 } {{} A.B A.B} finish_test |
Deleted test/window9.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/windowA.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/windowB.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/windowC.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/windowD.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/windowE.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/windowerr.tcl.
︙ | ︙ | |||
60 61 62 63 64 65 66 | 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) } | < < < | 60 61 62 63 64 65 66 67 68 69 | 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) } finish_test |
Changes to test/windowerr.test.
︙ | ︙ | |||
104 105 106 107 108 109 110 | # 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 | < < < < < | 104 105 106 107 108 109 110 111 | # 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 finish_test |
Changes to test/windowfault.test.
︙ | ︙ | |||
205 206 207 208 209 210 211 | } proc tmpread_injectstop {} { set ret [expr $::tmp_read_fail<=0] unset -nocomplain ::tmp_read_fail return $ret } | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | } proc tmpread_injectstop {} { set ret [expr $::tmp_read_fail<=0] unset -nocomplain ::tmp_read_fail return $ret } 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 {0 {}} } catch {db close} tvfs delete finish_test |
Deleted test/windowpushd.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 {recursive reference in a subquery: 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 | 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 xxxxxx | `--SCAN CONSTANT ROW |--SCAN SUBQUERY xxxxxx `--SCAN SUBQUERY xxxxxx } # 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. |
︙ | ︙ | |||
1071 1072 1073 1074 1075 1076 1077 | 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 { | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 | 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}} finish_test |
Changes to test/with2.test.
︙ | ︙ | |||
410 411 412 413 414 415 416 | SELECT 1 UNION ALL SELECT a+1 FROM q, v WHERE a<5 ) SELECT * FROM q; } {1 2 3 4 5} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
Changes to test/with3.test.
︙ | ︙ | |||
28 29 30 31 32 33 34 | 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}} | < < < < < < < < | 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), |
︙ | ︙ | |||
85 86 87 88 89 90 91 | } 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 | | | | | | | | | | | | | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | } 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 xxxxxx | |--SETUP | | `--SCAN CONSTANT ROW | `--RECURSIVE STEP | `--SCAN TABLE cnt |--SCAN SUBQUERY xxxxxx `--SEARCH TABLE 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 xxxxxx | |--SETUP | | `--SCAN CONSTANT ROW | `--RECURSIVE STEP | `--SCAN TABLE cnt |--SCAN TABLE y1 `--SEARCH SUBQUERY xxxxxx 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 xxxxxx | |--SETUP | | |--SCAN CONSTANT ROW | | `--SCALAR SUBQUERY xxxxxx | | `--SCAN TABLE w2 | `--RECURSIVE STEP | |--SCAN TABLE w1 | `--SCAN TABLE c |--SCAN SUBQUERY xxxxxx |--SEARCH TABLE w2 USING INTEGER PRIMARY KEY (rowid=?) `--SEARCH TABLE w1 USING INTEGER PRIMARY KEY (rowid=?) } finish_test |
Deleted test/with5.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/with6.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/without_rowid1.test.
︙ | ︙ | |||
13 14 15 16 17 18 19 | # focus of this file is testing WITHOUT ROWID tables. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix without_rowid1 | < < < < < < < < < < < | 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 | # 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; } {journal sherman gamma patriot | dynamic juliet flipper command | journal sherman ammonia helena | arctic sleep ammonia helena |} |
︙ | ︙ | |||
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | # 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} | > > > > > < < < < < < < < < < < < < < < < < < | 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 | # 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 stat3 { do_execsql_test without_rowid1-1.51 { SELECT DISTINCT tbl, idx FROM sqlite_stat3 ORDER BY idx; } {t1 t1 t1 t1bd} } 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 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 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 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} #------------------------------------------------------------------------- # 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 |
︙ | ︙ | |||
340 341 342 343 344 345 346 | 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'); | | | 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 | 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: t70a}} do_catchsql_test 7.3 { CREATE TABLE t70b( a INT CHECK( rowid!=33 ), b TEXT PRIMARY KEY ) WITHOUT ROWID; } {1 {no such column: rowid}} |
︙ | ︙ | |||
411 412 413 414 415 416 417 | 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} | < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 387 388 389 390 391 392 393 394 395 | 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} 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: ef}} 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: ef}} 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 | 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); | < | | | | | | 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 | 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; SELECT sql FROM 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)}} # 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 1 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 0 # 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_master 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_master 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 { |
︙ | ︙ | |||
1012 1013 1014 1015 1016 1017 1018 | # 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); | < | | | | | | 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 | # 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; 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 1 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 0 # 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_master 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_master 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 { |
︙ | ︙ | |||
1100 1101 1102 1103 1104 1105 1106 | 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); | < | | | | | | 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 | 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; 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 1 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 0 # 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_master 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_master 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 | # # Requirements testing for WITHOUT ROWID tables. # set testdir [file dirname $argv0] source $testdir/tester.tcl | < < < < | 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" |
︙ | ︙ | |||
185 186 187 188 189 190 191 | } {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} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 { |
︙ | ︙ |
Changes to test/without_rowid6.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 | # Verify that WITHOUT ROWID tables work correctly when the PRIMARY KEY # has redundant columns. # set testdir [file dirname $argv0] source $testdir/tester.tcl | < < < < < < < | 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 { |
︙ | ︙ | |||
54 55 56 57 58 59 60 | 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} | < < < | | | < < < | | 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 | 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; } {/SEARCH TABLE 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 TABLE 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 TABLE 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 without_rowid6-510 { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b>3 ORDER BY b; } {/SEARCH TABLE 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 |
Deleted test/without_rowid7.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 | # # $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)); } set ::sqlite3_max_blobsize } {10} do_test zeroblob-1.1.1 { 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 |
︙ | ︙ | |||
76 77 78 79 80 81 82 | # 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)); } | < < < | | < < < < | | < | 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 | # 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)); } 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)); } 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. |
︙ | ︙ | |||
220 221 222 223 224 225 226 | } {SQLITE_ROW} do_test zeroblob-7.2 { sqlite3_column_int $::STMT 0 } {450000} do_test zeroblob-7.3 { sqlite3_finalize $::STMT } {SQLITE_OK} | < | | | | | | < | 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | } {SQLITE_ROW} do_test zeroblob-7.2 { sqlite3_column_int $::STMT 0 } {450000} do_test zeroblob-7.3 { sqlite3_finalize $::STMT } {SQLITE_OK} 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; |
︙ | ︙ |
Deleted test/zeroblobfault.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/zipfile.test.
︙ | ︙ | |||
790 791 792 793 794 795 796 | 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} } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 |
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 | { if (message != null) Console.WriteLine(message); string fileName = Path.GetFileName( Process.GetCurrentProcess().MainModule.FileName); Console.WriteLine(String.Format("usage: {0} <uri>", fileName)); } /////////////////////////////////////////////////////////////////////// /// <summary> /// This method attempts to determine the file name portion of the /// specified URI. |
︙ | ︙ | |||
333 334 335 336 337 338 339 | // if (args == null) { Error(null, true); return (int)ExitCode.MissingArgs; } | | < < < < < < < < < < | | | | | | | | < < < < < < < < < < | 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 | // if (args == null) { Error(null, true); return (int)ExitCode.MissingArgs; } if (args.Length != 1) { 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: Attempt to extract the file name portion of the URI we // just created. // string fileName = GetFileName(uri); if (fileName == null) { Error("Could not extract the file name from the 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 { 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.
︙ | ︙ | |||
9 10 11 12 13 14 15 | SETLOCAL REM SET __ECHO=ECHO REM SET __ECHO2=ECHO REM SET __ECHO3=ECHO IF NOT DEFINED _AECHO (SET _AECHO=REM) IF NOT DEFINED _CECHO (SET _CECHO=REM) | < < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | SETLOCAL REM SET __ECHO=ECHO REM SET __ECHO2=ECHO REM SET __ECHO3=ECHO IF NOT DEFINED _AECHO (SET _AECHO=REM) IF NOT DEFINED _CECHO (SET _CECHO=REM) IF NOT DEFINED _VECHO (SET _VECHO=REM) SET OVERWRITE=^> IF DEFINED __ECHO SET OVERWRITE=^^^> SET APPEND=^>^> IF DEFINED __ECHO SET APPEND=^^^>^^^> |
︙ | ︙ | |||
37 38 39 40 41 42 43 | 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 | SET DUMMY2=%2 IF DEFINED DUMMY2 ( GOTO usage ) SET ROOT=%~dp0\.. SET ROOT=%ROOT:\\=\% %_VECHO% Root = '%ROOT%' SET TOOLS=%~dp0 SET TOOLS=%TOOLS:~0,-1% %_VECHO% Tools = '%TOOLS%' IF NOT DEFINED windir ( |
︙ | ︙ | |||
63 64 65 66 67 68 69 | ECHO The TEMP environment variable must be set first. GOTO errors ) %_VECHO% Temp = '%TEMP%' IF NOT DEFINED TCLKIT_URI ( | | < < < < < < < < < < < < < < < < < < < < < | 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 | ECHO The TEMP environment variable must be set first. GOTO errors ) %_VECHO% Temp = '%TEMP%' IF NOT DEFINED TCLKIT_URI ( SET TCLKIT_URI=https://tclsh.com/ ) %_VECHO% TclKitUri = '%TCLKIT_URI%' IF /I "%PROCESSOR%" == "x86" ( CALL :fn_TclKitX86Variables ) ELSE IF /I "%PROCESSOR%" == "x64" ( CALL :fn_TclKitX64Variables ) ELSE ( GOTO usage ) %_VECHO% TclKitVersion = '%TCLKIT_VERSION%' %_VECHO% TclKitPatchLevel = '%TCLKIT_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%' |
︙ | ︙ | |||
193 194 195 196 197 198 199 | GOTO errors ) :skip_sdkUnZip IF DEFINED TCLKIT_NOENV GOTO skip_sdkEnvironment | | | | | | | | | < < < | < | < | < < < | < | < | 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 | GOTO errors ) :skip_sdkUnZip IF DEFINED TCLKIT_NOENV GOTO skip_sdkEnvironment %__ECHO% ECHO SET TCLSH_CMD=%TEMP%\%TCLKIT_EXE%%OVERWRITE%"%ROOT%\SetTclKitEnv.bat" IF DEFINED TCLKIT_NOSDK GOTO skip_sdkVariables %__ECHO% ECHO SET TCLINCDIR=%TEMP%\%TCLKIT_SDK%\include%APPEND%"%ROOT%\SetTclKitEnv.bat" %__ECHO% ECHO SET TCLLIBDIR=%TEMP%\%TCLKIT_SDK%\lib%APPEND%"%ROOT%\SetTclKitEnv.bat" %__ECHO% ECHO SET LIBTCLPATH=%TEMP%\%TCLKIT_SDK%\lib%APPEND%"%ROOT%\SetTclKitEnv.bat" %__ECHO% ECHO SET LIBTCL=%TCLKIT_LIB%%APPEND%"%ROOT%\SetTclKitEnv.bat" %__ECHO% ECHO SET LIBTCLSTUB=%TCLKIT_LIB_STUB%%APPEND%"%ROOT%\SetTclKitEnv.bat" :skip_sdkVariables ECHO. ECHO Wrote "%ROOT%\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 ( SET TCLKIT_PATCHLEVEL=8.6.6 ) SET TCLKIT_VERSION=%TCLKIT_PATCHLEVEL:.=% SET TCLKIT_VERSION=%TCLKIT_VERSION:~0,2% REM SET TCLKIT_EXE=tclkit-%TCLKIT_PATCHLEVEL%.exe SET TCLKIT_EXE=tclkit-8.6.4.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 ( SET TCLKIT_PATCHLEVEL=8.6.6 ) SET TCLKIT_VERSION=%TCLKIT_PATCHLEVEL:.=% SET TCLKIT_VERSION=%TCLKIT_VERSION:~0,2% REM SET TCLKIT_EXE=tclkit-%TCLKIT_PATCHLEVEL%.exe SET TCLKIT_EXE=tclkit-8.6.4.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% |
︙ | ︙ |
Changes to tool/build-all-msvc.bat.
︙ | ︙ | |||
125 126 127 128 129 130 131 | SETLOCAL REM SET __ECHO=ECHO REM SET __ECHO2=ECHO REM SET __ECHO3=ECHO IF NOT DEFINED _AECHO (SET _AECHO=REM) IF NOT DEFINED _CECHO (SET _CECHO=REM) | < < | 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | SETLOCAL REM SET __ECHO=ECHO REM SET __ECHO2=ECHO REM SET __ECHO3=ECHO IF NOT DEFINED _AECHO (SET _AECHO=REM) IF NOT DEFINED _CECHO (SET _CECHO=REM) IF NOT DEFINED _VECHO (SET _VECHO=REM) SET REDIRECT=^> IF DEFINED __ECHO SET REDIRECT=^^^> %_AECHO% Running %0 %* |
︙ | ︙ | |||
175 176 177 178 179 180 181 | REM CALL :fn_ResetErrorLevel REM REM NOTE: Change the current directory to the root of the source tree, saving REM the current directory on the directory stack. REM | < | 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | REM CALL :fn_ResetErrorLevel REM REM NOTE: Change the current directory to the root of the source tree, saving REM the current directory on the directory stack. REM %__ECHO2% PUSHD "%ROOT%" IF ERRORLEVEL 1 ( ECHO Could not change directory to "%ROOT%". GOTO errors ) |
︙ | ︙ | |||
523 524 525 526 527 528 529 | REM symbols file for this platform to the platform-specific REM directory beneath the binary directory. REM "%ComSpec%" /C ( REM REM NOTE: Attempt to setup the MSVC environment for this platform. REM | < | 520 521 522 523 524 525 526 527 528 529 530 531 532 533 | REM symbols file for this platform to the platform-specific REM directory beneath the binary directory. REM "%ComSpec%" /C ( REM REM NOTE: Attempt to setup the MSVC environment for this platform. REM %__ECHO3% CALL "%VCVARSALL%" %%P IF ERRORLEVEL 1 ( ECHO Failed to call "%VCVARSALL%" for platform %%P. GOTO errors ) |
︙ | ︙ | |||
749 750 751 752 753 754 755 | GOTO errors ) ) REM REM NOTE: Restore the saved current directory from the directory stack. REM | < | 745 746 747 748 749 750 751 752 753 754 755 756 757 758 | GOTO errors ) ) REM REM NOTE: Restore the saved current directory from the directory stack. REM %__ECHO2% POPD IF ERRORLEVEL 1 ( ECHO Could not restore directory. GOTO errors ) |
︙ | ︙ |
Changes to tool/dbhash.c.
︙ | ︙ | |||
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)) | > > > > > > > > > > > > > > > | 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 | */ /* * 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. */ #if __GNUC__ && (defined(__i386__) || defined(__x86_64__)) /* * GCC by itself only generates left rotates. Use right rotates if * possible to be kinder to dinky implementations with iterative rotate * instructions. */ #define SHA_ROT(op, x, k) \ ({ unsigned int y; asm(op " %1,%0" : "=r" (y) : "I" (k), "0" (x)); y; }) #define rol(x,k) SHA_ROT("roll", x, k) #define ror(x,k) SHA_ROT("rorl", x, k) #else /* Generic C equivalent */ #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) #endif #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)) |
︙ | ︙ | |||
436 437 438 439 440 441 442 | ; zDb = argv[i]; rc = sqlite3_open_v2(zDb, &g.db, openFlags, 0); if( rc ){ fprintf(stderr, "cannot open database file '%s'\n", zDb); continue; } | | | | 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 | ; 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_master", 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_master\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) ){ |
︙ | ︙ | |||
472 473 474 475 476 477 478 | } sqlite3_finalize(pStmt); } /* Hash the database schema */ if( !omitSchema ){ hash_one_query( | | | 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 | } sqlite3_finalize(pStmt); } /* Hash the database schema */ if( !omitSchema ){ hash_one_query( "SELECT type, name, tbl_name, sql FROM sqlite_master\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.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** Copyright 2008 D. Richard Hipp and Hipp, Wyrick & Company, Inc. ** All Rights Reserved ** ****************************************************************************** ** ** This file implements a stand-alone utility program that converts ** a binary file (usually an SQLite database) into a text format that ** is compact and friendly to human-readers. ** ** Usage: ** | | < < < < < < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* ** Copyright 2008 D. Richard Hipp and Hipp, Wyrick & Company, Inc. ** All Rights Reserved ** ****************************************************************************** ** ** This file implements a stand-alone utility program that converts ** a binary file (usually an SQLite database) into a text format that ** is compact and friendly to human-readers. ** ** Usage: ** ** dbtotxt [--pagesize N] FILENAME ** ** The translation of the database appears on standard output. If the ** --pagesize command-line option is omitted, then the page size is taken ** from the database header. ** ** Compactness is achieved by suppressing lines of all zero bytes. This ** works well at compressing test databases that are mostly empty. But |
︙ | ︙ | |||
45 46 47 48 49 50 51 | 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 */ | < < < < | | | < < < < < < < | < < < < < < | | < | < < < < < < < < < < < < < < < < < < | > > | > > > > > > > < < < < | 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 | 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++; pgsz = atoi(argv[i]); if( pgsz<512 || pgsz>65536 || (pgsz&(pgsz-1))!=0 ){ fprintf(stderr, "Page size must be a power of two between" " 512 and 65536.\n"); nErr++; } continue; } fprintf(stderr, "Unknown option: %s\n", argv[i]); nErr++; }else if( zInputFile ){ fprintf(stderr, "Already using a different input file: [%s]\n", argv[i]); nErr++; }else{ zInputFile = argv[i]; } } if( zInputFile==0 ){ fprintf(stderr, "No input file specified.\n"); nErr++; } if( nErr ){ fprintf(stderr, "Usage: %s [--pagesize N] FILENAME\n", argv[0]); exit(1); } in = fopen(zInputFile, "rb"); 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 ){ fprintf(stderr, "Could not read input file starting at byte %d\n", i+got); } memset(aLine+got, 0, 16-got); } if( allZero(aLine) ) continue; iPage = i/pgsz + 1; if( lastPage!=iPage ){ 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; } |
Deleted tool/enlargedb.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
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_master 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_master WHERE type='table' AND name!='sqlite_sequence'" " AND rootpage>0" ); execExecSql(db, "SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14)" " FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %'" ); execExecSql(db, "SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21) " " FROM sqlite_master 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_master " "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_master WHERE name='sqlite_sequence'" ); execExecSql(db, "SELECT 'INSERT INTO vacuum_db.' || quote(name) " "|| ' SELECT * FROM main.' || quote(name) " "FROM vacuum_db.sqlite_master 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_master " " SELECT type, name, tbl_name, rootpage, sql" " FROM main.sqlite_master" " 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.
︙ | ︙ | |||
100 101 102 103 104 105 106 | 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; } | | | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | 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_master", -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; |
︙ | ︙ | |||
122 123 124 125 126 127 128 | 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)" | | | 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | 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_master" " 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 ){ |
︙ | ︙ | |||
201 202 203 204 205 206 207 | } sqlite3_finalize(pStmt); /* Generate the report */ rc = sqlite3_prepare_v2(db, "SELECT tbl, idx, cnt, " " (SELECT group_concat(name,',') FROM pragma_index_info(idx))" | | | | | 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | } 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_master" " WHERE temp.idxu.tbl=main.sqlite_master.tbl_name" " AND temp.idxu.idx=main.sqlite_master.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; } |
︙ | ︙ |
Changes to tool/lemon.c.
︙ | ︙ | |||
214 215 216 217 218 219 220 | 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); 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 */ |
︙ | ︙ | |||
288 289 290 291 292 293 294 295 296 297 | 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 */ | > > < < < < | 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 | 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 */ int noCode; /* True if this rule has no associated C code */ int codeEmitted; /* True if the code has been emitted already */ 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 canReduce; /* True if this rule is ever reduced */ Boolean doesReduce; /* Reduce actions occur after optimization */ 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 |
︙ | ︙ | |||
383 384 385 386 387 388 389 | 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 */ | < | | 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 | 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 */ char *arg; /* Declaration of the 3th 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 */ |
︙ | ︙ | |||
419 420 421 422 423 424 425 | 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 */ | < | 416 417 418 419 420 421 422 423 424 425 426 427 428 429 | 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(); \ |
︙ | ︙ | |||
484 485 486 487 488 489 490 | /****************** 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){ | | | | | | | | | | 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 | /****************** 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 *freelist = 0; struct action *newaction; if( freelist==0 ){ int i; int amt = 100; freelist = (struct action *)calloc(amt, sizeof(struct action)); if( freelist==0 ){ fprintf(stderr,"Unable to allocate memory for a new parser action."); exit(1); } for(i=0; i<amt-1; i++) freelist[i].next = &freelist[i+1]; freelist[amt-1].next = 0; } newaction = freelist; freelist = freelist->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 */ |
︙ | ︙ | |||
907 908 909 910 911 912 913 | Configlist_init(); /* Find the start symbol */ if( lemp->start ){ sp = Symbol_find(lemp->start); if( sp==0 ){ ErrorMsg(lemp->filename,0, | | | | | < < < | | | | 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 | 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{ sp = lemp->startRule->lhs; } /* 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 |
︙ | ︙ | |||
1026 1027 1028 1029 1030 1031 1032 | 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 */ | | | 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 | 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 contibutes 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 */ |
︙ | ︙ | |||
1082 1083 1084 1085 1086 1087 1088 | 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]; | | | | 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 | 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->cfp; 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->cfp; cfp; cfp=cfp->next){ for(plp=cfp->bplp; plp; plp=plp->next){ other = plp->cfp; Plink_add(&other->fplp,cfp); } } } } |
︙ | ︙ | |||
1114 1115 1116 1117 1118 1119 1120 | int i; struct config *cfp; struct plink *plp; int progress; int change; for(i=0; i<lemp->nstate; i++){ | < < | 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 | 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; |
︙ | ︙ | |||
1173 1174 1175 1176 1177 1178 1179 | } } } /* Add the accepting token */ if( lemp->start ){ sp = Symbol_find(lemp->start); | < < < < < < | < | 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 | } } } /* Add the accepting token */ if( lemp->start ){ sp = Symbol_find(lemp->start); if( sp==0 ) 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); |
︙ | ︙ | |||
1307 1308 1309 1310 1311 1312 1313 | 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){ | > > > > | > > > > > > > > > > | 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 | 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){ struct config *newcfg; if( freelist==0 ){ int i; int amt = 3; freelist = (struct config *)calloc( amt, sizeof(struct config) ); if( freelist==0 ){ fprintf(stderr,"Unable to allocate memory for a new configuration."); exit(1); } for(i=0; i<amt-1; i++) freelist[i].next = &freelist[i+1]; freelist[amt-1].next = 0; } newcfg = freelist; freelist = freelist->next; return newcfg; } /* The configuration "old" is no longer used */ PRIVATE void deleteconfig(struct config *old) { old->next = freelist; freelist = old; |
︙ | ︙ | |||
1585 1586 1587 1588 1589 1590 1591 | return pFirst; } /* ** Sort a list of rules in order of increasing iRule value */ static struct rule *Rule_sort(struct rule *rp){ | | | | 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 | return pFirst; } /* ** Sort a list of rules in order of increasing iRule value */ static struct rule *Rule_sort(struct rule *rp){ 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]) && x[i]; i++){ rp = Rule_merge(x[i], rp); x[i] = 0; } x[i] = rp; rp = pNext; } rp = 0; |
︙ | ︙ | |||
1619 1620 1621 1622 1623 1624 1625 | int nLabel = lemonStrlen(zLabel); printf(" %s%.*s %5d\n", zLabel, 35-nLabel, "................................", iValue); } /* The main program. Parse the command line and do it... */ | | > < < < < < < < | | 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 | 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 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_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, "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; 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; Symbol_new("$"); /* Parse the input file */ Parse(&lem); if( 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 */ |
︙ | ︙ | |||
1715 1716 1717 1718 1719 1720 1721 | /* 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; } | < | 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 | /* 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 */ |
︙ | ︙ | |||
1763 1764 1765 1766 1767 1768 1769 | ** 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 */ | | | 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 | ** 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); /* 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 ){ |
︙ | ︙ | |||
1881 1882 1883 1884 1885 1886 1887 | ** 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 | | | 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 | ** 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 ** orginally in list. ** ** Side effects: ** The "next" pointers for elements in list are changed. */ #define LISTSIZE 30 static char *msort( char *list, |
︙ | ︙ | |||
1913 1914 1915 1916 1917 1918 1919 | 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" **************************/ | | < | | < < < | | | | | | | | | | | | 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 | 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 **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( argv[0] ) fprintf(err,"%s",argv[0]); spcnt = lemonStrlen(argv[0]) + 1; for(i=1; i<n && argv[i]; i++){ fprintf(err," %s",argv[i]); spcnt += lemonStrlen(argv[i])+1; } spcnt += k; for(; argv[i]; i++) fprintf(err," %s",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( argv!=0 && *argv!=0 ){ for(i=1; argv[i]; i++){ if( dashdash || !ISOPT(argv[i]) ){ if( n==0 ) return i; n--; } if( strcmp(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(&argv[i][1],op[j].label,lemonStrlen(op[j].label))==0 ) break; } v = 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))(&argv[i][2]); }else{ if( err ){ fprintf(err,"%smissing argument on switch.\n",emsg); errline(i,1,err); } errcnt++; } |
︙ | ︙ | |||
2014 2015 2016 2017 2018 2019 2020 | { int lv = 0; double dv = 0.0; char *sv = 0, *end; char *cp; int j; int errcnt = 0; | | | | 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 | { int lv = 0; double dv = 0.0; char *sv = 0, *end; char *cp; int j; int errcnt = 0; cp = strchr(argv[i],'='); assert( cp!=0 ); *cp = 0; for(j=0; op[j].label; j++){ if( strcmp(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); } |
︙ | ︙ | |||
2045 2046 2047 2048 2049 2050 2051 | case OPT_DBL: case OPT_FDBL: dv = strtod(cp,&end); if( *end ){ if( err ){ fprintf(err, "%sillegal character in floating-point argument.\n",emsg); | | | | 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 | 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*)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*)argv[i]),err); } errcnt++; } break; case OPT_STR: case OPT_FSTR: sv = cp; |
︙ | ︙ | |||
2096 2097 2098 2099 2100 2101 2102 | } return errcnt; } int OptInit(char **a, struct s_options *o, FILE *err) { int errcnt = 0; | | | | | | | | | | | | 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 | } return errcnt; } int OptInit(char **a, struct s_options *o, FILE *err) { int errcnt = 0; argv = a; op = o; errstream = err; if( argv && *argv && op ){ int i; for(i=1; argv[i]; i++){ if( argv[i][0]=='+' || argv[i][0]=='-' ){ errcnt += handleflags(i,err); }else if( strchr(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( argv!=0 && argv[0]!=0 ){ for(i=1; argv[i]; i++){ if( dashdash || !ISOPT(argv[i]) ) cnt++; if( strcmp(argv[i],"--")==0 ) dashdash = 1; } } return cnt; } char *OptArg(int n) { int i; i = argindex(n); return i>=0 ? argv[i] : 0; } void OptErr(int n) { int i; i = argindex(n); if( i>=0 ) errline(i,0,errstream); |
︙ | ︙ | |||
2264 2265 2266 2267 2268 2269 2270 | #endif switch( psp->state ){ case INITIALIZE: psp->prevrule = 0; psp->preccounter = 0; psp->firstrule = psp->lastrule = 0; psp->gp->nrule = 0; | | | | | | < < | 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 | #endif switch( psp->state ){ case INITIALIZE: psp->prevrule = 0; psp->preccounter = 0; psp->firstrule = psp->lastrule = 0; psp->gp->nrule = 0; /* Fall thru to next case */ 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{ psp->prevrule->line = psp->tokenlineno; psp->prevrule->code = &x[1]; psp->prevrule->noCode = 0; } }else if( x[0]=='[' ){ psp->state = PRECEDENCE_MARK_1; |
︙ | ︙ | |||
2311 2312 2313 2314 2315 2316 2317 | 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, | | | | 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 | 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: |
︙ | ︙ | |||
2424 2425 2426 2427 2428 2429 2430 | psp->errorcnt++; psp->state = RESYNC_AFTER_RULE_ERROR; }else{ psp->rhs[psp->nrhs] = Symbol_new(x); psp->alias[psp->nrhs] = 0; psp->nrhs++; } | | | 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 | 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 ){ 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; |
︙ | ︙ | |||
2636 2637 2638 2639 2640 2641 2642 | if( *psp->declargslot ){ zOld = *psp->declargslot; }else{ zOld = ""; } nOld = lemonStrlen(zOld); n = nOld + nNew + 20; | | < < | | 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 | if( *psp->declargslot ){ zOld = *psp->declargslot; }else{ zOld = ""; } nOld = lemonStrlen(zOld); n = nOld + nNew + 20; addLineMacro = !psp->gp->nolinenosflag && psp->insertLineMacro && (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; |
︙ | ︙ | |||
2706 2707 2708 2709 2710 2711 2712 | } 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 ** | | | 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 | } 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]) ){ |
︙ | ︙ | |||
2742 2743 2744 2745 2746 2747 2748 | psp->errorcnt++; } } break; case WAITING_FOR_CLASS_ID: if( !ISLOWER(x[0]) ){ ErrorMsg(psp->filename, psp->tokenlineno, | | | 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 | 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: ", 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; |
︙ | ︙ | |||
2783 2784 2785 2786 2787 2788 2789 | 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; } } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < | < | < < | < < | | | > | | > > | | 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 | 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){ int i, j, k, n; 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],"%ifdef",6)==0 && ISSPACE(z[i+6])) || (strncmp(&z[i],"%ifndef",7)==0 && ISSPACE(z[i+7])) ){ if( exclude ){ exclude++; }else{ for(j=i+7; ISSPACE(z[j]); j++){} for(n=0; z[j+n] && !ISSPACE(z[j+n]); n++){} exclude = 1; for(k=0; k<nDefine; k++){ if( strncmp(azDefine[k],&z[j],n)==0 && lemonStrlen(azDefine[k])==n ){ exclude = 0; break; } } if( z[i+3]=='n' ) exclude = !exclude; if( exclude ){ start = i; start_lineno = lineno; } } for(j=i; z[j] && z[j]!='\n'; j++) z[j] = ' '; } |
︙ | ︙ | |||
2994 2995 2996 2997 2998 2999 3000 | return; } fclose(fp); filebuf[filesize] = 0; /* Make an initial pass through the file to handle %ifdef and %ifndef */ preprocess_input(filebuf); | < < < < < | < | 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 | 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 */ cp+=2; while( (c= *cp)!=0 && c!='\n' ) cp++; continue; } if( c=='/' && cp[1]=='*' ){ /* Skip C style comments */ cp+=2; while( (c= *cp)!=0 && (c!='/' || cp[-1]!='*') ){ if( c=='\n' ) lineno++; cp++; } if( c ) cp++; continue; } ps.tokenstart = cp; /* Mark the beginning of the token */ ps.tokenlineno = lineno; /* Linenumber on which token begins */ if( c=='\"' ){ /* String literals */ 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; |
︙ | ︙ | |||
3069 3070 3071 3072 3073 3074 3075 | if( prevc=='\\' ) prevc = 0; else prevc = c; } } } if( c==0 ){ ErrorMsg(ps.filename,ps.tokenlineno, | | < | 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 | 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++; |
︙ | ︙ | |||
3512 3513 3514 3515 3516 3517 3518 | fprintf(fp,"\n"); } fclose(fp); return; } /* Search for the file "name" which is in the same directory as | | | | | 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 | fprintf(fp,"\n"); } fclose(fp); return; } /* Search for the file "name" which is in the same directory as ** the exacutable */ PRIVATE char *pathsearch(char *argv0, char *name, int modemask) { const char *pathlist; char *pathbufptr; char *pathbuf; char *path,*cp; char c; #ifdef __WIN32__ cp = strrchr(argv0,'\\'); #else cp = strrchr(argv0,'/'); |
︙ | ︙ | |||
3551 3552 3553 3554 3555 3556 3557 | *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; } | < | > | < < | 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 | *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 ){ 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; |
︙ | ︙ | |||
3620 3621 3622 3623 3624 3625 3626 | } } } fprintf(out,"%s",&line[iStart]); } } | < < < < < < < < < < < | 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 | } } } 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); |
︙ | ︙ | |||
3670 3671 3672 3673 3674 3675 3676 | lemon_sprintf(buf,"%s.lt",lemp->filename); } if( access(buf,004)==0 ){ tpltname = buf; }else if( access(templatename,004)==0 ){ tpltname = templatename; }else{ | | | > < | 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 | lemon_sprintf(buf,"%s.lt",lemp->filename); } if( access(buf,004)==0 ){ tpltname = buf; }else if( access(templatename,004)==0 ){ tpltname = templatename; }else{ 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",templatename); lemp->errorcnt++; return 0; } 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); |
︙ | ︙ | |||
3869 3870 3871 3872 3873 3874 3875 | 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 | | | 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 | 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 distructor 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; |
︙ | ︙ | |||
3989 3990 3991 3992 3993 3994 3995 | 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.", | | | 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 | 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); 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]); |
︙ | ︙ | |||
4091 4092 4093 4094 4095 4096 4097 | */ 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 */ ){ | | | 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 | */ 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 = *plineno; /* 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 */ |
︙ | ︙ | |||
4283 4284 4285 4286 4287 4288 4289 | } } /* Generate C source code for the parser */ void ReportTable( struct lemon *lemp, | | < | > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < > > | < < | | | | | > | 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 | } } /* Generate C source code for the parser */ void ReportTable( struct lemon *lemp, int mhflag /* Output in makeheaders format if true */ ){ FILE *out, *in; char line[LINESIZE]; int lineno; struct state *stp; struct action *ap; struct rule *rp; struct acttab *pActtab; int i, j, n, sz; int szActionType; /* sizeof(YYACTIONTYPE) */ int szCodeType; /* sizeof(YYCODETYPE) */ const char *name; int mnTknOfst, mxTknOfst; int mnNtOfst, mxNtOfst; struct axset *ax; 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; } lineno = 1; 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( mhflag ){ const char *prefix; fprintf(out,"#if INTERFACE\n"); lineno++; if( lemp->tokenprefix ) prefix = lemp->tokenprefix; else prefix = ""; 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", |
︙ | ︙ | |||
4583 4584 4585 4586 4587 4588 4589 | } } /* 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++; | < < | 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 | } } /* 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++; |
︙ | ︙ | |||
4639 4640 4641 4642 4643 4644 4645 | 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); | | < < < < < < < < < < < < < < < < | 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 | 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 || i==n-1 ){ fprintf(out, "\n"); lineno++; j = 0; }else{ j++; } } 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++; |
︙ | ︙ | |||
4741 4742 4743 4744 4745 4746 4747 | 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; | < < | > | 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 | 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; 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, p->name, p->fallback->name); } lineno++; } } tplt_xfer(lemp->name, in, out, &lineno); /* Generate a table containing the symbolic name of every symbol */ for(i=0; i<lemp->nsymbol; i++){ lemon_sprintf(line,"\"%s\",",lemp->symbols[i]->name); fprintf(out," /* %4d */ \"%s\",\n",i, lemp->symbols[i]->name); lineno++; } tplt_xfer(lemp->name,in,out,&lineno); /* Generate a table containing a text string that describes every ** rule in the rule set of the grammar. This information is used ** when tracing REDUCE actions. |
︙ | ︙ | |||
4848 4849 4850 4851 4852 4853 4854 | 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 | | | 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 | 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 ** sequentually 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); |
︙ | ︙ | |||
4903 4904 4905 4906 4907 4908 4909 | ** 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); | < < < | | 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 | ** 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->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++; |
︙ | ︙ | |||
4934 4935 4936 4937 4938 4939 4940 | /* Append any addition code the user desires */ tplt_print(out,lemp,lemp->extracode,&lineno); acttab_free(pActtab); fclose(in); fclose(out); | < | 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 | /* Append any addition code the user desires */ tplt_print(out,lemp,lemp->extracode,&lineno); acttab_free(pActtab); fclose(in); fclose(out); return; } /* Generate a header file for the parser */ void ReportHeader(struct lemon *lemp) { FILE *out, *in; |
︙ | ︙ | |||
5336 5337 5338 5339 5340 5341 5342 | 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; } | | < | 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 | 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); *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); |
︙ | ︙ | |||
5505 5506 5507 5508 5509 5510 5511 | 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; } | | < < | 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 | 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); *x2a = array; } /* Insert the new data */ h = ph & (x2a->size-1); np = &(x2a->tbl[x2a->count++]); np->key = key; np->data = data; |
︙ | ︙ | |||
5843 5844 5845 5846 5847 5848 5849 | 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; } | | < < | 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 | 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); *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 25 26 27 | ** 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 **********************************/ | > > | > > | | | 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 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: */ #include <stdio.h> #include <assert.h> /************ Begin %include sections from the grammar ************************/ %% /**************** End of %include directives **********************************/ /* These constants specify the various numeric values for terminal symbols ** in a format understandable to "makeheaders". This section is blank unless ** "lemon" is run with the "-m" command-line option. ***************** Begin makeheaders token definitions *************************/ %% /**************** End makeheaders 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. |
︙ | ︙ | |||
219 220 221 222 223 224 225 | #else yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ yyStackEntry *yystackEnd; /* Last entry in the stack */ #endif }; typedef struct yyParser yyParser; | < | 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 |
︙ | ︙ | |||
514 515 516 517 518 519 520 | assert( stateno <= YY_SHIFT_COUNT ); #if defined(YYCOVERAGE) yycoverage[stateno][iLookAhead] = 1; #endif do{ i = yy_shift_ofst[stateno]; assert( i>=0 ); | < | < | | | < > > > > > > > | | > < | 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 | assert( stateno <= YY_SHIFT_COUNT ); #if defined(YYCOVERAGE) yycoverage[stateno][iLookAhead] = 1; #endif do{ i = yy_shift_ofst[stateno]; assert( i>=0 ); /* assert( i+YYNTOKEN<=(int)YY_NLOOKAHEAD ); */ assert( iLookAhead!=YYNOCODE ); assert( iLookAhead < YYNTOKEN ); i += iLookAhead; if( i>=YY_NLOOKAHEAD || yy_lookahead[i]!=iLookAhead ){ #ifdef YYFALLBACK YYCODETYPE iFallback; /* Fallback token */ if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0]) && (iFallback = yyFallback[iLookAhead])!=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; if( #if YY_SHIFT_MIN+YYWILDCARD<0 j>=0 && #endif #if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT j<YY_ACTTAB_COUNT && #endif j<(int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])) && 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{ return yy_action[i]; } }while(1); } /* ** Find the appropriate action for a parser given the non-terminal |
︙ | ︙ | |||
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 | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | 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; #ifndef NDEBUG if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ yysize = yyRuleInfoNRhs[yyruleno]; if( yysize ){ fprintf(yyTraceFILE, "%sReduce %d [%s], go to state %d.\n", yyTracePrompt, yyruleno, yyRuleName[yyruleno], yymsp[yysize].stateno); }else{ fprintf(yyTraceFILE, "%sReduce %d [%s].\n", yyTracePrompt, yyruleno, yyRuleName[yyruleno]); } } #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); /* The call to yyStackOverflow() above pops the stack until it is ** empty, causing the main parser loop to exit. So the return value ** is never used and does not matter. */ return 0; } #else if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){ if( yyGrowStack(yypParser) ){ yyStackOverflow(yypParser); /* The call to yyStackOverflow() above pops the stack until it is ** empty, causing the main parser loop to exit. So the return value ** is never used and does not matter. */ return 0; } yymsp = yypParser->yytos; } #endif } switch( yyruleno ){ /* Beginning here are the reduction cases. A typical example ** follows: ** case 0: ** #line <lineno> <grammarfile> ** { ... } // User supplied code |
︙ | ︙ | |||
872 873 874 875 876 877 878 | }else{ fprintf(yyTraceFILE,"%sInput '%s' with pending reduce %d\n", yyTracePrompt,yyTokenName[yymajor],yyact-YY_MIN_REDUCE); } } #endif | < < > < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < | | 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 | }else{ fprintf(yyTraceFILE,"%sInput '%s' with pending reduce %d\n", yyTracePrompt,yyTokenName[yymajor],yyact-YY_MIN_REDUCE); } } #endif do{ assert( yyact==yypParser->yytos->stateno ); yyact = yy_find_shift_action((YYCODETYPE)yymajor,yyact); if( yyact >= YY_MIN_REDUCE ){ yyact = yy_reduce(yypParser,yyact-YY_MIN_REDUCE,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 ){ |
︙ | ︙ | |||
977 978 979 980 981 982 983 | fprintf(yyTraceFILE,"%sDiscard input token %s\n", yyTracePrompt,yyTokenName[yymajor]); } #endif yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion); yymajor = YYNOCODE; }else{ | | | > | < > | | 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 | 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)) > YY_MAX_SHIFTREDUCE ){ 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 ){ |
︙ | ︙ | |||
1033 1034 1035 1036 1037 1038 1039 | #ifndef YYNOERRORRECOVERY yypParser->yyerrcnt = -1; #endif } break; #endif } | | | 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 | #ifndef YYNOERRORRECOVERY yypParser->yyerrcnt = -1; #endif } break; #endif } }while( yypParser->yytos>yypParser->yystack ); #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]); |
︙ | ︙ | |||
1055 1056 1057 1058 1059 1060 1061 | /* ** Return the fallback token corresponding to canonical token iToken, or ** 0 if iToken has no fallback. */ int ParseFallback(int iToken){ #ifdef YYFALLBACK | | | > < > | 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 | /* ** Return the fallback token corresponding to canonical token iToken, or ** 0 if iToken has no fallback. */ int ParseFallback(int iToken){ #ifdef YYFALLBACK if( iToken<(int)(sizeof(yyFallback)/sizeof(yyFallback[0])) ){ return yyFallback[iToken]; } #else (void)iToken; #endif return 0; } |
Changes to tool/logest.c.
︙ | ︙ | |||
71 72 73 74 75 76 77 | static sqlite3_uint64 logEstToInt(LogEst x){ sqlite3_uint64 n; if( x<10 ) return 1; n = x%10; x /= 10; if( n>=5 ) n -= 2; else if( n>=1 ) n -= 1; | < | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | static sqlite3_uint64 logEstToInt(LogEst x){ sqlite3_uint64 n; if( x<10 ) return 1; n = x%10; x /= 10; if( n>=5 ) n -= 2; else if( n>=1 ) n -= 1; if( x>=3 ) return (n+8)<<(x-3); return (n+8)>>(3-x); } static LogEst logEstFromDouble(double x){ sqlite3_uint64 a; LogEst e; assert( sizeof(x)==8 && sizeof(a)==8 ); |
︙ | ︙ | |||
146 147 148 149 150 151 152 | }else if( strcmp(z,"nlogn")==0 ){ if( n>0 ) a[n-1] += logEstFromInteger(a[n-1]) - 33; }else if( strcmp(z,"inv")==0 ){ if( n>0 ) a[n-1] = -a[n-1]; }else if( z[0]=='^' ){ a[n++] = (LogEst)atoi(z+1); }else if( isInteger(z) ){ | | < < | 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 | }else if( strcmp(z,"nlogn")==0 ){ if( n>0 ) a[n-1] += logEstFromInteger(a[n-1]) - 33; }else if( strcmp(z,"inv")==0 ){ if( n>0 ) a[n-1] = -a[n-1]; }else if( z[0]=='^' ){ a[n++] = (LogEst)atoi(z+1); }else if( isInteger(z) ){ a[n++] = logEstFromInteger(atoi(z)); }else if( isFloat(z) && z[0]!='-' ){ a[n++] = logEstFromDouble(atof(z)); }else{ showHelp(argv[0]); } } for(i=n-1; i>=0; i--){ if( a[i]<-40 ){ printf("%5d (%f)\n", a[i], 1.0/(double)logEstToInt(-a[i])); }else if( a[i]<10 ){ printf("%5d (%f)\n", a[i], logEstToInt(a[i]+100)/1024.0); }else{ sqlite3_uint64 x = logEstToInt(a[i]+100)*100/1024; printf("%5d (%lld.%02lld)\n", a[i], x/100, x%100); } } return 0; } |
Deleted tool/merge-test.tcl.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
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" and "sqlite3ext.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 | fi rm -rf $TMPSPACE cp -R $TOP/autoconf $TMPSPACE cp sqlite3.c $TMPSPACE cp sqlite3.h $TMPSPACE cp sqlite3ext.h $TMPSPACE | < | 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 | |
︙ | ︙ |
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 | #!/usr/bin/tclsh # # To build the # # const char **azCompileOpt[] # # declaration used in src/ctime.c, run this script. # # All Boolean compile time options. # set boolean_options { SQLITE_32BIT_ROWID SQLITE_4_BYTE_ALIGNED_MALLOC SQLITE_64BIT_STATS SQLITE_ALLOW_COVERING_INDEX_SCAN 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_MEMSTATUS 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_CEROD SQLITE_ENABLE_COLUMN_METADATA SQLITE_ENABLE_COLUMN_USED_MASK SQLITE_ENABLE_COSTMULT SQLITE_ENABLE_CURSOR_HINTS SQLITE_ENABLE_DBSTAT_VTAB SQLITE_ENABLE_EXPENSIVE_ASSERT SQLITE_ENABLE_FTS1 SQLITE_ENABLE_FTS2 SQLITE_ENABLE_FTS3 SQLITE_ENABLE_FTS3_PARENTHESIS SQLITE_ENABLE_FTS3_TOKENIZER SQLITE_ENABLE_FTS4 SQLITE_ENABLE_FTS5 SQLITE_ENABLE_HIDDEN_COLUMNS SQLITE_ENABLE_ICU SQLITE_ENABLE_IOTRACE SQLITE_ENABLE_JSON1 SQLITE_ENABLE_LOAD_EXTENSION SQLITE_ENABLE_LOCKING_STYLE SQLITE_ENABLE_MEMORY_MANAGEMENT SQLITE_ENABLE_MEMSYS3 SQLITE_ENABLE_MEMSYS5 SQLITE_ENABLE_MULTIPLEX SQLITE_ENABLE_NULL_TRIM SQLITE_ENABLE_OVERSIZE_CELL_CHECK SQLITE_ENABLE_PREUPDATE_HOOK SQLITE_ENABLE_RBU SQLITE_ENABLE_RTREE SQLITE_ENABLE_SELECTTRACE SQLITE_ENABLE_SESSION SQLITE_ENABLE_SNAPSHOT SQLITE_ENABLE_SQLLOG SQLITE_ENABLE_STMT_SCANSTATUS 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_HAS_CODEC SQLITE_HOMEGROWN_RECURSIVE_MUTEX 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_NREF SQLITE_MUTEX_OMIT SQLITE_MUTEX_PTHREADS SQLITE_MUTEX_W32 SQLITE_NEED_ERR_NAME SQLITE_NOINLINE 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_BTREECOUNT SQLITE_OMIT_CAST SQLITE_OMIT_CHECK 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_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_LIKE_OPTIMIZATION SQLITE_OMIT_LOAD_EXTENSION SQLITE_OMIT_LOCALTIME SQLITE_OMIT_LOOKASIDE SQLITE_OMIT_MEMORYDB SQLITE_OMIT_OR_OPTIMIZATION SQLITE_OMIT_PAGER_PRAGMAS |
︙ | ︙ | |||
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 | 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_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 } | > > > > | < < < < < < < < < > < < | 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 | 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_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_POWERSAFE_OVERWRITE 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_SYSTEM_MALLOC 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. # set value_options { 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_LOOKASIDE 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_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 |
︙ | ︙ | |||
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 | 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 } | > > > > > > > < < < < < < < < < < < < < | < < < < < < < < < < < < < | | | < < < < < < < < < < < < < < < < < < | | < | 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 | SQLITE_STAT4_SAMPLES SQLITE_STMTJRNL_SPILL SQLITE_TEMP_STORE } # Options that require custom code. # set options(ENABLE_STAT3) { #if defined(SQLITE_ENABLE_STAT4) "ENABLE_STAT4", #elif defined(SQLITE_ENABLE_STAT3) "ENABLE_STAT3", #endif } 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(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 b $boolean_options { set name [trim_name $b] set options($name) [subst { #if $b "$name", #endif }] } foreach v $value_options { set name [trim_name $v] set options($name) [subst { #ifdef $v "$name=" CTIMEOPT_VAL($v), #endif }] } foreach o [lsort [array names options]] { puts [string trim $options($o)] } |
Changes to tool/mkkeywordhash.c.
︙ | ︙ | |||
32 33 34 35 36 37 38 | ** 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 */ | < | | 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 | ** 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 */ #ifdef SQLITE_OMIT_ALTERTABLE # define ALTER 0 #else # define ALTER 0x00000001 #endif #define ALWAYS 0x00000002 #ifdef SQLITE_OMIT_ANALYZE # define ANALYZE 0 |
︙ | ︙ | |||
150 151 152 153 154 155 156 | # define UPSERT 0x00080000 #endif #ifdef SQLITE_OMIT_WINDOWFUNC # define WINDOWFUNC 0 #else # define WINDOWFUNC 0x00100000 #endif | < < < < < < < < < < < | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | < | | | | | | | | | | | | | | | | | | | | < | | | | < | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 | # define UPSERT 0x00080000 #endif #ifdef SQLITE_OMIT_WINDOWFUNC # define WINDOWFUNC 0 #else # define WINDOWFUNC 0x00100000 #endif /* ** These are the keywords */ static Keyword aKeywordTable[] = { { "ABORT", "TK_ABORT", CONFLICT|TRIGGER }, { "ACTION", "TK_ACTION", FKEY }, { "ADD", "TK_ADD", ALTER }, { "AFTER", "TK_AFTER", TRIGGER }, { "ALL", "TK_ALL", ALWAYS }, { "ALTER", "TK_ALTER", ALTER }, { "ANALYZE", "TK_ANALYZE", ANALYZE }, { "AND", "TK_AND", ALWAYS }, { "AS", "TK_AS", ALWAYS }, { "ASC", "TK_ASC", ALWAYS }, { "ATTACH", "TK_ATTACH", ATTACH }, { "AUTOINCREMENT", "TK_AUTOINCR", AUTOINCR }, { "BEFORE", "TK_BEFORE", TRIGGER }, { "BEGIN", "TK_BEGIN", ALWAYS }, { "BETWEEN", "TK_BETWEEN", ALWAYS }, { "BY", "TK_BY", ALWAYS }, { "CASCADE", "TK_CASCADE", FKEY }, { "CASE", "TK_CASE", ALWAYS }, { "CAST", "TK_CAST", CAST }, { "CHECK", "TK_CHECK", ALWAYS }, { "COLLATE", "TK_COLLATE", ALWAYS }, { "COLUMN", "TK_COLUMNKW", ALTER }, { "COMMIT", "TK_COMMIT", ALWAYS }, { "CONFLICT", "TK_CONFLICT", CONFLICT }, { "CONSTRAINT", "TK_CONSTRAINT", ALWAYS }, { "CREATE", "TK_CREATE", ALWAYS }, { "CROSS", "TK_JOIN_KW", ALWAYS }, { "CURRENT", "TK_CURRENT", WINDOWFUNC }, { "CURRENT_DATE", "TK_CTIME_KW", ALWAYS }, { "CURRENT_TIME", "TK_CTIME_KW", ALWAYS }, { "CURRENT_TIMESTAMP","TK_CTIME_KW", ALWAYS }, { "DATABASE", "TK_DATABASE", ATTACH }, { "DEFAULT", "TK_DEFAULT", ALWAYS }, { "DEFERRED", "TK_DEFERRED", ALWAYS }, { "DEFERRABLE", "TK_DEFERRABLE", FKEY }, { "DELETE", "TK_DELETE", ALWAYS }, { "DESC", "TK_DESC", ALWAYS }, { "DETACH", "TK_DETACH", ATTACH }, { "DISTINCT", "TK_DISTINCT", ALWAYS }, { "DO", "TK_DO", UPSERT }, { "DROP", "TK_DROP", ALWAYS }, { "END", "TK_END", ALWAYS }, { "EACH", "TK_EACH", TRIGGER }, { "ELSE", "TK_ELSE", ALWAYS }, { "ESCAPE", "TK_ESCAPE", ALWAYS }, { "EXCEPT", "TK_EXCEPT", COMPOUND }, { "EXCLUSIVE", "TK_EXCLUSIVE", ALWAYS }, { "EXCLUDE", "TK_EXCLUDE", WINDOWFUNC }, { "EXISTS", "TK_EXISTS", ALWAYS }, { "EXPLAIN", "TK_EXPLAIN", EXPLAIN }, { "FAIL", "TK_FAIL", CONFLICT|TRIGGER }, { "FILTER", "TK_FILTER", WINDOWFUNC }, { "FOLLOWING", "TK_FOLLOWING", WINDOWFUNC }, { "FOR", "TK_FOR", TRIGGER }, { "FOREIGN", "TK_FOREIGN", FKEY }, { "FROM", "TK_FROM", ALWAYS }, { "FULL", "TK_JOIN_KW", ALWAYS }, { "GLOB", "TK_LIKE_KW", ALWAYS }, { "GROUP", "TK_GROUP", ALWAYS }, { "GROUPS", "TK_GROUPS", WINDOWFUNC }, { "HAVING", "TK_HAVING", ALWAYS }, { "IF", "TK_IF", ALWAYS }, { "IGNORE", "TK_IGNORE", CONFLICT|TRIGGER }, { "IMMEDIATE", "TK_IMMEDIATE", ALWAYS }, { "IN", "TK_IN", ALWAYS }, { "INDEX", "TK_INDEX", ALWAYS }, { "INDEXED", "TK_INDEXED", ALWAYS }, { "INITIALLY", "TK_INITIALLY", FKEY }, { "INNER", "TK_JOIN_KW", ALWAYS }, { "INSERT", "TK_INSERT", ALWAYS }, { "INSTEAD", "TK_INSTEAD", TRIGGER }, { "INTERSECT", "TK_INTERSECT", COMPOUND }, { "INTO", "TK_INTO", ALWAYS }, { "IS", "TK_IS", ALWAYS }, { "ISNULL", "TK_ISNULL", ALWAYS }, { "JOIN", "TK_JOIN", ALWAYS }, { "KEY", "TK_KEY", ALWAYS }, { "LEFT", "TK_JOIN_KW", ALWAYS }, { "LIKE", "TK_LIKE_KW", ALWAYS }, { "LIMIT", "TK_LIMIT", ALWAYS }, { "MATCH", "TK_MATCH", ALWAYS }, { "NATURAL", "TK_JOIN_KW", ALWAYS }, { "NO", "TK_NO", FKEY|WINDOWFUNC }, { "NOT", "TK_NOT", ALWAYS }, { "NOTHING", "TK_NOTHING", UPSERT }, { "NOTNULL", "TK_NOTNULL", ALWAYS }, { "NULL", "TK_NULL", ALWAYS }, { "OF", "TK_OF", ALWAYS }, { "OFFSET", "TK_OFFSET", ALWAYS }, { "ON", "TK_ON", ALWAYS }, { "OR", "TK_OR", ALWAYS }, { "ORDER", "TK_ORDER", ALWAYS }, { "OTHERS", "TK_OTHERS", WINDOWFUNC }, { "OUTER", "TK_JOIN_KW", ALWAYS }, { "OVER", "TK_OVER", WINDOWFUNC }, { "PARTITION", "TK_PARTITION", WINDOWFUNC }, { "PLAN", "TK_PLAN", EXPLAIN }, { "PRAGMA", "TK_PRAGMA", PRAGMA }, { "PRECEDING", "TK_PRECEDING", WINDOWFUNC }, { "PRIMARY", "TK_PRIMARY", ALWAYS }, { "QUERY", "TK_QUERY", EXPLAIN }, { "RAISE", "TK_RAISE", TRIGGER }, { "RANGE", "TK_RANGE", WINDOWFUNC }, { "RECURSIVE", "TK_RECURSIVE", CTE }, { "REFERENCES", "TK_REFERENCES", FKEY }, { "REGEXP", "TK_LIKE_KW", ALWAYS }, { "REINDEX", "TK_REINDEX", REINDEX }, { "RELEASE", "TK_RELEASE", ALWAYS }, { "RENAME", "TK_RENAME", ALTER }, { "REPLACE", "TK_REPLACE", CONFLICT }, { "RESTRICT", "TK_RESTRICT", FKEY }, { "RIGHT", "TK_JOIN_KW", ALWAYS }, { "ROLLBACK", "TK_ROLLBACK", ALWAYS }, { "ROW", "TK_ROW", TRIGGER }, { "ROWS", "TK_ROWS", ALWAYS }, { "SAVEPOINT", "TK_SAVEPOINT", ALWAYS }, { "SELECT", "TK_SELECT", ALWAYS }, { "SET", "TK_SET", ALWAYS }, { "TABLE", "TK_TABLE", ALWAYS }, { "TEMP", "TK_TEMP", ALWAYS }, { "TEMPORARY", "TK_TEMP", ALWAYS }, { "THEN", "TK_THEN", ALWAYS }, { "TIES", "TK_TIES", WINDOWFUNC }, { "TO", "TK_TO", ALWAYS }, { "TRANSACTION", "TK_TRANSACTION", ALWAYS }, { "TRIGGER", "TK_TRIGGER", TRIGGER }, { "UNBOUNDED", "TK_UNBOUNDED", WINDOWFUNC }, { "UNION", "TK_UNION", COMPOUND }, { "UNIQUE", "TK_UNIQUE", ALWAYS }, { "UPDATE", "TK_UPDATE", ALWAYS }, { "USING", "TK_USING", ALWAYS }, { "VACUUM", "TK_VACUUM", VACUUM }, { "VALUES", "TK_VALUES", ALWAYS }, { "VIEW", "TK_VIEW", VIEW }, { "VIRTUAL", "TK_VIRTUAL", VTAB }, { "WHEN", "TK_WHEN", ALWAYS }, { "WHERE", "TK_WHERE", ALWAYS }, { "WINDOW", "TK_WINDOW", WINDOWFUNC }, { "WITH", "TK_WITH", CTE }, { "WITHOUT", "TK_WITHOUT", ALWAYS }, }; /* 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 '_' |
︙ | ︙ | |||
367 368 369 370 371 372 373 | int i; for(i=0; i<nKeyword; i++){ if( aKeywordTable[i].id==id ) break; } return &aKeywordTable[i]; } | < < < < < < < < < < < < < < < < < < < < < < < < < < | 348 349 350 351 352 353 354 355 356 357 358 359 360 361 | 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; |
︙ | ︙ | |||
423 424 425 426 427 428 429 | /* 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; | | | < | 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 | /* 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])*4) ^ (charMap(p->zName[p->len-1])*3) ^ (p->len*1); 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 */ |
︙ | ︙ | |||
509 510 511 512 513 514 515 | 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++){ | < < | 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 | 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 ); |
︙ | ︙ | |||
644 645 646 647 648 649 650 | j++; if( j>=5 ){ printf("\n"); j = 0; } } printf("%s};\n", j==0 ? "" : "\n"); | < < < < < < < < < < < | < | > < < < < < < | 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 | 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"); printf(" i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n) %% %d;\n", bestSize); printf(" for(i=((int)aKWHash[i])-1; i>=0; i=((int)aKWNext[i])-1){\n"); printf(" if( aKWLen[i]!=n ) continue;\n"); printf(" j = 0;\n"); printf(" zKW = &zKWText[aKWOffset[i]];\n"); printf("#ifdef SQLITE_ASCII\n"); printf(" while( j<n && (z[j]&~0x20)==zKW[j] ){ j++; }\n"); printf("#endif\n"); printf("#ifdef SQLITE_EBCDIC\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)?_[^@,]*)(?:@\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 | 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] rb] 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.
︙ | ︙ | |||
82 83 84 85 86 87 88 | set group($name) 0 set jump($name) 0 set in1($name) 0 set in2($name) 0 set in3($name) 0 set out2($name) 0 set out3($name) 0 | < | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | set group($name) 0 set jump($name) 0 set in1($name) 0 set in2($name) 0 set in3($name) 0 set out2($name) 0 set out3($name) 0 for {set i 3} {$i<[llength $line]-1} {incr i} { switch [string trim [lindex $line $i] ,] { same { incr i if {[lindex $line $i]=="as"} { incr i set sym [string trim [lindex $line $i] ,] |
︙ | ︙ | |||
104 105 106 107 108 109 110 | group {set group($name) 1} jump {set jump($name) 1} in1 {set in1($name) 1} in2 {set in2($name) 1} in3 {set in3($name) 1} out2 {set out2($name) 1} out3 {set out3($name) 1} | < | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | group {set group($name) 1} jump {set jump($name) 1} in1 {set in1($name) 1} in2 {set in2($name) 1} in3 {set in3($name) 1} out2 {set out2($name) 1} out3 {set out3($name) 1} } } if {$group($name)} { set newGroup 0 if {[info exists groups($nGroup)]} { if {$prevName=="" || !$group($prevName)} { set newGroup 1 |
︙ | ︙ | |||
138 139 140 141 142 143 144 | foreach name {OP_Noop OP_Explain OP_Abortable} { set jump($name) 0 set in1($name) 0 set in2($name) 0 set in3($name) 0 set out2($name) 0 set out3($name) 0 | < | < < | > > > > | < | 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 | foreach name {OP_Noop OP_Explain OP_Abortable} { set jump($name) 0 set in1($name) 0 set in2($name) 0 set in3($name) 0 set out2($name) 0 set out3($name) 0 set op($name) -1 set order($nOp) $name incr nOp } # The following are the opcodes that are processed by resolveP2Values() # set rp2v_ops { OP_Transaction OP_AutoCommit OP_Savepoint OP_Checkpoint OP_Vacuum OP_JournalMode OP_VUpdate OP_VFilter OP_Next OP_NextIfOpen OP_SorterNext OP_Prev OP_PrevIfOpen } # Assign small 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 } } # 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 |
︙ | ︙ | |||
205 206 207 208 209 210 211 | # 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 | < | | 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | # 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} { set seek $cnt; 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 } |
︙ | ︙ | |||
284 285 286 287 288 289 290 | if {[string match OP_NotUsed* $name]==0} { if {$jump($name)} {incr x 1} if {$in1($name)} {incr x 2} if {$in2($name)} {incr x 4} if {$in3($name)} {incr x 8} if {$out2($name)} {incr x 16} if {$out3($name)} {incr x 32} | < < | | 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 | if {[string match OP_NotUsed* $name]==0} { if {$jump($name)} {incr x 1} if {$in1($name)} {incr x 2} if {$in2($name)} {incr x 4} if {$in3($name)} {incr x 8} if {$out2($name)} {incr x 16} if {$out3($name)} {incr x 32} } set bv($i) $x } puts "" puts "/* Properties such as \"out2\" or \"jump\" that are specified in" puts "** comments following the \"case\" for each opcode in the vdbe.c" puts "** are encoded into bitvectors as follows:" puts "*/" puts "#define OPFLG_JUMP 0x01 /* jump: P2 holds jmp target */" puts "#define OPFLG_IN1 0x02 /* in1: P1 is an input */" puts "#define OPFLG_IN2 0x04 /* in2: P2 is an input */" puts "#define OPFLG_IN3 0x08 /* in3: P3 is an input */" puts "#define OPFLG_OUT2 0x10 /* out2: P2 is an output */" puts "#define OPFLG_OUT3 0x20 /* out3: P3 is an output */" puts "#define OPFLG_INITIALIZER \173\\" for {set i 0} {$i<=$max} {incr i} { if {$i%8==0} { puts -nonewline [format "/* %3d */" $i] } puts -nonewline [format " 0x%02x," $bv($i)] if {$i%8==7} { puts "\\" } } puts "\175" puts "" puts "/* The sqlite3P2Values() 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 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 | > > > > > | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) NAME: empty_result_callbacks TYPE: FLAG ARG: SQLITE_NullCallback IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) NAME: legacy_file_format TYPE: FLAG ARG: SQLITE_LegacyFileFmt IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) NAME: fullfsync TYPE: FLAG ARG: SQLITE_FullFSync IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) NAME: checkpoint_fullfsync TYPE: FLAG |
︙ | ︙ | |||
122 123 124 125 126 127 128 | TYPE: FLAG ARG: SQLITE_ReadUncommit IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) NAME: recursive_triggers TYPE: FLAG ARG: SQLITE_RecTriggers | < < < < < | 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | TYPE: FLAG ARG: SQLITE_ReadUncommit 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) |
︙ | ︙ | |||
227 228 229 230 231 232 233 | 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) | < < < < < < | 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 |
︙ | ︙ | |||
258 259 260 261 262 263 264 | NAME: index_list FLAG: NeedSchema Result1 SchemaOpt COLS: seq name unique origin partial IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) NAME: database_list | | | | | | | < | | | 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 | NAME: index_list FLAG: NeedSchema Result1 SchemaOpt COLS: seq name unique origin partial IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) NAME: database_list FLAG: NeedSchema Result0 COLS: seq name file IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) NAME: function_list FLAG: Result0 COLS: name builtin IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) IF: defined(SQLITE_INTROSPECTION_PRAGMAS) NAME: module_list FLAG: Result0 COLS: name IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) IF: !defined(SQLITE_OMIT_VIRTUALTABLE) IF: defined(SQLITE_INTROSPECTION_PRAGMAS) NAME: pragma_list FLAG: Result0 COLS: name IF: defined(SQLITE_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 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 NAME: integrity_check FLAG: NeedSchema Result0 Result1 IF: !defined(SQLITE_OMIT_INTEGRITY_CHECK) NAME: quick_check TYPE: INTEGRITY_CHECK FLAG: NeedSchema Result0 Result1 IF: !defined(SQLITE_OMIT_INTEGRITY_CHECK) NAME: encoding FLAG: Result0 NoColumns1 IF: !defined(SQLITE_OMIT_UTF16) NAME: schema_version |
︙ | ︙ | |||
372 373 374 375 376 377 378 379 | COLS: timeout NAME: lock_status FLAG: Result0 COLS: database status IF: defined(SQLITE_DEBUG) || defined(SQLITE_TEST) NAME: activate_extensions | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < < < < < < | 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 | COLS: timeout NAME: lock_status FLAG: Result0 COLS: database status IF: defined(SQLITE_DEBUG) || defined(SQLITE_TEST) NAME: key TYPE: KEY ARG: 0 IF: defined(SQLITE_HAS_CODEC) NAME: rekey TYPE: KEY ARG: 1 IF: defined(SQLITE_HAS_CODEC) NAME: hexkey TYPE: HEXKEY ARG: 2 IF: defined(SQLITE_HAS_CODEC) NAME: hexrekey TYPE: HEXKEY ARG: 3 IF: defined(SQLITE_HAS_CODEC) NAME: textkey TYPE: KEY ARG: 4 IF: defined(SQLITE_HAS_CODEC) NAME: textrekey TYPE: KEY ARG: 5 IF: defined(SQLITE_HAS_CODEC) NAME: activate_extensions IF: defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD) NAME: soft_heap_limit FLAG: Result0 NAME: threads FLAG: Result0 NAME: optimize FLAG: Result1 NeedSchema NAME: legacy_alter_table TYPE: FLAG ARG: SQLITE_LegacyAlter IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) |
︙ | ︙ | |||
471 472 473 474 475 476 477 | 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 | | | 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 | 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 (defined(SQLITE_DEBUG) and defined(SQLITE_HAS_CODEC)) # 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 | #!/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 | < | < | | | | < < < | < | < < < | 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 | #!/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. */} set in [open $topdir/src/shell.c.in rb] proc omit_redundant_typedefs {line} { global typedef_seen if {[regexp {^typedef .*;} $line]} { if {[info exists typedef_seen($line)]} { return "/* $line */" } set typedef_seen($line) 1 } return $line } while {1} { set lx [omit_redundant_typedefs [gets $in]] if {[eof $in]} break; if {[regexp {^INCLUDE } $lx]} { set cfile [lindex $lx 1] puts $out "/************************* Begin $cfile ******************/" set in2 [open $topdir/src/$cfile rb] while {![eof $in2]} { set lx [omit_redundant_typedefs [gets $in2]] if {[regexp {^#include "sqlite} $lx]} continue if {[regexp {^# *include "test_windirent.h"} $lx]} { set lx "/* $lx */" } set lx [string map [list __declspec(dllexport) {}] $lx] puts $out $lx } close $in2 puts $out "/************************* End $cfile ********************/" continue } puts $out $lx } close $in close $out |
Changes to tool/mksourceid.c.
︙ | ︙ | |||
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)) | > > > > > > > > > > > > > > > > > > | 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 | /* * 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. */ #if __GNUC__ && (defined(__i386__) || defined(__x86_64__)) /* * GCC by itself only generates left rotates. Use right rotates if * possible to be kinder to dinky implementations with iterative rotate * instructions. */ #define SHA_ROT(op, x, k) \ ({ unsigned int y; asm(op " %1,%0" : "=r" (y) : "I" (k), "0" (x)); y; }) #define rol(x,k) SHA_ROT("roll", x, k) #define ror(x,k) SHA_ROT("rorl", x, k) #else /* Generic C equivalent */ #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) #endif #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 | # 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 --srcdir $SRC # # The amalgamated SQLite code will be written into sqlite3.c # # Begin by reading the "sqlite3.h" header file. Extract the version number # from in this file. The version number is needed to generate the header # comment of the amalgamation. # set addstatic 1 set linemacros 0 set useapicall 0 for {set i 0} {$i<[llength $argv]} {incr i} { set x [lindex $argv $i] if {[regexp {^-+nostatic$} $x]} { set addstatic 0 } elseif {[regexp {^-+linemacros} $x]} { set linemacros 1 } elseif {[regexp {^-+useapicall} $x]} { set useapicall 1 } else { error "unknown command-line option: $x" } } set in [open tsrc/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 } close $in # Open the output file and write a header comment at the beginning # of the file. # set out [open sqlite3.c w] # Force the output to use unix line endings, even on Windows. fconfigure $out -translation lf set today [clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S UTC" -gmt 1] puts $out [subst \ {/****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite ** version $VERSION. By combining all the individual C code files into this |
︙ | ︙ | |||
112 113 114 115 116 117 118 | if {$addstatic} { puts $out \ {#ifndef SQLITE_PRIVATE # define SQLITE_PRIVATE static #endif} } | < < < < < < < < < < < < | 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | 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 btreeInt.h |
︙ | ︙ | |||
163 164 165 166 167 168 169 | sqliteInt.h sqliteLimit.h vdbe.h vdbeInt.h vxworks.h wal.h whereInt.h | < < | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | sqliteInt.h sqliteLimit.h vdbe.h vdbeInt.h 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 |
︙ | ︙ | |||
208 209 210 211 212 213 214 | # 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 | | | > | > | | 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 | # 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 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 [gets $in] incr ln if {[regexp {^\s*#\s*include\s+["<]([^">]+)[">]} $line all hdr]} { if {[info exists available_hdr($hdr)]} { if {$available_hdr($hdr)} { if {$hdr!="os_common.h" && $hdr!="hwtime.h"} { set available_hdr($hdr) 0 } section_comment "Include $hdr in the middle of $tail" copy_file tsrc/$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] */" } |
︙ | ︙ | |||
279 280 281 282 283 284 285 | if {[lsearch -exact $cdecllist $funcname] >= 0} { append line SQLITE_CDECL " " } else { append line SQLITE_APICALL " " } } append line $funcname $rest | | | < | 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 | if {[lsearch -exact $cdecllist $funcname] >= 0} { append line SQLITE_CDECL " " } else { append line SQLITE_APICALL " " } } append line $funcname $rest if {$funcname=="sqlite3_sourceid" && !$linemacros} { # The sqlite3_sourceid() routine is synthesized at the end of # the amalgamation puts $out "/* $line */" } else { puts $out $line } } else { puts $out "SQLITE_PRIVATE $line" } } elseif {[regexp $varpattern $line all varname]} { # Add the SQLITE_PRIVATE before variable declarations or # definitions for internal use regsub {^SQLITE_API } $line {} line if {![regexp {^sqlite3_} $varname]} { regsub {^extern } $line {} line puts $out "SQLITE_PRIVATE $line" } else { if {[regexp {const char sqlite3_version\[\];} $line]} { set line {const char sqlite3_version[] = SQLITE_VERSION;} } regsub {^SQLITE_EXTERN } $line {} line |
︙ | ︙ | |||
327 328 329 330 331 332 333 | } # Process the source files. Process files containing commonly # used subroutines first in order to help the compiler find # inlining opportunities. # | | < < > | 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 | } # Process the source files. Process files containing commonly # used subroutines first in order to help the compiler find # inlining opportunities. # foreach file { ctime.c sqliteInt.h global.c status.c date.c os.c fault.c |
︙ | ︙ | |||
357 358 359 360 361 362 363 | random.c threads.c utf.c util.c hash.c opcodes.c | < | 315 316 317 318 319 320 321 322 323 324 325 326 327 328 | random.c threads.c utf.c util.c hash.c opcodes.c os_unix.c os_win.c memdb.c bitvec.c pcache.c pcache1.c |
︙ | ︙ | |||
380 381 382 383 384 385 386 | vdbemem.c vdbeaux.c vdbeapi.c vdbetrace.c vdbe.c vdbeblob.c vdbesort.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 |
︙ | ︙ | |||
433 434 435 436 437 438 439 | fts3_tokenizer1.c fts3_tokenize_vtab.c fts3_write.c fts3_snippet.c fts3_unicode.c fts3_unicode2.c | | > > | < < | > > > > > > > > | > > > | > > > | | > | > > > > | | | 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 | fts3_tokenizer1.c fts3_tokenize_vtab.c fts3_write.c fts3_snippet.c fts3_unicode.c fts3_unicode2.c json1.c rtree.c icu.c fts3_icu.c sqlite3rbu.c dbstat.c dbpage.c sqlite3session.c fts5.c stmt.c } { copy_file tsrc/$file } # Synthesize an alternative sqlite3_sourceid() implementation that # that tries to detects changes in the amalgamation source text # and modify returns a modified source-id if changes are detected. # # The only detection mechanism we have is the __LINE__ macro. So only # edits that changes the number of lines of source code are detected. # if {!$linemacros} { flush $out set in2 [open sqlite3.c] set cnt 0 set oldsrcid {} while {![eof $in2]} { incr cnt gets $in2 line if {[regexp {^#define SQLITE_SOURCE_ID } $line]} {set oldsrcid $line} } close $in2 regsub {[0-9a-flt]{4}"} $oldsrcid {alt2"} oldsrcid puts $out \ "#if __LINE__!=[expr {$cnt+0}] #undef SQLITE_SOURCE_ID $oldsrcid #endif /* 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.
︙ | ︙ | |||
36 37 38 39 40 41 42 | # set TOP [lindex $argv 0] # Enable use of SQLITE_APICALL macros at the right points? # set useapicall 0 | < < < < < < < | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | # set TOP [lindex $argv 0] # Enable use of SQLITE_APICALL macros at the right points? # set useapicall 0 if {[lsearch -regexp [lrange $argv 1 end] {^-+useapicall}] != -1} { set useapicall 1 } # Get the SQLite version number (ex: 3.6.18) from the $TOP/VERSION file. # set in [open $TOP/VERSION] set zVersion [string trim [read $in]] close $in set nVersion [eval format "%d%03d%03d" [split $zVersion .]] |
︙ | ︙ | |||
87 88 89 90 91 92 93 | set filelist [subst { $TOP/src/sqlite.h.in $TOP/ext/rtree/sqlite3rtree.h $TOP/ext/session/sqlite3session.h $TOP/ext/fts5/fts5.h }] | < < < | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | set filelist [subst { $TOP/src/sqlite.h.in $TOP/ext/rtree/sqlite3rtree.h $TOP/ext/session/sqlite3session.h $TOP/ext/fts5/fts5.h }] # These are the functions that accept a variable number of arguments. They # always need to use the "cdecl" calling convention even when another calling # convention (e.g. "stcall") is being used for the rest of the library. set cdecllist { sqlite3_config sqlite3_db_config |
︙ | ︙ | |||
113 114 115 116 117 118 119 | 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 [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_master 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); |
︙ | ︙ |
Deleted tool/omittest-msvc.tcl.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
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 0 ;# 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 | incr i set ::TARGET [lindex $argv $i] } -{1,2}skip_run { set ::SKIP_RUN 1 } | < < < | 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 } -.* { |
︙ | ︙ | |||
191 192 193 194 195 196 197 | SQLITE_OMIT_AUTOINIT \ SQLITE_OMIT_AUTOMATIC_INDEX \ SQLITE_OMIT_AUTORESET \ SQLITE_OMIT_AUTOVACUUM \ SQLITE_OMIT_BETWEEN_OPTIMIZATION \ SQLITE_OMIT_BLOB_LITERAL \ SQLITE_OMIT_BTREECOUNT \ | < < < < < > | 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 | 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_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_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_LIKE_OPTIMIZATION \ SQLITE_OMIT_LOAD_EXTENSION \ SQLITE_OMIT_LOCALTIME \ SQLITE_OMIT_LOOKASIDE \ SQLITE_OMIT_MEMORYDB \ SQLITE_OMIT_MEMORY_ALLOCATION \ 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 \ |
︙ | ︙ | |||
252 253 254 255 256 257 258 | SQLITE_OMIT_WAL \ SQLITE_OMIT_WINDOWFUNC \ SQLITE_OMIT_WSD \ SQLITE_OMIT_XFER_OPT \ ] set ::ENABLE_SYMBOLS [list \ | < | 245 246 247 248 249 250 251 252 253 254 255 256 257 258 | SQLITE_OMIT_WAL \ SQLITE_OMIT_WINDOWFUNC \ SQLITE_OMIT_WSD \ SQLITE_OMIT_XFER_OPT \ ] set ::ENABLE_SYMBOLS [list \ 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 {$mode ni [list exact regsub include]} {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 | #endif #include <stdlib.h> #include <string.h> #include <assert.h> #include "sqlite3.h" | < < < < < | | > > > > | | 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 | #endif #include <stdlib.h> #include <string.h> #include <assert.h> #include "sqlite3.h" static struct GlobalData { int pagesize; /* Size of a database page */ int dbfd; /* File descriptor for reading the DB */ int 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}; typedef long long int i64; /* Datatype for 64-bit integers */ /* ** 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 unsigned int decodeInt32(const unsigned char *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"); |
︙ | ︙ | |||
138 139 140 141 142 143 144 | ** ** 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; | | | | | 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 | ** ** 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_malloc(nByte+32); 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 sqlite3_int64 fileGetsize(void){ sqlite3_int64 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{ |
︙ | ︙ | |||
182 183 184 185 186 187 188 | ** End of low-level file access functions. **************************************************************************/ /* ** Print a range of bytes as hex and as ascii. */ static unsigned char *print_byte_range( | | | | < < < < < < | 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 | ** End of low-level file access functions. **************************************************************************/ /* ** Print a range of bytes as hex and as ascii. */ static unsigned char *print_byte_range( int 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){ 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]); } |
︙ | ︙ | |||
233 234 235 236 237 238 239 | } return aData; } /* ** Print an entire page of content as hex */ | | | | | | | | | 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 | } return aData; } /* ** Print an entire page of content as hex */ static void print_page(int iPg){ int iStart; unsigned char *aData; iStart = (iPg-1)*g.pagesize; fprintf(stdout, "Page %d: (offsets 0x%x..0x%x)\n", iPg, iStart, iStart+g.pagesize-1); aData = print_byte_range(iStart, g.pagesize, 0); sqlite3_free(aData); } /* Print a line of decode output showing a 4-byte 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; int 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], " %9d", val); printf("%s %s\n", zBuf, zMsg); } /* ** Decode the database header. */ static void print_db_header(void){ |
︙ | ︙ | |||
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"); | < | 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 */ |
︙ | ︙ | |||
412 413 414 415 416 417 418 | 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; | | | | | | 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 | 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; int 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: %d ", 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 ){ int ovfl; unsigned char *b = &a[nLocal]; ovfl = ((b[0]*256 + b[1])*256 + b[2])*256 + b[3]; sprintf(&zDesc[nDesc], "ov: %d ", ovfl); nDesc += strlen(&zDesc[nDesc]); n += 4; } if( showCellContent && cType!=5 ){ nDesc += describeContent(a, nLocal, &zDesc[nDesc-1]); } *pzDesc = zDesc; |
︙ | ︙ | |||
489 490 491 492 493 494 495 | 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; | | | | 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 | 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; int 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:: %d\n", leftChild); x += 4; } if( cType!=5 ){ i = decodeVarint(x, &nPayload); printBytes(a, x, i); nLocal = localPayload(nPayload, cType); if( nLocal==nPayload ){ |
︙ | ︙ | |||
626 627 628 629 630 631 632 | } if( j<nLocal ){ printBytes(a, x+j, 0); printf("... %lld bytes of content ...\n", nLocal-j); } if( nLocal<nPayload ){ printBytes(a, x+nLocal, 4); | | | 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 | } 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: %d\n", decodeInt32(x+nLocal)); } } /* ** Decode a btree page */ |
︙ | ︙ | |||
722 723 724 725 726 727 728 | printf(" %03x: cell[%d] %s\n", cofst, i, zDesc); }else if( cellToDecode==(-1) || cellToDecode==i ){ decodeCell(a, pgno, i, hdrSize, cofst-hdrSize); } } if( showMap ){ printf("Page map: (H=header P=cell-index 1=page-1-header .=free-space)\n"); | | | | < | | | | | | | | | 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 | printf(" %03x: cell[%d] %s\n", cofst, i, zDesc); }else if( cellToDecode==(-1) || cellToDecode==i ){ decodeCell(a, pgno, i, hdrSize, cofst-hdrSize); } } if( showMap ){ printf("Page map: (H=header P=cell-index 1=page-1-header .=free-space)\n"); for(i=0; i<g.pagesize; i+=64){ printf(" %03x: %.64s\n", i, &zMap[i]); } sqlite3_free(zMap); } } /* ** Decode a freelist trunk page. */ static void decode_trunk_page( int pgno, /* The page number */ int detail, /* Show leaf pages if true */ int recursive /* Follow the trunk change if true */ ){ int n, i; 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 = (int)decodeInt32(&a[4]); for(i=0; i<n; i++){ unsigned int x = decodeInt32(&a[8+4*i]); char zIdx[10]; 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 = (int)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(int 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..%d: %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 */ int 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; |
︙ | ︙ | |||
828 829 830 831 832 833 834 | } if( cType==5 || cType==13 ){ i = decodeVarint(a, &rowid); a += i; n += i; } if( nLocal<nPayload ){ | | | | < < < < < < | < < | < < < | < < < < < < < < < < < < < < | < < < < < < < | | | < < | > | < | | < < < < | < < < < | 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 | } if( cType==5 || cType==13 ){ i = decodeVarint(a, &rowid); a += i; n += i; } if( nLocal<nPayload ){ int ovfl = decodeInt32(a+nLocal); int cnt = 0; while( ovfl && (cnt++)<g.mxPage ){ page_usage_msg(ovfl, "overflow %d from cell %d of page %d", cnt, cellno, pgno); a = fileRead((ovfl-1)*(sqlite3_int64)g.pagesize, 4); ovfl = decodeInt32(a); sqlite3_free(a); } } } /* ** Describe the usages of a b-tree page */ static void page_usage_btree( int pgno, /* Page to describe */ int 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; if( pgno<=0 || pgno>g.mxPage ) return; a = fileRead((pgno-1)*g.pagesize, g.pagesize); switch( a[hdr] ){ 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; } if( parent ){ page_usage_msg(pgno, "%s [%s], child %d of page %d", zType, zName, idx, parent); }else{ page_usage_msg(pgno, "root %s [%s]", zType, zName); } nCell = a[hdr+3]*256 + a[hdr+4]; if( a[hdr]==2 || a[hdr]==5 ){ int cellstart = hdr+12; unsigned int child; for(i=0; i<nCell; i++){ int ofst; ofst = cellstart + i*2; ofst = a[ofst]*256 + a[ofst+1]; 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 ){ |
︙ | ︙ | |||
942 943 944 945 946 947 948 | } sqlite3_free(a); } /* ** Determine page usage by the freelist */ | | | | | | | | | | | < | < < | | 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 | } sqlite3_free(a); } /* ** Determine page usage by the freelist */ static void page_usage_freelist(int pgno){ unsigned char *a; int cnt = 0; int i; int n; int iNext; int parent = 1; while( pgno>0 && pgno<=g.mxPage && (cnt++)<g.mxPage ){ page_usage_msg(pgno, "freelist trunk #%d child of %d", cnt, parent); a = fileRead((pgno-1)*g.pagesize, g.pagesize); iNext = decodeInt32(a); n = decodeInt32(a+4); for(i=0; i<n; i++){ int child = decodeInt32(a + (i*4+8)); page_usage_msg(child, "freelist leaf, child %d of trunk page %d", i, pgno); } sqlite3_free(a); parent = pgno; pgno = iNext; } } /* ** Determine pages used as PTRMAP pages */ static void page_usage_ptrmap(unsigned char *a){ if( a[55] ){ int usable = g.pagesize - a[20]; int pgno = 2; int perPage = usable/5; while( pgno<=g.mxPage ){ page_usage_msg(pgno, "PTRMAP page covering %d..%d", 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){ int 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_malloc( 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_master"); 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 ){ int pgno = sqlite3_column_int(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++){ printf("%5d: %s\n", i, zPageUse[i] ? zPageUse[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){ int pgno; unsigned char *aHdr; unsigned char *a; int usable; int perPage; int i; /* Avoid the pathological case */ |
︙ | ︙ | |||
1071 1072 1073 1074 1075 1076 1077 | if( aHdr[55]==0 ){ printf("database does not use PTRMAP pages\n"); return; } usable = g.pagesize - aHdr[20]; perPage = usable/5; sqlite3_free(aHdr); | | | | | < < < < < < < < < < < < | 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 | 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_master\n", 1); for(pgno=2; pgno<=g.mxPage; pgno += perPage+1){ printf("%5d: PTRMAP page covering %d..%d\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 = "???"; unsigned int 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("%5d: %s, parent=%u\n", pgno+1+i/5, zType, iFrom); } sqlite3_free(a); } } /* ** Print a usage comment */ static void usage(const char *argv0){ fprintf(stderr, "Usage %s ?--uri? FILENAME ?args...?\n\n", argv0); fprintf(stderr, "switches:\n" |
︙ | ︙ | |||
1160 1161 1162 1163 1164 1165 1166 | 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); | | | | | | 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 | 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 = (int)((szFile+g.pagesize-1)/g.pagesize); printf("Available pages: 1..%d\n", g.mxPage); if( nArg==2 ){ int i; for(i=1; i<=g.mxPage; i++) print_page(i); }else{ int i; for(i=2; i<nArg; i++){ int 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]); |
︙ | ︙ | |||
1191 1192 1193 1194 1195 1196 1197 | usage(zPrg); continue; } if( !ISDIGIT(azArg[i][0]) ){ fprintf(stderr, "%s: unknown option: [%s]\n", zPrg, azArg[i]); continue; } | | < < | 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 | usage(zPrg); continue; } if( !ISDIGIT(azArg[i][0]) ){ fprintf(stderr, "%s: unknown option: [%s]\n", zPrg, azArg[i]); continue; } iStart = strtol(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; if( iStart==1 ){ ofst = hdrSize = 100; nByte = g.pagesize-100; }else{ |
︙ | ︙ |
Changes to tool/showlocks.c.
︙ | ︙ | |||
20 21 22 23 24 25 26 | /* ** 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 | /* ** 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; 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 ) return 0; 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( x.l_start>lwr ){ cnt += showLocksInRange(fd, lwr, x.l_start-1); } if( x.l_start+x.l_len<upr ){ cnt += showLocksInRange(fd, x.l_start+x.l_len+1, upr); } 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(int 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){ int iStart; unsigned char *aData; iStart = 32 + (iFrame-1)*(pagesize+24); fprintf(stdout, "Frame %d: (offsets 0x%x..0x%x)\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){ int iStart; unsigned char *aData; unsigned int s0, s1; iStart = 32 + (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, |
︙ | ︙ | |||
508 509 510 511 512 513 514 | for(i=0; i<pagesize; i+=64){ printf(" %03x: %.64s\n", i, &zMap[i]); } free(zMap); } } | < < < < < < < < < < < < | 508 509 510 511 512 513 514 515 516 517 518 519 520 521 | for(i=0; i<pagesize; i+=64){ printf(" %03x: %.64s\n", i, &zMap[i]); } free(zMap); } } int main(int argc, char **argv){ struct stat sbuf; unsigned char zPgSz[4]; if( argc<2 ){ fprintf(stderr,"Usage: %s FILENAME ?PAGE? ...\n", argv[0]); exit(1); } |
︙ | ︙ | |||
567 568 569 570 571 572 573 | continue; } if( !ISDIGIT(argv[i][0]) ){ fprintf(stderr, "%s: unknown option: [%s]\n", argv[0], argv[i]); continue; } iStart = strtol(argv[i], &zLeft, 0); | < < < | | | | 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 | continue; } if( !ISDIGIT(argv[i][0]) ){ fprintf(stderr, "%s: unknown option: [%s]\n", argv[0], argv[i]); continue; } 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' ){ int ofst, nByte, hdrSize; unsigned char *a; if( iStart==1 ){ hdrSize = 100; ofst = hdrSize = 100; nByte = pagesize-100; }else{ hdrSize = 0; ofst = (iStart-1)*pagesize; nByte = pagesize; } ofst = 32 + hdrSize + (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_master 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_master} 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_master WHERE rootpage>0 } foreach {name tblname} [concat sqlite_master sqlite_master [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_master) # 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 | 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}] set ntable [db eval {SELECT count(*)+1 FROM sqlite_master WHERE type='table'}] set nindex [db eval {SELECT count(*) FROM sqlite_master WHERE type='index'}] set sql {SELECT count(*) FROM sqlite_master 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_master'}] 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 |
︙ | ︙ | |||
727 728 729 730 731 732 733 | 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 | | | 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 | 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_MASTER table used to store schema information. Number of indices The total number of indices in the database. Number of defined indices |
︙ | ︙ | |||
750 751 752 753 754 755 756 | 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 | | | 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 | 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_MASTER 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.
1 2 3 4 5 | #!/bin/bash # # This is a template for a script used for day-to-day size and # performance monitoring of SQLite. Typical usage: # | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #!/bin/bash # # This is a template for a script used for day-to-day size and # performance monitoring of SQLite. Typical usage: # # sh run-speed-test.sh trunk # Baseline measurement of trunk # sh run-speed-test.sh x1 # Measure some experimental change # fossil test-diff --tk cout-trunk.txt cout-x1.txt # View chanages # # There are multiple output files, all with a base name given by # the first argument: # # summary-$BASE.txt # Copy of standard output # cout-$BASE.txt # cachegrind output # explain-$BASE.txt # EXPLAIN listings (only with --explain) |
︙ | ︙ | |||
58 59 60 61 62 63 64 | ;; --stats) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; --without-rowid) SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1" ;; | < < < < < < < < < < < < < < < < < < < < < < | 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 |
︙ | ︙ | |||
142 143 144 145 146 147 148 | shift; SPEEDTEST_OPTS="$SPEEDTEST_OPTS --mmap $1" ;; --rtree) SPEEDTEST_OPTS="$SPEEDTEST_OPTS --testset rtree" CC_OPTS="$CC_OPTS -DSQLITE_ENABLE_RTREE" ;; | < < < | 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | shift; SPEEDTEST_OPTS="$SPEEDTEST_OPTS --mmap $1" ;; --rtree) SPEEDTEST_OPTS="$SPEEDTEST_OPTS --testset rtree" CC_OPTS="$CC_OPTS -DSQLITE_ENABLE_RTREE" ;; --orm) SPEEDTEST_OPTS="$SPEEDTEST_OPTS --testset orm" ;; --cte) SPEEDTEST_OPTS="$SPEEDTEST_OPTS --testset cte" ;; --fp) |
︙ | ︙ |
Changes to tool/split-sqlite3c.tcl.
︙ | ︙ | |||
70 71 72 73 74 75 76 | set all {} set N 0 } append all $buf incr N $n while {[gets $in line]>=0} { if {[regexp $BEGIN $line]} break | < < < < < | 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | set all {} set N 0 } append all $buf incr N $n while {[gets $in line]>=0} { if {[regexp $BEGIN $line]} break puts $out1 $line } } if {$N>0} { write_one_file $all } close $out1 |
︙ | ︙ |
Changes to tool/sqldiff.c.
︙ | ︙ | |||
31 32 33 34 35 36 37 | */ 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 */ | < | 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 |
︙ | ︙ | |||
189 190 191 192 193 194 195 | int i; for(i=0; az[i]; i++) sqlite3_free(az[i]); sqlite3_free(az); } } /* | | | < < < | 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 | int i; for(i=0; az[i]; i++) sqlite3_free(az[i]); sqlite3_free(az); } } /* ** Return a list of column names 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, 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. ** ** 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 ** ** CREATE TABLE t2(a INT UNIQUE, b INTEGER, c TEXT, PRIMARY KEY(b)); |
︙ | ︙ | |||
299 300 301 302 303 304 305 | while( SQLITE_ROW==sqlite3_step(pStmt) ){ if( sqlite3_column_int(pStmt,5)>0 ) nPK++; } sqlite3_reset(pStmt); if( nPK==0 ) nPK = 1; truePk = 1; } | < < < < < < < < < < < < | < < < < | | | < | | | < < | 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 | 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 ){ az[iPKey-1] = safeId((char*)sqlite3_column_text(pStmt,1)); }else{ az = sqlite3_realloc(az, sizeof(char*)*(naz+2) ); if( az==0 ) runtimeError("out of memory"); az[naz++] = safeId((char*)sqlite3_column_text(pStmt,1)); } } 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 three options - "rowid", "_rowid_" and "oid". Any ** of these will work, unless the table has an explicit column of the ** same name. */ 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 ){ |
︙ | ︙ | |||
399 400 401 402 403 404 405 406 407 408 409 | /* 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{ | > < < < < < < < < < < < < < < < < | | | < | 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 | /* 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); int i, j; if( zArg==0 ){ fprintf(out, "NULL"); }else{ fprintf(out, "'"); for(i=j=0; zArg[i]; i++){ if( zArg[i]=='\'' ){ fprintf(out, "%.*s'", i-j+1, &zArg[j]); j = i+1; } } fprintf(out, "%s'", &zArg[j]); } break; } case SQLITE_NULL: { |
︙ | ︙ | |||
451 452 453 454 455 456 457 | 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 */ | | | 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 | 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_master 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); |
︙ | ︙ | |||
501 502 503 504 505 506 507 | zSep = ","; } fprintf(out, ");\n"); } sqlite3_finalize(pStmt); strFree(&ins); } /* endif !g.bSchemaOnly */ | | < | < < < > < < < | < < < | | | 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 | zSep = ","; } fprintf(out, ");\n"); } sqlite3_finalize(pStmt); strFree(&ins); } /* endif !g.bSchemaOnly */ pStmt = db_prepare("SELECT sql FROM aux.sqlite_master" " 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); } /* ** Compute all differences for a single table. */ 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 */ 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. */ 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 */ 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, "DROP TABLE %s; -- due to schema mismatch\n", 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])); |
︙ | ︙ | |||
683 684 685 686 687 688 689 | 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( | | | | | | | | | 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 | 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_master" " WHERE type='index' AND tbl_name=%Q" " AND sql IS NOT NULL" " AND sql NOT IN (SELECT sql FROM aux.sqlite_master" " 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, "UPDATE %s", 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, "DELETE FROM %s", 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, "INSERT INTO %s(%s", 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_master" " WHERE type='index' AND tbl_name=%Q" " AND sql IS NOT NULL" " AND sql NOT IN (SELECT sql FROM main.sqlite_master" " 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); |
︙ | ︙ | |||
772 773 774 775 776 777 778 | ** 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( | | | 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 | ** 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_master A, aux.sqlite_master 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{ |
︙ | ︙ | |||
1588 1589 1590 1591 1592 1593 1594 | 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); | < | 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); |
︙ | ︙ | |||
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", | > | 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 | if( aiPk==0 ) runtimeError("out of memory"); } aiPk[i-1] = nCol-1; } } sqlite3_finalize(pStmt); if( nPk==0 ) goto end_changeset_one_table; strInit(&sql); 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", |
︙ | ︙ | |||
1751 1752 1753 1754 1755 1756 1757 | sqlite3_finalize(pStmt); end_changeset_one_table: while( nCol>0 ) sqlite3_free(azCol[--nCol]); sqlite3_free(azCol); sqlite3_free(aiPk); sqlite3_free(zId); | < < < < < < < < < < | | | | | 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 | 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. */ 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( *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 && *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_master 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 ){ |
︙ | ︙ | |||
1870 1871 1872 1873 1874 1875 1876 | rc = sqlite3_create_function( g.db, "module_name", 1, SQLITE_UTF8, 0, module_name_func, 0, 0 ); assert( rc==SQLITE_OK ); return | | | | | | | | 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 | 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_master\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_master AS a, temp.tblmap AS b \n" "WHERE module_name(a.sql) = b.module\n" " )\n" "UNION \n" "SELECT name FROM aux.sqlite_master\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_master 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_master\n" " WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n" " UNION\n" "SELECT name FROM aux.sqlite_master\n" " WHERE type='table' AND sql NOT LIKE 'CREATE VIRTUAL%%'\n" " ORDER BY name"; } } /* ** Print sketchy documentation for this utility program |
︙ | ︙ | |||
1918 1919 1920 1921 1922 1923 1924 | " --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" | < | 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; |
︙ | ︙ | |||
1985 1986 1987 1988 1989 1990 1991 | }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]; | < < < | 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 |
︙ | ︙ | |||
2009 2010 2011 2012 2013 2014 2015 | }else{ cmdlineError("unknown argument: %s", argv[i]); } } if( zDb2==0 ){ cmdlineError("two database arguments required"); } | < < < | < < | | 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 | }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); } rc = sqlite3_exec(g.db, "SELECT * FROM sqlite_master", 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); if( rc || zErrMsg ){ cmdlineError("cannot attach database \"%s\"", zDb2); } rc = sqlite3_exec(g.db, "SELECT * FROM aux.sqlite_master", 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 #ifndef USE_EXTERNAL_SQLITE INCLUDE sqlite3.c #endif INCLUDE $ROOT/src/tclsqlite.c const char *sqlite3_analyzer_init_proc(Tcl_Interp *interp){ (void)interp; return |
︙ | ︙ |
Deleted tool/stripccomments.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to tool/vdbe-compress.tcl.
︙ | ︙ | |||
61 62 63 64 65 66 67 | append beforeUnion $line\n } # Process the remaining text. Build up the union definition as we go. # set vlist {} set seenDecl 0 | | | 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | append beforeUnion $line\n } # Process the remaining text. Build up the union definition as we go. # set vlist {} set seenDecl 0 set namechars {abcdefghijklmnopqrstuvwxyz} set nnc [string length $namechars] while {![eof stdin]} { set line [gets stdin] if {[regexp "^case (OP_\\w+): \173" $line all operator]} { append afterUnion $line\n set vlist {} while {![eof stdin]} { |
︙ | ︙ |
Changes to tool/vdbe_profile.tcl.
︙ | ︙ | |||
62 63 64 65 66 67 68 | } close $in foreach stmt $allstmt { puts "********************************************************************" puts [string trim $sql($stmt)] puts "Execution count: $cnt($stmt)" | < < < < < < | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | } close $in foreach stmt $allstmt { puts "********************************************************************" puts [string trim $sql($stmt)] puts "Execution count: $cnt($stmt)" for {set i 0} {[info exists stat($stmt,$i)]} {incr i} { foreach {cx tx detail} $stat($stmt,$i) break if {$cx==0} { set ax 0 } else { set ax [expr {$tx/$cx}] } puts [format {%8d %12d %12d %4d %s} $cx $tx $ax $i $detail] } } puts "********************************************************************" puts "OPCODES:" foreach op [lsort [array names opcnt]] { set cx $opcnt($op) set tx $opcycle($op) if {$cx==0} { |
︙ | ︙ |
Changes to tool/warnings.sh.
1 2 3 4 5 6 7 8 9 10 11 12 13 | #/bin/sh # # Run this script in a directory with a working makefile to check for # compiler warnings in SQLite. # if uname | grep -i openbsd ; then # Use these for testing on OpenBSD: WARNING_OPTS=-Wall WARNING_ANDROID_OPTS=-Wall else # Use these for testing on Linux and Mac OSX: WARNING_OPTS="-Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long" | < < < | < < < | | 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 | #/bin/sh # # Run this script in a directory with a working makefile to check for # compiler warnings in SQLite. # if uname | grep -i openbsd ; then # Use these for testing on OpenBSD: WARNING_OPTS=-Wall WARNING_ANDROID_OPTS=-Wall else # Use these for testing on Linux and Mac OSX: WARNING_OPTS="-Wshadow -Wall -Wextra -pedantic-errors -Wno-long-long" WARNING_ANDROID_OPTS="-Wshadow -Wall -Wextra" fi rm -f sqlite3.c make sqlite3.c echo '********** No optimizations. Includes FTS4/5, GEOPOLY, JSON1 ***' echo '********** ' Options: $WARNING_OPTS gcc -c $WARNING_OPTS -std=c89 \ -ansi -DHAVE_STDINT_H -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_GEOPOLY \ -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_JSON1 \ sqlite3.c if test x`uname` = 'xLinux'; then echo '********** Android configuration ******************************' echo '********** ' Options: $WARNING_ANDROID_OPTS gcc -c \ -DHAVE_USLEEP=1 \ -DSQLITE_HAVE_ISNAN \ |
︙ | ︙ | |||
58 59 60 61 62 63 64 | gcc -c $WARNING_OPTS -std=c89 \ -ansi -DSQLITE_ENABLE_STAT4 -DSQLITE_THREADSAFE=0 \ sqlite3.c echo '********** Optimized -O3. Includes FTS4/5, GEOPOLY, JSON1 ******' echo '********** ' Options: $WARNING_OPTS gcc -O3 -c $WARNING_OPTS -std=c89 \ -ansi -DHAVE_STDINT_H -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_GEOPOLY \ | | | 52 53 54 55 56 57 58 59 60 | gcc -c $WARNING_OPTS -std=c89 \ -ansi -DSQLITE_ENABLE_STAT4 -DSQLITE_THREADSAFE=0 \ sqlite3.c echo '********** Optimized -O3. Includes FTS4/5, GEOPOLY, JSON1 ******' echo '********** ' Options: $WARNING_OPTS gcc -O3 -c $WARNING_OPTS -std=c89 \ -ansi -DHAVE_STDINT_H -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_GEOPOLY \ -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_JSON1 \ sqlite3.c |
Changes to vsixtest/App.xaml.cpp.
︙ | ︙ |