Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Difference From 2a832b19b657ba02 To 09b4f19f100fe82a
2009-11-11
| ||
13:17 | Allow media sector sizes as small as 32. The former minimum size was 512. (check-in: 5a32bfc17e user: drh tags: trunk) | |
04:17 | Modified CLI to raise an error when extra command line options are passed. Added tests to verify correct handling, as well as other basic handling of command line options. Ticket [f5cb008a65]. (check-in: 09b4f19f10 user: shaneh tags: trunk) | |
01:14 | Additional test cases for the coalesce() and ifnull() functions. (check-in: d0591258b6 user: drh tags: trunk) | |
2009-10-30
| ||
13:26 | Version 3.6.16.1 (Leaf check-in: 2a832b19b6 user: drh tags: release, branch_3_6_16) | |
2009-10-29
| ||
18:38 | Fix a 16-bit integer overflow that might occur in statements that use both an EXISTS clause and IN operator with a RHS holding in excess of 32K entries. (check-in: 65a1f1334d user: drh tags: branch_3_6_16) | |
Changes to Makefile.in.
︙ | ︙ | |||
161 162 163 164 165 166 167 | # You should not have to change anything below this line ############################################################################### # Object files for the SQLite library (non-amalgamation). # OBJS0 = alter.lo analyze.lo attach.lo auth.lo backup.lo bitvec.lo btmutex.lo \ btree.lo build.lo callback.lo complete.lo date.lo \ | | | 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | # You should not have to change anything below this line ############################################################################### # Object files for the SQLite library (non-amalgamation). # OBJS0 = alter.lo analyze.lo attach.lo auth.lo backup.lo bitvec.lo btmutex.lo \ btree.lo build.lo callback.lo complete.lo date.lo \ delete.lo expr.lo fault.lo fkey.lo func.lo global.lo \ hash.lo journal.lo insert.lo legacy.lo loadext.lo \ main.lo malloc.lo mem0.lo mem1.lo mem2.lo mem3.lo mem5.lo \ memjournal.lo \ mutex.lo mutex_noop.lo mutex_os2.lo mutex_unix.lo mutex_w32.lo \ notify.lo opcodes.lo os.lo os_unix.lo os_win.lo os_os2.lo \ pager.lo parse.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \ random.lo resolve.lo rowset.lo select.lo status.lo \ |
︙ | ︙ | |||
204 205 206 207 208 209 210 211 212 213 214 215 216 217 | $(TOP)/src/build.c \ $(TOP)/src/callback.c \ $(TOP)/src/complete.c \ $(TOP)/src/date.c \ $(TOP)/src/delete.c \ $(TOP)/src/expr.c \ $(TOP)/src/fault.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/journal.c \ | > | 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | $(TOP)/src/build.c \ $(TOP)/src/callback.c \ $(TOP)/src/complete.c \ $(TOP)/src/date.c \ $(TOP)/src/delete.c \ $(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/hash.h \ $(TOP)/src/hwtime.h \ $(TOP)/src/insert.c \ $(TOP)/src/journal.c \ |
︙ | ︙ | |||
231 232 233 234 235 236 237 | $(TOP)/src/mutex_os2.c \ $(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 \ | | | | | 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | $(TOP)/src/mutex_os2.c \ $(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_os2.c \ $(TOP)/src/os_unix.c \ $(TOP)/src/os_win.c \ $(TOP)/src/pager.c \ $(TOP)/src/pager.h \ $(TOP)/src/parse.y \ $(TOP)/src/pcache.c \ $(TOP)/src/pcache.h \ $(TOP)/src/pcache1.c \ $(TOP)/src/pragma.c \ |
︙ | ︙ | |||
334 335 336 337 338 339 340 | $(TOP)/src/bitvec.c \ $(TOP)/src/btree.c \ $(TOP)/src/build.c \ $(TOP)/src/date.c \ $(TOP)/src/expr.c \ $(TOP)/src/func.c \ $(TOP)/src/insert.c \ | | | 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 | $(TOP)/src/bitvec.c \ $(TOP)/src/btree.c \ $(TOP)/src/build.c \ $(TOP)/src/date.c \ $(TOP)/src/expr.c \ $(TOP)/src/func.c \ $(TOP)/src/insert.c \ $(TOP)/src/mem5.c \ $(TOP)/src/os.c \ $(TOP)/src/os_os2.c \ $(TOP)/src/os_unix.c \ $(TOP)/src/os_win.c \ $(TOP)/src/pager.c \ $(TOP)/src/pcache.c \ $(TOP)/src/pcache1.c \ |
︙ | ︙ | |||
377 378 379 380 381 382 383 | $(TOP)/src/test_async.c \ $(TOP)/src/test_backup.c \ $(TOP)/src/test_btree.c \ $(TOP)/src/test_config.c \ $(TOP)/src/test_devsym.c \ $(TOP)/src/test_func.c \ $(TOP)/src/test_hexio.c \ | | > | | | > | 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 | $(TOP)/src/test_async.c \ $(TOP)/src/test_backup.c \ $(TOP)/src/test_btree.c \ $(TOP)/src/test_config.c \ $(TOP)/src/test_devsym.c \ $(TOP)/src/test_func.c \ $(TOP)/src/test_hexio.c \ $(TOP)/src/test_init.c \ $(TOP)/src/test_intarray.c \ $(TOP)/src/test_journal.c \ $(TOP)/src/test_malloc.c \ $(TOP)/src/test_mutex.c \ $(TOP)/src/test_onefile.c \ $(TOP)/src/test_osinst.c \ $(TOP)/src/test_pcache.c \ $(TOP)/src/test_schema.c \ $(TOP)/src/test_server.c \ $(TOP)/src/test_tclvar.c \ $(TOP)/src/test_thread.c \ $(TOP)/src/test_wsd.c # Header files used by all library source files. # HDR = \ sqlite3.h \ $(TOP)/src/btree.h \ $(TOP)/src/btreeInt.h \ |
︙ | ︙ | |||
450 451 452 453 454 455 456 | Makefile: $(TOP)/Makefile.in ./config.status sqlite3.pc: $(TOP)/sqlite3.pc.in ./config.status | < < < < < < < | 453 454 455 456 457 458 459 460 461 462 463 464 465 466 | Makefile: $(TOP)/Makefile.in ./config.status sqlite3.pc: $(TOP)/sqlite3.pc.in ./config.status libsqlite3.la: $(LIBOBJ) $(LTLINK) -o $@ $(LIBOBJ) $(TLIBS) \ ${ALLOWRELEASE} -rpath "$(libdir)" -version-info "8:6:8" libtclsqlite3.la: tclsqlite.lo libsqlite3.la $(LTLINK) -o $@ tclsqlite.lo \ libsqlite3.la @TCL_STUB_LIB_SPEC@ $(TLIBS) \ |
︙ | ︙ | |||
493 494 495 496 497 498 499 | touch .target_source sqlite3.c: .target_source $(TOP)/tool/mksqlite3c.tcl $(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl # Rules to build the LEMON compiler generator # | | | | 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 | touch .target_source sqlite3.c: .target_source $(TOP)/tool/mksqlite3c.tcl $(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl # Rules to build the LEMON compiler generator # lemon$(BEXE): $(TOP)/tool/lemon.c $(TOP)/src/lempar.c $(BCC) -o $@ $(TOP)/tool/lemon.c cp $(TOP)/src/lempar.c . # Rule to build the amalgamation # sqlite3.lo: sqlite3.c $(LTCOMPILE) $(TEMP_STORE) -c sqlite3.c |
︙ | ︙ | |||
550 551 552 553 554 555 556 557 558 559 560 561 562 563 | expr.lo: $(TOP)/src/expr.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/expr.c fault.lo: $(TOP)/src/fault.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/fault.c func.lo: $(TOP)/src/func.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/func.c global.lo: $(TOP)/src/global.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/global.c hash.lo: $(TOP)/src/hash.c $(HDR) | > > > | 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 | expr.lo: $(TOP)/src/expr.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/expr.c fault.lo: $(TOP)/src/fault.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/fault.c fkey.lo: $(TOP)/src/fkey.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/fkey.c func.lo: $(TOP)/src/func.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/func.c global.lo: $(TOP)/src/global.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/global.c hash.lo: $(TOP)/src/hash.c $(HDR) |
︙ | ︙ | |||
678 679 680 681 682 683 684 | select.lo: $(TOP)/src/select.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/select.c status.lo: $(TOP)/src/status.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/status.c | | < | | 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 | select.lo: $(TOP)/src/select.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/select.c status.lo: $(TOP)/src/status.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/status.c sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest.uuid $(TOP)/VERSION tclsh $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h table.lo: $(TOP)/src/table.c $(HDR) $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/table.c tclsqlite.lo: $(TOP)/src/tclsqlite.c $(HDR) $(LTCOMPILE) -DUSE_TCL_STUBS=1 -c $(TOP)/src/tclsqlite.c |
︙ | ︙ |
Changes to Makefile.vxworks.
︙ | ︙ | |||
485 486 487 488 489 490 491 | 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 # | | | | 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 | 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)/src/lempar.c $(BCC) -o lemon $(TOP)/tool/lemon.c cp $(TOP)/src/lempar.c . # Rules to build individual *.o files from generated *.c files. This # applies to: # # parse.o # opcodes.o # |
︙ | ︙ |
Changes to README.
︙ | ︙ | |||
20 21 22 23 24 25 26 | 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. The linux binaries on the website are created using the generic makefile, | | < | | > > > > > > | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 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. The linux binaries on the website are created using the generic makefile, not the configure script. The windows binaries on the website are created using MinGW32 configured as a cross-compiler running under Linux. For details, see the ./publish.sh script at the top-level of the source tree. The developers do not use teh configure script. SQLite does not require TCL to run, but a TCL installation is required by the makefiles. SQLite contains a lot of generated code and TCL is used to do much of that code generation. The makefile also requires AWK. Contacts: http://www.sqlite.org/ |
Changes to VERSION.
|
| | | 1 | 3.6.20 |
Changes to addopcodes.awk.
︙ | ︙ | |||
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | } END { printf "#define TK_%-29s %4d\n", "TO_TEXT", ++max printf "#define TK_%-29s %4d\n", "TO_BLOB", ++max printf "#define TK_%-29s %4d\n", "TO_NUMERIC", ++max printf "#define TK_%-29s %4d\n", "TO_INT", ++max printf "#define TK_%-29s %4d\n", "TO_REAL", ++max printf "#define TK_%-29s %4d\n", "END_OF_FILE", ++max printf "#define TK_%-29s %4d\n", "ILLEGAL", ++max printf "#define TK_%-29s %4d\n", "SPACE", ++max printf "#define TK_%-29s %4d\n", "UNCLOSED_STRING", ++max printf "#define TK_%-29s %4d\n", "FUNCTION", ++max printf "#define TK_%-29s %4d\n", "COLUMN", ++max printf "#define TK_%-29s %4d\n", "AGG_FUNCTION", ++max printf "#define TK_%-29s %4d\n", "AGG_COLUMN", ++max printf "#define TK_%-29s %4d\n", "CONST_FUNC", ++max } | > > > | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | } END { printf "#define TK_%-29s %4d\n", "TO_TEXT", ++max printf "#define TK_%-29s %4d\n", "TO_BLOB", ++max printf "#define TK_%-29s %4d\n", "TO_NUMERIC", ++max printf "#define TK_%-29s %4d\n", "TO_INT", ++max printf "#define TK_%-29s %4d\n", "TO_REAL", ++max printf "#define TK_%-29s %4d\n", "ISNOT", ++max printf "#define TK_%-29s %4d\n", "END_OF_FILE", ++max printf "#define TK_%-29s %4d\n", "ILLEGAL", ++max printf "#define TK_%-29s %4d\n", "SPACE", ++max printf "#define TK_%-29s %4d\n", "UNCLOSED_STRING", ++max printf "#define TK_%-29s %4d\n", "FUNCTION", ++max printf "#define TK_%-29s %4d\n", "COLUMN", ++max printf "#define TK_%-29s %4d\n", "AGG_FUNCTION", ++max printf "#define TK_%-29s %4d\n", "AGG_COLUMN", ++max printf "#define TK_%-29s %4d\n", "CONST_FUNC", ++max printf "#define TK_%-29s %4d\n", "UMINUS", ++max printf "#define TK_%-29s %4d\n", "UPLUS", ++max } |
Added art/src_logo.gif.
cannot compute difference between binary files
Changes to configure.
1 2 | #! /bin/sh # Guess values for system-dependent variables and create Makefiles. | | | 1 2 3 4 5 6 7 8 9 10 | #! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.62 for sqlite 3.6.20. # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## --------------------- ## ## M4sh Initialization. ## |
︙ | ︙ | |||
739 740 741 742 743 744 745 | MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='sqlite' PACKAGE_TARNAME='sqlite' | | | | 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 | MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='sqlite' PACKAGE_TARNAME='sqlite' PACKAGE_VERSION='3.6.20' PACKAGE_STRING='sqlite 3.6.20' PACKAGE_BUGREPORT='' # Factoring default headers for most tests. ac_includes_default="\ #include <stdio.h> #ifdef HAVE_SYS_TYPES_H # include <sys/types.h> |
︙ | ︙ | |||
1483 1484 1485 1486 1487 1488 1489 | # # 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 | | | 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 | # # 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.6.20 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. |
︙ | ︙ | |||
1548 1549 1550 1551 1552 1553 1554 | --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 | | | 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 | --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.6.20:";; 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] |
︙ | ︙ | |||
1666 1667 1668 1669 1670 1671 1672 | cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF | | | | 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 | 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.6.20 generated by GNU Autoconf 2.62 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by sqlite $as_me 3.6.20, which was generated by GNU Autoconf 2.62. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { |
︙ | ︙ | |||
2061 2062 2063 2064 2065 2066 2067 | configure \$PACKAGE_VERSION = $PACKAGE_VERSION top level VERSION file = $sqlite_version_sanity_check please regen with autoconf" >&2;} { (exit 1); exit 1; }; } fi # The following RCS revision string applies to configure.in | | | 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 | configure \$PACKAGE_VERSION = $PACKAGE_VERSION top level VERSION file = $sqlite_version_sanity_check please regen with autoconf" >&2;} { (exit 1); exit 1; }; } fi # The following RCS revision string applies to configure.in # $Revision: 1.56 $ ######### # Programs needed # case `pwd` in *\ * | *\ *) { $as_echo "$as_me:$LINENO: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 |
︙ | ︙ | |||
13968 13969 13970 13971 13972 13973 13974 | exec 6>&1 # Save the log message, to keep $[0] and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" | | | 13968 13969 13970 13971 13972 13973 13974 13975 13976 13977 13978 13979 13980 13981 13982 | exec 6>&1 # Save the log message, to keep $[0] and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by sqlite $as_me 3.6.20, which was generated by GNU Autoconf 2.62. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ |
︙ | ︙ | |||
14021 14022 14023 14024 14025 14026 14027 | $config_commands Report bugs to <bug-autoconf@gnu.org>." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_version="\\ | | | 14021 14022 14023 14024 14025 14026 14027 14028 14029 14030 14031 14032 14033 14034 14035 | $config_commands Report bugs to <bug-autoconf@gnu.org>." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_version="\\ sqlite config.status 3.6.20 configured by $0, generated by GNU Autoconf 2.62, with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" Copyright (C) 2008 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." |
︙ | ︙ |
Deleted doc/report1.txt.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to ext/async/sqlite3async.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 2005 December 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 | /* ** 2005 December 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. ** ************************************************************************* ** ** $Id: sqlite3async.c,v 1.7 2009/07/18 11:52:04 danielk1977 Exp $ ** ** This file contains the implementation of an asynchronous IO backend ** for SQLite. */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ASYNCIO) |
︙ | ︙ | |||
664 665 666 667 668 669 670 | void *zOut, int iAmt, sqlite3_int64 iOffset ){ AsyncFileData *p = ((AsyncFile *)pFile)->pData; int rc = SQLITE_OK; sqlite3_int64 filesize; | < > > | > > > > > > > > < < < > | 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 | void *zOut, int iAmt, sqlite3_int64 iOffset ){ AsyncFileData *p = ((AsyncFile *)pFile)->pData; int rc = SQLITE_OK; sqlite3_int64 filesize; sqlite3_file *pBase = p->pBaseRead; sqlite3_int64 iAmt64 = (sqlite3_int64)iAmt; /* Grab the write queue mutex for the duration of the call */ async_mutex_enter(ASYNC_MUTEX_QUEUE); /* If an I/O error has previously occurred in this virtual file ** system, then all subsequent operations fail. */ if( async.ioError!=SQLITE_OK ){ rc = async.ioError; goto asyncread_out; } if( pBase->pMethods ){ sqlite3_int64 nRead; rc = pBase->pMethods->xFileSize(pBase, &filesize); if( rc!=SQLITE_OK ){ goto asyncread_out; } nRead = MIN(filesize - iOffset, iAmt64); if( nRead>0 ){ rc = pBase->pMethods->xRead(pBase, zOut, nRead, iOffset); ASYNC_TRACE(("READ %s %d bytes at %d\n", p->zName, nRead, iOffset)); } } if( rc==SQLITE_OK ){ AsyncWrite *pWrite; char *zName = p->zName; for(pWrite=async.pQueueFirst; pWrite; pWrite = pWrite->pNext){ if( pWrite->op==ASYNC_WRITE && ( (pWrite->pFileData==p) || (zName && pWrite->pFileData->zName==zName) )){ sqlite3_int64 nCopy; sqlite3_int64 nByte64 = (sqlite3_int64)pWrite->nByte; /* Set variable iBeginIn to the offset in buffer pWrite->zBuf[] from ** which data should be copied. Set iBeginOut to the offset within ** the output buffer to which data should be copied. If either of ** these offsets is a negative number, set them to 0. */ sqlite3_int64 iBeginOut = (pWrite->iOffset-iOffset); sqlite3_int64 iBeginIn = -iBeginOut; if( iBeginIn<0 ) iBeginIn = 0; if( iBeginOut<0 ) iBeginOut = 0; nCopy = MIN(nByte64-iBeginIn, iAmt64-iBeginOut); if( nCopy>0 ){ memcpy(&((char *)zOut)[iBeginOut], &pWrite->zBuf[iBeginIn], nCopy); ASYNC_TRACE(("OVERREAD %d bytes at %d\n", nCopy, iBeginOut+iOffset)); } } } } |
︙ | ︙ | |||
1061 1062 1063 1064 1065 1066 1067 | pData->nName = nName; memcpy(pData->zName, zName, nName); } if( !isAsyncOpen ){ int flagsout; rc = pVfs->xOpen(pVfs, pData->zName, pData->pBaseRead, flags, &flagsout); | > | > > | 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 | pData->nName = nName; memcpy(pData->zName, zName, nName); } if( !isAsyncOpen ){ int flagsout; rc = pVfs->xOpen(pVfs, pData->zName, pData->pBaseRead, flags, &flagsout); if( rc==SQLITE_OK && (flagsout&SQLITE_OPEN_READWRITE) && (flags&SQLITE_OPEN_EXCLUSIVE)==0 ){ rc = pVfs->xOpen(pVfs, pData->zName, pData->pBaseWrite, flags, 0); } if( pOutFlags ){ *pOutFlags = flagsout; } } |
︙ | ︙ |
Changes to ext/fts3/fts3_expr.c.
︙ | ︙ | |||
417 418 419 420 421 422 423 | ** limitation. */ iCol = pParse->iDefaultCol; iColLen = 0; for(ii=0; ii<pParse->nCol; ii++){ const char *zStr = pParse->azCol[ii]; int nStr = strlen(zStr); | | > > | 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 | ** limitation. */ iCol = pParse->iDefaultCol; iColLen = 0; for(ii=0; ii<pParse->nCol; ii++){ const char *zStr = pParse->azCol[ii]; int nStr = strlen(zStr); if( nInput>nStr && zInput[nStr]==':' && sqlite3_strnicmp(zStr, zInput, nStr)==0 ){ iCol = ii; iColLen = ((zInput - z) + nStr + 1); break; } } rc = getNextToken(pParse, iCol, &z[iColLen], n-iColLen, ppExpr, pnConsumed); *pnConsumed += iColLen; |
︙ | ︙ | |||
534 535 536 537 538 539 540 | rc = SQLITE_NOMEM; goto exprparse_out; } memset(pNot, 0, sizeof(Fts3Expr)); pNot->eType = FTSQUERY_NOT; pNot->pRight = p; if( pNotBranch ){ | < | > | 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 | rc = SQLITE_NOMEM; goto exprparse_out; } memset(pNot, 0, sizeof(Fts3Expr)); pNot->eType = FTSQUERY_NOT; pNot->pRight = p; if( pNotBranch ){ pNot->pLeft = pNotBranch; } pNotBranch = pNot; p = pPrev; }else{ int eType = p->eType; assert( eType!=FTSQUERY_PHRASE || !p->pPhrase->isNot ); isPhrase = (eType==FTSQUERY_PHRASE || p->pLeft); /* The isRequirePhrase variable is set to true if a phrase or ** an expression contained in parenthesis is required. If a |
︙ | ︙ | |||
619 620 621 622 623 624 625 | if( rc==SQLITE_DONE ){ rc = SQLITE_OK; if( !sqlite3_fts3_enable_parentheses && pNotBranch ){ if( !pRet ){ rc = SQLITE_ERROR; }else{ | > > > > | | 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 | if( rc==SQLITE_DONE ){ rc = SQLITE_OK; if( !sqlite3_fts3_enable_parentheses && pNotBranch ){ if( !pRet ){ rc = SQLITE_ERROR; }else{ Fts3Expr *pIter = pNotBranch; while( pIter->pLeft ){ pIter = pIter->pLeft; } pIter->pLeft = pRet; pRet = pNotBranch; } } } *pnConsumed = n - nIn; exprparse_out: |
︙ | ︙ |
Changes to ext/rtree/rtree.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code for implementations of the r-tree and r*-tree ** algorithms packaged as an SQLite virtual table module. | < < | 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 contains code for implementations of the r-tree and r*-tree ** algorithms packaged as an SQLite virtual table module. */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RTREE) /* ** This file contains an implementation of a couple of different variants ** of the r-tree algorithm. See the README file for further details. The |
︙ | ︙ | |||
1482 1483 1484 1485 1486 1487 1488 | /* Pick two "seed" cells from the array of cells. The algorithm used ** here is the LinearPickSeeds algorithm from Gutman[1984]. The ** indices of the two seed cells in the array are stored in local ** variables iLeftSeek and iRightSeed. */ for(i=0; i<pRtree->nDim; i++){ | | | | | | 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 | /* Pick two "seed" cells from the array of cells. The algorithm used ** here is the LinearPickSeeds algorithm from Gutman[1984]. The ** indices of the two seed cells in the array are stored in local ** variables iLeftSeek and iRightSeed. */ for(i=0; i<pRtree->nDim; i++){ float x1 = DCOORD(aCell[0].aCoord[i*2]); float x2 = DCOORD(aCell[0].aCoord[i*2+1]); float x3 = x1; float x4 = x2; int jj; int iCellLeft = 0; int iCellRight = 0; for(jj=1; jj<nCell; jj++){ float left = DCOORD(aCell[jj].aCoord[i*2]); float right = DCOORD(aCell[jj].aCoord[i*2+1]); if( left<x1 ) x1 = left; if( right>x4 ) x4 = right; if( left>x3 ){ x3 = left; iCellRight = jj; } |
︙ | ︙ | |||
1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 | ){ int iLeftSeed = 0; int iRightSeed = 1; int *aiUsed; int i; aiUsed = sqlite3_malloc(sizeof(int)*nCell); memset(aiUsed, 0, sizeof(int)*nCell); PickSeeds(pRtree, aCell, nCell, &iLeftSeed, &iRightSeed); memcpy(pBboxLeft, &aCell[iLeftSeed], sizeof(RtreeCell)); memcpy(pBboxRight, &aCell[iRightSeed], sizeof(RtreeCell)); nodeInsertCell(pRtree, pLeft, &aCell[iLeftSeed]); | > > > | 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 | ){ int iLeftSeed = 0; int iRightSeed = 1; int *aiUsed; int i; aiUsed = sqlite3_malloc(sizeof(int)*nCell); if( !aiUsed ){ return SQLITE_NOMEM; } memset(aiUsed, 0, sizeof(int)*nCell); PickSeeds(pRtree, aCell, nCell, &iLeftSeed, &iRightSeed); memcpy(pBboxLeft, &aCell[iLeftSeed], sizeof(RtreeCell)); memcpy(pBboxRight, &aCell[iRightSeed], sizeof(RtreeCell)); nodeInsertCell(pRtree, pLeft, &aCell[iLeftSeed]); |
︙ | ︙ | |||
2338 2339 2340 2341 2342 2343 2344 | return 1; } #endif /* ** The xUpdate method for rtree module virtual tables. */ | | | 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 | return 1; } #endif /* ** The xUpdate method for rtree module virtual tables. */ static int rtreeUpdate( sqlite3_vtab *pVtab, int nData, sqlite3_value **azData, sqlite_int64 *pRowid ){ Rtree *pRtree = (Rtree *)pVtab; int rc = SQLITE_OK; |
︙ | ︙ | |||
2733 2734 2735 2736 2737 2738 2739 | sqlite3_free(zTmp); } if( zSql ){ zTmp = zSql; zSql = sqlite3_mprintf("%s);", zTmp); sqlite3_free(zTmp); } | | > > | 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 | sqlite3_free(zTmp); } if( zSql ){ zTmp = zSql; zSql = sqlite3_mprintf("%s);", zTmp); sqlite3_free(zTmp); } if( !zSql ){ rc = SQLITE_NOMEM; }else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); } sqlite3_free(zSql); } if( rc==SQLITE_OK ){ *ppVtab = (sqlite3_vtab *)pRtree; }else{ |
︙ | ︙ |
Changes to ext/rtree/rtree1.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2008 Feb 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. # #*********************************************************************** # # The focus of this file is testing the r-tree extension. # | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # 2008 Feb 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. # #*********************************************************************** # # The focus of this file is testing the r-tree extension. # if {![info exists testdir]} { set testdir [file join [file dirname $argv0] .. .. test] } source [file join [file dirname [info script]] rtree_util.tcl] source $testdir/tester.tcl |
︙ | ︙ | |||
388 389 390 391 392 393 394 395 396 | } {1600} do_test rtree-9.3 { execsql { SELECT count(*) FROM bar b1, bar b2, foo s1 WHERE b1.minX <= b2.maxX AND s1.id = b1.id; } } {1600} finish_test | > > > > > > > > | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 | } {1600} do_test rtree-9.3 { execsql { SELECT count(*) FROM bar b1, bar b2, foo s1 WHERE b1.minX <= b2.maxX AND s1.id = b1.id; } } {1600} #------------------------------------------------------------------------- # Ticket #3970: Check that the error message is meaningful when a # keyword is used as a column name. # do_test rtree-10.1 { catchsql { CREATE VIRTUAL TABLE t7 USING rtree(index, x1, y1, x2, y2) } } {1 {near "index": syntax error}} finish_test |
Changes to ext/rtree/rtree2.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2008 Feb 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. # #*********************************************************************** # # The focus of this file is testing the r-tree extension. # | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # 2008 Feb 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. # #*********************************************************************** # # The focus of this file is testing the r-tree extension. # if {![info exists testdir]} { set testdir [file join [file dirname $argv0] .. .. test] } source [file join [file dirname [info script]] rtree_util.tcl] source $testdir/tester.tcl |
︙ | ︙ |
Changes to ext/rtree/rtree3.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # May you share freely, never taking more than you give. # #*********************************************************************** # # The focus of this file is testing that the r-tree correctly handles # out-of-memory conditions. # | < < | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # May you share freely, never taking more than you give. # #*********************************************************************** # # The focus of this file is testing that the r-tree correctly handles # out-of-memory conditions. # if {![info exists testdir]} { set testdir [file join [file dirname $argv0] .. .. test] } source $testdir/tester.tcl ifcapable !rtree { |
︙ | ︙ | |||
67 68 69 70 71 72 73 | set f [expr rand()] db eval { DELETE FROM rt WHERE x1<($f*10.0) AND x1>($f*10.5) } } db eval COMMIT } finish_test | < | 65 66 67 68 69 70 71 | set f [expr rand()] db eval { DELETE FROM rt WHERE x1<($f*10.0) AND x1>($f*10.5) } } db eval COMMIT } finish_test |
Changes to ext/rtree/rtree4.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2008 May 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. # #*********************************************************************** # # Randomized test cases for the rtree extension. # | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # 2008 May 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. # #*********************************************************************** # # Randomized test cases for the rtree extension. # if {![info exists testdir]} { set testdir [file join [file dirname $argv0] .. .. test] } source $testdir/tester.tcl ifcapable !rtree { |
︙ | ︙ |
Changes to ext/rtree/rtree5.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # May you share freely, never taking more than you give. # #*********************************************************************** # # The focus of this file is testing the r-tree extension when it is # configured to store values as 32 bit integers. # | < < | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # May you share freely, never taking more than you give. # #*********************************************************************** # # The focus of this file is testing the r-tree extension when it is # configured to store values as 32 bit integers. # if {![info exists testdir]} { set testdir [file join [file dirname $argv0] .. .. test] } source $testdir/tester.tcl ifcapable !rtree { |
︙ | ︙ |
Changes to ext/rtree/rtree6.test.
1 2 3 4 5 6 7 8 9 10 | # 2008 Sep 1 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** | | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # 2008 Sep 1 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # if {![info exists testdir]} { set testdir [file join [file dirname $argv0] .. .. test] } source $testdir/tester.tcl |
︙ | ︙ | |||
92 93 94 95 96 97 98 | {TABLE t2} \ {TABLE t1 VIRTUAL TABLE INDEX 1:} \ ] do_test rtree6.2.4 { query_plan {SELECT * FROM t1,t2 WHERE v=10 and x1<10 and x2>10} } [list \ | < > < | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | {TABLE t2} \ {TABLE t1 VIRTUAL TABLE INDEX 1:} \ ] do_test rtree6.2.4 { query_plan {SELECT * FROM t1,t2 WHERE v=10 and x1<10 and x2>10} } [list \ {TABLE t1 VIRTUAL TABLE INDEX 2:CaEb} \ {TABLE t2} \ ] do_test rtree6.2.5 { query_plan {SELECT * FROM t1,t2 WHERE k=ii AND x1<v} } [list \ {TABLE t2} \ {TABLE t1 VIRTUAL TABLE INDEX 1:} \ ] finish_test |
Changes to ext/rtree/rtree_perf.tcl.
︙ | ︙ | |||
68 69 70 71 72 73 74 | flush stdout set rtree_select_time [time { foreach {x1 x2 y1 y2} [lrange $data 0 [expr $NQUERY*4-1]] { db eval {SELECT * FROM rtree WHERE x1<$x1 AND x2>$x2 AND y1<$y1 AND y2>$y2} } }] puts "$rtree_select_time" | < < | 68 69 70 71 72 73 74 | flush stdout set rtree_select_time [time { foreach {x1 x2 y1 y2} [lrange $data 0 [expr $NQUERY*4-1]] { db eval {SELECT * FROM rtree WHERE x1<$x1 AND x2>$x2 AND y1<$y1 AND y2>$y2} } }] puts "$rtree_select_time" |
Changes to ext/rtree/rtree_util.tcl.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # # This file contains Tcl code that may be useful for testing or # analyzing r-tree structures created with this module. It is # used by both test procedures and the r-tree viewer application. # | < < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # #*********************************************************************** # # This file contains Tcl code that may be useful for testing or # analyzing r-tree structures created with this module. It is # used by both test procedures and the r-tree viewer application. # #-------------------------------------------------------------------------- # PUBLIC API: # # rtree_depth # rtree_ndim |
︙ | ︙ | |||
188 189 190 191 192 193 194 | set ret } proc rtree_treedump {db zTab} { set d [rtree_depth $db $zTab] rtree_nodetreedump $db $zTab "" $d 1 } | < | 186 187 188 189 190 191 192 | set ret } proc rtree_treedump {db zTab} { set d [rtree_depth $db $zTab] rtree_nodetreedump $db $zTab "" $d 1 } |
Changes to ext/rtree/tkt3363.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2008 Sep 08 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # The focus of this file is testing that ticket #3363 is fixed. # | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # 2008 Sep 08 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # The focus of this file is testing that ticket #3363 is fixed. # if {![info exists testdir]} { set testdir [file join [file dirname $argv0] .. .. test] } source [file join [file dirname [info script]] rtree_util.tcl] source $testdir/tester.tcl |
︙ | ︙ | |||
46 47 48 49 50 51 52 | do_test tkt3363.1.4 { execsql { SELECT count(*) FROM t1 WHERE y2>4000425.0; } } {7} finish_test | < < | 44 45 46 47 48 49 50 | do_test tkt3363.1.4 { execsql { SELECT count(*) FROM t1 WHERE y2>4000425.0; } } {7} finish_test |
Changes to ext/rtree/viewrtree.tcl.
︙ | ︙ | |||
182 183 184 185 186 187 188 | } return $zReport } view_node bind .c <Configure> view_node | < | 182 183 184 185 186 187 188 | } return $zReport } view_node bind .c <Configure> view_node |
Changes to main.mk.
︙ | ︙ | |||
48 49 50 51 52 53 54 | TCCX += -I$(TOP)/ext/rtree -I$(TOP)/ext/icu -I$(TOP)/ext/fts3 TCCX += -I$(TOP)/ext/async # Object files for the SQLite library. # LIBOBJ+= alter.o analyze.o attach.o auth.o \ backup.o bitvec.o btmutex.o btree.o build.o \ | | | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | TCCX += -I$(TOP)/ext/rtree -I$(TOP)/ext/icu -I$(TOP)/ext/fts3 TCCX += -I$(TOP)/ext/async # Object files for the SQLite library. # LIBOBJ+= alter.o analyze.o attach.o auth.o \ backup.o bitvec.o btmutex.o btree.o build.o \ callback.o complete.o date.o delete.o expr.o fault.o fkey.o \ fts3.o fts3_expr.o fts3_hash.o fts3_icu.o fts3_porter.o \ fts3_tokenizer.o fts3_tokenizer1.o \ func.o global.o hash.o \ icu.o insert.o journal.o legacy.o loadext.o \ main.o malloc.o mem0.o mem1.o mem2.o mem3.o mem5.o \ memjournal.o \ mutex.o mutex_noop.o mutex_os2.o mutex_unix.o mutex_w32.o \ |
︙ | ︙ | |||
86 87 88 89 90 91 92 93 94 95 96 97 98 99 | $(TOP)/src/build.c \ $(TOP)/src/callback.c \ $(TOP)/src/complete.c \ $(TOP)/src/date.c \ $(TOP)/src/delete.c \ $(TOP)/src/expr.c \ $(TOP)/src/fault.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/journal.c \ | > | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | $(TOP)/src/build.c \ $(TOP)/src/callback.c \ $(TOP)/src/complete.c \ $(TOP)/src/date.c \ $(TOP)/src/delete.c \ $(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/hash.h \ $(TOP)/src/hwtime.h \ $(TOP)/src/insert.c \ $(TOP)/src/journal.c \ |
︙ | ︙ | |||
188 189 190 191 192 193 194 | $(TOP)/ext/fts3/fts3_icu.c \ $(TOP)/ext/fts3/fts3_porter.c \ $(TOP)/ext/fts3/fts3_tokenizer.h \ $(TOP)/ext/fts3/fts3_tokenizer.c \ $(TOP)/ext/fts3/fts3_tokenizer1.c SRC += \ $(TOP)/ext/icu/sqliteicu.h \ | | | 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | $(TOP)/ext/fts3/fts3_icu.c \ $(TOP)/ext/fts3/fts3_porter.c \ $(TOP)/ext/fts3/fts3_tokenizer.h \ $(TOP)/ext/fts3/fts3_tokenizer.c \ $(TOP)/ext/fts3/fts3_tokenizer1.c SRC += \ $(TOP)/ext/icu/sqliteicu.h \ $(TOP)/ext/icu/icu.c SRC += \ $(TOP)/ext/rtree/rtree.h \ $(TOP)/ext/rtree/rtree.c # Generated source code files # |
︙ | ︙ | |||
225 226 227 228 229 230 231 | $(TOP)/src/test_async.c \ $(TOP)/src/test_backup.c \ $(TOP)/src/test_btree.c \ $(TOP)/src/test_config.c \ $(TOP)/src/test_devsym.c \ $(TOP)/src/test_func.c \ $(TOP)/src/test_hexio.c \ | | > | | | | > | 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 | $(TOP)/src/test_async.c \ $(TOP)/src/test_backup.c \ $(TOP)/src/test_btree.c \ $(TOP)/src/test_config.c \ $(TOP)/src/test_devsym.c \ $(TOP)/src/test_func.c \ $(TOP)/src/test_hexio.c \ $(TOP)/src/test_init.c \ $(TOP)/src/test_intarray.c \ $(TOP)/src/test_journal.c \ $(TOP)/src/test_malloc.c \ $(TOP)/src/test_mutex.c \ $(TOP)/src/test_onefile.c \ $(TOP)/src/test_osinst.c \ $(TOP)/src/test_pcache.c \ $(TOP)/src/test_schema.c \ $(TOP)/src/test_server.c \ $(TOP)/src/test_tclvar.c \ $(TOP)/src/test_thread.c \ $(TOP)/src/test_wsd.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/expr.c $(TOP)/src/func.c $(TOP)/src/insert.c $(TOP)/src/mem5.c \ $(TOP)/src/os.c \ $(TOP)/src/os_os2.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/where.c parse.c \ $(TOP)/ext/fts3/fts3.c $(TOP)/ext/fts3/fts3_expr.c \ |
︙ | ︙ | |||
341 342 343 344 345 346 347 | 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 # | | | | 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 | 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)/src/lempar.c $(BCC) -o lemon $(TOP)/tool/lemon.c cp $(TOP)/src/lempar.c . # Rules to build individual *.o files from generated *.c files. This # applies to: # # parse.o # opcodes.o # |
︙ | ︙ | |||
384 385 386 387 388 389 390 | parse.c: $(TOP)/src/parse.y lemon $(TOP)/addopcodes.awk cp $(TOP)/src/parse.y . rm -f parse.h ./lemon $(OPTS) parse.y mv parse.h parse.h.temp awk -f $(TOP)/addopcodes.awk parse.h.temp >parse.h | | < < | | 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 | parse.c: $(TOP)/src/parse.y lemon $(TOP)/addopcodes.awk cp $(TOP)/src/parse.y . rm -f parse.h ./lemon $(OPTS) parse.y mv parse.h parse.h.temp awk -f $(TOP)/addopcodes.awk parse.h.temp >parse.h sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest.uuid $(TOP)/VERSION 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 |
︙ | ︙ |
Changes to mkopcodeh.awk.
︙ | ︙ | |||
21 22 23 24 25 26 27 | # OP_Add and OP_Divide. By making TK_ADD==OP_Add and TK_DIVIDE==OP_Divide, # code to translate from one to the other is avoided. This makes the # code generator run (infinitesimally) faster and more importantly it makes # the library footprint smaller. # # This script also scans for lines of the form: # | | | | | < < < < < < | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | # OP_Add and OP_Divide. By making TK_ADD==OP_Add and TK_DIVIDE==OP_Divide, # code to translate from one to the other is avoided. This makes the # code generator run (infinitesimally) faster and more importantly it makes # the library footprint smaller. # # This script also scans for lines of the form: # # case OP_aaaa: /* jump, in1, in2, in3, out2-prerelease, out3 */ # # When such comments are found on an opcode, it means that certain # properties apply to that opcode. Set corresponding flags using the # OPFLG_INITIALIZER macro. # # Remember the TK_ values from the parse.h file /^#define TK_/ { tk[$2] = 0+$3 } |
︙ | ︙ | |||
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | in2[name] = 1 }else if(x=="in3"){ in3[name] = 1 }else if(x=="out3"){ out3[name] = 1 } } } # Assign numbers to all opcodes and output the result. END { cnt = 0 max = 0 print "/* Automatically generated. Do not edit */" print "/* See the mkopcodeh.awk script for details */" op["OP_Noop"] = -1; op["OP_Explain"] = -1; | > > > > | | 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | in2[name] = 1 }else if(x=="in3"){ in3[name] = 1 }else if(x=="out3"){ out3[name] = 1 } } order[n_op++] = name; } # Assign numbers to all opcodes and output the result. END { cnt = 0 max = 0 print "/* Automatically generated. Do not edit */" print "/* See the mkopcodeh.awk script for details */" op["OP_Noop"] = -1; order[n_op++] = "OP_Noop"; op["OP_Explain"] = -1; order[n_op++] = "OP_Explain"; for(i=0; i<n_op; i++){ name = order[i]; if( op[name]<0 ){ cnt++ while( used[cnt] ) cnt++ op[name] = cnt } used[op[name]] = 1; if( op[name]>max ) max = op[name] |
︙ | ︙ | |||
119 120 121 122 123 124 125 | # Generate the bitvectors: # # bit 0: jump # bit 1: pushes a result onto stack # bit 2: output to p1. release p1 before opcode runs # for(i=0; i<=max; i++) bv[i] = 0; | > | | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | # Generate the bitvectors: # # bit 0: jump # bit 1: pushes a result onto stack # bit 2: output to p1. release p1 before opcode runs # for(i=0; i<=max; i++) bv[i] = 0; for(i=0; i<n_op; i++){ name = order[i]; x = op[name] a0 = a1 = a2 = a3 = a4 = a5 = a6 = a7 = 0 # a8 = a9 = a10 = a11 = a12 = a13 = a14 = a15 = 0 if( jump[name] ) a0 = 1; if( out2_prerelease[name] ) a1 = 2; if( in1[name] ) a2 = 4; if( in2[name] ) a3 = 8; |
︙ | ︙ |
Changes to publish.sh.
︙ | ︙ | |||
88 89 90 91 92 93 94 95 96 | zip doc/sqlite-$VERSW.zip sqlite3.exe # Construct a tarball of the source tree # echo '***** BUILDING source archive' ORIGIN=`pwd` cd $srcdir cd .. mv sqlite sqlite-$VERS | > | | 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | zip doc/sqlite-$VERSW.zip sqlite3.exe # Construct a tarball of the source tree # echo '***** BUILDING source archive' ORIGIN=`pwd` cd $srcdir chmod +x configure cd .. mv sqlite sqlite-$VERS EXCLUDE=`find sqlite-$VERS -print | egrep '(www/|art/|doc/|contrib/|_FOSSIL_)' | sed 's,^, --exclude ,'` echo "tar czf $ORIGIN/doc/sqlite-$VERS.tar.gz $EXCLUDE sqlite-$VERS" tar czf $ORIGIN/doc/sqlite-$VERS.tar.gz $EXCLUDE sqlite-$VERS mv sqlite-$VERS sqlite cd $ORIGIN # # Build RPMS (binary) and Source RPM |
︙ | ︙ |
Changes to src/alter.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2005 February 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that used to generate VDBE code ** that implements the ALTER TABLE command. | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* ** 2005 February 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that used to generate VDBE code ** that implements the ALTER TABLE command. */ #include "sqliteInt.h" /* ** The code in this file only exists if we are not omitting the ** ALTER TABLE logic from the build. */ |
︙ | ︙ | |||
81 82 83 84 85 86 87 88 89 90 91 92 93 94 | zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", ((u8*)tname.z) - zSql, zSql, zTableName, tname.z+tname.n); sqlite3_result_text(context, zRet, -1, SQLITE_DYNAMIC); } } #ifndef SQLITE_OMIT_TRIGGER /* This function is used by SQL generated to implement the ** ALTER TABLE command. The first argument is the text of a CREATE TRIGGER ** statement. The second is a table name. The table name in the CREATE ** TRIGGER statement is replaced with the third argument and the result ** returned. This is analagous to renameTableFunc() above, except for CREATE ** TRIGGER, not CREATE INDEX and CREATE TABLE. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 79 80 81 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 | zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", ((u8*)tname.z) - zSql, zSql, zTableName, tname.z+tname.n); sqlite3_result_text(context, zRet, -1, SQLITE_DYNAMIC); } } /* ** This C function implements an SQL user function that is used by SQL code ** generated by the ALTER TABLE ... RENAME command to modify the definition ** of any foreign key constraints that use the table being renamed as the ** parent table. It is passed three arguments: ** ** 1) The complete text of the CREATE TABLE statement being modified, ** 2) The old name of the table being renamed, and ** 3) The new name of the table being renamed. ** ** It returns the new CREATE TABLE statement. For example: ** ** sqlite_rename_parent('CREATE TABLE t1(a REFERENCES t2)', 't2', 't3') ** -> 'CREATE TABLE t1(a REFERENCES t3)' */ #ifndef SQLITE_OMIT_FOREIGN_KEY static void renameParentFunc( sqlite3_context *context, int NotUsed, sqlite3_value **argv ){ sqlite3 *db = sqlite3_context_db_handle(context); char *zOutput = 0; char *zResult; unsigned char const *zInput = sqlite3_value_text(argv[0]); unsigned char const *zOld = sqlite3_value_text(argv[1]); unsigned char const *zNew = sqlite3_value_text(argv[2]); unsigned const char *z; /* Pointer to token */ int n; /* Length of token z */ int token; /* Type of token */ UNUSED_PARAMETER(NotUsed); for(z=zInput; *z; z=z+n){ n = sqlite3GetToken(z, &token); if( token==TK_REFERENCES ){ char *zParent; do { z += n; n = sqlite3GetToken(z, &token); }while( token==TK_SPACE ); zParent = sqlite3DbStrNDup(db, (const char *)z, n); if( zParent==0 ) break; sqlite3Dequote(zParent); if( 0==sqlite3StrICmp((const char *)zOld, zParent) ){ char *zOut = sqlite3MPrintf(db, "%s%.*s\"%w\"", (zOutput?zOutput:""), z-zInput, zInput, (const char *)zNew ); sqlite3DbFree(db, zOutput); zOutput = zOut; zInput = &z[n]; } sqlite3DbFree(db, zParent); } } zResult = sqlite3MPrintf(db, "%s%s", (zOutput?zOutput:""), zInput), sqlite3_result_text(context, zResult, -1, SQLITE_DYNAMIC); sqlite3DbFree(db, zOutput); } #endif #ifndef SQLITE_OMIT_TRIGGER /* This function is used by SQL generated to implement the ** ALTER TABLE command. The first argument is the text of a CREATE TRIGGER ** statement. The second is a table name. The table name in the CREATE ** TRIGGER statement is replaced with the third argument and the result ** returned. This is analagous to renameTableFunc() above, except for CREATE ** TRIGGER, not CREATE INDEX and CREATE TABLE. |
︙ | ︙ | |||
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | void sqlite3AlterFunctions(sqlite3 *db){ sqlite3CreateFunc(db, "sqlite_rename_table", 2, SQLITE_UTF8, 0, renameTableFunc, 0, 0); #ifndef SQLITE_OMIT_TRIGGER sqlite3CreateFunc(db, "sqlite_rename_trigger", 2, SQLITE_UTF8, 0, renameTriggerFunc, 0, 0); #endif } /* ** Generate the text of a WHERE expression which can be used to select all ** temporary triggers on table pTab from the sqlite_temp_master table. If ** table pTab has no temporary triggers, or is itself stored in the ** temporary database, NULL is returned. */ static char *whereTempTriggers(Parse *pParse, Table *pTab){ Trigger *pTrig; char *zWhere = 0; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < < < | < < | 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 | void sqlite3AlterFunctions(sqlite3 *db){ sqlite3CreateFunc(db, "sqlite_rename_table", 2, SQLITE_UTF8, 0, renameTableFunc, 0, 0); #ifndef SQLITE_OMIT_TRIGGER sqlite3CreateFunc(db, "sqlite_rename_trigger", 2, SQLITE_UTF8, 0, renameTriggerFunc, 0, 0); #endif #ifndef SQLITE_OMIT_FOREIGN_KEY sqlite3CreateFunc(db, "sqlite_rename_parent", 3, SQLITE_UTF8, 0, renameParentFunc, 0, 0); #endif } /* ** This function is used to create the text of expressions of the form: ** ** name=<constant1> OR name=<constant2> OR ... ** ** If argument zWhere is NULL, then a pointer string containing the text ** "name=<constant>" is returned, where <constant> is the quoted version ** of the string passed as argument zConstant. The returned buffer is ** allocated using sqlite3DbMalloc(). It is the responsibility of the ** caller to ensure that it is eventually freed. ** ** If argument zWhere is not NULL, then the string returned is ** "<where> OR name=<constant>", where <where> is the contents of zWhere. ** In this case zWhere is passed to sqlite3DbFree() before returning. ** */ static char *whereOrName(sqlite3 *db, char *zWhere, char *zConstant){ char *zNew; if( !zWhere ){ zNew = sqlite3MPrintf(db, "name=%Q", zConstant); }else{ zNew = sqlite3MPrintf(db, "%s OR name=%Q", zWhere, zConstant); sqlite3DbFree(db, zWhere); } return zNew; } #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) /* ** Generate the text of a WHERE expression which can be used to select all ** tables that have foreign key constraints that refer to table pTab (i.e. ** constraints for which pTab is the parent table) from the sqlite_master ** table. */ static char *whereForeignKeys(Parse *pParse, Table *pTab){ FKey *p; char *zWhere = 0; for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ zWhere = whereOrName(pParse->db, zWhere, p->pFrom->zName); } return zWhere; } #endif /* ** Generate the text of a WHERE expression which can be used to select all ** temporary triggers on table pTab from the sqlite_temp_master table. If ** table pTab has no temporary triggers, or is itself stored in the ** temporary database, NULL is returned. */ static char *whereTempTriggers(Parse *pParse, Table *pTab){ Trigger *pTrig; char *zWhere = 0; const Schema *pTempSchema = pParse->db->aDb[1].pSchema; /* Temp db schema */ /* If the table is not located in the temp-db (in which case NULL is ** returned, loop through the tables list of triggers. For each trigger ** that is not part of the temp-db schema, add a clause to the WHERE ** expression being built up in zWhere. */ if( pTab->pSchema!=pTempSchema ){ sqlite3 *db = pParse->db; for(pTrig=sqlite3TriggerList(pParse, pTab); pTrig; pTrig=pTrig->pNext){ if( pTrig->pSchema==pTempSchema ){ zWhere = whereOrName(db, zWhere, pTrig->zName); } } } return zWhere; } /* |
︙ | ︙ | |||
231 232 233 234 235 236 237 | assert( iDb>=0 ); #ifndef SQLITE_OMIT_TRIGGER /* Drop any table triggers from the internal schema. */ for(pTrig=sqlite3TriggerList(pParse, pTab); pTrig; pTrig=pTrig->pNext){ int iTrigDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema); assert( iTrigDb==iDb || iTrigDb==1 ); | | | | 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 | assert( iDb>=0 ); #ifndef SQLITE_OMIT_TRIGGER /* Drop any table triggers from the internal schema. */ for(pTrig=sqlite3TriggerList(pParse, pTab); pTrig; pTrig=pTrig->pNext){ int iTrigDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema); assert( iTrigDb==iDb || iTrigDb==1 ); sqlite3VdbeAddOp4(v, OP_DropTrigger, iTrigDb, 0, 0, pTrig->zName, 0); } #endif /* Drop the table and index from the internal schema. */ sqlite3VdbeAddOp4(v, OP_DropTable, iDb, 0, 0, pTab->zName, 0); /* Reload the table, index and permanent trigger schemas. */ zWhere = sqlite3MPrintf(pParse->db, "tbl_name=%Q", zName); if( !zWhere ) return; sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC); |
︙ | ︙ | |||
273 274 275 276 277 278 279 | 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; #ifndef SQLITE_OMIT_TRIGGER char *zWhere = 0; /* Where clause to locate temp triggers */ #endif | | | 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 | 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; #ifndef SQLITE_OMIT_TRIGGER char *zWhere = 0; /* Where clause to locate temp triggers */ #endif 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 = sqlite3LocateTable(pParse, 0, pSrc->a[0].zName, pSrc->a[0].zDatabase); if( !pTab ) goto exit_rename_table; |
︙ | ︙ | |||
328 329 330 331 332 333 334 | } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE if( sqlite3ViewGetColumnNames(pParse, pTab) ){ goto exit_rename_table; } | | > | > > | | | > > > > > > > > > > > > > > > > | 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 | } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE if( sqlite3ViewGetColumnNames(pParse, pTab) ){ goto exit_rename_table; } if( IsVirtual(pTab) ){ pVTab = sqlite3GetVTable(db, pTab); if( pVTab->pVtab->pModule->xRename==0 ){ pVTab = 0; } } #endif /* Begin a transaction and code the VerifyCookie for database iDb. ** Then modify the schema cookie (since the ALTER TABLE modifies the ** schema). Open a statement transaction if the table is a virtual ** table. */ v = sqlite3GetVdbe(pParse); if( v==0 ){ goto exit_rename_table; } sqlite3BeginWriteOperation(pParse, pVTab!=0, iDb); sqlite3ChangeCookie(pParse, iDb); /* 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; sqlite3VdbeAddOp4(v, OP_String8, 0, i, 0, zName, 0); sqlite3VdbeAddOp4(v, OP_VRename, i, 0, 0,(const char*)pVTab, P4_VTAB); sqlite3MayAbort(pParse); } #endif /* figure out how many UTF-8 characters are in zName */ zTabName = pTab->zName; nTabName = sqlite3Utf8CharLen(zTabName, -1); #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) if( db->flags&SQLITE_ForeignKeys ){ /* If foreign-key support is enabled, rewrite the CREATE TABLE ** statements corresponding to all child tables of foreign key constraints ** for which the renamed table is the parent table. */ if( (zWhere=whereForeignKeys(pParse, pTab))!=0 ){ sqlite3NestedParse(pParse, "UPDATE sqlite_master SET " "sql = sqlite_rename_parent(sql, %Q, %Q) " "WHERE %s;", zTabName, zName, zWhere); sqlite3DbFree(db, zWhere); } } #endif /* Modify the sqlite_master table to use the new table name. */ sqlite3NestedParse(pParse, "UPDATE %Q.%s SET " #ifdef SQLITE_OMIT_TRIGGER "sql = sqlite_rename_table(sql, %Q), " #else |
︙ | ︙ | |||
410 411 412 413 414 415 416 417 418 419 420 421 422 423 | if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){ sqlite3NestedParse(pParse, "UPDATE sqlite_temp_master SET " "sql = sqlite_rename_trigger(sql, %Q), " "tbl_name = %Q " "WHERE %s;", zName, zName, zWhere); sqlite3DbFree(db, zWhere); } #endif /* Drop and reload the internal table schema. */ reloadTableSchema(pParse, pTab, zName); exit_rename_table: | > > > > > > > > > > > > | 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 | if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){ sqlite3NestedParse(pParse, "UPDATE sqlite_temp_master SET " "sql = sqlite_rename_trigger(sql, %Q), " "tbl_name = %Q " "WHERE %s;", zName, zName, zWhere); sqlite3DbFree(db, zWhere); } #endif #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) if( db->flags&SQLITE_ForeignKeys ){ FKey *p; for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ Table *pFrom = p->pFrom; if( pFrom!=pTab ){ reloadTableSchema(pParse, p->pFrom, pFrom->zName); } } } #endif /* Drop and reload the internal table schema. */ reloadTableSchema(pParse, pTab, zName); exit_rename_table: |
︙ | ︙ | |||
506 507 508 509 510 511 512 513 514 515 516 517 518 519 | if( pCol->isPrimKey ){ sqlite3ErrorMsg(pParse, "Cannot add a PRIMARY KEY column"); return; } if( pNew->pIndex ){ sqlite3ErrorMsg(pParse, "Cannot add a UNIQUE column"); return; } if( pCol->notNull && !pDflt ){ sqlite3ErrorMsg(pParse, "Cannot add a NOT NULL column with default value NULL"); return; } | > > > > > | 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 | if( pCol->isPrimKey ){ 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; } |
︙ | ︙ |
Changes to src/analyze.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 2005 July 8 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code associated with the ANALYZE command. | < < | > > | > | > > | > > > > > > > > > > > > > > > > > < < < < > > > > | | | | | | | < | | | | > | | < < < < | > > > > > | | < | | | < < < < < < < > > > | | | > > | | < | | | | | | > > > > > > > > > > > > > > > | | | > | < | | < < | > | < | < | > > > > > | > | > > > | > > > | > > > > > > > > > > > > > | > > | < > | | | | > | > | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | < < < | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 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 | /* ** 2005 July 8 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code associated with the ANALYZE command. */ #ifndef SQLITE_OMIT_ANALYZE #include "sqliteInt.h" /* ** This routine generates code that opens the sqlite_stat1 table for ** writing with cursor iStatCur. If the library was built with the ** SQLITE_ENABLE_STAT2 macro defined, then the sqlite_stat2 table is ** opened for writing using cursor (iStatCur+1) ** ** If the sqlite_stat1 tables does not previously exist, it is created. ** Similarly, if the sqlite_stat2 table does not exist and the library ** is compiled with SQLITE_ENABLE_STAT2 defined, it is created. ** ** Argument zWhere may be a pointer to a buffer containing a table name, ** or it may be a NULL pointer. If it is not NULL, then all entries in ** the sqlite_stat1 and (if applicable) sqlite_stat2 tables associated ** with the named table are deleted. If zWhere==0, then code is generated ** to delete all stat table entries. */ static void openStatTable( Parse *pParse, /* Parsing context */ int iDb, /* The database we are looking in */ int iStatCur, /* Open the sqlite_stat1 table on this cursor */ const char *zWhere /* Delete entries associated with this table */ ){ static struct { const char *zName; const char *zCols; } aTable[] = { { "sqlite_stat1", "tbl,idx,stat" }, #ifdef SQLITE_ENABLE_STAT2 { "sqlite_stat2", "tbl,idx,sampleno,sample" }, #endif }; int aRoot[] = {0, 0}; u8 aCreateTbl[] = {0, 0}; int i; sqlite3 *db = pParse->db; Db *pDb; Vdbe *v = sqlite3GetVdbe(pParse); if( v==0 ) return; assert( sqlite3BtreeHoldsAllMutexes(db) ); assert( sqlite3VdbeDb(v)==db ); pDb = &db->aDb[iDb]; for(i=0; i<ArraySize(aTable); i++){ const char *zTab = aTable[i].zName; Table *pStat; if( (pStat = sqlite3FindTable(db, zTab, pDb->zName))==0 ){ /* The sqlite_stat[12] 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->zName, zTab, aTable[i].zCols ); aRoot[i] = pParse->regRoot; aCreateTbl[i] = 1; }else{ /* The table already exists. If zWhere is not NULL, delete all entries ** associated with the table zWhere. If zWhere is NULL, delete the ** entire contents of the table. */ aRoot[i] = pStat->tnum; sqlite3TableLock(pParse, iDb, aRoot[i], 1, zTab); if( zWhere ){ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE tbl=%Q", pDb->zName, zTab, zWhere ); }else{ /* The sqlite_stat[12] table already exists. Delete all rows. */ sqlite3VdbeAddOp2(v, OP_Clear, aRoot[i], iDb); } } } /* Open the sqlite_stat[12] tables for writing. */ for(i=0; i<ArraySize(aTable); i++){ sqlite3VdbeAddOp3(v, OP_OpenWrite, iStatCur+i, aRoot[i], iDb); sqlite3VdbeChangeP4(v, -1, (char *)3, P4_INT32); sqlite3VdbeChangeP5(v, aCreateTbl[i]); } } /* ** Generate code to do an analysis of all indices associated with ** a single table. */ static void analyzeOneTable( Parse *pParse, /* Parser context */ Table *pTab, /* Table whose indices are to be analyzed */ int iStatCur, /* Index of VdbeCursor that writes the sqlite_stat1 table */ int iMem /* Available memory locations begin here */ ){ sqlite3 *db = pParse->db; /* Database handle */ Index *pIdx; /* An index to being analyzed */ int iIdxCur; /* Cursor open on index being analyzed */ Vdbe *v; /* The virtual machine being built up */ int i; /* Loop counter */ int topOfLoop; /* The top of the loop */ int endOfLoop; /* The end of the loop */ int addr; /* The address of an instruction */ int iDb; /* Index of database containing pTab */ int regTabname = iMem++; /* Register containing table name */ int regIdxname = iMem++; /* Register containing index name */ int regSampleno = iMem++; /* Register containing next sample number */ int regCol = iMem++; /* Content of a column analyzed table */ int regRec = iMem++; /* Register holding completed record */ int regTemp = iMem++; /* Temporary use register */ int regRowid = iMem++; /* Rowid for the inserted record */ #ifdef SQLITE_ENABLE_STAT2 int regTemp2 = iMem++; /* Temporary use register */ int regSamplerecno = iMem++; /* Index of next sample to record */ int regRecno = iMem++; /* Current sample index */ int regLast = iMem++; /* Index of last sample to record */ int regFirst = iMem++; /* Index of first sample to record */ #endif v = sqlite3GetVdbe(pParse); if( v==0 || NEVER(pTab==0) || pTab->pIndex==0 ){ /* Do no analysis for tables that have no indices */ return; } assert( sqlite3BtreeHoldsAllMutexes(db) ); iDb = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iDb>=0 ); #ifndef SQLITE_OMIT_AUTHORIZATION if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab->zName, 0, db->aDb[iDb].zName ) ){ return; } #endif /* Establish a read-lock on the table at the shared-cache level. */ sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); iIdxCur = pParse->nTab++; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int nCol = pIdx->nColumn; KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); if( iMem+1+(nCol*2)>pParse->nMem ){ pParse->nMem = iMem+1+(nCol*2); } /* Open a cursor to the index to be analyzed. */ assert( iDb==sqlite3SchemaToIndex(db, pIdx->pSchema) ); sqlite3VdbeAddOp4(v, OP_OpenRead, iIdxCur, pIdx->tnum, iDb, (char *)pKey, P4_KEYINFO_HANDOFF); VdbeComment((v, "%s", pIdx->zName)); /* Populate the registers containing the table and index names. */ if( pTab->pIndex==pIdx ){ sqlite3VdbeAddOp4(v, OP_String8, 0, regTabname, 0, pTab->zName, 0); } sqlite3VdbeAddOp4(v, OP_String8, 0, regIdxname, 0, pIdx->zName, 0); #ifdef SQLITE_ENABLE_STAT2 /* If this iteration of the loop is generating code to analyze the ** first index in the pTab->pIndex list, then register regLast has ** not been populated. In this case populate it now. */ if( pTab->pIndex==pIdx ){ sqlite3VdbeAddOp2(v, OP_Integer, SQLITE_INDEX_SAMPLES, regSamplerecno); sqlite3VdbeAddOp2(v, OP_Integer, SQLITE_INDEX_SAMPLES*2-1, regTemp); sqlite3VdbeAddOp2(v, OP_Integer, SQLITE_INDEX_SAMPLES*2, regTemp2); sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regLast); sqlite3VdbeAddOp2(v, OP_Null, 0, regFirst); addr = sqlite3VdbeAddOp3(v, OP_Lt, regSamplerecno, 0, regLast); sqlite3VdbeAddOp3(v, OP_Divide, regTemp2, regLast, regFirst); sqlite3VdbeAddOp3(v, OP_Multiply, regLast, regTemp, regLast); sqlite3VdbeAddOp2(v, OP_AddImm, regLast, SQLITE_INDEX_SAMPLES*2-2); sqlite3VdbeAddOp3(v, OP_Divide, regTemp2, regLast, regLast); sqlite3VdbeJumpHere(v, addr); } /* Zero the regSampleno and regRecno registers. */ sqlite3VdbeAddOp2(v, OP_Integer, 0, regSampleno); sqlite3VdbeAddOp2(v, OP_Integer, 0, regRecno); sqlite3VdbeAddOp2(v, OP_Copy, regFirst, regSamplerecno); #endif /* The block of memory cells initialized here is used as follows. ** ** iMem: ** The total number of rows in the table. ** ** iMem+1 .. iMem+nCol: ** Number of distinct entries in index considering the ** left-most N columns only, where N is between 1 and nCol, ** inclusive. ** ** iMem+nCol+1 .. Mem+2*nCol: ** Previous value of indexed columns, from left to right. ** ** Cells iMem through iMem+nCol are initialized to 0. The others are ** initialized to contain an SQL NULL. */ for(i=0; i<=nCol; i++){ sqlite3VdbeAddOp2(v, OP_Integer, 0, iMem+i); } for(i=0; i<nCol; i++){ sqlite3VdbeAddOp2(v, OP_Null, 0, iMem+nCol+i+1); } /* Start the analysis loop. This loop runs through all the entries in ** the index b-tree. */ endOfLoop = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp2(v, OP_Rewind, iIdxCur, endOfLoop); topOfLoop = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp2(v, OP_AddImm, iMem, 1); for(i=0; i<nCol; i++){ sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regCol); #ifdef SQLITE_ENABLE_STAT2 if( i==0 ){ /* Check if the record that cursor iIdxCur points to contains a ** value that should be stored in the sqlite_stat2 table. If so, ** store it. */ int ne = sqlite3VdbeAddOp3(v, OP_Ne, regRecno, 0, regSamplerecno); assert( regTabname+1==regIdxname && regTabname+2==regSampleno && regTabname+3==regCol ); sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL); sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 4, regRec, "aaab", 0); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur+1, regRowid); sqlite3VdbeAddOp3(v, OP_Insert, iStatCur+1, regRec, regRowid); /* Calculate new values for regSamplerecno and regSampleno. ** ** sampleno = sampleno + 1 ** samplerecno = samplerecno+(remaining records)/(remaining samples) */ sqlite3VdbeAddOp2(v, OP_AddImm, regSampleno, 1); sqlite3VdbeAddOp3(v, OP_Subtract, regRecno, regLast, regTemp); sqlite3VdbeAddOp2(v, OP_AddImm, regTemp, -1); sqlite3VdbeAddOp2(v, OP_Integer, SQLITE_INDEX_SAMPLES, regTemp2); sqlite3VdbeAddOp3(v, OP_Subtract, regSampleno, regTemp2, regTemp2); sqlite3VdbeAddOp3(v, OP_Divide, regTemp2, regTemp, regTemp); sqlite3VdbeAddOp3(v, OP_Add, regSamplerecno, regTemp, regSamplerecno); sqlite3VdbeJumpHere(v, ne); sqlite3VdbeAddOp2(v, OP_AddImm, regRecno, 1); } #endif sqlite3VdbeAddOp3(v, OP_Ne, regCol, 0, iMem+nCol+i+1); /**** TODO: add collating sequence *****/ sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL); } if( db->mallocFailed ){ /* If a malloc failure has occurred, then the result of the expression ** passed as the second argument to the call to sqlite3VdbeJumpHere() ** below may be negative. Which causes an assert() to fail (or an ** out-of-bounds write if SQLITE_DEBUG is not defined). */ return; } sqlite3VdbeAddOp2(v, OP_Goto, 0, endOfLoop); for(i=0; i<nCol; i++){ sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-(nCol*2)); sqlite3VdbeAddOp2(v, OP_AddImm, iMem+i+1, 1); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, iMem+nCol+i+1); } /* End of the analysis loop. */ sqlite3VdbeResolveLabel(v, endOfLoop); sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, topOfLoop); sqlite3VdbeAddOp1(v, OP_Close, iIdxCur); /* Store the results in sqlite_stat1. ** ** The result is a single row of the sqlite_stat1 table. The first ** two columns are the names of the table and index. The third column ** is a string composed of a list of integer statistics about 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 ** column of the table. This additional integer is a guess of how many ** rows of the table the index will select. If D is the count of distinct ** values and K is the total number of rows, then the integer is computed ** as: ** ** I = (K+D-1)/D ** ** If K==0 then no entry is made into the sqlite_stat1 table. ** If K>0 then it is always the case the D>0 so division by zero ** is never possible. */ addr = sqlite3VdbeAddOp1(v, OP_IfNot, iMem); sqlite3VdbeAddOp2(v, OP_SCopy, iMem, regSampleno); for(i=0; i<nCol; i++){ sqlite3VdbeAddOp4(v, OP_String8, 0, regTemp, 0, " ", 0); sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regSampleno, regSampleno); sqlite3VdbeAddOp3(v, OP_Add, iMem, iMem+i+1, regTemp); sqlite3VdbeAddOp2(v, OP_AddImm, regTemp, -1); sqlite3VdbeAddOp3(v, OP_Divide, iMem+i+1, regTemp, regTemp); sqlite3VdbeAddOp1(v, OP_ToInt, regTemp); sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regSampleno, regSampleno); } sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regRec, "aaa", 0); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regRowid); sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regRowid); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); sqlite3VdbeJumpHere(v, addr); } } |
︙ | ︙ | |||
241 242 243 244 245 246 247 | sqlite3 *db = pParse->db; Schema *pSchema = db->aDb[iDb].pSchema; /* Schema of database iDb */ HashElem *k; int iStatCur; int iMem; sqlite3BeginWriteOperation(pParse, 0, iDb); | | > | 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 | sqlite3 *db = pParse->db; Schema *pSchema = db->aDb[iDb].pSchema; /* Schema of database iDb */ HashElem *k; int iStatCur; int iMem; sqlite3BeginWriteOperation(pParse, 0, iDb); iStatCur = pParse->nTab; pParse->nTab += 2; openStatTable(pParse, iDb, iStatCur, 0); iMem = pParse->nMem+1; for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ Table *pTab = (Table*)sqliteHashData(k); analyzeOneTable(pParse, pTab, iStatCur, iMem); } loadAnalysis(pParse, iDb); |
︙ | ︙ | |||
263 264 265 266 267 268 269 | int iDb; int iStatCur; assert( pTab!=0 ); assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); sqlite3BeginWriteOperation(pParse, 0, iDb); | | > | 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 | int iDb; int iStatCur; assert( pTab!=0 ); assert( sqlite3BtreeHoldsAllMutexes(pParse->db) ); iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); sqlite3BeginWriteOperation(pParse, 0, iDb); iStatCur = pParse->nTab; pParse->nTab += 2; openStatTable(pParse, iDb, iStatCur, pTab->zName); analyzeOneTable(pParse, pTab, iStatCur, pParse->nMem+1); loadAnalysis(pParse, iDb); } /* ** Generate code for the ANALYZE command. The parser calls this routine |
︙ | ︙ | |||
383 384 385 386 387 388 389 | pIndex->aiRowEst[i] = v; if( *z==' ' ) z++; } return 0; } /* | > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > | | < | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | 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 | pIndex->aiRowEst[i] = v; if( *z==' ' ) z++; } return 0; } /* ** If the Index.aSample variable is not NULL, delete the aSample[] array ** and its contents. */ void sqlite3DeleteIndexSamples(Index *pIdx){ #ifdef SQLITE_ENABLE_STAT2 if( pIdx->aSample ){ int j; sqlite3 *dbMem = pIdx->pTable->dbMem; for(j=0; j<SQLITE_INDEX_SAMPLES; j++){ IndexSample *p = &pIdx->aSample[j]; if( p->eType==SQLITE_TEXT || p->eType==SQLITE_BLOB ){ sqlite3DbFree(pIdx->pTable->dbMem, p->u.z); } } sqlite3DbFree(dbMem, pIdx->aSample); pIdx->aSample = 0; } #else UNUSED_PARAMETER(pIdx); #endif } /* ** Load the content of the sqlite_stat1 and sqlite_stat2 tables. The ** contents of sqlite_stat1 are used to populate the Index.aiRowEst[] ** arrays. The contents of sqlite_stat2 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_STAT2 was defined ** during compilation and the sqlite_stat2 table is present, no data is ** read from it. ** ** If SQLITE_ENABLE_STAT2 was defined during compilation and the ** sqlite_stat2 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; assert( iDb>=0 && iDb<db->nDb ); assert( db->aDb[iDb].pBt!=0 ); assert( sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) ); /* Clear any prior statistics */ for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){ Index *pIdx = sqliteHashData(i); sqlite3DefaultRowEst(pIdx); sqlite3DeleteIndexSamples(pIdx); } /* Check to make sure the sqlite_stat1 table exists */ sInfo.db = db; sInfo.zDatabase = db->aDb[iDb].zName; if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)==0 ){ return SQLITE_ERROR; } /* Load new statistics out of the sqlite_stat1 table */ zSql = sqlite3MPrintf(db, "SELECT idx, stat FROM %Q.sqlite_stat1", sInfo.zDatabase); if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ (void)sqlite3SafetyOff(db); rc = sqlite3_exec(db, zSql, analysisLoader, &sInfo, 0); (void)sqlite3SafetyOn(db); sqlite3DbFree(db, zSql); } /* Load the statistics from the sqlite_stat2 table. */ #ifdef SQLITE_ENABLE_STAT2 if( rc==SQLITE_OK && !sqlite3FindTable(db, "sqlite_stat2", sInfo.zDatabase) ){ rc = SQLITE_ERROR; } if( rc==SQLITE_OK ){ sqlite3_stmt *pStmt = 0; zSql = sqlite3MPrintf(db, "SELECT idx,sampleno,sample FROM %Q.sqlite_stat2", sInfo.zDatabase); if( !zSql ){ rc = SQLITE_NOMEM; }else{ (void)sqlite3SafetyOff(db); rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); (void)sqlite3SafetyOn(db); sqlite3DbFree(db, zSql); } if( rc==SQLITE_OK ){ (void)sqlite3SafetyOff(db); while( sqlite3_step(pStmt)==SQLITE_ROW ){ char *zIndex = (char *)sqlite3_column_text(pStmt, 0); Index *pIdx = sqlite3FindIndex(db, zIndex, sInfo.zDatabase); if( pIdx ){ int iSample = sqlite3_column_int(pStmt, 1); sqlite3 *dbMem = pIdx->pTable->dbMem; assert( dbMem==db || dbMem==0 ); if( iSample<SQLITE_INDEX_SAMPLES && iSample>=0 ){ int eType = sqlite3_column_type(pStmt, 2); if( pIdx->aSample==0 ){ static const int sz = sizeof(IndexSample)*SQLITE_INDEX_SAMPLES; pIdx->aSample = (IndexSample *)sqlite3DbMallocZero(dbMem, sz); if( pIdx->aSample==0 ){ db->mallocFailed = 1; break; } } assert( pIdx->aSample ); { IndexSample *pSample = &pIdx->aSample[iSample]; pSample->eType = (u8)eType; if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ pSample->u.r = sqlite3_column_double(pStmt, 2); }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){ const char *z = (const char *)( (eType==SQLITE_BLOB) ? sqlite3_column_blob(pStmt, 2): sqlite3_column_text(pStmt, 2) ); int n = sqlite3_column_bytes(pStmt, 2); if( n>24 ){ n = 24; } pSample->nByte = (u8)n; pSample->u.z = sqlite3DbMallocRaw(dbMem, n); if( pSample->u.z ){ memcpy(pSample->u.z, z, n); }else{ db->mallocFailed = 1; break; } } } } } } rc = sqlite3_finalize(pStmt); (void)sqlite3SafetyOn(db); } } #endif if( rc==SQLITE_NOMEM ){ db->mallocFailed = 1; } return rc; } #endif /* SQLITE_OMIT_ANALYZE */ |
Changes to src/attach.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 2003 April 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 contains code used to implement the ATTACH and DETACH commands. | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2003 April 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 contains code used to implement the ATTACH and DETACH commands. */ #include "sqliteInt.h" #ifndef SQLITE_OMIT_ATTACH /* ** Resolve an expression that was part of an ATTACH or DETACH statement. This ** is slightly different from resolving a normal SQL expression, because simple |
︙ | ︙ | |||
147 148 149 150 151 152 153 | sqlite3PagerLockingMode(pPager, db->dfltLockMode); sqlite3PagerJournalMode(pPager, db->dfltJournalMode); } aNew->zName = sqlite3DbStrDup(db, zName); aNew->safety_level = 3; #if SQLITE_HAS_CODEC | < > | | | 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 | sqlite3PagerLockingMode(pPager, db->dfltLockMode); sqlite3PagerJournalMode(pPager, db->dfltJournalMode); } aNew->zName = sqlite3DbStrDup(db, zName); aNew->safety_level = 3; #if 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 the main database */ sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); break; } } #endif /* 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 |
︙ | ︙ |
Changes to src/auth.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to implement the sqlite3_set_authorizer() ** API. This facility is an optional feature of the library. Embedded ** systems that do not need this facility may omit it by recompiling ** the library with -DSQLITE_OMIT_AUTHORIZATION=1 | < < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to implement the sqlite3_set_authorizer() ** API. This facility is an optional feature of the library. Embedded ** systems that do not need this facility may omit it by recompiling ** the library with -DSQLITE_OMIT_AUTHORIZATION=1 */ #include "sqliteInt.h" /* ** All of the code in this file may be omitted by defining a single ** macro. */ |
︙ | ︙ | |||
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | ** Write an error message into pParse->zErrMsg that explains that the ** user-supplied authorization function returned an illegal value. */ static void sqliteAuthBadReturnCode(Parse *pParse){ sqlite3ErrorMsg(pParse, "authorizer malfunction"); pParse->rc = SQLITE_ERROR; } /* ** The pExpr should be a TK_COLUMN expression. The table referred to ** is in pTabList or else it is the NEW or OLD table of a trigger. ** Check to see if it is OK to read this particular column. ** ** If the auth function returns SQLITE_IGNORE, change the TK_COLUMN ** instruction into a TK_NULL. If the auth function returns SQLITE_DENY, ** then generate an error. */ 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; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < > < > > > > > | | < < | | < < < < < < < | | > > | > | | < | < < < < < < < < < < < < | 84 85 86 87 88 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 | ** Write an error message into pParse->zErrMsg that explains that the ** user-supplied authorization function returned an illegal value. */ static void sqliteAuthBadReturnCode(Parse *pParse){ sqlite3ErrorMsg(pParse, "authorizer malfunction"); pParse->rc = SQLITE_ERROR; } /* ** Invoke the authorization callback for permission to read column zCol from ** table zTab in database zDb. This function assumes that an authorization ** callback has been registered (i.e. that sqlite3.xAuth is not NULL). ** ** If SQLITE_IGNORE is returned and pExpr is not NULL, then pExpr is changed ** to an SQL NULL expression. Otherwise, if pExpr is NULL, then SQLITE_IGNORE ** is treated as SQLITE_DENY. In this case an error is left in pParse. */ int sqlite3AuthReadCol( Parse *pParse, /* The parser context */ const char *zTab, /* Table name */ const char *zCol, /* Column name */ int iDb /* Index of containing database. */ ){ sqlite3 *db = pParse->db; /* Database handle */ char *zDb = db->aDb[iDb].zName; /* Name of attached database */ int rc; /* Auth callback return code */ rc = db->xAuth(db->pAuthArg, SQLITE_READ, zTab,zCol,zDb,pParse->zAuthContext); if( rc==SQLITE_DENY ){ if( db->nDb>2 || iDb!=0 ){ sqlite3ErrorMsg(pParse, "access to %s.%s.%s is prohibited",zDb,zTab,zCol); }else{ sqlite3ErrorMsg(pParse, "access to %s.%s is prohibited", zTab, zCol); } pParse->rc = SQLITE_AUTH; }else if( rc!=SQLITE_IGNORE && rc!=SQLITE_OK ){ sqliteAuthBadReturnCode(pParse); } return rc; } /* ** The pExpr should be a TK_COLUMN expression. The table referred to ** is in pTabList or else it is the NEW or OLD table of a trigger. ** Check to see if it is OK to read this particular column. ** ** If the auth function returns SQLITE_IGNORE, change the TK_COLUMN ** instruction into a TK_NULL. If the auth function returns SQLITE_DENY, ** then generate an error. */ 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 */ 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; } assert( pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER ); 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 ** either SQLITE_OK (zero) or SQLITE_IGNORE or SQLITE_DENY. If SQLITE_DENY ** is returned, then the error count and error message in pParse are |
︙ | ︙ |
Changes to src/backup.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2009 January 28 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the implementation of the sqlite3_backup_XXX() ** API functions and the related features. | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* ** 2009 January 28 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the implementation of the sqlite3_backup_XXX() ** API functions and the related features. */ #include "sqliteInt.h" #include "btreeInt.h" /* Macro to find the minimum of two numeric values. */ #ifndef MIN |
︙ | ︙ | |||
314 315 316 317 318 319 320 | } /* Lock the destination database, if it is not locked already. */ if( SQLITE_OK==rc && p->bDestLocked==0 && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2)) ){ p->bDestLocked = 1; | | | 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 | } /* Lock the destination database, if it is not locked already. */ if( SQLITE_OK==rc && p->bDestLocked==0 && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2)) ){ p->bDestLocked = 1; sqlite3BtreeGetMeta(p->pDest, BTREE_SCHEMA_VERSION, &p->iDestSchema); } /* 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) ){ |
︙ | ︙ | |||
354 355 356 357 358 359 360 | if( p->iNext>(Pgno)nSrcPage ){ rc = SQLITE_DONE; }else if( !p->isAttached ){ attachBackupObject(p); } } | > > > > > | > > < < < < < < | 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 | if( p->iNext>(Pgno)nSrcPage ){ rc = SQLITE_DONE; }else if( !p->isAttached ){ attachBackupObject(p); } } /* Update the schema version field in the destination database. This ** is to make sure that the schema-version really does change in ** the case where the source and destination databases have the ** same schema version. */ if( rc==SQLITE_DONE && (rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1))==SQLITE_OK ){ const int nSrcPagesize = sqlite3BtreeGetPageSize(p->pSrc); const int nDestPagesize = sqlite3BtreeGetPageSize(p->pDest); int nDestTruncate; if( p->pDestDb ){ sqlite3ResetInternalSchema(p->pDestDb, 0); } /* Set nDestTruncate to the final number of pages in the destination ** database. The complication here is that the destination page ** size may be different to the source page size. |
︙ | ︙ |
Changes to src/bitvec.c.
︙ | ︙ | |||
29 30 31 32 33 34 35 | ** Test operations are about 100 times more common that set operations. ** Clear operations are exceedingly rare. There are usually between ** 5 and 500 set operations per Bitvec object, though the number of sets can ** sometimes grow into tens of thousands or larger. The size of the ** Bitvec object is the number of pages in the database file at the ** start of a transaction, and is thus usually less than a few thousand, ** but can be as large as 2 billion for a really big database. | < < | | 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | ** Test operations are about 100 times more common that set operations. ** Clear operations are exceedingly rare. There are usually between ** 5 and 500 set operations per Bitvec object, though the number of sets can ** sometimes grow into tens of thousands or larger. The size of the ** Bitvec object is the number of pages in the database file at the ** start of a transaction, and is thus usually less than a few thousand, ** but can be as large as 2 billion for a really big database. */ #include "sqliteInt.h" /* Size of the Bitvec structure in bytes. */ #define BITVEC_SZ (sizeof(void*)*128) /* 512 on 32bit. 1024 on 64bit */ /* Round the union size down to the nearest pointer boundary, since that's how ** it will be aligned within the Bitvec struct. */ #define BITVEC_USIZE (((BITVEC_SZ-(3*sizeof(u32)))/sizeof(Bitvec*))*sizeof(Bitvec*)) /* Type of the array "element" for the bitmap representation. ** Should be a power of 2, and ideally, evenly divide into BITVEC_USIZE. |
︙ | ︙ | |||
142 143 144 145 146 147 148 | } if( p->iSize<=BITVEC_NBIT ){ return (p->u.aBitmap[i/BITVEC_SZELEM] & (1<<(i&(BITVEC_SZELEM-1))))!=0; } else{ u32 h = BITVEC_HASH(i++); while( p->u.aHash[h] ){ if( p->u.aHash[h]==i ) return 1; | < | | | 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 | } if( p->iSize<=BITVEC_NBIT ){ return (p->u.aBitmap[i/BITVEC_SZELEM] & (1<<(i&(BITVEC_SZELEM-1))))!=0; } else{ u32 h = BITVEC_HASH(i++); while( p->u.aHash[h] ){ if( p->u.aHash[h]==i ) return 1; h = (h+1) % BITVEC_NINT; } return 0; } } /* ** Set the i-th bit. Return 0 on success and an error code if ** anything goes wrong. ** ** This routine might cause sub-bitmaps to be allocated. Failing ** to get the memory needed to hold the sub-bitmap is the only ** that can go wrong with an insert, assuming p and i are valid. ** ** The calling function must ensure that p is a valid Bitvec object ** and that the value for "i" is within range of the Bitvec object. ** Otherwise the behavior is undefined. */ int sqlite3BitvecSet(Bitvec *p, u32 i){ u32 h; if( p==0 ) return SQLITE_OK; assert( i>0 ); assert( i<=p->iSize ); i--; while((p->iSize > BITVEC_NBIT) && p->iDivisor) { u32 bin = i/p->iDivisor; i = i%p->iDivisor; if( p->u.apSub[bin]==0 ){ |
︙ | ︙ | |||
233 234 235 236 237 238 239 | /* ** Clear the i-th bit. ** ** pBuf must be a pointer to at least BITVEC_SZ bytes of temporary storage ** that BitvecClear can use to rebuilt its hash table. */ void sqlite3BitvecClear(Bitvec *p, u32 i, void *pBuf){ | | | 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 | /* ** Clear the i-th bit. ** ** pBuf must be a pointer to at least BITVEC_SZ bytes of temporary storage ** that BitvecClear can use to rebuilt its hash table. */ void sqlite3BitvecClear(Bitvec *p, u32 i, void *pBuf){ if( p==0 ) return; assert( i>0 ); i--; while( p->iDivisor ){ u32 bin = i/p->iDivisor; i = i%p->iDivisor; p = p->u.apSub[bin]; if (!p) { |
︙ | ︙ | |||
344 345 346 347 348 349 350 351 352 353 354 355 356 357 | ** bits to act as the reference */ pBitvec = sqlite3BitvecCreate( sz ); pV = sqlite3_malloc( (sz+7)/8 + 1 ); pTmpSpace = sqlite3_malloc(BITVEC_SZ); if( pBitvec==0 || pV==0 || pTmpSpace==0 ) goto bitvec_end; memset(pV, 0, (sz+7)/8 + 1); /* Run the program */ pc = 0; while( (op = aOp[pc])!=0 ){ switch( op ){ case 1: case 2: case 5: { | > > > > | 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 | ** bits to act as the reference */ pBitvec = sqlite3BitvecCreate( sz ); pV = sqlite3_malloc( (sz+7)/8 + 1 ); pTmpSpace = sqlite3_malloc(BITVEC_SZ); if( pBitvec==0 || pV==0 || pTmpSpace==0 ) goto bitvec_end; memset(pV, 0, (sz+7)/8 + 1); /* 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: { |
︙ | ︙ |
Changes to src/btmutex.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 2007 August 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. ** ************************************************************************* ** | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2007 August 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 code used to implement mutexes on Btree objects. ** This code really belongs in btree.c. But btree.c is getting too ** big and we want to break it down some. This packaged seemed like ** a good breakout. */ #include "btreeInt.h" #ifndef SQLITE_OMIT_SHARED_CACHE |
︙ | ︙ | |||
193 194 195 196 197 198 199 | p = db->aDb[i].pBt; assert( !p || (p->locked==0 && p->sharable) || p->pBt->db==p->db ); if( p && p->sharable ){ p->wantToLock++; if( !p->locked ){ assert( p->wantToLock==1 ); while( p->pPrev ) p = p->pPrev; | > > | | 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 | p = db->aDb[i].pBt; assert( !p || (p->locked==0 && p->sharable) || p->pBt->db==p->db ); if( p && p->sharable ){ p->wantToLock++; if( !p->locked ){ assert( p->wantToLock==1 ); while( p->pPrev ) p = p->pPrev; /* Reason for ALWAYS: There must be at least on unlocked Btree in ** the chain. Otherwise the !p->locked test above would have failed */ while( p->locked && ALWAYS(p->pNext) ) p = p->pNext; for(pLater = p->pNext; pLater; pLater=pLater->pNext){ if( pLater->locked ){ unlockBtreeMutex(pLater); } } while( p ){ lockBtreeMutex(p); |
︙ | ︙ | |||
304 305 306 307 308 309 310 311 | /* Some basic sanity checking */ assert( i==0 || pArray->aBtree[i-1]->pBt<p->pBt ); assert( !p->locked || p->wantToLock>0 ); /* We should already hold a lock on the database connection */ assert( sqlite3_mutex_held(p->db->mutex) ); p->wantToLock++; | > > > > | | | | 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 | /* Some basic sanity checking */ assert( i==0 || pArray->aBtree[i-1]->pBt<p->pBt ); assert( !p->locked || p->wantToLock>0 ); /* We should already hold a lock on the database connection */ assert( sqlite3_mutex_held(p->db->mutex) ); /* The Btree is sharable because only sharable Btrees are entered ** into the array in the first place. */ assert( p->sharable ); p->wantToLock++; if( !p->locked ){ lockBtreeMutex(p); } } } /* ** Leave the mutex of every btree in the group. */ void sqlite3BtreeMutexArrayLeave(BtreeMutexArray *pArray){ int i; for(i=0; i<pArray->nMutex; i++){ Btree *p = pArray->aBtree[i]; /* Some basic sanity checking */ assert( i==0 || pArray->aBtree[i-1]->pBt<p->pBt ); assert( p->locked ); assert( p->wantToLock>0 ); /* We should already hold a lock on the database connection */ assert( sqlite3_mutex_held(p->db->mutex) ); p->wantToLock--; if( p->wantToLock==0 ){ unlockBtreeMutex(p); } } } #else void sqlite3BtreeEnter(Btree *p){ |
︙ | ︙ |
Changes to src/btree.c.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2004 April 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 18 | /* ** 2004 April 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 a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. ** Including a description of file format and an overview of operation. */ #include "btreeInt.h" /* |
︙ | ︙ | |||
63 64 65 66 67 68 69 | int sqlite3_enable_shared_cache(int enable){ sqlite3GlobalConfig.sharedCacheEnabled = enable; return SQLITE_OK; } #endif | < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | < < < < < < < < < < < < < < < < < < < < < | | | | | | | | | | | | | | | | | | | < > > > > > > > > > | | < < < < | < | | | < < < < < | < < < < | > > > > | 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 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 | int sqlite3_enable_shared_cache(int enable){ sqlite3GlobalConfig.sharedCacheEnabled = enable; return SQLITE_OK; } #endif #ifdef SQLITE_OMIT_SHARED_CACHE /* ** The functions querySharedCacheTableLock(), setSharedCacheTableLock(), ** and clearAllSharedCacheTableLocks() ** manipulate entries in the BtShared.pLock linked list used to store ** shared-cache table level locks. If the library is compiled with the ** shared-cache feature disabled, then there is only ever one user ** of each BtShared structure and so this locking is not necessary. ** So define the lock related functions as no-ops. */ #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 #ifndef SQLITE_OMIT_SHARED_CACHE #ifdef SQLITE_DEBUG /* **** This function is only used as part of an assert() statement. *** ** ** Check to see if pBtree holds the required locks to read or write to the ** table with root page iRoot. Return 1 if it does and 0 if not. ** ** For example, when writing to a table with root-page iRoot via ** Btree connection pBtree: ** ** assert( hasSharedCacheTableLock(pBtree, iRoot, 0, WRITE_LOCK) ); ** ** When writing to an index that resides in a sharable database, the ** caller should have first obtained a lock specifying the root page of ** the corresponding table. This makes things a bit more complicated, ** as this module treats each table as a separate structure. To determine ** the table corresponding to the index being written, this ** function has to search through the database schema. ** ** Instead of a lock on the table/index rooted at page iRoot, the caller may ** hold a write-lock on the schema table (root page 1). This is also ** acceptable. */ static int hasSharedCacheTableLock( Btree *pBtree, /* Handle that must hold lock */ Pgno iRoot, /* Root page of b-tree */ int isIndex, /* True if iRoot is the root of an index b-tree */ int eLockType /* Required lock type (READ_LOCK or WRITE_LOCK) */ ){ Schema *pSchema = (Schema *)pBtree->pBt->pSchema; Pgno iTab = 0; BtLock *pLock; /* If this database is not shareable, or if the client is reading ** and has the read-uncommitted flag set, then no lock is required. ** Return true immediately. */ if( (pBtree->sharable==0) || (eLockType==READ_LOCK && (pBtree->db->flags & SQLITE_ReadUncommitted)) ){ return 1; } /* If the client is reading or writing an index and the schema is ** not loaded, then it is too difficult to actually check to see if ** the correct locks are held. So do not bother - just return true. ** This case does not come up very often anyhow. */ if( isIndex && (!pSchema || (pSchema->flags&DB_SchemaLoaded)==0) ){ return 1; } /* 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 ){ iTab = pIdx->pTable->tnum; } } }else{ iTab = iRoot; } /* Search for the required lock. Either a write-lock on root-page iTab, a ** write-lock on the schema table, or (if the client is reading) a ** read-lock on iTab will suffice. Return 1 if any of these are found. */ for(pLock=pBtree->pBt->pLock; pLock; pLock=pLock->pNext){ if( pLock->pBtree==pBtree && (pLock->iTable==iTab || (pLock->eLock==WRITE_LOCK && pLock->iTable==1)) && pLock->eLock>=eLockType ){ return 1; } } /* Failed to find the required lock. */ return 0; } #endif /* SQLITE_DEBUG */ #ifdef SQLITE_DEBUG /* **** This function may be used as part of assert() statements only. **** ** ** Return true if it would be illegal for pBtree to write into the ** table or index rooted at iRoot because other shared connections are ** simultaneously reading that same table or index. ** ** It is illegal for pBtree to write if some other Btree object that ** shares the same BtShared object is currently reading or writing ** the iRoot table. Except, if the other Btree object has the ** read-uncommitted flag set, then it is OK for the other object to ** have a read cursor. ** ** For example, before writing to any part of the table or index ** rooted at page iRoot, one should call: ** ** assert( !hasReadConflicts(pBtree, iRoot) ); */ static int hasReadConflicts(Btree *pBtree, Pgno iRoot){ BtCursor *p; for(p=pBtree->pBt->pCursor; p; p=p->pNext){ if( p->pgnoRoot==iRoot && p->pBtree!=pBtree && 0==(p->pBtree->db->flags & SQLITE_ReadUncommitted) ){ return 1; } } return 0; } #endif /* #ifdef SQLITE_DEBUG */ /* ** Query to see if Btree handle p may obtain a lock of type eLock ** (READ_LOCK or WRITE_LOCK) on the table with root-page iTab. Return ** SQLITE_OK if the lock may be obtained (by calling ** setSharedCacheTableLock()), or SQLITE_LOCKED if not. */ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){ BtShared *pBt = p->pBt; BtLock *pIter; assert( sqlite3BtreeHoldsMutex(p) ); assert( eLock==READ_LOCK || eLock==WRITE_LOCK ); assert( p->db!=0 ); assert( !(p->db->flags&SQLITE_ReadUncommitted)||eLock==WRITE_LOCK||iTab==1 ); /* If requesting a write-lock, then the Btree must have an open write ** transaction on this file. And, obviously, for this to be so there ** must be an open write transaction on the file itself. */ assert( eLock==READ_LOCK || (p==pBt->pWriter && p->inTrans==TRANS_WRITE) ); assert( eLock==READ_LOCK || pBt->inTransaction==TRANS_WRITE ); /* This routine is a no-op if the shared-cache is not enabled */ if( !p->sharable ){ return SQLITE_OK; } /* If some other connection is holding an exclusive lock, the ** requested lock may not be obtained. */ if( pBt->pWriter!=p && pBt->isExclusive ){ sqlite3ConnectionBlocked(p->db, pBt->pWriter->db); return SQLITE_LOCKED_SHAREDCACHE; } for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ /* The condition (pIter->eLock!=eLock) in the following if(...) ** statement is a simplification of: ** ** (eLock==WRITE_LOCK || pIter->eLock==WRITE_LOCK) ** ** since we know that if eLock==WRITE_LOCK, then no other connection ** may hold a WRITE_LOCK on any table in this file (since there can ** only be a single writer). */ assert( pIter->eLock==READ_LOCK || pIter->eLock==WRITE_LOCK ); assert( eLock==READ_LOCK || pIter->pBtree==p || pIter->eLock==READ_LOCK); if( pIter->pBtree!=p && pIter->iTable==iTab && pIter->eLock!=eLock ){ sqlite3ConnectionBlocked(p->db, pIter->pBtree->db); if( eLock==WRITE_LOCK ){ assert( p==pBt->pWriter ); pBt->isPending = 1; } return SQLITE_LOCKED_SHAREDCACHE; } } return SQLITE_OK; } #endif /* !SQLITE_OMIT_SHARED_CACHE */ #ifndef SQLITE_OMIT_SHARED_CACHE /* ** Add a lock on the table with root-page iTable to the shared-btree used ** by Btree handle p. Parameter eLock must be either READ_LOCK or ** WRITE_LOCK. ** ** This function assumes the following: ** ** (a) The specified Btree object p is connected to a sharable ** database (one with the BtShared.sharable flag set), and ** ** (b) No other Btree objects hold a lock that conflicts ** with the requested lock (i.e. querySharedCacheTableLock() has ** already been called and returned SQLITE_OK). ** ** SQLITE_OK is returned if the lock is added successfully. SQLITE_NOMEM ** is returned if a malloc attempt fails. */ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){ BtShared *pBt = p->pBt; BtLock *pLock = 0; BtLock *pIter; 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_ReadUncommitted) || 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) ); /* First search the list for an existing lock on this table. */ for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ if( pIter->iTable==iTable && pIter->pBtree==p ){ pLock = pIter; break; } |
︙ | ︙ | |||
243 244 245 246 247 248 249 | return SQLITE_OK; } #endif /* !SQLITE_OMIT_SHARED_CACHE */ #ifndef SQLITE_OMIT_SHARED_CACHE /* ** Release all the table locks (locks obtained via calls to | | | > > | > | > > > > > > > > > > > > > > > > > > > > | | | 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 | return SQLITE_OK; } #endif /* !SQLITE_OMIT_SHARED_CACHE */ #ifndef SQLITE_OMIT_SHARED_CACHE /* ** Release all the table locks (locks obtained via calls to ** the setSharedCacheTableLock() procedure) held by Btree object p. ** ** This function assumes that Btree p has an open read or write ** transaction. If it does not, then the BtShared.isPending variable ** may be incorrectly cleared. */ static void clearAllSharedCacheTableLocks(Btree *p){ BtShared *pBt = p->pBt; BtLock **ppIter = &pBt->pLock; assert( sqlite3BtreeHoldsMutex(p) ); assert( p->sharable || 0==*ppIter ); assert( p->inTrans>0 ); while( *ppIter ){ BtLock *pLock = *ppIter; assert( pBt->isExclusive==0 || pBt->pWriter==pLock->pBtree ); assert( pLock->pBtree->inTrans>=pLock->eLock ); if( pLock->pBtree==p ){ *ppIter = pLock->pNext; assert( pLock->iTable!=1 || pLock==&p->lock ); if( pLock->iTable!=1 ){ sqlite3_free(pLock); } }else{ ppIter = &pLock->pNext; } } assert( pBt->isPending==0 || pBt->pWriter ); if( pBt->pWriter==p ){ pBt->pWriter = 0; pBt->isExclusive = 0; pBt->isPending = 0; }else if( pBt->nTransaction==2 ){ /* This function is called when Btree p is concluding its ** transaction. If there currently exists a writer, and p is not ** that writer, then the number of locks held by connections other ** than the writer must be about to drop to zero. In this case ** set the isPending flag to 0. ** ** If there is not currently a writer, then BtShared.isPending must ** be zero already. So this next line is harmless in that case. */ pBt->isPending = 0; } } /* ** This function changes all write-locks held by Btree p into read-locks. */ static void downgradeAllSharedCacheTableLocks(Btree *p){ BtShared *pBt = p->pBt; if( pBt->pWriter==p ){ BtLock *pLock; pBt->pWriter = 0; pBt->isExclusive = 0; pBt->isPending = 0; for(pLock=pBt->pLock; pLock; pLock=pLock->pNext){ assert( pLock->eLock==READ_LOCK || pLock->pBtree==p ); pLock->eLock = READ_LOCK; } } } #endif /* SQLITE_OMIT_SHARED_CACHE */ static void releasePage(MemPage *pPage); /* Forward reference */ /* ***** This routine is used inside of assert() only **** ** ** Verify that the cursor holds the mutex on its BtShared */ #ifdef SQLITE_DEBUG static int cursorHoldsMutex(BtCursor *p){ return sqlite3_mutex_held(p->pBt->mutex); } #endif #ifndef SQLITE_OMIT_INCRBLOB |
︙ | ︙ | |||
322 323 324 325 326 327 328 329 330 331 | static void invalidateAllOverflowCache(BtShared *pBt){ BtCursor *p; assert( sqlite3_mutex_held(pBt->mutex) ); for(p=pBt->pCursor; p; p=p->pNext){ invalidateOverflowCache(p); } } #else #define invalidateOverflowCache(x) #define invalidateAllOverflowCache(x) | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 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 | static void invalidateAllOverflowCache(BtShared *pBt){ BtCursor *p; assert( sqlite3_mutex_held(pBt->mutex) ); for(p=pBt->pCursor; p; p=p->pNext){ invalidateOverflowCache(p); } } /* ** This function is called before modifying the contents of a table ** to invalidate any incrblob cursors that are open on the ** row or one of the rows being modified. ** ** If argument isClearTable is true, then the entire contents of the ** table is about to be deleted. In this case invalidate all incrblob ** cursors open on any row within the table with root-page pgnoRoot. ** ** Otherwise, if argument isClearTable is false, then the row with ** rowid iRow is being replaced or deleted. In this case invalidate ** only those incrblob cursors open on that specific row. */ static void invalidateIncrblobCursors( Btree *pBtree, /* The database file to check */ i64 iRow, /* The rowid that might be changing */ int isClearTable /* True if all rows are being deleted */ ){ BtCursor *p; BtShared *pBt = pBtree->pBt; assert( sqlite3BtreeHoldsMutex(pBtree) ); for(p=pBt->pCursor; p; p=p->pNext){ if( p->isIncrblobHandle && (isClearTable || p->info.nKey==iRow) ){ p->eState = CURSOR_INVALID; } } } #else /* Stub functions when INCRBLOB is omitted */ #define invalidateOverflowCache(x) #define invalidateAllOverflowCache(x) #define invalidateIncrblobCursors(x,y,z) #endif /* SQLITE_OMIT_INCRBLOB */ /* ** Set bit pgno of the BtShared.pHasContent bitvec. This is called ** when a page that previously contained data becomes a free-list leaf ** page. ** ** The BtShared.pHasContent bitvec exists to work around an obscure |
︙ | ︙ | |||
358 359 360 361 362 363 364 | ** is extracted from the free-list and reused, then the original data ** may be lost. In the event of a rollback, it may not be possible ** to restore the database to its original configuration. ** ** The solution is the BtShared.pHasContent bitvec. Whenever a page is ** moved to become a free-list leaf page, the corresponding bit is ** set in the bitvec. Whenever a leaf page is extracted from the free-list, | | | | | > | | | < | 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 | ** is extracted from the free-list and reused, then the original data ** may be lost. In the event of a rollback, it may not be possible ** to restore the database to its original configuration. ** ** The solution is the BtShared.pHasContent bitvec. Whenever a page is ** moved to become a free-list leaf page, the corresponding bit is ** set in the bitvec. Whenever a leaf page is extracted from the free-list, ** optimization 2 above is omitted if the corresponding bit is already ** set in BtShared.pHasContent. The contents of the bitvec are cleared ** at the end of every transaction. */ static int btreeSetHasContent(BtShared *pBt, Pgno pgno){ int rc = SQLITE_OK; if( !pBt->pHasContent ){ int nPage = 100; sqlite3PagerPagecount(pBt->pPager, &nPage); /* If sqlite3PagerPagecount() fails there is no harm because the ** nPage variable is unchanged from its default value of 100 */ pBt->pHasContent = sqlite3BitvecCreate((u32)nPage); if( !pBt->pHasContent ){ rc = SQLITE_NOMEM; } } if( rc==SQLITE_OK && pgno<=sqlite3BitvecSize(pBt->pHasContent) ){ rc = sqlite3BitvecSet(pBt->pHasContent, pgno); } return rc; } |
︙ | ︙ | |||
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 | sqlite3BitvecDestroy(pBt->pHasContent); pBt->pHasContent = 0; } /* ** Save the current cursor position in the variables BtCursor.nKey ** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK. */ static int saveCursorPosition(BtCursor *pCur){ int rc; assert( CURSOR_VALID==pCur->eState ); assert( 0==pCur->pKey ); assert( cursorHoldsMutex(pCur) ); rc = sqlite3BtreeKeySize(pCur, &pCur->nKey); /* If this is an intKey table, then the above call to BtreeKeySize() ** stores the integer key in pCur->nKey. In this case this value is ** all that is required. Otherwise, if pCur is not open on an intKey ** table, then malloc space for and store the pCur->nKey bytes of key ** data. */ | > > > > | | 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 | sqlite3BitvecDestroy(pBt->pHasContent); pBt->pHasContent = 0; } /* ** Save the current cursor position in the variables BtCursor.nKey ** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK. ** ** The caller must ensure that the cursor is valid (has eState==CURSOR_VALID) ** prior to calling this routine. */ static int saveCursorPosition(BtCursor *pCur){ int rc; assert( CURSOR_VALID==pCur->eState ); assert( 0==pCur->pKey ); assert( cursorHoldsMutex(pCur) ); rc = sqlite3BtreeKeySize(pCur, &pCur->nKey); assert( rc==SQLITE_OK ); /* KeySize() cannot fail */ /* If this is an intKey table, then the above call to BtreeKeySize() ** stores the integer key in pCur->nKey. In this case this value is ** all that is required. Otherwise, if pCur is not open on an intKey ** table, then malloc space for and store the pCur->nKey bytes of key ** data. */ if( 0==pCur->apPage[0]->intKey ){ void *pKey = sqlite3Malloc( (int)pCur->nKey ); if( pKey ){ rc = sqlite3BtreeKey(pCur, 0, (int)pCur->nKey, pKey); if( rc==SQLITE_OK ){ pCur->pKey = pKey; }else{ sqlite3_free(pKey); |
︙ | ︙ | |||
450 451 452 453 454 455 456 | } invalidateOverflowCache(pCur); return rc; } /* | | | | 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 | } invalidateOverflowCache(pCur); return rc; } /* ** Save the positions of all cursors (except pExcept) that are open on ** the table with root-page iRoot. Usually, this is called just before cursor ** pExcept is used to modify the table (BtreeDelete() or BtreeInsert()). */ static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){ BtCursor *p; assert( sqlite3_mutex_held(pBt->mutex) ); assert( pExcept==0 || pExcept->pBt==pBt ); for(p=pBt->pCursor; p; p=p->pNext){ |
︙ | ︙ | |||
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 | */ void sqlite3BtreeClearCursor(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); sqlite3_free(pCur->pKey); pCur->pKey = 0; pCur->eState = CURSOR_INVALID; } /* ** Restore the cursor to the position it was in (or as close to as possible) ** when saveCursorPosition() was called. Note that this call deletes the ** saved position info stored by saveCursorPosition(), so there can be ** at most one effective restoreCursorPosition() call after each ** saveCursorPosition(). */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | 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 | */ void sqlite3BtreeClearCursor(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); sqlite3_free(pCur->pKey); 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 */ char aSpace[150]; /* Temp space for pIdxKey - to avoid a malloc */ if( pKey ){ assert( nKey==(i64)(int)nKey ); pIdxKey = sqlite3VdbeRecordUnpack(pCur->pKeyInfo, (int)nKey, pKey, aSpace, sizeof(aSpace)); if( pIdxKey==0 ) return SQLITE_NOMEM; }else{ pIdxKey = 0; } rc = sqlite3BtreeMovetoUnpacked(pCur, pIdxKey, nKey, bias, pRes); if( pKey ){ sqlite3VdbeDeleteUnpackedRecord(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 ** saved position info stored by saveCursorPosition(), so there can be ** at most one effective restoreCursorPosition() call after each ** saveCursorPosition(). */ static int btreeRestoreCursorPosition(BtCursor *pCur){ int rc; assert( cursorHoldsMutex(pCur) ); assert( pCur->eState>=CURSOR_REQUIRESEEK ); if( pCur->eState==CURSOR_FAULT ){ return pCur->skipNext; } pCur->eState = CURSOR_INVALID; rc = btreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &pCur->skipNext); if( rc==SQLITE_OK ){ sqlite3_free(pCur->pKey); pCur->pKey = 0; assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_INVALID ); } return rc; } #define restoreCursorPosition(p) \ (p->eState>=CURSOR_REQUIRESEEK ? \ btreeRestoreCursorPosition(p) : \ SQLITE_OK) /* ** Determine whether or not a cursor has moved from the position it ** was last placed at. Cursors can move when the row they are pointing ** at is deleted out from under them. ** ** This routine returns an error code if something goes wrong. The ** integer *pHasMoved is set to one if the cursor has moved and 0 if not. */ int sqlite3BtreeCursorHasMoved(BtCursor *pCur, int *pHasMoved){ int rc; rc = restoreCursorPosition(pCur); if( rc ){ *pHasMoved = 1; return rc; } if( pCur->eState!=CURSOR_VALID || pCur->skipNext!=0 ){ *pHasMoved = 1; }else{ *pHasMoved = 0; } return SQLITE_OK; } |
︙ | ︙ | |||
557 558 559 560 561 562 563 | } /* ** Write an entry into the pointer map. ** ** This routine updates the pointer map entry for page number 'key' ** so that it maps to type 'eType' and parent page number 'pgno'. | > | > > | | > > | > > | | > | > < | 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 | } /* ** Write an entry into the pointer map. ** ** This routine updates the pointer map entry for page number 'key' ** so that it maps to type 'eType' and parent page number 'pgno'. ** ** If *pRC is initially non-zero (non-SQLITE_OK) then this routine is ** a no-op. If an error occurs, the appropriate error code is written ** into *pRC. */ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){ DbPage *pDbPage; /* The pointer map page */ u8 *pPtrmap; /* The pointer map data */ 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; } iPtrmap = PTRMAP_PAGENO(pBt, key); rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage); if( rc!=SQLITE_OK ){ *pRC = rc; return; } offset = PTRMAP_PTROFFSET(iPtrmap, key); if( offset<0 ){ *pRC = SQLITE_CORRUPT_BKPT; goto ptrmap_exit; } pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage); if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){ TRACE(("PTRMAP_UPDATE: %d->(%d,%d)\n", key, eType, parent)); *pRC= rc = sqlite3PagerWrite(pDbPage); if( rc==SQLITE_OK ){ pPtrmap[offset] = eType; put4byte(&pPtrmap[offset+1], parent); } } ptrmap_exit: sqlite3PagerUnref(pDbPage); } /* ** Read an entry from the pointer map. ** ** This routine retrieves the pointer map entry for page 'key', writing ** the type and parent page number to *pEType and *pPgno respectively. |
︙ | ︙ | |||
632 633 634 635 636 637 638 | sqlite3PagerUnref(pDbPage); if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_BKPT; return SQLITE_OK; } #else /* if defined SQLITE_OMIT_AUTOVACUUM */ | | > | | 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 | sqlite3PagerUnref(pDbPage); if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_BKPT; return SQLITE_OK; } #else /* if defined SQLITE_OMIT_AUTOVACUUM */ #define ptrmapPut(w,x,y,z,rc) #define ptrmapGet(w,x,y,z) SQLITE_OK #define ptrmapPutOvflPtr(x, y, rc) #endif /* ** Given a btree page and a cell index (0 means the first cell on ** the page, 1 means the second cell, and so forth) return a pointer ** to the cell content. ** ** This routine works only for pages that do not contain overflow cells. */ #define findCell(P,I) \ ((P)->aData + ((P)->maskPage & get2byte(&(P)->aData[(P)->cellOffset+2*(I)]))) /* ** This a more complex version of findCell() that works for ** pages that do contain overflow cells. */ static u8 *findOverflowCell(MemPage *pPage, int iCell){ int i; assert( sqlite3_mutex_held(pPage->pBt->mutex) ); for(i=pPage->nOverflow-1; i>=0; i--){ int k; struct _OvflCell *pOvfl; |
︙ | ︙ | |||
670 671 672 673 674 675 676 | } } return findCell(pPage, iCell); } /* ** Parse a cell content block and fill in the CellInfo structure. There | | | | | | 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 | } } return findCell(pPage, iCell); } /* ** Parse a cell content block and fill in the CellInfo structure. There ** are two versions of this function. btreeParseCell() takes a ** cell index as the second argument and btreeParseCellPtr() ** takes a pointer to the body of the cell as its second argument. ** ** Within this file, the parseCell() macro can be called instead of ** btreeParseCellPtr(). Using some compilers, this will be faster. */ static void btreeParseCellPtr( MemPage *pPage, /* Page containing the cell */ u8 *pCell, /* Pointer to the cell text. */ CellInfo *pInfo /* Fill in this structure */ ){ u16 n; /* Number bytes in cell content header */ u32 nPayload; /* Number of bytes of cell payload */ |
︙ | ︙ | |||
706 707 708 709 710 711 712 713 714 715 716 717 718 719 | }else{ pInfo->nData = 0; n += getVarint32(&pCell[n], nPayload); pInfo->nKey = nPayload; } pInfo->nPayload = nPayload; pInfo->nHeader = n; if( likely(nPayload<=pPage->maxLocal) ){ /* This is the (easy) common case where the entire payload fits ** on the local page. No overflow is required. */ int nSize; /* Total size of cell content in bytes */ nSize = nPayload + n; pInfo->nLocal = (u16)nPayload; | > > | 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 | }else{ pInfo->nData = 0; n += getVarint32(&pCell[n], nPayload); pInfo->nKey = nPayload; } pInfo->nPayload = nPayload; pInfo->nHeader = n; testcase( nPayload==pPage->maxLocal ); testcase( nPayload==pPage->maxLocal+1 ); if( likely(nPayload<=pPage->maxLocal) ){ /* This is the (easy) common case where the entire payload fits ** on the local page. No overflow is required. */ int nSize; /* Total size of cell content in bytes */ nSize = nPayload + n; pInfo->nLocal = (u16)nPayload; |
︙ | ︙ | |||
735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 | int minLocal; /* Minimum amount of payload held locally */ int maxLocal; /* Maximum amount of payload held locally */ int surplus; /* Overflow payload available for local storage */ minLocal = pPage->minLocal; maxLocal = pPage->maxLocal; surplus = minLocal + (nPayload - minLocal)%(pPage->pBt->usableSize - 4); if( surplus <= maxLocal ){ pInfo->nLocal = (u16)surplus; }else{ pInfo->nLocal = (u16)minLocal; } pInfo->iOverflow = (u16)(pInfo->nLocal + n); pInfo->nSize = pInfo->iOverflow + 4; } } #define parseCell(pPage, iCell, pInfo) \ | > > | | | 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 | int minLocal; /* Minimum amount of payload held locally */ int maxLocal; /* Maximum amount of payload held locally */ int surplus; /* Overflow payload available for local storage */ minLocal = pPage->minLocal; maxLocal = pPage->maxLocal; surplus = minLocal + (nPayload - minLocal)%(pPage->pBt->usableSize - 4); testcase( surplus==maxLocal ); testcase( surplus==maxLocal+1 ); if( surplus <= maxLocal ){ pInfo->nLocal = (u16)surplus; }else{ pInfo->nLocal = (u16)minLocal; } pInfo->iOverflow = (u16)(pInfo->nLocal + n); pInfo->nSize = pInfo->iOverflow + 4; } } #define parseCell(pPage, iCell, pInfo) \ btreeParseCellPtr((pPage), findCell((pPage), (iCell)), (pInfo)) static void btreeParseCell( MemPage *pPage, /* Page containing the cell */ int iCell, /* The cell index. First cell is 0 */ CellInfo *pInfo /* Fill in this structure */ ){ parseCell(pPage, iCell, pInfo); } |
︙ | ︙ | |||
770 771 772 773 774 775 776 | #ifdef SQLITE_DEBUG /* The value returned by this function should always be the same as ** the (CellInfo.nSize) value found by doing a full parse of the ** cell. If SQLITE_DEBUG is defined, an assert() at the bottom of ** this function verifies that this invariant is not violated. */ CellInfo debuginfo; | | > > > > | > > > | > | | < < > > > > > > > > > > > | > > > > > > > | > | > > | < | | | | > | < | | | | < < | | | > > > < | < | > | | > > > < > | > > | > > | > > > > > > > > > > > > > | > > > | > > | > | | > > > > > > > > > > < | | | | | | 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 | #ifdef SQLITE_DEBUG /* The value returned by this function should always be the same as ** the (CellInfo.nSize) value found by doing a full parse of the ** cell. If SQLITE_DEBUG is defined, an assert() at the bottom of ** this function verifies that this invariant is not violated. */ CellInfo debuginfo; btreeParseCellPtr(pPage, pCell, &debuginfo); #endif if( pPage->intKey ){ u8 *pEnd; if( pPage->hasData ){ pIter += getVarint32(pIter, nSize); }else{ nSize = 0; } /* 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 ); }else{ pIter += getVarint32(pIter, nSize); } testcase( nSize==pPage->maxLocal ); testcase( nSize==pPage->maxLocal+1 ); if( nSize>pPage->maxLocal ){ 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; } nSize += (u32)(pIter - pCell); /* The minimum size of any cell is 4 bytes. */ if( nSize<4 ){ nSize = 4; } assert( nSize==debuginfo.nSize ); return (u16)nSize; } #ifdef SQLITE_DEBUG /* This variation on cellSizePtr() is used inside of assert() statements ** only. */ static u16 cellSize(MemPage *pPage, int iCell){ return cellSizePtr(pPage, findCell(pPage, iCell)); } #endif #ifndef SQLITE_OMIT_AUTOVACUUM /* ** If the cell pCell, part of page pPage contains a pointer ** to an overflow page, insert an entry into the pointer-map ** for the overflow page. */ static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){ CellInfo info; if( *pRC ) return; assert( pCell!=0 ); btreeParseCellPtr(pPage, pCell, &info); assert( (info.nData+(pPage->intKey?0:info.nKey))==info.nPayload ); if( info.iOverflow ){ Pgno ovfl = get4byte(&pCell[info.iOverflow]); ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, pRC); } } #endif /* ** Defragment the page given. All Cells are moved to the ** end of the page and all free space is collected into one ** big FreeBlk that occurs in between the header and cell ** pointer array and the cell content area. */ static int defragmentPage(MemPage *pPage){ int i; /* Loop counter */ int pc; /* Address of a i-th cell */ int hdr; /* Offset to the page header */ int size; /* Size of a cell */ int usableSize; /* Number of usable bytes on a page */ int cellOffset; /* Offset to the cell pointer array */ 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 */ 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 = sqlite3PagerTempSpace(pPage->pBt->pPager); data = pPage->aData; hdr = pPage->hdrOffset; cellOffset = pPage->cellOffset; nCell = pPage->nCell; assert( nCell==get2byte(&data[hdr+3]) ); usableSize = pPage->pBt->usableSize; cbrk = get2byte(&data[hdr+5]); memcpy(&temp[cbrk], &data[cbrk], usableSize - cbrk); cbrk = usableSize; iCellFirst = cellOffset + 2*nCell; 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 ); #if !defined(SQLITE_ENABLE_OVERSIZE_CELL_CHECK) /* These conditions have already been verified in btreeInitPage() ** if SQLITE_ENABLE_OVERSIZE_CELL_CHECK is defined */ if( pc<iCellFirst || pc>iCellLast ){ return SQLITE_CORRUPT_BKPT; } #endif assert( pc>=iCellFirst && pc<=iCellLast ); size = cellSizePtr(pPage, &temp[pc]); cbrk -= size; #if defined(SQLITE_ENABLE_OVERSIZE_CELL_CHECK) if( cbrk<iCellFirst ){ return SQLITE_CORRUPT_BKPT; } #else if( cbrk<iCellFirst || pc+size>usableSize ){ return SQLITE_CORRUPT_BKPT; } #endif assert( cbrk+size<=usableSize && cbrk>=iCellFirst ); testcase( cbrk+size==usableSize ); testcase( pc+size==usableSize ); memcpy(&data[cbrk], &temp[pc], size); put2byte(pAddr, cbrk); } assert( cbrk>=iCellFirst ); put2byte(&data[hdr+5], cbrk); data[hdr+1] = 0; data[hdr+2] = 0; data[hdr+7] = 0; memset(&data[iCellFirst], 0, cbrk-iCellFirst); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); if( cbrk-iCellFirst!=pPage->nFree ){ return SQLITE_CORRUPT_BKPT; } return SQLITE_OK; } /* ** Allocate nByte bytes of space from within the B-Tree page passed ** as the first argument. Write into *pIdx the index into pPage->aData[] ** of the first byte of allocated space. Return either SQLITE_OK or ** an error code (usually SQLITE_CORRUPT). ** ** The caller guarantees that there is sufficient space to make the ** allocation. This routine might need to defragment in order to bring ** all the space together, however. This routine will avoid using ** the first two bytes past the cell pointer area since presumably this ** allocation is being made in order to insert a new cell, so we will ** 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 nFrag; /* Number of fragmented bytes on pPage */ int top; /* First byte of cell content area */ int gap; /* First byte of gap between cell pointers and cell content */ int rc; /* Integer return code */ 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<pPage->pBt->usableSize-8 ); nFrag = data[hdr+7]; assert( pPage->cellOffset == hdr + 12 - 4*pPage->leaf ); gap = pPage->cellOffset + 2*pPage->nCell; top = get2byte(&data[hdr+5]); if( gap>top ) return SQLITE_CORRUPT_BKPT; testcase( gap+2==top ); testcase( gap+1==top ); testcase( gap==top ); if( nFrag>=60 ){ /* Always defragment highly fragmented pages */ rc = defragmentPage(pPage); if( rc ) return rc; top = get2byte(&data[hdr+5]); }else if( gap+2<=top ){ /* Search the freelist looking for a free slot big enough to satisfy ** the request. The allocation is made from the first free slot in ** the list that is large enough to accomadate it. */ int pc, addr; for(addr=hdr+1; (pc = get2byte(&data[addr]))>0; addr=pc){ int size = get2byte(&data[pc+2]); /* Size of free slot */ if( size>=nByte ){ int x = size - nByte; testcase( x==4 ); testcase( x==3 ); if( x<4 ){ /* Remove the slot from the free-list. Update the number of ** fragmented bytes within the page. */ memcpy(&data[addr], &data[pc], 2); data[hdr+7] = (u8)(nFrag + x); }else{ /* The slot remains on the free-list. Reduce its size to account ** for the portion used by the new allocation. */ put2byte(&data[pc+2], x); } *pIdx = pc + x; return SQLITE_OK; } } } /* Check to make sure there is enough space in the gap to satisfy ** the allocation. If not, defragment. */ testcase( gap+2+nByte==top ); if( gap+2+nByte>top ){ rc = defragmentPage(pPage); if( rc ) return rc; top = get2byte(&data[hdr+5]); assert( gap+nByte<=top ); } /* Allocate memory from the gap in between the cell pointer array ** and the cell content area. The btreeInitPage() call has already ** validated the freelist. Given that the freelist is valid, there ** is no way that the allocation can extend off the end of the page. ** The assert() below verifies the previous sentence. */ top -= nByte; put2byte(&data[hdr+5], top); assert( top+nByte <= pPage->pBt->usableSize ); *pIdx = top; return SQLITE_OK; } /* ** Return a section of the pPage->aData to the freelist. ** The first byte of the new free block is pPage->aDisk[start] ** and the size of the block is "size" bytes. ** ** Most of the effort here is involved in coalesing adjacent ** free blocks into a single big free block. */ static int freeSpace(MemPage *pPage, int start, int size){ int addr, pbegin, hdr; int iLast; /* Largest possible freeblock offset */ unsigned char *data = pPage->aData; assert( pPage->pBt!=0 ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( start>=pPage->hdrOffset+6+pPage->childPtrSize ); assert( (start + size)<=pPage->pBt->usableSize ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( size>=0 ); /* Minimum cell size is 4 */ #ifdef SQLITE_SECURE_DELETE /* Overwrite deleted information with zeros when the SECURE_DELETE ** option is enabled at compile-time */ memset(&data[start], 0, size); #endif /* Add the space back into the linked list of freeblocks. Note that ** even though the freeblock list was checked by btreeInitPage(), ** btreeInitPage() did not detect overlapping cells or ** freeblocks that overlapped cells. Nor does it detect when the ** cell content area exceeds the value in the page header. If these ** situations arise, then subsequent insert operations might corrupt ** the freelist. So we do need to check for corruption while scanning ** the freelist. */ hdr = pPage->hdrOffset; addr = hdr + 1; iLast = pPage->pBt->usableSize - 4; assert( start<=iLast ); while( (pbegin = get2byte(&data[addr]))<start && pbegin>0 ){ if( pbegin<addr+4 ){ return SQLITE_CORRUPT_BKPT; } addr = pbegin; } if( pbegin>iLast ){ return SQLITE_CORRUPT_BKPT; } assert( pbegin>addr || pbegin==0 ); put2byte(&data[addr], start); put2byte(&data[start], pbegin); put2byte(&data[start+2], size); pPage->nFree = pPage->nFree + (u16)size; /* Coalesce adjacent free blocks */ addr = hdr + 1; while( (pbegin = get2byte(&data[addr]))>0 ){ int pnext, psize, x; assert( pbegin>addr ); assert( pbegin<=pPage->pBt->usableSize-4 ); pnext = get2byte(&data[pbegin]); psize = get2byte(&data[pbegin+2]); if( pbegin + psize + 3 >= pnext && pnext>0 ){ int frag = pnext - (pbegin+psize); if( (frag<0) || (frag>(int)data[hdr+7]) ){ return SQLITE_CORRUPT_BKPT; } data[hdr+7] -= (u8)frag; x = get2byte(&data[pnext]); put2byte(&data[pbegin], x); x = pnext + get2byte(&data[pnext+2]) - pbegin; put2byte(&data[pbegin+2], x); }else{ addr = pbegin; } |
︙ | ︙ | |||
1094 1095 1096 1097 1098 1099 1100 | ** ** Return SQLITE_OK on success. If we see that the page does ** not contain a well-formed database page, then return ** SQLITE_CORRUPT. Note that a return of SQLITE_OK does not ** guarantee that the page is well-formed. It only shows that ** we failed to detect any corruption. */ | | > > > | > > < < < < > > > > | | | | > < | < < < < < < < < < < < < < < < < < < < < | 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 | ** ** Return SQLITE_OK on success. If we see that the page does ** not contain a well-formed database page, then return ** SQLITE_CORRUPT. Note that a return of SQLITE_OK does not ** guarantee that the page is well-formed. It only shows that ** we failed to detect any corruption. */ static int btreeInitPage(MemPage *pPage){ assert( pPage->pBt!=0 ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) ); assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) ); if( !pPage->isInit ){ u16 pc; /* Address of a freeblock within pPage->aData[] */ u8 hdr; /* Offset to beginning of page header */ u8 *data; /* Equal to pPage->aData */ BtShared *pBt; /* The main btree structure */ u16 usableSize; /* Amount of usable space on each page */ u16 cellOffset; /* Offset from start of page to first cell pointer */ u16 nFree; /* Number of unused bytes on the page */ u16 top; /* First byte of the cell content area */ int iCellFirst; /* First allowable cell or freeblock offset */ int iCellLast; /* Last possible cell or freeblock offset */ pBt = pPage->pBt; hdr = pPage->hdrOffset; data = pPage->aData; if( decodeFlags(pPage, data[hdr]) ) return SQLITE_CORRUPT_BKPT; assert( pBt->pageSize>=512 && pBt->pageSize<=32768 ); pPage->maskPage = pBt->pageSize - 1; pPage->nOverflow = 0; usableSize = pBt->usableSize; pPage->cellOffset = cellOffset = hdr + 12 - 4*pPage->leaf; top = get2byte(&data[hdr+5]); pPage->nCell = get2byte(&data[hdr+3]); if( pPage->nCell>MX_CELL(pBt) ){ /* To many cells for a single page. The page must be corrupt */ return SQLITE_CORRUPT_BKPT; } testcase( pPage->nCell==MX_CELL(pBt) ); /* A malformed database page might cause us to read past the end ** of page when parsing a cell. ** ** The following block of code checks early to see if a cell extends ** past the end of a page boundary and causes SQLITE_CORRUPT to be ** returned if it does. */ iCellFirst = cellOffset + 2*pPage->nCell; iCellLast = usableSize - 4; #if defined(SQLITE_ENABLE_OVERSIZE_CELL_CHECK) { int i; /* Index into the cell pointer array */ int sz; /* Size of a cell */ if( !pPage->leaf ) iCellLast--; for(i=0; i<pPage->nCell; i++){ pc = get2byte(&data[cellOffset+i*2]); testcase( pc==iCellFirst ); testcase( pc==iCellLast ); if( pc<iCellFirst || pc>iCellLast ){ return SQLITE_CORRUPT_BKPT; } sz = cellSizePtr(pPage, &data[pc]); testcase( pc+sz==usableSize ); if( pc+sz>usableSize ){ return SQLITE_CORRUPT_BKPT; } } if( !pPage->leaf ) iCellLast++; } #endif /* Compute the total free space on the page */ pc = get2byte(&data[hdr+1]); nFree = data[hdr+7] + top; while( pc>0 ){ u16 next, size; if( pc<iCellFirst || pc>iCellLast ){ /* Start of free block is off the page */ return SQLITE_CORRUPT_BKPT; } next = get2byte(&data[pc]); size = get2byte(&data[pc+2]); if( (next>0 && next<=pc+size+3) || pc+size>usableSize ){ /* Free blocks must be in ascending order. And the last byte of ** the free-block must lie on the database page. */ return SQLITE_CORRUPT_BKPT; } nFree = nFree + size; pc = next; } /* 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_BKPT; } pPage->nFree = (u16)(nFree - iCellFirst); pPage->isInit = 1; } return SQLITE_OK; } /* ** Set up a raw page so that it looks like a database page holding |
︙ | ︙ | |||
1273 1274 1275 1276 1277 1278 1279 | ** If the noContent flag is set, it means that we do not care about ** the content of the page at this time. So do not go to the disk ** to fetch the content. Just fill in the content with zeros for now. ** If in the future we call sqlite3PagerWrite() on this page, that ** means we have started to be concerned about content and the disk ** read should occur at that point. */ | | | 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 | ** If the noContent flag is set, it means that we do not care about ** the content of the page at this time. So do not go to the disk ** to fetch the content. Just fill in the content with zeros for now. ** If in the future we call sqlite3PagerWrite() on this page, that ** means we have started to be concerned about content and the disk ** read should occur at that point. */ static int btreeGetPage( BtShared *pBt, /* The btree */ Pgno pgno, /* Number of the page to fetch */ MemPage **ppPage, /* Return the page in this parameter */ int noContent /* Do not load page content if true */ ){ int rc; DbPage *pDbPage; |
︙ | ︙ | |||
1318 1319 1320 1321 1322 1323 1324 | assert( pBt->pPage1 ); rc = sqlite3PagerPagecount(pBt->pPager, &nPage); assert( rc==SQLITE_OK || nPage==-1 ); return (Pgno)nPage; } /* | | | | > > > < | < < | | < < < < < < | | | | < < < < < < < < | > > > > | | < > | | | 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 | assert( pBt->pPage1 ); rc = sqlite3PagerPagecount(pBt->pPager, &nPage); assert( rc==SQLITE_OK || nPage==-1 ); return (Pgno)nPage; } /* ** Get a page from the pager and initialize it. This routine is just a ** convenience wrapper around separate calls to btreeGetPage() and ** btreeInitPage(). ** ** If an error occurs, then the value *ppPage is set to is undefined. It ** may remain unchanged, or it may be set to an invalid value. */ static int getAndInitPage( BtShared *pBt, /* The database file */ Pgno pgno, /* Number of the page to get */ MemPage **ppPage /* Write the page pointer here */ ){ int rc; TESTONLY( Pgno iLastPg = pagerPagecount(pBt); ) assert( sqlite3_mutex_held(pBt->mutex) ); rc = btreeGetPage(pBt, pgno, ppPage, 0); if( rc==SQLITE_OK ){ rc = btreeInitPage(*ppPage); if( rc!=SQLITE_OK ){ releasePage(*ppPage); } } /* If the requested page number was either 0 or greater than the page ** number of the last page in the database, this function should return ** SQLITE_CORRUPT or some other error (i.e. SQLITE_FULL). Check that this ** is the case. */ assert( (pgno>0 && pgno<=iLastPg) || rc!=SQLITE_OK ); testcase( pgno==0 ); testcase( pgno==iLastPg ); return rc; } /* ** Release a MemPage. This should be called once for each prior ** call to btreeGetPage. */ static void releasePage(MemPage *pPage){ if( pPage ){ assert( pPage->nOverflow==0 || sqlite3PagerPageRefcount(pPage->pDbPage)>1 ); assert( pPage->aData ); assert( pPage->pBt ); assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage ); |
︙ | ︙ | |||
1397 1398 1399 1400 1401 1402 1403 | assert( sqlite3PagerPageRefcount(pData)>0 ); if( pPage->isInit ){ assert( sqlite3_mutex_held(pPage->pBt->mutex) ); pPage->isInit = 0; if( sqlite3PagerPageRefcount(pData)>1 ){ /* pPage might not be a btree page; it might be an overflow page ** or ptrmap page or a free page. In those cases, the following | | | | | 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 | assert( sqlite3PagerPageRefcount(pData)>0 ); if( pPage->isInit ){ assert( sqlite3_mutex_held(pPage->pBt->mutex) ); pPage->isInit = 0; if( sqlite3PagerPageRefcount(pData)>1 ){ /* pPage might not be a btree page; it might be an overflow page ** or ptrmap page or a free page. In those cases, the following ** call to btreeInitPage() will likely return SQLITE_CORRUPT. ** But no harm is done by this. And it is very important that ** btreeInitPage() be called on every btree page so we make ** the call for every page that comes in for re-initing. */ btreeInitPage(pPage); } } } /* ** Invoke the busy handler for a btree. */ |
︙ | ︙ | |||
1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 | pVfs = db->pVfs; p = sqlite3MallocZero(sizeof(Btree)); if( !p ){ return SQLITE_NOMEM; } p->inTrans = TRANS_NONE; p->db = db; #if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) /* ** If this Btree is a candidate for shared cache, try to find an ** existing BtShared object that we can share with */ if( isMemdb==0 && zFilename && zFilename[0] ){ | > > > > | < | 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 | pVfs = db->pVfs; p = sqlite3MallocZero(sizeof(Btree)); if( !p ){ return SQLITE_NOMEM; } p->inTrans = TRANS_NONE; p->db = db; #ifndef SQLITE_OMIT_SHARED_CACHE p->lock.pBtree = p; p->lock.iTable = 1; #endif #if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) /* ** If this Btree is a candidate for shared cache, try to find an ** existing BtShared object that we can share with */ if( isMemdb==0 && zFilename && zFilename[0] ){ if( vfsFlags & SQLITE_OPEN_SHAREDCACHE ){ int nFullPathname = pVfs->mxPathname+1; char *zFullPathname = sqlite3Malloc(nFullPathname); sqlite3_mutex *mutexShared; p->sharable = 1; if( !zFullPathname ){ sqlite3_free(p); return SQLITE_NOMEM; } sqlite3OsFullPathname(pVfs, zFilename, nFullPathname, zFullPathname); mutexOpen = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_OPEN); sqlite3_mutex_enter(mutexOpen); |
︙ | ︙ | |||
1544 1545 1546 1547 1548 1549 1550 | pBt = sqlite3MallocZero( sizeof(*pBt) ); if( pBt==0 ){ rc = SQLITE_NOMEM; goto btree_open_out; } rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename, | | < | 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 | pBt = sqlite3MallocZero( sizeof(*pBt) ); if( pBt==0 ){ rc = SQLITE_NOMEM; goto btree_open_out; } rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename, EXTRA_SIZE, flags, vfsFlags, pageReinit); if( rc==SQLITE_OK ){ rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader); } if( rc!=SQLITE_OK ){ goto btree_open_out; } pBt->db = db; sqlite3PagerSetBusyhandler(pBt->pPager, btreeInvokeBusyHandler, pBt); p->pBt = pBt; pBt->pCursor = 0; pBt->pPage1 = 0; pBt->readOnly = sqlite3PagerIsreadonly(pBt->pPager); pBt->pageSize = get2byte(&zDbHeader[16]); if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE || ((pBt->pageSize-1)&pBt->pageSize)!=0 ){ pBt->pageSize = 0; |
︙ | ︙ | |||
1980 1981 1982 1983 1984 1985 1986 | static int lockBtree(BtShared *pBt){ int rc; MemPage *pPage1; int nPage; assert( sqlite3_mutex_held(pBt->mutex) ); assert( pBt->pPage1==0 ); | > > | | 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 | static int lockBtree(BtShared *pBt){ int rc; MemPage *pPage1; int nPage; 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. */ rc = sqlite3PagerPagecount(pBt->pPager, &nPage); if( rc!=SQLITE_OK ){ |
︙ | ︙ | |||
2033 2034 2035 2036 2037 2038 2039 | */ releasePage(pPage1); pBt->usableSize = (u16)usableSize; pBt->pageSize = (u16)pageSize; freeTempSpace(pBt); rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize, pageSize-usableSize); | < | | 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 | */ releasePage(pPage1); pBt->usableSize = (u16)usableSize; pBt->pageSize = (u16)pageSize; freeTempSpace(pBt); rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize, pageSize-usableSize); return rc; } if( usableSize<480 ){ goto page1_init_failed; } pBt->pageSize = (u16)pageSize; pBt->usableSize = (u16)usableSize; #ifndef SQLITE_OMIT_AUTOVACUUM |
︙ | ︙ | |||
2074 2075 2076 2077 2078 2079 2080 | page1_init_failed: releasePage(pPage1); pBt->pPage1 = 0; return rc; } | < < < < < < < < < < < < < < < < < < < < < < < < < > | > | | > > > | | 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 | page1_init_failed: releasePage(pPage1); pBt->pPage1 = 0; return rc; } /* ** If there are no outstanding cursors and we are not in the middle ** of a transaction but there is a read lock on the database, then ** this routine unrefs the first page of the database file which ** has the effect of releasing the read lock. ** ** If there is a transaction in progress, this routine is a no-op. */ static void unlockBtreeIfUnused(BtShared *pBt){ assert( sqlite3_mutex_held(pBt->mutex) ); assert( pBt->pCursor==0 || pBt->inTransaction>TRANS_NONE ); if( pBt->inTransaction==TRANS_NONE && pBt->pPage1!=0 ){ assert( pBt->pPage1->aData ); assert( sqlite3PagerRefcount(pBt->pPager)==1 ); assert( pBt->pPage1->aData ); releasePage(pBt->pPage1); pBt->pPage1 = 0; } } /* ** If pBt points to an empty file then convert that empty file ** into a new empty database by initializing the first page of ** the database. */ static int newDatabase(BtShared *pBt){ MemPage *pP1; unsigned char *data; int rc; int nPage; assert( sqlite3_mutex_held(pBt->mutex) ); /* The database size has already been measured and cached, so failure ** is impossible here. If the original size measurement failed, then ** processing aborts before entering this routine. */ rc = sqlite3PagerPagecount(pBt->pPager, &nPage); if( NEVER(rc!=SQLITE_OK) || nPage>0 ){ return rc; } pP1 = pBt->pPage1; assert( pP1!=0 ); data = pP1->aData; rc = sqlite3PagerWrite(pP1->pDbPage); if( rc ) return rc; |
︙ | ︙ | |||
2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 | if( pBlock ){ sqlite3ConnectionBlocked(p->db, pBlock); rc = SQLITE_LOCKED_SHAREDCACHE; goto trans_begun; } #endif 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. | > > > > > > | 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 | if( pBlock ){ sqlite3ConnectionBlocked(p->db, pBlock); rc = SQLITE_LOCKED_SHAREDCACHE; goto trans_begun; } #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; 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. |
︙ | ︙ | |||
2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 | } }while( rc==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE && btreeInvokeBusyHandler(pBt) ); if( rc==SQLITE_OK ){ if( p->inTrans==TRANS_NONE ){ pBt->nTransaction++; } p->inTrans = (wrflag?TRANS_WRITE:TRANS_READ); if( p->inTrans>pBt->inTransaction ){ pBt->inTransaction = p->inTrans; } #ifndef SQLITE_OMIT_SHARED_CACHE if( wrflag ){ | > > > > > > > > | 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 | } }while( rc==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE && btreeInvokeBusyHandler(pBt) ); 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 ); p->lock.eLock = READ_LOCK; p->lock.pNext = pBt->pLock; pBt->pLock = &p->lock; } #endif } p->inTrans = (wrflag?TRANS_WRITE:TRANS_READ); if( p->inTrans>pBt->inTransaction ){ pBt->inTransaction = p->inTrans; } #ifndef SQLITE_OMIT_SHARED_CACHE if( wrflag ){ |
︙ | ︙ | |||
2315 2316 2317 2318 2319 2320 2321 | int nCell; /* Number of cells in page pPage */ int rc; /* Return code */ BtShared *pBt = pPage->pBt; u8 isInitOrig = pPage->isInit; Pgno pgno = pPage->pgno; assert( sqlite3_mutex_held(pPage->pBt->mutex) ); | | | < < < | < | < | | | | 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 | int nCell; /* Number of cells in page pPage */ int rc; /* Return code */ BtShared *pBt = pPage->pBt; u8 isInitOrig = pPage->isInit; Pgno pgno = pPage->pgno; assert( sqlite3_mutex_held(pPage->pBt->mutex) ); rc = btreeInitPage(pPage); if( rc!=SQLITE_OK ){ goto set_child_ptrmaps_out; } nCell = pPage->nCell; for(i=0; i<nCell; i++){ u8 *pCell = findCell(pPage, i); ptrmapPutOvflPtr(pPage, pCell, &rc); if( !pPage->leaf ){ Pgno childPgno = get4byte(pCell); ptrmapPut(pBt, childPgno, PTRMAP_BTREE, pgno, &rc); } } if( !pPage->leaf ){ Pgno childPgno = get4byte(&pPage->aData[pPage->hdrOffset+8]); ptrmapPut(pBt, childPgno, PTRMAP_BTREE, pgno, &rc); } set_child_ptrmaps_out: pPage->isInit = isInitOrig; return rc; } /* ** Somewhere on pPage is a pointer to page iFrom. Modify this pointer so ** that it points to iTo. Parameter eType describes the type of pointer to ** be modified, as follows: ** ** PTRMAP_BTREE: pPage is a btree-page. The pointer points at a child ** page of pPage. ** ** PTRMAP_OVERFLOW1: pPage is a btree-page. The pointer points at an overflow ** page pointed to by one of the cells on pPage. ** |
︙ | ︙ | |||
2375 2376 2377 2378 2379 2380 2381 | } put4byte(pPage->aData, iTo); }else{ u8 isInitOrig = pPage->isInit; int i; int nCell; | | | | 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 | } put4byte(pPage->aData, iTo); }else{ u8 isInitOrig = pPage->isInit; int i; int nCell; btreeInitPage(pPage); nCell = pPage->nCell; for(i=0; i<nCell; i++){ u8 *pCell = findCell(pPage, i); if( eType==PTRMAP_OVERFLOW1 ){ CellInfo info; btreeParseCellPtr(pPage, pCell, &info); if( info.iOverflow ){ if( iFrom==get4byte(&pCell[info.iOverflow]) ){ put4byte(&pCell[info.iOverflow], iTo); break; } } }else{ |
︙ | ︙ | |||
2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 | return SQLITE_OK; } /* ** Move the open database page pDbPage to location iFreePage in the ** database. The pDbPage reference remains valid. */ static int relocatePage( BtShared *pBt, /* Btree */ MemPage *pDbPage, /* Open page to move */ u8 eType, /* Pointer map 'type' entry for pDbPage */ Pgno iPtrPage, /* Pointer map 'page-no' entry for pDbPage */ Pgno iFreePage, /* The location to move pDbPage to */ | > > > > > | | 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 | return SQLITE_OK; } /* ** Move the open database page pDbPage to location iFreePage in the ** database. The pDbPage reference remains valid. ** ** The isCommit flag indicates that there is no need to remember that ** the journal needs to be sync()ed before database page pDbPage->pgno ** can be written to. The caller has already promised not to write to that ** page. */ static int relocatePage( BtShared *pBt, /* Btree */ MemPage *pDbPage, /* Open page to move */ u8 eType, /* Pointer map 'type' entry for pDbPage */ Pgno iPtrPage, /* Pointer map 'page-no' entry for pDbPage */ Pgno iFreePage, /* The location to move pDbPage to */ int isCommit /* isCommit flag passed to sqlite3PagerMovepage */ ){ MemPage *pPtrPage; /* The page that contains a pointer to pDbPage */ Pgno iDbPage = pDbPage->pgno; Pager *pPager = pBt->pPager; int rc; assert( eType==PTRMAP_OVERFLOW2 || eType==PTRMAP_OVERFLOW1 || |
︙ | ︙ | |||
2458 2459 2460 2461 2462 2463 2464 | rc = setChildPtrmaps(pDbPage); if( rc!=SQLITE_OK ){ return rc; } }else{ Pgno nextOvfl = get4byte(pDbPage->aData); if( nextOvfl!=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 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 | rc = setChildPtrmaps(pDbPage); if( rc!=SQLITE_OK ){ return rc; } }else{ Pgno nextOvfl = get4byte(pDbPage->aData); if( nextOvfl!=0 ){ ptrmapPut(pBt, nextOvfl, PTRMAP_OVERFLOW2, iFreePage, &rc); if( rc!=SQLITE_OK ){ return rc; } } } /* Fix the database pointer on page iPtrPage that pointed at iDbPage so ** that it points at iFreePage. Also fix the pointer map entry for ** iPtrPage. */ if( eType!=PTRMAP_ROOTPAGE ){ rc = btreeGetPage(pBt, iPtrPage, &pPtrPage, 0); if( rc!=SQLITE_OK ){ return rc; } rc = sqlite3PagerWrite(pPtrPage->pDbPage); if( rc!=SQLITE_OK ){ releasePage(pPtrPage); return rc; } rc = modifyPagePointer(pPtrPage, iDbPage, iFreePage, eType); releasePage(pPtrPage); if( rc==SQLITE_OK ){ ptrmapPut(pBt, iFreePage, eType, iPtrPage, &rc); } } return rc; } /* Forward declaration required by incrVacuumStep(). */ static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8); /* ** Perform a single step of an incremental-vacuum. If successful, ** return SQLITE_OK. If there is no work to do (and therefore no ** point in calling this function again), return SQLITE_DONE. ** ** More specificly, this function attempts to re-organize the ** database so that the last page of the file currently in use ** is no longer in use. ** ** If the nFin parameter is non-zero, this function assumes ** that the caller will keep calling incrVacuumStep() until ** it returns SQLITE_DONE or an error, and that nFin is the ** number of pages the database file will contain after this ** process is complete. If nFin is zero, it is assumed that ** incrVacuumStep() will be called a finite amount of times ** which may or may not empty the freelist. A full autovacuum ** has nFin>0. A "PRAGMA incremental_vacuum" has nFin==0. */ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){ Pgno nFreeList; /* Number of pages still on the free-list */ assert( sqlite3_mutex_held(pBt->mutex) ); assert( iLastPg>nFin ); |
︙ | ︙ | |||
2550 2551 2552 2553 2554 2555 2556 | assert( iFreePg==iLastPg ); releasePage(pFreePg); } } else { Pgno iFreePg; /* Index of free page to move pLastPg to */ MemPage *pLastPg; | | | 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 | assert( iFreePg==iLastPg ); releasePage(pFreePg); } } else { Pgno iFreePg; /* Index of free page to move pLastPg to */ MemPage *pLastPg; rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0); if( rc!=SQLITE_OK ){ return rc; } /* If nFin is zero, this loop runs exactly once and page pLastPg ** is swapped with the first free page pulled off the free list. ** |
︙ | ︙ | |||
2589 2590 2591 2592 2593 2594 2595 | } if( nFin==0 ){ iLastPg--; while( iLastPg==PENDING_BYTE_PAGE(pBt)||PTRMAP_ISPAGE(pBt, iLastPg) ){ if( PTRMAP_ISPAGE(pBt, iLastPg) ){ MemPage *pPg; | | | 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 | } if( nFin==0 ){ iLastPg--; while( iLastPg==PENDING_BYTE_PAGE(pBt)||PTRMAP_ISPAGE(pBt, iLastPg) ){ if( PTRMAP_ISPAGE(pBt, iLastPg) ){ MemPage *pPg; int rc = btreeGetPage(pBt, iLastPg, &pPg, 0); if( rc!=SQLITE_OK ){ return rc; } rc = sqlite3PagerWrite(pPg->pDbPage); releasePage(pPg); if( rc!=SQLITE_OK ){ return rc; |
︙ | ︙ | |||
2648 2649 2650 2651 2652 2653 2654 | Pager *pPager = pBt->pPager; VVA_ONLY( int nRef = sqlite3PagerRefcount(pPager) ); assert( sqlite3_mutex_held(pBt->mutex) ); invalidateAllOverflowCache(pBt); assert(pBt->autoVacuum); if( !pBt->incrVacuum ){ | | | | | | | > > | | 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 | 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 nPtrmap; /* Number of PtrMap pages to be freed */ Pgno iFree; /* The next page to be freed */ int nEntry; /* Number of entries on one ptrmap page */ Pgno nOrig; /* Database size before freeing */ nOrig = pagerPagecount(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]); nEntry = pBt->usableSize/5; nPtrmap = (nFree-nOrig+PTRMAP_PAGENO(pBt, nOrig)+nEntry)/nEntry; nFin = nOrig - nFree - nPtrmap; if( nOrig>PENDING_BYTE_PAGE(pBt) && nFin<PENDING_BYTE_PAGE(pBt) ){ nFin--; } while( PTRMAP_ISPAGE(pBt, nFin) || nFin==PENDING_BYTE_PAGE(pBt) ){ nFin--; } |
︙ | ︙ | |||
2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 | } #endif rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zMaster, 0); sqlite3BtreeLeave(p); } return rc; } /* ** Commit the transaction currently in progress. ** ** This routine implements the second phase of a 2-phase commit. The ** sqlite3BtreeCommitPhaseOne() routine does the first phase and should ** be invoked prior to calling this routine. The sqlite3BtreeCommitPhaseOne() | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } #endif rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zMaster, 0); sqlite3BtreeLeave(p); } return rc; } /* ** This function is called from both BtreeCommitPhaseTwo() and BtreeRollback() ** at the conclusion of a transaction. */ static void btreeEndTransaction(Btree *p){ BtShared *pBt = p->pBt; assert( sqlite3BtreeHoldsMutex(p) ); btreeClearHasContent(pBt); if( p->inTrans>TRANS_NONE && p->db->activeVdbeCnt>1 ){ /* If there are other active statements that belong to this database ** handle, downgrade to a read-only transaction. The other statements ** may still be reading from the database. */ downgradeAllSharedCacheTableLocks(p); p->inTrans = TRANS_READ; }else{ /* If the handle had any kind of transaction open, decrement the ** transaction count of the shared btree. If the transaction count ** reaches 0, set the shared state to TRANS_NONE. The unlockBtreeIfUnused() ** call below will unlock the pager. */ if( p->inTrans!=TRANS_NONE ){ clearAllSharedCacheTableLocks(p); pBt->nTransaction--; if( 0==pBt->nTransaction ){ pBt->inTransaction = TRANS_NONE; } } /* Set the current transaction state to TRANS_NONE and unlock the ** pager if this call closed the only read or write transaction. */ p->inTrans = TRANS_NONE; unlockBtreeIfUnused(pBt); } btreeIntegrity(p); } /* ** Commit the transaction currently in progress. ** ** This routine implements the second phase of a 2-phase commit. The ** sqlite3BtreeCommitPhaseOne() routine does the first phase and should ** be invoked prior to calling this routine. The sqlite3BtreeCommitPhaseOne() |
︙ | ︙ | |||
2779 2780 2781 2782 2783 2784 2785 | if( rc!=SQLITE_OK ){ sqlite3BtreeLeave(p); return rc; } pBt->inTransaction = TRANS_READ; } | < < < < < < < | < < < < < < < < < < < < < | 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 | if( rc!=SQLITE_OK ){ sqlite3BtreeLeave(p); return rc; } pBt->inTransaction = TRANS_READ; } btreeEndTransaction(p); sqlite3BtreeLeave(p); return SQLITE_OK; } /* ** Do both phases of a commit. */ |
︙ | ︙ | |||
2863 2864 2865 2866 2867 2868 2869 | void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode){ BtCursor *p; sqlite3BtreeEnter(pBtree); for(p=pBtree->pBt->pCursor; p; p=p->pNext){ int i; sqlite3BtreeClearCursor(p); p->eState = CURSOR_FAULT; | | | 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 | void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode){ BtCursor *p; sqlite3BtreeEnter(pBtree); for(p=pBtree->pBt->pCursor; p; p=p->pNext){ int i; sqlite3BtreeClearCursor(p); p->eState = CURSOR_FAULT; p->skipNext = errCode; for(i=0; i<=p->iPage; i++){ releasePage(p->apPage[i]); p->apPage[i] = 0; } } sqlite3BtreeLeave(pBtree); } |
︙ | ︙ | |||
2912 2913 2914 2915 2916 2917 2918 | assert( TRANS_WRITE==pBt->inTransaction ); rc2 = sqlite3PagerRollback(pBt->pPager); if( rc2!=SQLITE_OK ){ rc = rc2; } /* The rollback may have destroyed the pPage1->aData value. So | | | < < < | < < < < < < < < < < | 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 | assert( TRANS_WRITE==pBt->inTransaction ); rc2 = sqlite3PagerRollback(pBt->pPager); if( rc2!=SQLITE_OK ){ rc = rc2; } /* The rollback may have destroyed the pPage1->aData value. So ** call btreeGetPage() on page 1 again to make ** sure pPage1->aData is set correctly. */ if( btreeGetPage(pBt, 1, &pPage1, 0)==SQLITE_OK ){ releasePage(pPage1); } assert( countWriteCursors(pBt)==0 ); pBt->inTransaction = TRANS_READ; } btreeEndTransaction(p); sqlite3BtreeLeave(p); return rc; } /* ** Start a statement subtransaction. The subtransaction can can be rolled ** back independently of the main transaction. You must start a transaction |
︙ | ︙ | |||
3010 3011 3012 3013 3014 3015 3016 | sqlite3BtreeLeave(p); } return rc; } /* ** Create a new cursor for the BTree whose root is on the page | | > | > | 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 | sqlite3BtreeLeave(p); } return rc; } /* ** Create a new cursor for the BTree whose root is on the page ** iTable. If a read-only cursor is requested, it is assumed that ** the caller already has at least a read-only transaction open ** on the database already. If a write-cursor is requested, then ** the caller is assumed to have an open write transaction. ** ** If wrFlag==0, then the cursor can only be used for reading. ** If wrFlag==1, then the cursor can be used for reading or for ** writing if other conditions for writing are also met. These ** are the conditions that must be met in order for writing to ** be allowed: ** |
︙ | ︙ | |||
3045 3046 3047 3048 3049 3050 3051 | 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 */ ){ | < < | < < < < | > > > > > | < < < | < | > > | < < < | < < < | | | | < < < < | < | < < > > < < < < < < | 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 | 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 */ assert( sqlite3BtreeHoldsMutex(p) ); assert( wrFlag==0 || wrFlag==1 ); /* 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+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 ); if( NEVER(wrFlag && pBt->readOnly) ){ return SQLITE_READONLY; } if( iTable==1 && pagerPagecount(pBt)==0 ){ return SQLITE_EMPTY; } /* 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->wrFlag = (u8)wrFlag; pCur->pNext = pBt->pCursor; if( pCur->pNext ){ pCur->pNext->pPrev = pCur; } pBt->pCursor = pCur; pCur->eState = CURSOR_INVALID; pCur->cachedRowid = 0; 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 */ |
︙ | ︙ | |||
3192 3193 3194 3195 3196 3197 3198 | invalidateOverflowCache(pCur); /* sqlite3_free(pCur); */ sqlite3BtreeLeave(pBtree); } return SQLITE_OK; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | > > > > > > > > > > > > > > > < < < < | | | | | | | < | | > > > > > | < < > > < < < < | < < < < | | < < | | 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 | invalidateOverflowCache(pCur); /* sqlite3_free(pCur); */ sqlite3BtreeLeave(pBtree); } return SQLITE_OK; } /* ** Make sure the BtCursor* given in the argument has a valid ** BtCursor.info structure. If it is not already valid, call ** btreeParseCell() to fill it in. ** ** BtCursor.info is a cache of the information in the current cell. ** Using this cache reduces the number of calls to btreeParseCell(). ** ** 2007-06-25: There is a bug in some versions of MSVC that cause the ** compiler to crash when getCellInfo() is implemented as a macro. ** But there is a measureable speed advantage to using the macro on gcc ** (when less compiler optimizations like -Os or -O0 are used and the ** compiler is not doing agressive inlining.) So we use a real function ** for MSVC and a macro for everything else. Ticket #2457. */ #ifndef NDEBUG static void assertCellInfo(BtCursor *pCur){ CellInfo info; int iPage = pCur->iPage; memset(&info, 0, sizeof(info)); btreeParseCell(pCur->apPage[iPage], pCur->aiIdx[iPage], &info); assert( memcmp(&info, &pCur->info, sizeof(info))==0 ); } #else #define assertCellInfo(x) #endif #ifdef _MSC_VER /* Use a real function in MSVC to work around bugs in that compiler. */ static void getCellInfo(BtCursor *pCur){ if( pCur->info.nSize==0 ){ int iPage = pCur->iPage; btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); pCur->validNKey = 1; }else{ assertCellInfo(pCur); } } #else /* if not _MSC_VER */ /* Use a macro in all other compilers so that the function is inlined */ #define getCellInfo(pCur) \ if( pCur->info.nSize==0 ){ \ int iPage = pCur->iPage; \ btreeParseCell(pCur->apPage[iPage],pCur->aiIdx[iPage],&pCur->info); \ pCur->validNKey = 1; \ }else{ \ assertCellInfo(pCur); \ } #endif /* _MSC_VER */ #ifndef NDEBUG /* The next routine used only within assert() statements */ /* ** Return true if the given BtCursor is valid. A valid cursor is one ** that is currently pointing to a row in a (non-empty) table. ** This is a verification routine is used only within assert() statements. */ int sqlite3BtreeCursorIsValid(BtCursor *pCur){ return pCur && pCur->eState==CURSOR_VALID; } #endif /* NDEBUG */ /* ** Set *pSize to the size of the buffer needed to hold the value of ** the key for the current entry. If the cursor is not pointing ** to a valid entry, *pSize is set to 0. ** ** For a table with the INTKEY flag set, this routine returns the key ** itself, not the number of bytes in the key. ** ** The caller must position the cursor prior to invoking this routine. ** ** This routine cannot fail. It always returns SQLITE_OK. */ int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID ); if( pCur->eState!=CURSOR_VALID ){ *pSize = 0; }else{ getCellInfo(pCur); *pSize = pCur->info.nKey; } return SQLITE_OK; } /* ** Set *pSize to the number of bytes of data in the entry the ** cursor currently points to. ** ** The caller must guarantee that the cursor is pointing to a non-NULL ** valid entry. In other words, the calling procedure must guarantee ** that the cursor has Cursor.eState==CURSOR_VALID. ** ** Failure is not possible. This function always returns SQLITE_OK. ** It might just as well be a procedure (returning void) but we continue ** to return an integer result code for historical reasons. */ int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); getCellInfo(pCur); *pSize = pCur->info.nData; return SQLITE_OK; } /* ** Given the page number of an overflow page in the database (parameter ** ovfl), this function finds the page number of the next page in the ** linked list of overflow pages. If possible, it uses the auto-vacuum ** pointer-map data instead of reading the content of page ovfl to do so. |
︙ | ︙ | |||
3344 3345 3346 3347 3348 3349 3350 | ** to page number pOvfl was obtained, then *ppPage is set to point to that ** reference. It is the responsibility of the caller to call releasePage() ** on *ppPage to free the reference. In no reference was obtained (because ** the pointer-map was used to obtain the value for *pPgnoNext), then ** *ppPage is set to zero. */ static int getOverflowPage( | | | | 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 | ** to page number pOvfl was obtained, then *ppPage is set to point to that ** reference. It is the responsibility of the caller to call releasePage() ** on *ppPage to free the reference. In no reference was obtained (because ** the pointer-map was used to obtain the value for *pPgnoNext), then ** *ppPage is set to zero. */ static int getOverflowPage( BtShared *pBt, /* The database file */ Pgno ovfl, /* Current overflow page number */ MemPage **ppPage, /* OUT: MemPage handle (may be NULL) */ Pgno *pPgnoNext /* OUT: Next overflow page number */ ){ Pgno next = 0; MemPage *pPage = 0; int rc = SQLITE_OK; |
︙ | ︙ | |||
3382 3383 3384 3385 3386 3387 3388 3389 | next = iGuess; rc = SQLITE_DONE; } } } #endif if( rc==SQLITE_OK ){ | > | | | | 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 | next = iGuess; rc = SQLITE_DONE; } } } #endif assert( next==0 || rc==SQLITE_DONE ); if( rc==SQLITE_OK ){ rc = btreeGetPage(pBt, ovfl, &pPage, 0); assert( rc==SQLITE_OK || pPage==0 ); if( rc==SQLITE_OK ){ next = get4byte(pPage->aData); } } *pPgnoNext = next; if( ppPage ){ *ppPage = pPage; |
︙ | ︙ | |||
3441 3442 3443 3444 3445 3446 3447 | ** parameter is 0, this is a read operation (data copied into ** buffer pBuf). If it is non-zero, a write (data copied from ** buffer pBuf). ** ** A total of "amt" bytes are read or written beginning at "offset". ** Data is read to or from the buffer pBuf. ** | | < | < | 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 | ** parameter is 0, this is a read operation (data copied into ** buffer pBuf). If it is non-zero, a write (data copied from ** buffer pBuf). ** ** A total of "amt" bytes are read or written beginning at "offset". ** Data is read to or from the buffer pBuf. ** ** The content being read or written might appear on the main page ** or be scattered out on multiple overflow pages. ** ** If the BtCursor.isIncrblobHandle flag is set, and the current ** cursor entry uses one or more overflow pages, this function ** allocates space for and lazily popluates the overflow page-list ** cache array (BtCursor.aOverflow). Subsequent calls use this ** cache to make seeking to the supplied offset more efficient. ** |
︙ | ︙ | |||
3466 3467 3468 3469 3470 3471 3472 | ** * Creating a table (may require moving an overflow page). */ static int accessPayload( BtCursor *pCur, /* Cursor pointing to entry to read from */ u32 offset, /* Begin reading this far into payload */ u32 amt, /* Read this many bytes */ unsigned char *pBuf, /* Write the bytes into this buffer */ | < < < < | | 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 | ** * Creating a table (may require moving an overflow page). */ static int accessPayload( BtCursor *pCur, /* Cursor pointing to entry to read from */ u32 offset, /* Begin reading this far into payload */ u32 amt, /* Read this many bytes */ unsigned char *pBuf, /* Write the bytes into this buffer */ int eOp /* zero to read. non-zero to write. */ ){ unsigned char *aPayload; int rc = SQLITE_OK; u32 nKey; int iIdx = 0; MemPage *pPage = pCur->apPage[pCur->iPage]; /* Btree page of current entry */ BtShared *pBt = pCur->pBt; /* Btree this cursor belongs to */ assert( pPage ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->aiIdx[pCur->iPage]<pPage->nCell ); assert( cursorHoldsMutex(pCur) ); getCellInfo(pCur); aPayload = pCur->info.pCell + pCur->info.nHeader; nKey = (pPage->intKey ? 0 : (int)pCur->info.nKey); if( NEVER(offset+amt > nKey+pCur->info.nData) || &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] ){ /* Trying to read or write past the end of the data is an error */ return SQLITE_CORRUPT_BKPT; } /* Check if data must be read/written to/from the btree page itself. */ |
︙ | ︙ | |||
3526 3527 3528 3529 3530 3531 3532 | ** 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). */ if( pCur->isIncrblobHandle && !pCur->aOverflow ){ int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize; pCur->aOverflow = (Pgno *)sqlite3MallocZero(sizeof(Pgno)*nOvfl); | > > | | 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 | ** 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). */ if( pCur->isIncrblobHandle && !pCur->aOverflow ){ int nOvfl = (pCur->info.nPayload-pCur->info.nLocal+ovflSize-1)/ovflSize; pCur->aOverflow = (Pgno *)sqlite3MallocZero(sizeof(Pgno)*nOvfl); /* nOvfl is always positive. If it were zero, fetchPayload would have ** been used instead of this routine. */ if( ALWAYS(nOvfl) && !pCur->aOverflow ){ rc = SQLITE_NOMEM; } } /* If the overflow page-list cache has been allocated and the ** entry for the first required overflow page is valid, skip ** directly to it. |
︙ | ︙ | |||
3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 | return rc; } /* ** Read part of the key associated with cursor pCur. Exactly ** "amt" bytes will be transfered into pBuf[]. The transfer ** begins at "offset". ** ** Return SQLITE_OK on success or an error code if anything goes ** wrong. An error is returned if "offset+amt" is larger than ** the available payload. */ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ | > > > < < < < | | < < < | | < < | 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 | return rc; } /* ** Read part of the key associated with cursor pCur. Exactly ** "amt" bytes will be transfered into pBuf[]. The transfer ** begins at "offset". ** ** The caller must ensure that pCur is pointing to a valid row ** in the table. ** ** Return SQLITE_OK on success or an error code if anything goes ** wrong. An error is returned if "offset+amt" is larger than ** the available payload. */ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] ); assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell ); return accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0); } /* ** Read part of the data associated with cursor pCur. Exactly ** "amt" bytes will be transfered into pBuf[]. The transfer ** begins at "offset". ** |
︙ | ︙ | |||
3645 3646 3647 3648 3649 3650 3651 | assert( cursorHoldsMutex(pCur) ); rc = restoreCursorPosition(pCur); if( rc==SQLITE_OK ){ assert( pCur->eState==CURSOR_VALID ); assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] ); assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell ); | | | 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 | assert( cursorHoldsMutex(pCur) ); rc = restoreCursorPosition(pCur); if( rc==SQLITE_OK ){ assert( pCur->eState==CURSOR_VALID ); assert( pCur->iPage>=0 && pCur->apPage[pCur->iPage] ); assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell ); rc = accessPayload(pCur, offset, amt, pBuf, 0); } return rc; } /* ** Return a pointer to payload information from the entry that the ** pCur cursor is pointing to. The pointer is to the beginning of |
︙ | ︙ | |||
3684 3685 3686 3687 3688 3689 3690 | u32 nLocal; assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]); assert( pCur->eState==CURSOR_VALID ); assert( cursorHoldsMutex(pCur) ); pPage = pCur->apPage[pCur->iPage]; assert( pCur->aiIdx[pCur->iPage]<pPage->nCell ); | > > | > | < < | 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 | u32 nLocal; assert( pCur!=0 && pCur->iPage>=0 && pCur->apPage[pCur->iPage]); assert( pCur->eState==CURSOR_VALID ); assert( cursorHoldsMutex(pCur) ); pPage = pCur->apPage[pCur->iPage]; assert( pCur->aiIdx[pCur->iPage]<pPage->nCell ); if( NEVER(pCur->info.nSize==0) ){ btreeParseCell(pCur->apPage[pCur->iPage], pCur->aiIdx[pCur->iPage], &pCur->info); } aPayload = pCur->info.pCell; aPayload += pCur->info.nHeader; if( pPage->intKey ){ nKey = 0; }else{ nKey = (int)pCur->info.nKey; } if( skipKey ){ aPayload += nKey; nLocal = pCur->info.nLocal - nKey; }else{ nLocal = pCur->info.nLocal; assert( nLocal<=nKey ); } *pAmt = nLocal; return aPayload; } /* |
︙ | ︙ | |||
3721 3722 3723 3724 3725 3726 3727 3728 3729 | ** Hence, a mutex on the BtShared should be held prior to calling ** this routine. ** ** These routines is used to get quick access to key and data ** in the common case where no overflow pages are used. */ const void *sqlite3BtreeKeyFetch(BtCursor *pCur, int *pAmt){ assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( cursorHoldsMutex(pCur) ); | > | | | > | | | > > > > > | 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 | ** Hence, a mutex on the BtShared should be held prior to calling ** this routine. ** ** These routines is used to get quick access to key and data ** in the common case where no overflow pages are used. */ const void *sqlite3BtreeKeyFetch(BtCursor *pCur, int *pAmt){ const void *p = 0; assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( cursorHoldsMutex(pCur) ); if( ALWAYS(pCur->eState==CURSOR_VALID) ){ p = (const void*)fetchPayload(pCur, pAmt, 0); } return p; } const void *sqlite3BtreeDataFetch(BtCursor *pCur, int *pAmt){ const void *p = 0; assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( cursorHoldsMutex(pCur) ); if( ALWAYS(pCur->eState==CURSOR_VALID) ){ p = (const void*)fetchPayload(pCur, pAmt, 1); } return p; } /* ** Move the cursor down to a new child page. The newPgno argument is the ** page number of the child page to move to. ** ** 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){ int rc; int i = pCur->iPage; MemPage *pNewPage; BtShared *pBt = pCur->pBt; |
︙ | ︙ | |||
3762 3763 3764 3765 3766 3767 3768 | if( rc ) return rc; pCur->apPage[i+1] = pNewPage; pCur->aiIdx[i+1] = 0; pCur->iPage++; pCur->info.nSize = 0; pCur->validNKey = 0; | | | 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 | if( rc ) return rc; pCur->apPage[i+1] = pNewPage; pCur->aiIdx[i+1] = 0; pCur->iPage++; pCur->info.nSize = 0; pCur->validNKey = 0; if( pNewPage->nCell<1 || pNewPage->intKey!=pCur->apPage[i]->intKey ){ return SQLITE_CORRUPT_BKPT; } return SQLITE_OK; } #ifndef NDEBUG /* |
︙ | ︙ | |||
3796 3797 3798 3799 3800 3801 3802 | ** Move the cursor up to the parent page. ** ** pCur->idx is set to the cell index that contains the pointer ** to the page we are coming from. If we are coming from the ** right-most child page then pCur->idx is set to one more than ** the largest cell index. */ | | | > > > > > > > > > > > > > > > > > > > | > < | | > | > > > > > > > | > > > > > > > > > | < < | 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 | ** Move the cursor up to the parent page. ** ** pCur->idx is set to the cell index that contains the pointer ** to the page we are coming from. If we are coming from the ** right-most child page then pCur->idx is set to one more than ** the largest cell index. */ static void moveToParent(BtCursor *pCur){ assert( cursorHoldsMutex(pCur) ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->iPage>0 ); assert( pCur->apPage[pCur->iPage] ); assertParentIndex( pCur->apPage[pCur->iPage-1], pCur->aiIdx[pCur->iPage-1], pCur->apPage[pCur->iPage]->pgno ); releasePage(pCur->apPage[pCur->iPage]); pCur->iPage--; pCur->info.nSize = 0; pCur->validNKey = 0; } /* ** Move the cursor to point to the root page of its b-tree structure. ** ** If the table has a virtual root page, then the cursor is moved to point ** to the virtual root page instead of the actual root page. A table has a ** virtual root page when the actual root page contains no cells and a ** single child page. This can only happen with the table rooted at page 1. ** ** If the b-tree structure is empty, the cursor state is set to ** CURSOR_INVALID. Otherwise, the cursor is set to point to the first ** cell located on the root (or virtual root) page and the cursor state ** is set to CURSOR_VALID. ** ** If this function returns successfully, it may be assumed that the ** page-header flags indicate that the [virtual] root-page is the expected ** kind of b-tree page (i.e. if when opening the cursor the caller did not ** specify a KeyInfo structure the flags byte is set to 0x05 or 0x0D, ** indicating a table b-tree, or if the caller did specify a KeyInfo ** structure the flags byte is set to 0x02 or 0x0A, indicating an index ** b-tree). */ static int moveToRoot(BtCursor *pCur){ MemPage *pRoot; int rc = SQLITE_OK; Btree *p = pCur->pBtree; BtShared *pBt = p->pBt; assert( cursorHoldsMutex(pCur) ); assert( CURSOR_INVALID < CURSOR_REQUIRESEEK ); assert( CURSOR_VALID < CURSOR_REQUIRESEEK ); assert( CURSOR_FAULT > CURSOR_REQUIRESEEK ); if( pCur->eState>=CURSOR_REQUIRESEEK ){ if( pCur->eState==CURSOR_FAULT ){ assert( pCur->skipNext!=SQLITE_OK ); return pCur->skipNext; } sqlite3BtreeClearCursor(pCur); } if( pCur->iPage>=0 ){ int i; for(i=1; i<=pCur->iPage; i++){ releasePage(pCur->apPage[i]); } pCur->iPage = 0; }else{ rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->apPage[0]); if( rc!=SQLITE_OK ){ pCur->eState = CURSOR_INVALID; return rc; } pCur->iPage = 0; /* If pCur->pKeyInfo is not NULL, then the caller that opened this cursor ** 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. */ assert( pCur->apPage[0]->intKey==1 || pCur->apPage[0]->intKey==0 ); if( (pCur->pKeyInfo==0)!=pCur->apPage[0]->intKey ){ return SQLITE_CORRUPT_BKPT; } } /* Assert that the root page is of the correct type. This must be the ** case as the call to this function that loaded the root-page (either ** this call or a previous invocation) would have detected corruption ** if the assumption were not true, and it is not possible for the flags ** byte to have been modified while this cursor is holding a reference ** to the page. */ pRoot = pCur->apPage[0]; assert( pRoot->pgno==pCur->pgnoRoot ); assert( pRoot->isInit && (pCur->pKeyInfo==0)==pRoot->intKey ); pCur->aiIdx[0] = 0; pCur->info.nSize = 0; pCur->atLast = 0; pCur->validNKey = 0; if( pRoot->nCell==0 && !pRoot->leaf ){ Pgno subpage; if( pRoot->pgno!=1 ) return SQLITE_CORRUPT_BKPT; subpage = get4byte(&pRoot->aData[pRoot->hdrOffset+8]); pCur->eState = CURSOR_VALID; rc = moveToChild(pCur, subpage); }else{ pCur->eState = ((pRoot->nCell>0)?CURSOR_VALID:CURSOR_INVALID); } return rc; } |
︙ | ︙ | |||
4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 | int biasRight, /* If true, bias the search to the high end */ int *pRes /* Write search results here */ ){ int rc; assert( cursorHoldsMutex(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); /* If the cursor is already positioned at the point we are trying ** to move to, then just return without doing any work */ if( pCur->eState==CURSOR_VALID && pCur->validNKey && pCur->apPage[0]->intKey ){ if( pCur->info.nKey==intKey ){ | > > | 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 | int biasRight, /* If true, bias the search to the high end */ int *pRes /* Write search results here */ ){ int rc; assert( cursorHoldsMutex(pCur) ); assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) ); assert( pRes ); assert( (pIdxKey==0)==(pCur->pKeyInfo==0) ); /* If the cursor is already positioned at the point we are trying ** to move to, then just return without doing any work */ if( pCur->eState==CURSOR_VALID && pCur->validNKey && pCur->apPage[0]->intKey ){ if( pCur->info.nKey==intKey ){ |
︙ | ︙ | |||
4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 | rc = moveToRoot(pCur); if( rc ){ return rc; } assert( pCur->apPage[pCur->iPage] ); assert( pCur->apPage[pCur->iPage]->isInit ); if( pCur->eState==CURSOR_INVALID ){ *pRes = -1; assert( pCur->apPage[pCur->iPage]->nCell==0 ); return SQLITE_OK; } assert( pCur->apPage[0]->intKey || pIdxKey ); for(;;){ int lwr, upr; Pgno chldPg; MemPage *pPage = pCur->apPage[pCur->iPage]; | > > | > > > > > > > > < < < < | 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 | rc = moveToRoot(pCur); if( rc ){ return rc; } assert( pCur->apPage[pCur->iPage] ); assert( pCur->apPage[pCur->iPage]->isInit ); assert( pCur->apPage[pCur->iPage]->nCell>0 || pCur->eState==CURSOR_INVALID ); if( pCur->eState==CURSOR_INVALID ){ *pRes = -1; assert( pCur->apPage[pCur->iPage]->nCell==0 ); return SQLITE_OK; } assert( pCur->apPage[0]->intKey || pIdxKey ); for(;;){ int lwr, upr; Pgno chldPg; MemPage *pPage = pCur->apPage[pCur->iPage]; int c; /* 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; if( biasRight ){ pCur->aiIdx[pCur->iPage] = (u16)upr; }else{ pCur->aiIdx[pCur->iPage] = (u16)((upr+lwr)/2); } for(;;){ int idx = pCur->aiIdx[pCur->iPage]; /* Index of current cell in pPage */ |
︙ | ︙ | |||
4118 4119 4120 4121 4122 4123 4124 | }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. */ void *pCellKey; u8 * const pCellBody = pCell - pPage->childPtrSize; | | | > > > > < | 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 | }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. */ void *pCellKey; u8 * const pCellBody = pCell - pPage->childPtrSize; btreeParseCellPtr(pPage, pCellBody, &pCur->info); nCell = (int)pCur->info.nKey; pCellKey = sqlite3Malloc( nCell ); if( pCellKey==0 ){ rc = SQLITE_NOMEM; goto moveto_finish; } rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0); if( rc ){ sqlite3_free(pCellKey); goto moveto_finish; } c = sqlite3VdbeRecordCompare(nCell, pCellKey, pIdxKey); sqlite3_free(pCellKey); } } if( c==0 ){ if( pPage->intKey && !pPage->leaf ){ lwr = idx; upr = lwr - 1; break; |
︙ | ︙ | |||
4163 4164 4165 4166 4167 4168 4169 | }else if( lwr>=pPage->nCell ){ chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]); }else{ chldPg = get4byte(findCell(pPage, lwr)); } if( chldPg==0 ){ assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell ); | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | }else if( lwr>=pPage->nCell ){ chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]); }else{ chldPg = get4byte(findCell(pPage, lwr)); } if( chldPg==0 ){ assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell ); *pRes = c; rc = SQLITE_OK; goto moveto_finish; } pCur->aiIdx[pCur->iPage] = (u16)lwr; pCur->info.nSize = 0; pCur->validNKey = 0; rc = moveToChild(pCur, chldPg); if( rc ) goto moveto_finish; } moveto_finish: return rc; } /* ** Return TRUE if the cursor is not pointing at an entry of the table. ** |
︙ | ︙ | |||
4246 4247 4248 4249 4250 4251 4252 | return rc; } assert( pRes!=0 ); if( CURSOR_INVALID==pCur->eState ){ *pRes = 1; return SQLITE_OK; } | | | | | 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 | return rc; } assert( pRes!=0 ); if( CURSOR_INVALID==pCur->eState ){ *pRes = 1; return SQLITE_OK; } if( pCur->skipNext>0 ){ pCur->skipNext = 0; *pRes = 0; return SQLITE_OK; } pCur->skipNext = 0; pPage = pCur->apPage[pCur->iPage]; idx = ++pCur->aiIdx[pCur->iPage]; assert( pPage->isInit ); assert( idx<=pPage->nCell ); pCur->info.nSize = 0; |
︙ | ︙ | |||
4274 4275 4276 4277 4278 4279 4280 | } do{ if( pCur->iPage==0 ){ *pRes = 1; pCur->eState = CURSOR_INVALID; return SQLITE_OK; } | | | 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 | } do{ if( pCur->iPage==0 ){ *pRes = 1; pCur->eState = CURSOR_INVALID; return SQLITE_OK; } moveToParent(pCur); pPage = pCur->apPage[pCur->iPage]; }while( pCur->aiIdx[pCur->iPage]>=pPage->nCell ); *pRes = 0; if( pPage->intKey ){ rc = sqlite3BtreeNext(pCur, pRes); }else{ rc = SQLITE_OK; |
︙ | ︙ | |||
4314 4315 4316 4317 4318 4319 4320 | return rc; } pCur->atLast = 0; if( CURSOR_INVALID==pCur->eState ){ *pRes = 1; return SQLITE_OK; } | | | | | | 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 | return rc; } pCur->atLast = 0; if( CURSOR_INVALID==pCur->eState ){ *pRes = 1; return SQLITE_OK; } if( pCur->skipNext<0 ){ pCur->skipNext = 0; *pRes = 0; return SQLITE_OK; } pCur->skipNext = 0; pPage = pCur->apPage[pCur->iPage]; assert( pPage->isInit ); if( !pPage->leaf ){ int idx = pCur->aiIdx[pCur->iPage]; rc = moveToChild(pCur, get4byte(findCell(pPage, idx))); if( rc ){ return rc; } rc = moveToRightmost(pCur); }else{ while( pCur->aiIdx[pCur->iPage]==0 ){ if( pCur->iPage==0 ){ pCur->eState = CURSOR_INVALID; *pRes = 1; return SQLITE_OK; } moveToParent(pCur); } pCur->info.nSize = 0; pCur->validNKey = 0; pCur->aiIdx[pCur->iPage]--; pPage = pCur->apPage[pCur->iPage]; if( pPage->intKey && !pPage->leaf ){ |
︙ | ︙ | |||
4394 4395 4396 4397 4398 4399 4400 | MemPage *pPrevTrunk = 0; Pgno mxPage; /* Total size of the database file */ assert( sqlite3_mutex_held(pBt->mutex) ); pPage1 = pBt->pPage1; mxPage = pagerPagecount(pBt); n = get4byte(&pPage1->aData[36]); | > | | 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 | MemPage *pPrevTrunk = 0; Pgno mxPage; /* Total size of the database file */ assert( sqlite3_mutex_held(pBt->mutex) ); pPage1 = pBt->pPage1; mxPage = pagerPagecount(pBt); 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. */ Pgno iTrunk; u8 searchList = 0; /* If the free-list must be searched for 'nearby' */ |
︙ | ︙ | |||
4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 | do { pPrevTrunk = pTrunk; if( pPrevTrunk ){ iTrunk = get4byte(&pPrevTrunk->aData[0]); }else{ iTrunk = get4byte(&pPage1->aData[32]); } if( iTrunk>mxPage ){ rc = SQLITE_CORRUPT_BKPT; }else{ | > | | 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 | do { pPrevTrunk = pTrunk; if( pPrevTrunk ){ iTrunk = get4byte(&pPrevTrunk->aData[0]); }else{ iTrunk = get4byte(&pPage1->aData[32]); } testcase( iTrunk==mxPage ); if( iTrunk>mxPage ){ rc = SQLITE_CORRUPT_BKPT; }else{ rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0); } if( rc ){ pTrunk = 0; goto end_allocate_page; } k = get4byte(&pTrunk->aData[4]); |
︙ | ︙ | |||
4496 4497 4498 4499 4500 4501 4502 | */ MemPage *pNewTrunk; Pgno iNewTrunk = get4byte(&pTrunk->aData[8]); if( iNewTrunk>mxPage ){ rc = SQLITE_CORRUPT_BKPT; goto end_allocate_page; } | > | | 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 | */ MemPage *pNewTrunk; Pgno iNewTrunk = get4byte(&pTrunk->aData[8]); if( iNewTrunk>mxPage ){ rc = SQLITE_CORRUPT_BKPT; goto end_allocate_page; } testcase( iNewTrunk==mxPage ); rc = btreeGetPage(pBt, iNewTrunk, &pNewTrunk, 0); if( rc!=SQLITE_OK ){ goto end_allocate_page; } rc = sqlite3PagerWrite(pNewTrunk->pDbPage); if( rc!=SQLITE_OK ){ releasePage(pNewTrunk); goto end_allocate_page; |
︙ | ︙ | |||
4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 | } } }else{ closest = 0; } iPage = get4byte(&aData[8+closest*4]); if( iPage>mxPage ){ rc = SQLITE_CORRUPT_BKPT; goto end_allocate_page; } if( !searchList || iPage==nearby ){ int noContent; | > > < < < < < < < | | 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 | } } }else{ closest = 0; } iPage = get4byte(&aData[8+closest*4]); testcase( iPage==mxPage ); if( iPage>mxPage ){ rc = SQLITE_CORRUPT_BKPT; goto end_allocate_page; } testcase( iPage==mxPage ); if( !searchList || iPage==nearby ){ int noContent; *pPgno = iPage; TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d" ": %d more free pages\n", *pPgno, closest+1, k, pTrunk->pgno, n-1)); if( closest<k-1 ){ memcpy(&aData[8+closest*4], &aData[4+k*4], 4); } put4byte(&aData[4], k-1); assert( sqlite3PagerIswriteable(pTrunk->pDbPage) ); noContent = !btreeGetHasContent(pBt, *pPgno); rc = btreeGetPage(pBt, *pPgno, ppPage, noContent); if( rc==SQLITE_OK ){ rc = sqlite3PagerWrite((*ppPage)->pDbPage); if( rc!=SQLITE_OK ){ releasePage(*ppPage); } } searchList = 0; |
︙ | ︙ | |||
4606 4607 4608 4609 4610 4611 4612 | /* If *pPgno refers to a pointer-map page, allocate two new pages ** at the end of the file instead of one. The first allocated page ** becomes a new pointer-map page, the second is used by the caller. */ MemPage *pPg = 0; TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", *pPgno)); assert( *pPgno!=PENDING_BYTE_PAGE(pBt) ); | | | | 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 | /* If *pPgno refers to a pointer-map page, allocate two new pages ** at the end of the file instead of one. The first allocated page ** becomes a new pointer-map page, the second is used by the caller. */ MemPage *pPg = 0; TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", *pPgno)); assert( *pPgno!=PENDING_BYTE_PAGE(pBt) ); rc = btreeGetPage(pBt, *pPgno, &pPg, 0); if( rc==SQLITE_OK ){ rc = sqlite3PagerWrite(pPg->pDbPage); releasePage(pPg); } if( rc ) return rc; (*pPgno)++; if( *pPgno==PENDING_BYTE_PAGE(pBt) ){ (*pPgno)++; } } #endif assert( *pPgno!=PENDING_BYTE_PAGE(pBt) ); rc = btreeGetPage(pBt, *pPgno, ppPage, 0); if( rc ) return rc; rc = sqlite3PagerWrite((*ppPage)->pDbPage); if( rc!=SQLITE_OK ){ releasePage(*ppPage); } TRACE(("ALLOCATE: %d from end of file\n", *pPgno)); } |
︙ | ︙ | |||
4685 4686 4687 4688 4689 4690 4691 | nFree = get4byte(&pPage1->aData[36]); put4byte(&pPage1->aData[36], nFree+1); #ifdef SQLITE_SECURE_DELETE /* If the SQLITE_SECURE_DELETE compile-time option is enabled, then ** always fully overwrite deleted information with zeros. */ | | | | | > | | | | 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 | nFree = get4byte(&pPage1->aData[36]); put4byte(&pPage1->aData[36], nFree+1); #ifdef SQLITE_SECURE_DELETE /* If the SQLITE_SECURE_DELETE compile-time option is enabled, then ** always fully overwrite deleted information with zeros. */ if( (!pPage && (rc = btreeGetPage(pBt, iPage, &pPage, 0))) || (rc = sqlite3PagerWrite(pPage->pDbPage)) ){ goto freepage_out; } memset(pPage->aData, 0, pPage->pBt->pageSize); #endif /* 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 ); if( nLeaf > (u32)pBt->usableSize/4 - 2 ){ rc = SQLITE_CORRUPT_BKPT; goto freepage_out; } if( nLeaf < (u32)pBt->usableSize/4 - 8 ){ /* In this case there is room on the trunk page to insert the page ** being freed as a new leaf. ** ** Note that the trunk page is not really full until it contains ** usableSize/4 - 2 entries, not usableSize/4 - 8 entries as we have ** coded. But due to a coding error in versions of SQLite prior to ** 3.6.0, databases with freelist trunk pages holding more than ** usableSize/4 - 8 entries will be reported as corrupt. In order ** to maintain backwards compatibility with older versions of SQLite, ** we will continue to restrict the number of entries to usableSize/4 - 8 ** for now. At some point in the future (once everyone has upgraded ** to 3.6.0 or later) we should consider fixing the conditional above ** to read "usableSize/4-2" instead of "usableSize/4-8". */ rc = sqlite3PagerWrite(pTrunk->pDbPage); if( rc==SQLITE_OK ){ put4byte(&pTrunk->aData[4], nLeaf+1); |
︙ | ︙ | |||
4759 4760 4761 4762 4763 4764 4765 | /* If control flows to this point, then it was not possible to add the ** the page being freed as a leaf page of the first trunk in the free-list. ** Possibly because the free-list is empty, or possibly because the ** first trunk in the free-list is full. Either way, the page being freed ** will become the new first trunk page in the free-list. */ | | > > | | | > | > | | 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 | /* If control flows to this point, then it was not possible to add the ** the page being freed as a leaf page of the first trunk in the free-list. ** Possibly because the free-list is empty, or possibly because the ** first trunk in the free-list is full. Either way, the page being freed ** will become the new first trunk page in the free-list. */ if( pPage==0 && SQLITE_OK!=(rc = btreeGetPage(pBt, iPage, &pPage, 0)) ){ goto freepage_out; } rc = sqlite3PagerWrite(pPage->pDbPage); if( rc!=SQLITE_OK ){ goto freepage_out; } put4byte(pPage->aData, iTrunk); put4byte(&pPage->aData[4], 0); put4byte(&pPage1->aData[32], iPage); TRACE(("FREE-PAGE: %d new trunk page replacing %d\n", pPage->pgno, iTrunk)); freepage_out: if( pPage ){ pPage->isInit = 0; } releasePage(pPage); releasePage(pTrunk); return rc; } 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. */ static int clearCell(MemPage *pPage, unsigned char *pCell){ BtShared *pBt = pPage->pBt; CellInfo info; Pgno ovflPgno; int rc; int nOvfl; u16 ovflPageSize; assert( sqlite3_mutex_held(pPage->pBt->mutex) ); btreeParseCellPtr(pPage, pCell, &info); if( info.iOverflow==0 ){ return SQLITE_OK; /* No overflow pages. Return without doing anything */ } ovflPgno = get4byte(&pCell[info.iOverflow]); assert( pBt->usableSize > 4 ); ovflPageSize = pBt->usableSize - 4; nOvfl = (info.nPayload - info.nLocal + ovflPageSize - 1)/ovflPageSize; |
︙ | ︙ | |||
4876 4877 4878 4879 4880 4881 4882 | } if( pPage->hasData ){ nHeader += putVarint(&pCell[nHeader], nData+nZero); }else{ nData = nZero = 0; } nHeader += putVarint(&pCell[nHeader], *(u64*)&nKey); | | | | | 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 | } if( pPage->hasData ){ nHeader += putVarint(&pCell[nHeader], nData+nZero); }else{ nData = nZero = 0; } nHeader += putVarint(&pCell[nHeader], *(u64*)&nKey); btreeParseCellPtr(pPage, pCell, &info); assert( info.nHeader==nHeader ); assert( info.nKey==nKey ); assert( info.nData==(u32)(nData+nZero) ); /* Fill in the payload */ nPayload = nData + nZero; if( pPage->intKey ){ pSrc = pData; nSrc = nData; nData = 0; }else{ if( NEVER(nKey>0x7fffffff || pKey==0) ){ return SQLITE_CORRUPT_BKPT; } nPayload += (int)nKey; pSrc = pKey; nSrc = (int)nKey; } *pnSize = info.nSize; spaceLeft = info.nLocal; |
︙ | ︙ | |||
4926 4927 4928 4929 4930 4931 4932 | ** to the pointer-map. If we write nothing to this pointer-map slot, ** then the optimistic overflow chain processing in clearCell() ** may misinterpret the uninitialised values and delete the ** wrong pages from the database. */ if( pBt->autoVacuum && rc==SQLITE_OK ){ u8 eType = (pgnoPtrmap?PTRMAP_OVERFLOW2:PTRMAP_OVERFLOW1); | | | 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 | ** to the pointer-map. If we write nothing to this pointer-map slot, ** then the optimistic overflow chain processing in clearCell() ** may misinterpret the uninitialised values and delete the ** wrong pages from the database. */ if( pBt->autoVacuum && rc==SQLITE_OK ){ u8 eType = (pgnoPtrmap?PTRMAP_OVERFLOW2:PTRMAP_OVERFLOW1); ptrmapPut(pBt, pgnoOvfl, eType, pgnoPtrmap, &rc); if( rc ){ releasePage(pOvfl); } } #endif if( rc ){ releasePage(pToRelease); |
︙ | ︙ | |||
4995 4996 4997 4998 4999 5000 5001 | ** Remove the i-th cell from pPage. This routine effects pPage only. ** The cell content is not freed or deallocated. It is assumed that ** the cell content has been copied someplace else. This routine just ** removes the reference to the cell from pPage. ** ** "sz" must be the number of bytes in the cell. */ | | > > > | > | > | > | > | | < | | > < < > > | 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 | ** Remove the i-th cell from pPage. This routine effects pPage only. ** The cell content is not freed or deallocated. It is assumed that ** the cell content has been copied someplace else. This routine just ** removes the reference to the cell from pPage. ** ** "sz" must be the number of bytes in the cell. */ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){ int i; /* Loop counter */ int 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( sz==cellSize(pPage, idx) ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); data = pPage->aData; ptr = &data[pPage->cellOffset + 2*idx]; pc = get2byte(ptr); hdr = pPage->hdrOffset; testcase( pc==get2byte(&data[hdr+5]) ); testcase( pc+sz==pPage->pBt->usableSize ); if( pc < get2byte(&data[hdr+5]) || pc+sz > pPage->pBt->usableSize ){ *pRC = SQLITE_CORRUPT_BKPT; return; } rc = freeSpace(pPage, pc, sz); if( rc ){ *pRC = rc; return; } for(i=idx+1; i<pPage->nCell; i++, ptr+=2){ ptr[0] = ptr[2]; ptr[1] = ptr[3]; } pPage->nCell--; put2byte(&data[hdr+3], pPage->nCell); pPage->nFree += 2; } /* ** Insert a new cell on pPage at cell index "i". pCell points to the ** content of the cell. ** ** 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->aOvfl[] 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. ** ** If nSkip is non-zero, then do not copy the first nSkip bytes of the ** cell. The caller will overwrite them after this function returns. If ** nSkip is non-zero, then pCell may not point to an invalid memory location ** (but pCell+nSkip is always valid). */ 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; /* Where to write new cell content in data[] */ int j; /* Loop counter */ int end; /* First byte past the last cell pointer in data[] */ int ins; /* Index in data[] where new cell pointer is inserted */ int cellOffset; /* Address of first cell pointer in data[] */ u8 *data; /* The content of the whole page */ u8 *ptr; /* Used for moving information around in data[] */ int nSkip = (iChild ? 4 : 0); if( *pRC ) return; assert( i>=0 && i<=pPage->nCell+pPage->nOverflow ); assert( pPage->nCell<=MX_CELL(pPage->pBt) && MX_CELL(pPage->pBt)<=5460 ); assert( pPage->nOverflow<=ArraySize(pPage->aOvfl) ); assert( sz==cellSizePtr(pPage, pCell) ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); if( pPage->nOverflow || sz+2>pPage->nFree ){ |
︙ | ︙ | |||
5084 5085 5086 5087 5088 5089 5090 | j = pPage->nOverflow++; assert( j<(int)(sizeof(pPage->aOvfl)/sizeof(pPage->aOvfl[0])) ); pPage->aOvfl[j].pCell = pCell; pPage->aOvfl[j].idx = (u16)i; }else{ int rc = sqlite3PagerWrite(pPage->pDbPage); if( rc!=SQLITE_OK ){ | > | < < | < | < | < < < < | > | < | < < | | | | < < | 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 | j = pPage->nOverflow++; assert( j<(int)(sizeof(pPage->aOvfl)/sizeof(pPage->aOvfl[0])) ); pPage->aOvfl[j].pCell = pCell; pPage->aOvfl[j].idx = (u16)i; }else{ int rc = sqlite3PagerWrite(pPage->pDbPage); if( rc!=SQLITE_OK ){ *pRC = rc; return; } assert( sqlite3PagerIswriteable(pPage->pDbPage) ); data = pPage->aData; cellOffset = pPage->cellOffset; end = cellOffset + 2*pPage->nCell; ins = cellOffset + 2*i; rc = allocateSpace(pPage, sz, &idx); if( rc ){ *pRC = rc; return; } /* The allocateSpace() routine guarantees the following two properties ** if it returns success */ assert( idx >= end+2 ); assert( idx+sz <= pPage->pBt->usableSize ); pPage->nCell++; pPage->nFree -= (u16)(2 + sz); memcpy(&data[idx+nSkip], pCell+nSkip, sz-nSkip); if( iChild ){ put4byte(&data[idx], iChild); } for(j=end, ptr=&data[j]; j>ins; j-=2, ptr-=2){ ptr[0] = ptr[-2]; ptr[1] = ptr[-1]; } put2byte(&data[ins], idx); put2byte(&data[pPage->hdrOffset+3], pPage->nCell); #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, pCell, pRC); } #endif } } /* ** Add a list of cells to a page. The page should be initially empty. ** The cells are guaranteed to fit on the page. */ static void assemblePage( |
︙ | ︙ | |||
5195 5196 5197 5198 5199 5200 5201 | #ifndef SQLITE_OMIT_QUICKBALANCE /* ** This version of balance() handles the common special case where ** a new entry is being inserted on the extreme right-end of the ** tree, in other words, when the new entry will become the largest ** entry in the tree. ** | | | 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 | #ifndef SQLITE_OMIT_QUICKBALANCE /* ** This version of balance() handles the common special case where ** a new entry is being inserted on the extreme right-end of the ** tree, in other words, when the new entry will become the largest ** entry in the tree. ** ** Instead of trying to balance the 3 right-most leaf pages, just add ** a new page to the right-hand side and put the one new entry in ** that page. This leaves the right side of the tree somewhat ** unbalanced. But odds are that we will be inserting new entries ** at the end soon afterwards so the nearly empty page will quickly ** fill up. On average. ** ** pPage is the leaf page which is the right-most page in the tree. |
︙ | ︙ | |||
5252 5253 5254 5255 5256 5257 5258 | ** 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 ){ | | | | | 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 | ** 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, pCell, &rc); } } /* Create a divider cell to insert into pParent. The divider cell ** consists of a 4-byte page number (the page number of pPage) and ** a variable length key value (which must be the same value as the ** largest key on pPage). |
︙ | ︙ | |||
5278 5279 5280 5281 5282 5283 5284 | pCell = findCell(pPage, pPage->nCell-1); pStop = &pCell[9]; while( (*(pCell++)&0x80) && pCell<pStop ); pStop = &pCell[9]; while( ((*(pOut++) = *(pCell++))&0x80) && pCell<pStop ); /* Insert the new divider cell into pParent. */ | | > | 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 | pCell = findCell(pPage, pPage->nCell-1); pStop = &pCell[9]; while( (*(pCell++)&0x80) && pCell<pStop ); pStop = &pCell[9]; while( ((*(pOut++) = *(pCell++))&0x80) && pCell<pStop ); /* Insert the new divider cell into pParent. */ 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); } |
︙ | ︙ | |||
5311 5312 5313 5314 5315 5316 5317 | assert( pPage->isInit ); for(j=0; j<pPage->nCell; j++){ CellInfo info; u8 *z; z = findCell(pPage, j); | | | 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 | assert( pPage->isInit ); for(j=0; j<pPage->nCell; j++){ CellInfo info; u8 *z; z = findCell(pPage, j); btreeParseCellPtr(pPage, z, &info); if( info.iOverflow ){ Pgno ovfl = get4byte(&z[info.iOverflow]); ptrmapGet(pBt, ovfl, &e, &n); assert( n==pPage->pgno && e==PTRMAP_OVERFLOW1 ); } if( !pPage->leaf ){ Pgno child = get4byte(z); |
︙ | ︙ | |||
5344 5345 5346 5347 5348 5349 5350 | ** parent page stored in the pointer map is page pTo. If pFrom contained ** any cells with overflow page pointers, then the corresponding pointer ** map entries are also updated so that the parent page is page pTo. ** ** If pFrom is currently carrying any overflow cells (entries in the ** MemPage.aOvfl[] array), they are not copied to pTo. ** | | | > | | | | | | | | > | | | | | | | | | | | | | | | | | | > | | | < > | 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 | ** parent page stored in the pointer map is page pTo. If pFrom contained ** any cells with overflow page pointers, then the corresponding pointer ** map entries are also updated so that the parent page is page pTo. ** ** If pFrom is currently carrying any overflow cells (entries in the ** MemPage.aOvfl[] array), they are not copied to pTo. ** ** Before returning, page pTo is reinitialized using btreeInitPage(). ** ** The performance of this function is not critical. It is only used by ** the balance_shallower() and balance_deeper() procedures, neither of ** which are called often under normal circumstances. */ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){ if( (*pRC)==SQLITE_OK ){ BtShared * const pBt = pFrom->pBt; u8 * const aFrom = pFrom->aData; u8 * const aTo = pTo->aData; int const iFromHdr = pFrom->hdrOffset; int const iToHdr = ((pTo->pgno==1) ? 100 : 0); TESTONLY(int rc;) int iData; assert( pFrom->isInit ); assert( pFrom->nFree>=iToHdr ); assert( get2byte(&aFrom[iFromHdr+5])<=pBt->usableSize ); /* Copy the b-tree node content from page pFrom to page pTo. */ iData = get2byte(&aFrom[iFromHdr+5]); memcpy(&aTo[iData], &aFrom[iData], pBt->usableSize-iData); memcpy(&aTo[iToHdr], &aFrom[iFromHdr], pFrom->cellOffset + 2*pFrom->nCell); /* Reinitialize page pTo so that the contents of the MemPage structure ** match the new data. The initialization of pTo "cannot" fail, as the ** data copied from pFrom is known to be valid. */ pTo->isInit = 0; TESTONLY(rc = ) btreeInitPage(pTo); assert( rc==SQLITE_OK ); /* 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 ** (hereafter "the page") and up to 2 siblings so that all pages have about the ** same amount of free space. Usually a single sibling on either side of the ** page are used in the balancing, though both siblings might come from one |
︙ | ︙ | |||
5412 5413 5414 5415 5416 5417 5418 | ** balancing routine to fix this problem (see the balance() routine). ** ** If this routine fails for any reason, it might leave the database ** in a corrupted state. So if this routine fails, the database should ** be rolled back. ** ** The third argument to this function, aOvflSpace, is a pointer to a | | | | | 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 | ** balancing routine to fix this problem (see the balance() routine). ** ** If this routine fails for any reason, it might leave the database ** in a corrupted state. So if this routine fails, the database should ** be rolled back. ** ** The third argument to this function, aOvflSpace, is a pointer to a ** buffer big enough to hold one page. If while inserting cells into the parent ** page (pParent) the parent page becomes overfull, this buffer is ** used to store the parent's overflow cells. Because this function inserts ** a maximum of four divider cells into the parent page, and the maximum ** size of a cell stored within an internal node is always less than 1/4 ** of the page-size, the aOvflSpace[] buffer is guaranteed to be large ** enough for all overflow cells. ** ** If aOvflSpace is set to a null pointer, this function returns ** SQLITE_NOMEM. |
︙ | ︙ | |||
5468 5469 5470 5471 5472 5473 5474 | #if 0 TRACE(("BALANCE: begin page %d child of %d\n", pPage->pgno, pParent->pgno)); #endif /* 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 | | > | | > | 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 | #if 0 TRACE(("BALANCE: begin page %d child of %d\n", pPage->pgno, pParent->pgno)); #endif /* At this point pParent may have at most one overflow cell. And if ** this overflow cell is present, it must be the cell with ** index iParentIdx. This scenario comes about when this function ** is called (indirectly) from sqlite3BtreeDelete(). */ assert( pParent->nOverflow==0 || pParent->nOverflow==1 ); assert( pParent->nOverflow==0 || pParent->aOvfl[0].idx==iParentIdx ); if( !aOvflSpace ){ return SQLITE_NOMEM; } /* Find the sibling pages to balance. Also locate the cells in pParent ** that divide the siblings. An attempt is made to find NN siblings on ** either side of pPage. More siblings are taken from one side, however, ** if there are fewer than NN siblings on the other side. If pParent ** has NB or fewer children then all children of pParent are taken. ** ** This loop also drops the divider cells from the parent page. This ** way, the remainder of the function does not have to deal with any ** overflow cells in the parent page, since if any existed they will ** have already been removed. */ i = pParent->nOverflow + pParent->nCell; if( i<2 ){ nxDiv = 0; nOld = i+1; }else{ nOld = 3; if( iParentIdx==0 ){ |
︙ | ︙ | |||
5510 5511 5512 5513 5514 5515 5516 | }else{ pRight = findCell(pParent, i+nxDiv-pParent->nOverflow); } pgno = get4byte(pRight); while( 1 ){ rc = getAndInitPage(pBt, pgno, &apOld[i]); if( rc ){ | | | | 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 | }else{ pRight = findCell(pParent, i+nxDiv-pParent->nOverflow); } pgno = get4byte(pRight); while( 1 ){ rc = getAndInitPage(pBt, pgno, &apOld[i]); if( rc ){ memset(apOld, 0, (i+1)*sizeof(MemPage*)); goto balance_cleanup; } nMaxCells += 1+apOld[i]->nCell+apOld[i]->nOverflow; if( (i--)==0 ) break; if( i+nxDiv==pParent->aOvfl[0].idx && pParent->nOverflow ){ apDiv[i] = pParent->aOvfl[0].pCell; pgno = get4byte(apDiv[i]); szNew[i] = cellSizePtr(pParent, apDiv[i]); pParent->nOverflow = 0; }else{ apDiv[i] = findCell(pParent, i+nxDiv-pParent->nOverflow); pgno = get4byte(apDiv[i]); |
︙ | ︙ | |||
5542 5543 5544 5545 5546 5547 5548 | ** 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. */ #ifdef SQLITE_SECURE_DELETE memcpy(&aOvflSpace[apDiv[i]-pParent->aData], apDiv[i], szNew[i]); apDiv[i] = &aOvflSpace[apDiv[i]-pParent->aData]; #endif | | | 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 | ** 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. */ #ifdef SQLITE_SECURE_DELETE memcpy(&aOvflSpace[apDiv[i]-pParent->aData], apDiv[i], szNew[i]); apDiv[i] = &aOvflSpace[apDiv[i]-pParent->aData]; #endif dropCell(pParent, i+nxDiv-pParent->nOverflow, szNew[i], &rc); } } /* Make nMaxCells a multiple of 4 in order to preserve 8-byte ** alignment */ nMaxCells = (nMaxCells + 3)&~3; |
︙ | ︙ | |||
5736 5737 5738 5739 5740 5741 5742 | rc = allocateBtreePage(pBt, &pNew, &pgno, pgno, 0); if( rc ) goto balance_cleanup; apNew[i] = pNew; nNew++; /* Set the pointer-map entry for the new sibling page. */ if( ISAUTOVACUUM ){ | | | | 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 | rc = allocateBtreePage(pBt, &pNew, &pgno, pgno, 0); if( rc ) goto balance_cleanup; apNew[i] = pNew; nNew++; /* 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; } } } } /* Free any old pages that were not reused as new pages. */ while( i<nOld ){ freePage(apOld[i], &rc); if( rc ) goto balance_cleanup; releasePage(apOld[i]); apOld[i] = 0; i++; } /* |
︙ | ︙ | |||
5835 5836 5837 5838 5839 5840 5841 | /* If the tree is a leaf-data tree, and the siblings are leaves, ** then there is no divider cell in apCell[]. Instead, the divider ** cell consists of the integer key for the right-most cell of ** the sibling-page assembled above only. */ CellInfo info; j--; | | | | | 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 | /* If the tree is a leaf-data tree, and the siblings are leaves, ** then there is no divider cell in apCell[]. Instead, the divider ** cell consists of the integer key for the right-most cell of ** the sibling-page assembled above only. */ CellInfo info; j--; btreeParseCellPtr(pNew, apCell[j], &info); pCell = pTemp; sz = 4 + putVarint(&pCell[4], info.nKey); pTemp = 0; }else{ pCell -= 4; /* Obscure case for non-leaf-data trees: If the cell at pCell was ** previously stored on a leaf node, and its reported size was 4 ** bytes, then it may actually be smaller than this ** (see btreeParseCellPtr(), 4 bytes is the minimum size of ** any cell). But it is important to pass the correct size to ** insertCell(), so reparse the cell now. ** ** Note that this can never happen in an SQLite data file, as all ** cells are at least 4 bytes. It only happens in b-trees used ** to evaluate "IN (SELECT ...)" and similar clauses. */ if( szCell[j]==4 ){ assert(leafCorrection==4); sz = cellSizePtr(pParent, pCell); } } iOvflSpace += sz; assert( sz<=pBt->pageSize/4 ); assert( iOvflSpace<=pBt->pageSize ); insertCell(pParent, nxDiv, pCell, sz, pTemp, pNew->pgno, &rc); if( rc!=SQLITE_OK ) goto balance_cleanup; assert( sqlite3PagerIswriteable(pParent->pDbPage) ); j++; nxDiv++; } } |
︙ | ︙ | |||
5895 5896 5897 5898 5899 5900 5901 | ** (it must be, as it was just reconstructed using assemblePage()). This ** is important if the parent page happens to be page 1 of the database ** image. */ assert( nNew==1 ); assert( apNew[0]->nFree == (get2byte(&apNew[0]->aData[5])-apNew[0]->cellOffset-apNew[0]->nCell*2) ); | | | < | 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 | ** (it must be, as it was just reconstructed using assemblePage()). This ** is important if the parent page happens to be page 1 of the database ** image. */ assert( nNew==1 ); assert( apNew[0]->nFree == (get2byte(&apNew[0]->aData[5])-apNew[0]->cellOffset-apNew[0]->nCell*2) ); copyNodeContent(apNew[0], pParent, &rc); freePage(apNew[0], &rc); }else if( ISAUTOVACUUM ){ /* Fix the pointer-map entries for all the cells that were shifted around. ** There are several different types of pointer-map entries that need to ** be dealt with by this routine. Some of these have been set already, but ** many have not. The following is a summary: ** ** 1) The entries associated with new sibling pages that were not |
︙ | ︙ | |||
5937 5938 5939 5940 5941 5942 5943 | MemPage *pNew = apNew[0]; MemPage *pOld = apCopy[0]; int nOverflow = pOld->nOverflow; int iNextOld = pOld->nCell + nOverflow; int iOverflow = (nOverflow ? pOld->aOvfl[0].idx : -1); j = 0; /* Current 'old' sibling page */ k = 0; /* Current 'new' sibling page */ | | | 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 | MemPage *pNew = apNew[0]; MemPage *pOld = apCopy[0]; int nOverflow = pOld->nOverflow; int iNextOld = pOld->nCell + nOverflow; int iOverflow = (nOverflow ? pOld->aOvfl[0].idx : -1); j = 0; /* Current 'old' sibling page */ k = 0; /* Current 'new' sibling page */ for(i=0; i<nCell; i++){ int isDivider = 0; while( i==iNextOld ){ /* Cell i is the cell immediately following the last cell on old ** sibling page j. If the siblings are not leaf pages of an ** intkey b-tree, then cell i was a divider cell. */ pOld = apCopy[++j]; iNextOld = i + !leafData + pOld->nCell + pOld->nOverflow; |
︙ | ︙ | |||
5969 5970 5971 5972 5973 5974 5975 | if( i==cntNew[k] ){ /* Cell i is the cell immediately following the last cell on new ** sibling page k. If the siblings are not leaf pages of an ** intkey b-tree, then cell i is a divider cell. */ pNew = apNew[++k]; if( !leafData ) continue; } | < | | | | < | > | 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 | if( i==cntNew[k] ){ /* Cell i is the cell immediately following the last cell on new ** sibling page k. If the siblings are not leaf pages of an ** intkey b-tree, then cell i is a divider cell. */ pNew = apNew[++k]; if( !leafData ) continue; } assert( j<nOld ); assert( k<nNew ); /* If the cell was originally divider cell (and is not now) or ** an overflow cell, or if the cell was located on a different sibling ** page before the balancing, then the pointer map entries associated ** with any child or overflow pages need to be updated. */ if( isDivider || pOld->pgno!=pNew->pgno ){ if( !leafCorrection ){ ptrmapPut(pBt, get4byte(apCell[i]), PTRMAP_BTREE, pNew->pgno, &rc); } if( szCell[i]>pNew->minLocal ){ ptrmapPutOvflPtr(pNew, apCell[i], &rc); } } } if( !leafCorrection ){ for(i=0; i<nNew; i++){ u32 key = get4byte(&apNew[i]->aData[8]); ptrmapPut(pBt, key, PTRMAP_BTREE, apNew[i]->pgno, &rc); } } #if 0 /* 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 |
︙ | ︙ | |||
6046 6047 6048 6049 6050 6051 6052 | ** page and SQLITE_OK is returned. In this case the caller is required ** to call releasePage() on *ppChild exactly once. If an error occurs, ** an error code is returned and *ppChild is set to 0. */ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){ int rc; /* Return value from subprocedures */ MemPage *pChild = 0; /* Pointer to a new child page */ | | | > | | | | > > | | 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 | ** page and SQLITE_OK is returned. In this case the caller is required ** to call releasePage() on *ppChild exactly once. If an error occurs, ** an error code is returned and *ppChild is set to 0. */ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){ int rc; /* Return value from subprocedures */ MemPage *pChild = 0; /* Pointer to a new child page */ Pgno pgnoChild = 0; /* Page number of the new child page */ BtShared *pBt = pRoot->pBt; /* The BTree */ assert( pRoot->nOverflow>0 ); assert( sqlite3_mutex_held(pBt->mutex) ); /* Make pRoot, the root page of the b-tree, writable. Allocate a new ** 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; } assert( sqlite3PagerIswriteable(pChild->pDbPage) ); assert( sqlite3PagerIswriteable(pRoot->pDbPage) ); assert( pChild->nCell==pRoot->nCell ); |
︙ | ︙ | |||
6206 6207 6208 6209 6210 6211 6212 | if( pFree ){ sqlite3PageFree(pFree); } return rc; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | > > | | | | | > > > > > < < | | | < > > > > > | < | > > > | | | | < | > > | < | > | 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 | if( pFree ){ sqlite3PageFree(pFree); } return rc; } /* ** Insert a new record into the BTree. The key is given by (pKey,nKey) ** and the data is given by (pData,nData). The cursor is used only to ** define what table the record should be inserted into. The cursor ** is left pointing at a random location. ** ** For an INTKEY table, only the nKey value of the key is used. pKey is ** ignored. For a ZERODATA table, the pData and nData are both ignored. ** ** If the seekResult parameter is non-zero, then a successful call to ** MovetoUnpacked() to seek cursor pCur to (pKey, nKey) has already ** been performed. seekResult is the search result returned (a negative ** number if pCur points at an entry that is smaller than (pKey, nKey), or ** a positive value if pCur points at an etry that is larger than ** (pKey, nKey)). ** ** If the seekResult parameter is non-zero, then the caller guarantees that ** cursor pCur is pointing at the existing copy of a row that is to be ** overwritten. If the seekResult parameter is 0, then cursor pCur may ** point to any entry or to no entry at all and so this function has to seek ** the cursor before the new key can be inserted. */ int sqlite3BtreeInsert( BtCursor *pCur, /* Insert data into the table of this cursor */ const void *pKey, i64 nKey, /* The key of the new record */ const void *pData, int nData, /* The data of the new record */ int nZero, /* Number of extra 0 bytes to append to data */ int appendBias, /* 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; if( pCur->eState==CURSOR_FAULT ){ assert( pCur->skipNext!=SQLITE_OK ); return pCur->skipNext; } assert( cursorHoldsMutex(pCur) ); assert( pCur->wrFlag && pBt->inTransaction==TRANS_WRITE && !pBt->readOnly ); 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( (pKey==0)==(pCur->pKeyInfo==0) ); /* If this is an insert into a table b-tree, invalidate any incrblob ** cursors open on the row being replaced (assuming this is a replace ** operation - if it is not, the following is a no-op). */ if( pCur->pKeyInfo==0 ){ invalidateIncrblobCursors(p, nKey, 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. */ rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur); if( rc ) return rc; if( !loc ){ rc = btreeMoveto(pCur, pKey, nKey, appendBias, &loc); if( rc ) return rc; } assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) ); pPage = pCur->apPage[pCur->iPage]; assert( pPage->intKey || nKey>=0 ); assert( pPage->leaf || !pPage->intKey ); TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n", pCur->pgnoRoot, nKey, nData, pPage->pgno, loc==0 ? "overwrite" : "new entry")); assert( pPage->isInit ); allocateTempSpace(pBt); newCell = pBt->pTmpSpace; if( newCell==0 ) return SQLITE_NOMEM; |
︙ | ︙ | |||
6375 6376 6377 6378 6379 6380 6381 | } oldCell = findCell(pPage, idx); if( !pPage->leaf ){ memcpy(newCell, oldCell, 4); } szOld = cellSizePtr(pPage, oldCell); rc = clearCell(pPage, oldCell); | < | < | < | | 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 | } oldCell = findCell(pPage, idx); if( !pPage->leaf ){ memcpy(newCell, oldCell, 4); } szOld = cellSizePtr(pPage, oldCell); rc = clearCell(pPage, oldCell); dropCell(pPage, idx, szOld, &rc); if( rc ) goto end_insert; }else if( loc<0 && pPage->nCell>0 ){ assert( pPage->leaf ); idx = ++pCur->aiIdx[pCur->iPage]; }else{ assert( pPage->leaf ); } insertCell(pPage, idx, newCell, szNew, 0, 0, &rc); assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 ); /* If no error has occured and pPage has an overflow cell, call balance() ** to redistribute the cells within the tree. Since balance() may move ** the cursor, zero the BtCursor.info.nSize and BtCursor.validNKey ** variables. ** |
︙ | ︙ | |||
6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 | int iCellIdx; /* Index of cell to delete */ int iCellDepth; /* Depth of node containing pCell */ assert( cursorHoldsMutex(pCur) ); assert( pBt->inTransaction==TRANS_WRITE ); assert( !pBt->readOnly ); assert( pCur->wrFlag ); if( NEVER(pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell) || NEVER(pCur->eState!=CURSOR_VALID) ){ return SQLITE_ERROR; /* Something has gone awry. */ } | > > > | > | < | | | < | > | > | > | | < | < | | | < | < | 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 | int iCellIdx; /* Index of cell to delete */ int iCellDepth; /* Depth of node containing pCell */ assert( cursorHoldsMutex(pCur) ); assert( pBt->inTransaction==TRANS_WRITE ); assert( !pBt->readOnly ); assert( pCur->wrFlag ); assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) ); assert( !hasReadConflicts(p, pCur->pgnoRoot) ); if( NEVER(pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell) || NEVER(pCur->eState!=CURSOR_VALID) ){ return SQLITE_ERROR; /* Something has gone awry. */ } /* 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->info.nKey, 0); } iCellDepth = pCur->iPage; iCellIdx = pCur->aiIdx[iCellDepth]; pPage = pCur->apPage[iCellDepth]; pCell = findCell(pPage, iCellIdx); /* 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 ** of the 'next' entry, as the previous entry is always a part of the ** sub-tree headed by the child page of the cell being deleted. This makes ** balancing the tree following the delete operation easier. */ if( !pPage->leaf ){ int notUsed; rc = sqlite3BtreePrevious(pCur, ¬Used); if( rc ) return rc; } /* Save the positions of any other cursors open on this table before ** making any modifications. 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 = saveAllCursors(pBt, pCur->pgnoRoot, pCur); if( rc ) return rc; rc = sqlite3PagerWrite(pPage->pDbPage); if( rc ) return rc; rc = clearCell(pPage, pCell); dropCell(pPage, iCellIdx, cellSizePtr(pPage, pCell), &rc); if( rc ) return rc; /* If the cell deleted was not located on a leaf page, then the cursor ** is currently pointing to the largest entry in the sub-tree headed ** by the child-page of the cell that was just deleted from an internal ** node. The cell from the leaf node needs to be moved to the internal ** node to replace the deleted cell. */ if( !pPage->leaf ){ MemPage *pLeaf = pCur->apPage[pCur->iPage]; int nCell; Pgno n = pCur->apPage[iCellDepth+1]->pgno; unsigned char *pTmp; pCell = findCell(pLeaf, pLeaf->nCell-1); nCell = cellSizePtr(pLeaf, pCell); assert( MX_CELL_SIZE(pBt)>=nCell ); allocateTempSpace(pBt); pTmp = pBt->pTmpSpace; rc = sqlite3PagerWrite(pLeaf->pDbPage); 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. ** |
︙ | ︙ | |||
6584 6585 6586 6587 6588 6589 6590 | */ 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). */ | | < < < | 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 | */ 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) ){ |
︙ | ︙ | |||
6615 6616 6617 6618 6619 6620 6621 | if( pgnoMove!=pgnoRoot ){ /* pgnoRoot is the page that will be used for the root-page of ** the new table (assuming an error did not occur). But we were ** allocated pgnoMove. If required (i.e. if it was not allocated ** by extending the file), the current page at position pgnoMove ** is already journaled. */ | | | | | | | 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 | if( pgnoMove!=pgnoRoot ){ /* pgnoRoot is the page that will be used for the root-page of ** the new table (assuming an error did not occur). But we were ** allocated pgnoMove. If required (i.e. if it was not allocated ** by extending the file), the current page at position pgnoMove ** is already journaled. */ u8 eType = 0; Pgno iPtrPage = 0; releasePage(pPageMove); /* Move the page currently at pgnoRoot to pgnoMove. */ rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0); if( rc!=SQLITE_OK ){ return rc; } rc = ptrmapGet(pBt, pgnoRoot, &eType, &iPtrPage); if( eType==PTRMAP_ROOTPAGE || eType==PTRMAP_FREEPAGE ){ rc = SQLITE_CORRUPT_BKPT; } if( rc!=SQLITE_OK ){ releasePage(pRoot); return rc; } assert( eType!=PTRMAP_ROOTPAGE ); assert( eType!=PTRMAP_FREEPAGE ); rc = relocatePage(pBt, pRoot, eType, iPtrPage, pgnoMove, 0); releasePage(pRoot); /* Obtain the page at pgnoRoot */ if( rc!=SQLITE_OK ){ return rc; } rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0); if( rc!=SQLITE_OK ){ return rc; } rc = sqlite3PagerWrite(pRoot->pDbPage); if( rc!=SQLITE_OK ){ releasePage(pRoot); return rc; } }else{ pRoot = pPageMove; } /* Update the pointer-map and meta-data with the new root-page number. */ ptrmapPut(pBt, pgnoRoot, PTRMAP_ROOTPAGE, 0, &rc); if( rc ){ releasePage(pRoot); return rc; } rc = sqlite3BtreeUpdateMeta(p, 4, pgnoRoot); if( rc ){ releasePage(pRoot); |
︙ | ︙ | |||
6696 6697 6698 6699 6700 6701 6702 | */ 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 ){ | | | | | 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 | */ 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 ){ MemPage *pPage; int rc; unsigned char *pCell; int i; assert( sqlite3_mutex_held(pBt->mutex) ); if( pgno>pagerPagecount(pBt) ){ return SQLITE_CORRUPT_BKPT; } rc = getAndInitPage(pBt, pgno, &pPage); if( rc ) return rc; for(i=0; i<pPage->nCell; i++){ pCell = findCell(pPage, i); if( !pPage->leaf ){ rc = clearDatabasePage(pBt, get4byte(pCell), 1, pnChange); if( rc ) goto cleardatabasepage_out; } rc = clearCell(pPage, pCell); if( rc ) goto cleardatabasepage_out; } if( !pPage->leaf ){ rc = clearDatabasePage(pBt, get4byte(&pPage->aData[8]), 1, pnChange); if( rc ) goto cleardatabasepage_out; }else if( pnChange ){ assert( pPage->intKey ); *pnChange += pPage->nCell; } if( freePageFlag ){ freePage(pPage, &rc); }else if( (rc = sqlite3PagerWrite(pPage->pDbPage))==0 ){ zeroPage(pPage, pPage->aData[0] | PTF_LEAF); } cleardatabasepage_out: releasePage(pPage); return rc; |
︙ | ︙ | |||
6753 6754 6755 6756 6757 6758 6759 | ** 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 ); | | > > > > | | < < > | 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 | ** 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 ); /* 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, 0, 1); rc = saveAllCursors(pBt, (Pgno)iTable, 0); if( SQLITE_OK==rc ){ rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange); } sqlite3BtreeLeave(p); return rc; } /* |
︙ | ︙ | |||
6797 6798 6799 6800 6801 6802 6803 6804 | assert( p->inTrans==TRANS_WRITE ); /* It is illegal to drop a table if any cursors are open on the ** database. This is because in auto-vacuum mode the backend may ** need to move another root-page to fill a gap left by the deleted ** root page. If an open cursor was using this page a problem would ** occur. */ | > > | | | | < < < < | | > | < < < | | < < | | | > > > > > > | < < < | < < < < < < | < < < < | < < < < < < < < < < < < < < < | < < | < < < < < < < | | < < < < < < < < < < | 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 | assert( p->inTrans==TRANS_WRITE ); /* It is illegal to drop a table if any cursors are open on the ** database. This is because in auto-vacuum mode the backend may ** need to move another root-page to fill a gap left by the deleted ** root page. If an open cursor was using this page a problem would ** occur. ** ** This error is caught long before control reaches this point. */ if( NEVER(pBt->pCursor) ){ sqlite3ConnectionBlocked(p->db, pBt->pCursor->pBtree->db); return SQLITE_LOCKED_SHAREDCACHE; } rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0); if( rc ) return rc; rc = sqlite3BtreeClearTable(p, iTable, 0); if( rc ){ releasePage(pPage); return rc; } *piMoved = 0; if( iTable>1 ){ #ifdef SQLITE_OMIT_AUTOVACUUM freePage(pPage, &rc); releasePage(pPage); #else if( pBt->autoVacuum ){ Pgno maxRootPgno; sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &maxRootPgno); if( iTable==maxRootPgno ){ /* If the table being dropped is the table with the largest root-page ** number in the database, put the root page on the free list. */ freePage(pPage, &rc); releasePage(pPage); if( rc!=SQLITE_OK ){ return rc; } }else{ /* The table being dropped does not have the largest root-page ** number in the database. So move the page that does into the ** gap left by the deleted root-page. */ MemPage *pMove; releasePage(pPage); rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0); if( rc!=SQLITE_OK ){ return rc; } rc = relocatePage(pBt, pMove, PTRMAP_ROOTPAGE, 0, iTable, 0); releasePage(pMove); if( rc!=SQLITE_OK ){ return rc; } pMove = 0; rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0); freePage(pMove, &rc); releasePage(pMove); if( rc!=SQLITE_OK ){ return rc; } *piMoved = maxRootPgno; } /* Set the new 'max-root-page' value in the database header. This ** is the old value less one, less one more if that happens to ** be a root-page number, less one again if that is the ** PENDING_BYTE_PAGE. */ maxRootPgno--; while( maxRootPgno==PENDING_BYTE_PAGE(pBt) || PTRMAP_ISPAGE(pBt, maxRootPgno) ){ maxRootPgno--; } assert( maxRootPgno!=PENDING_BYTE_PAGE(pBt) ); rc = sqlite3BtreeUpdateMeta(p, 4, maxRootPgno); }else{ freePage(pPage, &rc); releasePage(pPage); } #endif }else{ /* If sqlite3BtreeDropTable was called on page 1. ** This really never should happen except in a corrupt ** database. */ zeroPage(pPage, PTF_INTKEY|PTF_LEAF ); releasePage(pPage); } return rc; } int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){ int rc; sqlite3BtreeEnter(p); rc = btreeDropTable(p, iTable, piMoved); sqlite3BtreeLeave(p); return rc; } /* ** This function may only be called if the b-tree connection already ** has a read or write transaction open on the database. ** ** Read the meta-information out of a database file. Meta[0] ** is the number of free pages currently in the database. Meta[1] ** through meta[15] are available for use by higher layers. Meta[0] ** is read-only, the others are read/write. ** ** The schema layer numbers meta values differently. At the schema ** layer (and the SetCookie and ReadCookie opcodes) the number of ** free pages is not visible. So Cookie[0] is the same as Meta[1]. */ 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 ); *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 if( idx==BTREE_LARGEST_ROOT_PAGE && *pMeta>0 ) pBt->readOnly = 1; #endif sqlite3BtreeLeave(p); } /* ** Write meta-information back into the database. Meta[0] is ** read-only and may not be written. */ int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){ |
︙ | ︙ | |||
7004 7005 7006 7007 7008 7009 7010 | } #endif } sqlite3BtreeLeave(p); return rc; } | < < < < < < < < < < < < < < < < < | 7107 7108 7109 7110 7111 7112 7113 7114 7115 7116 7117 7118 7119 7120 | } #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 |
︙ | ︙ | |||
7068 7069 7070 7071 7072 7073 7074 | if( pPage->leaf ){ do { if( pCur->iPage==0 ){ /* All pages of the b-tree have been visited. Return successfully. */ *pnEntry = nEntry; return SQLITE_OK; } | | | 7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168 | if( pPage->leaf ){ do { if( pCur->iPage==0 ){ /* All pages of the b-tree have been visited. Return successfully. */ *pnEntry = nEntry; return SQLITE_OK; } moveToParent(pCur); }while ( pCur->aiIdx[pCur->iPage]>=pCur->apPage[pCur->iPage]->nCell ); pCur->aiIdx[pCur->iPage]++; pPage = pCur->apPage[pCur->iPage]; } /* Descend to the child node of the cell that the cursor currently |
︙ | ︙ | |||
7295 7296 7297 7298 7299 7300 7301 | /* Check that the page exists */ pBt = pCheck->pBt; usableSize = pBt->usableSize; if( iPage==0 ) return 0; if( checkRef(pCheck, iPage, zParentContext) ) return 0; | | < > > > > | | | | 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 | /* Check that the page exists */ pBt = pCheck->pBt; usableSize = pBt->usableSize; if( iPage==0 ) return 0; if( checkRef(pCheck, iPage, zParentContext) ) return 0; if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){ checkAppendMsg(pCheck, zContext, "unable to get the page. error code=%d", rc); return 0; } /* Clear MemPage.isInit to make sure the corruption detection code in ** btreeInitPage() is executed. */ pPage->isInit = 0; if( (rc = btreeInitPage(pPage))!=0 ){ assert( rc==SQLITE_CORRUPT ); /* The only possible error from InitPage */ checkAppendMsg(pCheck, zContext, "btreeInitPage() returns error code %d", rc); releasePage(pPage); return 0; } /* Check out all the cells. */ depth = 0; for(i=0; i<pPage->nCell && pCheck->mxErr; i++){ u8 *pCell; u32 sz; CellInfo info; /* Check payload overflow pages */ sqlite3_snprintf(sizeof(zContext), zContext, "On tree page %d cell %d: ", iPage, i); pCell = findCell(pPage,i); btreeParseCellPtr(pPage, pCell, &info); sz = info.nData; if( !pPage->intKey ) sz += (int)info.nKey; assert( sz==info.nPayload ); if( (sz>info.nLocal) && (&pCell[info.iOverflow]<=&pPage->aData[pBt->usableSize]) ){ int nPage = (sz - info.nLocal + usableSize - 5)/(usableSize - 4); |
︙ | ︙ | |||
7376 7377 7378 7379 7380 7381 7382 | data = pPage->aData; hdr = pPage->hdrOffset; hit = sqlite3PageMalloc( pBt->pageSize ); if( hit==0 ){ pCheck->mallocFailed = 1; }else{ u16 contentOffset = get2byte(&data[hdr+5]); | | < < < < | | | > | > | < | < < < | < | > > > | < | < > > > > < < < < < < < | 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 | data = pPage->aData; hdr = pPage->hdrOffset; hit = sqlite3PageMalloc( pBt->pageSize ); if( hit==0 ){ pCheck->mallocFailed = 1; }else{ u16 contentOffset = get2byte(&data[hdr+5]); assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */ memset(hit+contentOffset, 0, usableSize-contentOffset); memset(hit, 1, contentOffset); nCell = get2byte(&data[hdr+3]); cellStart = hdr + 12 - 4*pPage->leaf; for(i=0; i<nCell; i++){ int pc = get2byte(&data[cellStart+i*2]); u16 size = 1024; int j; if( pc<=usableSize-4 ){ size = cellSizePtr(pPage, &data[pc]); } if( (pc+size-1)>=usableSize ){ checkAppendMsg(pCheck, 0, "Corruption detected in cell %d on page %d",i,iPage,0); }else{ for(j=pc+size-1; j>=pc; j--) hit[j]++; } } i = get2byte(&data[hdr+1]); while( i>0 ){ int size, j; assert( i<=usableSize-4 ); /* Enforced by btreeInitPage() */ size = get2byte(&data[i+2]); assert( i+size<=usableSize ); /* Enforced by btreeInitPage() */ for(j=i+size-1; j>=i; j--) hit[j]++; j = get2byte(&data[i]); assert( j==0 || j>i+size ); /* Enforced by btreeInitPage() */ assert( j<=usableSize-4 ); /* Enforced by btreeInitPage() */ i = j; } for(i=cnt=0; i<usableSize; i++){ if( hit[i]==0 ){ cnt++; }else if( hit[i]>1 ){ checkAppendMsg(pCheck, 0, "Multiple uses for byte %d of page %d", i, iPage); break; } } if( cnt!=data[hdr+7] ){ checkAppendMsg(pCheck, 0, "Fragmentation of %d bytes reported as %d on page %d", cnt, data[hdr+7], iPage); } } sqlite3PageFree(hit); releasePage(pPage); return depth+1; } #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ #ifndef SQLITE_OMIT_INTEGRITY_CHECK /* ** This routine does a complete check of the given BTree file. aRoot[] is ** an array of pages numbers were each page number is the root page of ** a table. nRoot is the number of entries in aRoot. ** ** 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; int nRef; IntegrityCk sCheck; BtShared *pBt = p->pBt; char zErr[100]; sqlite3BtreeEnter(p); assert( p->inTrans>TRANS_NONE && pBt->inTransaction>TRANS_NONE ); nRef = sqlite3PagerRefcount(pBt->pPager); sCheck.pBt = pBt; sCheck.pPager = pBt->pPager; sCheck.nPage = pagerPagecount(sCheck.pBt); sCheck.mxErr = mxErr; sCheck.nErr = 0; sCheck.mallocFailed = 0; *pnErr = 0; if( sCheck.nPage==0 ){ sqlite3BtreeLeave(p); return 0; } sCheck.anRef = sqlite3Malloc( (sCheck.nPage+1)*sizeof(sCheck.anRef[0]) ); if( !sCheck.anRef ){ *pnErr = 1; sqlite3BtreeLeave(p); return 0; } for(i=0; i<=sCheck.nPage; i++){ sCheck.anRef[i] = 0; } i = PENDING_BYTE_PAGE(pBt); if( i<=sCheck.nPage ){ |
︙ | ︙ | |||
7534 7535 7536 7537 7538 7539 7540 | #endif } /* Make sure this analysis did not leave any unref() pages. ** This is an internal consistency check; an integrity check ** of the integrity check. */ | < | 7614 7615 7616 7617 7618 7619 7620 7621 7622 7623 7624 7625 7626 7627 | #endif } /* Make sure this analysis did not leave any unref() pages. ** This is an internal consistency check; an integrity check ** of the integrity check. */ if( NEVER(nRef != sqlite3PagerRefcount(pBt->pPager)) ){ checkAppendMsg(&sCheck, 0, "Outstanding page count goes from %d to %d during this analysis", nRef, sqlite3PagerRefcount(pBt->pPager) ); } |
︙ | ︙ | |||
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 | /* ** Obtain a lock on the table whose root page is iTab. The ** lock is a write lock if isWritelock is true or a read lock ** if it is false. */ int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){ int rc = SQLITE_OK; if( p->sharable ){ u8 lockType = READ_LOCK + isWriteLock; assert( READ_LOCK+1==WRITE_LOCK ); assert( isWriteLock==0 || isWriteLock==1 ); sqlite3BtreeEnter(p); rc = querySharedCacheTableLock(p, iTab, lockType); if( rc==SQLITE_OK ){ rc = setSharedCacheTableLock(p, iTab, lockType); } sqlite3BtreeLeave(p); } return rc; } #endif #ifndef SQLITE_OMIT_INCRBLOB /* ** Argument pCsr must be a cursor opened for writing on an ** INTKEY table currently pointing at a valid table entry. ** This function modifies the data stored as part of that entry. | > > > | | > > < | | > > > | | > > | | | | < < < < < | < | < | | 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 | /* ** Obtain a lock on the table whose root page is iTab. The ** lock is a write lock if isWritelock is true or a read lock ** if it is false. */ int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){ int rc = SQLITE_OK; assert( p->inTrans!=TRANS_NONE ); if( p->sharable ){ u8 lockType = READ_LOCK + isWriteLock; assert( READ_LOCK+1==WRITE_LOCK ); assert( isWriteLock==0 || isWriteLock==1 ); sqlite3BtreeEnter(p); rc = querySharedCacheTableLock(p, iTab, lockType); if( rc==SQLITE_OK ){ rc = setSharedCacheTableLock(p, iTab, lockType); } sqlite3BtreeLeave(p); } return rc; } #endif #ifndef SQLITE_OMIT_INCRBLOB /* ** Argument pCsr must be a cursor opened for writing on an ** INTKEY table currently pointing at a valid table entry. ** This function modifies the data stored as part of that entry. ** ** Only the data content may only be modified, it is not possible to ** change the length of the data stored. If this function is called with ** parameters that attempt to write past the end of the existing data, ** no modifications are made and SQLITE_CORRUPT is returned. */ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){ int rc; assert( cursorHoldsMutex(pCsr) ); assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) ); assert( pCsr->isIncrblobHandle ); rc = restoreCursorPosition(pCsr); if( rc!=SQLITE_OK ){ return rc; } assert( pCsr->eState!=CURSOR_REQUIRESEEK ); if( pCsr->eState!=CURSOR_VALID ){ return SQLITE_ABORT; } /* Check some assumptions: ** (a) the cursor is open for writing, ** (b) there is a read/write transaction open, ** (c) the connection holds a write-lock on the table (if required), ** (d) there are no conflicting read-locks, and ** (e) the cursor points at a valid row of an intKey table. */ if( !pCsr->wrFlag ){ return SQLITE_READONLY; } assert( !pCsr->pBt->readOnly && pCsr->pBt->inTransaction==TRANS_WRITE ); assert( hasSharedCacheTableLock(pCsr->pBtree, pCsr->pgnoRoot, 0, 2) ); assert( !hasReadConflicts(pCsr->pBtree, pCsr->pgnoRoot) ); assert( pCsr->apPage[pCsr->iPage]->intKey ); return accessPayload(pCsr, offset, amt, (unsigned char *)z, 1); } /* ** Set a flag on this cursor to cache the locations of pages from the ** overflow list for the current row. This is used by cursors opened ** for incremental blob IO only. ** |
︙ | ︙ |
Changes to src/btree.h.
︙ | ︙ | |||
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 header file defines the interface that the sqlite B-Tree file ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. | < < | 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. ** ************************************************************************* ** This header file defines the interface that the sqlite B-Tree file ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. */ #ifndef _BTREE_H_ #define _BTREE_H_ /* TODO: This definition is just included so other modules compile. It ** needs to be revisited. */ |
︙ | ︙ | |||
93 94 95 96 97 98 99 | int sqlite3BtreeRollback(Btree*); 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 *)); | | | | | 91 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 | int sqlite3BtreeRollback(Btree*); 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); int sqlite3BtreeLockTable(Btree *pBtree, int iTab, u8 isWriteLock); 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 following flags: */ #define BTREE_INTKEY 1 /* Table has only 64-bit signed integer keys */ #define BTREE_ZERODATA 2 /* Table has keys only - no data */ #define BTREE_LEAFDATA 4 /* Data stored in leaves only. Implies INTKEY */ int sqlite3BtreeDropTable(Btree*, int, int*); int sqlite3BtreeClearTable(Btree*, int, int*); void sqlite3BtreeTripAllCursors(Btree*, int); void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue); int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value); /* ** The second parameter to sqlite3BtreeGetMeta or sqlite3BtreeUpdateMeta ** should be one of the following values. The integer values are assigned ** to constants so that the offset of the corresponding field in an ** SQLite database header may be found using the following formula: |
︙ | ︙ | |||
148 149 150 151 152 153 154 | int wrFlag, /* 1 for writing. 0 for read-only */ struct KeyInfo*, /* First argument to compare function */ BtCursor *pCursor /* Space to write cursor structure */ ); int sqlite3BtreeCursorSize(void); int sqlite3BtreeCloseCursor(BtCursor*); | < < < < < < < < > > > > | 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 | int wrFlag, /* 1 for writing. 0 for read-only */ struct KeyInfo*, /* First argument to compare function */ BtCursor *pCursor /* Space to write cursor structure */ ); int sqlite3BtreeCursorSize(void); int sqlite3BtreeCloseCursor(BtCursor*); int sqlite3BtreeMovetoUnpacked( BtCursor*, UnpackedRecord *pUnKey, i64 intKey, int bias, int *pRes ); int sqlite3BtreeCursorHasMoved(BtCursor*, int*); int sqlite3BtreeDelete(BtCursor*); int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey, const void *pData, int nData, int nZero, int bias, int seekResult); int sqlite3BtreeFirst(BtCursor*, int *pRes); int sqlite3BtreeLast(BtCursor*, int *pRes); int sqlite3BtreeNext(BtCursor*, int *pRes); int sqlite3BtreeEof(BtCursor*); int sqlite3BtreePrevious(BtCursor*, int *pRes); int sqlite3BtreeKeySize(BtCursor*, i64 *pSize); int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*); const void *sqlite3BtreeKeyFetch(BtCursor*, int *pAmt); const void *sqlite3BtreeDataFetch(BtCursor*, int *pAmt); int sqlite3BtreeDataSize(BtCursor*, u32 *pSize); int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*); void sqlite3BtreeSetCachedRowid(BtCursor*, sqlite3_int64); sqlite3_int64 sqlite3BtreeGetCachedRowid(BtCursor*); char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*); struct Pager *sqlite3BtreePager(Btree*); int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*); void sqlite3BtreeCacheOverflow(BtCursor *); void sqlite3BtreeClearCursor(BtCursor *); #ifndef NDEBUG int sqlite3BtreeCursorIsValid(BtCursor*); #endif #ifndef SQLITE_OMIT_BTREECOUNT int sqlite3BtreeCount(BtCursor *, i64 *); #endif #ifdef SQLITE_TEST int sqlite3BtreeCursorInfo(BtCursor*, int*, int); |
︙ | ︙ |
Changes to src/btreeInt.h.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2004 April 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 18 | /* ** 2004 April 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 a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to ** ** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3: ** "Sorting And Searching", pages 473-480. Addison-Wesley ** Publishing Company, Reading, Massachusetts. ** |
︙ | ︙ | |||
44 45 46 47 48 49 50 | ** page has a small header which contains the Ptr(N) pointer and other ** information such as the size of key and data. ** ** FORMAT DETAILS ** ** The file is divided into pages. The first page is called page 1, ** the second is page 2, and so forth. A page number of zero indicates | | | | | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | ** page has a small header which contains the Ptr(N) pointer and other ** information such as the size of key and data. ** ** FORMAT DETAILS ** ** The file is divided into pages. The first page is called page 1, ** the second is page 2, and so forth. A page number of zero indicates ** "no such page". The page size can be any power of 2 between 512 and 32768. ** Each page can be either a btree page, a freelist page, an overflow ** page, or a pointer-map page. ** ** The first page is always a btree page. The first 100 bytes of the first ** page contain a special header (the "file header") that describes the file. ** The format of the file header is as follows: ** ** OFFSET SIZE DESCRIPTION ** 0 16 Header string: "SQLite format 3\000" |
︙ | ︙ | |||
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 | /* ** The in-memory image of a disk page has the auxiliary information appended ** to the end. EXTRA_SIZE is the number of bytes of space needed to hold ** that extra information. */ #define EXTRA_SIZE sizeof(MemPage) /* A Btree handle ** ** A database connection contains a pointer to an instance of ** this object for every database file that it has open. This structure ** is opaque to the database connection. The database connection cannot ** see the internals of this structure and only deals with pointers to ** this structure. ** ** For some database files, the same underlying database cache might be | > > > > > > > > > > > > > > > > > > | | > > > | 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 | /* ** The in-memory image of a disk page has the auxiliary information appended ** to the end. EXTRA_SIZE is the number of bytes of space needed to hold ** that extra information. */ #define EXTRA_SIZE sizeof(MemPage) /* ** A linked list of the following structures is stored at BtShared.pLock. ** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor ** is opened on the table with root page BtShared.iTable. Locks are removed ** from this list when a transaction is committed or rolled back, or when ** a btree handle is closed. */ struct BtLock { Btree *pBtree; /* Btree handle holding this lock */ Pgno iTable; /* Root page of table */ u8 eLock; /* READ_LOCK or WRITE_LOCK */ BtLock *pNext; /* Next in BtShared.pLock list */ }; /* Candidate values for BtLock.eLock */ #define READ_LOCK 1 #define WRITE_LOCK 2 /* A Btree handle ** ** A database connection contains a pointer to an instance of ** this object for every database file that it has open. This structure ** is opaque to the database connection. The database connection cannot ** see the internals of this structure and only deals with pointers to ** this structure. ** ** For some database files, the same underlying database cache might be ** shared between multiple connections. In that case, each connection ** has it own instance of this object. But each instance of this object ** points to the same BtShared object. The database cache and the ** schema associated with the database file are all contained within ** the BtShared object. ** ** All fields in this structure are accessed under sqlite3.mutex. ** The pBt pointer itself may not be changed while there exists cursors ** in the referenced BtShared that point back to this Btree since those ** cursors have to do go through this Btree to find their BtShared and ** they often do so without holding sqlite3.mutex. */ struct Btree { sqlite3 *db; /* The database connection holding this btree */ 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 */ int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */ int nBackup; /* Number of backup operations reading this btree */ 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, |
︙ | ︙ | |||
446 447 448 449 450 451 452 | /* ** A cursor is a pointer to a particular entry within a particular ** b-tree within a database file. ** ** The entry is identified by its MemPage and the index in ** MemPage.aCell[] of the entry. ** | | | | 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 | /* ** A cursor is a pointer to a particular entry within a particular ** b-tree within a database file. ** ** The entry is identified by its MemPage and the index in ** MemPage.aCell[] of the entry. ** ** A single database file can shared by two more database connections, ** but cursors cannot be shared. Each cursor is associated with a ** particular database connection identified BtCursor.pBtree.db. ** ** Fields in this structure are accessed under the BtShared.mutex ** found at self->pBt->mutex. */ struct BtCursor { Btree *pBtree; /* The Btree to which this cursor belongs */ BtShared *pBt; /* The BtShared this cursor points to */ BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */ struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */ Pgno pgnoRoot; /* The root page of this tree */ sqlite3_int64 cachedRowid; /* Next rowid cache. 0 means not valid */ CellInfo info; /* A parse of the cell we are pointing at */ u8 wrFlag; /* True if writable */ u8 atLast; /* Cursor pointing to the last entry */ u8 validNKey; /* True if info.nKey is valid */ u8 eState; /* One of the CURSOR_XXX constants (see below) */ void *pKey; /* Saved key that was cursor's last known position */ i64 nKey; /* Size of pKey, or last integer key */ int skipNext; /* Prev() is noop if negative. Next() is noop if positive */ #ifndef SQLITE_OMIT_INCRBLOB u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */ Pgno *aOverflow; /* Cache of overflow page locations */ #endif i16 iPage; /* Index of current page in apPage */ MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */ u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */ |
︙ | ︙ | |||
512 513 514 515 516 517 518 | #define CURSOR_FAULT 3 /* ** The database page the PENDING_BYTE occupies. This page is never used. */ # define PENDING_BYTE_PAGE(pBt) PAGER_MJ_PGNO(pBt) | < < < < < < < < < < < < < < < < < < | 531 532 533 534 535 536 537 538 539 540 541 542 543 544 | #define CURSOR_FAULT 3 /* ** 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. ** ** PTRMAP_PAGENO returns the database page number of the pointer-map |
︙ | ︙ | |||
631 632 633 634 635 636 637 | /* ** 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)) #define get4byte sqlite3Get4byte #define put4byte sqlite3Put4byte | < < < < < < < < < < < < < < < | 632 633 634 635 636 637 638 | /* ** 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)) #define get4byte sqlite3Get4byte #define put4byte sqlite3Put4byte |
Changes to src/build.c.
︙ | ︙ | |||
17 18 19 20 21 22 23 | ** DROP TABLE ** CREATE INDEX ** DROP INDEX ** creating ID lists ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK | < < | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | ** DROP TABLE ** CREATE INDEX ** DROP INDEX ** creating ID lists ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK */ #include "sqliteInt.h" /* ** This routine is called when a new SQL statement is beginning to ** be parsed. Initialize the pParse structure as needed. */ |
︙ | ︙ | |||
60 61 62 63 64 65 66 67 68 69 | 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 */ ){ int i; int nBytes; TableLock *p; | > < > | | | | | | | | | | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | 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 ); for(i=0; i<pToplevel->nTableLock; i++){ p = &pToplevel->aTableLock[i]; if( p->iDb==iDb && p->iTab==iTab ){ p->isWriteLock = (p->isWriteLock || isWriteLock); return; } } nBytes = sizeof(TableLock) * (pToplevel->nTableLock+1); pToplevel->aTableLock = sqlite3DbReallocOrFree(pToplevel->db, pToplevel->aTableLock, nBytes); if( pToplevel->aTableLock ){ p = &pToplevel->aTableLock[pToplevel->nTableLock++]; p->iDb = iDb; p->iTab = iTab; p->isWriteLock = isWriteLock; p->zName = zName; }else{ pToplevel->nTableLock = 0; pToplevel->db->mallocFailed = 1; } } /* ** Code an OP_TableLock instruction for each table locked by the ** statement (configured by calls to sqlite3TableLock()). */ |
︙ | ︙ | |||
133 134 135 136 137 138 139 140 141 142 143 144 145 146 | if( pParse->nested ) return; if( pParse->nErr ) return; /* Begin by generating some termination code at the end of the ** vdbe program */ v = sqlite3GetVdbe(pParse); if( v ){ sqlite3VdbeAddOp0(v, OP_Halt); /* 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 | > > | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | if( pParse->nested ) return; if( pParse->nErr ) 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); /* 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 |
︙ | ︙ | |||
158 159 160 161 162 163 164 | sqlite3VdbeAddOp2(v,OP_VerifyCookie, iDb, pParse->cookieValue[iDb]); } } #ifndef SQLITE_OMIT_VIRTUALTABLE { int i; for(i=0; i<pParse->nVtabLock; i++){ | | | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | sqlite3VdbeAddOp2(v,OP_VerifyCookie, iDb, pParse->cookieValue[iDb]); } } #ifndef SQLITE_OMIT_VIRTUALTABLE { int i; 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, |
︙ | ︙ | |||
189 190 191 192 193 194 195 196 | */ if( v && ALWAYS(pParse->nErr==0) && !db->mallocFailed ){ #ifdef SQLITE_DEBUG FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0; sqlite3VdbeTrace(v, trace); #endif assert( pParse->iCacheLevel==0 ); /* Disables and re-enables match */ sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem, | > > > | > | 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | */ if( v && ALWAYS(pParse->nErr==0) && !db->mallocFailed ){ #ifdef SQLITE_DEBUG FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0; sqlite3VdbeTrace(v, trace); #endif assert( pParse->iCacheLevel==0 ); /* Disables and re-enables match */ /* A minimum of one cursor is required if autoincrement is used * See ticket [a696379c1f08866] */ if( pParse->pAinc!=0 && pParse->nTab==0 ) pParse->nTab = 1; sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem, pParse->nTab, pParse->nMaxArg, pParse->explain, pParse->isMultiWrite && pParse->mayAbort); pParse->rc = SQLITE_DONE; pParse->colNamesSet = 0; }else if( pParse->rc==SQLITE_OK ){ pParse->rc = SQLITE_ERROR; } pParse->nTab = 0; pParse->nMem = 0; |
︙ | ︙ | |||
338 339 340 341 342 343 344 | } /* ** Reclaim the memory used by an index */ static void freeIndex(Index *p){ sqlite3 *db = p->pTable->dbMem; | | > > | 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 | } /* ** Reclaim the memory used by an index */ static void freeIndex(Index *p){ sqlite3 *db = p->pTable->dbMem; #ifndef SQLITE_OMIT_ANALYZE sqlite3DeleteIndexSamples(p); #endif sqlite3DbFree(db, p->zColAff); sqlite3DbFree(db, p); } /* ** Remove the given index from the index hash table, and free ** its memory structures. |
︙ | ︙ | |||
420 421 422 423 424 425 426 427 428 429 430 431 432 433 | assert(i==1 || (pDb->pBt && sqlite3BtreeHoldsMutex(pDb->pBt))); sqlite3SchemaFree(pDb->pSchema); } if( iDb>0 ) return; } assert( iDb==0 ); db->flags &= ~SQLITE_InternChanges; sqlite3BtreeLeaveAll(db); /* If one or more of the auxiliary database files has been closed, ** then remove them from the auxiliary database list. We take the ** opportunity to do this here since we have just deleted all of the ** schema hash tables and therefore do not have to make any changes ** to any of those tables. | > | 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 | assert(i==1 || (pDb->pBt && sqlite3BtreeHoldsMutex(pDb->pBt))); sqlite3SchemaFree(pDb->pSchema); } if( iDb>0 ) return; } assert( iDb==0 ); db->flags &= ~SQLITE_InternChanges; sqlite3VtabUnlockList(db); sqlite3BtreeLeaveAll(db); /* If one or more of the auxiliary database files has been closed, ** then remove them from the auxiliary database list. We take the ** opportunity to do this here since we have just deleted all of the ** schema hash tables and therefore do not have to make any changes ** to any of those tables. |
︙ | ︙ | |||
490 491 492 493 494 495 496 | ** This routine just deletes the data structure. It does not unlink ** the table data structure from the hash table. But it does destroy ** memory structures of the indices and foreign keys associated with ** the table. */ void sqlite3DeleteTable(Table *pTable){ Index *pIndex, *pNext; | < | 498 499 500 501 502 503 504 505 506 507 508 509 510 511 | ** This routine just deletes the data structure. It does not unlink ** the table data structure from the hash table. But it does destroy ** memory structures of the indices and foreign keys associated with ** the table. */ void sqlite3DeleteTable(Table *pTable){ Index *pIndex, *pNext; sqlite3 *db; if( pTable==0 ) return; db = pTable->dbMem; testcase( db==0 ); /* Do not delete the table until the reference count reaches zero. */ |
︙ | ︙ | |||
512 513 514 515 516 517 518 | */ for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){ pNext = pIndex->pNext; assert( pIndex->pSchema==pTable->pSchema ); sqlite3DeleteIndex(pIndex); } | < | < < | < < | 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 | */ for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){ pNext = pIndex->pNext; assert( pIndex->pSchema==pTable->pSchema ); sqlite3DeleteIndex(pIndex); } /* Delete any foreign keys attached to this table. */ sqlite3FkDelete(pTable); /* Delete the Table structure itself. */ sqliteResetColumnNames(pTable); sqlite3DbFree(db, pTable->zName); sqlite3DbFree(db, pTable->zColAff); sqlite3SelectDelete(db, pTable->pSelect); |
︙ | ︙ | |||
1160 1161 1162 1163 1164 1165 1166 | pTab->tabFlags |= autoInc*TF_Autoincrement; }else if( autoInc ){ #ifndef SQLITE_OMIT_AUTOINCREMENT sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an " "INTEGER PRIMARY KEY"); #endif }else{ | > | > > > | 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 | pTab->tabFlags |= autoInc*TF_Autoincrement; }else if( autoInc ){ #ifndef SQLITE_OMIT_AUTOINCREMENT sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an " "INTEGER PRIMARY KEY"); #endif }else{ Index *p; p = sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0, sortOrder, 0); if( p ){ p->autoIndex = 2; } pList = 0; } primary_key_exit: sqlite3ExprListDelete(pParse->db, pList); return; } |
︙ | ︙ | |||
1251 1252 1253 1254 1255 1256 1257 | 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) ){ | | | 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 | 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(db, enc, pColl, zName); if( !pColl ){ sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName); } } return pColl; } |
︙ | ︙ | |||
1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 | ** 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); sqlite3VdbeAddOp3(v, OP_Destroy, iTable, r1, iDb); #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 | > | 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 | ** 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); 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 |
︙ | ︙ | |||
1998 1999 2000 2001 2002 2003 2004 | code = SQLITE_DROP_TEMP_VIEW; }else{ code = SQLITE_DROP_VIEW; } #ifndef SQLITE_OMIT_VIRTUALTABLE }else if( IsVirtual(pTab) ){ code = SQLITE_DROP_VTABLE; | | | 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 | code = SQLITE_DROP_TEMP_VIEW; }else{ code = SQLITE_DROP_VIEW; } #ifndef SQLITE_OMIT_VIRTUALTABLE }else if( IsVirtual(pTab) ){ code = SQLITE_DROP_VTABLE; zArg2 = sqlite3GetVTable(db, pTab)->pMod->zName; #endif }else{ if( !OMIT_TEMPDB && iDb==1 ){ code = SQLITE_DROP_TEMP_TABLE; }else{ code = SQLITE_DROP_TABLE; } |
︙ | ︙ | |||
2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 | sqlite3BeginWriteOperation(pParse, 1, iDb); #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 ){ | > | 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 | sqlite3BeginWriteOperation(pParse, 1, iDb); #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ sqlite3VdbeAddOp0(v, OP_VBegin); } #endif sqlite3FkDropTable(pParse, pName, pTab); /* 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 ){ |
︙ | ︙ | |||
2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 | Token *pTo, /* Name of the other table */ ExprList *pToCol, /* Columns in the other table */ int flags /* Conflict resolution algorithms. */ ){ sqlite3 *db = pParse->db; #ifndef SQLITE_OMIT_FOREIGN_KEY FKey *pFKey = 0; Table *p = pParse->pNewTable; int nByte; int i; int nCol; char *z; assert( pTo!=0 ); | > | 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 | Token *pTo, /* Name of the other table */ ExprList *pToCol, /* Columns in the other table */ 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 ); |
︙ | ︙ | |||
2212 2213 2214 2215 2216 2217 2218 | pFKey->aCol[i].zCol = z; memcpy(z, pToCol->a[i].zName, n); z[n] = 0; z += n+1; } } pFKey->isDeferred = 0; | | | | > > > > > > > > > > > > | 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 | pFKey->aCol[i].zCol = z; 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 */ pNextTo = (FKey *)sqlite3HashInsert(&p->pSchema->fkeyHash, pFKey->zTo, sqlite3Strlen30(pFKey->zTo), (void *)pFKey ); if( pNextTo==pFKey ){ db->mallocFailed = 1; goto fk_end; } if( pNextTo ){ 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: |
︙ | ︙ | |||
2240 2241 2242 2243 2244 2245 2246 | ** 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; | | | 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 | ** 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 ** used to initialize a newly created index or to recompute the |
︙ | ︙ | |||
2312 2313 2314 2315 2316 2317 2318 | ** (made available to the compiler for reuse) using ** sqlite3ReleaseTempRange(). So in some ways having the OP_IsUnique ** opcode use the values stored within seems dangerous. However, since ** we can be sure that no other temp registers have been allocated ** since sqlite3ReleaseTempRange() was called, it is safe to do so. */ sqlite3VdbeAddOp4(v, OP_IsUnique, iIdx, j2, regRowid, pRegKey, P4_INT32); | | | | 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 | ** (made available to the compiler for reuse) using ** sqlite3ReleaseTempRange(). So in some ways having the OP_IsUnique ** opcode use the values stored within seems dangerous. However, since ** we can be sure that no other temp registers have been allocated ** since sqlite3ReleaseTempRange() was called, it is safe to do so. */ sqlite3VdbeAddOp4(v, OP_IsUnique, iIdx, j2, regRowid, pRegKey, P4_INT32); sqlite3HaltConstraint( pParse, OE_Abort, "indexed columns are not unique", P4_STATIC); } sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdx, regRecord); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); sqlite3ReleaseTempReg(pParse, regRecord); sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp1(v, OP_Close, iTab); |
︙ | ︙ | |||
2335 2336 2337 2338 2339 2340 2341 2342 | ** 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. ** ** pList is a list of columns to be indexed. pList will be NULL if this ** is a primary key or unique-constraint on the most recent column added ** to the table currently under construction. */ | > > > > | > | 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 | ** 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. ** ** pList is a list of columns to be indexed. pList will be NULL if this ** is a primary key or unique-constraint on the most recent column added ** to the table currently under construction. ** ** If the index is created successfully, return a pointer to the new Index ** structure. This is used by sqlite3AddPrimaryKey() to mark the index ** as the tables primary key (Index.autoIndex==2). */ Index *sqlite3CreateIndex( Parse *pParse, /* All information about this parse */ Token *pName1, /* First part of index name. May be NULL */ Token *pName2, /* Second part of index name. May be NULL */ SrcList *pTblName, /* Table to index. Use pParse->pNewTable if 0 */ ExprList *pList, /* A list of columns to be indexed */ int onError, /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ Token *pStart, /* The CREATE token that begins this statement */ Token *pEnd, /* The ")" that closes the CREATE INDEX statement */ int sortOrder, /* Sort order of primary key when pList==NULL */ int ifNotExist /* Omit error if index already exists */ ){ Index *pRet = 0; /* Pointer to return */ Table *pTab = 0; /* Table to be indexed */ Index *pIndex = 0; /* The index to be created */ char *zName = 0; /* Name of the index */ int nName; /* Number of characters in zName */ int i, j; Token nullId; /* Fake token for an empty ID list */ DbFixer sFix; /* For assigning database names to pTable */ |
︙ | ︙ | |||
2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 | Index *pOther = pTab->pIndex; while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){ pOther = pOther->pNext; } pIndex->pNext = pOther->pNext; pOther->pNext = pIndex; } pIndex = 0; } /* Clean up before exiting */ exit_create_index: if( pIndex ){ sqlite3_free(pIndex->zColAff); sqlite3DbFree(db, pIndex); } sqlite3ExprListDelete(db, pList); sqlite3SrcListDelete(db, pTblName); sqlite3DbFree(db, zName); | > | | 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 | Index *pOther = pTab->pIndex; while( pOther->pNext && pOther->pNext->onError!=OE_Replace ){ pOther = pOther->pNext; } pIndex->pNext = pOther->pNext; pOther->pNext = pIndex; } pRet = pIndex; pIndex = 0; } /* Clean up before exiting */ exit_create_index: if( pIndex ){ sqlite3_free(pIndex->zColAff); sqlite3DbFree(db, pIndex); } sqlite3ExprListDelete(db, pList); sqlite3SrcListDelete(db, pTblName); sqlite3DbFree(db, zName); return pRet; } /* ** Fill the Index.aiRowEst[] array with default information - information ** to be used when we have not run the ANALYZE command. ** ** aiRowEst[0] is suppose to contain the number of elements in the index. |
︙ | ︙ | |||
3204 3205 3206 3207 3208 3209 3210 3211 3212 | 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; p = sqlite3SrcListAppend(db, p, pTable, pDatabase); if( p==0 || NEVER(p->nSrc==0) ){ | > > > > > > < < < < > > > > > > > > | 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 | 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(db, p, pTable, pDatabase); if( p==0 || NEVER(p->nSrc==0) ){ goto append_from_error; } pItem = &p->a[p->nSrc-1]; 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){ |
︙ | ︙ | |||
3406 3407 3408 3409 3410 3411 3412 | ** cookie verification subroutine code happens in sqlite3FinishCoding(). ** ** If iDb<0 then code the OP_Goto only - don't set flag to verify the ** schema on any databases. This can be used to position the OP_Goto ** early in the code, before we know if any database tables will be used. */ void sqlite3CodeVerifySchema(Parse *pParse, int iDb){ | | < < > | | < < | > > > | | | | > | | > | > > > > > > > > > > > | > > > > > > > > > > > > > > > > | > > > | > > > > > > > > > > | 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 | ** cookie verification subroutine code happens in sqlite3FinishCoding(). ** ** If iDb<0 then code the OP_Goto only - don't set flag to verify the ** schema on any databases. This can be used to position the OP_Goto ** early in the code, before we know if any database tables will be used. */ void sqlite3CodeVerifySchema(Parse *pParse, int iDb){ Parse *pToplevel = sqlite3ParseToplevel(pParse); if( pToplevel->cookieGoto==0 ){ Vdbe *v = sqlite3GetVdbe(pToplevel); if( v==0 ) return; /* This only happens if there was a prior error */ pToplevel->cookieGoto = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0)+1; } if( iDb>=0 ){ sqlite3 *db = pToplevel->db; int mask; assert( iDb<db->nDb ); assert( db->aDb[iDb].pBt!=0 || iDb==1 ); assert( iDb<SQLITE_MAX_ATTACHED+2 ); mask = 1<<iDb; if( (pToplevel->cookieMask & mask)==0 ){ pToplevel->cookieMask |= mask; pToplevel->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie; if( !OMIT_TEMPDB && iDb==1 ){ sqlite3OpenTempDatabase(pToplevel); } } } } /* ** Generate VDBE code that prepares for doing an operation that ** might change the database. ** ** This routine starts a new transaction if we are not already within ** a transaction. If we are already within a transaction, then a checkpoint ** is set if the setStatement parameter is true. A checkpoint should ** be set for operations that might fail (due to a constraint) part of ** 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); pToplevel->writeMask |= 1<<iDb; pToplevel->isMultiWrite |= setStatement; } /* ** Indicate that the statement currently under construction might write ** more than one entry (example: deleting one row then inserting another, ** inserting multiple rows in a table, or inserting a row and index entries.) ** If an abort occurs after some of these writes have completed, then it will ** be necessary to undo the completed writes. */ void sqlite3MultiWrite(Parse *pParse){ Parse *pToplevel = sqlite3ParseToplevel(pParse); pToplevel->isMultiWrite = 1; } /* ** The code generator calls this routine if is discovers that it is ** possible to abort a statement prior to completion. In order to ** perform this abort without corrupting the database, we need to make ** sure that the statement is protected by a statement transaction. ** ** Technically, we only need to set the mayAbort flag if the ** isMultiWrite flag was previously set. There is a time dependency ** such that the abort must occur after the multiwrite. This makes ** some statements involving the REPLACE conflict resolution algorithm ** go a little faster. But taking advantage of this time dependency ** makes it more difficult to prove that the code is correct (in ** particular, it prevents us from writing an effective ** implementation of sqlite3AssertMayAbort()) and so we have chosen ** to take the safe route and skip the optimization. */ void sqlite3MayAbort(Parse *pParse){ Parse *pToplevel = sqlite3ParseToplevel(pParse); pToplevel->mayAbort = 1; } /* ** Code an OP_Halt that causes the vdbe to return an SQLITE_CONSTRAINT ** error. The onError parameter determines which (if any) of the statement ** and/or current transaction is rolled back. */ void sqlite3HaltConstraint(Parse *pParse, int onError, char *p4, int p4type){ Vdbe *v = sqlite3GetVdbe(pParse); if( onError==OE_Abort ){ sqlite3MayAbort(pParse); } sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0, p4, p4type); } /* ** Check to see if pIndex uses the collating sequence pColl. Return ** true if it does and false if it does not. */ #ifndef SQLITE_OMIT_REINDEX |
︙ | ︙ |
Changes to src/callback.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 functions used to access the internal hash tables ** of user defined functions and collation sequences. | < < | < | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains functions used to access the internal hash tables ** of user defined functions and collation sequences. */ #include "sqliteInt.h" /* ** Invoke the 'collation needed' callback to request a collation sequence ** in the encoding enc of name zName, length nName. */ static void callCollNeeded(sqlite3 *db, int enc, const char *zName){ assert( !db->xCollNeeded || !db->xCollNeeded16 ); if( db->xCollNeeded ){ char *zExternal = sqlite3DbStrDup(db, zName); if( !zExternal ) return; db->xCollNeeded(db->pCollNeededArg, db, enc, zExternal); sqlite3DbFree(db, zExternal); } #ifndef SQLITE_OMIT_UTF16 if( db->xCollNeeded16 ){ char const *zExternal; sqlite3_value *pTmp = sqlite3ValueNew(db); sqlite3ValueSetStr(pTmp, -1, zName, SQLITE_UTF8, SQLITE_STATIC); |
︙ | ︙ | |||
67 68 69 70 71 72 73 | } return SQLITE_ERROR; } /* ** This function is responsible for invoking the collation factory callback ** or substituting a collation sequence of a different encoding when the | | < > | | | | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 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 | } 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. ** ** See also: sqlite3LocateCollSeq(), sqlite3FindCollSeq() */ CollSeq *sqlite3GetCollSeq( sqlite3* db, /* The database connection */ 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; 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 ); return p; } |
︙ | ︙ | |||
118 119 120 121 122 123 124 | ** request a definition of the collating sequence. If this doesn't work, ** an equivalent collating sequence that uses a text encoding different ** from the main database is substituted, if one is available. */ int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){ if( pColl ){ const char *zName = pColl->zName; | > | | 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | ** request a definition of the collating sequence. If this doesn't work, ** an equivalent collating sequence that uses a text encoding different ** from the main database is substituted, if one is available. */ int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){ if( pColl ){ const char *zName = pColl->zName; sqlite3 *db = pParse->db; CollSeq *p = sqlite3GetCollSeq(db, ENC(db), pColl, zName); if( !p ){ sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName); pParse->nErr++; return SQLITE_ERROR; } assert( p==pColl ); } |
︙ | ︙ | |||
419 420 421 422 423 424 425 426 427 428 429 430 431 432 | sqlite3HashInit(&pSchema->tblHash); for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){ Table *pTab = sqliteHashData(pElem); assert( pTab->dbMem==0 ); sqlite3DeleteTable(pTab); } sqlite3HashClear(&temp1); pSchema->pSeqTab = 0; pSchema->flags &= ~DB_SchemaLoaded; } /* ** Find and return the schema associated with a BTree. Create ** a new one if necessary. | > | 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 | sqlite3HashInit(&pSchema->tblHash); for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){ Table *pTab = sqliteHashData(pElem); assert( pTab->dbMem==0 ); sqlite3DeleteTable(pTab); } sqlite3HashClear(&temp1); sqlite3HashClear(&pSchema->fkeyHash); pSchema->pSeqTab = 0; pSchema->flags &= ~DB_SchemaLoaded; } /* ** Find and return the schema associated with a BTree. Create ** a new one if necessary. |
︙ | ︙ | |||
440 441 442 443 444 445 446 447 448 449 450 | } if( !p ){ db->mallocFailed = 1; }else if ( 0==p->file_format ){ sqlite3HashInit(&p->tblHash); sqlite3HashInit(&p->idxHash); sqlite3HashInit(&p->trigHash); p->enc = SQLITE_UTF8; } return p; } | > | 439 440 441 442 443 444 445 446 447 448 449 450 | } if( !p ){ db->mallocFailed = 1; }else if ( 0==p->file_format ){ sqlite3HashInit(&p->tblHash); sqlite3HashInit(&p->idxHash); sqlite3HashInit(&p->trigHash); sqlite3HashInit(&p->fkeyHash); p->enc = SQLITE_UTF8; } return p; } |
Changes to src/complete.c.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ************************************************************************* ** An tokenizer for SQL ** ** This file contains C code that implements the sqlite3_complete() API. ** This code used to be part of the tokenizer.c source file. But by ** separating it out, the code will be automatically omitted from ** static links that do not use it. | < < | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ************************************************************************* ** An tokenizer for SQL ** ** This file contains C code that implements the sqlite3_complete() API. ** This code used to be part of the tokenizer.c source file. But by ** separating it out, the code will be automatically omitted from ** static links that do not use it. */ #include "sqliteInt.h" #ifndef SQLITE_OMIT_COMPLETE /* ** This is defined in tokenize.c. We just have to import the definition. */ |
︙ | ︙ |
Changes to src/date.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 | ** This file contains the C functions that implement date and time ** functions for SQLite. ** ** There is only one exported symbol in this file - the function ** sqlite3RegisterDateTimeFunctions() found at the bottom of the file. ** All other code has file scope. ** | < < | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ** This file contains the C functions that implement date and time ** functions for SQLite. ** ** There is only one exported symbol in this file - the function ** sqlite3RegisterDateTimeFunctions() found at the bottom of the file. ** All other code has file scope. ** ** SQLite processes all times and dates as Julian Day numbers. The ** dates and times are stored as the number of days since noon ** in Greenwich on November 24, 4714 B.C. according to the Gregorian ** calendar system. ** ** 1970-01-01 00:00:00 is JD 2440587.5 ** 2000-01-01 00:00:00 is JD 2451544.5 |
︙ | ︙ | |||
444 445 446 447 448 449 450 | } else { int s = (int)(x.s + 0.5); x.s = s; } x.tz = 0; x.validJD = 0; computeJD(&x); | | | | 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 | } 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); #ifdef HAVE_LOCALTIME_R { struct tm sLocal; localtime_r(&t, &sLocal); 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; } #elif defined(HAVE_LOCALTIME_S) && HAVE_LOCALTIME_S { struct tm sLocal; localtime_s(&sLocal, &t); y.Y = sLocal.tm_year + 1900; y.M = sLocal.tm_mon + 1; y.D = sLocal.tm_mday; y.h = sLocal.tm_hour; |
︙ | ︙ |
Changes to src/delete.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** in order to generate code for DELETE FROM statements. | < < | 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 contains C code routines that are called by the parser ** in order to generate code for DELETE FROM statements. */ #include "sqliteInt.h" /* ** Look up every table that is named in pSrc. If any table is not found, ** add an error message to pParse->zErrMsg and return NULL. If all tables ** are found, return a pointer to the last table. |
︙ | ︙ | |||
39 40 41 42 43 44 45 | /* ** 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){ | > > > > > > > > > > > > | | | < < < > | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | /* ** 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){ /* A table is not writable under the following circumstances: ** ** 1) It is a virtual table and no implementation of the xUpdate method ** has been provided, or ** 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. ** ** In either case leave an error message in pParse and return non-zero. */ if( ( IsVirtual(pTab) && sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0 ) || ( (pTab->tabFlags & TF_Readonly)!=0 && (pParse->db->flags & SQLITE_WriteSchema)==0 && pParse->nested==0 ) ){ 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; |
︙ | ︙ | |||
214 215 216 217 218 219 220 | int end, addr = 0; /* A couple addresses of generated code */ int i; /* Loop counter */ WhereInfo *pWInfo; /* Information about the WHERE clause */ Index *pIdx; /* For looping over indices of the table */ int iCur; /* VDBE Cursor number for pTab */ sqlite3 *db; /* Main database structure */ AuthContext sContext; /* Authorization context */ | < < < < < < | | 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 | int end, addr = 0; /* A couple addresses of generated code */ int i; /* Loop counter */ WhereInfo *pWInfo; /* Information about the WHERE clause */ Index *pIdx; /* For looping over indices of the table */ int iCur; /* VDBE Cursor number for pTab */ sqlite3 *db; /* Main database structure */ AuthContext sContext; /* Authorization context */ NameContext sNC; /* Name context to resolve expressions in */ int iDb; /* Database number */ int memCnt = -1; /* Memory cell used for change counting */ int rcauth; /* Value returned by authorization callback */ #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 |
︙ | ︙ | |||
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 | # define pTrigger 0 # define isView 0 #endif #ifdef SQLITE_OMIT_VIEW # undef isView # define isView 0 #endif if( sqlite3IsReadOnly(pParse, pTab, (pTrigger?1:0)) ){ goto delete_from_cleanup; } iDb = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iDb<db->nDb ); zDb = db->aDb[iDb].zName; rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb); assert( rcauth==SQLITE_OK || rcauth==SQLITE_DENY || rcauth==SQLITE_IGNORE ); if( rcauth==SQLITE_DENY ){ goto delete_from_cleanup; } assert(!isView || pTrigger); | > > > > > > < < < < < < < < < < < < | 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 | # define pTrigger 0 # define isView 0 #endif #ifdef SQLITE_OMIT_VIEW # undef isView # define isView 0 #endif /* If pTab is really a view, make sure it has been initialized. */ if( sqlite3ViewGetColumnNames(pParse, pTab) ){ goto delete_from_cleanup; } if( sqlite3IsReadOnly(pParse, pTab, (pTrigger?1:0)) ){ goto delete_from_cleanup; } iDb = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iDb<db->nDb ); zDb = db->aDb[iDb].zName; rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb); assert( rcauth==SQLITE_OK || rcauth==SQLITE_DENY || rcauth==SQLITE_IGNORE ); if( rcauth==SQLITE_DENY ){ goto delete_from_cleanup; } assert(!isView || pTrigger); /* Assign cursor number to the table and all its indices. */ assert( pTabList->nSrc==1 ); iCur = pTabList->a[0].iCursor = pParse->nTab++; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ pParse->nTab++; } |
︙ | ︙ | |||
306 307 308 309 310 311 312 | /* Begin generating code. */ v = sqlite3GetVdbe(pParse); if( v==0 ){ goto delete_from_cleanup; } if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); | | < < < < < < < < < < < < < < < < < < | 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 | /* Begin generating code. */ v = sqlite3GetVdbe(pParse); if( v==0 ){ goto delete_from_cleanup; } if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); sqlite3BeginWriteOperation(pParse, 1, iDb); /* If we are trying to delete from a view, realize that view into ** a ephemeral table. */ #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) if( isView ){ sqlite3MaterializeView(pParse, pTab, pWhere, iCur); |
︙ | ︙ | |||
354 355 356 357 358 359 360 | if( db->flags & SQLITE_CountRows ){ memCnt = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, memCnt); } #ifndef SQLITE_OMIT_TRUNCATE_OPTIMIZATION /* Special case: A DELETE without a WHERE clause deletes everything. | | | | | > > < > < < < < < < | < > > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | > | | > | < < < < < < < < < < | | | < | | > > > > > > > > > | < | | | > > > > > | > > | > > > > > | > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > | | | | | > > > > > > > > > > > > > > > | | 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 | if( db->flags & SQLITE_CountRows ){ memCnt = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, memCnt); } #ifndef SQLITE_OMIT_TRUNCATE_OPTIMIZATION /* Special case: A DELETE without a WHERE clause deletes everything. ** It is easier just to erase the whole table. Prior to version 3.6.5, ** this optimization caused the row change count (the value returned by ** API function sqlite3_count_changes) to be set incorrectly. */ if( rcauth==SQLITE_OK && pWhere==0 && !pTrigger && !IsVirtual(pTab) && 0==sqlite3FkRequired(pParse, pTab, 0, 0) ){ assert( !isView ); sqlite3VdbeAddOp4(v, OP_Clear, pTab->tnum, iDb, memCnt, 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 */ /* The usual case: There is a WHERE clause so we have to scan through ** the table and pick which records to delete. */ { int iRowSet = ++pParse->nMem; /* Register for rowset of rows to delete */ int iRowid = ++pParse->nMem; /* Used for storing rowid values. */ int regRowid; /* Actual register containing rowids */ /* Collect rowids of every row to be deleted. */ sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet); pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere,0,WHERE_DUPLICATES_OK); if( pWInfo==0 ) goto delete_from_cleanup; regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, iRowid, 0); sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, regRowid); if( db->flags & SQLITE_CountRows ){ sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1); } sqlite3WhereEnd(pWInfo); /* Delete every item whose key was written to the list during the ** database scan. We have to delete items after the scan is complete ** because deleting an item can change the scan order. */ end = sqlite3VdbeMakeLabel(v); /* Unless this is a view, open cursors for the table we are ** deleting from and all its indices. If this is a view, then the ** only effect this statement has is to fire the INSTEAD OF ** triggers. */ if( !isView ){ sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite); } addr = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, end, iRowid); /* Delete the row */ #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ const char *pVTab = (const char *)sqlite3GetVTable(db, pTab); sqlite3VtabMakeWritable(pParse, pTab); sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iRowid, pVTab, P4_VTAB); sqlite3MayAbort(pParse); }else #endif { int count = (pParse->nested==0); /* True to count changes */ sqlite3GenerateRowDelete(pParse, pTab, iCur, iRowid, count, pTrigger, OE_Default); } /* End of the delete loop */ sqlite3VdbeAddOp2(v, OP_Goto, 0, addr); sqlite3VdbeResolveLabel(v, end); /* Close the cursors open on the table and its indexes. */ if( !isView && !IsVirtual(pTab) ){ for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ sqlite3VdbeAddOp2(v, OP_Close, iCur + i, pIdx->tnum); } sqlite3VdbeAddOp1(v, OP_Close, iCur); } } /* 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 that were deleted. If this routine is ** generating code because of a call to sqlite3NestedParse(), do not ** invoke the callback function. */ if( (db->flags&SQLITE_CountRows) && !pParse->nested && !pParse->pTriggerTab ){ 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); return; } /* Make sure "isView" and other macros defined above are undefined. Otherwise ** thely 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 #endif #ifdef pTrigger #undef pTrigger #endif /* ** This routine generates VDBE code that causes a single row of a ** single table to be deleted. ** ** The VDBE must be in a particular state when this routine is called. ** These are the requirements: ** ** 1. A read/write cursor pointing to pTab, the table containing the row ** to be deleted, must be opened as cursor number $iCur. ** ** 2. Read/write cursors for all indices of pTab must be open as ** cursor number base+i for the i-th index. ** ** 3. The record number of the row to be deleted must be stored in ** memory cell iRowid. ** ** This routine generates code to remove both the table record and all ** index entries that point to that record. */ void sqlite3GenerateRowDelete( Parse *pParse, /* Parsing context */ Table *pTab, /* Table containing the row to be deleted */ int iCur, /* Cursor number for the table */ int iRowid, /* Memory cell that contains the rowid to delete */ int count, /* If non-zero, increment the row change counter */ Trigger *pTrigger, /* List of triggers to (potentially) fire */ int onconf /* Default ON CONFLICT policy for triggers */ ){ Vdbe *v = pParse->pVdbe; /* Vdbe */ int iOld = 0; /* First register in OLD.* array */ int iLabel; /* Label resolved to end of generated code */ /* Vdbe is guaranteed to have been allocated by this stage. */ assert( v ); /* Seek cursor iCur to the row to delete. If this row no longer exists ** (this can happen if a trigger program has already deleted it), do ** not attempt to delete it or fire any DELETE triggers. */ iLabel = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp3(v, OP_NotExists, iCur, iLabel, iRowid); /* If there are any triggers to fire, allocate a range of registers to ** use for the old.* references in the triggers. */ if( sqlite3FkRequired(pParse, pTab, 0, 0) || pTrigger ){ u32 mask; /* Mask of OLD.* columns in use */ int iCol; /* Iterator used while populating OLD.* */ /* TODO: Could use temporary registers here. Also could attempt to ** avoid copying the contents of the rowid register. */ mask = sqlite3TriggerOldmask(pParse, pTrigger, 0, pTab, onconf); mask |= sqlite3FkOldmask(pParse, pTab); iOld = pParse->nMem+1; pParse->nMem += (1 + pTab->nCol); /* Populate the OLD.* pseudo-table register array. These values will be ** used by any BEFORE and AFTER triggers that exist. */ sqlite3VdbeAddOp2(v, OP_Copy, iRowid, iOld); for(iCol=0; iCol<pTab->nCol; iCol++){ if( mask==0xffffffff || mask&(1<<iCol) ){ int iTarget = iOld + iCol + 1; sqlite3VdbeAddOp3(v, OP_Column, iCur, iCol, iTarget); sqlite3ColumnDefault(v, pTab, iCol, iTarget); } } /* Invoke BEFORE DELETE trigger programs. */ sqlite3CodeRowTrigger(pParse, pTrigger, TK_DELETE, 0, TRIGGER_BEFORE, pTab, iOld, onconf, iLabel ); /* Seek the cursor to the row to be deleted again. It may be that ** the BEFORE triggers coded above have already removed the row ** being deleted. Do not attempt to delete the row a second time, and ** do not fire AFTER triggers. */ sqlite3VdbeAddOp3(v, OP_NotExists, iCur, iLabel, iRowid); /* Do FK processing. This call checks that any FK constraints that ** refer to this table (i.e. constraints attached to other tables) ** are not violated by deleting this row. */ sqlite3FkCheck(pParse, pTab, iOld, 0); } /* Delete the index and table entries. Skip this step if pTab is really ** a view (in which case the only effect of the DELETE statement is to ** fire the INSTEAD OF triggers). */ if( pTab->pSelect==0 ){ sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, 0); sqlite3VdbeAddOp2(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0)); if( count ){ sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_STATIC); } } /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to ** handle rows (possibly in other tables) that refer via a foreign key ** to the row just deleted. */ sqlite3FkActions(pParse, pTab, 0, iOld); /* Invoke AFTER DELETE trigger programs. */ sqlite3CodeRowTrigger(pParse, pTrigger, TK_DELETE, 0, TRIGGER_AFTER, pTab, iOld, onconf, iLabel ); /* Jump here if the row had already been deleted before any BEFORE ** trigger programs were invoked. Or if a trigger program throws a ** RAISE(IGNORE) exception. */ sqlite3VdbeResolveLabel(v, iLabel); } /* ** This routine generates VDBE code that causes the deletion of all ** index entries associated with a single row of a single table. ** ** The VDBE must be in a particular state when this routine is called. |
︙ | ︙ | |||
603 604 605 606 607 608 609 | sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regBase+nCol); for(j=0; j<nCol; j++){ int idx = pIdx->aiColumn[j]; if( idx==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_SCopy, regBase+nCol, regBase+j); }else{ sqlite3VdbeAddOp3(v, OP_Column, iCur, idx, regBase+j); | | | < < < < < | 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 | sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regBase+nCol); for(j=0; j<nCol; j++){ int idx = pIdx->aiColumn[j]; if( idx==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_SCopy, regBase+nCol, regBase+j); }else{ sqlite3VdbeAddOp3(v, OP_Column, iCur, idx, regBase+j); sqlite3ColumnDefault(v, pTab, idx, -1); } } if( doMakeRec ){ sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol+1, regOut); sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), 0); sqlite3ExprCacheAffinityChange(pParse, regBase, nCol+1); } sqlite3ReleaseTempRange(pParse, regBase, nCol+1); return regBase; } |
Changes to src/expr.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. | < < | 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 contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. */ #include "sqliteInt.h" /* ** Return the 'affinity' of the expression pExpr if any. ** ** If pExpr is a column, a reference to a column via an 'AS' alias, |
︙ | ︙ | |||
88 89 90 91 92 93 94 | CollSeq *pColl = 0; Expr *p = pExpr; while( ALWAYS(p) ){ int op; pColl = p->pColl; if( pColl ) break; op = p->op; | > | > | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | CollSeq *pColl = 0; Expr *p = pExpr; while( ALWAYS(p) ){ int op; pColl = p->pColl; if( pColl ) break; op = p->op; if( p->pTab!=0 && ( op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_REGISTER || op==TK_TRIGGER )){ /* op==TK_REGISTER && p->pTab!=0 happens when pExpr was originally ** a TK_COLUMN but was previously evaluated and cached in a register */ const char *zColl; int j = p->iColumn; if( j>=0 ){ sqlite3 *db = pParse->db; zColl = p->pTab->aCol[j].zColl; |
︙ | ︙ | |||
148 149 150 151 152 153 154 | ** 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 || | | | 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | ** 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 ){ |
︙ | ︙ | |||
567 568 569 570 571 572 573 | assert( !ExprHasAnyProperty(pExpr, EP_IntValue|EP_Reduced|EP_TokenOnly) ); z = pExpr->u.zToken; assert( z!=0 ); assert( z[0]!=0 ); if( z[1]==0 ){ /* Wildcard of the form "?". Assign the next variable number */ assert( z[0]=='?' ); | | < | > | 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 | assert( !ExprHasAnyProperty(pExpr, EP_IntValue|EP_Reduced|EP_TokenOnly) ); z = pExpr->u.zToken; assert( z!=0 ); assert( z[0]!=0 ); if( z[1]==0 ){ /* Wildcard of the form "?". Assign the next variable number */ assert( z[0]=='?' ); pExpr->iColumn = (ynVar)(++pParse->nVar); }else if( z[0]=='?' ){ /* Wildcard of the form "?nnn". Convert "nnn" to an integer and ** use it as the variable number */ int i = atoi((char*)&z[1]); pExpr->iColumn = (ynVar)i; testcase( i==0 ); testcase( i==1 ); testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]-1 ); testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ); if( 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]); |
︙ | ︙ | |||
596 597 598 599 600 601 602 | int i; u32 n; n = sqlite3Strlen30(z); for(i=0; i<pParse->nVarExpr; i++){ Expr *pE = pParse->apVarExpr[i]; assert( pE!=0 ); if( memcmp(pE->u.zToken, z, n)==0 && pE->u.zToken[n]==0 ){ | | | | 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 | int i; u32 n; n = sqlite3Strlen30(z); for(i=0; i<pParse->nVarExpr; i++){ Expr *pE = pParse->apVarExpr[i]; assert( pE!=0 ); if( memcmp(pE->u.zToken, z, n)==0 && pE->u.zToken[n]==0 ){ pExpr->iColumn = pE->iColumn; break; } } if( i>=pParse->nVarExpr ){ pExpr->iColumn = (ynVar)(++pParse->nVar); if( pParse->nVarExpr>=pParse->nVarExprAlloc-1 ){ pParse->nVarExprAlloc += pParse->nVarExprAlloc + 10; pParse->apVarExpr = sqlite3DbReallocOrFree( db, pParse->apVarExpr, pParse->nVarExprAlloc*sizeof(pParse->apVarExpr[0]) |
︙ | ︙ | |||
882 883 884 885 886 887 888 | pNew->a = pItem = sqlite3DbMallocRaw(db, p->nExpr*sizeof(p->a[0]) ); if( pItem==0 ){ sqlite3DbFree(db, pNew); return 0; } pOldItem = p->a; for(i=0; i<p->nExpr; i++, pItem++, pOldItem++){ | < | | 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 | pNew->a = pItem = sqlite3DbMallocRaw(db, p->nExpr*sizeof(p->a[0]) ); if( pItem==0 ){ sqlite3DbFree(db, pNew); return 0; } pOldItem = p->a; for(i=0; i<p->nExpr; i++, pItem++, pOldItem++){ Expr *pOldExpr = pOldItem->pExpr; pItem->pExpr = sqlite3ExprDup(db, pOldExpr, flags); pItem->zName = sqlite3DbStrDup(db, pOldItem->zName); pItem->zSpan = sqlite3DbStrDup(db, pOldItem->zSpan); pItem->sortOrder = pOldItem->sortOrder; pItem->done = 0; pItem->iCol = pOldItem->iCol; pItem->iAlias = pOldItem->iAlias; } |
︙ | ︙ | |||
1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 | */ #ifndef SQLITE_OMIT_SUBQUERY int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ 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 = (prNotFound==0); /* True if RHS must be unique */ /* 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. */ p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0); if( ALWAYS(pParse->nErr==0) && isCandidateForInOpt(p) ){ | > > | 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 | */ #ifndef SQLITE_OMIT_SUBQUERY int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){ 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 = (prNotFound==0); /* True if RHS must be unique */ assert( pX->op==TK_IN ); /* 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. */ p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0); if( ALWAYS(pParse->nErr==0) && isCandidateForInOpt(p) ){ |
︙ | ︙ | |||
1395 1396 1397 1398 1399 1400 1401 | ** has already been allocated. So assume sqlite3GetVdbe() is always ** successful here. */ assert(v); if( iCol<0 ){ int iMem = ++pParse->nMem; int iAddr; | < | 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 | ** has already been allocated. So assume sqlite3GetVdbe() is always ** successful here. */ assert(v); if( iCol<0 ){ int iMem = ++pParse->nMem; int iAddr; iAddr = sqlite3VdbeAddOp1(v, OP_If, iMem); sqlite3VdbeAddOp2(v, OP_Integer, 1, iMem); sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); eType = IN_INDEX_ROWID; |
︙ | ︙ | |||
1429 1430 1431 1432 1433 1434 1435 | && (!mustBeUnique || (pIdx->nColumn==1 && pIdx->onError!=OE_None)) ){ int iMem = ++pParse->nMem; int iAddr; char *pKey; pKey = (char *)sqlite3IndexKeyinfo(pParse, pIdx); | < < < | | 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 | && (!mustBeUnique || (pIdx->nColumn==1 && pIdx->onError!=OE_None)) ){ int iMem = ++pParse->nMem; int iAddr; char *pKey; pKey = (char *)sqlite3IndexKeyinfo(pParse, pIdx); iAddr = sqlite3VdbeAddOp1(v, OP_If, iMem); sqlite3VdbeAddOp2(v, OP_Integer, 1, iMem); sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb, pKey,P4_KEYINFO_HANDOFF); VdbeComment((v, "%s", pIdx->zName)); eType = IN_INDEX_INDEX; sqlite3VdbeJumpHere(v, iAddr); if( prNotFound && !pTab->aCol[iCol].notNull ){ *prNotFound = ++pParse->nMem; } } } } } if( eType==0 ){ /* Could not found an existing table or index to use as the RHS b-tree. ** We will have to generate an ephemeral table to do the job. */ int rMayHaveNull = 0; eType = IN_INDEX_EPH; if( prNotFound ){ *prNotFound = rMayHaveNull = ++pParse->nMem; }else if( pX->pLeft->iColumn<0 && !ExprHasAnyProperty(pX, EP_xIsSelect) ){ |
︙ | ︙ | |||
1497 1498 1499 1500 1501 1502 1503 1504 1505 | ** all corresponding LHS elements. All this routine does is initialize ** the register given by rMayHaveNull to NULL. Calling routines will take ** care of changing this register value to non-NULL if the RHS is NULL-free. ** ** If rMayHaveNull is zero, that means that the subquery is being used ** for membership testing only. There is no need to initialize any ** registers to indicate the presense or absence of NULLs on the RHS. */ #ifndef SQLITE_OMIT_SUBQUERY | > > > | > | | | 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 | ** all corresponding LHS elements. All this routine does is initialize ** the register given by rMayHaveNull to NULL. Calling routines will take ** care of changing this register value to non-NULL if the RHS is NULL-free. ** ** If rMayHaveNull is zero, that means that the subquery is being used ** for membership testing only. There is no need to initialize any ** registers to indicate the presense or absence of NULLs on the RHS. ** ** For a SELECT or EXISTS operator, return the register that holds the ** result. For IN operators or if an error occurs, the return value is 0. */ #ifndef SQLITE_OMIT_SUBQUERY int sqlite3CodeSubselect( Parse *pParse, /* Parsing context */ Expr *pExpr, /* The IN, SELECT, or EXISTS operator */ int rMayHaveNull, /* Register that records whether NULLs exist in RHS */ int isRowid /* If true, LHS of IN operator is a rowid */ ){ int testAddr = 0; /* One-time test address */ int rReg = 0; /* Register storing resulting */ Vdbe *v = sqlite3GetVdbe(pParse); if( NEVER(v==0) ) return 0; sqlite3ExprCachePush(pParse); /* This code must be run in its entirety 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( !ExprHasAnyProperty(pExpr, EP_VarSelect) && !pParse->pTriggerTab ){ int mem = ++pParse->nMem; sqlite3VdbeAddOp1(v, OP_If, mem); testAddr = sqlite3VdbeAddOp2(v, OP_Integer, 1, mem); assert( testAddr>0 || pParse->db->mallocFailed ); } switch( pExpr->op ){ |
︙ | ︙ | |||
1572 1573 1574 1575 1576 1577 1578 | ExprList *pEList; assert( !isRowid ); sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable); dest.affinity = (u8)affinity; assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable ); if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){ | | | 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 | ExprList *pEList; assert( !isRowid ); sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable); dest.affinity = (u8)affinity; assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable ); if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){ return 0; } pEList = pExpr->x.pSelect->pEList; if( ALWAYS(pEList!=0 && pEList->nExpr>0) ){ keyInfo.aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pEList->a[0].pExpr); } }else if( pExpr->x.pList!=0 ){ |
︙ | ︙ | |||
1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 | /* Loop through each expression in <exprlist>. */ r1 = sqlite3GetTempReg(pParse); r2 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_Null, 0, r2); 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( testAddr && !sqlite3ExprIsConstant(pE2) ){ sqlite3VdbeChangeToNoop(v, testAddr-1, 2); testAddr = 0; } /* Evaluate the expression and insert it into the temp table */ | > > > > | | | > | | | | | > | 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 | /* Loop through each expression in <exprlist>. */ r1 = sqlite3GetTempReg(pParse); r2 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_Null, 0, r2); for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){ Expr *pE2 = pItem->pExpr; int iValToIns; /* 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( testAddr && !sqlite3ExprIsConstant(pE2) ){ sqlite3VdbeChangeToNoop(v, testAddr-1, 2); testAddr = 0; } /* Evaluate the expression and insert it into the temp table */ if( isRowid && sqlite3ExprIsInteger(pE2, &iValToIns) ){ sqlite3VdbeAddOp3(v, OP_InsertInt, pExpr->iTable, r2, iValToIns); }else{ r3 = sqlite3ExprCodeTarget(pParse, pE2, r1); if( isRowid ){ sqlite3VdbeAddOp2(v, OP_MustBeInt, r3, sqlite3VdbeCurrentAddr(v)+2); sqlite3VdbeAddOp3(v, OP_Insert, pExpr->iTable, r2, r3); }else{ sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1); sqlite3ExprCacheAffinityChange(pParse, r3, 1); sqlite3VdbeAddOp2(v, OP_IdxInsert, pExpr->iTable, r2); } } } sqlite3ReleaseTempReg(pParse, r1); sqlite3ReleaseTempReg(pParse, r2); } if( !isRowid ){ sqlite3VdbeChangeP4(v, addr, (void *)&keyInfo, P4_KEYINFO); |
︙ | ︙ | |||
1666 1667 1668 1669 1670 1671 1672 | dest.eDest = SRT_Exists; sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iParm); VdbeComment((v, "Init EXISTS result")); } sqlite3ExprDelete(pParse->db, pSel->pLimit); pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &one); if( sqlite3Select(pParse, pSel, &dest) ){ | | | | | 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 | dest.eDest = SRT_Exists; sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iParm); VdbeComment((v, "Init EXISTS result")); } sqlite3ExprDelete(pParse->db, pSel->pLimit); pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &one); if( sqlite3Select(pParse, pSel, &dest) ){ return 0; } rReg = dest.iParm; ExprSetIrreducible(pExpr); break; } } if( testAddr ){ sqlite3VdbeJumpHere(v, testAddr-1); } sqlite3ExprCachePop(pParse, 1); return rReg; } #endif /* SQLITE_OMIT_SUBQUERY */ /* ** Duplicate an 8-byte value */ static char *dup8bytes(Vdbe *v, const char *in){ |
︙ | ︙ | |||
1707 1708 1709 1710 1711 1712 1713 | ** like the continuation of the number. */ static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){ if( ALWAYS(z!=0) ){ double value; char *zV; sqlite3AtoF(z, &value); | | < < | | | < | 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 | ** like the continuation of the number. */ static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){ if( ALWAYS(z!=0) ){ double value; char *zV; sqlite3AtoF(z, &value); assert( !sqlite3IsNaN(value) ); /* The new AtoF never returns NaN */ if( negateFlag ) value = -value; zV = dup8bytes(v, (char*)&value); sqlite3VdbeAddOp4(v, OP_Real, 0, iMem, 0, zV, P4_REAL); } } /* ** Generate an instruction that will put the integer describe by ** text z[0..n-1] into register iMem. |
︙ | ︙ | |||
1921 1922 1923 1924 1925 1926 1927 | } assert( v!=0 ); if( iColumn<0 ){ sqlite3VdbeAddOp2(v, OP_Rowid, iTable, iReg); }else if( ALWAYS(pTab!=0) ){ int op = IsVirtual(pTab) ? OP_VColumn : OP_Column; sqlite3VdbeAddOp3(v, op, iTable, iColumn, iReg); | | < < < < < | 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 | } assert( v!=0 ); if( iColumn<0 ){ sqlite3VdbeAddOp2(v, OP_Rowid, iTable, iReg); }else if( ALWAYS(pTab!=0) ){ int op = IsVirtual(pTab) ? OP_VColumn : OP_Column; sqlite3VdbeAddOp3(v, op, iTable, iColumn, iReg); sqlite3ColumnDefault(v, pTab, iColumn, iReg); } sqlite3ExprCacheStore(pParse, iTable, iColumn, iReg); return iReg; } /* ** Clear all column cache entries. |
︙ | ︙ | |||
2173 2174 2175 2176 2177 2178 2179 | case TK_VARIABLE: { VdbeOp *pOp; assert( !ExprHasProperty(pExpr, EP_IntValue) ); assert( pExpr->u.zToken!=0 ); assert( pExpr->u.zToken[0]!=0 ); if( pExpr->u.zToken[1]==0 && (pOp = sqlite3VdbeGetOp(v, -1))->opcode==OP_Variable | | | | 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 | case TK_VARIABLE: { VdbeOp *pOp; assert( !ExprHasProperty(pExpr, EP_IntValue) ); assert( pExpr->u.zToken!=0 ); assert( pExpr->u.zToken[0]!=0 ); if( pExpr->u.zToken[1]==0 && (pOp = sqlite3VdbeGetOp(v, -1))->opcode==OP_Variable && pOp->p1+pOp->p3==pExpr->iColumn && pOp->p2+pOp->p3==target && pOp->p4.z==0 ){ /* If the previous instruction was a copy of the previous unnamed ** parameter into the previous register, then simply increment the ** repeat count on the prior instruction rather than making a new ** instruction. */ pOp->p3++; }else{ sqlite3VdbeAddOp3(v, OP_Variable, pExpr->iColumn, target, 1); if( pExpr->u.zToken[1]!=0 ){ sqlite3VdbeChangeP4(v, -1, pExpr->u.zToken, 0); } } break; } case TK_REGISTER: { |
︙ | ︙ | |||
2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 | codeCompareOperands(pParse, pExpr->pLeft, &r1, ®Free1, pExpr->pRight, &r2, ®Free2); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, r1, r2, inReg, SQLITE_STOREP2); testcase( regFree1==0 ); testcase( regFree2==0 ); break; } case TK_AND: case TK_OR: case TK_PLUS: case TK_STAR: case TK_MINUS: case TK_REM: | > > > > > > > > > > > > > | 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 | codeCompareOperands(pParse, pExpr->pLeft, &r1, ®Free1, pExpr->pRight, &r2, ®Free2); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, r1, r2, inReg, SQLITE_STOREP2); testcase( regFree1==0 ); testcase( regFree2==0 ); break; } case TK_IS: case TK_ISNOT: { testcase( op==TK_IS ); testcase( op==TK_ISNOT ); codeCompareOperands(pParse, pExpr->pLeft, &r1, ®Free1, pExpr->pRight, &r2, ®Free2); op = (op==TK_IS) ? TK_EQ : TK_NE; codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, r1, r2, inReg, SQLITE_STOREP2 | SQLITE_NULLEQ); testcase( regFree1==0 ); testcase( regFree2==0 ); break; } case TK_AND: case TK_OR: case TK_PLUS: case TK_STAR: case TK_MINUS: case TK_REM: |
︙ | ︙ | |||
2374 2375 2376 2377 2378 2379 2380 | pFarg = pExpr->x.pList; } nFarg = pFarg ? pFarg->nExpr : 0; assert( !ExprHasProperty(pExpr, EP_IntValue) ); zId = pExpr->u.zToken; nId = sqlite3Strlen30(zId); pDef = sqlite3FindFunction(db, zId, nId, nFarg, enc, 0); | > > > > > > > > > > > | > > > > > > > > > > > > > > > | 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 | pFarg = pExpr->x.pList; } nFarg = pFarg ? pFarg->nExpr : 0; assert( !ExprHasProperty(pExpr, EP_IntValue) ); zId = pExpr->u.zToken; nId = sqlite3Strlen30(zId); pDef = sqlite3FindFunction(db, zId, nId, nFarg, enc, 0); if( pDef==0 ){ sqlite3ErrorMsg(pParse, "unknown function: %.*s()", nId, zId); break; } /* Attempt a direct implementation of the built-in COALESCE() and ** IFNULL() functions. This avoids unnecessary evalation of ** arguments past the first non-NULL argument. */ if( pDef->flags & SQLITE_FUNC_COALESCE ){ int endCoalesce = sqlite3VdbeMakeLabel(v); assert( nFarg>=2 ); sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target); for(i=1; i<nFarg; i++){ sqlite3VdbeAddOp2(v, OP_NotNull, target, endCoalesce); sqlite3ExprCacheRemove(pParse, target); sqlite3ExprCachePush(pParse); sqlite3ExprCode(pParse, pFarg->a[i].pExpr, target); sqlite3ExprCachePop(pParse, 1); } sqlite3VdbeResolveLabel(v, endCoalesce); break; } if( pFarg ){ r1 = sqlite3GetTempRange(pParse, nFarg); sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */ sqlite3ExprCodeExprList(pParse, pFarg, r1, 1); sqlite3ExprCachePop(pParse, 1); /* Ticket 2ea2425d34be */ }else{ r1 = 0; } #ifndef SQLITE_OMIT_VIRTUALTABLE /* Possibly overload the function if the first argument is ** a virtual table column. ** |
︙ | ︙ | |||
2426 2427 2428 2429 2430 2431 2432 | break; } #ifndef SQLITE_OMIT_SUBQUERY case TK_EXISTS: case TK_SELECT: { testcase( op==TK_EXISTS ); testcase( op==TK_SELECT ); | | < | 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 | break; } #ifndef SQLITE_OMIT_SUBQUERY case TK_EXISTS: case TK_SELECT: { testcase( op==TK_EXISTS ); testcase( op==TK_SELECT ); inReg = sqlite3CodeSubselect(pParse, pExpr, 0, 0); break; } case TK_IN: { int rNotFound = 0; int rMayHaveNull = 0; int j2, j3, j4, j5; char affinity; |
︙ | ︙ | |||
2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 | sqlite3ReleaseTempReg(pParse, r4); break; } case TK_UPLUS: { inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); break; } /* ** Form A: ** CASE x WHEN e1 THEN r1 WHEN e2 THEN r2 ... WHEN eN THEN rN ELSE y END ** ** Form B: ** CASE WHEN e1 THEN r1 WHEN e2 THEN r2 ... WHEN eN THEN rN ELSE y END | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | sqlite3ReleaseTempReg(pParse, r4); break; } case TK_UPLUS: { inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); break; } case TK_TRIGGER: { /* If the opcode is TK_TRIGGER, then the expression is a reference ** to a column in the new.* or old.* pseudo-tables available to ** trigger programs. In this case Expr.iTable is set to 1 for the ** new.* pseudo-table, or 0 for the old.* pseudo-table. Expr.iColumn ** is set to the column of the pseudo-table to read, or to -1 to ** read the rowid field. ** ** The expression is implemented using an OP_Param opcode. The p1 ** parameter is set to 0 for an old.rowid reference, or to (i+1) ** to reference another column of the old.* pseudo-table, where ** i is the index of the column. For a new.rowid reference, p1 is ** set to (n+1), where n is the number of columns in each pseudo-table. ** For a reference to any other column in the new.* pseudo-table, p1 ** is set to (n+2+i), where n and i are as defined previously. For ** example, if the table on which triggers are being fired is ** declared as: ** ** CREATE TABLE t1(a, b); ** ** 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->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, "%s.%s -> $%d", (pExpr->iTable ? "new" : "old"), (pExpr->iColumn<0 ? "rowid" : pExpr->pTab->aCol[pExpr->iColumn].zName), target )); /* If the column has REAL affinity, it may currently be stored as an ** integer. Use OP_RealAffinity to make sure it is really real. */ if( pExpr->iColumn>=0 && pTab->aCol[pExpr->iColumn].affinity==SQLITE_AFF_REAL ){ sqlite3VdbeAddOp1(v, OP_RealAffinity, target); } break; } /* ** Form A: ** CASE x WHEN e1 THEN r1 WHEN e2 THEN r2 ... WHEN eN THEN rN ELSE y END ** ** Form B: ** CASE WHEN e1 THEN r1 WHEN e2 THEN r2 ... WHEN eN THEN rN ELSE y END |
︙ | ︙ | |||
2644 2645 2646 2647 2648 2649 2650 | assert( db->mallocFailed || pParse->nErr>0 || pParse->iCacheLevel==iCacheLevel ); sqlite3VdbeResolveLabel(v, endLabel); break; } #ifndef SQLITE_OMIT_TRIGGER case TK_RAISE: { | > > > > > | | < | < > | > | | | | < < < > | 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 | assert( db->mallocFailed || pParse->nErr>0 || pParse->iCacheLevel==iCacheLevel ); 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); }else{ sqlite3HaltConstraint(pParse, pExpr->affinity, pExpr->u.zToken, 0); } break; } #endif } sqlite3ReleaseTempReg(pParse, regFree1); sqlite3ReleaseTempReg(pParse, regFree2); return inReg; |
︙ | ︙ | |||
2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 | ** keep the ALWAYS() in case the conditions above change with future ** modifications or enhancements. */ if( ALWAYS(pExpr->op!=TK_REGISTER) ){ int iMem; iMem = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Copy, inReg, iMem); pExpr->iTable = iMem; pExpr->op = TK_REGISTER; } return inReg; } /* ** Return TRUE if pExpr is an constant expression that is appropriate | > | 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 | ** keep the ALWAYS() in case the conditions above change with future ** modifications or enhancements. */ if( ALWAYS(pExpr->op!=TK_REGISTER) ){ int iMem; iMem = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Copy, inReg, iMem); pExpr->iTable = iMem; pExpr->op2 = pExpr->op; pExpr->op = TK_REGISTER; } return inReg; } /* ** Return TRUE if pExpr is an constant expression that is appropriate |
︙ | ︙ | |||
2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 | ** factoring out of a loop, then evaluate the expression ** into a register and convert the expression into a TK_REGISTER ** expression. */ static int evalConstExpr(Walker *pWalker, Expr *pExpr){ Parse *pParse = pWalker->pParse; switch( pExpr->op ){ case TK_REGISTER: { return WRC_Prune; } case TK_FUNCTION: case TK_AGG_FUNCTION: case TK_CONST_FUNC: { /* The arguments to a function have a fixed destination. | > | 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 | ** factoring out of a loop, then evaluate the expression ** into a register and convert the expression into a TK_REGISTER ** expression. */ static int evalConstExpr(Walker *pWalker, Expr *pExpr){ Parse *pParse = pWalker->pParse; switch( pExpr->op ){ case TK_IN: case TK_REGISTER: { return WRC_Prune; } case TK_FUNCTION: case TK_AGG_FUNCTION: case TK_CONST_FUNC: { /* The arguments to a function have a fixed destination. |
︙ | ︙ | |||
2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 | } } if( isAppropriateForFactoring(pExpr) ){ int r1 = ++pParse->nMem; int r2; r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1); if( NEVER(r1!=r2) ) sqlite3ReleaseTempReg(pParse, r1); pExpr->op = TK_REGISTER; pExpr->iTable = r2; return WRC_Prune; } return WRC_Continue; } | > | 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 | } } if( isAppropriateForFactoring(pExpr) ){ int r1 = ++pParse->nMem; int r2; r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1); if( NEVER(r1!=r2) ) sqlite3ReleaseTempReg(pParse, r1); pExpr->op2 = pExpr->op; pExpr->op = TK_REGISTER; pExpr->iTable = r2; return WRC_Prune; } return WRC_Continue; } |
︙ | ︙ | |||
2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 | codeCompareOperands(pParse, pExpr->pLeft, &r1, ®Free1, pExpr->pRight, &r2, ®Free2); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, r1, r2, dest, jumpIfNull); testcase( regFree1==0 ); testcase( regFree2==0 ); break; } case TK_ISNULL: case TK_NOTNULL: { assert( TK_ISNULL==OP_IsNull ); assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_ISNULL ); testcase( op==TK_NOTNULL ); | > > > > > > > > > > > > > | 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 | codeCompareOperands(pParse, pExpr->pLeft, &r1, ®Free1, pExpr->pRight, &r2, ®Free2); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, r1, r2, dest, jumpIfNull); testcase( regFree1==0 ); testcase( regFree2==0 ); break; } case TK_IS: case TK_ISNOT: { testcase( op==TK_IS ); testcase( op==TK_ISNOT ); codeCompareOperands(pParse, pExpr->pLeft, &r1, ®Free1, pExpr->pRight, &r2, ®Free2); op = (op==TK_IS) ? TK_EQ : TK_NE; codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, r1, r2, dest, SQLITE_NULLEQ); testcase( regFree1==0 ); testcase( regFree2==0 ); break; } case TK_ISNULL: case TK_NOTNULL: { assert( TK_ISNULL==OP_IsNull ); assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_ISNULL ); testcase( op==TK_NOTNULL ); |
︙ | ︙ | |||
3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 | codeCompareOperands(pParse, pExpr->pLeft, &r1, ®Free1, pExpr->pRight, &r2, ®Free2); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, r1, r2, dest, jumpIfNull); testcase( regFree1==0 ); testcase( regFree2==0 ); break; } case TK_ISNULL: case TK_NOTNULL: { testcase( op==TK_ISNULL ); testcase( op==TK_NOTNULL ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); sqlite3VdbeAddOp2(v, op, r1, dest); | > > > > > > > > > > > > > | 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 | codeCompareOperands(pParse, pExpr->pLeft, &r1, ®Free1, pExpr->pRight, &r2, ®Free2); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, r1, r2, dest, jumpIfNull); testcase( regFree1==0 ); testcase( regFree2==0 ); break; } case TK_IS: case TK_ISNOT: { testcase( pExpr->op==TK_IS ); testcase( pExpr->op==TK_ISNOT ); codeCompareOperands(pParse, pExpr->pLeft, &r1, ®Free1, pExpr->pRight, &r2, ®Free2); op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ; codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, r1, r2, dest, SQLITE_NULLEQ); testcase( regFree1==0 ); testcase( regFree2==0 ); break; } case TK_ISNULL: case TK_NOTNULL: { testcase( op==TK_ISNULL ); testcase( op==TK_NOTNULL ); r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1); sqlite3VdbeAddOp2(v, op, r1, dest); |
︙ | ︙ |
Changes to src/fault.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 2008 Jan 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 | /* ** 2008 Jan 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains code to support the concept of "benign" ** malloc failures (when the xMalloc() or xRealloc() method of the ** sqlite3_mem_methods structure fails to allocate a block of memory ** and returns 0). ** ** Most malloc failures are non-benign. After they occur, SQLite ** abandons the current operation and returns an error code (usually |
︙ | ︙ |
Added src/fkey.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 | /* ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used by the compiler to add foreign key ** support to compiled SQL statements. */ #include "sqliteInt.h" #ifndef SQLITE_OMIT_FOREIGN_KEY #ifndef SQLITE_OMIT_TRIGGER /* ** Deferred and Immediate FKs ** -------------------------- ** ** Foreign keys in SQLite come in two flavours: deferred and immediate. ** If an immediate foreign key constraint is violated, SQLITE_CONSTRAINT ** is returned and the current statement transaction rolled back. If a ** deferred foreign key constraint is violated, no action is taken ** immediately. However if the application attempts to commit the ** transaction before fixing the constraint violation, the attempt fails. ** ** Deferred constraints are implemented using a simple counter associated ** with the database handle. The counter is set to zero each time a ** database transaction is opened. Each time a statement is executed ** that causes a foreign key violation, the counter is incremented. Each ** time a statement is executed that removes an existing violation from ** the database, the counter is decremented. When the transaction is ** committed, the commit fails if the current value of the counter is ** greater than zero. This scheme has two big drawbacks: ** ** * When a commit fails due to a deferred foreign key constraint, ** there is no way to tell which foreign constraint is not satisfied, ** or which row it is not satisfied for. ** ** * If the database contains foreign key violations when the ** transaction is opened, this may cause the mechanism to malfunction. ** ** Despite these problems, this approach is adopted as it seems simpler ** than the alternatives. ** ** INSERT operations: ** ** I.1) For each FK for which the table is the child table, search ** the parent table for a match. If none is found increment the ** constraint counter. ** ** I.2) For each FK for which the table is the parent table, ** search the child table for rows that correspond to the new ** row in the parent table. Decrement the counter for each row ** found (as the constraint is now satisfied). ** ** DELETE operations: ** ** D.1) For each FK for which the table is the child table, ** search the parent table for a row that corresponds to the ** deleted row in the child table. If such a row is not found, ** decrement the counter. ** ** D.2) For each FK for which the table is the parent table, search ** the child table for rows that correspond to the deleted row ** in the parent table. For each found increment the counter. ** ** UPDATE operations: ** ** An UPDATE command requires that all 4 steps above are taken, but only ** for FK constraints for which the affected columns are actually ** modified (values must be compared at runtime). ** ** Note that I.1 and D.1 are very similar operations, as are I.2 and D.2. ** This simplifies the implementation a bit. ** ** For the purposes of immediate FK constraints, the OR REPLACE conflict ** resolution is considered to delete rows before the new row is inserted. ** If a delete caused by OR REPLACE violates an FK constraint, an exception ** is thrown, even if the FK constraint would be satisfied after the new ** row is inserted. ** ** Immediate constraints are usually handled similarly. The only difference ** is that the counter used is stored as part of each individual statement ** object (struct Vdbe). If, after the statement has run, its immediate ** constraint counter is greater than zero, it returns SQLITE_CONSTRAINT ** and the statement transaction is rolled back. An exception is an INSERT ** statement that inserts a single row only (no triggers). In this case, ** instead of using a counter, an exception is thrown immediately if the ** INSERT violates a foreign key constraint. This is necessary as such ** an INSERT does not open a statement transaction. ** ** TODO: How should dropping a table be handled? How should renaming a ** table be handled? ** ** ** Query API Notes ** --------------- ** ** Before coding an UPDATE or DELETE row operation, the code-generator ** for those two operations needs to know whether or not the operation ** requires any FK processing and, if so, which columns of the original ** row are required by the FK processing VDBE code (i.e. if FKs were ** implemented using triggers, which of the old.* columns would be ** accessed). No information is required by the code-generator before ** coding an INSERT operation. The functions used by the UPDATE/DELETE ** generation code to query for this information are: ** ** sqlite3FkRequired() - Test to see if FK processing is required. ** sqlite3FkOldmask() - Query for the set of required old.* columns. ** ** ** Externally accessible module functions ** -------------------------------------- ** ** sqlite3FkCheck() - Check for foreign key violations. ** sqlite3FkActions() - Code triggers for ON UPDATE/ON DELETE actions. ** sqlite3FkDelete() - Delete an FKey structure. */ /* ** VDBE Calling Convention ** ----------------------- ** ** Example: ** ** For the following INSERT statement: ** ** CREATE TABLE t1(a, b INTEGER PRIMARY KEY, c); ** INSERT INTO t1 VALUES(1, 2, 3.1); ** ** Register (x): 2 (type integer) ** Register (x+1): 1 (type integer) ** Register (x+2): NULL (type NULL) ** Register (x+3): 3.1 (type real) */ /* ** A foreign key constraint requires that the key columns in the parent ** table are collectively subject to a UNIQUE or PRIMARY KEY constraint. ** Given that pParent is the parent table for foreign key constraint pFKey, ** search the schema a unique index on the parent key columns. ** ** If successful, zero is returned. If the parent key is an INTEGER PRIMARY ** KEY column, then output variable *ppIdx is set to NULL. Otherwise, *ppIdx ** is set to point to the unique index. ** ** If the parent key consists of a single column (the foreign key constraint ** is not a composite foreign key), output variable *paiCol is set to NULL. ** Otherwise, it is set to point to an allocated array of size N, where ** N is the number of columns in the parent key. The first element of the ** array is the index of the child table column that is mapped by the FK ** constraint to the parent table column stored in the left-most column ** of index *ppIdx. The second element of the array is the index of the ** child table column that corresponds to the second left-most column of ** *ppIdx, and so on. ** ** If the required index cannot be found, either because: ** ** 1) The named parent key columns do not exist, or ** ** 2) The named parent key columns do exist, but are not subject to a ** UNIQUE or PRIMARY KEY constraint, or ** ** 3) No parent key columns were provided explicitly as part of the ** foreign key definition, and the parent table does not have a ** PRIMARY KEY, or ** ** 4) No parent key columns were provided explicitly as part of the ** foreign key definition, and the PRIMARY KEY of the parent table ** consists of a a different number of columns to the child key in ** the child table. ** ** then non-zero is returned, and a "foreign key mismatch" error loaded ** into pParse. If an OOM error occurs, non-zero is returned and the ** pParse->db->mallocFailed flag is set. */ static int locateFkeyIndex( Parse *pParse, /* Parse context to store any error in */ Table *pParent, /* Parent table of FK constraint pFKey */ FKey *pFKey, /* Foreign key to find index for */ Index **ppIdx, /* OUT: Unique index on parent table */ int **paiCol /* OUT: Map of index columns in pFKey */ ){ Index *pIdx = 0; /* Value to return via *ppIdx */ int *aiCol = 0; /* Value to return via *paiCol */ int nCol = pFKey->nCol; /* Number of columns in parent key */ char *zKey = pFKey->aCol[0].zCol; /* Name of left-most parent key column */ /* The caller is responsible for zeroing output parameters. */ assert( ppIdx && *ppIdx==0 ); assert( !paiCol || *paiCol==0 ); assert( pParse ); /* If this is a non-composite (single column) foreign key, check if it ** maps to the INTEGER PRIMARY KEY of table pParent. If so, leave *ppIdx ** and *paiCol set to zero and return early. ** ** Otherwise, for a composite foreign key (more than one column), allocate ** space for the aiCol array (returned via output parameter *paiCol). ** Non-composite foreign keys do not require the aiCol array. */ if( nCol==1 ){ /* The FK maps to the IPK if any of the following are true: ** ** 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 *)sqlite3DbMallocRaw(pParse->db, nCol*sizeof(int)); if( !aiCol ) return 1; *paiCol = aiCol; } for(pIdx=pParent->pIndex; pIdx; pIdx=pIdx->pNext){ if( pIdx->nColumn==nCol && pIdx->onError!=OE_None ){ /* pIdx is a UNIQUE index (or a PRIMARY KEY) and has the right number ** of columns. If each indexed column corresponds to a foreign key ** column of pFKey, then this index is a winner. */ if( zKey==0 ){ /* If zKey is NULL, then this foreign key is implicitly mapped to ** the PRIMARY KEY of table pParent. The PRIMARY KEY index may be ** identified by the test (Index.autoIndex==2). */ if( pIdx->autoIndex==2 ){ if( aiCol ){ int i; for(i=0; i<nCol; i++) aiCol[i] = pFKey->aCol[i].iFrom; } break; } }else{ /* If zKey is non-NULL, then this foreign key was declared to ** map to an explicit list of columns in table pParent. Check if this ** index matches those columns. Also, check that the index uses ** the default collation sequences for each column. */ int i, j; for(i=0; i<nCol; i++){ int iCol = pIdx->aiColumn[i]; /* Index of column in parent tbl */ char *zDfltColl; /* Def. collation for column */ char *zIdxCol; /* Name of indexed column */ /* If the index uses a collation sequence that is different from ** the default collation sequence for the column, this index is ** unusable. Bail out early in this case. */ zDfltColl = pParent->aCol[iCol].zColl; if( !zDfltColl ){ zDfltColl = "BINARY"; } 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; } if( i==nCol ) break; /* pIdx is usable */ } } } if( !pIdx ){ if( !pParse->disableTriggers ){ sqlite3ErrorMsg(pParse, "foreign key mismatch"); } sqlite3DbFree(pParse->db, aiCol); return 1; } *ppIdx = pIdx; return 0; } /* ** This function is called when a row is inserted into or deleted from the ** child table of foreign key constraint pFKey. If an SQL UPDATE is executed ** on the child table of pFKey, this function is invoked twice for each row ** affected - once to "delete" the old row, and then again to "insert" the ** new row. ** ** Each time it is called, this function generates VDBE code to locate the ** row in the parent table that corresponds to the row being inserted into ** or deleted from the child table. If the parent row can be found, no ** special action is taken. Otherwise, if the parent row can *not* be ** found in the parent table: ** ** Operation | FK type | Action taken ** -------------------------------------------------------------------------- ** INSERT immediate Increment the "immediate constraint counter". ** ** DELETE immediate Decrement the "immediate constraint counter". ** ** INSERT deferred Increment the "deferred constraint counter". ** ** DELETE deferred Decrement the "deferred constraint counter". ** ** These operations are identified in the comment at the top of this file ** (fkey.c) as "I.1" and "D.1". */ static void fkLookupParent( Parse *pParse, /* Parse context */ int iDb, /* Index of database housing pTab */ Table *pTab, /* Parent table of FK pFKey */ Index *pIdx, /* Unique index on parent key columns in pTab */ FKey *pFKey, /* Foreign key constraint */ int *aiCol, /* Map from parent key columns to child table columns */ int regData, /* Address of array containing child table row */ int nIncr, /* Increment constraint counter by this */ int isIgnore /* If true, pretend pTab contains all NULL values */ ){ int i; /* Iterator variable */ Vdbe *v = sqlite3GetVdbe(pParse); /* Vdbe to add code to */ int iCur = pParse->nTab - 1; /* Cursor number to use */ int iOk = sqlite3VdbeMakeLabel(v); /* jump here if parent key found */ /* If nIncr is less than zero, then check at runtime if there are any ** outstanding constraints to resolve. If there are not, there is no need ** to check if deleting this row resolves any outstanding violations. ** ** Check if any of the key columns in the child table row are NULL. If ** any are, then the constraint is considered satisfied. No need to ** search for a matching row in the parent table. */ if( nIncr<0 ){ sqlite3VdbeAddOp2(v, OP_FkIfZero, pFKey->isDeferred, iOk); } for(i=0; i<pFKey->nCol; i++){ int iReg = aiCol[i] + regData + 1; sqlite3VdbeAddOp2(v, OP_IsNull, iReg, iOk); } 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); /* 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( pTab==pFKey->pFrom && nIncr==1 ){ sqlite3VdbeAddOp3(v, OP_Eq, regData, iOk, regTemp); } sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead); sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regTemp); sqlite3VdbeAddOp2(v, OP_Goto, 0, 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); KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); sqlite3VdbeAddOp3(v, OP_OpenRead, iCur, pIdx->tnum, iDb); sqlite3VdbeChangeP4(v, -1, (char*)pKey, P4_KEYINFO_HANDOFF); for(i=0; i<nCol; i++){ sqlite3VdbeAddOp2(v, OP_SCopy, 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( 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; sqlite3VdbeAddOp3(v, OP_Ne, iChild, iJump, iParent); } sqlite3VdbeAddOp2(v, OP_Goto, 0, iOk); } sqlite3VdbeAddOp3(v, OP_MakeRecord, regTemp, nCol, regRec); sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), 0); sqlite3VdbeAddOp3(v, OP_Found, iCur, iOk, regRec); sqlite3ReleaseTempReg(pParse, regRec); sqlite3ReleaseTempRange(pParse, regTemp, nCol); } } if( !pFKey->isDeferred && !pParse->pToplevel && !pParse->isMultiWrite ){ /* Special case: If this is an INSERT statement that will insert exactly ** one row into the table, raise a constraint immediately instead of ** incrementing a counter. This is necessary as the VM code is being ** generated for will not open a statement transaction. */ assert( nIncr==1 ); sqlite3HaltConstraint( pParse, OE_Abort, "foreign key constraint failed", P4_STATIC ); }else{ if( nIncr>0 && pFKey->isDeferred==0 ){ sqlite3ParseToplevel(pParse)->mayAbort = 1; } sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr); } sqlite3VdbeResolveLabel(v, iOk); sqlite3VdbeAddOp1(v, OP_Close, iCur); } /* ** This function is called to generate code executed when a row is deleted ** from the parent table of foreign key constraint pFKey and, if pFKey is ** deferred, when a row is inserted into the same table. When generating ** code for an SQL UPDATE operation, this function may be called twice - ** once to "delete" the old row and once to "insert" the new row. ** ** 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( Parse *pParse, /* Parse context */ SrcList *pSrc, /* SrcList containing the table to scan */ Table *pTab, Index *pIdx, /* Foreign key index */ FKey *pFKey, /* Foreign key relationship */ int *aiCol, /* Map from pIdx cols to child table cols */ int regData, /* Referenced table data starts here */ int nIncr /* Amount to increment deferred counter by */ ){ sqlite3 *db = pParse->db; /* Database handle */ int i; /* Iterator variable */ Expr *pWhere = 0; /* WHERE clause to scan with */ NameContext sNameContext; /* Context used to resolve WHERE clause */ WhereInfo *pWInfo; /* Context used by sqlite3WhereXXX() */ int iFkIfZero = 0; /* Address of OP_FkIfZero */ Vdbe *v = sqlite3GetVdbe(pParse); assert( !pIdx || pIdx->pTable==pTab ); if( nIncr<0 ){ iFkIfZero = sqlite3VdbeAddOp2(v, OP_FkIfZero, pFKey->isDeferred, 0); } /* Create an Expr object representing an SQL expression like: ** ** <parent-key1> = <child-key1> AND <parent-key2> = <child-key2> ... ** ** The collation sequence used for the comparison should be that of ** the parent key columns. The affinity of the parent key column should ** be applied to each child key value before the comparison takes place. */ for(i=0; i<pFKey->nCol; i++){ Expr *pLeft; /* Value from parent table row */ Expr *pRight; /* Column ref to child table */ Expr *pEq; /* Expression (pLeft = pRight) */ int iCol; /* Index of column in child table */ const char *zCol; /* Name of column in child table */ pLeft = sqlite3Expr(db, TK_REGISTER, 0); if( pLeft ){ /* Set the collation sequence and affinity of the LHS of each TK_EQ ** expression to the parent key column defaults. */ if( pIdx ){ Column *pCol; iCol = pIdx->aiColumn[i]; pCol = &pIdx->pTable->aCol[iCol]; pLeft->iTable = regData+iCol+1; pLeft->affinity = pCol->affinity; pLeft->pColl = sqlite3LocateCollSeq(pParse, pCol->zColl); }else{ pLeft->iTable = regData; pLeft->affinity = SQLITE_AFF_INTEGER; } } 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, 0); pWhere = sqlite3ExprAnd(db, pWhere, pEq); } /* If the child table is the same as the parent table, and this scan ** is taking place as part of a DELETE operation (operation D.2), omit the ** row being deleted from the scan by adding ($rowid != rowid) to the WHERE ** clause, where $rowid is the rowid of the row being deleted. */ if( pTab==pFKey->pFrom && nIncr>0 ){ Expr *pEq; /* Expression (pLeft = pRight) */ Expr *pLeft; /* Value from parent table row */ Expr *pRight; /* Column ref to child table */ pLeft = sqlite3Expr(db, TK_REGISTER, 0); pRight = sqlite3Expr(db, TK_COLUMN, 0); if( pLeft && pRight ){ pLeft->iTable = regData; pLeft->affinity = SQLITE_AFF_INTEGER; pRight->iTable = pSrc->a[0].iCursor; pRight->iColumn = -1; } pEq = sqlite3PExpr(pParse, TK_NE, pLeft, pRight, 0); pWhere = sqlite3ExprAnd(db, pWhere, pEq); } /* Resolve the references in the WHERE clause. */ memset(&sNameContext, 0, sizeof(NameContext)); sNameContext.pSrcList = pSrc; sNameContext.pParse = pParse; sqlite3ResolveExprNames(&sNameContext, pWhere); /* Create VDBE to loop through the entries in pSrc that match the WHERE ** clause. If the constraint is not deferred, throw an exception for ** each row found. Otherwise, for deferred constraints, increment the ** deferred constraint counter by nIncr for each row selected. */ pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0); if( nIncr>0 && pFKey->isDeferred==0 ){ sqlite3ParseToplevel(pParse)->mayAbort = 1; } sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr); if( pWInfo ){ sqlite3WhereEnd(pWInfo); } /* Clean up the WHERE clause constructed above. */ sqlite3ExprDelete(db, pWhere); if( iFkIfZero ){ sqlite3VdbeJumpHere(v, iFkIfZero); } } /* ** This function returns a pointer to the head of a linked list of FK ** constraints for which table pTab is the parent table. For example, ** given the following schema: ** ** CREATE TABLE t1(a PRIMARY KEY); ** CREATE TABLE t2(b REFERENCES t1(a); ** ** Calling this function with table "t1" as an argument returns a pointer ** to the FKey structure representing the foreign key constraint on table ** "t2". Calling this function with "t2" as the argument would return a ** NULL pointer (as there are no FK constraints for which t2 is the parent ** table). */ FKey *sqlite3FkReferences(Table *pTab){ int nName = sqlite3Strlen30(pTab->zName); return (FKey *)sqlite3HashFind(&pTab->pSchema->fkeyHash, pTab->zName, nName); } /* ** The second argument is a Trigger structure allocated by the ** fkActionTrigger() routine. This function deletes the Trigger structure ** and all of its sub-components. ** ** The Trigger structure or any of its sub-components may be allocated from ** the lookaside buffer belonging to database handle dbMem. */ static void fkTriggerDelete(sqlite3 *dbMem, Trigger *p){ if( p ){ TriggerStep *pStep = p->step_list; sqlite3ExprDelete(dbMem, pStep->pWhere); 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) && !pTab->pSelect ){ int iSkip = 0; Vdbe *v = sqlite3GetVdbe(pParse); assert( v ); /* VDBE has already been allocated */ 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 ) break; } if( !p ) return; iSkip = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp2(v, OP_FkIfZero, 1, iSkip); } pParse->disableTriggers = 1; sqlite3DeleteFrom(pParse, sqlite3SrcListDup(db, pName, 0), 0); pParse->disableTriggers = 0; /* If the DELETE has generated immediate foreign key constraint ** violations, halt the VDBE and return an error at this point, before ** any modifications to the schema are made. This is because statement ** transactions are not able to rollback schema changes. */ sqlite3VdbeAddOp2(v, OP_FkIfZero, 0, sqlite3VdbeCurrentAddr(v)+2); sqlite3HaltConstraint( pParse, OE_Abort, "foreign key constraint failed", P4_STATIC ); if( iSkip ){ sqlite3VdbeResolveLabel(v, iSkip); } } } /* ** This function is called when inserting, deleting or updating a row of ** table pTab to generate VDBE code to perform foreign key constraint ** processing for the operation. ** ** For a DELETE operation, parameter regOld is passed the index of the ** first register in an array of (pTab->nCol+1) registers containing the ** rowid of the row being deleted, followed by each of the column values ** of the row being deleted, from left to right. Parameter regNew is passed ** zero in this case. ** ** For an INSERT operation, regOld is passed zero and regNew is passed the ** first register of an array of (pTab->nCol+1) registers containing the new ** row data. ** ** For an UPDATE operation, this function is called twice. Once before ** the original record is deleted from the table using the calling convention ** described for DELETE. Then again after the original record is deleted ** but before the new record is inserted using the INSERT convention. */ void sqlite3FkCheck( Parse *pParse, /* Parse context */ Table *pTab, /* Row is being deleted from this table */ int regOld, /* Previous row data is stored here */ int regNew /* New row data is stored here */ ){ sqlite3 *db = pParse->db; /* Database handle */ Vdbe *v; /* VM to write code to */ FKey *pFKey; /* Used to iterate through FKs */ int iDb; /* Index of database containing pTab */ const char *zDb; /* Name of database containing pTab */ 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; v = sqlite3GetVdbe(pParse); iDb = sqlite3SchemaToIndex(db, pTab->pSchema); zDb = db->aDb[iDb].zName; /* 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 isIgnore = 0; /* Find the parent table of this foreign key. Also find a unique index ** on the parent key columns in the parent table. If either of these ** schema items cannot be located, set an error in pParse and return ** early. */ if( pParse->disableTriggers ){ pTo = sqlite3FindTable(db, pFKey->zTo, zDb); }else{ pTo = sqlite3LocateTable(pParse, 0, pFKey->zTo, zDb); } if( !pTo || locateFkeyIndex(pParse, pTo, pFKey, &pIdx, &aiFree) ){ if( !isIgnoreErrors || db->mallocFailed ) return; continue; } assert( pFKey->nCol==1 || (aiFree && pIdx) ); if( aiFree ){ aiCol = aiFree; }else{ iCol = pFKey->aCol[0].iFrom; aiCol = &iCol; } for(i=0; i<pFKey->nCol; i++){ if( aiCol[i]==pTab->iPKey ){ aiCol[i] = -1; } #ifndef SQLITE_OMIT_AUTHORIZATION /* Request permission to read the parent key columns. If the ** authorization callback returns SQLITE_IGNORE, behave as if any ** values read from the parent table are NULL. */ if( db->xAuth ){ int rcauth; char *zCol = pTo->aCol[pIdx ? pIdx->aiColumn[i] : pTo->iPKey].zName; rcauth = sqlite3AuthReadCol(pParse, pTo->zName, zCol, iDb); isIgnore = (rcauth==SQLITE_IGNORE); } #endif } /* Take a shared-cache advisory read-lock on the parent table. Allocate ** a cursor to use to search the unique index on the parent key columns ** in the parent table. */ sqlite3TableLock(pParse, iDb, pTo->tnum, 0, pTo->zName); pParse->nTab++; if( regOld!=0 ){ /* A row is being removed from the child table. Search for the parent. ** If the parent does not exist, removing the child row resolves an ** outstanding foreign key constraint violation. */ fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regOld, -1,isIgnore); } if( regNew!=0 ){ /* A row is being added to the child table. If a parent row cannot ** be found, adding the child row has violated the FK constraint. */ fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regNew, +1,isIgnore); } sqlite3DbFree(db, aiFree); } /* Loop through all the foreign key constraints that refer to this table */ for(pFKey = sqlite3FkReferences(pTab); pFKey; pFKey=pFKey->pNextTo){ Index *pIdx = 0; /* Foreign key index for pFKey */ SrcList *pSrc; int *aiCol = 0; if( !pFKey->isDeferred && !pParse->pToplevel && !pParse->isMultiWrite ){ assert( regOld==0 && regNew!=0 ); /* Inserting a single row into a parent table cannot cause an immediate ** foreign key violation. So do nothing in this case. */ continue; } if( locateFkeyIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ){ if( !isIgnoreErrors || db->mallocFailed ) return; continue; } assert( aiCol || pFKey->nCol==1 ); /* Create a SrcList structure containing a single table (the table ** the foreign key that refers to this table is attached to). This ** is required for the sqlite3WhereXXX() interface. */ pSrc = sqlite3SrcListAppend(db, 0, 0, 0); if( pSrc ){ struct SrcList_item *pItem = pSrc->a; pItem->pTab = pFKey->pFrom; pItem->zName = pFKey->pFrom->zName; pItem->pTab->nRef++; pItem->iCursor = pParse->nTab++; if( regNew!=0 ){ fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regNew, -1); } if( regOld!=0 ){ /* If there is a RESTRICT action configured for the current operation ** on the parent table of this FK, then throw an exception ** immediately if the FK constraint is violated, even if this is a ** deferred trigger. That's what RESTRICT means. To defer checking ** the constraint, the FK should specify NO ACTION (represented ** using OE_None). NO ACTION is the default. */ fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regOld, 1); } pItem->zName = 0; sqlite3SrcListDelete(db, pSrc); } sqlite3DbFree(db, aiCol); } } #define COLUMN_MASK(x) (((x)>31) ? 0xffffffff : ((u32)1<<(x))) /* ** This function is called before generating code to update or delete a ** 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; locateFkeyIndex(pParse, pTab, p, &pIdx, 0); if( pIdx ){ for(i=0; i<pIdx->nColumn; i++) mask |= COLUMN_MASK(pIdx->aiColumn[i]); } } } return mask; } /* ** This function is called before generating code to update or delete a ** row contained in table pTab. If the operation is a DELETE, then ** parameter aChange is passed a NULL value. For an UPDATE, aChange points ** to an array of size N, where N is the number of columns in table pTab. ** If the i'th column is not modified by the UPDATE, then the corresponding ** entry in the aChange[] array is set to -1. If the column is modified, ** the value is 0 or greater. Parameter chngRowid is set to true if the ** UPDATE statement modifies the rowid fields of the table. ** ** If any foreign key processing will be required, this function returns ** true. If there is no foreign key related processing, this function ** returns false. */ 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 */ ){ 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. */ return (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. */ int i; FKey *p; /* Check if any child key columns are being modified. */ for(p=pTab->pFKey; p; p=p->pNextFrom){ for(i=0; i<p->nCol; i++){ int iChildKey = p->aCol[i].iFrom; if( aChange[iChildKey]>=0 ) return 1; if( iChildKey==pTab->iPKey && chngRowid ) return 1; } } /* Check if any parent key columns are being modified. */ for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ for(i=0; i<p->nCol; i++){ char *zKey = p->aCol[i].zCol; int iKey; for(iKey=0; iKey<pTab->nCol; iKey++){ Column *pCol = &pTab->aCol[iKey]; if( (zKey ? !sqlite3StrICmp(pCol->zName, zKey) : pCol->isPrimKey) ){ if( aChange[iKey]>=0 ) return 1; if( iKey==pTab->iPKey && chngRowid ) return 1; } } } } } } return 0; } /* ** This function is called when an UPDATE or DELETE operation is being ** compiled on table pTab, which is the parent table of foreign-key pFKey. ** If the current operation is an UPDATE, then the pChanges parameter is ** passed a pointer to the list of columns being modified. If it is a ** 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); ** ** then the returned trigger structure is equivalent to: ** ** CREATE TRIGGER ... DELETE ON p BEGIN ** DELETE FROM c WHERE ck = old.pk; ** END; ** ** The returned pointer is cached as part of the foreign key object. It ** is eventually freed along with the rest of the foreign key object by ** sqlite3FkDelete(). */ static Trigger *fkActionTrigger( Parse *pParse, /* Parse context */ Table *pTab, /* Table being updated or deleted from */ FKey *pFKey, /* Foreign key to get action for */ ExprList *pChanges /* Change-list for UPDATE, NULL for DELETE */ ){ sqlite3 *db = pParse->db; /* Database handle */ int action; /* One of OE_None, OE_Cascade etc. */ Trigger *pTrigger; /* Trigger definition to return */ int iAction = (pChanges!=0); /* 1 for UPDATE, 0 for DELETE */ action = pFKey->aAction[iAction]; pTrigger = pFKey->apTrigger[iAction]; if( action!=OE_None && !pTrigger ){ u8 enableLookaside; /* Copy of db->lookaside.bEnabled */ char const *zFrom; /* Name of child table */ int nFrom; /* Length in bytes of zFrom */ Index *pIdx = 0; /* Parent key index for this FK */ int *aiCol = 0; /* child table cols -> parent key cols */ TriggerStep *pStep = 0; /* First (only) step of trigger program */ Expr *pWhere = 0; /* WHERE clause of trigger step */ ExprList *pList = 0; /* Changes list if ON UPDATE CASCADE */ Select *pSelect = 0; /* If RESTRICT, "SELECT RAISE(...)" */ int i; /* Iterator variable */ Expr *pWhen = 0; /* WHEN clause for the trigger */ if( locateFkeyIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ) return 0; assert( aiCol || pFKey->nCol==1 ); for(i=0; i<pFKey->nCol; i++){ Token tOld = { "old", 3 }; /* Literal "old" token */ Token tNew = { "new", 3 }; /* Literal "new" token */ Token tFromCol; /* Name of column in child table */ Token tToCol; /* Name of column in parent table */ int iFromCol; /* Idx of column in child table */ Expr *pEq; /* tFromCol = OLD.tToCol */ iFromCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom; assert( iFromCol>=0 ); tToCol.z = pIdx ? pTab->aCol[pIdx->aiColumn[i]].zName : "oid"; tFromCol.z = pFKey->pFrom->aCol[iFromCol].zName; tToCol.n = sqlite3Strlen30(tToCol.z); tFromCol.n = sqlite3Strlen30(tFromCol.z); /* Create the expression "OLD.zToCol = zFromCol". It is important ** 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, sqlite3PExpr(pParse, TK_ID, 0, 0, &tOld), sqlite3PExpr(pParse, TK_ID, 0, 0, &tToCol) , 0), sqlite3PExpr(pParse, TK_ID, 0, 0, &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, sqlite3PExpr(pParse, TK_ID, 0, 0, &tOld), sqlite3PExpr(pParse, TK_ID, 0, 0, &tToCol), 0), sqlite3PExpr(pParse, TK_DOT, sqlite3PExpr(pParse, TK_ID, 0, 0, &tNew), sqlite3PExpr(pParse, TK_ID, 0, 0, &tToCol), 0), 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, sqlite3PExpr(pParse, TK_ID, 0, 0, &tNew), sqlite3PExpr(pParse, TK_ID, 0, 0, &tToCol) , 0); }else if( action==OE_SetDflt ){ Expr *pDflt = pFKey->pFrom->aCol[iFromCol].pDflt; if( pDflt ){ pNew = sqlite3ExprDup(db, pDflt, 0); }else{ pNew = sqlite3PExpr(pParse, TK_NULL, 0, 0, 0); } }else{ pNew = sqlite3PExpr(pParse, TK_NULL, 0, 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(db, 0, &tFrom, 0), pWhere, 0, 0, 0, 0, 0, 0 ); pWhere = 0; } /* In the current implementation, pTab->dbMem==0 for all tables except ** for temporary tables used to describe subqueries. And temporary ** tables do not have foreign key constraints. Hence, pTab->dbMem ** should always be 0 there. */ enableLookaside = db->lookaside.bEnabled; db->lookaside.bEnabled = 0; pTrigger = (Trigger *)sqlite3DbMallocZero(db, sizeof(Trigger) + /* struct Trigger */ sizeof(TriggerStep) + /* Single step in trigger program */ nFrom + 1 /* Space for pStep->target.z */ ); if( pTrigger ){ pStep = pTrigger->step_list = (TriggerStep *)&pTrigger[1]; pStep->target.z = (char *)&pStep[1]; pStep->target.n = nFrom; memcpy((char *)pStep->target.z, zFrom, nFrom); pStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); pStep->pExprList = sqlite3ExprListDup(db, pList, EXPRDUP_REDUCE); pStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); if( pWhen ){ pWhen = sqlite3PExpr(pParse, TK_NOT, pWhen, 0, 0); pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE); } } /* Re-enable the lookaside buffer, if it was disabled earlier. */ db->lookaside.bEnabled = enableLookaside; sqlite3ExprDelete(db, pWhere); sqlite3ExprDelete(db, pWhen); sqlite3ExprListDelete(db, pList); sqlite3SelectDelete(db, pSelect); if( db->mallocFailed==1 ){ fkTriggerDelete(db, pTrigger); return 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; pTrigger->op = (pChanges ? TK_UPDATE : TK_DELETE); } return pTrigger; } /* ** This function is called when deleting or updating a row to implement ** any required CASCADE, SET NULL or SET DEFAULT actions. */ void sqlite3FkActions( Parse *pParse, /* Parse context */ Table *pTab, /* Table being updated or deleted from */ ExprList *pChanges, /* Change-list for UPDATE, NULL for DELETE */ int regOld /* Address of array containing old row */ ){ /* If foreign-key support is enabled, iterate through all FKs that ** refer to table pTab. If there is an action associated with the FK ** for this operation (either update or delete), invoke the associated ** trigger sub-program. */ if( pParse->db->flags&SQLITE_ForeignKeys ){ FKey *pFKey; /* Iterator variable */ for(pFKey = sqlite3FkReferences(pTab); pFKey; pFKey=pFKey->pNextTo){ Trigger *pAction = fkActionTrigger(pParse, pTab, pFKey, pChanges); if( pAction ){ sqlite3CodeRowTriggerDirect(pParse, pAction, pTab, regOld, OE_Abort, 0); } } } } #endif /* ifndef SQLITE_OMIT_TRIGGER */ /* ** Free all memory associated with foreign key definitions attached to ** table pTab. Remove the deleted foreign keys from the Schema.fkeyHash ** hash table. */ void sqlite3FkDelete(Table *pTab){ FKey *pFKey; /* Iterator variable */ FKey *pNext; /* Copy of pFKey->pNextFrom */ for(pFKey=pTab->pFKey; pFKey; pFKey=pNext){ /* Remove the FK from the fkeyHash hash table. */ if( pFKey->pPrevTo ){ pFKey->pPrevTo->pNextTo = pFKey->pNextTo; }else{ void *data = (void *)pFKey->pNextTo; const char *z = (data ? pFKey->pNextTo->zTo : pFKey->zTo); sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, sqlite3Strlen30(z), data); } if( pFKey->pNextTo ){ pFKey->pNextTo->pPrevTo = pFKey->pPrevTo; } /* Delete any triggers created to implement actions for this FK. */ #ifndef SQLITE_OMIT_TRIGGER fkTriggerDelete(pTab->dbMem, pFKey->apTrigger[0]); fkTriggerDelete(pTab->dbMem, pFKey->apTrigger[1]); #endif /* EV: R-30323-21917 Each foreign key constraint in SQLite is ** classified as either immediate or deferred. */ assert( pFKey->isDeferred==0 || pFKey->isDeferred==1 ); pNext = pFKey->pNextFrom; sqlite3DbFree(pTab->dbMem, pFKey); } } #endif /* ifndef SQLITE_OMIT_FOREIGN_KEY */ |
Changes to src/func.c.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ************************************************************************* ** This file contains the C functions that implement various SQL ** functions of SQLite. ** ** There is only one exported symbol in this file - the function ** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** All other code has file scope. | < < | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ************************************************************************* ** This file contains the C functions that implement various SQL ** functions of SQLite. ** ** There is only one exported symbol in this file - the function ** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** All other code has file scope. */ #include "sqliteInt.h" #include <stdlib.h> #include <assert.h> #include "vdbeInt.h" /* |
︙ | ︙ | |||
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 | z1[i] = sqlite3Tolower(z1[i]); } sqlite3_result_text(context, (char *)z1, -1, sqlite3_free); } } } /* ** Implementation of the IFNULL(), NVL(), and COALESCE() functions. ** All three do the same thing. They return the first non-NULL ** argument. */ static void ifnullFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ int i; for(i=0; i<argc; i++){ if( SQLITE_NULL!=sqlite3_value_type(argv[i]) ){ sqlite3_result_value(context, argv[i]); break; } } } /* ** Implementation of random(). Return a random integer. */ static void randomFunc( sqlite3_context *context, int NotUsed, | > > > > > > > > > > | 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 | z1[i] = sqlite3Tolower(z1[i]); } sqlite3_result_text(context, (char *)z1, -1, sqlite3_free); } } } #if 0 /* This function is never used. */ /* ** The COALESCE() and IFNULL() functions used to be implemented as shown ** here. But now they are implemented as VDBE code so that unused arguments ** do not have to be computed. This legacy implementation is retained as ** comment. */ /* ** Implementation of the IFNULL(), NVL(), and COALESCE() functions. ** All three do the same thing. They return the first non-NULL ** argument. */ static void ifnullFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ int i; for(i=0; i<argc; i++){ if( SQLITE_NULL!=sqlite3_value_type(argv[i]) ){ sqlite3_result_value(context, argv[i]); break; } } } #endif /* NOT USED */ #define ifnullFunc versionFunc /* Substitute function - never called */ /* ** Implementation of random(). Return a random integer. */ static void randomFunc( sqlite3_context *context, int NotUsed, |
︙ | ︙ | |||
698 699 700 701 702 703 704 | UNUSED_PARAMETER(NotUsed); if( sqlite3MemCompare(argv[0], argv[1], pColl)!=0 ){ sqlite3_result_value(context, argv[0]); } } /* | | > > > > > > > > > > > > > > | 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 | UNUSED_PARAMETER(NotUsed); if( sqlite3MemCompare(argv[0], argv[1], pColl)!=0 ){ sqlite3_result_value(context, argv[0]); } } /* ** Implementation of the sqlite_version() function. The result is the version ** of the SQLite library that is running. */ static void versionFunc( sqlite3_context *context, int NotUsed, sqlite3_value **NotUsed2 ){ UNUSED_PARAMETER2(NotUsed, NotUsed2); sqlite3_result_text(context, sqlite3_version, -1, SQLITE_STATIC); } /* ** Implementation of the sqlite_source_id() function. The result is a string ** that identifies the particular version of the source code used to build ** SQLite. */ static void sourceidFunc( sqlite3_context *context, int NotUsed, sqlite3_value **NotUsed2 ){ UNUSED_PARAMETER2(NotUsed, NotUsed2); sqlite3_result_text(context, SQLITE_SOURCE_ID, -1, SQLITE_STATIC); } /* Array for converting from half-bytes (nybbles) into ASCII hex ** digits. */ static const char hexdigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; |
︙ | ︙ | |||
1421 1422 1423 1424 1425 1426 1427 | #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(coalesce, 1, 0, 0, 0 ), | > | | | > > | 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 | #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(coalesce, 1, 0, 0, 0 ), FUNCTION(coalesce, 0, 0, 0, 0 ), /* FUNCTION(coalesce, -1, 0, 0, ifnullFunc ), */ {-1,SQLITE_UTF8,SQLITE_FUNC_COALESCE,0,0,ifnullFunc,0,0,"coalesce",0}, FUNCTION(hex, 1, 0, 0, hexFunc ), /* FUNCTION(ifnull, 2, 0, 0, ifnullFunc ), */ {2,SQLITE_UTF8,SQLITE_FUNC_COALESCE,0,0,ifnullFunc,0,0,"ifnull",0}, FUNCTION(random, 0, 0, 0, randomFunc ), FUNCTION(randomblob, 1, 0, 0, randomBlob ), FUNCTION(nullif, 2, 0, 1, nullifFunc ), FUNCTION(sqlite_version, 0, 0, 0, versionFunc ), FUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ), FUNCTION(quote, 1, 0, 0, quoteFunc ), FUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid), FUNCTION(changes, 0, 0, 0, changes ), FUNCTION(total_changes, 0, 0, 0, total_changes ), FUNCTION(replace, 3, 0, 0, replaceFunc ), FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ), #ifdef SQLITE_SOUNDEX |
︙ | ︙ |
Changes to src/global.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2008 June 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 definitions of global variables and contants. | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* ** 2008 June 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 definitions of global variables and contants. */ #include "sqliteInt.h" /* An array to map all upper-case characters into their corresponding ** lower-case character. ** |
︙ | ︙ | |||
149 150 151 152 153 154 155 | 0, /* szScratch */ 0, /* nScratch */ (void*)0, /* pPage */ 0, /* szPage */ 0, /* nPage */ 0, /* mxParserStack */ 0, /* sharedCacheEnabled */ | | > > | 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | 0, /* szScratch */ 0, /* nScratch */ (void*)0, /* pPage */ 0, /* szPage */ 0, /* nPage */ 0, /* mxParserStack */ 0, /* sharedCacheEnabled */ /* All the rest should always be initialized to zero */ 0, /* isInit */ 0, /* inProgress */ 0, /* isMutexInit */ 0, /* isMallocInit */ 0, /* isPCacheInit */ 0, /* pInitMutex */ 0, /* nRefInitMutex */ }; /* ** Hash table for global functions - functions common to all |
︙ | ︙ |
Changes to src/hash.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 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. | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* ** 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. */ #include "sqliteInt.h" #include <assert.h> /* Turn bulk memory into a hash table object by initializing the ** fields of the Hash structure. ** |
︙ | ︙ |
Changes to src/hash.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 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 implemenation ** used in SQLite. | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* ** 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 implemenation ** used in SQLite. */ #ifndef _SQLITE_HASH_H_ #define _SQLITE_HASH_H_ /* Forward declarations of structures. */ typedef struct Hash Hash; typedef struct HashElem HashElem; |
︙ | ︙ |
Changes to src/hwtime.h.
︙ | ︙ | |||
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 inline asm code for retrieving "high-performance" ** counters for x86 class CPUs. | < < | 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. ** ****************************************************************************** ** ** This file contains inline asm code for retrieving "high-performance" ** counters for x86 class CPUs. */ #ifndef _HWTIME_H_ #define _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 |
︙ | ︙ |
Changes to src/insert.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. | < < | 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 contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. */ #include "sqliteInt.h" /* ** Generate code that will open a table for reading. */ void sqlite3OpenTable( |
︙ | ︙ | |||
33 34 35 36 37 38 39 | sqlite3TableLock(p, iDb, pTab->tnum, (opcode==OP_OpenWrite)?1:0, pTab->zName); sqlite3VdbeAddOp3(v, opcode, iCur, pTab->tnum, iDb); sqlite3VdbeChangeP4(v, -1, SQLITE_INT_TO_PTR(pTab->nCol), P4_INT32); VdbeComment((v, "%s", pTab->zName)); } /* | | | | > > > > | | | | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | sqlite3TableLock(p, iDb, pTab->tnum, (opcode==OP_OpenWrite)?1:0, pTab->zName); sqlite3VdbeAddOp3(v, opcode, iCur, pTab->tnum, iDb); sqlite3VdbeChangeP4(v, -1, SQLITE_INT_TO_PTR(pTab->nCol), P4_INT32); VdbeComment((v, "%s", pTab->zName)); } /* ** Return a pointer to the column affinity string associated with index ** pIdx. A column affinity string has one character for each column in ** the table, according to the affinity of the column: ** ** Character Column affinity ** ------------------------------ ** 'a' TEXT ** 'b' NONE ** 'c' NUMERIC ** 'd' INTEGER ** 'e' REAL ** ** An extra 'b' is appended to the end of the string to cover the ** rowid that appears as the last column in every index. ** ** Memory for the buffer containing the column index affinity string ** is managed along with the rest of the Index structure. It will be ** released when sqlite3DeleteIndex() is called. */ const char *sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){ if( !pIdx->zColAff ){ /* The first time a column affinity string for a particular index is ** required, it is allocated and populated here. It is then stored as ** a member of the Index structure for subsequent use. ** ** The column affinity string will eventually be deleted by ** sqliteDeleteIndex() when the Index structure itself is cleaned ** up. */ int n; Table *pTab = pIdx->pTable; sqlite3 *db = sqlite3VdbeDb(v); pIdx->zColAff = (char *)sqlite3Malloc(pIdx->nColumn+2); if( !pIdx->zColAff ){ db->mallocFailed = 1; return 0; } for(n=0; n<pIdx->nColumn; n++){ pIdx->zColAff[n] = pTab->aCol[pIdx->aiColumn[n]].affinity; } pIdx->zColAff[n++] = SQLITE_AFF_NONE; pIdx->zColAff[n] = 0; } return pIdx->zColAff; } /* ** Set P4 of the most recently inserted opcode to a column affinity ** string for table pTab. A column affinity string has one character ** for each column indexed by the index, according to the affinity of the ** column: |
︙ | ︙ | |||
127 128 129 130 131 132 133 | /* ** Return non-zero if the table pTab in database iDb or any of its indices ** have been opened at any point in the VDBE program beginning at location ** iStartAddr throught the end of the program. This is used to see if ** a statement of the form "INSERT INTO <iDb, pTab> SELECT ..." can ** run without using temporary table for the results of the SELECT. */ | | > > > > > | | 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 | /* ** Return non-zero if the table pTab in database iDb or any of its indices ** have been opened at any point in the VDBE program beginning at location ** iStartAddr throught the end of the program. This is used to see if ** a statement of the form "INSERT INTO <iDb, pTab> SELECT ..." can ** run without using temporary table for the results of the SELECT. */ static int readsTable(Parse *p, int iStartAddr, int iDb, Table *pTab){ Vdbe *v = sqlite3GetVdbe(p); int i; int iEnd = sqlite3VdbeCurrentAddr(v); #ifndef SQLITE_OMIT_VIRTUALTABLE VTable *pVTab = IsVirtual(pTab) ? sqlite3GetVTable(p->db, pTab) : 0; #endif for(i=iStartAddr; 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; |
︙ | ︙ | |||
184 185 186 187 188 189 190 191 192 | static int autoIncBegin( Parse *pParse, /* Parsing context */ int iDb, /* Index of the database holding pTab */ Table *pTab /* The table we are writing to */ ){ int memId = 0; /* Register holding maximum rowid */ if( pTab->tabFlags & TF_Autoincrement ){ AutoincInfo *pInfo; | > | | | | | | > > > > > | 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 | static int autoIncBegin( Parse *pParse, /* Parsing context */ int iDb, /* Index of the database holding pTab */ Table *pTab /* The table we are writing to */ ){ int memId = 0; /* Register holding maximum rowid */ if( pTab->tabFlags & TF_Autoincrement ){ Parse *pToplevel = sqlite3ParseToplevel(pParse); AutoincInfo *pInfo; pInfo = pToplevel->pAinc; while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; } if( pInfo==0 ){ pInfo = sqlite3DbMallocRaw(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++; /* Rowid in sqlite_sequence */ } memId = pInfo->regCtr; } return memId; } /* ** This routine generates code that will initialize all of the ** register used by the autoincrement tracker. */ void sqlite3AutoincrementBegin(Parse *pParse){ AutoincInfo *p; /* Information about an AUTOINCREMENT */ sqlite3 *db = pParse->db; /* The database connection */ Db *pDb; /* Database only autoinc table */ int memId; /* Register holding max rowid */ int addr; /* A VDBE address */ Vdbe *v = pParse->pVdbe; /* VDBE under construction */ /* This routine is never called during trigger-generation. It is ** only called from the top-level */ assert( pParse->pTriggerTab==0 ); assert( pParse==sqlite3ParseToplevel(pParse) ); assert( v ); /* We failed long ago if this is not so */ for(p = pParse->pAinc; p; p = p->pNext){ pDb = &db->aDb[p->iDb]; memId = p->regCtr; sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead); addr = sqlite3VdbeCurrentAddr(v); |
︙ | ︙ | |||
437 438 439 440 441 442 443 | int endOfLoop; /* Label for the end of the insertion loop */ int useTempTable = 0; /* Store SELECT results in intermediate table */ int srcTab = 0; /* Data comes from this temporary cursor if >=0 */ int addrInsTop = 0; /* Jump to label "D" */ int addrCont = 0; /* Top of insert loop. Label "C" in templates 3 and 4 */ int addrSelect = 0; /* Address of coroutine that implements the SELECT */ SelectDest dest; /* Destination for SELECT on rhs of INSERT */ | < < | 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 | int endOfLoop; /* Label for the end of the insertion loop */ int useTempTable = 0; /* Store SELECT results in intermediate table */ int srcTab = 0; /* Data comes from this temporary cursor if >=0 */ int addrInsTop = 0; /* Jump to label "D" */ int addrCont = 0; /* Top of insert loop. Label "C" in templates 3 and 4 */ int addrSelect = 0; /* Address of coroutine that implements the SELECT */ SelectDest dest; /* Destination for SELECT on rhs of INSERT */ int iDb; /* Index of database holding TABLE */ Db *pDb; /* The database containing table being inserted into */ int appendFlag = 0; /* True if the insert is likely to be an append */ /* 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 regRecord; /* Holds the assemblied row record */ int regEof = 0; /* Register recording end of SELECT data */ 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 |
︙ | ︙ | |||
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 | # define isView 0 #endif #ifdef SQLITE_OMIT_VIEW # undef isView # define isView 0 #endif assert( (pTrigger && tmask) || (pTrigger==0 && tmask==0) ); /* Ensure that: * (a) the table is not read-only, * (b) that if it is a view then ON INSERT triggers exist */ if( sqlite3IsReadOnly(pParse, pTab, tmask) ){ goto insert_cleanup; } | > > > > > > > > < < < < < < < < < < < < < < | 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 | # 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 (or virtual ** module table). */ if( sqlite3ViewGetColumnNames(pParse, pTab) ){ goto insert_cleanup; } /* Ensure that: * (a) the table is not read-only, * (b) that if it is a view then ON INSERT triggers exist */ if( sqlite3IsReadOnly(pParse, pTab, tmask) ){ goto insert_cleanup; } /* Allocate a VDBE */ v = sqlite3GetVdbe(pParse); if( v==0 ) goto insert_cleanup; if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); sqlite3BeginWriteOperation(pParse, pSelect || pTrigger, iDb); #ifndef SQLITE_OMIT_XFER_OPT /* If the statement is of the form ** ** INSERT INTO <table1> SELECT * FROM <table2>; ** ** Then special optimizations can be applied that make the transfer ** very fast and which reduce fragmentation of indices. |
︙ | ︙ | |||
616 617 618 619 620 621 622 | ** FALSE if each* row of the SELECT can be written directly into ** the destination table (template 3). ** ** A temp table must be used if the table being updated is also one ** of the tables being read by the SELECT statement. Also use a ** temp table in the case of row triggers. */ | | | 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 | ** FALSE if each* row of the SELECT can be written directly into ** the destination table (template 3). ** ** A temp table must be used if the table being updated is also one ** of the tables being read by the SELECT statement. Also use a ** temp table in the case of row triggers. */ if( pTrigger || readsTable(pParse, addrSelect, iDb, pTab) ){ useTempTable = 1; } if( useTempTable ){ /* Invoke the coroutine to extract information from the SELECT ** and add it to a transient table srcTab. The code generated ** here is from the 4th template: |
︙ | ︙ | |||
732 733 734 735 736 737 738 | /* If there is no IDLIST term but the table has an integer primary ** key, the set the keyColumn variable to the primary key column index ** in the original table definition. */ if( pColumn==0 && nColumn>0 ){ keyColumn = pTab->iPKey; } | < < < < < < | 737 738 739 740 741 742 743 744 745 746 747 748 749 750 | /* If there is no IDLIST term but the table has an integer primary ** key, the set the keyColumn variable to the primary key column index ** in the original table definition. */ if( pColumn==0 && nColumn>0 ){ keyColumn = pTab->iPKey; } /* Initialize the count of rows to be inserted */ if( db->flags & SQLITE_CountRows ){ regRowCount = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount); } |
︙ | ︙ | |||
804 805 806 807 808 809 810 | } regData = regRowid+1; /* Run the BEFORE and INSTEAD OF triggers, if there are any */ endOfLoop = sqlite3VdbeMakeLabel(v); if( tmask & TRIGGER_BEFORE ){ | < | < < | | | | | | | < | | | < < > < < < < | | < | > | 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 | } regData = regRowid+1; /* Run the BEFORE and INSTEAD OF triggers, if there are any */ endOfLoop = sqlite3VdbeMakeLabel(v); if( tmask & TRIGGER_BEFORE ){ int regCols = sqlite3GetTempRange(pParse, pTab->nCol+1); /* build the NEW.* reference row. Note that if there is an INTEGER ** PRIMARY KEY into which a NULL is being inserted, that NULL will be ** translated into a unique ID for the row. But on a BEFORE trigger, ** we do not know what the unique ID will be (because the insert has ** not happened yet) so we substitute a rowid of -1 */ if( keyColumn<0 ){ sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols); }else{ int j1; if( useTempTable ){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, keyColumn, regCols); }else{ assert( pSelect==0 ); /* Otherwise useTempTable is true */ sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, regCols); } j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regCols); sqlite3VdbeAddOp2(v, OP_Integer, -1, regCols); sqlite3VdbeJumpHere(v, j1); sqlite3VdbeAddOp1(v, OP_MustBeInt, regCols); } /* 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=0; i<pTab->nCol; i++){ if( pColumn==0 ){ j = i; }else{ for(j=0; j<pColumn->nId; j++){ if( pColumn->a[j].idx==i ) break; } } if( pColumn && j>=pColumn->nId ){ 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 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 ){ sqlite3VdbeAddOp2(v, OP_Affinity, regCols+1, pTab->nCol); sqlite3TableAffinityStr(v, pTab); } /* 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); } /* Push the record number for the new entry onto the stack. The ** record number is a randomly generate integer created by NewRowid ** except when the table has an INTEGER PRIMARY KEY column, in which ** case the record number is the same as that column. */ |
︙ | ︙ | |||
972 973 974 975 976 977 978 979 | } /* Generate code to check constraints and generate index keys and ** do the insertion. */ #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTab) ){ sqlite3VtabMakeWritable(pParse, pTab); | > | < > > | < | | < < | 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 | } /* 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); sqlite3MayAbort(pParse); }else #endif { int isReplace; /* Set to true if constraints may cause a replace */ sqlite3GenerateConstraintChecks(pParse, pTab, baseCur, regIns, aRegIdx, keyColumn>=0, 0, onError, endOfLoop, &isReplace ); sqlite3FkCheck(pParse, pTab, 0, regIns); sqlite3CompleteInsertion( pParse, pTab, baseCur, regIns, aRegIdx, 0, appendFlag, isReplace==0 ); } } /* Update the count of rows that are inserted */ if( (db->flags & SQLITE_CountRows)!=0 ){ sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1); } if( pTrigger ){ /* Code AFTER triggers */ sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_AFTER, pTab, regData-2-pTab->nCol, onError, endOfLoop); } /* The bottom of the main insertion loop, if the data source ** is a SELECT statement. */ sqlite3VdbeResolveLabel(v, endOfLoop); if( useTempTable ){ |
︙ | ︙ | |||
1029 1030 1031 1032 1033 1034 1035 | } insert_end: /* Update the sqlite_sequence table by storing the content of the ** maximum rowid counter values recorded while inserting into ** autoincrement tables. */ | | | > > > > > > > > > > > > > > < < < < | | | | > | > | | | | | 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 | } 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( (db->flags&SQLITE_CountRows) && !pParse->nested && !pParse->pTriggerTab ){ 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); sqlite3SelectDelete(db, pSelect); sqlite3IdListDelete(db, pColumn); sqlite3DbFree(db, aRegIdx); } /* Make sure "isView" and other macros defined above are undefined. Otherwise ** thely 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 #endif #ifdef pTrigger #undef pTrigger #endif #ifdef tmask #undef tmask #endif /* ** Generate code to do constraint checks prior to an INSERT or an UPDATE. ** ** The input is a range of consecutive registers as follows: ** ** 1. The rowid of the row after the update. ** ** 2. The data in the first column of the entry after the update. ** ** i. Data from middle columns... ** ** N. The data in the last column of the entry after the update. ** ** The regRowid parameter is the index of the register containing (1). ** ** If isUpdate is true and rowidChng is non-zero, then rowidChng contains ** the address of a register containing the rowid before the update takes ** place. isUpdate is true for UPDATEs and false for INSERTs. If isUpdate ** is false, indicating an INSERT statement, then a non-zero rowidChng ** indicates that the rowid was explicitly specified as part of the ** INSERT statement. If rowidChng is false, it means that the rowid is ** computed automatically in an insert or that the rowid value is not ** modified by an update. ** ** The code generated by this routine 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 ** attached to the table. ** |
︙ | ︙ | |||
1151 1152 1153 1154 1155 1156 1157 | int onError; /* Conflict resolution strategy */ int j1; /* Addresss of jump instruction */ int j2 = 0, j3; /* Addresses of jump instructions */ int regData; /* Register containing first data column */ int iCur; /* Table cursor number */ Index *pIdx; /* Pointer to one of the indices */ int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */ | | < | > | | 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 | int onError; /* Conflict resolution strategy */ int j1; /* Addresss of jump instruction */ int j2 = 0, j3; /* Addresses of jump instructions */ int regData; /* Register containing first data column */ int iCur; /* Table cursor number */ Index *pIdx; /* Pointer to one of the indices */ int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */ int regOldRowid = (rowidChng && isUpdate) ? rowidChng : regRowid; v = sqlite3GetVdbe(pParse); assert( v!=0 ); assert( pTab->pSelect==0 ); /* This table is not a VIEW */ nCol = pTab->nCol; regData = regRowid + 1; /* Test all NOT NULL constraints. */ for(i=0; i<nCol; i++){ if( i==pTab->iPKey ){ continue; } onError = pTab->aCol[i].notNull; if( onError==OE_None ) continue; 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 ); switch( onError ){ case OE_Abort: sqlite3MayAbort(pParse); case OE_Rollback: case OE_Fail: { char *zMsg; j1 = sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT, onError, regData+i); zMsg = sqlite3MPrintf(pParse->db, "%s.%s may not be NULL", pTab->zName, pTab->aCol[i].zName); sqlite3VdbeChangeP4(v, -1, zMsg, P4_DYNAMIC); |
︙ | ︙ | |||
1215 1216 1217 1218 1219 1220 1221 | int allOk = sqlite3VdbeMakeLabel(v); pParse->ckBase = regData; sqlite3ExprIfTrue(pParse, pTab->pCheck, allOk, SQLITE_JUMPIFNULL); onError = overrideError!=OE_Default ? overrideError : OE_Abort; if( onError==OE_Ignore ){ sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); }else{ | | < | | | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | < | 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 | int allOk = sqlite3VdbeMakeLabel(v); pParse->ckBase = regData; sqlite3ExprIfTrue(pParse, pTab->pCheck, allOk, SQLITE_JUMPIFNULL); onError = overrideError!=OE_Default ? overrideError : OE_Abort; if( onError==OE_Ignore ){ sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); }else{ sqlite3HaltConstraint(pParse, onError, 0, 0); } sqlite3VdbeResolveLabel(v, allOk); } #endif /* !defined(SQLITE_OMIT_CHECK) */ /* If we have an INTEGER PRIMARY KEY, make sure the primary key ** of the new record does not previously exist. Except, if this ** is an UPDATE and the primary key is not changing, that is OK. */ if( rowidChng ){ onError = pTab->keyConf; if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ onError = OE_Abort; } if( isUpdate ){ j2 = sqlite3VdbeAddOp3(v, OP_Eq, regRowid, 0, rowidChng); } j3 = sqlite3VdbeAddOp3(v, OP_NotExists, baseCur, 0, regRowid); switch( onError ){ default: { onError = OE_Abort; /* Fall thru into the next case */ } case OE_Rollback: case OE_Abort: case OE_Fail: { sqlite3HaltConstraint( pParse, onError, "PRIMARY KEY must be unique", P4_STATIC); break; } case OE_Replace: { /* If there are DELETE triggers on this table and the ** recursive-triggers flag is set, call GenerateRowDelete() to ** remove the conflicting row from the the table. This will fire ** the triggers and remove both the table and index b-tree entries. ** ** Otherwise, if there are no triggers or the recursive-triggers ** flag is not set, call GenerateRowIndexDelete(). This removes ** the index b-tree entries only. The table b-tree entry will be ** replaced by the new entry when it is inserted. */ Trigger *pTrigger = 0; if( pParse->db->flags&SQLITE_RecTriggers ){ pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0); } sqlite3MultiWrite(pParse); if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){ sqlite3GenerateRowDelete( pParse, pTab, baseCur, regRowid, 0, pTrigger, OE_Replace ); }else{ sqlite3GenerateRowIndexDelete(pParse, pTab, baseCur, 0); } seenReplace = 1; break; } case OE_Ignore: { assert( seenReplace==0 ); sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); break; } } sqlite3VdbeJumpHere(v, j3); if( isUpdate ){ sqlite3VdbeJumpHere(v, j2); } } /* Test all UNIQUE constraints by creating entries for each UNIQUE ** index and making sure that duplicate entries do not already exist. ** Add the new records to the indices as we go. */ |
︙ | ︙ | |||
1290 1291 1292 1293 1294 1295 1296 | sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i); }else{ sqlite3VdbeAddOp2(v, OP_SCopy, regData+idx, regIdx+i); } } sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i); sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn+1, aRegIdx[iCur]); | | < | | 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 | sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i); }else{ sqlite3VdbeAddOp2(v, OP_SCopy, regData+idx, regIdx+i); } } sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i); sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn+1, aRegIdx[iCur]); sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), 0); sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn+1); /* Find out what action to take in case there is an indexing conflict */ onError = pIdx->onError; if( onError==OE_None ){ sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn+1); continue; /* pIdx is not a UNIQUE index */ } if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ onError = OE_Abort; } if( seenReplace ){ if( onError==OE_Ignore ) onError = OE_Replace; else if( onError==OE_Fail ) onError = OE_Abort; } /* Check to see if the new index entry will be unique */ regR = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_SCopy, regOldRowid, regR); j3 = sqlite3VdbeAddOp4(v, OP_IsUnique, baseCur+iCur+1, 0, regR, SQLITE_INT_TO_PTR(regIdx), P4_INT32); sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn+1); /* Generate code that executes if the new index entry is not unique */ assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail |
︙ | ︙ | |||
1342 1343 1344 1345 1346 1347 1348 | sqlite3StrAccumAppend(&errMsg, zSep, -1); zSep = ", "; sqlite3StrAccumAppend(&errMsg, zCol, -1); } sqlite3StrAccumAppend(&errMsg, pIdx->nColumn>1 ? " are not unique" : " is not unique", -1); zErr = sqlite3StrAccumFinish(&errMsg); | | > > > > > | > > | | 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 | sqlite3StrAccumAppend(&errMsg, zSep, -1); zSep = ", "; sqlite3StrAccumAppend(&errMsg, zCol, -1); } sqlite3StrAccumAppend(&errMsg, pIdx->nColumn>1 ? " are not unique" : " is not unique", -1); zErr = sqlite3StrAccumFinish(&errMsg); sqlite3HaltConstraint(pParse, onError, zErr, 0); sqlite3DbFree(errMsg.db, zErr); break; } case OE_Ignore: { assert( seenReplace==0 ); sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); break; } default: { Trigger *pTrigger = 0; assert( onError==OE_Replace ); sqlite3MultiWrite(pParse); if( pParse->db->flags&SQLITE_RecTriggers ){ pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0); } sqlite3GenerateRowDelete( pParse, pTab, baseCur, regR, 0, pTrigger, OE_Replace ); seenReplace = 1; break; } } sqlite3VdbeJumpHere(v, j3); sqlite3ReleaseTempReg(pParse, regR); } if( pbMayReplace ){ *pbMayReplace = seenReplace; } } /* ** This routine generates code to finish the INSERT or UPDATE operation |
︙ | ︙ | |||
1383 1384 1385 1386 1387 1388 1389 | void sqlite3CompleteInsertion( Parse *pParse, /* The parser context */ Table *pTab, /* the table into which we are inserting */ int baseCur, /* Index of a read/write cursor pointing at pTab */ int regRowid, /* Range of content */ int *aRegIdx, /* Register used by each index. 0 for unused indices */ int isUpdate, /* True for UPDATE, False for INSERT */ | < | 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 | void sqlite3CompleteInsertion( Parse *pParse, /* The parser context */ Table *pTab, /* the table into which we are inserting */ int baseCur, /* Index of a read/write cursor pointing at pTab */ int regRowid, /* Range of content */ int *aRegIdx, /* Register used by each index. 0 for unused indices */ int isUpdate, /* 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 */ ){ int i; Vdbe *v; int nIdx; Index *pIdx; |
︙ | ︙ | |||
1411 1412 1413 1414 1415 1416 1417 | } } regData = regRowid + 1; regRec = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec); sqlite3TableAffinityStr(v, pTab); sqlite3ExprCacheAffinityChange(pParse, regData, pTab->nCol); | < < < < < | 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 | } } regData = regRowid + 1; regRec = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec); sqlite3TableAffinityStr(v, pTab); sqlite3ExprCacheAffinityChange(pParse, regData, pTab->nCol); if( pParse->nested ){ pik_flags = 0; }else{ pik_flags = OPFLAG_NCHANGE; pik_flags |= (isUpdate?OPFLAG_ISUPDATE:OPFLAG_LASTROWID); } if( appendBias ){ |
︙ | ︙ | |||
1739 1740 1741 1742 1743 1744 1745 | sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead); emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); regData = sqlite3GetTempReg(pParse); regRowid = sqlite3GetTempReg(pParse); if( pDest->iPKey>=0 ){ addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid); addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid); | | | | 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 | sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead); emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); regData = sqlite3GetTempReg(pParse); regRowid = sqlite3GetTempReg(pParse); if( pDest->iPKey>=0 ){ addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid); addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid); sqlite3HaltConstraint( pParse, onError, "PRIMARY KEY must be unique", P4_STATIC); sqlite3VdbeJumpHere(v, addr2); autoIncStep(pParse, regAutoinc, regRowid); }else if( pDest->pIndex==0 ){ addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid); }else{ addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid); assert( (pDest->tabFlags & TF_Autoincrement)==0 ); |
︙ | ︙ | |||
1790 1791 1792 1793 1794 1795 1796 | sqlite3VdbeAddOp2(v, OP_Close, iDest, 0); return 0; }else{ return 1; } } #endif /* SQLITE_OMIT_XFER_OPT */ | < < < < < | 1809 1810 1811 1812 1813 1814 1815 | sqlite3VdbeAddOp2(v, OP_Close, iDest, 0); return 0; }else{ return 1; } } #endif /* SQLITE_OMIT_XFER_OPT */ |
Changes to src/journal.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 2007 August 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 | /* ** 2007 August 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 special kind of sqlite3_file object used ** by SQLite to create journal files if the atomic-write optimization ** is enabled. ** ** The distinctive characteristic of this sqlite3_file is that the ** actual on disk file is created lazily. When the file is created, ** the caller specifies a buffer size for an in-memory buffer to ** be used to service read() and write() requests. The actual file ** on disk is not created or populated until either: ** ** 1) The in-memory representation grows too large for the allocated ** buffer, or ** 2) The sqlite3JournalCreate() function is called. */ #ifdef SQLITE_ENABLE_ATOMIC_WRITE #include "sqliteInt.h" /* ** A JournalFile object is a subclass of sqlite3_file used by ** as an open file handle for journal files. */ |
︙ | ︙ |
Changes to src/legacy.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Main file for the SQLite library. The routines in this file ** implement the programmer interface to the library. Routines in ** other files are for internal use by SQLite and should not be ** accessed by users of the library. | < < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Main file for the SQLite library. The routines in this file ** implement the programmer interface to the library. Routines in ** other files are for internal use by SQLite and should not be ** accessed by users of the library. */ #include "sqliteInt.h" /* ** Execute SQL code. Return one of the SQLITE_ success/failure ** codes. Also write an error message into memory obtained from |
︙ | ︙ | |||
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | rc = sqlite3ApiExit(db, rc); if( rc!=SQLITE_OK && ALWAYS(rc==sqlite3_errcode(db)) && pzErrMsg ){ int nErrMsg = 1 + sqlite3Strlen30(sqlite3_errmsg(db)); *pzErrMsg = sqlite3Malloc(nErrMsg); if( *pzErrMsg ){ memcpy(*pzErrMsg, sqlite3_errmsg(db), nErrMsg); } }else if( pzErrMsg ){ *pzErrMsg = 0; } assert( (rc&db->errMask)==rc ); sqlite3_mutex_leave(db->mutex); return rc; } | > > > | 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | rc = sqlite3ApiExit(db, rc); if( rc!=SQLITE_OK && ALWAYS(rc==sqlite3_errcode(db)) && pzErrMsg ){ int nErrMsg = 1 + sqlite3Strlen30(sqlite3_errmsg(db)); *pzErrMsg = sqlite3Malloc(nErrMsg); if( *pzErrMsg ){ memcpy(*pzErrMsg, sqlite3_errmsg(db), nErrMsg); }else{ rc = SQLITE_NOMEM; sqlite3Error(db, SQLITE_NOMEM, 0); } }else if( pzErrMsg ){ *pzErrMsg = 0; } assert( (rc&db->errMask)==rc ); sqlite3_mutex_leave(db->mutex); return rc; } |
Added src/lempar.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 | /* Driver template for the LEMON parser generator. ** The author disclaims copyright to this source code. ** ** This version of "lempar.c" is modified, slightly, for use by SQLite. ** The only modifications are the addition of a couple of NEVER() ** macros to disable tests that are needed in the case of a general ** LALR(1) grammar but which are always false in the ** specific grammar used by SQLite. */ /* First off, code is included that follows the "include" declaration ** in the input grammar file. */ #include <stdio.h> %% /* Next is all token values, in a form suitable for use by makeheaders. ** This section will be null unless lemon is run with the -m switch. */ /* ** These constants (all generated automatically by the parser generator) ** specify the various kinds of tokens (terminals) that the parser ** understands. ** ** Each symbol here is a terminal symbol in the grammar. */ %% /* Make sure the INTERFACE macro is defined. */ #ifndef INTERFACE # define INTERFACE 1 #endif /* The next thing included is series of defines which control ** various aspects of the generated parser. ** YYCODETYPE is the data type used for storing terminal ** and nonterminal numbers. "unsigned char" is ** used if there are fewer than 250 terminals ** and nonterminals. "int" is used otherwise. ** YYNOCODE is a number of type YYCODETYPE which corresponds ** to no legal terminal or nonterminal number. This ** number is used to fill in empty slots of the hash ** table. ** YYFALLBACK If defined, this indicates that one or more tokens ** have fall-back values which should be used if the ** original value of the token will not parse. ** YYACTIONTYPE is the data type used for storing terminal ** and nonterminal numbers. "unsigned char" is ** used if there are fewer than 250 rules and ** states combined. "int" is used otherwise. ** ParseTOKENTYPE is the data type used for minor tokens given ** directly to the parser from the tokenizer. ** YYMINORTYPE is the data type used for all minor tokens. ** This is typically a union of many types, one of ** which is ParseTOKENTYPE. The entry in the union ** for base tokens is called "yy0". ** YYSTACKDEPTH is the maximum depth of the parser's stack. If ** zero the stack is dynamically sized using realloc() ** ParseARG_SDECL A static variable declaration for the %extra_argument ** ParseARG_PDECL A parameter declaration for the %extra_argument ** ParseARG_STORE Code to store %extra_argument into yypParser ** ParseARG_FETCH Code to extract %extra_argument from yypParser ** YYNSTATE the combined number of states. ** YYNRULE the number of rules in the grammar ** YYERRORSYMBOL is the code number of the error symbol. If not ** defined, then do no error processing. */ %% #define YY_NO_ACTION (YYNSTATE+YYNRULE+2) #define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1) #define YY_ERROR_ACTION (YYNSTATE+YYNRULE) /* The yyzerominor constant is used to initialize instances of ** YYMINORTYPE objects to zero. */ static const YYMINORTYPE yyzerominor = { 0 }; /* Define the yytestcase() macro to be a no-op if is not already defined ** otherwise. ** ** Applications can choose to define yytestcase() in the %include section ** to a macro that can assist in verifying code coverage. For production ** code the yytestcase() macro should be turned off. But it is useful ** for testing. */ #ifndef yytestcase # define yytestcase(X) #endif /* Next are the tables used to determine what action to take based on the ** current state and lookahead token. These tables are used to implement ** functions that take a state number and lookahead value and return an ** action integer. ** ** Suppose the action integer is N. Then the action is determined as ** follows ** ** 0 <= N < YYNSTATE Shift N. That is, push the lookahead ** token onto the stack and goto state N. ** ** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE. ** ** N == YYNSTATE+YYNRULE A syntax error has occurred. ** ** N == YYNSTATE+YYNRULE+1 The parser accepts its input. ** ** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused ** slots in the yy_action[] table. ** ** The action table is constructed as a single large table named yy_action[]. ** Given state S and lookahead X, the action is computed as ** ** yy_action[ yy_shift_ofst[S] + X ] ** ** If the index value yy_shift_ofst[S]+X is out of range or if the value ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S] ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table ** and that yy_default[S] should be used instead. ** ** The formula above is for computing the action when the lookahead is ** a terminal symbol. If the lookahead is a non-terminal (as occurs after ** a reduce action) then the yy_reduce_ofst[] array is used in place of ** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of ** YY_SHIFT_USE_DFLT. ** ** The following are the tables generated in this section: ** ** yy_action[] A single table containing all actions. ** yy_lookahead[] A table containing the lookahead for each entry in ** yy_action. Used to detect hash collisions. ** yy_shift_ofst[] For each state, the offset into yy_action for ** shifting terminals. ** yy_reduce_ofst[] For each state, the offset into yy_action for ** shifting non-terminals after a reduce. ** yy_default[] Default action for each state. */ %% /* The next table maps tokens into fallback tokens. If a construct ** like the following: ** ** %fallback ID X Y Z. ** ** appears in the grammar, then ID becomes a fallback token for X, Y, ** and Z. Whenever one of the tokens X, Y, or Z is input to the parser ** but it does not parse, the type of the token is changed to ID and ** the parse is retried before an error is thrown. */ #ifdef YYFALLBACK static const YYCODETYPE yyFallback[] = { %% }; #endif /* YYFALLBACK */ /* The following structure represents a single element of the ** parser's stack. Information stored includes: ** ** + The state number for the parser at this level of the stack. ** ** + The value of the token stored at this level of the stack. ** (In other words, the "major" token.) ** ** + The semantic value stored at this level of the stack. This is ** the information used by the action routines in the grammar. ** It is sometimes called the "minor" token. */ struct yyStackEntry { YYACTIONTYPE stateno; /* The state-number */ YYCODETYPE major; /* The major token value. This is the code ** number for the token at this stack level */ YYMINORTYPE minor; /* The user-supplied minor token value. This ** is the value of the token */ }; typedef struct yyStackEntry yyStackEntry; /* The state of the parser is completely contained in an instance of ** the following structure */ struct yyParser { int yyidx; /* Index of top element in stack */ #ifdef YYTRACKMAXSTACKDEPTH int yyidxMax; /* Maximum value of yyidx */ #endif int yyerrcnt; /* Shifts left before out of the error */ ParseARG_SDECL /* A place to hold %extra_argument */ #if YYSTACKDEPTH<=0 int yystksz; /* Current side of the stack */ yyStackEntry *yystack; /* The parser's stack */ #else yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ #endif }; typedef struct yyParser yyParser; #ifndef NDEBUG #include <stdio.h> static FILE *yyTraceFILE = 0; static char *yyTracePrompt = 0; #endif /* NDEBUG */ #ifndef NDEBUG /* ** Turn parser tracing on by giving a stream to which to write the trace ** and a prompt to preface each trace message. Tracing is turned off ** by making either argument NULL ** ** Inputs: ** <ul> ** <li> A FILE* to which trace output should be written. ** If NULL, then tracing is turned off. ** <li> A prefix string written at the beginning of every ** line of trace output. If NULL, then tracing is ** turned off. ** </ul> ** ** Outputs: ** None. */ void ParseTrace(FILE *TraceFILE, char *zTracePrompt){ yyTraceFILE = TraceFILE; yyTracePrompt = zTracePrompt; if( yyTraceFILE==0 ) yyTracePrompt = 0; else if( yyTracePrompt==0 ) yyTraceFILE = 0; } #endif /* NDEBUG */ #ifndef NDEBUG /* For tracing shifts, the names of all terminals and nonterminals ** are required. The following table supplies these names */ static const char *const yyTokenName[] = { %% }; #endif /* NDEBUG */ #ifndef NDEBUG /* For tracing reduce actions, the names of all rules are required. */ static const char *const yyRuleName[] = { %% }; #endif /* NDEBUG */ #if YYSTACKDEPTH<=0 /* ** Try to increase the size of the parser stack. */ static void yyGrowStack(yyParser *p){ int newSize; yyStackEntry *pNew; newSize = p->yystksz*2 + 100; pNew = realloc(p->yystack, newSize*sizeof(pNew[0])); if( pNew ){ p->yystack = pNew; p->yystksz = newSize; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sStack grows to %d entries!\n", yyTracePrompt, p->yystksz); } #endif } } #endif /* ** This function allocates a new parser. ** The only argument is a pointer to a function which works like ** malloc. ** ** Inputs: ** A pointer to the function used to allocate memory. ** ** Outputs: ** A pointer to a parser. This pointer is used in subsequent calls ** to Parse and ParseFree. */ void *ParseAlloc(void *(*mallocProc)(size_t)){ yyParser *pParser; pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) ); if( pParser ){ pParser->yyidx = -1; #ifdef YYTRACKMAXSTACKDEPTH pParser->yyidxMax = 0; #endif #if YYSTACKDEPTH<=0 pParser->yystack = NULL; pParser->yystksz = 0; yyGrowStack(pParser); #endif } return pParser; } /* The following function deletes the value associated with a ** symbol. The symbol can be either a terminal or nonterminal. ** "yymajor" is the symbol code, and "yypminor" is a pointer to ** the value. */ static void yy_destructor( yyParser *yypParser, /* The parser */ YYCODETYPE yymajor, /* Type code for object to destroy */ YYMINORTYPE *yypminor /* The object to be destroyed */ ){ ParseARG_FETCH; switch( yymajor ){ /* Here is inserted the actions which take place when a ** terminal or non-terminal is destroyed. This can happen ** when the symbol is popped from the stack during a ** reduce or during error processing or when a parser is ** being destroyed before it is finished parsing. ** ** Note: during a reduce, the only symbols destroyed are those ** which appear on the RHS of the rule, but which are not used ** inside the C code. */ %% default: break; /* If no destructor action specified: do nothing */ } } /* ** Pop the parser's stack once. ** ** If there is a destructor routine associated with the token which ** is popped from the stack, then call it. ** ** Return the major token number for the symbol popped. */ static int yy_pop_parser_stack(yyParser *pParser){ YYCODETYPE yymajor; yyStackEntry *yytos = &pParser->yystack[pParser->yyidx]; /* There is no mechanism by which the parser stack can be popped below ** empty in SQLite. */ if( NEVER(pParser->yyidx<0) ) return 0; #ifndef NDEBUG if( yyTraceFILE && pParser->yyidx>=0 ){ fprintf(yyTraceFILE,"%sPopping %s\n", yyTracePrompt, yyTokenName[yytos->major]); } #endif yymajor = yytos->major; yy_destructor(pParser, yymajor, &yytos->minor); pParser->yyidx--; return yymajor; } /* ** Deallocate and destroy a parser. Destructors are all called for ** all stack elements before shutting the parser down. ** ** Inputs: ** <ul> ** <li> A pointer to the parser. This should be a pointer ** obtained from ParseAlloc. ** <li> A pointer to a function used to reclaim memory obtained ** from malloc. ** </ul> */ void ParseFree( void *p, /* The parser to be deleted */ void (*freeProc)(void*) /* Function used to reclaim memory */ ){ yyParser *pParser = (yyParser*)p; /* In SQLite, we never try to destroy a parser that was not successfully ** created in the first place. */ if( NEVER(pParser==0) ) return; while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser); #if YYSTACKDEPTH<=0 free(pParser->yystack); #endif (*freeProc)((void*)pParser); } /* ** Return the peak depth of the stack for a parser. */ #ifdef YYTRACKMAXSTACKDEPTH int ParseStackPeak(void *p){ yyParser *pParser = (yyParser*)p; return pParser->yyidxMax; } #endif /* ** Find the appropriate action for a parser given the terminal ** look-ahead token iLookAhead. ** ** If the look-ahead token is YYNOCODE, then check to see if the action is ** independent of the look-ahead. If it is, return the action, otherwise ** return YY_NO_ACTION. */ static int yy_find_shift_action( yyParser *pParser, /* The parser */ YYCODETYPE iLookAhead /* The look-ahead token */ ){ int i; int stateno = pParser->yystack[pParser->yyidx].stateno; if( stateno>YY_SHIFT_COUNT || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){ return yy_default[stateno]; } assert( iLookAhead!=YYNOCODE ); i += iLookAhead; if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ if( iLookAhead>0 ){ #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 return yy_find_shift_action(pParser, iFallback); } #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 yy_lookahead[j]==YYWILDCARD ){ #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]; } } /* ** Find the appropriate action for a parser given the non-terminal ** look-ahead token iLookAhead. ** ** If the look-ahead token is YYNOCODE, then check to see if the action is ** independent of the look-ahead. If it is, return the action, otherwise ** return YY_NO_ACTION. */ static int yy_find_reduce_action( int stateno, /* Current state number */ YYCODETYPE iLookAhead /* The look-ahead token */ ){ int i; #ifdef YYERRORSYMBOL if( stateno>YY_REDUCE_COUNT ){ return yy_default[stateno]; } #else assert( stateno<=YY_REDUCE_COUNT ); #endif i = yy_reduce_ofst[stateno]; assert( i!=YY_REDUCE_USE_DFLT ); assert( iLookAhead!=YYNOCODE ); i += iLookAhead; #ifdef YYERRORSYMBOL if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ return yy_default[stateno]; } #else assert( i>=0 && i<YY_ACTTAB_COUNT ); assert( yy_lookahead[i]==iLookAhead ); #endif return yy_action[i]; } /* ** The following routine is called if the stack overflows. */ static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){ ParseARG_FETCH; yypParser->yyidx--; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt); } #endif while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will execute if the parser ** stack every overflows */ %% ParseARG_STORE; /* Suppress warning about unused %extra_argument var */ } /* ** Perform a shift action. */ static void yy_shift( yyParser *yypParser, /* The parser to be shifted */ int yyNewState, /* The new state to shift in */ int yyMajor, /* The major token to shift in */ YYMINORTYPE *yypMinor /* Pointer to the minor token to shift in */ ){ yyStackEntry *yytos; yypParser->yyidx++; #ifdef YYTRACKMAXSTACKDEPTH if( yypParser->yyidx>yypParser->yyidxMax ){ yypParser->yyidxMax = yypParser->yyidx; } #endif #if YYSTACKDEPTH>0 if( yypParser->yyidx>=YYSTACKDEPTH ){ yyStackOverflow(yypParser, yypMinor); return; } #else if( yypParser->yyidx>=yypParser->yystksz ){ yyGrowStack(yypParser); if( yypParser->yyidx>=yypParser->yystksz ){ yyStackOverflow(yypParser, yypMinor); return; } } #endif yytos = &yypParser->yystack[yypParser->yyidx]; yytos->stateno = (YYACTIONTYPE)yyNewState; yytos->major = (YYCODETYPE)yyMajor; yytos->minor = *yypMinor; #ifndef NDEBUG if( yyTraceFILE && yypParser->yyidx>0 ){ int i; fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState); fprintf(yyTraceFILE,"%sStack:",yyTracePrompt); for(i=1; i<=yypParser->yyidx; i++) fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]); fprintf(yyTraceFILE,"\n"); } #endif } /* The following table contains information about every rule that ** is used during the reduce. */ static const struct { YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ unsigned char nrhs; /* Number of right-hand side symbols in the rule */ } yyRuleInfo[] = { %% }; static void yy_accept(yyParser*); /* Forward Declaration */ /* ** Perform a reduce action and the shift that must immediately ** follow the reduce. */ static void yy_reduce( yyParser *yypParser, /* The parser */ int yyruleno /* Number of the rule by which to reduce */ ){ int yygoto; /* The next state */ int yyact; /* The next action */ YYMINORTYPE yygotominor; /* The LHS of the rule reduced */ yyStackEntry *yymsp; /* The top of the parser's stack */ int yysize; /* Amount to pop the stack */ ParseARG_FETCH; yymsp = &yypParser->yystack[yypParser->yyidx]; #ifndef NDEBUG if( yyTraceFILE && yyruleno>=0 && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt, yyRuleName[yyruleno]); } #endif /* NDEBUG */ /* Silence complaints from purify about yygotominor being uninitialized ** in some cases when it is copied into the stack after the following ** switch. yygotominor is uninitialized when a rule reduces that does ** not set the value of its left-hand side nonterminal. Leaving the ** value of the nonterminal uninitialized is utterly harmless as long ** as the value is never used. So really the only thing this code ** accomplishes is to quieten purify. ** ** 2007-01-16: The wireshark project (www.wireshark.org) reports that ** without this code, their parser segfaults. I'm not sure what there ** parser is doing to make this happen. This is the second bug report ** from wireshark this week. Clearly they are stressing Lemon in ways ** that it has not been previously stressed... (SQLite ticket #2172) */ /*memset(&yygotominor, 0, sizeof(yygotominor));*/ yygotominor = yyzerominor; switch( yyruleno ){ /* Beginning here are the reduction cases. A typical example ** follows: ** case 0: ** #line <lineno> <grammarfile> ** { ... } // User supplied code ** #line <lineno> <thisfile> ** break; */ %% }; yygoto = yyRuleInfo[yyruleno].lhs; yysize = yyRuleInfo[yyruleno].nrhs; yypParser->yyidx -= yysize; yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto); if( yyact < YYNSTATE ){ #ifdef NDEBUG /* If we are not debugging and the reduce action popped at least ** one element off the stack, then we can push the new element back ** onto the stack here, and skip the stack overflow test in yy_shift(). ** That gives a significant speed improvement. */ if( yysize ){ yypParser->yyidx++; yymsp -= yysize-1; yymsp->stateno = (YYACTIONTYPE)yyact; yymsp->major = (YYCODETYPE)yygoto; yymsp->minor = yygotominor; }else #endif { yy_shift(yypParser,yyact,yygoto,&yygotominor); } }else{ assert( yyact == YYNSTATE + YYNRULE + 1 ); yy_accept(yypParser); } } /* ** The following code executes when the parse fails */ #ifndef YYNOERRORRECOVERY static void yy_parse_failed( yyParser *yypParser /* The parser */ ){ ParseARG_FETCH; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt); } #endif while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will be executed whenever the ** parser fails */ %% ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ } #endif /* YYNOERRORRECOVERY */ /* ** The following code executes when a syntax error first occurs. */ static void yy_syntax_error( yyParser *yypParser, /* The parser */ int yymajor, /* The major type of the error token */ YYMINORTYPE yyminor /* The minor type of the error token */ ){ ParseARG_FETCH; #define TOKEN (yyminor.yy0) %% ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ } /* ** The following is executed when the parser accepts */ static void yy_accept( yyParser *yypParser /* The parser */ ){ ParseARG_FETCH; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); } #endif while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will be executed whenever the ** parser accepts */ %% ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ } /* The main parser program. ** The first argument is a pointer to a structure obtained from ** "ParseAlloc" which describes the current state of the parser. ** The second argument is the major token number. The third is ** the minor token. The fourth optional argument is whatever the ** user wants (and specified in the grammar) and is available for ** use by the action routines. ** ** Inputs: ** <ul> ** <li> A pointer to the parser (an opaque structure.) ** <li> The major token number. ** <li> The minor token number. ** <li> An option argument of a grammar-specified type. ** </ul> ** ** Outputs: ** None. */ void Parse( void *yyp, /* The parser */ int yymajor, /* The major token code number */ ParseTOKENTYPE yyminor /* The value for the token */ ParseARG_PDECL /* Optional %extra_argument parameter */ ){ YYMINORTYPE yyminorunion; int yyact; /* The parser action. */ int yyendofinput; /* True if we are at the end of input */ #ifdef YYERRORSYMBOL int yyerrorhit = 0; /* True if yymajor has invoked an error */ #endif yyParser *yypParser; /* The parser */ /* (re)initialize the parser, if necessary */ yypParser = (yyParser*)yyp; if( yypParser->yyidx<0 ){ #if YYSTACKDEPTH<=0 if( yypParser->yystksz <=0 ){ /*memset(&yyminorunion, 0, sizeof(yyminorunion));*/ yyminorunion = yyzerominor; yyStackOverflow(yypParser, &yyminorunion); return; } #endif yypParser->yyidx = 0; yypParser->yyerrcnt = -1; yypParser->yystack[0].stateno = 0; yypParser->yystack[0].major = 0; } yyminorunion.yy0 = yyminor; yyendofinput = (yymajor==0); ParseARG_STORE; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]); } #endif do{ yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); if( yyact<YYNSTATE ){ assert( !yyendofinput ); /* Impossible to shift the $ token */ yy_shift(yypParser,yyact,yymajor,&yyminorunion); yypParser->yyerrcnt--; yymajor = YYNOCODE; }else if( yyact < YYNSTATE + YYNRULE ){ yy_reduce(yypParser,yyact-YYNSTATE); }else{ assert( yyact == YY_ERROR_ACTION ); #ifdef YYERRORSYMBOL int yymx; #endif #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt); } #endif #ifdef YYERRORSYMBOL /* A syntax error has occurred. ** The response to an error depends upon whether or not the ** grammar defines an error token "ERROR". ** ** This is what we do if the grammar does define ERROR: ** ** * Call the %syntax_error function. ** ** * Begin popping the stack until we enter a state where ** it is legal to shift the error symbol, then shift ** the error symbol. ** ** * Set the error count to three. ** ** * Begin accepting and shifting new tokens. No new error ** processing will occur until three tokens have been ** shifted successfully. ** */ if( yypParser->yyerrcnt<0 ){ yy_syntax_error(yypParser,yymajor,yyminorunion); } yymx = yypParser->yystack[yypParser->yyidx].major; if( yymx==YYERRORSYMBOL || yyerrorhit ){ #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sDiscard input token %s\n", yyTracePrompt,yyTokenName[yymajor]); } #endif yy_destructor(yypParser, (YYCODETYPE)yymajor,&yyminorunion); yymajor = YYNOCODE; }else{ while( yypParser->yyidx >= 0 && yymx != YYERRORSYMBOL && (yyact = yy_find_reduce_action( yypParser->yystack[yypParser->yyidx].stateno, YYERRORSYMBOL)) >= YYNSTATE ){ yy_pop_parser_stack(yypParser); } if( yypParser->yyidx < 0 || yymajor==0 ){ yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); yy_parse_failed(yypParser); yymajor = YYNOCODE; }else if( yymx!=YYERRORSYMBOL ){ YYMINORTYPE u2; u2.YYERRSYMDT = 0; yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2); } } yypParser->yyerrcnt = 3; yyerrorhit = 1; #elif defined(YYNOERRORRECOVERY) /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to ** do any kind of error recovery. Instead, simply invoke the syntax ** error routine and continue going as if nothing had happened. ** ** Applications can set this macro (for example inside %include) if ** they intend to abandon the parse upon the first syntax error seen. */ yy_syntax_error(yypParser,yymajor,yyminorunion); yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); yymajor = YYNOCODE; #else /* YYERRORSYMBOL is not defined */ /* This is what we do if the grammar does not define ERROR: ** ** * Report an error message, and throw away the input token. ** ** * If the input token is $, then fail the parse. ** ** As before, subsequent error messages are suppressed until ** three input tokens have been successfully shifted. */ if( yypParser->yyerrcnt<=0 ){ yy_syntax_error(yypParser,yymajor,yyminorunion); } yypParser->yyerrcnt = 3; yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); if( yyendofinput ){ yy_parse_failed(yypParser); } yymajor = YYNOCODE; #endif } }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 ); return; } |
Changes to src/loadext.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2006 June 7 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to dynamically load extensions into ** the SQLite library. | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* ** 2006 June 7 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to dynamically load extensions into ** the SQLite library. */ #ifndef SQLITE_CORE #define SQLITE_CORE 1 /* Disable the API redefinition in sqlite3ext.h */ #endif #include "sqlite3ext.h" #include "sqliteInt.h" |
︙ | ︙ |
Changes to src/main.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Main file for the SQLite library. The routines in this file ** implement the programmer interface to the library. Routines in ** other files are for internal use by SQLite and should not be ** accessed by users of the library. | < < > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Main file for the SQLite library. The routines in this file ** implement the programmer interface to the library. Routines in ** other files are for internal use by SQLite and should not be ** accessed by users of the library. */ #include "sqliteInt.h" #ifdef SQLITE_ENABLE_FTS3 # include "fts3.h" #endif #ifdef SQLITE_ENABLE_RTREE # include "rtree.h" #endif #ifdef SQLITE_ENABLE_ICU # include "sqliteicu.h" #endif /* ** The version of the library */ #ifndef SQLITE_AMALGAMATION const char sqlite3_version[] = SQLITE_VERSION; #endif const char *sqlite3_libversion(void){ return sqlite3_version; } const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; } int sqlite3_threadsafe(void){ return SQLITE_THREADSAFE; } #if !defined(SQLITE_OMIT_TRACE) && defined(SQLITE_ENABLE_IOTRACE) /* ** If the following function pointer is not NULL and if ** SQLITE_ENABLE_IOTRACE is enabled, then messages describing |
︙ | ︙ | |||
121 122 123 124 125 126 127 128 129 130 131 132 133 | ** 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. */ pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); sqlite3_mutex_enter(pMaster); if( !sqlite3GlobalConfig.isMallocInit ){ rc = sqlite3MallocInit(); } if( rc==SQLITE_OK ){ sqlite3GlobalConfig.isMallocInit = 1; if( !sqlite3GlobalConfig.pInitMutex ){ | > | > | < | < > > | > > | | 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 | ** 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. */ 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; } } } 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; } /* Do the rest of the initialization under the recursive mutex so ** that we will be able to handle recursive calls into ** sqlite3_initialize(). The recursive calls normally come through ** sqlite3_os_init() when it invokes sqlite3_vfs_register(), but other ** recursive calls might also be possible. */ sqlite3_mutex_enter(sqlite3GlobalConfig.pInitMutex); if( sqlite3GlobalConfig.isInit==0 && sqlite3GlobalConfig.inProgress==0 ){ FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions); sqlite3GlobalConfig.inProgress = 1; memset(pHash, 0, sizeof(sqlite3GlobalFunctions)); sqlite3RegisterGlobalFunctions(); if( sqlite3GlobalConfig.isPCacheInit==0 ){ rc = sqlite3PcacheInitialize(); } if( rc==SQLITE_OK ){ sqlite3GlobalConfig.isPCacheInit = 1; rc = sqlite3OsInit(); } if( rc==SQLITE_OK ){ sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage, sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage); sqlite3GlobalConfig.isInit = 1; } sqlite3GlobalConfig.inProgress = 0; |
︙ | ︙ | |||
215 216 217 218 219 220 221 | ** while any part of SQLite is otherwise in use in any thread. This ** routine is not threadsafe. But it is safe to invoke this routine ** on when SQLite is already shut down. If SQLite is already shut down ** when this routine is invoked, then this routine is a harmless no-op. */ int sqlite3_shutdown(void){ if( sqlite3GlobalConfig.isInit ){ | > > | > > | > | > > > | > | 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 | ** while any part of SQLite is otherwise in use in any thread. This ** routine is not threadsafe. But it is safe to invoke this routine ** on when SQLite is already shut down. If SQLite is already shut down ** when this routine is invoked, then this routine is a harmless no-op. */ int sqlite3_shutdown(void){ if( sqlite3GlobalConfig.isInit ){ sqlite3_os_end(); sqlite3_reset_auto_extension(); sqlite3GlobalConfig.isInit = 0; } if( sqlite3GlobalConfig.isPCacheInit ){ sqlite3PcacheShutdown(); sqlite3GlobalConfig.isPCacheInit = 0; } if( sqlite3GlobalConfig.isMallocInit ){ sqlite3MallocEnd(); sqlite3GlobalConfig.isMallocInit = 0; } if( sqlite3GlobalConfig.isMutexInit ){ sqlite3MutexEnd(); sqlite3GlobalConfig.isMutexInit = 0; } return SQLITE_OK; } /* ** This API allows applications to modify the global configuration of ** the SQLite library at run-time. ** |
︙ | ︙ | |||
714 715 716 717 718 719 720 721 722 723 724 725 726 727 | sqlite3VtabRollback(db); sqlite3EndBenignMalloc(); if( db->flags&SQLITE_InternChanges ){ sqlite3ExpirePreparedStatements(db); sqlite3ResetInternalSchema(db, 0); } /* If one has been configured, invoke the rollback-hook callback */ if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){ db->xRollbackCallback(db->pRollbackArg); } } | > > > | 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 | sqlite3VtabRollback(db); sqlite3EndBenignMalloc(); if( db->flags&SQLITE_InternChanges ){ sqlite3ExpirePreparedStatements(db); sqlite3ResetInternalSchema(db, 0); } /* Any deferred constraint violations have now been resolved. */ db->nDeferredCons = 0; /* If one has been configured, invoke the rollback-hook callback */ if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){ db->xRollbackCallback(db->pRollbackArg); } } |
︙ | ︙ | |||
1200 1201 1202 1203 1204 1205 1206 | ** soon as the connection is closed. ** ** A virtual database can be either a disk file (that is automatically ** deleted when the file is closed) or it an be held entirely in memory. ** The sqlite3TempInMemory() function is used to determine which. */ int sqlite3BtreeFactory( | | | 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 | ** soon as the connection is closed. ** ** A virtual database can be either a disk file (that is automatically ** deleted when the file is closed) or it an be held entirely in memory. ** The sqlite3TempInMemory() function is used to determine which. */ int sqlite3BtreeFactory( sqlite3 *db, /* Main database when opening aux otherwise 0 */ const char *zFilename, /* Name of the file containing the BTree database */ int omitJournal, /* if TRUE then do not journal this file */ int nCache, /* How many pages in the page cache */ int vfsFlags, /* Flags passed through to vfsOpen */ Btree **ppBtree /* Pointer to new Btree object written here */ ){ int btFlags = 0; |
︙ | ︙ | |||
1341 1342 1343 1344 1345 1346 1347 | } /* ** Create a new collating function for database "db". The name is zName ** and the encoding is enc. */ static int createCollation( | | | > | 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 | } /* ** Create a new collating function for database "db". The name is zName ** and the encoding is enc. */ static int createCollation( sqlite3* db, const char *zName, u8 enc, u8 collType, void* pCtx, int(*xCompare)(void*,int,const void*,int,const void*), void(*xDel)(void*) ){ CollSeq *pColl; int enc2; int nName = sqlite3Strlen30(zName); |
︙ | ︙ | |||
1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 | pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 1); if( pColl ){ pColl->xCmp = xCompare; pColl->pUser = pCtx; pColl->xDel = xDel; pColl->enc = (u8)(enc2 | (enc & SQLITE_UTF16_ALIGNED)); } sqlite3Error(db, SQLITE_OK, 0); return SQLITE_OK; } /* | > | 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 | pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 1); if( pColl ){ pColl->xCmp = xCompare; pColl->pUser = pCtx; pColl->xDel = xDel; pColl->enc = (u8)(enc2 | (enc & SQLITE_UTF16_ALIGNED)); pColl->type = collType; } sqlite3Error(db, SQLITE_OK, 0); return SQLITE_OK; } /* |
︙ | ︙ | |||
1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 | SQLITE_MAX_EXPR_DEPTH, SQLITE_MAX_COMPOUND_SELECT, SQLITE_MAX_VDBE_OP, SQLITE_MAX_FUNCTION_ARG, SQLITE_MAX_ATTACHED, SQLITE_MAX_LIKE_PATTERN_LENGTH, SQLITE_MAX_VARIABLE_NUMBER, }; /* ** Make sure the hard limits are set to reasonable values */ #if SQLITE_MAX_LENGTH<100 # error SQLITE_MAX_LENGTH must be at least 100 | > | 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 | SQLITE_MAX_EXPR_DEPTH, SQLITE_MAX_COMPOUND_SELECT, SQLITE_MAX_VDBE_OP, SQLITE_MAX_FUNCTION_ARG, SQLITE_MAX_ATTACHED, SQLITE_MAX_LIKE_PATTERN_LENGTH, SQLITE_MAX_VARIABLE_NUMBER, SQLITE_MAX_TRIGGER_DEPTH, }; /* ** Make sure the hard limits are set to reasonable values */ #if SQLITE_MAX_LENGTH<100 # error SQLITE_MAX_LENGTH must be at least 100 |
︙ | ︙ | |||
1459 1460 1461 1462 1463 1464 1465 | #endif #if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>30 # error SQLITE_MAX_ATTACHED must be between 0 and 30 #endif #if SQLITE_MAX_LIKE_PATTERN_LENGTH<1 # error SQLITE_MAX_LIKE_PATTERN_LENGTH must be at least 1 #endif | < < < > > > | 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 | #endif #if SQLITE_MAX_ATTACHED<0 || SQLITE_MAX_ATTACHED>30 # error SQLITE_MAX_ATTACHED must be between 0 and 30 #endif #if SQLITE_MAX_LIKE_PATTERN_LENGTH<1 # error SQLITE_MAX_LIKE_PATTERN_LENGTH must be at least 1 #endif #if SQLITE_MAX_COLUMN>32767 # error SQLITE_MAX_COLUMN must not exceed 32767 #endif #if SQLITE_MAX_TRIGGER_DEPTH<1 # error SQLITE_MAX_TRIGGER_DEPTH must be at least 1 #endif /* ** Change the value of a limit. Report the old value. ** If an invalid limit index is supplied, report -1. ** Make no changes but still report the old value if the ** new limit is negative. |
︙ | ︙ | |||
1505 1506 1507 1508 1509 1510 1511 | const char *zFilename, /* Database filename UTF-8 encoded */ sqlite3 **ppDb, /* OUT: Returned database handle */ unsigned flags, /* Operational flags */ const char *zVfs /* Name of the VFS to use */ ){ sqlite3 *db; int rc; | < > > > > > | 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 | const char *zFilename, /* Database filename UTF-8 encoded */ sqlite3 **ppDb, /* OUT: Returned database handle */ unsigned flags, /* Operational flags */ const char *zVfs /* Name of the VFS to use */ ){ sqlite3 *db; int rc; int isThreadsafe; *ppDb = 0; #ifndef SQLITE_OMIT_AUTOINIT rc = sqlite3_initialize(); if( rc ) return rc; #endif if( sqlite3GlobalConfig.bCoreMutex==0 ){ isThreadsafe = 0; }else if( flags & SQLITE_OPEN_NOMUTEX ){ isThreadsafe = 0; }else if( flags & SQLITE_OPEN_FULLMUTEX ){ isThreadsafe = 1; }else{ isThreadsafe = sqlite3GlobalConfig.bFullMutex; } if( flags & SQLITE_OPEN_PRIVATECACHE ){ flags &= ~SQLITE_OPEN_SHAREDCACHE; }else if( sqlite3GlobalConfig.sharedCacheEnabled ){ flags |= SQLITE_OPEN_SHAREDCACHE; } /* 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, |
︙ | ︙ | |||
1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 | db->flags |= SQLITE_ShortColNames #if SQLITE_DEFAULT_FILE_FORMAT<4 | SQLITE_LegacyFileFmt #endif #ifdef SQLITE_ENABLE_LOAD_EXTENSION | SQLITE_LoadExtension #endif ; sqlite3HashInit(&db->aCollSeq); #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3HashInit(&db->aModule); #endif db->pVfs = sqlite3_vfs_find(zVfs); if( !db->pVfs ){ rc = SQLITE_ERROR; sqlite3Error(db, rc, "no such vfs: %s", zVfs); goto opendb_out; } /* Add the default collation sequence BINARY. BINARY works for both UTF-8 ** and UTF-16, so add a version for each to avoid any unnecessary ** conversions. The only error that can occur here is a malloc() failure. */ | > > > | > | > | > | > | | < < < < < < | 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 | db->flags |= SQLITE_ShortColNames #if SQLITE_DEFAULT_FILE_FORMAT<4 | SQLITE_LegacyFileFmt #endif #ifdef SQLITE_ENABLE_LOAD_EXTENSION | SQLITE_LoadExtension #endif #if SQLITE_DEFAULT_RECURSIVE_TRIGGERS | SQLITE_RecTriggers #endif ; sqlite3HashInit(&db->aCollSeq); #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3HashInit(&db->aModule); #endif db->pVfs = sqlite3_vfs_find(zVfs); if( !db->pVfs ){ rc = SQLITE_ERROR; sqlite3Error(db, rc, "no such vfs: %s", zVfs); goto opendb_out; } /* Add the default collation sequence BINARY. BINARY works for both UTF-8 ** and UTF-16, so add a version for each to avoid any unnecessary ** conversions. The only error that can occur here is a malloc() failure. */ createCollation(db, "BINARY", SQLITE_UTF8, SQLITE_COLL_BINARY, 0, binCollFunc, 0); createCollation(db, "BINARY", SQLITE_UTF16BE, SQLITE_COLL_BINARY, 0, binCollFunc, 0); createCollation(db, "BINARY", SQLITE_UTF16LE, SQLITE_COLL_BINARY, 0, binCollFunc, 0); createCollation(db, "RTRIM", SQLITE_UTF8, SQLITE_COLL_USER, (void*)1, binCollFunc, 0); if( db->mallocFailed ){ goto opendb_out; } db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 0); assert( db->pDfltColl!=0 ); /* Also add a UTF-8 case-insensitive collation sequence. */ createCollation(db, "NOCASE", SQLITE_UTF8, SQLITE_COLL_NOCASE, 0, nocaseCollatingFunc, 0); /* Open the backend database driver */ db->openFlags = flags; rc = sqlite3BtreeFactory(db, zFilename, 0, SQLITE_DEFAULT_CACHE_SIZE, flags | SQLITE_OPEN_MAIN_DB, &db->aDb[0].pBt); if( rc!=SQLITE_OK ){ |
︙ | ︙ | |||
1632 1633 1634 1635 1636 1637 1638 | /* The default safety_level for the main database is 'full'; for the temp ** database it is 'NONE'. This matches the pager layer defaults. */ db->aDb[0].zName = "main"; db->aDb[0].safety_level = 3; | < < | 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 | /* The default safety_level for the main database is 'full'; for the temp ** database it is 'NONE'. This matches the pager layer defaults. */ db->aDb[0].zName = "main"; db->aDb[0].safety_level = 3; db->aDb[1].zName = "temp"; db->aDb[1].safety_level = 1; db->magic = SQLITE_MAGIC_OPEN; if( db->mallocFailed ){ goto opendb_out; } /* Register all built-in functions, but do not attempt to read the |
︙ | ︙ | |||
1792 1793 1794 1795 1796 1797 1798 | int enc, void* pCtx, int(*xCompare)(void*,int,const void*,int,const void*) ){ int rc; sqlite3_mutex_enter(db->mutex); assert( !db->mallocFailed ); | | | | 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 | int enc, void* pCtx, int(*xCompare)(void*,int,const void*,int,const void*) ){ int rc; sqlite3_mutex_enter(db->mutex); assert( !db->mallocFailed ); rc = createCollation(db, zName, (u8)enc, SQLITE_COLL_USER, pCtx, xCompare, 0); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; } /* ** Register a new collation sequence with the database handle db. */ int sqlite3_create_collation_v2( sqlite3* db, const char *zName, int enc, void* pCtx, int(*xCompare)(void*,int,const void*,int,const void*), void(*xDel)(void*) ){ int rc; sqlite3_mutex_enter(db->mutex); assert( !db->mallocFailed ); rc = createCollation(db, zName, (u8)enc, SQLITE_COLL_USER, pCtx, xCompare, xDel); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; } #ifndef SQLITE_OMIT_UTF16 /* |
︙ | ︙ | |||
1835 1836 1837 1838 1839 1840 1841 | ){ int rc = SQLITE_OK; char *zName8; sqlite3_mutex_enter(db->mutex); assert( !db->mallocFailed ); zName8 = sqlite3Utf16to8(db, zName, -1); if( zName8 ){ | | | 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 | ){ int rc = SQLITE_OK; char *zName8; sqlite3_mutex_enter(db->mutex); assert( !db->mallocFailed ); zName8 = sqlite3Utf16to8(db, zName, -1); if( zName8 ){ rc = createCollation(db, zName8, (u8)enc, SQLITE_COLL_USER, pCtx, xCompare, 0); sqlite3DbFree(db, zName8); } rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; } #endif /* SQLITE_OMIT_UTF16 */ |
︙ | ︙ | |||
2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 | ** } */ case SQLITE_TESTCTRL_ALWAYS: { int x = va_arg(ap,int); rc = ALWAYS(x); break; } } va_end(ap); #endif /* SQLITE_OMIT_BUILTIN_TEST */ return rc; } | > > > > > > > > > > > > > > > | 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 | ** } */ case SQLITE_TESTCTRL_ALWAYS: { int x = va_arg(ap,int); rc = ALWAYS(x); 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; } } va_end(ap); #endif /* SQLITE_OMIT_BUILTIN_TEST */ return rc; } |
Changes to src/malloc.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** Memory allocation functions used throughout sqlite. | < < | 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. ** ************************************************************************* ** ** Memory allocation functions used throughout sqlite. */ #include "sqliteInt.h" #include <stdarg.h> /* ** This routine runs when the memory allocator sees that the ** total memory allocation is about to exceed the soft heap |
︙ | ︙ | |||
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | sqlite3_uint64 iLimit; int overage; if( n<0 ){ iLimit = 0; }else{ iLimit = n; } sqlite3_initialize(); if( iLimit>0 ){ sqlite3MemoryAlarm(softHeapLimitEnforcer, 0, iLimit); }else{ sqlite3MemoryAlarm(0, 0, 0); } overage = (int)(sqlite3_memory_used() - (i64)n); if( overage>0 ){ sqlite3_release_memory(overage); } } /* ** Attempt to release up to n bytes of non-essential memory currently ** held by SQLite. An example of non-essential memory is memory used to ** cache database pages that are not currently in use. */ int sqlite3_release_memory(int n){ #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT int nRet = 0; | > > < < < | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | sqlite3_uint64 iLimit; int overage; if( n<0 ){ iLimit = 0; }else{ iLimit = n; } #ifndef SQLITE_OMIT_AUTOINIT sqlite3_initialize(); #endif if( iLimit>0 ){ sqlite3MemoryAlarm(softHeapLimitEnforcer, 0, iLimit); }else{ sqlite3MemoryAlarm(0, 0, 0); } overage = (int)(sqlite3_memory_used() - (i64)n); if( overage>0 ){ sqlite3_release_memory(overage); } } /* ** Attempt to release up to n bytes of non-essential memory currently ** held by SQLite. An example of non-essential memory is memory used to ** cache database pages that are not currently in use. */ int sqlite3_release_memory(int n){ #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT int nRet = 0; nRet += sqlite3PcacheReleaseMemory(n-nRet); return nRet; #else UNUSED_PARAMETER(n); return SQLITE_OK; #endif } |
︙ | ︙ | |||
84 85 86 87 88 89 90 | sqlite3_mutex *mutex; /* Mutex to serialize access */ /* ** The alarm callback and its arguments. The mem0.mutex lock will ** be held while the callback is running. Recursive calls into ** the memory subsystem are allowed, but no new callbacks will be | | < < | | 81 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 | sqlite3_mutex *mutex; /* Mutex to serialize access */ /* ** The alarm callback and its arguments. The mem0.mutex lock will ** be held while the callback is running. Recursive calls into ** the memory subsystem are allowed, but no new callbacks will be ** issued. */ sqlite3_int64 alarmThreshold; void (*alarmCallback)(void*, sqlite3_int64,int); void *alarmArg; /* ** Pointers to the end of sqlite3GlobalConfig.pScratch and ** sqlite3GlobalConfig.pPage to a block of memory that records ** which pages are available. */ u32 *aScratchFree; u32 *aPageFree; } mem0 = { 0, 0, 0, 0, 0, 0, 0, 0 }; #define mem0 GLOBAL(struct Mem0Global, mem0) /* ** Initialize the memory allocation subsystem. */ int sqlite3MallocInit(void){ |
︙ | ︙ | |||
216 217 218 219 220 221 222 | /* ** Trigger the alarm */ static void sqlite3MallocAlarm(int nByte){ void (*xCallback)(void*,sqlite3_int64,int); sqlite3_int64 nowUsed; void *pArg; | | < > > | | 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | /* ** Trigger the alarm */ static void sqlite3MallocAlarm(int nByte){ void (*xCallback)(void*,sqlite3_int64,int); sqlite3_int64 nowUsed; void *pArg; if( mem0.alarmCallback==0 ) return; xCallback = mem0.alarmCallback; nowUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); pArg = mem0.alarmArg; mem0.alarmCallback = 0; sqlite3_mutex_leave(mem0.mutex); xCallback(pArg, nowUsed, nByte); sqlite3_mutex_enter(mem0.mutex); mem0.alarmCallback = xCallback; mem0.alarmArg = pArg; } /* ** Do a memory allocation with statistics and alarms. Assume the ** lock is already held. */ static int mallocWithAlarm(int n, void **pp){ |
︙ | ︙ | |||
420 421 422 423 424 425 426 | ** sqlite3Malloc() or sqlite3_malloc(). */ int sqlite3MallocSize(void *p){ return sqlite3GlobalConfig.m.xSize(p); } int sqlite3DbMallocSize(sqlite3 *db, void *p){ assert( db==0 || sqlite3_mutex_held(db->mutex) ); | < < | | 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 | ** sqlite3Malloc() or sqlite3_malloc(). */ int sqlite3MallocSize(void *p){ return sqlite3GlobalConfig.m.xSize(p); } int sqlite3DbMallocSize(sqlite3 *db, void *p){ assert( db==0 || sqlite3_mutex_held(db->mutex) ); if( isLookaside(db, p) ){ return db->lookaside.sz; }else{ return sqlite3GlobalConfig.m.xSize(p); } } /* |
︙ | ︙ | |||
478 479 480 481 482 483 484 | return 0; } if( nBytes>=0x7fffff00 ){ /* The 0x7ffff00 limit term is explained in comments on sqlite3Malloc() */ return 0; } nOld = sqlite3MallocSize(pOld); | < < < | | | | > > | | | | | | | | | | | | | < | | 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 | return 0; } if( nBytes>=0x7fffff00 ){ /* The 0x7ffff00 limit term is explained in comments on sqlite3Malloc() */ return 0; } nOld = sqlite3MallocSize(pOld); nNew = sqlite3GlobalConfig.m.xRoundup(nBytes); if( nOld==nNew ){ pNew = pOld; }else if( sqlite3GlobalConfig.bMemstat ){ sqlite3_mutex_enter(mem0.mutex); sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, nBytes); if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)+nNew-nOld >= mem0.alarmThreshold ){ sqlite3MallocAlarm(nNew-nOld); } pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); if( pNew==0 && mem0.alarmCallback ){ sqlite3MallocAlarm(nBytes); pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); } if( pNew ){ nNew = sqlite3MallocSize(pNew); sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, nNew-nOld); } sqlite3_mutex_leave(mem0.mutex); }else{ pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); } return pNew; } /* ** The public interface to sqlite3Realloc. Make sure that the memory ** subsystem is initialized prior to invoking sqliteRealloc. |
︙ | ︙ |
Changes to src/mem0.c.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ************************************************************************* ** ** This file contains a no-op memory allocation drivers for use when ** SQLITE_ZERO_MALLOC is defined. The allocation drivers implemented ** here always fail. SQLite will not operate with these drivers. These ** are merely placeholders. Real drivers must be substituted using ** sqlite3_config() before SQLite will operate. | < < | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ************************************************************************* ** ** This file contains a no-op memory allocation drivers for use when ** SQLITE_ZERO_MALLOC is defined. The allocation drivers implemented ** here always fail. SQLite will not operate with these drivers. These ** are merely placeholders. Real drivers must be substituted using ** sqlite3_config() before SQLite will operate. */ #include "sqliteInt.h" /* ** This version of the memory allocator is the default. It is ** used when no other memory allocator is specified using compile-time ** macros. |
︙ | ︙ |
Changes to src/mem1.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 | ** ** This file contains low-level memory allocation drivers for when ** SQLite will use the standard C-library malloc/realloc/free interface ** to obtain the memory it needs. ** ** This file contains implementations of the low-level memory allocation ** routines specified in the sqlite3_mem_methods object. | < < | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ** ** This file contains low-level memory allocation drivers for when ** SQLite will use the standard C-library malloc/realloc/free interface ** to obtain the memory it needs. ** ** This file contains implementations of the low-level memory allocation ** routines specified in the sqlite3_mem_methods object. */ #include "sqliteInt.h" /* ** This version of the memory allocator is the default. It is ** used when no other memory allocator is specified using compile-time ** macros. |
︙ | ︙ |
Changes to src/mem2.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** SQLite will use the standard C-library malloc/realloc/free interface ** to obtain the memory it needs while adding lots of additional debugging ** information to each allocation in order to help detect and fix memory ** leaks and memory usage errors. ** ** This file contains implementations of the low-level memory allocation ** routines specified in the sqlite3_mem_methods object. | < < | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | ** SQLite will use the standard C-library malloc/realloc/free interface ** to obtain the memory it needs while adding lots of additional debugging ** information to each allocation in order to help detect and fix memory ** leaks and memory usage errors. ** ** This file contains implementations of the low-level memory allocation ** routines specified in the sqlite3_mem_methods object. */ #include "sqliteInt.h" /* ** This version of the memory allocator is used only if the ** SQLITE_MEMDEBUG macro is defined */ |
︙ | ︙ |
Changes to src/mem3.c.
︙ | ︙ | |||
18 19 20 21 22 23 24 | ** are made and returned by the xMalloc() and xRealloc() ** implementations. Once sqlite3_initialize() has been called, ** the amount of memory available to SQLite is fixed and cannot ** be changed. ** ** This version of the memory allocation subsystem is included ** in the build only if SQLITE_ENABLE_MEMSYS3 is defined. | < < | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | ** are made and returned by the xMalloc() and xRealloc() ** implementations. Once sqlite3_initialize() has been called, ** the amount of memory available to SQLite is fixed and cannot ** be changed. ** ** This version of the memory allocation subsystem is included ** in the build only if SQLITE_ENABLE_MEMSYS3 is defined. */ #include "sqliteInt.h" /* ** This version of the memory allocator is only built into the library ** SQLITE_ENABLE_MEMSYS3 is defined. Defining this symbol does not ** mean that the library will use a memory-pool by default, just that |
︙ | ︙ | |||
574 575 576 577 578 579 580 581 582 583 584 585 586 587 | } /* ** Deinitialize this module. */ static void memsys3Shutdown(void *NotUsed){ UNUSED_PARAMETER(NotUsed); return; } /* ** Open the file indicated and write a log of all unfreed memory | > | 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 | } /* ** Deinitialize this module. */ static void memsys3Shutdown(void *NotUsed){ UNUSED_PARAMETER(NotUsed); mem3.mutex = 0; return; } /* ** Open the file indicated and write a log of all unfreed memory |
︙ | ︙ |
Changes to src/mem5.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the C functions that implement a memory ** allocation subsystem for use by SQLite. ** ** This version of the memory allocation subsystem omits all | | | > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | > > | > > > > > > > | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 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 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the C functions that implement a memory ** allocation subsystem for use by SQLite. ** ** This version of the memory allocation subsystem omits all ** use of malloc(). The application gives SQLite a block of memory ** before calling sqlite3_initialize() from which allocations ** are made and returned by the xMalloc() and xRealloc() ** implementations. Once sqlite3_initialize() has been called, ** the amount of memory available to SQLite is fixed and cannot ** be changed. ** ** This version of the memory allocation subsystem is included ** in the build only if SQLITE_ENABLE_MEMSYS5 is defined. ** ** This memory allocator uses the following algorithm: ** ** 1. All memory allocations sizes are rounded up to a power of 2. ** ** 2. If two adjacent free blocks are the halves of a larger block, ** then the two blocks are coalesed into the single larger block. ** ** 3. New memory is allocated from the first available free block. ** ** This algorithm is described in: J. M. Robson. "Bounds for Some Functions ** Concerning Dynamic Storage Allocation". Journal of the Association for ** Computing Machinery, Volume 21, Number 8, July 1974, pages 491-499. ** ** Let n be the size of the largest allocation divided by the minimum ** allocation size (after rounding all sizes up to a power of 2.) Let M ** be the maximum amount of memory ever outstanding at one time. Let ** N be the total amount of memory available for allocation. Robson ** proved that this memory allocator will never breakdown due to ** fragmentation as long as the following constraint holds: ** ** N >= M*(1 + log2(n)/2) - n + 1 ** ** The sqlite3_status() logic tracks the maximum values of n and M so ** that an application can, at any time, verify this constraint. */ #include "sqliteInt.h" /* ** This version of the memory allocator is used only when ** SQLITE_ENABLE_MEMSYS5 is defined. */ #ifdef SQLITE_ENABLE_MEMSYS5 /* ** A minimum allocation is an instance of the following structure. ** Larger allocations are an array of these structures where the ** size of the array is a power of 2. ** ** The size of this object must be a power of two. That fact is ** verified in memsys5Init(). */ typedef struct Mem5Link Mem5Link; struct Mem5Link { int next; /* Index of next free chunk */ int prev; /* Index of previous free chunk */ }; /* ** Maximum size of any allocation is ((1<<LOGMAX)*mem5.szAtom). Since ** mem5.szAtom is always at least 8 and 32-bit integers are used, ** it is not actually possible to reach this limit. */ #define LOGMAX 30 /* ** Masks used for mem5.aCtrl[] elements. */ #define CTRL_LOGSIZE 0x1f /* Log2 Size of this block */ #define CTRL_FREE 0x20 /* True if not checked out */ /* ** All of the static variables used by this module are collected ** into a single structure named "mem5". This is to keep the ** static variables organized and to reduce namespace pollution ** when this module is combined with other in the amalgamation. */ static SQLITE_WSD struct Mem5Global { /* ** Memory available for allocation */ int szAtom; /* Smallest possible allocation in bytes */ int nBlock; /* Number of szAtom sized blocks in zPool */ u8 *zPool; /* Memory available to be allocated */ /* ** Mutex to control access to the memory allocation subsystem. */ sqlite3_mutex *mutex; /* ** Performance statistics */ u64 nAlloc; /* Total number of calls to malloc */ u64 totalAlloc; /* Total of all malloc calls - includes internal frag */ u64 totalExcess; /* Total internal fragmentation */ u32 currentOut; /* Current checkout, including internal fragmentation */ u32 currentCount; /* Current number of distinct checkouts */ u32 maxOut; /* Maximum instantaneous currentOut */ u32 maxCount; /* Maximum instantaneous currentCount */ u32 maxRequest; /* Largest allocation (exclusive of internal frag) */ /* ** Lists of free blocks. aiFreelist[0] is a list of free blocks of ** size mem5.szAtom. aiFreelist[1] holds blocks of size szAtom*2. ** and so forth. */ int aiFreelist[LOGMAX+1]; /* ** Space for tracking which blocks are checked out and the size ** of each block. One byte per block. */ u8 *aCtrl; } mem5 = { 0 }; /* ** Access the static variable through a macro for SQLITE_OMIT_WSD */ #define mem5 GLOBAL(struct Mem5Global, mem5) /* ** Assuming mem5.zPool is divided up into an array of Mem5Link ** structures, return a pointer to the idx-th such lik. */ #define MEM5LINK(idx) ((Mem5Link *)(&mem5.zPool[(idx)*mem5.szAtom])) /* ** Unlink the chunk at mem5.aPool[i] from list it is currently ** on. It should be found on mem5.aiFreelist[iLogsize]. */ static void memsys5Unlink(int i, int iLogsize){ int next, prev; |
︙ | ︙ | |||
149 150 151 152 153 154 155 | /* ** If the STATIC_MEM mutex is not already held, obtain it now. The mutex ** will already be held (obtained by code in malloc.c) if ** sqlite3GlobalConfig.bMemStat is true. */ static void memsys5Enter(void){ | < < < | | | 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 | /* ** If the STATIC_MEM mutex is not already held, obtain it now. The mutex ** will already be held (obtained by code in malloc.c) if ** sqlite3GlobalConfig.bMemStat is true. */ static void memsys5Enter(void){ sqlite3_mutex_enter(mem5.mutex); } static void memsys5Leave(void){ sqlite3_mutex_leave(mem5.mutex); } /* ** Return the size of an outstanding allocation, in bytes. The ** size returned omits the 8-byte header overhead. This only ** works for chunks that are currently checked out. */ static int memsys5Size(void *p){ int iSize = 0; if( p ){ int i = ((u8 *)p-mem5.zPool)/mem5.szAtom; assert( i>=0 && i<mem5.nBlock ); iSize = mem5.szAtom * (1 << (mem5.aCtrl[i]&CTRL_LOGSIZE)); } return iSize; } /* ** Find the first entry on the freelist iLogsize. Unlink that ** entry and return its index. |
︙ | ︙ | |||
194 195 196 197 198 199 200 | } memsys5Unlink(iFirst, iLogsize); return iFirst; } /* ** Return a block of memory of at least nBytes in size. | | > > > > > > > > > > > > > > > > | | 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 | } memsys5Unlink(iFirst, iLogsize); return iFirst; } /* ** Return a block of memory of at least nBytes in size. ** Return NULL if unable. Return NULL if nBytes==0. ** ** The caller guarantees that nByte positive. ** ** The caller has obtained a mutex prior to invoking this ** routine so there is never any chance that two or more ** threads can be in this routine at the same time. */ static void *memsys5MallocUnsafe(int nByte){ int i; /* Index of a mem5.aPool[] slot */ int iBin; /* Index into mem5.aiFreelist[] */ int iFullSz; /* Size of allocation rounded up to power of 2 */ int iLogsize; /* Log2 of iFullSz/POW2_MIN */ /* nByte must be a positive */ assert( nByte>0 ); /* Keep track of the maximum allocation request. Even unfulfilled ** requests are counted */ if( (u32)nByte>mem5.maxRequest ){ mem5.maxRequest = nByte; } /* Abort if the requested allocation size is larger than the largest ** power of two that we can represent using 32-bit signed integers. */ if( nByte > 0x40000000 ){ return 0; } /* Round nByte up to the next valid power of two */ for(iFullSz=mem5.szAtom, iLogsize=0; iFullSz<nByte; iFullSz *= 2, iLogsize++){} /* Make sure mem5.aiFreelist[iLogsize] contains at least one free ** block. If not, then split a block of the next larger power of ** two in order to create a new free block of size iLogsize. */ for(iBin=iLogsize; mem5.aiFreelist[iBin]<0 && iBin<=LOGMAX; iBin++){} if( iBin>LOGMAX ) return 0; |
︙ | ︙ | |||
238 239 240 241 242 243 244 | mem5.totalExcess += iFullSz - nByte; mem5.currentCount++; mem5.currentOut += iFullSz; if( mem5.maxCount<mem5.currentCount ) mem5.maxCount = mem5.currentCount; if( mem5.maxOut<mem5.currentOut ) mem5.maxOut = mem5.currentOut; /* Return a pointer to the allocated memory. */ | | | | | | | | | | 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 | mem5.totalExcess += iFullSz - nByte; mem5.currentCount++; mem5.currentOut += iFullSz; if( mem5.maxCount<mem5.currentCount ) mem5.maxCount = mem5.currentCount; if( mem5.maxOut<mem5.currentOut ) mem5.maxOut = mem5.currentOut; /* Return a pointer to the allocated memory. */ return (void*)&mem5.zPool[i*mem5.szAtom]; } /* ** Free an outstanding memory allocation. */ static void memsys5FreeUnsafe(void *pOld){ u32 size, iLogsize; int iBlock; /* Set iBlock to the index of the block pointed to by pOld in ** the array of mem5.szAtom byte blocks pointed to by mem5.zPool. */ iBlock = ((u8 *)pOld-mem5.zPool)/mem5.szAtom; /* Check that the pointer pOld points to a valid, non-free block. */ assert( iBlock>=0 && iBlock<mem5.nBlock ); assert( ((u8 *)pOld-mem5.zPool)%mem5.szAtom==0 ); assert( (mem5.aCtrl[iBlock] & CTRL_FREE)==0 ); iLogsize = mem5.aCtrl[iBlock] & CTRL_LOGSIZE; size = 1<<iLogsize; assert( iBlock+size-1<(u32)mem5.nBlock ); mem5.aCtrl[iBlock] |= CTRL_FREE; mem5.aCtrl[iBlock+size-1] |= CTRL_FREE; assert( mem5.currentCount>0 ); assert( mem5.currentOut>=(size*mem5.szAtom) ); mem5.currentCount--; mem5.currentOut -= size*mem5.szAtom; assert( mem5.currentOut>0 || mem5.currentCount==0 ); assert( mem5.currentCount>0 || mem5.currentOut==0 ); mem5.aCtrl[iBlock] = CTRL_FREE | iLogsize; while( ALWAYS(iLogsize<LOGMAX) ){ int iBuddy; if( (iBlock>>iLogsize) & 1 ){ iBuddy = iBlock - size; }else{ iBuddy = iBlock + size; } assert( iBuddy>=0 ); |
︙ | ︙ | |||
312 313 314 315 316 317 318 319 320 | memsys5Leave(); } return (void*)p; } /* ** Free memory. */ static void memsys5Free(void *pPrior){ | > > > < | < < | > > > > > > > > > | > | < | < | > > > > > > > | > > > > > > > > > > | > > > | | | | | > | | > > > > | > > > | | | | | > > > > > > > < | | < < < > | 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 | memsys5Leave(); } return (void*)p; } /* ** Free memory. ** ** The outer layer memory allocator prevents this routine from ** being called with pPrior==0. */ static void memsys5Free(void *pPrior){ assert( pPrior!=0 ); memsys5Enter(); memsys5FreeUnsafe(pPrior); memsys5Leave(); } /* ** Change the size of an existing memory allocation. ** ** The outer layer memory allocator prevents this routine from ** being called with pPrior==0. ** ** nBytes is always a value obtained from a prior call to ** memsys5Round(). Hence nBytes is always a non-negative power ** of two. If nBytes==0 that means that an oversize allocation ** (an allocation larger than 0x40000000) was requested and this ** routine should return 0 without freeing pPrior. */ static void *memsys5Realloc(void *pPrior, int nBytes){ int nOld; void *p; assert( pPrior!=0 ); assert( (nBytes&(nBytes-1))==0 ); assert( nBytes>=0 ); if( nBytes==0 ){ return 0; } nOld = memsys5Size(pPrior); if( nBytes<=nOld ){ return pPrior; } memsys5Enter(); p = memsys5MallocUnsafe(nBytes); if( p ){ memcpy(p, pPrior, nOld); memsys5FreeUnsafe(pPrior); } memsys5Leave(); return p; } /* ** Round up a request size to the next valid allocation size. If ** the allocation is too large to be handled by this allocation system, ** return 0. ** ** 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 ** memsys5Log(2) -> 1 ** memsys5Log(4) -> 2 ** memsys5Log(5) -> 3 ** memsys5Log(8) -> 3 ** memsys5Log(9) -> 4 */ static int memsys5Log(int iValue){ int iLog; for(iLog=0; (1<<iLog)<iValue; iLog++); return iLog; } /* ** Initialize the memory allocator. ** ** This routine is not threadsafe. The caller must be holding a mutex ** to prevent multiple threads from entering at the same time. */ static int memsys5Init(void *NotUsed){ int ii; /* Loop counter */ int nByte; /* Number of bytes of memory available to this allocator */ u8 *zByte; /* Memory usable by this allocator */ int nMinLog; /* Log base 2 of minimum allocation size in bytes */ int iOffset; /* An offset into mem5.aCtrl[] */ UNUSED_PARAMETER(NotUsed); /* For the purposes of this routine, disable the mutex */ mem5.mutex = 0; /* The size of a Mem5Link object must be a power of two. Verify that ** this is case. */ assert( (sizeof(Mem5Link)&(sizeof(Mem5Link)-1))==0 ); nByte = sqlite3GlobalConfig.nHeap; zByte = (u8*)sqlite3GlobalConfig.pHeap; assert( zByte!=0 ); /* sqlite3_config() does not allow otherwise */ nMinLog = memsys5Log(sqlite3GlobalConfig.mnReq); mem5.szAtom = (1<<nMinLog); while( (int)sizeof(Mem5Link)>mem5.szAtom ){ mem5.szAtom = mem5.szAtom << 1; } mem5.nBlock = (nByte / (mem5.szAtom+sizeof(u8))); mem5.zPool = zByte; mem5.aCtrl = (u8 *)&mem5.zPool[mem5.nBlock*mem5.szAtom]; for(ii=0; ii<=LOGMAX; ii++){ mem5.aiFreelist[ii] = -1; } iOffset = 0; for(ii=LOGMAX; ii>=0; ii--){ int nAlloc = (1<<ii); if( (iOffset+nAlloc)<=mem5.nBlock ){ mem5.aCtrl[iOffset] = ii | CTRL_FREE; memsys5Link(iOffset, ii); iOffset += nAlloc; } assert((iOffset+nAlloc)>mem5.nBlock); } /* If a mutex is required for normal operation, allocate one */ if( sqlite3GlobalConfig.bMemstat==0 ){ mem5.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); } return SQLITE_OK; } /* ** Deinitialize this module. */ static void memsys5Shutdown(void *NotUsed){ UNUSED_PARAMETER(NotUsed); mem5.mutex = 0; return; } #ifdef SQLITE_TEST /* ** Open the file indicated and write a log of all unfreed memory ** allocations into that log. */ void sqlite3Memsys5Dump(const char *zFilename){ FILE *out; int i, j, n; int nMinLog; if( zFilename==0 || zFilename[0]==0 ){ out = stdout; }else{ out = fopen(zFilename, "w"); if( out==0 ){ fprintf(stderr, "** Unable to output memory debug output log: %s **\n", zFilename); return; } } memsys5Enter(); nMinLog = memsys5Log(mem5.szAtom); for(i=0; i<=LOGMAX && i+nMinLog<32; i++){ for(n=0, j=mem5.aiFreelist[i]; j>=0; j = MEM5LINK(j)->next, n++){} fprintf(out, "freelist items of size %d: %d\n", mem5.szAtom << i, n); } fprintf(out, "mem5.nAlloc = %llu\n", mem5.nAlloc); fprintf(out, "mem5.totalAlloc = %llu\n", mem5.totalAlloc); fprintf(out, "mem5.totalExcess = %llu\n", mem5.totalExcess); fprintf(out, "mem5.currentOut = %u\n", mem5.currentOut); fprintf(out, "mem5.currentCount = %u\n", mem5.currentCount); fprintf(out, "mem5.maxOut = %u\n", mem5.maxOut); fprintf(out, "mem5.maxCount = %u\n", mem5.maxCount); fprintf(out, "mem5.maxRequest = %u\n", mem5.maxRequest); memsys5Leave(); if( out==stdout ){ fflush(stdout); }else{ fclose(out); } } #endif /* ** This routine is the only routine in this file with external ** linkage. It returns a pointer to a static sqlite3_mem_methods ** struct populated with the memsys5 methods. */ const sqlite3_mem_methods *sqlite3MemGetMemsys5(void){ |
︙ | ︙ |
Changes to src/memjournal.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains code use to implement an in-memory rollback journal. ** The in-memory rollback journal is used to journal transactions for ** ":memory:" databases and when the journal_mode=MEMORY pragma is used. | < < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains code use to implement an in-memory rollback journal. ** The in-memory rollback journal is used to journal transactions for ** ":memory:" databases and when the journal_mode=MEMORY pragma is used. */ #include "sqliteInt.h" /* Forward references to internal structures */ typedef struct MemJournal MemJournal; typedef struct FilePoint FilePoint; typedef struct FileChunk FileChunk; |
︙ | ︙ |
Changes to src/mutex.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 15 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the C functions that implement mutexes. ** ** This file contains code that is common across all mutex implementations. | > > < < > > > > > > > | < < < < < < | | | < < | < | < | < | < | < < < | | | > > > > > > > > > | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the C functions that implement mutexes. ** ** This file contains code that is common across all mutex implementations. */ #include "sqliteInt.h" #if defined(SQLITE_DEBUG) && !defined(SQLITE_MUTEX_OMIT) /* ** For debugging purposes, record when the mutex subsystem is initialized ** and uninitialized so that we can assert() if there is an attempt to ** allocate a mutex while the system is uninitialized. */ static SQLITE_WSD int mutexIsInit = 0; #endif /* SQLITE_DEBUG */ #ifndef SQLITE_MUTEX_OMIT /* ** Initialize the mutex system. */ int sqlite3MutexInit(void){ int rc = SQLITE_OK; if( sqlite3GlobalConfig.bCoreMutex ){ if( !sqlite3GlobalConfig.mutex.xMutexAlloc ){ /* If the xMutexAlloc method has not been set, then the user did not ** install a mutex implementation via sqlite3_config() prior to ** sqlite3_initialize() being called. This block copies pointers to ** the default implementation into the sqlite3GlobalConfig structure. */ sqlite3_mutex_methods *pFrom = sqlite3DefaultMutex(); sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex; memcpy(pTo, pFrom, offsetof(sqlite3_mutex_methods, xMutexAlloc)); memcpy(&pTo->xMutexFree, &pFrom->xMutexFree, sizeof(*pTo) - offsetof(sqlite3_mutex_methods, xMutexFree)); pTo->xMutexAlloc = pFrom->xMutexAlloc; } 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(). */ int sqlite3MutexEnd(void){ int rc = SQLITE_OK; if( sqlite3GlobalConfig.mutex.xMutexEnd ){ rc = sqlite3GlobalConfig.mutex.xMutexEnd(); } #ifdef SQLITE_DEBUG GLOBAL(int, mutexIsInit) = 0; #endif return rc; } /* ** Retrieve a pointer to a static mutex or allocate a new dynamic one. */ sqlite3_mutex *sqlite3_mutex_alloc(int id){ #ifndef SQLITE_OMIT_AUTOINIT if( sqlite3_initialize() ) return 0; #endif return sqlite3GlobalConfig.mutex.xMutexAlloc(id); } sqlite3_mutex *sqlite3MutexAlloc(int id){ if( !sqlite3GlobalConfig.bCoreMutex ){ return 0; } assert( GLOBAL(int, mutexIsInit) ); return sqlite3GlobalConfig.mutex.xMutexAlloc(id); } /* ** Free a dynamic mutex. */ void sqlite3_mutex_free(sqlite3_mutex *p){ |
︙ | ︙ | |||
142 143 144 145 146 147 148 | return p==0 || sqlite3GlobalConfig.mutex.xMutexHeld(p); } int sqlite3_mutex_notheld(sqlite3_mutex *p){ return p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld(p); } #endif | | | 143 144 145 146 147 148 149 150 | return p==0 || sqlite3GlobalConfig.mutex.xMutexHeld(p); } int sqlite3_mutex_notheld(sqlite3_mutex *p){ return p==0 || sqlite3GlobalConfig.mutex.xMutexNotheld(p); } #endif #endif /* SQLITE_MUTEX_OMIT */ |
Changes to src/mutex.h.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** The sqliteInt.h header #includes this file so that it is available ** to all source files. We break it out in an effort to keep the code ** better organized. ** ** NOTE: source files should *not* #include this header file directly. ** Source files should #include the sqliteInt.h file and let that file ** include this one indirectly. | < < | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | ** The sqliteInt.h header #includes this file so that it is available ** to all source files. We break it out in an effort to keep the code ** better organized. ** ** NOTE: source files should *not* #include this header file directly. ** Source files should #include the sqliteInt.h file and let that file ** include this one indirectly. */ /* ** Figure out what version of the code to use. The choices are ** ** SQLITE_MUTEX_OMIT No mutex logic. Not even stubs. The |
︙ | ︙ | |||
66 67 68 69 70 71 72 | #define sqlite3_mutex_try(X) SQLITE_OK #define sqlite3_mutex_leave(X) #define sqlite3_mutex_held(X) 1 #define sqlite3_mutex_notheld(X) 1 #define sqlite3MutexAlloc(X) ((sqlite3_mutex*)8) #define sqlite3MutexInit() SQLITE_OK #define sqlite3MutexEnd() | | | 64 65 66 67 68 69 70 71 | #define sqlite3_mutex_try(X) SQLITE_OK #define sqlite3_mutex_leave(X) #define sqlite3_mutex_held(X) 1 #define sqlite3_mutex_notheld(X) 1 #define sqlite3MutexAlloc(X) ((sqlite3_mutex*)8) #define sqlite3MutexInit() SQLITE_OK #define sqlite3MutexEnd() #endif /* defined(SQLITE_MUTEX_OMIT) */ |
Changes to src/mutex_noop.c.
︙ | ︙ | |||
20 21 22 23 24 25 26 | ** sqlite3_config(SQLITE_CONFIG_MUTEX,...) ** ** interface. ** ** If compiled with SQLITE_DEBUG, then additional logic is inserted ** that does error checking on mutexes to make sure they are being ** called correctly. | < < | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | ** sqlite3_config(SQLITE_CONFIG_MUTEX,...) ** ** interface. ** ** If compiled with SQLITE_DEBUG, then additional logic is inserted ** that does error checking on mutexes to make sure they are being ** called correctly. */ #include "sqliteInt.h" #if defined(SQLITE_MUTEX_NOOP) && !defined(SQLITE_DEBUG) /* ** Stub routines for all mutex methods. |
︙ | ︙ |
Changes to src/mutex_os2.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 2007 August 28 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the C functions that implement mutexes for OS/2 | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2007 August 28 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the C functions that implement mutexes for OS/2 */ #include "sqliteInt.h" /* ** The code in this file is only used if SQLITE_MUTEX_OS2 is defined. ** See the mutex.h file for details. */ |
︙ | ︙ |
Changes to src/mutex_unix.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 2007 August 28 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the C functions that implement mutexes for pthreads | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2007 August 28 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the C functions that implement mutexes for pthreads */ #include "sqliteInt.h" /* ** The code in this file is only used if we are compiling threadsafe ** under unix with pthreads. ** |
︙ | ︙ | |||
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | ** <li> SQLITE_MUTEX_FAST ** <li> SQLITE_MUTEX_RECURSIVE ** <li> SQLITE_MUTEX_STATIC_MASTER ** <li> SQLITE_MUTEX_STATIC_MEM ** <li> SQLITE_MUTEX_STATIC_MEM2 ** <li> SQLITE_MUTEX_STATIC_PRNG ** <li> SQLITE_MUTEX_STATIC_LRU ** </ul> ** ** The first two constants cause sqlite3_mutex_alloc() to create ** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE ** is used but not necessarily so when SQLITE_MUTEX_FAST is used. ** The mutex implementation does not need to make a distinction ** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does ** not want to. But SQLite will only request a recursive mutex in ** cases where it really needs one. If a faster non-recursive mutex ** implementation is available on the host platform, the mutex subsystem ** might return such a mutex in response to SQLITE_MUTEX_FAST. ** ** The other allowed parameters to sqlite3_mutex_alloc() each return | > | | 85 86 87 88 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 | ** <li> SQLITE_MUTEX_FAST ** <li> SQLITE_MUTEX_RECURSIVE ** <li> SQLITE_MUTEX_STATIC_MASTER ** <li> SQLITE_MUTEX_STATIC_MEM ** <li> SQLITE_MUTEX_STATIC_MEM2 ** <li> SQLITE_MUTEX_STATIC_PRNG ** <li> SQLITE_MUTEX_STATIC_LRU ** <li> SQLITE_MUTEX_STATIC_LRU2 ** </ul> ** ** The first two constants cause sqlite3_mutex_alloc() to create ** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE ** is used but not necessarily so when SQLITE_MUTEX_FAST is used. ** The mutex implementation does not need to make a distinction ** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does ** not want to. But SQLite will only request a recursive mutex in ** cases where it really needs one. If a faster non-recursive mutex ** implementation is available on the host platform, the mutex subsystem ** might return such a mutex in response to SQLITE_MUTEX_FAST. ** ** The other allowed parameters to sqlite3_mutex_alloc() each return ** a pointer to a static preexisting mutex. Six static mutexes are ** used by the current version of SQLite. Future versions of SQLite ** may add additional static mutexes. Static mutexes are for internal ** use by SQLite only. Applications that use SQLite mutexes should ** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or ** SQLITE_MUTEX_RECURSIVE. ** ** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST |
︙ | ︙ |
Changes to src/mutex_w32.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 2007 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. ** ************************************************************************* ** This file contains the C functions that implement mutexes for win32 | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2007 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. ** ************************************************************************* ** This file contains the C functions that implement mutexes for win32 */ #include "sqliteInt.h" /* ** The code in this file is only used if we are compiling multithreaded ** on a win32 system. */ |
︙ | ︙ | |||
89 90 91 92 93 94 95 | ** processing, the "interlocked" magic is probably not ** strictly necessary. */ static long winMutex_lock = 0; static int winMutexInit(void){ /* The first to increment to 1 does actual initialization */ | | | > | | | | | | | > > > | | 87 88 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 | ** processing, the "interlocked" magic is probably not ** strictly necessary. */ static long winMutex_lock = 0; static int winMutexInit(void){ /* The first to increment to 1 does actual initialization */ if( InterlockedCompareExchange(&winMutex_lock, 1, 0)==0 ){ int i; for(i=0; i<ArraySize(winMutex_staticMutexes); i++){ InitializeCriticalSection(&winMutex_staticMutexes[i].mutex); } winMutex_isInit = 1; }else{ /* Someone else is in the process of initing the static mutexes */ while( !winMutex_isInit ){ Sleep(1); } } return SQLITE_OK; } static int winMutexEnd(void){ /* The first to decrement to 0 does actual shutdown ** (which should be the last to shutdown.) */ if( InterlockedCompareExchange(&winMutex_lock, 0, 1)==1 ){ if( winMutex_isInit==1 ){ int i; for(i=0; i<ArraySize(winMutex_staticMutexes); i++){ DeleteCriticalSection(&winMutex_staticMutexes[i].mutex); } winMutex_isInit = 0; } } return SQLITE_OK; } /* ** The sqlite3_mutex_alloc() routine allocates a new ** mutex and returns a pointer to it. If it returns NULL ** 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_MEM2 ** <li> SQLITE_MUTEX_STATIC_PRNG ** <li> SQLITE_MUTEX_STATIC_LRU ** <li> SQLITE_MUTEX_STATIC_LRU2 ** </ul> ** ** The first two constants cause sqlite3_mutex_alloc() to create ** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE ** is used but not necessarily so when SQLITE_MUTEX_FAST is used. ** The mutex implementation does not need to make a distinction ** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does ** not want to. But SQLite will only request a recursive mutex in ** cases where it really needs one. If a faster non-recursive mutex ** implementation is available on the host platform, the mutex subsystem ** might return such a mutex in response to SQLITE_MUTEX_FAST. ** ** The other allowed parameters to sqlite3_mutex_alloc() each return ** a pointer to a static preexisting mutex. Six static mutexes are ** used by the current version of SQLite. Future versions of SQLite ** may add additional static mutexes. Static mutexes are for internal ** use by SQLite only. Applications that use SQLite mutexes should ** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or ** SQLITE_MUTEX_RECURSIVE. ** ** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST |
︙ | ︙ | |||
173 174 175 176 177 178 179 | InitializeCriticalSection(&p->mutex); } break; } default: { assert( winMutex_isInit==1 ); assert( iType-2 >= 0 ); | | | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | InitializeCriticalSection(&p->mutex); } break; } default: { assert( winMutex_isInit==1 ); assert( iType-2 >= 0 ); assert( iType-2 < ArraySize(winMutex_staticMutexes) ); p = &winMutex_staticMutexes[iType-2]; p->id = iType; break; } } return p; } |
︙ | ︙ |
Changes to src/notify.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 the implementation of the sqlite3_unlock_notify() ** API method and its associated functionality. | < < | 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. ** ************************************************************************* ** ** This file contains the implementation of the sqlite3_unlock_notify() ** API method and its associated functionality. */ #include "sqliteInt.h" #include "btreeInt.h" /* Omit this entire file if SQLITE_ENABLE_UNLOCK_NOTIFY is not defined. */ #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY |
︙ | ︙ |
Changes to src/os.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 OS interface code that is common to all ** architectures. | < < | 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. ** ****************************************************************************** ** ** This file contains OS interface code that is common to all ** architectures. */ #define _SQLITE_OS_C_ 1 #include "sqliteInt.h" #undef _SQLITE_OS_C_ /* ** The default SQLite sqlite3_vfs implementations do not allocate |
︙ | ︙ | |||
33 34 35 36 37 38 39 | ** sqlite3OsRead() ** sqlite3OsWrite() ** sqlite3OsSync() ** sqlite3OsLock() ** */ #if defined(SQLITE_TEST) && (SQLITE_OS_WIN==0) | | | | | | | | | | | | | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | ** sqlite3OsRead() ** sqlite3OsWrite() ** sqlite3OsSync() ** sqlite3OsLock() ** */ #if defined(SQLITE_TEST) && (SQLITE_OS_WIN==0) #define DO_OS_MALLOC_TEST(x) if (!x || !sqlite3IsMemJournal(x)) { \ void *pTstAlloc = sqlite3Malloc(10); \ if (!pTstAlloc) return SQLITE_IOERR_NOMEM; \ sqlite3_free(pTstAlloc); \ } #else #define DO_OS_MALLOC_TEST(x) #endif /* ** The following routines are convenience wrappers around methods ** of the sqlite3_file object. This is mostly just syntactic sugar. All ** of this would be completely automatic if SQLite were coded using ** C++ instead of plain old C. */ int sqlite3OsClose(sqlite3_file *pId){ int rc = SQLITE_OK; if( pId->pMethods ){ rc = pId->pMethods->xClose(pId); pId->pMethods = 0; } return rc; } int sqlite3OsRead(sqlite3_file *id, void *pBuf, int amt, i64 offset){ DO_OS_MALLOC_TEST(id); return id->pMethods->xRead(id, pBuf, amt, offset); } int sqlite3OsWrite(sqlite3_file *id, const void *pBuf, int amt, i64 offset){ DO_OS_MALLOC_TEST(id); return id->pMethods->xWrite(id, pBuf, amt, offset); } int sqlite3OsTruncate(sqlite3_file *id, i64 size){ return id->pMethods->xTruncate(id, size); } int sqlite3OsSync(sqlite3_file *id, int flags){ DO_OS_MALLOC_TEST(id); return id->pMethods->xSync(id, flags); } 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); } int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){ return id->pMethods->xFileControl(id, op, pArg); } int sqlite3OsSectorSize(sqlite3_file *id){ int (*xSectorSize)(sqlite3_file*) = id->pMethods->xSectorSize; |
︙ | ︙ | |||
109 110 111 112 113 114 115 | sqlite3_vfs *pVfs, const char *zPath, sqlite3_file *pFile, int flags, int *pFlagsOut ){ int rc; | | > > > > | | | 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 | sqlite3_vfs *pVfs, const char *zPath, sqlite3_file *pFile, int flags, int *pFlagsOut ){ int rc; DO_OS_MALLOC_TEST(0); /* 0x7f1f 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 & 0x7f1f, pFlagsOut); assert( rc==SQLITE_OK || pFile->pMethods==0 ); return rc; } int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ return pVfs->xDelete(pVfs, zPath, dirSync); } int sqlite3OsAccess( sqlite3_vfs *pVfs, const char *zPath, int flags, int *pResOut ){ DO_OS_MALLOC_TEST(0); return pVfs->xAccess(pVfs, zPath, flags, pResOut); } int sqlite3OsFullPathname( sqlite3_vfs *pVfs, const char *zPath, int nPathOut, char *zPathOut |
︙ | ︙ | |||
185 186 187 188 189 190 191 192 193 194 195 196 197 198 | int sqlite3OsCloseFree(sqlite3_file *pFile){ int rc = SQLITE_OK; assert( pFile ); rc = sqlite3OsClose(pFile); sqlite3_free(pFile); return rc; } /* ** The list of all registered VFS implementations. */ static sqlite3_vfs * SQLITE_WSD vfsList = 0; #define vfsList GLOBAL(sqlite3_vfs *, vfsList) | > > > > > > > > > > > > > | 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 | int sqlite3OsCloseFree(sqlite3_file *pFile){ int rc = SQLITE_OK; assert( pFile ); rc = sqlite3OsClose(pFile); sqlite3_free(pFile); return rc; } /* ** This function is a wrapper around the OS specific implementation of ** sqlite3_os_init(). The purpose of the wrapper is to provide the ** ability to simulate a malloc failure, so that the handling of an ** error in sqlite3_os_init() by the upper layers can be tested. */ int sqlite3OsInit(void){ void *p = sqlite3_malloc(10); if( p==0 ) return SQLITE_NOMEM; sqlite3_free(p); return sqlite3_os_init(); } /* ** The list of all registered VFS implementations. */ static sqlite3_vfs * SQLITE_WSD vfsList = 0; #define vfsList GLOBAL(sqlite3_vfs *, vfsList) |
︙ | ︙ |
Changes to src/os.h.
︙ | ︙ | |||
12 13 14 15 16 17 18 | ** ** This header file (together with is companion C source-code file ** "os.c") attempt to abstract the underlying operating system so that ** the SQLite library will work on both POSIX and windows systems. ** ** This header file is #include-ed by sqliteInt.h and thus ends up ** being included by every source file. | < < | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ** ** This header file (together with is companion C source-code file ** "os.c") attempt to abstract the underlying operating system so that ** the SQLite library will work on both POSIX and windows systems. ** ** This header file is #include-ed by sqliteInt.h and thus ends up ** being included by every source file. */ #ifndef _SQLITE_OS_H_ #define _SQLITE_OS_H_ /* ** Figure out if we are dealing with Unix, Windows, or some other ** operating system. After the following block of preprocess macros, |
︙ | ︙ | |||
220 221 222 223 224 225 226 227 228 229 230 231 232 233 | ** */ #define PENDING_BYTE sqlite3PendingByte #define RESERVED_BYTE (PENDING_BYTE+1) #define SHARED_FIRST (PENDING_BYTE+2) #define SHARED_SIZE 510 /* ** Functions for accessing sqlite3_file methods */ int sqlite3OsClose(sqlite3_file*); int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset); int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset); int sqlite3OsTruncate(sqlite3_file*, i64 size); | > > > > > | 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | ** */ #define PENDING_BYTE sqlite3PendingByte #define RESERVED_BYTE (PENDING_BYTE+1) #define SHARED_FIRST (PENDING_BYTE+2) #define SHARED_SIZE 510 /* ** Wrapper around OS specific sqlite3_os_init() function. */ int sqlite3OsInit(void); /* ** Functions for accessing sqlite3_file methods */ int sqlite3OsClose(sqlite3_file*); int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset); int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset); int sqlite3OsTruncate(sqlite3_file*, i64 size); |
︙ | ︙ |
Changes to src/os_common.h.
︙ | ︙ | |||
12 13 14 15 16 17 18 | ** ** This file contains macros and a little bit of code that is common to ** all of the platform-specific files (os_*.c) and is #included into those ** files. ** ** This file should be #included by the os_*.c files only. It is not a ** general purpose header file. | < < | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ** ** This file contains macros and a little bit of code that is common to ** all of the platform-specific files (os_*.c) and is #included into those ** files. ** ** This file should be #included by the os_*.c files only. It is not a ** general purpose header file. */ #ifndef _OS_COMMON_H_ #define _OS_COMMON_H_ /* ** At least two bugs have slipped in because we changed the MEMORY_DEBUG ** macro to SQLITE_DEBUG and some older makefiles have not yet made the |
︙ | ︙ |
Changes to src/os_os2.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2006 Feb 14 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains code that is specific to OS/2. | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* ** 2006 Feb 14 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains code that is specific to OS/2. */ #include "sqliteInt.h" #if SQLITE_OS_OS2 /* |
︙ | ︙ |
Changes to src/os_unix.c.
︙ | ︙ | |||
38 39 40 41 42 43 44 | ** * sqlite3_file methods not associated with locking. ** * Definitions of sqlite3_io_methods objects for all locking ** methods plus "finder" functions for each locking method. ** * sqlite3_vfs method implementations. ** * Locking primitives for the proxy uber-locking-method. (MacOSX only) ** * Definitions of sqlite3_vfs objects for all locking methods ** plus implementations of sqlite3_os_init() and sqlite3_os_end(). | < < | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | ** * sqlite3_file methods not associated with locking. ** * Definitions of sqlite3_io_methods objects for all locking ** methods plus "finder" functions for each locking method. ** * sqlite3_vfs method implementations. ** * Locking primitives for the proxy uber-locking-method. (MacOSX only) ** * Definitions of sqlite3_vfs objects for all locking methods ** plus implementations of sqlite3_os_init() and sqlite3_os_end(). */ #include "sqliteInt.h" #if SQLITE_OS_UNIX /* This file is used on unix only */ /* ** There are various methods for file locking used for concurrency ** control: |
︙ | ︙ | |||
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 | /* ** 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)) /* ** The unixFile structure is subclass of sqlite3_file specific to the unix ** VFS implementations. */ typedef struct unixFile unixFile; struct unixFile { sqlite3_io_methods const *pMethod; /* Always the first entry */ struct unixOpenCnt *pOpen; /* Info about all open fd's on this inode */ struct unixLockInfo *pLock; /* Info about locks on this inode */ int h; /* The file descriptor */ int dirfd; /* File descriptor for the directory */ unsigned char locktype; /* The type of lock held on this fd */ int lastErrno; /* The unix errno from the last I/O error */ void *lockingContext; /* Locking style specific state */ #if SQLITE_ENABLE_LOCKING_STYLE int openFlags; /* The flags specified at open() */ #endif #if SQLITE_THREADSAFE && defined(__linux__) pthread_t tid; /* The thread that "owns" this unixFile */ #endif #if OS_VXWORKS | > > > > > > > > > > > > > > > | 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 | /* ** 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)) /* ** Sometimes, after a file handle is closed by SQLite, the file descriptor ** cannot be closed immediately. In these cases, instances of the following ** structure are used to store the file descriptor while waiting for an ** opportunity to either close or reuse it. */ typedef struct UnixUnusedFd UnixUnusedFd; struct UnixUnusedFd { int fd; /* File descriptor to close */ int flags; /* Flags this file descriptor was opened with */ UnixUnusedFd *pNext; /* Next unused file descriptor on same file */ }; /* ** The unixFile structure is subclass of sqlite3_file specific to the unix ** VFS implementations. */ typedef struct unixFile unixFile; struct unixFile { sqlite3_io_methods const *pMethod; /* Always the first entry */ struct unixOpenCnt *pOpen; /* Info about all open fd's on this inode */ struct unixLockInfo *pLock; /* Info about locks on this inode */ int h; /* The file descriptor */ int dirfd; /* File descriptor for the directory */ unsigned char locktype; /* The type of lock held on this fd */ int lastErrno; /* The unix errno from the last I/O error */ void *lockingContext; /* Locking style specific state */ UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */ int fileFlags; /* Miscellanous flags */ #if SQLITE_ENABLE_LOCKING_STYLE int openFlags; /* The flags specified at open() */ #endif #if SQLITE_THREADSAFE && defined(__linux__) pthread_t tid; /* The thread that "owns" this unixFile */ #endif #if OS_VXWORKS |
︙ | ︙ | |||
200 201 202 203 204 205 206 | ** occur if a file is updated without also updating the transaction ** counter. This test is made to avoid new problems similar to the ** one described by ticket #3584. */ unsigned char transCntrChng; /* True if the transaction counter changed */ unsigned char dbUpdate; /* True if any part of database file changed */ unsigned char inNormalWrite; /* True if in a normal write operation */ | < < < < < > > > > > | 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 | ** occur if a file is updated without also updating the transaction ** counter. This test is made to avoid new problems similar to the ** one described by ticket #3584. */ unsigned char transCntrChng; /* True if the transaction counter changed */ unsigned char dbUpdate; /* True if any part of database file changed */ unsigned char inNormalWrite; /* True if in a normal write operation */ #endif #ifdef SQLITE_TEST /* In test mode, increase the size of this structure a bit so that ** it is larger than the struct CrashFile defined in test6.c. */ char aPadding[32]; #endif }; /* ** The following macros define bits in unixFile.fileFlags */ #define SQLITE_WHOLE_FILE_LOCKING 0x0001 /* Use whole-file locking */ /* ** Include code that is common to all os_*.c files */ #include "os_common.h" /* ** Define various macros that are missing from some systems. |
︙ | ︙ | |||
258 259 260 261 262 263 264 | #define threadid pthread_self() #else #define threadid 0 #endif /* | | > > > > > > > > > > > > > > > > | | | | | | 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 | #define threadid pthread_self() #else #define threadid 0 #endif /* ** Helper functions to obtain and relinquish the global mutex. The ** global mutex is used to protect the unixOpenCnt, unixLockInfo and ** vxworksFileId objects used by this file, all of which may be ** shared by multiple threads. ** ** Function unixMutexHeld() is used to assert() that the global mutex ** is held when required. This function is only used as part of assert() ** statements. e.g. ** ** unixEnterMutex() ** assert( unixMutexHeld() ); ** unixEnterLeave() */ static void unixEnterMutex(void){ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); } static void unixLeaveMutex(void){ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); } #ifdef SQLITE_DEBUG static int unixMutexHeld(void) { return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); } #endif #ifdef SQLITE_DEBUG /* ** Helper function for printing out trace information from debugging ** binaries. This returns the string represetation of the supplied ** integer lock-type. */ static const char *locktypeName(int locktype){ switch( locktype ){ case NO_LOCK: return "NONE"; case SHARED_LOCK: return "SHARED"; case RESERVED_LOCK: return "RESERVED"; case PENDING_LOCK: return "PENDING"; case EXCLUSIVE_LOCK: return "EXCLUSIVE"; } return "ERROR"; } #endif #ifdef SQLITE_LOCK_TRACE /* |
︙ | ︙ | |||
734 735 736 737 738 739 740 | ** The close() system call would only occur when the last database ** using the file closes. */ struct unixOpenCnt { struct unixFileId fileId; /* The lookup key */ int nRef; /* Number of pointers to this structure */ int nLock; /* Number of outstanding locks */ | | < | | 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 | ** The close() system call would only occur when the last database ** using the file closes. */ struct unixOpenCnt { struct unixFileId fileId; /* The lookup key */ int nRef; /* Number of pointers to this structure */ int nLock; /* Number of outstanding locks */ UnixUnusedFd *pUnused; /* Unused file descriptors to close */ #if OS_VXWORKS sem_t *pSem; /* Named POSIX semaphore */ char aSemName[MAX_PATHNAME+2]; /* Name of that semaphore */ #endif struct unixOpenCnt *pNext, *pPrev; /* List of all unixOpenCnt objects */ }; /* ** Lists of all unixLockInfo and unixOpenCnt objects. These used to be hash ** tables. But the number of objects is rarely more than a dozen and |
︙ | ︙ | |||
835 836 837 838 839 840 841 | l.l_whence = SEEK_SET; rc = fcntl(fd_orig, F_SETLK, &l); if( rc!=0 ) return; memset(&d, 0, sizeof(d)); d.fd = fd; d.lock = l; d.lock.l_type = F_WRLCK; | | | > | > > > > | 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 | l.l_whence = SEEK_SET; rc = fcntl(fd_orig, F_SETLK, &l); if( rc!=0 ) return; memset(&d, 0, sizeof(d)); d.fd = fd; d.lock = l; d.lock.l_type = F_WRLCK; if( pthread_create(&t, 0, threadLockingTest, &d)==0 ){ pthread_join(t, 0); } close(fd); if( d.result!=0 ) return; threadsOverrideEachOthersLocks = (d.lock.l_type==F_UNLCK); } #endif /* SQLITE_THREADSAFE && defined(__linux__) */ /* ** Release a unixLockInfo structure previously allocated by findLockInfo(). ** ** The mutex entered using the unixEnterMutex() function must be held ** when this function is called. */ static void releaseLockInfo(struct unixLockInfo *pLock){ assert( unixMutexHeld() ); if( pLock ){ pLock->nRef--; if( pLock->nRef==0 ){ if( pLock->pPrev ){ assert( pLock->pPrev->pNext==pLock ); pLock->pPrev->pNext = pLock->pNext; }else{ |
︙ | ︙ | |||
868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 | sqlite3_free(pLock); } } } /* ** Release a unixOpenCnt structure previously allocated by findLockInfo(). */ static void releaseOpenCnt(struct unixOpenCnt *pOpen){ if( pOpen ){ pOpen->nRef--; if( pOpen->nRef==0 ){ if( pOpen->pPrev ){ assert( pOpen->pPrev->pNext==pOpen ); pOpen->pPrev->pNext = pOpen->pNext; }else{ assert( openList==pOpen ); openList = pOpen->pNext; } if( pOpen->pNext ){ assert( pOpen->pNext->pPrev==pOpen ); pOpen->pNext->pPrev = pOpen->pPrev; } | > > > > > > > | > > > > > > > > > > > > | 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 | sqlite3_free(pLock); } } } /* ** Release a unixOpenCnt structure previously allocated by findLockInfo(). ** ** The mutex entered using the unixEnterMutex() function must be held ** when this function is called. */ static void releaseOpenCnt(struct unixOpenCnt *pOpen){ assert( unixMutexHeld() ); if( pOpen ){ pOpen->nRef--; if( pOpen->nRef==0 ){ if( pOpen->pPrev ){ assert( pOpen->pPrev->pNext==pOpen ); pOpen->pPrev->pNext = pOpen->pNext; }else{ assert( openList==pOpen ); openList = pOpen->pNext; } if( pOpen->pNext ){ assert( pOpen->pNext->pPrev==pOpen ); pOpen->pNext->pPrev = pOpen->pPrev; } #if SQLITE_THREADSAFE && defined(__linux__) assert( !pOpen->pUnused || threadsOverrideEachOthersLocks==0 ); #endif /* If pOpen->pUnused is not null, then memory and file-descriptors ** are leaked. ** ** This will only happen if, under Linuxthreads, the user has opened ** a transaction in one thread, then attempts to close the database ** handle from another thread (without first unlocking the db file). ** This is a misuse. */ sqlite3_free(pOpen); } } } /* ** Given a file descriptor, locate unixLockInfo and unixOpenCnt structures that ** describes that file descriptor. Create new ones if necessary. The ** return values might be uninitialized if an error occurs. ** ** The mutex entered using the unixEnterMutex() function must be held ** when this function is called. ** ** Return an appropriate error code. */ static int findLockInfo( unixFile *pFile, /* Unix file with file desc used in the key */ struct unixLockInfo **ppLock, /* Return the unixLockInfo structure here */ struct unixOpenCnt **ppOpen /* Return the unixOpenCnt structure here */ ){ int rc; /* System call return code */ int fd; /* The file descriptor for pFile */ struct unixLockKey lockKey; /* Lookup key for the unixLockInfo structure */ struct unixFileId fileId; /* Lookup key for the unixOpenCnt struct */ struct stat statbuf; /* Low-level file information */ struct unixLockInfo *pLock = 0;/* Candidate unixLockInfo object */ struct unixOpenCnt *pOpen; /* Candidate unixOpenCnt object */ assert( unixMutexHeld() ); /* Get low-level information about the file that we can used to ** create a unique name for the file. */ fd = pFile->h; rc = fstat(fd, &statbuf); if( rc!=0 ){ |
︙ | ︙ | |||
972 973 974 975 976 977 978 | } if( pLock==0 ){ pLock = sqlite3_malloc( sizeof(*pLock) ); if( pLock==0 ){ rc = SQLITE_NOMEM; goto exit_findlockinfo; } | | | 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 | } if( pLock==0 ){ pLock = sqlite3_malloc( sizeof(*pLock) ); if( pLock==0 ){ rc = SQLITE_NOMEM; goto exit_findlockinfo; } memcpy(&pLock->lockKey,&lockKey,sizeof(lockKey)); pLock->nRef = 1; pLock->cnt = 0; pLock->locktype = 0; pLock->pNext = lockList; pLock->pPrev = 0; if( lockList ) lockList->pPrev = pLock; lockList = pLock; |
︙ | ︙ | |||
997 998 999 1000 1001 1002 1003 1004 1005 | if( pOpen==0 ){ pOpen = sqlite3_malloc( sizeof(*pOpen) ); if( pOpen==0 ){ releaseLockInfo(pLock); rc = SQLITE_NOMEM; goto exit_findlockinfo; } pOpen->fileId = fileId; pOpen->nRef = 1; | > < < < < < < < < | 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 | if( pOpen==0 ){ pOpen = sqlite3_malloc( sizeof(*pOpen) ); if( pOpen==0 ){ releaseLockInfo(pLock); rc = SQLITE_NOMEM; goto exit_findlockinfo; } memset(pOpen, 0, sizeof(*pOpen)); pOpen->fileId = fileId; pOpen->nRef = 1; pOpen->pNext = openList; if( openList ) openList->pPrev = pOpen; openList = pOpen; }else{ pOpen->nRef++; } *ppOpen = pOpen; } exit_findlockinfo: |
︙ | ︙ | |||
1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 | unixLeaveMutex(); OSTRACE4("TEST WR-LOCK %d %d %d\n", pFile->h, rc, reserved); *pResOut = reserved; return rc; } /* ** Lock the file with the lock specified by parameter locktype - one ** of the following: ** ** (1) SHARED_LOCK ** (2) RESERVED_LOCK | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | unixLeaveMutex(); OSTRACE4("TEST WR-LOCK %d %d %d\n", pFile->h, rc, reserved); *pResOut = reserved; return rc; } /* ** Perform a file locking operation on a range of bytes in a file. ** The "op" parameter should be one of F_RDLCK, F_WRLCK, or F_UNLCK. ** Return 0 on success or -1 for failure. On failure, write the error ** code into *pErrcode. ** ** If the SQLITE_WHOLE_FILE_LOCKING bit is clear, then only lock ** the range of bytes on the locking page between SHARED_FIRST and ** SHARED_SIZE. If SQLITE_WHOLE_FILE_LOCKING is set, then lock all ** bytes from 0 up to but not including PENDING_BYTE, and all bytes ** that follow SHARED_FIRST. ** ** In other words, of SQLITE_WHOLE_FILE_LOCKING if false (the historical ** default case) then only lock a small range of bytes from SHARED_FIRST ** through SHARED_FIRST+SHARED_SIZE-1. But if SQLITE_WHOLE_FILE_LOCKING is ** true then lock every byte in the file except for PENDING_BYTE and ** RESERVED_BYTE. ** ** SQLITE_WHOLE_FILE_LOCKING=true overlaps SQLITE_WHOLE_FILE_LOCKING=false ** and so the locking schemes are compatible. One type of lock will ** effectively exclude the other type. The reason for using the ** SQLITE_WHOLE_FILE_LOCKING=true is that by indicating the full range ** of bytes to be read or written, we give hints to NFS to help it ** maintain cache coherency. On the other hand, whole file locking ** is slower, so we don't want to use it except for NFS. */ static int rangeLock(unixFile *pFile, int op, int *pErrcode){ struct flock lock; int rc; lock.l_type = op; lock.l_start = SHARED_FIRST; lock.l_whence = SEEK_SET; if( (pFile->fileFlags & SQLITE_WHOLE_FILE_LOCKING)==0 ){ lock.l_len = SHARED_SIZE; rc = fcntl(pFile->h, F_SETLK, &lock); *pErrcode = errno; }else{ lock.l_len = 0; rc = fcntl(pFile->h, F_SETLK, &lock); *pErrcode = errno; if( NEVER(op==F_UNLCK) || rc!=(-1) ){ lock.l_start = 0; lock.l_len = PENDING_BYTE; rc = fcntl(pFile->h, F_SETLK, &lock); if( ALWAYS(op!=F_UNLCK) && rc==(-1) ){ *pErrcode = errno; lock.l_type = F_UNLCK; lock.l_start = SHARED_FIRST; lock.l_len = 0; fcntl(pFile->h, F_SETLK, &lock); } } } return rc; } /* ** Lock the file with the lock specified by parameter locktype - one ** of the following: ** ** (1) SHARED_LOCK ** (2) RESERVED_LOCK |
︙ | ︙ | |||
1183 1184 1185 1186 1187 1188 1189 | ** locking a random byte from a range, concurrent SHARED locks may exist ** even if the locking primitive used is always a write-lock. */ int rc = SQLITE_OK; unixFile *pFile = (unixFile*)id; struct unixLockInfo *pLock = pFile->pLock; struct flock lock; | | > | > > > | 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 | ** locking a random byte from a range, concurrent SHARED locks may exist ** even if the locking primitive used is always a write-lock. */ int rc = SQLITE_OK; unixFile *pFile = (unixFile*)id; struct unixLockInfo *pLock = pFile->pLock; struct flock lock; int s = 0; int tErrno; assert( pFile ); OSTRACE7("LOCK %d %s was %s(%s,%d) pid=%d\n", pFile->h, locktypeName(locktype), locktypeName(pFile->locktype), locktypeName(pLock->locktype), pLock->cnt , getpid()); /* If there is already a lock of this type or more restrictive on the ** unixFile, do nothing. Don't use the end_lock: exit path, as ** unixEnterMutex() hasn't been called yet. */ if( pFile->locktype>=locktype ){ OSTRACE3("LOCK %d %s ok (already held)\n", pFile->h, locktypeName(locktype)); return SQLITE_OK; } /* Make sure the locking sequence is correct. ** (1) We never move from unlocked to anything higher than shared lock. ** (2) SQLite never explicitly requests a pendig lock. ** (3) A shared lock is always held when a reserve lock is requested. */ assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); assert( locktype!=PENDING_LOCK ); assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); /* This mutex is needed because pFile->pLock is shared across threads */ |
︙ | ︙ | |||
1244 1245 1246 1247 1248 1249 1250 | assert( pLock->cnt>0 ); pFile->locktype = SHARED_LOCK; pLock->cnt++; pFile->pOpen->nLock++; goto end_lock; } | < < < > > | < < < < | | | 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 | assert( pLock->cnt>0 ); pFile->locktype = SHARED_LOCK; pLock->cnt++; pFile->pOpen->nLock++; goto end_lock; } /* 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( locktype==SHARED_LOCK || (locktype==EXCLUSIVE_LOCK && pFile->locktype<PENDING_LOCK) ){ lock.l_type = (locktype==SHARED_LOCK?F_RDLCK:F_WRLCK); lock.l_start = PENDING_BYTE; s = fcntl(pFile->h, F_SETLK, &lock); if( s==(-1) ){ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); if( IS_LOCK_ERROR(rc) ){ pFile->lastErrno = tErrno; } goto end_lock; } } /* If control gets to this point, then actually go ahead and make ** operating system calls for the specified lock. */ if( locktype==SHARED_LOCK ){ assert( pLock->cnt==0 ); assert( pLock->locktype==0 ); /* Now get the read-lock */ s = rangeLock(pFile, F_RDLCK, &tErrno); /* Drop the temporary PENDING lock */ lock.l_start = PENDING_BYTE; lock.l_len = 1L; lock.l_type = F_UNLCK; if( fcntl(pFile->h, F_SETLK, &lock)!=0 ){ if( s != -1 ){ /* This could happen with a network mount */ |
︙ | ︙ | |||
1322 1323 1324 1325 1326 1327 1328 1329 1330 | ** already. */ assert( 0!=pFile->locktype ); lock.l_type = F_WRLCK; switch( locktype ){ case RESERVED_LOCK: lock.l_start = RESERVED_BYTE; break; case EXCLUSIVE_LOCK: | > > < < > < < | 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 | ** already. */ assert( 0!=pFile->locktype ); lock.l_type = F_WRLCK; switch( locktype ){ case RESERVED_LOCK: lock.l_start = RESERVED_BYTE; s = fcntl(pFile->h, F_SETLK, &lock); tErrno = errno; break; case EXCLUSIVE_LOCK: s = rangeLock(pFile, F_WRLCK, &tErrno); break; default: assert(0); } if( s==(-1) ){ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK); if( IS_LOCK_ERROR(rc) ){ pFile->lastErrno = tErrno; } } } |
︙ | ︙ | |||
1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 | end_lock: unixLeaveMutex(); OSTRACE4("LOCK %d %s %s\n", pFile->h, locktypeName(locktype), rc==SQLITE_OK ? "ok" : "failed"); return rc; } /* ** Lower the locking level on file descriptor pFile to locktype. locktype ** must be either NO_LOCK or SHARED_LOCK. ** ** If the locking level of the file descriptor is already at or below ** the requested locking level, this routine is a no-op. */ static int unixUnlock(sqlite3_file *id, int locktype){ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | < | > | 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 | end_lock: unixLeaveMutex(); OSTRACE4("LOCK %d %s %s\n", pFile->h, locktypeName(locktype), rc==SQLITE_OK ? "ok" : "failed"); return rc; } /* ** Close all file descriptors accumuated in the unixOpenCnt->pUnused list. ** If all such file descriptors are closed without error, the list is ** cleared and SQLITE_OK returned. ** ** Otherwise, if an error occurs, then successfully closed file descriptor ** entries are removed from the list, and SQLITE_IOERR_CLOSE returned. ** not deleted and SQLITE_IOERR_CLOSE returned. */ static int closePendingFds(unixFile *pFile){ int rc = SQLITE_OK; struct unixOpenCnt *pOpen = pFile->pOpen; UnixUnusedFd *pError = 0; UnixUnusedFd *p; UnixUnusedFd *pNext; for(p=pOpen->pUnused; p; p=pNext){ pNext = p->pNext; if( close(p->fd) ){ pFile->lastErrno = errno; rc = SQLITE_IOERR_CLOSE; p->pNext = pError; pError = p; }else{ sqlite3_free(p); } } pOpen->pUnused = pError; return rc; } /* ** Add the file descriptor used by file handle pFile to the corresponding ** pUnused list. */ static void setPendingFd(unixFile *pFile){ struct unixOpenCnt *pOpen = pFile->pOpen; UnixUnusedFd *p = pFile->pUnused; p->pNext = pOpen->pUnused; pOpen->pUnused = p; pFile->h = -1; pFile->pUnused = 0; } /* ** Lower the locking level on file descriptor pFile to locktype. locktype ** must be either NO_LOCK or SHARED_LOCK. ** ** If the locking level of the file descriptor is already at or below ** the requested locking level, this routine is a no-op. */ static int unixUnlock(sqlite3_file *id, int locktype){ unixFile *pFile = (unixFile*)id; /* The open file */ struct unixLockInfo *pLock; /* Structure describing current lock state */ struct flock lock; /* Information passed into fcntl() */ int rc = SQLITE_OK; /* Return code from this interface */ int h; /* The underlying file descriptor */ int tErrno; /* Error code from system call errors */ assert( pFile ); OSTRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d\n", pFile->h, locktype, pFile->locktype, pFile->pLock->locktype, pFile->pLock->cnt, getpid()); assert( locktype<=SHARED_LOCK ); if( pFile->locktype<=locktype ){ |
︙ | ︙ | |||
1425 1426 1427 1428 1429 1430 1431 | || pFile->dbUpdate==0 || pFile->transCntrChng==1 ); pFile->inNormalWrite = 0; #endif if( locktype==SHARED_LOCK ){ | < < < < | < | < | | < < < < < < < < < < < < < < < | < < < | | > | 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 | || pFile->dbUpdate==0 || pFile->transCntrChng==1 ); pFile->inNormalWrite = 0; #endif if( locktype==SHARED_LOCK ){ if( rangeLock(pFile, F_RDLCK, &tErrno)==(-1) ){ rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_RDLOCK); if( IS_LOCK_ERROR(rc) ){ pFile->lastErrno = tErrno; } goto end_unlock; } } lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = PENDING_BYTE; lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE ); if( fcntl(h, F_SETLK, &lock)!=(-1) ){ pLock->locktype = SHARED_LOCK; }else{ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); if( IS_LOCK_ERROR(rc) ){ pFile->lastErrno = tErrno; } goto end_unlock; } } if( locktype==NO_LOCK ){ struct unixOpenCnt *pOpen; /* Decrement the shared lock counter. Release the lock using an ** OS call only when all threads in this same process have released ** the lock. */ pLock->cnt--; if( pLock->cnt==0 ){ lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = lock.l_len = 0L; SimulateIOErrorBenign(1); SimulateIOError( h=(-1) ) SimulateIOErrorBenign(0); if( fcntl(h, F_SETLK, &lock)!=(-1) ){ pLock->locktype = NO_LOCK; }else{ tErrno = errno; rc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_UNLOCK); if( IS_LOCK_ERROR(rc) ){ pFile->lastErrno = tErrno; } pLock->locktype = NO_LOCK; pFile->locktype = NO_LOCK; } } /* Decrement the count of locks against this same file. When the ** count reaches zero, close any other file descriptors whose close ** was deferred because of outstanding locks. */ pOpen = pFile->pOpen; pOpen->nLock--; assert( pOpen->nLock>=0 ); if( pOpen->nLock==0 ){ int rc2 = closePendingFds(pFile); if( rc==SQLITE_OK ){ rc = rc2; } } } end_unlock: unixLeaveMutex(); if( rc==SQLITE_OK ) pFile->locktype = locktype; return rc; |
︙ | ︙ | |||
1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 | } vxworksReleaseFileId(pFile->pId); pFile->pId = 0; } #endif OSTRACE2("CLOSE %-3d\n", pFile->h); OpenCounter(-1); memset(pFile, 0, sizeof(unixFile)); } return SQLITE_OK; } /* ** Close a file. */ static int unixClose(sqlite3_file *id){ int rc = SQLITE_OK; if( id ){ unixFile *pFile = (unixFile *)id; unixUnlock(id, NO_LOCK); unixEnterMutex(); if( pFile->pOpen && pFile->pOpen->nLock ){ /* If there are outstanding locks, do not actually close the file just ** yet because that would clear those locks. Instead, add the file | > | | < < < < < < < < | < < | 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 | } vxworksReleaseFileId(pFile->pId); pFile->pId = 0; } #endif OSTRACE2("CLOSE %-3d\n", pFile->h); OpenCounter(-1); sqlite3_free(pFile->pUnused); memset(pFile, 0, sizeof(unixFile)); } return SQLITE_OK; } /* ** Close a file. */ static int unixClose(sqlite3_file *id){ int rc = SQLITE_OK; if( id ){ unixFile *pFile = (unixFile *)id; unixUnlock(id, NO_LOCK); unixEnterMutex(); if( pFile->pOpen && pFile->pOpen->nLock ){ /* If there are outstanding locks, do not actually close the file just ** yet because that would clear those locks. Instead, add the file ** descriptor to pOpen->pUnused list. It will be automatically closed ** when the last lock is cleared. */ setPendingFd(pFile); } releaseLockInfo(pFile->pLock); releaseOpenCnt(pFile->pOpen); rc = closeUnixFile(id); unixLeaveMutex(); } return rc; |
︙ | ︙ | |||
1647 1648 1649 1650 1651 1652 1653 | /******************* End of the no-op lock implementation ********************* ******************************************************************************/ /****************************************************************************** ************************* Begin dot-file Locking ****************************** ** | | | 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 | /******************* End of the no-op lock implementation ********************* ******************************************************************************/ /****************************************************************************** ************************* Begin dot-file Locking ****************************** ** ** The dotfile locking implementation uses the existance of separate lock ** files in order to control access to the database. This works on just ** about every filesystem imaginable. But there are serious downsides: ** ** (1) There is zero concurrency. A single reader blocks all other ** connections from reading or writing the database. ** ** (2) An application crash or power loss can leave stale lock files |
︙ | ︙ | |||
2427 2428 2429 2430 2431 2432 2433 | } } /* If control gets to this point, then actually go ahead and make ** operating system calls for the specified lock. */ if( locktype==SHARED_LOCK ){ | | > | 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 | } } /* If control gets to this point, then actually go ahead and make ** operating system calls for the specified lock. */ if( locktype==SHARED_LOCK ){ int lk, lrc1, lrc2; int lrc1Errno = 0; /* Now get the read-lock SHARED_LOCK */ /* note that the quality of the randomness doesn't matter that much */ lk = random(); context->sharedByte = (lk & 0x7fffffff)%(SHARED_SIZE - 1); lrc1 = afpSetLock(context->dbPath, pFile, SHARED_FIRST+context->sharedByte, 1, 1); |
︙ | ︙ | |||
2559 2560 2561 2562 2563 2564 2565 | } if( rc==SQLITE_OK ){ if( locktype==NO_LOCK ){ struct unixOpenCnt *pOpen = pFile->pOpen; pOpen->nLock--; assert( pOpen->nLock>=0 ); | | < < < < < < < < < < < < | < < | > > < < < < < < < < | < < | 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 | } if( rc==SQLITE_OK ){ if( locktype==NO_LOCK ){ struct unixOpenCnt *pOpen = pFile->pOpen; pOpen->nLock--; assert( pOpen->nLock>=0 ); if( pOpen->nLock==0 ){ rc = closePendingFds(pFile); } } } unixLeaveMutex(); if( rc==SQLITE_OK ){ pFile->locktype = locktype; } return rc; } /* ** Close a file & cleanup AFP specific locking context */ static int afpClose(sqlite3_file *id) { if( id ){ unixFile *pFile = (unixFile*)id; afpUnlock(id, NO_LOCK); unixEnterMutex(); if( pFile->pOpen && pFile->pOpen->nLock ){ /* If there are outstanding locks, do not actually close the file just ** yet because that would clear those locks. Instead, add the file ** descriptor to pOpen->aPending. It will be automatically closed when ** the last lock is cleared. */ setPendingFd(pFile); } releaseOpenCnt(pFile->pOpen); sqlite3_free(pFile->lockingContext); closeUnixFile(id); unixLeaveMutex(); } return SQLITE_OK; |
︙ | ︙ | |||
2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 | */ static int unixRead( sqlite3_file *id, void *pBuf, int amt, sqlite3_int64 offset ){ int got; assert( id ); | > > | | | | > | | | 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 | */ static int unixRead( sqlite3_file *id, void *pBuf, int amt, sqlite3_int64 offset ){ unixFile *pFile = (unixFile *)id; int got; assert( id ); /* If this is a database file (not a journal, master-journal or temp ** file), the bytes in the locking range should never be read or written. */ assert( pFile->pUnused==0 || offset>=PENDING_BYTE+512 || offset+amt<=PENDING_BYTE ); got = seekAndRead(pFile, offset, pBuf, amt); if( got==amt ){ return SQLITE_OK; }else if( got<0 ){ /* lastErrno set by seekAndRead */ return SQLITE_IOERR_READ; }else{ pFile->lastErrno = 0; /* not a system error */ /* Unread parts of the buffer must be zero-filled */ memset(&((char*)pBuf)[got], 0, amt-got); return SQLITE_IOERR_SHORT_READ; } } /* |
︙ | ︙ | |||
2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 | */ static int unixWrite( sqlite3_file *id, const void *pBuf, int amt, sqlite3_int64 offset ){ int wrote = 0; assert( id ); assert( amt>0 ); | > > | | | | > | < | | | 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 | */ static int unixWrite( sqlite3_file *id, const void *pBuf, int amt, 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. */ assert( pFile->pUnused==0 || offset>=PENDING_BYTE+512 || offset+amt<=PENDING_BYTE ); #ifndef NDEBUG /* If we are doing a normal write to a database file (as opposed to ** doing a hot-journal rollback or a write to some file other than a ** normal database file) then record the fact that the database ** has changed. If the transaction counter is modified, record that ** fact too. */ if( pFile->inNormalWrite ){ pFile->dbUpdate = 1; /* The database has been modified */ if( offset<=24 && offset+amt>=27 ){ int rc; char oldCntr[4]; SimulateIOErrorBenign(1); rc = seekAndRead(pFile, 24, oldCntr, 4); SimulateIOErrorBenign(0); if( rc!=4 || memcmp(oldCntr, &((char*)pBuf)[24-offset], 4)!=0 ){ pFile->transCntrChng = 1; /* The transaction counter has changed */ } } } #endif while( amt>0 && (wrote = seekAndWrite(pFile, offset, pBuf, amt))>0 ){ amt -= wrote; offset += wrote; pBuf = &((char*)pBuf)[wrote]; } SimulateIOError(( wrote=(-1), amt=1 )); SimulateDiskfullError(( wrote=0, amt=1 )); if( amt>0 ){ if( wrote<0 ){ /* lastErrno set by seekAndWrite */ return SQLITE_IOERR_WRITE; }else{ pFile->lastErrno = 0; /* not a system error */ return SQLITE_FULL; } } return SQLITE_OK; } #ifdef SQLITE_TEST |
︙ | ︙ | |||
3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 | assert( id ); SimulateIOError( return SQLITE_IOERR_TRUNCATE ); rc = ftruncate(((unixFile*)id)->h, (off_t)nByte); if( rc ){ ((unixFile*)id)->lastErrno = errno; return SQLITE_IOERR_TRUNCATE; }else{ return SQLITE_OK; } } /* ** Determine the current size of a file in bytes */ | > > > > > > > > > > > > > | 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 | assert( id ); SimulateIOError( return SQLITE_IOERR_TRUNCATE ); rc = ftruncate(((unixFile*)id)->h, (off_t)nByte); if( rc ){ ((unixFile*)id)->lastErrno = errno; return SQLITE_IOERR_TRUNCATE; }else{ #ifndef NDEBUG /* If we are doing a normal write to a database file (as opposed to ** doing a hot-journal rollback or a write to some file other than a ** normal database file) and we truncate the file to zero length, ** that effectively updates the change counter. This might happen ** when restoring a database using the backup API from a zero-length ** source. */ if( ((unixFile*)id)->inNormalWrite && nByte==0 ){ ((unixFile*)id)->transCntrChng = 1; } #endif return SQLITE_OK; } } /* ** Determine the current size of a file in bytes */ |
︙ | ︙ | |||
3134 3135 3136 3137 3138 3139 3140 | ** looks at the filesystem type and tries to guess the best locking ** strategy from that. ** ** For finder-funtion F, two objects are created: ** ** (1) The real finder-function named "FImpt()". ** | | | 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 | ** looks at the filesystem type and tries to guess the best locking ** strategy from that. ** ** For finder-funtion F, two objects are created: ** ** (1) The real finder-function named "FImpt()". ** ** (2) A constant pointer to this function named just "F". ** ** ** A pointer to the F pointer is used as the pAppData value for VFS ** objects. We have to do this instead of letting pAppData point ** directly at the finder-function since C90 rules prevent a void* ** from be cast into a function pointer. ** |
︙ | ︙ | |||
3167 3168 3169 3170 3171 3172 3173 | LOCK, /* xLock */ \ UNLOCK, /* xUnlock */ \ CKLOCK, /* xCheckReservedLock */ \ unixFileControl, /* xFileControl */ \ unixSectorSize, /* xSectorSize */ \ unixDeviceCharacteristics /* xDeviceCapabilities */ \ }; \ | | | | | 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 | LOCK, /* xLock */ \ UNLOCK, /* xUnlock */ \ CKLOCK, /* xCheckReservedLock */ \ unixFileControl, /* xFileControl */ \ unixSectorSize, /* xSectorSize */ \ unixDeviceCharacteristics /* xDeviceCapabilities */ \ }; \ static const sqlite3_io_methods *FINDER##Impl(const char *z, unixFile *p){ \ UNUSED_PARAMETER(z); UNUSED_PARAMETER(p); \ return &METHOD; \ } \ static const sqlite3_io_methods *(*const FINDER)(const char*,unixFile *p) \ = FINDER##Impl; /* ** Here are all of the sqlite3_io_methods objects for each of the ** locking strategies. Functions that return pointers to these methods ** are also created. */ |
︙ | ︙ | |||
3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 | afpClose, /* xClose method */ afpLock, /* xLock method */ afpUnlock, /* xUnlock method */ afpCheckReservedLock /* xCheckReservedLock method */ ) #endif /* ** The proxy locking method is a "super-method" in the sense that it ** opens secondary file descriptors for the conch and lock files and ** it uses proxy, dot-file, AFP, and flock() locking methods on those ** secondary files. For this reason, the division that implements ** proxy locking is located much further down in the file. But we need ** to go ahead and define the sqlite3_io_methods and finder function | > > > > > > > > > > > > > > > > > | 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 | afpClose, /* xClose method */ afpLock, /* xLock method */ afpUnlock, /* xUnlock method */ afpCheckReservedLock /* xCheckReservedLock method */ ) #endif /* ** The "Whole File Locking" finder returns the same set of methods as ** the posix locking finder. But it also sets the SQLITE_WHOLE_FILE_LOCKING ** flag to force the posix advisory locks to cover the whole file instead ** of just a small span of bytes near the 1GiB boundary. Whole File Locking ** is useful on NFS-mounted files since it helps NFS to maintain cache ** coherency. But it is a detriment to other filesystems since it runs ** slower. */ static const sqlite3_io_methods *posixWflIoFinderImpl(const char*z, unixFile*p){ UNUSED_PARAMETER(z); p->fileFlags = SQLITE_WHOLE_FILE_LOCKING; return &posixIoMethods; } static const sqlite3_io_methods *(*const posixWflIoFinder)(const char*,unixFile *p) = posixWflIoFinderImpl; /* ** The proxy locking method is a "super-method" in the sense that it ** opens secondary file descriptors for the conch and lock files and ** it uses proxy, dot-file, AFP, and flock() locking methods on those ** secondary files. For this reason, the division that implements ** proxy locking is located much further down in the file. But we need ** to go ahead and define the sqlite3_io_methods and finder function |
︙ | ︙ | |||
3272 3273 3274 3275 3276 3277 3278 | ** for the database file "filePath". It then returns the sqlite3_io_methods ** object that implements that strategy. ** ** This is for MacOSX only. */ static const sqlite3_io_methods *autolockIoFinderImpl( const char *filePath, /* name of the database file */ | | | 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 | ** for the database file "filePath". It then returns the sqlite3_io_methods ** object that implements that strategy. ** ** This is for MacOSX only. */ static const sqlite3_io_methods *autolockIoFinderImpl( const char *filePath, /* name of the database file */ unixFile *pNew /* open file object for the database file */ ){ static const struct Mapping { const char *zFilesystem; /* Filesystem type name */ const sqlite3_io_methods *pMethods; /* Appropriate locking method */ } aMap[] = { { "hfs", &posixIoMethods }, { "ufs", &posixIoMethods }, |
︙ | ︙ | |||
3317 3318 3319 3320 3321 3322 3323 | ** Test byte-range lock using fcntl(). If the call succeeds, ** assume that the file-system supports POSIX style locks. */ lockInfo.l_len = 1; lockInfo.l_start = 0; lockInfo.l_whence = SEEK_SET; lockInfo.l_type = F_RDLCK; | | > | | | | | | | | 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 | ** Test byte-range lock using fcntl(). If the call succeeds, ** assume that the file-system supports POSIX style locks. */ lockInfo.l_len = 1; lockInfo.l_start = 0; lockInfo.l_whence = SEEK_SET; lockInfo.l_type = F_RDLCK; if( fcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) { pNew->fileFlags = SQLITE_WHOLE_FILE_LOCKING; return &posixIoMethods; }else{ return &dotlockIoMethods; } } static const sqlite3_io_methods *(*const autolockIoFinder)(const char*,unixFile*) = autolockIoFinderImpl; #endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */ #if OS_VXWORKS && SQLITE_ENABLE_LOCKING_STYLE /* ** This "finder" function attempts to determine the best locking strategy ** for the database file "filePath". It then returns the sqlite3_io_methods ** object that implements that strategy. ** ** This is for VXWorks only. */ static const sqlite3_io_methods *autolockIoFinderImpl( const char *filePath, /* name of the database file */ unixFile *pNew /* the open file object */ ){ struct flock lockInfo; if( !filePath ){ /* If filePath==NULL that means we are dealing with a transient file ** that does not need to be locked. */ return &nolockIoMethods; } /* Test if fcntl() is supported and use POSIX style locks. ** Otherwise fall back to the named semaphore method. */ lockInfo.l_len = 1; lockInfo.l_start = 0; lockInfo.l_whence = SEEK_SET; lockInfo.l_type = F_RDLCK; if( fcntl(pNew->h, F_GETLK, &lockInfo)!=-1 ) { return &posixIoMethods; }else{ return &semIoMethods; } } static const sqlite3_io_methods *(*const autolockIoFinder)(const char*,unixFile*) = autolockIoFinderImpl; #endif /* OS_VXWORKS && SQLITE_ENABLE_LOCKING_STYLE */ /* ** An abstract type for a pointer to a IO method finder function: */ typedef const sqlite3_io_methods *(*finder_type)(const char*,unixFile*); /**************************************************************************** **************************** sqlite3_vfs methods **************************** ** ** This division contains the implementation of methods on the ** sqlite3_vfs object. |
︙ | ︙ | |||
3398 3399 3400 3401 3402 3403 3404 | const sqlite3_io_methods *pLockingStyle; unixFile *pNew = (unixFile *)pId; int rc = SQLITE_OK; assert( pNew->pLock==NULL ); assert( pNew->pOpen==NULL ); | | | < < < > | > > > > > > > > > > > > > > > > > > > > > > | 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 | const sqlite3_io_methods *pLockingStyle; unixFile *pNew = (unixFile *)pId; int rc = SQLITE_OK; assert( pNew->pLock==NULL ); assert( pNew->pOpen==NULL ); /* Parameter isDelete is only used on vxworks. Express this explicitly ** here to prevent compiler warnings about unused parameters. */ UNUSED_PARAMETER(isDelete); OSTRACE3("OPEN %-3d %s\n", h, zFilename); pNew->h = h; pNew->dirfd = dirfd; SET_THREADID(pNew); pNew->fileFlags = 0; #if OS_VXWORKS pNew->pId = vxworksFindFileId(zFilename); if( pNew->pId==0 ){ noLock = 1; rc = SQLITE_NOMEM; } #endif if( noLock ){ pLockingStyle = &nolockIoMethods; }else{ pLockingStyle = (**(finder_type*)pVfs->pAppData)(zFilename, pNew); #if SQLITE_ENABLE_LOCKING_STYLE /* Cache zFilename in the locking context (AFP and dotlock override) for ** proxyLock activation is possible (remote proxy is based on db name) ** zFilename remains valid until file is closed, to support */ pNew->lockingContext = (void*)zFilename; #endif } if( pLockingStyle == &posixIoMethods ){ unixEnterMutex(); rc = findLockInfo(pNew, &pNew->pLock, &pNew->pOpen); if( rc!=SQLITE_OK ){ /* If an error occured in findLockInfo(), close the file descriptor ** immediately, before releasing the mutex. findLockInfo() may fail ** in two scenarios: ** ** (a) A call to fstat() failed. ** (b) A malloc failed. ** ** Scenario (b) may only occur if the process is holding no other ** file descriptors open on the same file. If there were other file ** descriptors on this file, then no malloc would be required by ** findLockInfo(). If this is the case, it is quite safe to close ** handle h - as it is guaranteed that no posix locks will be released ** by doing so. ** ** If scenario (a) caused the error then things are not so safe. The ** implicit assumption here is that if fstat() fails, things are in ** such bad shape that dropping a lock or two doesn't matter much. */ close(h); h = -1; } unixLeaveMutex(); } #if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) else if( pLockingStyle == &afpIoMethods ){ /* AFP locking uses the file path so it needs to be included in ** the afpLockingContext. |
︙ | ︙ | |||
3485 3486 3487 3488 3489 3490 3491 | ** included in the semLockingContext */ unixEnterMutex(); rc = findLockInfo(pNew, &pNew->pLock, &pNew->pOpen); if( (rc==SQLITE_OK) && (pNew->pOpen->pSem==NULL) ){ char *zSemName = pNew->pOpen->aSemName; int n; | | | | 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 | ** included in the semLockingContext */ unixEnterMutex(); rc = findLockInfo(pNew, &pNew->pLock, &pNew->pOpen); if( (rc==SQLITE_OK) && (pNew->pOpen->pSem==NULL) ){ char *zSemName = pNew->pOpen->aSemName; int n; sqlite3_snprintf(MAX_PATHNAME, zSemName, "/%s.sem", pNew->pId->zCanonicalName); for( n=1; zSemName[n]; n++ ) if( zSemName[n]=='/' ) zSemName[n] = '_'; pNew->pOpen->pSem = sem_open(zSemName, O_CREAT, 0666, 1); if( pNew->pOpen->pSem == SEM_FAILED ){ rc = SQLITE_NOMEM; pNew->pOpen->aSemName[0] = '\0'; } } |
︙ | ︙ | |||
3509 3510 3511 3512 3513 3514 3515 | unlink(zFilename); isDelete = 0; } pNew->isDelete = isDelete; #endif if( rc!=SQLITE_OK ){ if( dirfd>=0 ) close(dirfd); /* silent leak if fail, already in error */ | | | 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 | unlink(zFilename); isDelete = 0; } pNew->isDelete = isDelete; #endif if( rc!=SQLITE_OK ){ if( dirfd>=0 ) close(dirfd); /* silent leak if fail, already in error */ if( h>=0 ) close(h); }else{ pNew->pMethod = pLockingStyle; OpenCounter(+1); } return rc; } |
︙ | ︙ | |||
3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 | ** 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 /* ** Open the file zPath. ** ** Previously, the SQLite OS layer used three functions in place of this ** one: ** | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ** 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 ** describing "Posix Advisory Locking" at the start of this file for ** further details. Also, ticket #4018. ** ** If a suitable file descriptor is found, then it is returned. If no ** such file descriptor is located, -1 is returned. */ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){ UnixUnusedFd *pUnused = 0; /* Do not search for an unused file descriptor on vxworks. Not because ** vxworks would not benefit from the change (it might, we're not sure), ** but because no way to test it is currently available. It is better ** not to risk breaking vxworks support for the sake of such an obscure ** feature. */ #if !OS_VXWORKS struct stat sStat; /* Results of stat() call */ /* A stat() call may fail for various reasons. If this happens, it is ** almost certain that an open() call on the same path will also fail. ** For this reason, if an error occurs in the stat() call here, it is ** ignored and -1 is returned. The caller will try to open a new file ** descriptor on the same path, fail, and return an error to SQLite. ** ** Even if a subsequent open() call does succeed, the consequences of ** not searching for a resusable file descriptor are not dire. */ if( 0==stat(zPath, &sStat) ){ struct unixOpenCnt *pO; struct unixFileId id; id.dev = sStat.st_dev; id.ino = sStat.st_ino; unixEnterMutex(); for(pO=openList; pO && memcmp(&id, &pO->fileId, sizeof(id)); pO=pO->pNext); if( pO ){ UnixUnusedFd **pp; for(pp=&pO->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext)); pUnused = *pp; if( pUnused ){ *pp = pUnused->pNext; } } unixLeaveMutex(); } #endif /* if !OS_VXWORKS */ return pUnused; } /* ** Open the file zPath. ** ** Previously, the SQLite OS layer used three functions in place of this ** one: ** |
︙ | ︙ | |||
3648 3649 3650 3651 3652 3653 3654 | static int unixOpen( sqlite3_vfs *pVfs, /* The VFS for which this is the xOpen method */ const char *zPath, /* Pathname of file to be opened */ 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 */ ){ | > | | | 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 | static int unixOpen( sqlite3_vfs *pVfs, /* The VFS for which this is the xOpen method */ const char *zPath, /* Pathname of file to be opened */ 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 dirfd = -1; /* Directory file descriptor */ 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 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); |
︙ | ︙ | |||
3688 3689 3690 3691 3692 3693 3694 | */ assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly)); assert(isCreate==0 || isReadWrite); assert(isExclusive==0 || isCreate); assert(isDelete==0 || isCreate); /* The main DB, main journal, and master journal are never automatically | | < | | | | > > > > > > > > > > > > | > > > > > > > | | | | | > | | > | | | > | > > > > > > > > > > > | < < < < < < < < < < > > > > > | < > | | | < < > > > > > > > | > | > | > | | > > > | > > > | 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 | */ assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly)); assert(isCreate==0 || isReadWrite); assert(isExclusive==0 || isCreate); assert(isDelete==0 || isCreate); /* The main DB, main journal, 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 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 ); 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_malloc(sizeof(*pUnused)); if( !pUnused ){ return SQLITE_NOMEM; } } p->pUnused = pUnused; }else if( !zName ){ /* If zName is NULL, the upper layer is requesting a temp file. */ assert(isDelete && !isOpenDirectory); rc = getTempname(MAX_PATHNAME+1, zTmpname); if( rc!=SQLITE_OK ){ return rc; } zName = zTmpname; } /* Determine the value of the flags parameter passed to POSIX function ** 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 = (isDelete?0600:SQLITE_DEFAULT_FILE_PERMISSIONS); fd = open(zName, openFlags, openMode); OSTRACE4("OPENX %-3d %s 0%o\n", fd, zName, openFlags); if( fd<0 && errno!=EISDIR && isReadWrite && !isExclusive ){ /* Failed to open the file for read/write access. Try read-only. */ flags &= ~(SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE); openFlags &= ~(O_RDWR|O_CREAT); flags |= SQLITE_OPEN_READONLY; openFlags |= O_RDONLY; fd = open(zName, openFlags, openMode); } if( fd<0 ){ rc = SQLITE_CANTOPEN; goto open_finished; } } assert( fd>=0 ); if( pOutFlags ){ *pOutFlags = flags; } if( p->pUnused ){ p->pUnused->fd = fd; p->pUnused->flags = flags; } if( isDelete ){ #if OS_VXWORKS zPath = zName; #else unlink(zName); #endif } #if SQLITE_ENABLE_LOCKING_STYLE else{ p->openFlags = openFlags; } #endif if( isOpenDirectory ){ rc = openDirectory(zPath, &dirfd); if( rc!=SQLITE_OK ){ /* It is safe to close fd at this point, because it is guaranteed not ** to be open on a database file. If it were open on a database file, ** it would not be safe to close as this would release any locks held ** on the file by this process. */ assert( eType!=SQLITE_OPEN_MAIN_DB ); close(fd); /* silently leak if fail, already in error */ goto open_finished; } } #ifdef FD_CLOEXEC fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC); #endif noLock = eType!=SQLITE_OPEN_MAIN_DB; #if SQLITE_PREFER_PROXY_LOCKING if( zPath!=NULL && !noLock && pVfs->xOpen ){ char *envforce = getenv("SQLITE_FORCE_PROXY_LOCKING"); int useProxy = 0; /* SQLITE_FORCE_PROXY_LOCKING==1 means force always use proxy, 0 means ** never use proxy, NULL means use proxy for non-local files only. */ if( envforce!=NULL ){ useProxy = atoi(envforce)>0; }else{ struct statfs fsInfo; if( statfs(zPath, &fsInfo) == -1 ){ /* In theory, the close(fd) call is sub-optimal. If the file opened ** with fd is a database file, and there are other connections open ** on that file that are currently holding advisory locks on it, ** then the call to close() will cancel those locks. In practice, ** we're assuming that statfs() doesn't fail very often. At least ** not while other file descriptors opened by the same process on ** the same file are working. */ p->lastErrno = errno; if( dirfd>=0 ){ close(dirfd); /* silently leak if fail, in error */ } close(fd); /* silently leak if fail, in error */ rc = SQLITE_IOERR_ACCESS; goto open_finished; } useProxy = !(fsInfo.f_flags&MNT_LOCAL); } if( useProxy ){ rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, isDelete); if( rc==SQLITE_OK ){ rc = proxyTransformUnixFile((unixFile*)pFile, ":auto:"); } goto open_finished; } } #endif rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, isDelete); open_finished: if( rc!=SQLITE_OK ){ sqlite3_free(p->pUnused); } return rc; } /* ** Delete the file at zPath. If the dirSync argument is true, fsync() ** the directory after deleting the file. */ static int unixDelete( sqlite3_vfs *NotUsed, /* VFS containing this as the xDelete method */ |
︙ | ︙ | |||
4468 4469 4470 4471 4472 4473 4474 | ** Create a new VFS file descriptor (stored in memory obtained from ** sqlite3_malloc) and open the file named "path" in the file descriptor. ** ** The caller is responsible not only for closing the file descriptor ** but also for freeing the memory associated with the file descriptor. */ static int proxyCreateUnixFile(const char *path, unixFile **ppFile) { | < < > < < < < < | | < > > > > > > > > > > > > | > | | | | < > | > > > > | 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 | ** Create a new VFS file descriptor (stored in memory obtained from ** sqlite3_malloc) and open the file named "path" in the file descriptor. ** ** The caller is responsible not only for closing the file descriptor ** but also for freeing the memory associated with the file descriptor. */ static int proxyCreateUnixFile(const char *path, unixFile **ppFile) { unixFile *pNew; int flags = SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE; int rc = SQLITE_OK; sqlite3_vfs dummyVfs; pNew = (unixFile *)sqlite3_malloc(sizeof(unixFile)); if( !pNew ){ return SQLITE_NOMEM; } memset(pNew, 0, sizeof(unixFile)); /* Call unixOpen() to open the proxy file. The flags passed to unixOpen() ** suggest that the file being opened is a "main database". This is ** necessary as other file types do not necessarily support locking. It ** is better to use unixOpen() instead of opening the file directly with ** open(), as unixOpen() sets up the various mechanisms required to ** make sure a call to close() does not cause the system to discard ** POSIX locks prematurely. ** ** It is important that the xOpen member of the VFS object passed to ** unixOpen() is NULL. This tells unixOpen() may try to open a proxy-file ** for the proxy-file (creating a potential infinite loop). */ dummyVfs.pAppData = (void*)&autolockIoFinder; dummyVfs.xOpen = 0; rc = unixOpen(&dummyVfs, path, (sqlite3_file *)pNew, flags, &flags); if( rc==SQLITE_OK && (flags&SQLITE_OPEN_READONLY) ){ pNew->pMethod->xClose((sqlite3_file *)pNew); rc = SQLITE_CANTOPEN; } if( rc!=SQLITE_OK ){ sqlite3_free(pNew); pNew = 0; } *ppFile = pNew; return rc; } /* takes the conch by taking a shared lock and read the contents conch, if ** lockPath is non-NULL, the host ID and lock file path must match. A NULL ** lockPath means that the lockPath in the conch file will be used if the ** host IDs match, or a new lock path will be generated automatically |
︙ | ︙ | |||
5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 | #if SQLITE_ENABLE_LOCKING_STYLE && (OS_VXWORKS || defined(__APPLE__)) UNIXVFS("unix", autolockIoFinder ), #else UNIXVFS("unix", posixIoFinder ), #endif UNIXVFS("unix-none", nolockIoFinder ), UNIXVFS("unix-dotfile", dotlockIoFinder ), #if OS_VXWORKS UNIXVFS("unix-namedsem", semIoFinder ), #endif #if SQLITE_ENABLE_LOCKING_STYLE UNIXVFS("unix-posix", posixIoFinder ), #if !OS_VXWORKS UNIXVFS("unix-flock", flockIoFinder ), | > | 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 | #if SQLITE_ENABLE_LOCKING_STYLE && (OS_VXWORKS || defined(__APPLE__)) UNIXVFS("unix", autolockIoFinder ), #else UNIXVFS("unix", posixIoFinder ), #endif UNIXVFS("unix-none", nolockIoFinder ), UNIXVFS("unix-dotfile", dotlockIoFinder ), UNIXVFS("unix-wfl", posixWflIoFinder ), #if OS_VXWORKS UNIXVFS("unix-namedsem", semIoFinder ), #endif #if SQLITE_ENABLE_LOCKING_STYLE UNIXVFS("unix-posix", posixIoFinder ), #if !OS_VXWORKS UNIXVFS("unix-flock", flockIoFinder ), |
︙ | ︙ |
Changes to src/os_win.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2004 May 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains code that is specific to windows. | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* ** 2004 May 22 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains code that is specific to windows. */ #include "sqliteInt.h" #if SQLITE_OS_WIN /* This file is used for windows only */ /* ** A Note About Memory Allocation: |
︙ | ︙ | |||
71 72 73 74 75 76 77 | /* ** Determine if we are dealing with WindowsCE - which has a much ** reduced API. */ #if SQLITE_OS_WINCE # define AreFileApisANSI() 1 | | | 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | /* ** Determine if we are dealing with WindowsCE - which has a much ** reduced API. */ #if SQLITE_OS_WINCE # define AreFileApisANSI() 1 # define FormatMessageW(a,b,c,d,e,f,g) 0 #endif /* ** WinCE lacks native support for file locking so we have to fake it ** with some code of our own. */ #if SQLITE_OS_WINCE |
︙ | ︙ | |||
305 306 307 308 309 310 311 | { static struct tm y; FILETIME uTm, lTm; SYSTEMTIME pTm; sqlite3_int64 t64; t64 = *t; t64 = (t64 + 11644473600)*10000000; | | | | | 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 | { static struct tm y; FILETIME uTm, lTm; SYSTEMTIME pTm; sqlite3_int64 t64; t64 = *t; t64 = (t64 + 11644473600)*10000000; uTm.dwLowDateTime = (DWORD)(t64 & 0xFFFFFFFF); uTm.dwHighDateTime= (DWORD)(t64 >> 32); FileTimeToLocalFileTime(&uTm,&lTm); FileTimeToSystemTime(&lTm,&pTm); y.tm_year = pTm.wYear - 1900; y.tm_mon = pTm.wMonth - 1; y.tm_wday = pTm.wDayOfWeek; y.tm_mday = pTm.wDay; y.tm_hour = pTm.wHour; y.tm_min = pTm.wMinute; y.tm_sec = pTm.wSecond; return &y; } /* This will never be called, but defined to make the code compile */ #define GetTempPathA(a,b) #define LockFile(a,b,c,d,e) winceLockFile(&a, b, c, d, e) #define UnlockFile(a,b,c,d,e) winceUnlockFile(&a, b, c, d, e) #define LockFileEx(a,b,c,d,e,f) winceLockFileEx(&a, b, c, d, e, f) #define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)] /* ** Acquire a lock on the handle h */ static void winceMutexAcquire(HANDLE h){ DWORD dwErr; do { |
︙ | ︙ | |||
465 466 467 468 469 470 471 472 473 474 475 | DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh ){ winFile *pFile = HANDLE_TO_WINFILE(phFile); BOOL bReturn = FALSE; if (!pFile->hMutex) return TRUE; winceMutexAcquire(pFile->hMutex); /* Wanting an exclusive lock? */ | > > > | | | < | | > | | 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 | DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh ){ winFile *pFile = HANDLE_TO_WINFILE(phFile); BOOL bReturn = FALSE; UNUSED_PARAMETER(dwFileOffsetHigh); UNUSED_PARAMETER(nNumberOfBytesToLockHigh); if (!pFile->hMutex) return TRUE; winceMutexAcquire(pFile->hMutex); /* Wanting an exclusive lock? */ if (dwFileOffsetLow == (DWORD)SHARED_FIRST && nNumberOfBytesToLockLow == (DWORD)SHARED_SIZE){ if (pFile->shared->nReaders == 0 && pFile->shared->bExclusive == 0){ pFile->shared->bExclusive = TRUE; pFile->local.bExclusive = TRUE; bReturn = TRUE; } } /* Want a read-only lock? */ else if (dwFileOffsetLow == (DWORD)SHARED_FIRST && nNumberOfBytesToLockLow == 1){ if (pFile->shared->bExclusive == 0){ pFile->local.nReaders ++; if (pFile->local.nReaders == 1){ pFile->shared->nReaders ++; } bReturn = TRUE; } } /* Want a pending lock? */ else if (dwFileOffsetLow == (DWORD)PENDING_BYTE && nNumberOfBytesToLockLow == 1){ /* If no pending lock has been acquired, then acquire it */ if (pFile->shared->bPending == 0) { pFile->shared->bPending = TRUE; pFile->local.bPending = TRUE; bReturn = TRUE; } } /* Want a reserved lock? */ else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE && nNumberOfBytesToLockLow == 1){ if (pFile->shared->bReserved == 0) { pFile->shared->bReserved = TRUE; pFile->local.bReserved = TRUE; bReturn = TRUE; } } |
︙ | ︙ | |||
526 527 528 529 530 531 532 533 534 535 536 | DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh ){ winFile *pFile = HANDLE_TO_WINFILE(phFile); BOOL bReturn = FALSE; if (!pFile->hMutex) return TRUE; winceMutexAcquire(pFile->hMutex); /* Releasing a reader lock or an exclusive lock */ | > > > | < > > | | | 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 | DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh ){ winFile *pFile = HANDLE_TO_WINFILE(phFile); BOOL bReturn = FALSE; UNUSED_PARAMETER(dwFileOffsetHigh); UNUSED_PARAMETER(nNumberOfBytesToUnlockHigh); if (!pFile->hMutex) return TRUE; winceMutexAcquire(pFile->hMutex); /* Releasing a reader lock or an exclusive lock */ if (dwFileOffsetLow == (DWORD)SHARED_FIRST){ /* Did we have an exclusive lock? */ if (pFile->local.bExclusive){ assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE); pFile->local.bExclusive = FALSE; pFile->shared->bExclusive = FALSE; bReturn = TRUE; } /* Did we just have a reader lock? */ else if (pFile->local.nReaders){ assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE || nNumberOfBytesToUnlockLow == 1); pFile->local.nReaders --; if (pFile->local.nReaders == 0) { pFile->shared->nReaders --; } bReturn = TRUE; } } /* Releasing a pending lock */ else if (dwFileOffsetLow == (DWORD)PENDING_BYTE && nNumberOfBytesToUnlockLow == 1){ if (pFile->local.bPending){ pFile->local.bPending = FALSE; pFile->shared->bPending = FALSE; bReturn = TRUE; } } /* Releasing a reserved lock */ else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE && nNumberOfBytesToUnlockLow == 1){ if (pFile->local.bReserved) { pFile->local.bReserved = FALSE; pFile->shared->bReserved = FALSE; bReturn = TRUE; } } |
︙ | ︙ | |||
582 583 584 585 586 587 588 589 590 | HANDLE *phFile, DWORD dwFlags, DWORD dwReserved, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh, LPOVERLAPPED lpOverlapped ){ /* If the caller wants a shared read lock, forward this call ** to winceLockFile */ | > > > | | | 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 | HANDLE *phFile, DWORD dwFlags, DWORD dwReserved, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh, LPOVERLAPPED lpOverlapped ){ UNUSED_PARAMETER(dwReserved); UNUSED_PARAMETER(nNumberOfBytesToLockHigh); /* If the caller wants a shared read lock, forward this call ** to winceLockFile */ if (lpOverlapped->Offset == (DWORD)SHARED_FIRST && dwFlags == 1 && nNumberOfBytesToLockLow == (DWORD)SHARED_SIZE){ return winceLockFile(phFile, SHARED_FIRST, 0, 1, 0); } return FALSE; } /* ** End of the special code for wince *****************************************************************************/ |
︙ | ︙ | |||
1236 1237 1238 1239 1240 1241 1242 | /* ** The return value of getLastErrorMsg ** is zero if the error message fits in the buffer, or non-zero ** otherwise (if the message was truncated). */ static int getLastErrorMsg(int nBuf, char *zBuf){ | < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | < > | < > > | > > | | > > > > > > > > | 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 | /* ** The return value of getLastErrorMsg ** is zero if the error message fits in the buffer, or non-zero ** otherwise (if the message was truncated). */ static int getLastErrorMsg(int nBuf, char *zBuf){ /* FormatMessage returns 0 on failure. Otherwise it ** returns the number of TCHARs written to the output ** buffer, excluding the terminating null char. */ DWORD error = GetLastError(); DWORD dwLen = 0; char *zOut = 0; if( isNT() ){ WCHAR *zTempWide = NULL; dwLen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, 0, (LPWSTR) &zTempWide, 0, 0); if( dwLen > 0 ){ /* allocate a buffer and convert to UTF8 */ zOut = unicodeToUtf8(zTempWide); /* free the system buffer allocated by FormatMessage */ LocalFree(zTempWide); } /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. ** Since the ASCII version of these Windows API do not exist for WINCE, ** it's important to not reference them for WINCE builds. */ #if SQLITE_OS_WINCE==0 }else{ char *zTemp = NULL; dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, 0, (LPSTR) &zTemp, 0, 0); if( dwLen > 0 ){ /* allocate a buffer and convert to UTF8 */ zOut = sqlite3_win32_mbcs_to_utf8(zTemp); /* free the system buffer allocated by FormatMessage */ LocalFree(zTemp); } #endif } if( 0 == dwLen ){ sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", error, error); }else{ /* copy a maximum of nBuf chars to output buffer */ sqlite3_snprintf(nBuf, zBuf, "%s", zOut); /* free the UTF8 buffer */ free(zOut); } return 0; } /* ** Open a file. */ static int winOpen( |
︙ | ︙ | |||
1588 1589 1590 1591 1592 1593 1594 1595 1596 | ** file. */ static int getSectorSize( sqlite3_vfs *pVfs, const char *zRelative /* UTF-8 file name */ ){ DWORD bytesPerSector = SQLITE_DEFAULT_SECTOR_SIZE; char zFullpath[MAX_PATH+1]; int rc; | > > > > > | > | 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 | ** file. */ static int getSectorSize( sqlite3_vfs *pVfs, const char *zRelative /* UTF-8 file name */ ){ DWORD bytesPerSector = SQLITE_DEFAULT_SECTOR_SIZE; /* GetDiskFreeSpace is not supported under WINCE */ #if SQLITE_OS_WINCE UNUSED_PARAMETER(pVfs); UNUSED_PARAMETER(zRelative); #else char zFullpath[MAX_PATH+1]; int rc; DWORD dwRet = 0; DWORD dwDummy; /* ** We need to get the full path name of the file ** to get the drive letter to look up the sector ** size. */ rc = winFullPathname(pVfs, zRelative, MAX_PATH, zFullpath); |
︙ | ︙ | |||
1616 1617 1618 1619 1620 1621 1622 | } } dwRet = GetDiskFreeSpaceW((WCHAR*)zConverted, &dwDummy, &bytesPerSector, &dwDummy, &dwDummy); | < | | < > | 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 | } } dwRet = GetDiskFreeSpaceW((WCHAR*)zConverted, &dwDummy, &bytesPerSector, &dwDummy, &dwDummy); }else{ /* trim path to just drive reference */ char *p = (char *)zConverted; for(;*p;p++){ if( *p == '\\' ){ *p = '\0'; break; } } dwRet = GetDiskFreeSpaceA((char*)zConverted, &dwDummy, &bytesPerSector, &dwDummy, &dwDummy); } free(zConverted); } if( !dwRet ){ bytesPerSector = SQLITE_DEFAULT_SECTOR_SIZE; } } #endif return (int) bytesPerSector; } #ifndef SQLITE_OMIT_LOAD_EXTENSION /* ** Interfaces for opening a shared library, finding entry points ** within the shared library, and closing the shared library. |
︙ | ︙ | |||
1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 | winDlSym, /* xDlSym */ winDlClose, /* xDlClose */ winRandomness, /* xRandomness */ winSleep, /* xSleep */ winCurrentTime, /* xCurrentTime */ winGetLastError /* xGetLastError */ }; sqlite3_vfs_register(&winVfs, 1); return SQLITE_OK; } int sqlite3_os_end(void){ return SQLITE_OK; } #endif /* SQLITE_OS_WIN */ | > | 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 | winDlSym, /* xDlSym */ winDlClose, /* xDlClose */ winRandomness, /* xRandomness */ winSleep, /* xSleep */ winCurrentTime, /* xCurrentTime */ winGetLastError /* xGetLastError */ }; sqlite3_vfs_register(&winVfs, 1); return SQLITE_OK; } int sqlite3_os_end(void){ return SQLITE_OK; } #endif /* SQLITE_OS_WIN */ |
Changes to src/pager.c.
︙ | ︙ | |||
13 14 15 16 17 18 19 | ** ** The pager is used to access a database disk file. It implements ** atomic commit and rollback through the use of a journal file that ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. | < < | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ** ** The pager is used to access a database disk file. It implements ** atomic commit and rollback through the use of a journal file that ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" /* ** Macros for troubleshooting. Normally turned off */ |
︙ | ︙ | |||
110 111 112 113 114 115 116 | 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 /* | | | | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | 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 /* ** An instance of the following structure is allocated for each active ** savepoint and statement transaction in the system. All such structures ** are stored in the Pager.aSavepoint[] array, which is allocated and ** resized using sqlite3Realloc(). ** |
︙ | ︙ | |||
781 782 783 784 785 786 787 | assert( isOpen(pPager->fd) || pPager->noSync ); if( (pPager->noSync) || (pPager->journalMode==PAGER_JOURNALMODE_MEMORY) || (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND) ){ memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic)); put32bits(&zHeader[sizeof(aJournalMagic)], 0xffffffff); }else{ | < | | 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 | assert( isOpen(pPager->fd) || pPager->noSync ); if( (pPager->noSync) || (pPager->journalMode==PAGER_JOURNALMODE_MEMORY) || (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND) ){ memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic)); put32bits(&zHeader[sizeof(aJournalMagic)], 0xffffffff); }else{ memset(zHeader, 0, sizeof(aJournalMagic)+4); } /* The random check-hash initialiser */ sqlite3_randomness(sizeof(pPager->cksumInit), &pPager->cksumInit); put32bits(&zHeader[sizeof(aJournalMagic)+4], pPager->cksumInit); /* The initial database size */ put32bits(&zHeader[sizeof(aJournalMagic)+8], pPager->dbOrigSize); |
︙ | ︙ | |||
1123 1124 1125 1126 1127 1128 1129 | sqlite3BitvecDestroy(pPager->pInJournal); pPager->pInJournal = 0; releaseAllSavepoints(pPager); /* If the file is unlocked, somebody else might change it. The ** values stored in Pager.dbSize etc. might become invalid if ** this happens. TODO: Really, this doesn't need to be cleared | | | 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 | sqlite3BitvecDestroy(pPager->pInJournal); pPager->pInJournal = 0; releaseAllSavepoints(pPager); /* If the file is unlocked, somebody else might change it. The ** values stored in Pager.dbSize etc. might become invalid if ** this happens. TODO: Really, this doesn't need to be cleared ** until the change-counter check fails in PagerSharedLock(). */ pPager->dbSizeValid = 0; rc = osUnlock(pPager->fd, NO_LOCK); if( rc ){ pPager->errCode = rc; } |
︙ | ︙ | |||
1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 | ** the contents of the pager-cache. If a transaction was active when ** the persistent error occurred, then the rollback journal may need ** to be replayed to restore the contents of the database file (as if ** it were a hot-journal). */ static int pager_error(Pager *pPager, int rc){ int rc2 = rc & 0xff; assert( pPager->errCode==SQLITE_FULL || pPager->errCode==SQLITE_OK || (pPager->errCode & 0xff)==SQLITE_IOERR ); | > < | < < < < < < < < < < < < | 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 | ** the contents of the pager-cache. If a transaction was active when ** the persistent error occurred, then the rollback journal may need ** to be replayed to restore the contents of the database file (as if ** it were a hot-journal). */ static int pager_error(Pager *pPager, int rc){ int rc2 = rc & 0xff; assert( rc==SQLITE_OK || !MEMDB ); assert( pPager->errCode==SQLITE_FULL || pPager->errCode==SQLITE_OK || (pPager->errCode & 0xff)==SQLITE_IOERR ); if( rc2==SQLITE_FULL || rc2==SQLITE_IOERR ){ pPager->errCode = rc; } return rc; } /* ** Execute a rollback if a transaction is active and unlock the ** database file. |
︙ | ︙ | |||
1288 1289 1290 1291 1292 1293 1294 | return SQLITE_OK; } releaseAllSavepoints(pPager); assert( isOpen(pPager->jfd) || pPager->pInJournal==0 ); if( isOpen(pPager->jfd) ){ | < < < < < < < < > | < < < < > > > > | > > | | 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 | return SQLITE_OK; } releaseAllSavepoints(pPager); assert( isOpen(pPager->jfd) || pPager->pInJournal==0 ); if( isOpen(pPager->jfd) ){ /* Finalize the journal file. */ if( sqlite3IsMemJournal(pPager->jfd) ){ assert( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ); sqlite3OsClose(pPager->jfd); }else if( pPager->journalMode==PAGER_JOURNALMODE_TRUNCATE ){ if( pPager->journalOff==0 ){ rc = SQLITE_OK; }else{ rc = sqlite3OsTruncate(pPager->jfd, 0); } pPager->journalOff = 0; pPager->journalStarted = 0; }else if( pPager->exclusiveMode || pPager->journalMode==PAGER_JOURNALMODE_PERSIST ){ rc = zeroJournalHdr(pPager, hasMaster); pager_error(pPager, rc); pPager->journalOff = 0; pPager->journalStarted = 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. */ assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE || pPager->journalMode==PAGER_JOURNALMODE_MEMORY ); sqlite3OsClose(pPager->jfd); if( !pPager->tempFile ){ rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0); } } #ifdef SQLITE_CHECK_PAGES sqlite3PcacheIterateDirty(pPager->pPCache, pager_set_pagehash); #endif |
︙ | ︙ | |||
1571 1572 1573 1574 1575 1576 1577 | ** database active. However such a page may be rolled back as a result ** of an internal error resulting in an automatic call to ** sqlite3PagerRollback(). */ void *pData; pData = pPg->pData; memcpy(pData, aData, pPager->pageSize); | < | < | 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 | ** database active. However such a page may be rolled back as a result ** of an internal error resulting in an automatic call to ** sqlite3PagerRollback(). */ void *pData; pData = pPg->pData; memcpy(pData, aData, pPager->pageSize); pPager->xReiniter(pPg); if( isMainJrnl && (!isSavepnt || *pOffset<=pPager->journalHdr) ){ /* If the contents of this page were just restored from the main ** journal file, then its content must be as they were when the ** transaction was first opened. In this case we can mark the page ** as clean, since there will be no need to write it out to the. ** ** There is one exception to this rule. If the page is being rolled |
︙ | ︙ | |||
1611 1612 1613 1614 1615 1616 1617 | /* Decode the page just read from disk */ CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM); sqlite3PcacheRelease(pPg); } return rc; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 | /* Decode the page just read from disk */ CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM); 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 |
︙ | ︙ | |||
1726 1727 1728 1729 1730 1731 1732 | char *zJournal; char *zMasterPtr = 0; int nMasterPtr = pVfs->mxPathname+1; /* Load the entire master journal file into space obtained from ** sqlite3_malloc() and pointed to by zMasterJournal. */ | | | > | 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 | char *zJournal; char *zMasterPtr = 0; int nMasterPtr = pVfs->mxPathname+1; /* Load the entire master journal file into space obtained from ** sqlite3_malloc() and pointed to by zMasterJournal. */ zMasterJournal = sqlite3Malloc((int)nMasterJournal + nMasterPtr + 1); if( !zMasterJournal ){ rc = SQLITE_NOMEM; 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; |
︙ | ︙ | |||
1875 1876 1877 1878 1879 1880 1881 | ** number of page records from the journal size. ** (3) 4 byte big-endian integer which is the initial value for the ** sanity checksum. ** (4) 4 byte integer which is the number of pages to truncate the ** database to during a rollback. ** (5) 4 byte big-endian integer which is the sector size. The header ** is this many bytes in size. | | | < < < < < < | | | | 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 | ** number of page records from the journal size. ** (3) 4 byte big-endian integer which is the initial value for the ** sanity checksum. ** (4) 4 byte integer which is the number of pages to truncate the ** database to during a rollback. ** (5) 4 byte big-endian integer which is the sector size. The header ** is this many bytes in size. ** (6) 4 byte big-endian integer which is the page size. ** (7) zero padding out to the next sector size. ** (8) Zero or more pages instances, each as follows: ** + 4 byte page number. ** + pPager->pageSize bytes of data. ** + 4 byte checksum ** ** When we speak of the journal header, we mean the first 7 items above. ** Each entry in the journal is an instance of the 8th item. ** ** Call the value from the second bullet "nRec". nRec is the number of ** valid page entries in the journal. In most cases, you can compute the ** value of nRec from the size of the journal file. But if a power ** failure occurred while the journal was being written, it could be the ** case that the size of the journal file had already been increased but ** the extra entries had not yet made it safely to disk. In such a case, |
︙ | ︙ | |||
2009 2010 2011 2012 2013 2014 2015 | ** When rolling back a hot journal, nRec==0 always means that the next ** chunk of the journal contains zero pages to be rolled back. But ** when doing a ROLLBACK and the nRec==0 chunk is the last chunk in ** the journal, it means that the journal might contain additional ** pages that need to be rolled back and that the number of pages ** should be computed based on the journal file size. */ | < < < < < | 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 | ** When rolling back a hot journal, nRec==0 always means that the next ** chunk of the journal contains zero pages to be rolled back. But ** when doing a ROLLBACK and the nRec==0 chunk is the last chunk in ** the journal, it means that the journal might contain additional ** pages that need to be rolled back and that the number of pages ** should be computed based on the journal file size. */ if( nRec==0 && !isHot && pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff ){ nRec = (int)((szJ - pPager->journalOff) / JOURNAL_PG_SZ(pPager)); isUnsync = 1; } /* If this is the first header read from the journal, truncate the |
︙ | ︙ | |||
2205 2206 2207 2208 2209 2210 2211 | assert( rc!=SQLITE_DONE ); /* ** The "pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff" ** test is related to ticket #2565. See the discussion in the ** pager_playback() function for additional information. */ | < < < < < | 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 | assert( rc!=SQLITE_DONE ); /* ** The "pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff" ** test is related to ticket #2565. See the discussion in the ** pager_playback() function for additional information. */ if( nJRec==0 && pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff ){ nJRec = (u32)((szJ - pPager->journalOff)/JOURNAL_PG_SZ(pPager)); } for(ii=0; rc==SQLITE_OK && ii<nJRec && pPager->journalOff<szJ; ii++){ rc = pager_playback_one_page(pPager, 1, 0, &pPager->journalOff, 1, pDone); |
︙ | ︙ | |||
2357 2358 2359 2360 2361 2362 2363 | int (*xBusyHandler)(void *), /* Pointer to busy-handler function */ void *pBusyHandlerArg /* Argument to pass to xBusyHandler */ ){ pPager->xBusyHandler = xBusyHandler; pPager->pBusyHandlerArg = pBusyHandlerArg; } | < < < < < < < < < < < | 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 | int (*xBusyHandler)(void *), /* Pointer to busy-handler function */ void *pBusyHandlerArg /* Argument to pass to xBusyHandler */ ){ pPager->xBusyHandler = xBusyHandler; pPager->pBusyHandlerArg = pBusyHandlerArg; } /* ** 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 ){ |
︙ | ︙ | |||
2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 | ** If the page size is not changed, either because one of the enumerated ** conditions above is not true, the pager was in error state when this ** function was called, or because the memory allocation attempt failed, ** then *pPageSize is set to the old, retained page size before returning. */ int sqlite3PagerSetPagesize(Pager *pPager, u16 *pPageSize, int nReserve){ int rc = pPager->errCode; if( rc==SQLITE_OK ){ u16 pageSize = *pPageSize; assert( pageSize==0 || (pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE) ); | > < | > | 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 | ** If the page size is not changed, either because one of the enumerated ** conditions above is not true, the pager was in error state when this ** function was called, or because the memory allocation attempt failed, ** then *pPageSize is set to the old, retained page size before returning. */ int sqlite3PagerSetPagesize(Pager *pPager, u16 *pPageSize, int nReserve){ int rc = pPager->errCode; if( rc==SQLITE_OK ){ u16 pageSize = *pPageSize; assert( pageSize==0 || (pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE) ); if( (pPager->memDb==0 || pPager->dbSize==0) && sqlite3PcacheRefCount(pPager->pPCache)==0 && pageSize && pageSize!=pPager->pageSize ){ char *pNew = (char *)sqlite3PageMalloc(pageSize); if( !pNew ){ rc = SQLITE_NOMEM; }else{ pager_reset(pPager); pPager->pageSize = pageSize; |
︙ | ︙ | |||
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 | pPager->state = (u8)locktype; IOTRACE(("LOCK %p %d\n", pPager, locktype)) } } return rc; } /* ** 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. */ void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){ assert( pPager->dbSizeValid ); assert( pPager->dbSize>=nPage ); assert( pPager->state>=PAGER_RESERVED ); pPager->dbSize = nPage; } /* ** Shutdown the page cache. Free all memory and close all files. ** ** If a transaction was in progress when this routine is called, that ** transaction is rolled back. All outstanding pages are invalidated | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | pPager->state = (u8)locktype; IOTRACE(("LOCK %p %d\n", pPager, locktype)) } } return rc; } /* ** 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 behaviour 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. */ void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){ assert( pPager->dbSizeValid ); assert( pPager->dbSize>=nPage ); assert( pPager->state>=PAGER_RESERVED ); pPager->dbSize = nPage; assertTruncateConstraint(pPager); } /* ** Shutdown the page cache. Free all memory and close all files. ** ** If a transaction was in progress when this routine is called, that ** transaction is rolled back. All outstanding pages are invalidated |
︙ | ︙ | |||
2879 2880 2881 2882 2883 2884 2885 | ** occurs, an IO error code is returned. Or, if the EXCLUSIVE lock cannot ** be obtained, SQLITE_BUSY is returned. */ static int pager_write_pagelist(PgHdr *pList){ Pager *pPager; /* Pager object */ int rc; /* Return code */ | | | 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 | ** occurs, an IO error code is returned. Or, if the EXCLUSIVE lock cannot ** be obtained, SQLITE_BUSY is returned. */ static int pager_write_pagelist(PgHdr *pList){ Pager *pPager; /* Pager object */ int rc; /* Return code */ if( NEVER(pList==0) ) return SQLITE_OK; pPager = pList->pPager; /* At this point there may be either a RESERVED or EXCLUSIVE lock on the ** database file. If there is already an EXCLUSIVE lock, the following ** call is a no-op. ** ** Moving the lock from RESERVED to EXCLUSIVE actually involves going |
︙ | ︙ | |||
2919 2920 2921 2922 2923 2924 2925 | /* If there are dirty pages in the page cache with page numbers greater ** than Pager.dbSize, this means sqlite3PagerTruncateImage() was called to ** make the file smaller (presumably by auto-vacuum code). Do not write ** any such pages to the file. ** ** Also, do not write out any page that has the PGHDR_DONT_WRITE flag | | > > | 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 | /* If there are dirty pages in the page cache with page numbers greater ** than Pager.dbSize, this means sqlite3PagerTruncateImage() was called to ** make the file smaller (presumably by auto-vacuum code). Do not write ** any such pages to the file. ** ** Also, do not write out any page that has the PGHDR_DONT_WRITE flag ** set (set by sqlite3PagerDontWrite()). Note that if compiled with ** SQLITE_SECURE_DELETE the PGHDR_DONT_WRITE bit is never set and so ** the second test is always true. */ 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 */ /* Encode the database */ CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM, pData); |
︙ | ︙ | |||
2996 2997 2998 2999 3000 3001 3002 | rc = sqlite3OsWrite(pPager->sjfd, pData2, pPager->pageSize, offset+4); } } if( rc==SQLITE_OK ){ pPager->nSubRec++; assert( pPager->nSavepoint>0 ); rc = addToSavepointBitvecs(pPager, pPg->pgno); | < | 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 | rc = sqlite3OsWrite(pPager->sjfd, pData2, pPager->pageSize, offset+4); } } if( rc==SQLITE_OK ){ pPager->nSubRec++; assert( pPager->nSavepoint>0 ); rc = addToSavepointBitvecs(pPager, pPg->pgno); } return rc; } /* ** This function is called by the pcache layer when it has reached some |
︙ | ︙ | |||
3041 3042 3043 3044 3045 3046 3047 | ** flag is set, return without doing anything. The pcache layer will ** just have to go ahead and allocate a new page buffer instead of ** reusing pPg. ** ** Similarly, if the pager has already entered the error state, do not ** try to write the contents of pPg to disk. */ | > | > | 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 | ** flag is set, return without doing anything. The pcache layer will ** just have to go ahead and allocate a new page buffer instead of ** reusing pPg. ** ** Similarly, if the pager has already entered the error state, do not ** try to write the contents of pPg to disk. */ if( NEVER(pPager->errCode) || (pPager->doNotSync && pPg->flags&PGHDR_NEED_SYNC) ){ return SQLITE_OK; } /* Sync the journal file if required. */ if( pPg->flags&PGHDR_NEED_SYNC ){ rc = syncJournal(pPager); if( rc==SQLITE_OK && pPager->fullSync && |
︙ | ︙ | |||
3084 3085 3086 3087 3088 3089 3090 | ** was executed. ** ** The solution is to write the current data for page X into the ** sub-journal file now (if it is not already there), so that it will ** be restored to its current value when the "ROLLBACK TO sp" is ** executed. */ | > | > | 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 | ** was executed. ** ** The solution is to write the current data for page X into the ** sub-journal file now (if it is not already there), so that it will ** be restored to its current value when the "ROLLBACK TO sp" is ** executed. */ if( NEVER( rc==SQLITE_OK && pPg->pgno>pPager->dbSize && subjRequiresPage(pPg) ) ){ rc = subjournalPage(pPg); } /* Write the contents of the page out to the database file. */ if( rc==SQLITE_OK ){ pPg->pDirty = 0; rc = pager_write_pagelist(pPg); |
︙ | ︙ | |||
3140 3141 3142 3143 3144 3145 3146 | */ int sqlite3PagerOpen( sqlite3_vfs *pVfs, /* The virtual file system to use */ Pager **ppPager, /* OUT: Return the Pager structure here */ const char *zFilename, /* Name of the database file to open */ int nExtra, /* Extra bytes append to each in-memory page */ int flags, /* flags controlling this file */ | | > | 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 | */ int sqlite3PagerOpen( sqlite3_vfs *pVfs, /* The virtual file system to use */ Pager **ppPager, /* OUT: Return the Pager structure here */ const char *zFilename, /* Name of the database file to open */ int nExtra, /* Extra bytes append to each in-memory page */ int flags, /* flags controlling this file */ int vfsFlags, /* flags passed through to sqlite3_vfs.xOpen() */ 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 */ int readOnly = 0; /* True if this is a read-only file */ |
︙ | ︙ | |||
3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 | /* Fill in the Pager.zFilename and Pager.zJournal buffers, if required. */ if( zPathname ){ pPager->zJournal = (char*)(pPtr += nPathname + 1); memcpy(pPager->zFilename, zPathname, nPathname); memcpy(pPager->zJournal, zPathname, nPathname); memcpy(&pPager->zJournal[nPathname], "-journal", 8); sqlite3_free(zPathname); } pPager->pVfs = pVfs; pPager->vfsFlags = vfsFlags; /* Open the pager file. */ | > | 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 | /* Fill in the Pager.zFilename and Pager.zJournal buffers, if required. */ if( zPathname ){ pPager->zJournal = (char*)(pPtr += nPathname + 1); memcpy(pPager->zFilename, zPathname, nPathname); memcpy(pPager->zJournal, zPathname, nPathname); memcpy(&pPager->zJournal[nPathname], "-journal", 8); if( pPager->zFilename[0]==0 ) pPager->zJournal[0] = 0; sqlite3_free(zPathname); } pPager->pVfs = pVfs; pPager->vfsFlags = vfsFlags; /* Open the pager file. */ |
︙ | ︙ | |||
3358 3359 3360 3361 3362 3363 3364 | || 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; /* pPager->needSync = 0; */ | > | > > | > | 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 | || 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; /* pPager->needSync = 0; */ assert( useJournal || pPager->tempFile ); pPager->noSync = pPager->tempFile; pPager->fullSync = pPager->noSync ?0:1; pPager->sync_flags = SQLITE_SYNC_NORMAL; /* 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); if( !useJournal ){ pPager->journalMode = PAGER_JOURNALMODE_OFF; }else if( memDb ){ pPager->journalMode = PAGER_JOURNALMODE_MEMORY; } /* pPager->xBusyHandler = 0; */ /* pPager->pBusyHandlerArg = 0; */ pPager->xReiniter = xReinit; /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */ *ppPager = pPager; return SQLITE_OK; } |
︙ | ︙ | |||
3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 | int rc; /* Return code */ int exists; /* True if a journal file is present */ assert( pPager!=0 ); assert( pPager->useJournal ); assert( isOpen(pPager->fd) ); assert( !isOpen(pPager->jfd) ); *pExists = 0; rc = sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &exists); if( rc==SQLITE_OK && exists ){ int locked; /* True if some process holds a RESERVED lock */ /* Race condition here: Another process might have been holding the | > | 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 | int rc; /* Return code */ int exists; /* True if a journal file is present */ assert( pPager!=0 ); assert( pPager->useJournal ); assert( isOpen(pPager->fd) ); assert( !isOpen(pPager->jfd) ); assert( pPager->state <= PAGER_SHARED ); *pExists = 0; rc = sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &exists); if( rc==SQLITE_OK && exists ){ int locked; /* True if some process holds a RESERVED lock */ /* Race condition here: Another process might have been holding the |
︙ | ︙ | |||
3448 3449 3450 3451 3452 3453 3454 | ** a RESERVED lock to avoid race conditions and to avoid violating ** [H33020]. */ rc = sqlite3PagerPagecount(pPager, &nPage); if( rc==SQLITE_OK ){ if( nPage==0 ){ sqlite3BeginBenignMalloc(); | < | < < | < | 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 | ** a RESERVED lock to avoid race conditions and to avoid violating ** [H33020]. */ rc = sqlite3PagerPagecount(pPager, &nPage); if( rc==SQLITE_OK ){ if( nPage==0 ){ sqlite3BeginBenignMalloc(); if( sqlite3OsLock(pPager->fd, RESERVED_LOCK)==SQLITE_OK ){ sqlite3OsDelete(pVfs, pPager->zJournal, 0); sqlite3OsUnlock(pPager->fd, SHARED_LOCK); } sqlite3EndBenignMalloc(); }else{ /* The journal file exists and no other connection has a reserved ** or greater lock on the database file. Now check that there is ** at least one non-zero bytes at the start of the journal file. ** If there is, then we consider this journal to be hot. If not, |
︙ | ︙ | |||
3513 3514 3515 3516 3517 3518 3519 3520 | static int readDbPage(PgHdr *pPg){ Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */ Pgno pgno = pPg->pgno; /* Page number to read */ int rc; /* Return code */ i64 iOffset; /* Byte offset of file to read from */ assert( pPager->state>=PAGER_SHARED && !MEMDB ); | > | | 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 | static int readDbPage(PgHdr *pPg){ Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */ Pgno pgno = pPg->pgno; /* Page number to read */ int rc; /* Return code */ i64 iOffset; /* Byte offset of file to read from */ assert( pPager->state>=PAGER_SHARED && !MEMDB ); assert( isOpen(pPager->fd) ); if( NEVER(!isOpen(pPager->fd)) ){ assert( pPager->tempFile ); memset(pPg->pData, 0, pPager->pageSize); return SQLITE_OK; } iOffset = (pgno-1)*(i64)pPager->pageSize; rc = sqlite3OsRead(pPager->fd, pPg->pData, pPager->pageSize, iOffset); if( rc==SQLITE_IOERR_SHORT_READ ){ |
︙ | ︙ | |||
3540 3541 3542 3543 3544 3545 3546 | PAGERTRACE(("FETCH %d page %d hash(%08x)\n", PAGERID(pPager), pgno, pager_pagehash(pPg))); return rc; } /* | | | | | > > | 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 | PAGERTRACE(("FETCH %d page %d hash(%08x)\n", PAGERID(pPager), pgno, pager_pagehash(pPg))); return rc; } /* ** This function is called to obtain a shared lock on the database file. ** It is illegal to call sqlite3PagerAcquire() until after this function ** has been successfully called. If a shared-lock is already held when ** this function is called, it is a no-op. ** ** The following operations are also performed by this function. ** ** 1) If the pager is currently in PAGER_UNLOCK state (no lock held ** on the database file), then an attempt is made to obtain a ** SHARED lock on the database file. Immediately after obtaining ** the SHARED lock, the file-system is checked for a hot-journal, ** which is played back if present. Following any hot-journal ** rollback, the contents of the cache are validated by checking |
︙ | ︙ | |||
3569 3570 3571 3572 3573 3574 3575 | ** the error state error code is returned. It is permitted to read the ** database when in SQLITE_FULL error state. ** ** Otherwise, if everything is successful, SQLITE_OK is returned. If an ** IO error occurs while locking the database, checking for a hot-journal ** file or rolling back a journal file, the IO error code is returned. */ | | > | > > | > | | | < < < < < < < < | > > > < < > | 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 | ** the error state error code is returned. It is permitted to read the ** database when in SQLITE_FULL error state. ** ** Otherwise, if everything is successful, SQLITE_OK is returned. If an ** IO error occurs while locking the database, checking for a hot-journal ** file or rolling back a journal file, the IO error code is returned. */ int sqlite3PagerSharedLock(Pager *pPager){ int rc = SQLITE_OK; /* Return code */ int isErrorReset = 0; /* True if recovering from error state */ /* This routine is only called from b-tree and only when there are no ** outstanding pages */ assert( sqlite3PcacheRefCount(pPager->pPCache)==0 ); if( NEVER(MEMDB && pPager->errCode) ){ return pPager->errCode; } /* If this database is in an error-state, now is a chance to clear ** the error. Discard the contents of the pager-cache and rollback ** any hot journal in the file-system. */ if( pPager->errCode ){ if( isOpen(pPager->jfd) || pPager->zJournal ){ isErrorReset = 1; } pPager->errCode = SQLITE_OK; pager_reset(pPager); } if( pPager->state==PAGER_UNLOCK || isErrorReset ){ sqlite3_vfs * const pVfs = pPager->pVfs; int isHotJournal = 0; assert( !MEMDB ); assert( sqlite3PcacheRefCount(pPager->pPCache)==0 ); if( pPager->noReadlock ){ assert( pPager->readOnly ); pPager->state = PAGER_SHARED; }else{ rc = pager_wait_on_lock(pPager, SHARED_LOCK); if( rc!=SQLITE_OK ){ assert( pPager->state==PAGER_UNLOCK ); return pager_error(pPager, rc); } } assert( pPager->state>=SHARED_LOCK ); /* If a journal file exists, and there is no RESERVED lock on the ** database file, then it either needs to be played back or deleted. */ if( !isErrorReset ){ assert( pPager->state <= PAGER_SHARED ); rc = hasHotJournal(pPager, &isHotJournal); if( rc!=SQLITE_OK ){ goto failed; } } if( isErrorReset || isHotJournal ){ /* Get an EXCLUSIVE lock on the database file. At this point it is |
︙ | ︙ | |||
3765 3766 3767 3768 3769 3770 3771 | if( (sqlite3PcacheRefCount(pPager->pPCache)==0) && (!pPager->exclusiveMode || pPager->journalOff>0) ){ pagerUnlockAndRollback(pPager); } } | < < < < < < < < < < < < < < < < < | 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 | if( (sqlite3PcacheRefCount(pPager->pPCache)==0) && (!pPager->exclusiveMode || pPager->journalOff>0) ){ pagerUnlockAndRollback(pPager); } } /* ** Acquire a reference to page number pgno in pager pPager (a page ** reference has type DbPage*). If the requested reference is ** successfully obtained, it is copied to *ppPage and SQLITE_OK returned. ** ** If the requested page is already in the cache, it is returned. ** Otherwise, a new page object is allocated and populated with data ** read from the database file. In some cases, the pcache module may ** choose not to allocate a new page object and may reuse an existing ** object with no outstanding references. ** ** The extra data appended to a page is always initialized to zeros the |
︙ | ︙ | |||
3838 3839 3840 3841 3842 3843 3844 | */ int sqlite3PagerAcquire( Pager *pPager, /* The pager open on the database file */ Pgno pgno, /* Page number to fetch */ DbPage **ppPage, /* Write a pointer to the page here */ int noContent /* Do not bother reading content from disk if true */ ){ | < > | < < < < < < | | | | | > > | | < < < < | > > > > | > < | > > > | | | | < < | < > > > > > > > > > | < < | > | 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 | */ int sqlite3PagerAcquire( Pager *pPager, /* The pager open on the database file */ Pgno pgno, /* Page number to fetch */ DbPage **ppPage, /* Write a pointer to the page here */ int noContent /* Do not bother reading content from disk if true */ ){ int rc; PgHdr *pPg; assert( assert_pager_state(pPager) ); assert( pPager->state>PAGER_UNLOCK ); if( pgno==0 ){ return SQLITE_CORRUPT_BKPT; } /* If the pager is in the error state, return an error immediately. ** Otherwise, request the page from the PCache layer. */ if( pPager->errCode!=SQLITE_OK && pPager->errCode!=SQLITE_FULL ){ rc = pPager->errCode; }else{ rc = sqlite3PcacheFetch(pPager->pPCache, pgno, 1, ppPage); } if( rc!=SQLITE_OK ){ /* Either the call to sqlite3PcacheFetch() returned an error or the ** pager was already in the error-state when this function was called. ** Set pPg to 0 and jump to the exception handler. */ pPg = 0; goto pager_acquire_err; } assert( (*ppPage)->pgno==pgno ); assert( (*ppPage)->pPager==pPager || (*ppPage)->pPager==0 ); if( (*ppPage)->pPager ){ /* 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) ); PAGER_INCR(pPager->nHit); return SQLITE_OK; }else{ /* The pager cache has created a new page. Its content needs to ** be initialized. */ int nMax; PAGER_INCR(pPager->nMiss); pPg = *ppPage; pPg->pPager = pPager; /* The maximum page number is 2^31. Return SQLITE_CORRUPT if a page ** number greater than this, or the unused locking-page, is requested. */ if( pgno>PAGER_MAX_PGNO || pgno==PAGER_MJ_PGNO(pPager) ){ rc = SQLITE_CORRUPT_BKPT; goto pager_acquire_err; } rc = sqlite3PagerPagecount(pPager, &nMax); if( rc!=SQLITE_OK ){ goto pager_acquire_err; } if( nMax<(int)pgno || MEMDB || noContent ){ if( pgno>pPager->mxPgno ){ rc = SQLITE_FULL; goto pager_acquire_err; } if( noContent ){ /* Failure to set the bits in the InJournal bit-vectors is benign. ** It merely means that we might do some extra work to journal a ** page that does not need to be journaled. Nevertheless, be sure ** to test the case where a malloc error occurs while trying to set ** a bit in a bit vector. |
︙ | ︙ | |||
3918 3919 3920 3921 3922 3923 3924 | memset(pPg->pData, 0, pPager->pageSize); } IOTRACE(("ZERO %p %d\n", pPager, pgno)); }else{ assert( pPg->pPager==pPager ); rc = readDbPage(pPg); if( rc!=SQLITE_OK ){ | | < > | > | | > > > > | | | | < < | < < | 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 | memset(pPg->pData, 0, pPager->pageSize); } IOTRACE(("ZERO %p %d\n", pPager, pgno)); }else{ assert( pPg->pPager==pPager ); rc = readDbPage(pPg); if( rc!=SQLITE_OK ){ goto pager_acquire_err; } } #ifdef SQLITE_CHECK_PAGES pPg->pageHash = pager_pagehash(pPg); #endif } return SQLITE_OK; pager_acquire_err: assert( rc!=SQLITE_OK ); if( pPg ){ sqlite3PcacheDrop(pPg); } pagerUnlockIfUnused(pPager); *ppPage = 0; return rc; } /* ** 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. Also, return 0 if the ** pager is in PAGER_UNLOCK state when this function is called, ** or if the pager is in an error state other than SQLITE_FULL. ** ** See also sqlite3PagerGet(). The difference between this routine ** and sqlite3PagerGet() is that _get() will go to the disk and read ** in the page if the page is not already in cache. This routine ** returns NULL if the page is not in cache or if a disk I/O error ** has ever happened. */ DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){ PgHdr *pPg = 0; assert( pPager!=0 ); assert( pgno!=0 ); assert( pPager->pPCache!=0 ); assert( pPager->state > PAGER_UNLOCK ); sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &pPg); return pPg; } /* ** Release a page reference. ** ** If the number of references to the page drop to zero, then the |
︙ | ︙ | |||
4026 4027 4028 4029 4030 4031 4032 4033 4034 | */ static int pager_open_journal(Pager *pPager){ int rc = SQLITE_OK; /* Return code */ sqlite3_vfs * const pVfs = pPager->pVfs; /* Local cache of vfs pointer */ assert( pPager->state>=PAGER_RESERVED ); assert( pPager->useJournal ); assert( pPager->pInJournal==0 ); | > | > | | < | 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 | */ static int pager_open_journal(Pager *pPager){ int rc = SQLITE_OK; /* Return code */ sqlite3_vfs * const pVfs = pPager->pVfs; /* Local cache of vfs pointer */ assert( pPager->state>=PAGER_RESERVED ); assert( pPager->useJournal ); assert( pPager->journalMode!=PAGER_JOURNALMODE_OFF ); assert( pPager->pInJournal==0 ); /* If already in the error state, this function is a no-op. But on ** the other hand, this routine is never called if we are already in ** an error state. */ if( NEVER(pPager->errCode) ) return pPager->errCode; /* TODO: Is it really possible to get here with dbSizeValid==0? If not, ** the call to PagerPagecount() can be removed. */ testcase( pPager->dbSizeValid==0 ); sqlite3PagerPagecount(pPager, 0); |
︙ | ︙ | |||
4141 4142 4143 4144 4145 4146 4147 | rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); } } /* If the required locks were successfully obtained, open the journal ** file and write the first journal-header to it. */ | | < < > > > > > > > > > > | | < | | > > | | > > > | | > < | < | | | 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 | rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); } } /* If the required locks were successfully obtained, open the journal ** file and write the first journal-header to it. */ if( rc==SQLITE_OK && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){ rc = pager_open_journal(pPager); } }else if( isOpen(pPager->jfd) && pPager->journalOff==0 ){ /* This happens when the pager was in exclusive-access mode the last ** time a (read or write) transaction was successfully concluded ** by this connection. Instead of deleting the journal file it was ** kept open and either was truncated to 0 bytes or its header was ** overwritten with zeros. */ assert( pPager->nRec==0 ); assert( pPager->dbOrigSize==0 ); assert( pPager->pInJournal==0 ); rc = pager_open_journal(pPager); } PAGERTRACE(("TRANSACTION %d\n", PAGERID(pPager))); assert( !isOpen(pPager->jfd) || pPager->journalOff>0 || rc!=SQLITE_OK ); if( rc!=SQLITE_OK ){ assert( !pPager->dbModified ); /* Ignore any IO error that occurs within pager_end_transaction(). The ** purpose of this call is to reset the internal state of the pager ** sub-system. It doesn't matter if the journal-file is not properly ** finalized at this point (since it is not a valid journal file anyway). */ pager_end_transaction(pPager, 0); } return rc; } /* ** Mark a single data page as writeable. The page is written into the ** main journal or sub-journal as required. If the page is written into ** one of the journals, the corresponding bit is set in the ** Pager.pInJournal bitvec and the PagerSavepoint.pInSavepoint bitvecs ** of any open savepoints as appropriate. */ static int pager_write(PgHdr *pPg){ void *pData = pPg->pData; Pager *pPager = pPg->pPager; int rc = SQLITE_OK; /* This routine is not called unless a transaction has already been ** started. */ assert( pPager->state>=PAGER_RESERVED ); /* If an error has been previously detected, we should not be ** calling this routine. Repeat the error for robustness. */ if( NEVER(pPager->errCode) ) return pPager->errCode; /* Higher-level routines never call this function if database is not ** writable. But check anyway, just for robustness. */ if( NEVER(pPager->readOnly) ) return SQLITE_PERM; assert( !pPager->setMaster ); CHECK_PAGE(pPg); /* Mark the page as dirty. If the page has already been written ** to the journal then we can return right away. */ sqlite3PcacheMakeDirty(pPg); if( pageInJournal(pPg) && !subjRequiresPage(pPg) ){ pPager->dbModified = 1; }else{ /* If we get this far, it means that the page needs to be ** written to the transaction journal or the ckeckpoint journal ** or both. ** ** Higher level routines should have already started a transaction, ** which means they have acquired the necessary locks and opened ** a rollback journal. Double-check to makes sure this is the case. */ rc = sqlite3PagerBegin(pPager, 0, pPager->subjInMemory); if( NEVER(rc!=SQLITE_OK) ){ return rc; } if( !isOpen(pPager->jfd) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){ assert( pPager->useJournal ); rc = pager_open_journal(pPager); if( rc!=SQLITE_OK ) return rc; } pPager->dbModified = 1; /* The transaction journal now exists and we have a RESERVED or an ** EXCLUSIVE lock on the main database file. Write the current page to |
︙ | ︙ | |||
4390 4391 4392 4393 4394 4395 4396 | /* If the PGHDR_NEED_SYNC flag is set for any of the nPage pages ** starting at pg1, then it needs to be set for all of them. Because ** writing to any of these nPage pages may damage the others, the ** journal file must contain sync()ed copies of all of them ** before any of them can be written out to the database file. */ | | | | 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 | /* If the PGHDR_NEED_SYNC flag is set for any of the nPage pages ** starting at pg1, then it needs to be set for all of them. Because ** writing to any of these nPage pages may damage the others, the ** journal file must contain sync()ed copies of all of them ** before any of them can be written out to the database file. */ if( rc==SQLITE_OK && needSync ){ assert( !MEMDB && pPager->noSync==0 ); for(ii=0; ii<nPage; ii++){ PgHdr *pPage = pager_lookup(pPager, pg1+ii); if( pPage ){ pPage->flags |= PGHDR_NEED_SYNC; sqlite3PagerUnref(pPage); } } assert(pPager->needSync); |
︙ | ︙ | |||
4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 | */ #ifndef NDEBUG int sqlite3PagerIswriteable(DbPage *pPg){ return pPg->flags&PGHDR_DIRTY; } #endif /* ** A call to this routine tells the pager that it is not necessary to ** write the information on page pPg back to the disk, even though ** that page might be marked as dirty. This happens, for example, when ** the page has been added as a leaf of the freelist and so its ** content no longer matters. ** | > | 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 | */ #ifndef NDEBUG int sqlite3PagerIswriteable(DbPage *pPg){ return pPg->flags&PGHDR_DIRTY; } #endif #ifndef SQLITE_SECURE_DELETE /* ** A call to this routine tells the pager that it is not necessary to ** write the information on page pPg back to the disk, even though ** that page might be marked as dirty. This happens, for example, when ** the page has been added as a leaf of the freelist and so its ** content no longer matters. ** |
︙ | ︙ | |||
4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 | IOTRACE(("CLEAN %p %d\n", pPager, pPg->pgno)) pPg->flags |= PGHDR_DONT_WRITE; #ifdef SQLITE_CHECK_PAGES pPg->pageHash = pager_pagehash(pPg); #endif } } /* ** This routine is called to increment the value of the database file ** change-counter, stored as a 4-byte big-endian integer starting at ** byte offset 24 of the pager file. ** | > | | | | | > > | | > > | | < < > | | 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 | IOTRACE(("CLEAN %p %d\n", pPager, pPg->pgno)) pPg->flags |= PGHDR_DONT_WRITE; #ifdef SQLITE_CHECK_PAGES pPg->pageHash = pager_pagehash(pPg); #endif } } #endif /* !defined(SQLITE_SECURE_DELETE) */ /* ** This routine is called to increment the value of the database file ** change-counter, stored as a 4-byte big-endian integer starting at ** byte offset 24 of the pager file. ** ** If the isDirectMode flag is zero, then this is done by calling ** sqlite3PagerWrite() on page 1, then modifying the contents of the ** page data. In this case the file will be updated when the current ** transaction is committed. ** ** The isDirectMode flag may only be non-zero if the library was compiled ** with the SQLITE_ENABLE_ATOMIC_WRITE macro defined. In this case, ** if isDirect is non-zero, then the database file is updated directly ** by writing an updated version of page 1 using a call to the ** sqlite3OsWrite() function. */ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){ int rc = SQLITE_OK; /* Declare and initialize constant integer 'isDirect'. If the ** atomic-write optimization is enabled in this build, then isDirect ** is initialized to the value passed as the isDirectMode parameter ** to this function. Otherwise, it is always set to zero. ** ** The idea is that if the atomic-write optimization is not ** enabled at compile time, the compiler can omit the tests of ** 'isDirect' below, as well as the block enclosed in the ** "if( isDirect )" condition. */ #ifndef SQLITE_ENABLE_ATOMIC_WRITE # define DIRECT_MODE 0 assert( isDirectMode==0 ); UNUSED_PARAMETER(isDirectMode); #else # define DIRECT_MODE isDirectMode #endif assert( pPager->state>=PAGER_RESERVED ); if( !pPager->changeCountDone && pPager->dbSize>0 ){ PgHdr *pPgHdr; /* Reference to page 1 */ u32 change_counter; /* Initial value of change-counter field */ assert( !pPager->tempFile && isOpen(pPager->fd) ); /* Open page 1 of the file for writing. */ rc = sqlite3PagerGet(pPager, 1, &pPgHdr); assert( pPgHdr==0 || rc==SQLITE_OK ); /* If page one was fetched successfully, and this function is not ** operating in direct-mode, make page 1 writable. When not in ** direct mode, page 1 is always held in cache and hence the PagerGet() ** above is always successful - hence the ALWAYS on rc==SQLITE_OK. */ if( !DIRECT_MODE && ALWAYS(rc==SQLITE_OK) ){ rc = sqlite3PagerWrite(pPgHdr); } if( rc==SQLITE_OK ){ /* Increment the value just read and write it back to byte 24. */ change_counter = sqlite3Get4byte((u8*)pPager->dbFileVers); change_counter++; put32bits(((char*)pPgHdr->pData)+24, change_counter); /* If running in direct mode, write the contents of page 1 to the file. */ if( DIRECT_MODE ){ const void *zBuf = pPgHdr->pData; assert( pPager->dbFileSize>0 ); rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0); if( rc==SQLITE_OK ){ pPager->changeCountDone = 1; } }else{ pPager->changeCountDone = 1; } } /* Release the page reference. */ sqlite3PagerUnref(pPgHdr); } return rc; } /* ** Sync the pager file to disk. This is a no-op for in-memory files ** or pages with the Pager.noSync flag set. ** ** If successful, or 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){ int rc; /* Return code */ assert( !MEMDB ); if( pPager->noSync ){ rc = SQLITE_OK; }else{ rc = sqlite3OsSync(pPager->fd, pPager->sync_flags); } return rc; } |
︙ | ︙ | |||
4577 4578 4579 4580 4581 4582 4583 | 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 */ | | | | > > > > > | | > | < | 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 | 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 */ /* The dbOrigSize is never set if journal_mode=OFF */ assert( pPager->journalMode!=PAGER_JOURNALMODE_OFF || pPager->dbOrigSize==0 ); /* If a prior error occurred, this routine should not be called. ROLLBACK ** is the appropriate response to an error, not COMMIT. Guard against ** coding errors by repeating the prior error. */ if( NEVER(pPager->errCode) ) return pPager->errCode; PAGERTRACE(("DATABASE SYNC: File=%s zMaster=%s nSize=%d\n", pPager->zFilename, zMaster, pPager->dbSize)); if( MEMDB && pPager->dbModified ){ /* If this is an in-memory db, or no pages have been written to, or this ** function has already been called, it is mostly a no-op. However, any ** backup in progress needs to be restarted. */ sqlite3BackupRestart(pPager->pBackup); }else if( pPager->state!=PAGER_SYNCED && pPager->dbModified ){ /* The following block updates the change-counter. Exactly how it ** does this depends on whether or not the atomic-update optimization ** was enabled at compile time, and if this transaction meets the ** runtime criteria to use the operation: |
︙ | ︙ | |||
4649 4650 4651 4652 4653 4654 4655 4656 4657 | ** file. This can only happen in auto-vacuum mode. ** ** Before reading the pages with page numbers larger than the ** current value of Pager.dbSize, set dbSize back to the value ** that it took at the start of the transaction. Otherwise, the ** calls to sqlite3PagerGet() return zeroed pages instead of ** reading data from the database file. */ #ifndef SQLITE_OMIT_AUTOVACUUM | > > > | | | 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 | ** file. This can only happen in auto-vacuum mode. ** ** Before reading the pages with page numbers larger than the ** current value of Pager.dbSize, set dbSize back to the value ** that it took at the start of the transaction. Otherwise, the ** calls to sqlite3PagerGet() return zeroed pages instead of ** reading data from the database file. ** ** When journal_mode==OFF the dbOrigSize is always zero, so this ** block never runs if journal_mode=OFF. */ #ifndef SQLITE_OMIT_AUTOVACUUM if( pPager->dbSize<pPager->dbOrigSize && ALWAYS(pPager->journalMode!=PAGER_JOURNALMODE_OFF) ){ Pgno i; /* Iterator variable */ const Pgno iSkip = PAGER_MJ_PGNO(pPager); /* Pending lock page */ const Pgno dbSize = pPager->dbSize; /* Database image size */ pPager->dbSize = pPager->dbOrigSize; for( i=dbSize+1; i<=pPager->dbOrigSize; i++ ){ if( !sqlite3BitvecTest(pPager->pInJournal, i) && i!=iSkip ){ |
︙ | ︙ | |||
4714 4715 4716 4717 4718 4719 4720 | } IOTRACE(("DBSYNC %p\n", pPager)) pPager->state = PAGER_SYNCED; } commit_phase_one_exit: | < < < < < < < < | 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 | } IOTRACE(("DBSYNC %p\n", pPager)) pPager->state = PAGER_SYNCED; } commit_phase_one_exit: return rc; } /* ** When this function is called, the database file has been completely ** updated to reflect the changes made by the current transaction and |
︙ | ︙ | |||
4744 4745 4746 4747 4748 4749 4750 | ** ** If an error occurs, an IO error code is returned and the pager ** moves into the error state. Otherwise, SQLITE_OK is returned. */ int sqlite3PagerCommitPhaseTwo(Pager *pPager){ int rc = SQLITE_OK; /* Return code */ | | | > | < | | < < | 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 | ** ** If an error occurs, an IO error code is returned and the pager ** moves into the error state. Otherwise, SQLITE_OK is returned. */ 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; /* This function should not be called if the pager is not in at least ** PAGER_RESERVED state. And indeed SQLite never does this. But it is ** nice to have this defensive test here anyway. */ if( NEVER(pPager->state<PAGER_RESERVED) ) return SQLITE_ERROR; /* An optimization. If the database was not actually modified during ** this transaction, the pager is running in exclusive-mode and is ** using persistent journals, then this function is a no-op. ** ** The start of the journal file currently contains a single journal ** header with the nRec field set to 0. If such a journal is used as |
︙ | ︙ | |||
4950 4951 4952 4953 4954 4955 4956 | pPager->aSavepoint = aNew; pPager->nSavepoint = nSavepoint; /* Populate the PagerSavepoint structures just allocated. */ for(ii=nCurrent; ii<nSavepoint; ii++){ assert( pPager->dbSizeValid ); aNew[ii].nOrig = pPager->dbSize; | | > | 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 | pPager->aSavepoint = aNew; pPager->nSavepoint = nSavepoint; /* Populate the PagerSavepoint structures just allocated. */ for(ii=nCurrent; ii<nSavepoint; ii++){ assert( pPager->dbSizeValid ); aNew[ii].nOrig = pPager->dbSize; if( isOpen(pPager->jfd) && ALWAYS(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; } } /* Open the sub-journal, if it is not already opened. */ rc = openSubJournal(pPager); assertTruncateConstraint(pPager); } return rc; } /* ** This function is called to rollback or release (commit) a savepoint. |
︙ | ︙ | |||
5091 5092 5093 5094 5095 5096 5097 | 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); | | | 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 | 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); pPager->xCodec = pPager->memDb ? 0 : xCodec; pPager->xCodecSizeChng = xCodecSizeChng; pPager->xCodecFree = xCodecFree; pPager->pCodec = pCodec; pagerReportSize(pPager); } static void *sqlite3PagerGetCodec(Pager *pPager){ return pPager->pCodec; |
︙ | ︙ | |||
5219 5220 5221 5222 5223 5224 5225 | ** The sqlite3PagerGet() call may cause the journal to sync. So make ** sure the Pager.needSync flag is set too. */ PgHdr *pPgHdr; assert( pPager->needSync ); rc = sqlite3PagerGet(pPager, needSyncPgno, &pPgHdr); if( rc!=SQLITE_OK ){ | | | 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 | ** The sqlite3PagerGet() call may cause the journal to sync. So make ** sure the Pager.needSync flag is set too. */ PgHdr *pPgHdr; assert( pPager->needSync ); rc = sqlite3PagerGet(pPager, needSyncPgno, &pPgHdr); if( rc!=SQLITE_OK ){ if( needSyncPgno<=pPager->dbOrigSize ){ assert( pPager->pTmpSpace!=0 ); sqlite3BitvecClear(pPager->pInJournal, needSyncPgno, pPager->pTmpSpace); } return rc; } pPager->needSync = 1; assert( pPager->noSync==0 && !MEMDB ); |
︙ | ︙ | |||
5241 5242 5243 5244 5245 5246 5247 | ** to exist, in case the transaction needs to roll back. We allocate ** the page now, instead of at rollback, because we can better deal ** with an out-of-memory error now. Ticket #3761. */ if( MEMDB ){ DbPage *pNew; rc = sqlite3PagerAcquire(pPager, origPgno, &pNew, 1); | | > > > < | | 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 | ** to exist, in case the transaction needs to roll back. We allocate ** the page now, instead of at rollback, because we can better deal ** with an out-of-memory error now. Ticket #3761. */ if( MEMDB ){ DbPage *pNew; rc = sqlite3PagerAcquire(pPager, origPgno, &pNew, 1); if( rc!=SQLITE_OK ){ sqlite3PcacheMove(pPg, origPgno); return rc; } sqlite3PagerUnref(pNew); } return SQLITE_OK; } #endif /* ** Return a pointer to the data for the specified page. */ void *sqlite3PagerGetData(DbPage *pPg){ assert( pPg->nRef>0 || pPg->pPager->memDb ); return pPg->pData; } /* ** Return a pointer to the Pager.nExtra bytes of "extra" space ** allocated along with the specified page. */ void *sqlite3PagerGetExtra(DbPage *pPg){ return pPg->pExtra; } /* ** Get/set the locking-mode for this pager. Parameter eMode must be one ** of PAGER_LOCKINGMODE_QUERY, PAGER_LOCKINGMODE_NORMAL or ** PAGER_LOCKINGMODE_EXCLUSIVE. If the parameter is not _QUERY, then ** the locking-mode is set to the value specified. |
︙ | ︙ |
Changes to src/pager.h.
︙ | ︙ | |||
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 header file defines the interface that the sqlite page cache ** subsystem. The page cache subsystem reads and writes a file a page ** at a time and provides a journal for rollback. | < < | 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. ** ************************************************************************* ** This header file defines the interface that the sqlite page cache ** subsystem. The page cache subsystem reads and writes a file a page ** at a time and provides a journal for rollback. */ #ifndef _PAGER_H_ #define _PAGER_H_ /* ** Default maximum size for persistent journal files. A negative |
︙ | ︙ | |||
82 83 84 85 86 87 88 | /* ** The remainder of this file contains the declarations of the functions ** that make up the Pager sub-system API. See source code comments for ** a detailed description of each routine. */ /* Open and close a Pager connection. */ | | > > > > > > > > < | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | /* ** The remainder of this file contains the declarations of the functions ** that make up the Pager sub-system API. See source code comments for ** a detailed description of each routine. */ /* Open and close a Pager connection. */ int sqlite3PagerOpen( sqlite3_vfs*, Pager **ppPager, const char*, int, int, int, void(*)(DbPage*) ); int sqlite3PagerClose(Pager *pPager); int sqlite3PagerReadFileheader(Pager*, int, unsigned char*); /* Functions used to configure a Pager object. */ void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *); int sqlite3PagerSetPagesize(Pager*, u16*, int); int sqlite3PagerMaxPageCount(Pager*, int); void sqlite3PagerSetCachesize(Pager*, int); void sqlite3PagerSetSafetyLevel(Pager*,int,int); int sqlite3PagerLockingMode(Pager *, int); int sqlite3PagerJournalMode(Pager *, int); i64 sqlite3PagerJournalSizeLimit(Pager *, i64); |
︙ | ︙ | |||
122 123 124 125 126 127 128 129 130 131 132 133 134 135 | int sqlite3PagerBegin(Pager*, int exFlag, int); int sqlite3PagerCommitPhaseOne(Pager*,const char *zMaster, int); int sqlite3PagerSync(Pager *pPager); int sqlite3PagerCommitPhaseTwo(Pager*); int sqlite3PagerRollback(Pager*); int sqlite3PagerOpenSavepoint(Pager *pPager, int n); int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint); /* Functions used to query pager state and configuration. */ u8 sqlite3PagerIsreadonly(Pager*); int sqlite3PagerRefcount(Pager*); const char *sqlite3PagerFilename(Pager*); const sqlite3_vfs *sqlite3PagerVfs(Pager*); sqlite3_file *sqlite3PagerFile(Pager*); | > | 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | int sqlite3PagerBegin(Pager*, int exFlag, int); int sqlite3PagerCommitPhaseOne(Pager*,const char *zMaster, int); int sqlite3PagerSync(Pager *pPager); int sqlite3PagerCommitPhaseTwo(Pager*); int sqlite3PagerRollback(Pager*); int sqlite3PagerOpenSavepoint(Pager *pPager, int n); int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint); int sqlite3PagerSharedLock(Pager *pPager); /* Functions used to query pager state and configuration. */ u8 sqlite3PagerIsreadonly(Pager*); int sqlite3PagerRefcount(Pager*); const char *sqlite3PagerFilename(Pager*); const sqlite3_vfs *sqlite3PagerVfs(Pager*); sqlite3_file *sqlite3PagerFile(Pager*); |
︙ | ︙ |
Changes to src/parse.y.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** 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. | < < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains 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. |
︙ | ︙ | |||
192 193 194 195 196 197 198 | id(A) ::= INDEXED(X). {A = X;} // The following directive causes tokens ABORT, AFTER, ASC, etc. to // fallback to ID if they will not parse as their original value. // This obviates the need for the "id" nonterminal. // %fallback ID | | | | | 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | id(A) ::= INDEXED(X). {A = X;} // The following directive causes tokens ABORT, AFTER, ASC, etc. to // fallback to ID if they will not parse as their original value. // This obviates the need for the "id" nonterminal. // %fallback ID ABORT ACTION AFTER ANALYZE ASC ATTACH BEFORE BEGIN BY CASCADE CAST COLUMNKW CONFLICT DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH NO PLAN QUERY KEY OF OFFSET PRAGMA RAISE RELEASE REPLACE RESTRICT ROW ROLLBACK SAVEPOINT TEMP TRIGGER VACUUM VIEW VIRTUAL %ifdef SQLITE_OMIT_COMPOUND_SELECT EXCEPT INTERSECT UNION %endif SQLITE_OMIT_COMPOUND_SELECT REINDEX RENAME CTIME_KW IF . |
︙ | ︙ | |||
226 227 228 229 230 231 232 | %left GT LE LT GE. %right ESCAPE. %left BITAND BITOR LSHIFT RSHIFT. %left PLUS MINUS. %left STAR SLASH REM. %left CONCAT. %left COLLATE. | | | 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | %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. // And "ids" is an identifer-or-string. // %type ids {Token} ids(A) ::= ID|STRING(X). {A = X;} // The name of a column or table can be any of the following: |
︙ | ︙ | |||
310 311 312 313 314 315 316 | // The next group of rules parses the arguments to a REFERENCES clause // that determine if the referential integrity checking is deferred or // or immediate and which determine what action to take if a ref-integ // check fails. // %type refargs {int} | | < | | | | > | | 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 | // The next group of rules parses the arguments to a REFERENCES clause // that determine if the referential integrity checking is deferred or // or immediate and which determine what action to take if a ref-integ // check fails. // %type refargs {int} refargs(A) ::= . { A = OE_None*0x0101; /* EV: R-19803-45884 */} refargs(A) ::= refargs(X) refarg(Y). { A = (X & ~Y.mask) | Y.value; } %type refarg {struct {int value; int mask;}} refarg(A) ::= MATCH nm. { A.value = 0; A.mask = 0x000000; } refarg(A) ::= ON DELETE refact(X). { A.value = X; A.mask = 0x0000ff; } refarg(A) ::= ON UPDATE refact(X). { A.value = X<<8; A.mask = 0x00ff00; } %type refact {int} refact(A) ::= SET NULL. { A = OE_SetNull; /* EV: R-33326-45252 */} refact(A) ::= SET DEFAULT. { A = OE_SetDflt; /* EV: R-33326-45252 */} refact(A) ::= CASCADE. { A = OE_Cascade; /* EV: R-33326-45252 */} refact(A) ::= RESTRICT. { A = OE_Restrict; /* EV: R-33326-45252 */} refact(A) ::= NO ACTION. { A = OE_None; /* EV: R-33326-45252 */} %type defer_subclause {int} defer_subclause(A) ::= NOT DEFERRABLE init_deferred_pred_opt. {A = 0;} defer_subclause(A) ::= DEFERRABLE init_deferred_pred_opt(X). {A = X;} %type init_deferred_pred_opt {int} init_deferred_pred_opt(A) ::= . {A = 0;} init_deferred_pred_opt(A) ::= INITIALLY DEFERRED. {A = 1;} init_deferred_pred_opt(A) ::= INITIALLY IMMEDIATE. {A = 0;} // For the time being, the only constraint we care about is the primary |
︙ | ︙ | |||
358 359 360 361 362 363 364 | defer_subclause_opt(A) ::= . {A = 0;} defer_subclause_opt(A) ::= defer_subclause(X). {A = X;} // The following is a non-standard extension that allows us to declare the // default behavior when there is a constraint conflict. // %type onconf {int} | | | | 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 | defer_subclause_opt(A) ::= . {A = 0;} defer_subclause_opt(A) ::= defer_subclause(X). {A = X;} // The following is a non-standard extension that allows us to declare the // default behavior when there is a constraint conflict. // %type onconf {int} %type orconf {u8} %type resolvetype {int} onconf(A) ::= . {A = OE_Default;} onconf(A) ::= ON CONFLICT resolvetype(X). {A = X;} orconf(A) ::= . {A = OE_Default;} orconf(A) ::= OR resolvetype(X). {A = (u8)X;} resolvetype(A) ::= raisetype(X). {A = X;} resolvetype(A) ::= IGNORE. {A = OE_Ignore;} resolvetype(A) ::= REPLACE. {A = OE_Replace;} ////////////////////////// The DROP TABLE ///////////////////////////////////// // cmd ::= DROP TABLE ifexists(E) fullname(X). { |
︙ | ︙ | |||
500 501 502 503 504 505 506 | %ifndef SQLITE_OMIT_SUBQUERY seltablist(A) ::= stl_prefix(X) LP select(S) RP as(Z) on_opt(N) using_opt(U). { A = sqlite3SrcListAppendFromTerm(pParse,X,0,0,&Z,S,N,U); } seltablist(A) ::= stl_prefix(X) LP seltablist(F) RP as(Z) on_opt(N) using_opt(U). { | | < < | 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 | %ifndef SQLITE_OMIT_SUBQUERY seltablist(A) ::= stl_prefix(X) LP select(S) RP as(Z) on_opt(N) using_opt(U). { A = sqlite3SrcListAppendFromTerm(pParse,X,0,0,&Z,S,N,U); } seltablist(A) ::= stl_prefix(X) LP seltablist(F) RP as(Z) on_opt(N) using_opt(U). { if( X==0 && Z.n==0 && N==0 && U==0 ){ A = F; }else{ Select *pSubquery; sqlite3SrcListShiftJoinType(F); pSubquery = sqlite3SelectNew(pParse,0,F,0,0,0,0,0,0,0); A = sqlite3SrcListAppendFromTerm(pParse,X,0,0,&Z,pSubquery,N,U); } |
︙ | ︙ | |||
685 686 687 688 689 690 691 | VALUES LP itemlist(Y) RP. {sqlite3Insert(pParse, X, Y, 0, F, R);} cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F) select(S). {sqlite3Insert(pParse, X, 0, S, F, R);} cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F) DEFAULT VALUES. {sqlite3Insert(pParse, X, 0, 0, F, R);} | | | 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 | VALUES LP itemlist(Y) RP. {sqlite3Insert(pParse, X, Y, 0, F, R);} cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F) select(S). {sqlite3Insert(pParse, X, 0, S, F, R);} cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F) DEFAULT VALUES. {sqlite3Insert(pParse, X, 0, 0, F, R);} %type insert_cmd {u8} insert_cmd(A) ::= INSERT orconf(R). {A = R;} insert_cmd(A) ::= REPLACE. {A = OE_Replace;} %type itemlist {ExprList*} %destructor itemlist {sqlite3ExprListDelete(pParse->db, $$);} |
︙ | ︙ | |||
882 883 884 885 886 887 888 | pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0, 0); pOut->zStart = pOperand->zStart; pOut->zEnd = &pPostOp->z[pPostOp->n]; } } expr(A) ::= expr(X) ISNULL|NOTNULL(E). {spanUnaryPostfix(&A,pParse,@E,&X,&E);} | < > > > > > > > | | > > > > > > > > > > | 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 | pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0, 0); pOut->zStart = pOperand->zStart; pOut->zEnd = &pPostOp->z[pPostOp->n]; } } expr(A) ::= expr(X) ISNULL|NOTNULL(E). {spanUnaryPostfix(&A,pParse,@E,&X,&E);} expr(A) ::= expr(X) NOT NULL(E). {spanUnaryPostfix(&A,pParse,TK_NOTNULL,&X,&E);} // expr1 IS expr2 // expr1 IS NOT expr2 // // If expr2 is NULL then code as TK_ISNULL or TK_NOTNULL. If expr2 // is any other expression, code as TK_IS or TK_ISNOT. // expr(A) ::= expr(X) IS expr(Y). { spanBinaryExpr(&A,pParse,TK_IS,&X,&Y); if( pParse->db->mallocFailed==0 && Y.pExpr->op==TK_NULL ){ A.pExpr->op = TK_ISNULL; } } expr(A) ::= expr(X) IS NOT expr(Y). { spanBinaryExpr(&A,pParse,TK_ISNOT,&X,&Y); if( pParse->db->mallocFailed==0 && Y.pExpr->op==TK_NULL ){ A.pExpr->op = TK_NOTNULL; } } %include { /* Construct an expression node for a unary prefix operator */ static void spanUnaryPrefix( ExprSpan *pOut, /* Write the new expression node here */ Parse *pParse, /* Parsing context to record errors */ |
︙ | ︙ | |||
907 908 909 910 911 912 913 | } } expr(A) ::= NOT(B) expr(X). {spanUnaryPrefix(&A,pParse,@B,&X,&B);} expr(A) ::= BITNOT(B) expr(X). {spanUnaryPrefix(&A,pParse,@B,&X,&B);} | | | | 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 | } } expr(A) ::= NOT(B) expr(X). {spanUnaryPrefix(&A,pParse,@B,&X,&B);} expr(A) ::= BITNOT(B) expr(X). {spanUnaryPrefix(&A,pParse,@B,&X,&B);} expr(A) ::= MINUS(B) expr(X). [BITNOT] {spanUnaryPrefix(&A,pParse,TK_UMINUS,&X,&B);} expr(A) ::= PLUS(B) expr(X). [BITNOT] {spanUnaryPrefix(&A,pParse,TK_UPLUS,&X,&B);} %type between_op {int} between_op(A) ::= BETWEEN. {A = 0;} between_op(A) ::= NOT BETWEEN. {A = 1;} expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] { ExprList *pList = sqlite3ExprListAppend(pParse,0, X.pExpr); |
︙ | ︙ | |||
1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 | A = Y; } trigger_cmd_list(A) ::= trigger_cmd(X) SEMI. { assert( X!=0 ); X->pLast = X; A = X; } %type trigger_cmd {TriggerStep*} %destructor trigger_cmd {sqlite3DeleteTriggerStep(pParse->db, $$);} // UPDATE | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | | | | | | | 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 | A = Y; } trigger_cmd_list(A) ::= trigger_cmd(X) SEMI. { assert( X!=0 ); X->pLast = X; A = X; } // Disallow qualified table names on INSERT, UPDATE, and DELETE statements // within a trigger. The table to INSERT, UPDATE, or DELETE is always in // the same database as the table that the trigger fires on. // %type trnm {Token} trnm(A) ::= nm(X). {A = X;} trnm(A) ::= nm DOT nm(X). { A = X; sqlite3ErrorMsg(pParse, "qualified table names are not allowed on INSERT, UPDATE, and DELETE " "statements within triggers"); } // Disallow the INDEX BY and NOT INDEXED clauses on UPDATE and DELETE // statements within triggers. We make a specific error message for this // since it is an exception to the default grammar rules. // tridxby ::= . tridxby ::= INDEXED BY nm. { sqlite3ErrorMsg(pParse, "the INDEXED BY clause is not allowed on UPDATE or DELETE statements " "within triggers"); } tridxby ::= NOT INDEXED. { sqlite3ErrorMsg(pParse, "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements " "within triggers"); } %type trigger_cmd {TriggerStep*} %destructor trigger_cmd {sqlite3DeleteTriggerStep(pParse->db, $$);} // UPDATE trigger_cmd(A) ::= UPDATE orconf(R) trnm(X) tridxby SET setlist(Y) where_opt(Z). { A = sqlite3TriggerUpdateStep(pParse->db, &X, Y, Z, R); } // INSERT trigger_cmd(A) ::= insert_cmd(R) INTO trnm(X) inscollist_opt(F) VALUES LP itemlist(Y) RP. {A = sqlite3TriggerInsertStep(pParse->db, &X, F, Y, 0, R);} trigger_cmd(A) ::= insert_cmd(R) INTO trnm(X) inscollist_opt(F) select(S). {A = sqlite3TriggerInsertStep(pParse->db, &X, F, 0, S, R);} // DELETE trigger_cmd(A) ::= DELETE FROM trnm(X) tridxby where_opt(Y). {A = sqlite3TriggerDeleteStep(pParse->db, &X, Y);} // SELECT trigger_cmd(A) ::= select(X). {A = sqlite3TriggerSelectStep(pParse->db, X); } // The special RAISE expression that may occur in trigger programs expr(A) ::= RAISE(X) LP IGNORE RP(Y). { |
︙ | ︙ |
Changes to src/pcache.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 2008 August 05 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file implements that page cache. | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2008 August 05 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file implements that page cache. */ #include "sqliteInt.h" /* ** A complete page cache is an instance of this structure. */ struct PCache { |
︙ | ︙ | |||
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | int createFlag, /* If true, create page if it does not exist already */ PgHdr **ppPage /* Write the page here */ ){ PgHdr *pPage = 0; int eCreate; assert( pCache!=0 ); assert( pgno>0 ); /* If the pluggable cache (sqlite3_pcache*) has not been allocated, ** allocate it now. */ if( !pCache->pCache && createFlag ){ sqlite3_pcache *p; int nByte; nByte = pCache->szPage + pCache->szExtra + sizeof(PgHdr); p = sqlite3GlobalConfig.pcache.xCreate(nByte, pCache->bPurgeable); if( !p ){ return SQLITE_NOMEM; } sqlite3GlobalConfig.pcache.xCachesize(p, pCache->nMax); pCache->pCache = p; } | > | < < < | 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 | int createFlag, /* If true, create page if it does not exist already */ PgHdr **ppPage /* Write the page here */ ){ PgHdr *pPage = 0; int eCreate; assert( pCache!=0 ); assert( createFlag==1 || createFlag==0 ); assert( pgno>0 ); /* If the pluggable cache (sqlite3_pcache*) has not been allocated, ** allocate it now. */ if( !pCache->pCache && createFlag ){ sqlite3_pcache *p; int nByte; nByte = pCache->szPage + pCache->szExtra + sizeof(PgHdr); p = sqlite3GlobalConfig.pcache.xCreate(nByte, pCache->bPurgeable); if( !p ){ return SQLITE_NOMEM; } sqlite3GlobalConfig.pcache.xCachesize(p, pCache->nMax); pCache->pCache = p; } eCreate = createFlag * (1 + (!pCache->bPurgeable || !pCache->pDirty)); if( pCache->pCache ){ pPage = sqlite3GlobalConfig.pcache.xFetch(pCache->pCache, pgno, eCreate); } if( !pPage && eCreate==1 ){ PgHdr *pPg; |
︙ | ︙ | |||
466 467 468 469 470 471 472 473 | return result.pDirty; } /* ** Sort the list of pages in accending order by pgno. Pages are ** connected by pDirty pointers. The pDirtyPrev pointers are ** corrupted by this sort. */ | > > > > > | < < < < < < < | | | | | < < | 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 | return result.pDirty; } /* ** Sort the list of pages in accending order by pgno. Pages are ** connected by pDirty pointers. The pDirtyPrev pointers are ** corrupted by this sort. ** ** Since there cannot be more than 2^31 distinct pages in a database, ** there cannot be more than 31 buckets required by the merge sorter. ** One extra bucket is added to catch overflow in case something ** ever changes to make the previous sentence incorrect. */ #define N_SORT_BUCKET 32 static PgHdr *pcacheSortDirtyList(PgHdr *pIn){ PgHdr *a[N_SORT_BUCKET], *p; int i; memset(a, 0, sizeof(a)); while( pIn ){ p = pIn; pIn = p->pDirty; p->pDirty = 0; for(i=0; ALWAYS(i<N_SORT_BUCKET-1); i++){ if( a[i]==0 ){ a[i] = p; break; }else{ p = pcacheMergeDirtyList(a[i], p); a[i] = 0; } } if( NEVER(i==N_SORT_BUCKET-1) ){ /* To get here, there need to be 2^(N_SORT_BUCKET) elements in ** the input list. But that is impossible. */ a[i] = pcacheMergeDirtyList(a[i], p); } } p = a[0]; for(i=1; i<N_SORT_BUCKET; i++){ p = pcacheMergeDirtyList(p, a[i]); |
︙ | ︙ | |||
563 564 565 566 567 568 569 | void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){ pCache->nMax = mxPage; if( pCache->pCache ){ sqlite3GlobalConfig.pcache.xCachesize(pCache->pCache, mxPage); } } | | | 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 | void sqlite3PcacheSetCachesize(PCache *pCache, int mxPage){ pCache->nMax = mxPage; if( pCache->pCache ){ sqlite3GlobalConfig.pcache.xCachesize(pCache->pCache, mxPage); } } #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG) /* ** For all dirty pages currently in the cache, invoke the specified ** callback. This is only used if the SQLITE_CHECK_PAGES macro is ** defined. */ void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)){ PgHdr *pDirty; for(pDirty=pCache->pDirty; pDirty; pDirty=pDirty->pDirtyNext){ xIter(pDirty); } } #endif |
Changes to src/pcache.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2008 August 05 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite page cache ** subsystem. | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* ** 2008 August 05 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite page cache ** subsystem. */ #ifndef _PCACHE_H_ typedef struct PgHdr PgHdr; typedef struct PCache PCache; |
︙ | ︙ | |||
120 121 122 123 124 125 126 | void sqlite3PcacheRef(PgHdr*); int sqlite3PcachePageRefcount(PgHdr*); /* Return the total number of pages stored in the cache */ int sqlite3PcachePagecount(PCache*); | | | 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | void sqlite3PcacheRef(PgHdr*); int sqlite3PcachePageRefcount(PgHdr*); /* Return the total number of pages stored in the cache */ int sqlite3PcachePagecount(PCache*); #if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG) /* Iterate through all dirty pages currently stored in the cache. This ** interface is only available if SQLITE_CHECK_PAGES is defined when the ** library is built. */ void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *)); #endif |
︙ | ︙ |
Changes to src/pcache1.c.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ************************************************************************* ** ** This file implements the default page cache implementation (the ** sqlite3_pcache interface). It also contains part of the implementation ** of the SQLITE_CONFIG_PAGECACHE and sqlite3_release_memory() features. ** If the default page cache implementation is overriden, then neither of ** these two features are available. | < < | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ************************************************************************* ** ** This file implements the default page cache implementation (the ** sqlite3_pcache interface). It also contains part of the implementation ** of the SQLITE_CONFIG_PAGECACHE and sqlite3_release_memory() features. ** If the default page cache implementation is overriden, then neither of ** these two features are available. */ #include "sqliteInt.h" typedef struct PCache1 PCache1; typedef struct PgHdr1 PgHdr1; typedef struct PgFreeslot PgFreeslot; |
︙ | ︙ | |||
214 215 216 217 218 219 220 221 222 | p = 0; } return p; } /* ** Free a page object allocated by pcache1AllocPage(). */ static void pcache1FreePage(PgHdr1 *p){ | > > > > | | 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | p = 0; } return p; } /* ** Free a page object allocated by pcache1AllocPage(). ** ** The pointer is allowed to be NULL, which is prudent. But it turns out ** that the current implementation happens to never call this routine ** with a NULL pointer, so we mark the NULL test with ALWAYS(). */ static void pcache1FreePage(PgHdr1 *p){ if( ALWAYS(p) ){ if( p->pCache->bPurgeable ){ pcache1.nCurrentPage--; } pcache1Free(PGHDR1_TO_PAGE(p)); } } |
︙ | ︙ | |||
404 405 406 407 408 409 410 411 412 413 414 415 416 417 | } pcache1.isInit = 1; return SQLITE_OK; } /* ** Implementation of the sqlite3_pcache.xShutdown method. */ static void pcache1Shutdown(void *NotUsed){ UNUSED_PARAMETER(NotUsed); assert( pcache1.isInit!=0 ); memset(&pcache1, 0, sizeof(pcache1)); } | > > | 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 | } pcache1.isInit = 1; return SQLITE_OK; } /* ** Implementation of the sqlite3_pcache.xShutdown method. ** Note that the static mutex allocated in xInit does ** not need to be freed. */ static void pcache1Shutdown(void *NotUsed){ UNUSED_PARAMETER(NotUsed); assert( pcache1.isInit!=0 ); memset(&pcache1, 0, sizeof(pcache1)); } |
︙ | ︙ | |||
467 468 469 470 471 472 473 | /* ** Implementation of the sqlite3_pcache.xFetch method. ** ** Fetch a page by key value. ** ** Whether or not a new page may be allocated by this function depends on | | > > > > > > > | | < | 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 | /* ** Implementation of the sqlite3_pcache.xFetch method. ** ** Fetch a page by key value. ** ** Whether or not a new page may be allocated by this function depends on ** the value of the createFlag argument. 0 means do not allocate a new ** page. 1 means allocate a new page if space is easily available. 2 ** means to try really hard to allocate a new page. ** ** For a non-purgeable cache (a cache used as the storage for an in-memory ** database) there is really no difference between createFlag 1 and 2. So ** the calling function (pcache.c) will never have a createFlag of 1 on ** a non-purgable cache. ** ** There are three different approaches to obtaining space for a page, ** depending on the value of parameter createFlag (which may be 0, 1 or 2). ** ** 1. Regardless of the value of createFlag, the cache is searched for a ** copy of the requested page. If one is found, it is returned. ** ** 2. If createFlag==0 and the page is not already in the cache, NULL is ** returned. ** ** 3. If createFlag is 1, and the page is not already in the cache, ** and if either of the following are true, return NULL: ** ** (a) the number of pages pinned by the cache is greater than ** PCache1.nMax, or ** (b) the number of pages pinned by the cache is greater than ** the sum of nMax for all purgeable caches, less the sum of ** nMin for all other purgeable caches. ** |
︙ | ︙ | |||
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 | ** 5. Otherwise, allocate and return a new page buffer. */ static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){ unsigned int nPinned; PCache1 *pCache = (PCache1 *)p; PgHdr1 *pPage = 0; pcache1EnterMutex(); if( createFlag==1 ) sqlite3BeginBenignMalloc(); /* Search the hash table for an existing entry. */ if( pCache->nHash>0 ){ unsigned int h = iKey % pCache->nHash; for(pPage=pCache->apHash[h]; pPage&&pPage->iKey!=iKey; pPage=pPage->pNext); } if( pPage || createFlag==0 ){ pcache1PinPage(pPage); goto fetch_out; } /* Step 3 of header comment. */ nPinned = pCache->nPage - pCache->nRecyclable; | > | | 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 | ** 5. Otherwise, allocate and return a new page buffer. */ static void *pcache1Fetch(sqlite3_pcache *p, unsigned int iKey, int createFlag){ unsigned int nPinned; PCache1 *pCache = (PCache1 *)p; PgHdr1 *pPage = 0; assert( pCache->bPurgeable || createFlag!=1 ); pcache1EnterMutex(); if( createFlag==1 ) sqlite3BeginBenignMalloc(); /* Search the hash table for an existing entry. */ if( pCache->nHash>0 ){ unsigned int h = iKey % pCache->nHash; for(pPage=pCache->apHash[h]; pPage&&pPage->iKey!=iKey; pPage=pPage->pNext); } if( pPage || createFlag==0 ){ pcache1PinPage(pPage); goto fetch_out; } /* Step 3 of header comment. */ nPinned = pCache->nPage - pCache->nRecyclable; if( createFlag==1 && ( nPinned>=(pcache1.nMaxPage+pCache->nMin-pcache1.nMinPage) || nPinned>=(pCache->nMax * 9 / 10) )){ goto fetch_out; } if( pCache->nPage>=pCache->nHash && pcache1ResizeHash(pCache) ){ |
︙ | ︙ | |||
651 652 653 654 655 656 657 | *pp = pPage->pNext; h = iNew%pCache->nHash; pPage->iKey = iNew; pPage->pNext = pCache->apHash[h]; pCache->apHash[h] = pPage; | > > > > > > > | | 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 | *pp = pPage->pNext; h = iNew%pCache->nHash; pPage->iKey = iNew; pPage->pNext = pCache->apHash[h]; pCache->apHash[h] = pPage; /* The xRekey() interface is only used to move pages earlier in the ** database file (in order to move all free pages to the end of the ** file where they can be truncated off.) Hence, it is not possible ** for the new page number to be greater than the largest previously ** fetched page. But we retain the following test in case xRekey() ** begins to be used in different ways in the future. */ if( NEVER(iNew>pCache->iMaxKey) ){ pCache->iMaxKey = iNew; } pcache1LeaveMutex(); } /* |
︙ | ︙ |
Changes to src/pragma.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 2003 April 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 contains code used to implement the PRAGMA command. | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2003 April 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 contains code used to implement the PRAGMA command. */ #include "sqliteInt.h" /* Ignore this whole file if pragmas are disabled */ #if !defined(SQLITE_OMIT_PRAGMA) |
︙ | ︙ | |||
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | /* The following is VERY experimental */ { "writable_schema", SQLITE_WriteSchema|SQLITE_RecoveryMode }, { "omit_readlock", SQLITE_NoReadlock }, /* TODO: Maybe it shouldn't be possible to change the ReadUncommitted ** flag if there are any active statements. */ { "read_uncommitted", SQLITE_ReadUncommitted }, }; int i; const struct sPragmaType *p; for(i=0, p=aPragma; i<ArraySize(aPragma); i++, p++){ if( sqlite3StrICmp(zLeft, p->zName)==0 ){ sqlite3 *db = pParse->db; Vdbe *v; v = sqlite3GetVdbe(pParse); assert( v!=0 ); /* Already allocated by sqlite3Pragma() */ if( ALWAYS(v) ){ if( zRight==0 ){ returnSingleInt(pParse, p->zName, (db->flags & p->mask)!=0 ); }else{ if( getBoolean(zRight) ){ | > > > > > > > > > > > > > > | | > | | | > | | > | 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 | /* The following is VERY experimental */ { "writable_schema", SQLITE_WriteSchema|SQLITE_RecoveryMode }, { "omit_readlock", SQLITE_NoReadlock }, /* TODO: Maybe it shouldn't be possible to change the ReadUncommitted ** flag if there are any active statements. */ { "read_uncommitted", SQLITE_ReadUncommitted }, { "recursive_triggers", SQLITE_RecTriggers }, /* This flag may only be set if both foreign-key and trigger support ** are present in the build. */ #if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER) { "foreign_keys", SQLITE_ForeignKeys }, #endif }; int i; const struct sPragmaType *p; for(i=0, p=aPragma; i<ArraySize(aPragma); i++, p++){ if( sqlite3StrICmp(zLeft, p->zName)==0 ){ sqlite3 *db = pParse->db; Vdbe *v; v = sqlite3GetVdbe(pParse); assert( v!=0 ); /* Already allocated by sqlite3Pragma() */ if( ALWAYS(v) ){ if( zRight==0 ){ returnSingleInt(pParse, p->zName, (db->flags & p->mask)!=0 ); }else{ int mask = p->mask; /* Mask of bits to set or clear. */ if( db->autoCommit==0 ){ /* Foreign key support may not be enabled or disabled while not ** in auto-commit mode. */ mask &= ~(SQLITE_ForeignKeys); } if( getBoolean(zRight) ){ db->flags |= mask; }else{ db->flags &= ~mask; } /* 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. */ sqlite3VdbeAddOp2(v, OP_Expire, 0, 0); } } return 1; } } return 0; } #endif /* SQLITE_OMIT_FLAG_PRAGMAS */ /* ** Return a human-readable name for a constraint resolution action. */ #ifndef SQLITE_OMIT_FOREIGN_KEY static const char *actionName(u8 action){ const char *zName; switch( action ){ case OE_SetNull: zName = "SET NULL"; break; case OE_SetDflt: zName = "SET DEFAULT"; break; case OE_Cascade: zName = "CASCADE"; break; case OE_Restrict: zName = "RESTRICT"; break; default: zName = "NO ACTION"; assert( action==OE_None ); break; } return zName; } #endif /* ** Process a pragma statement. ** ** Pragmas are of this form: ** ** PRAGMA [database.]id [= value] |
︙ | ︙ | |||
314 315 316 317 318 319 320 | ** database file. The cache size is actually the absolute value of ** this memory location. The sign of meta-value 2 determines the ** synchronous setting. A negative value means synchronous is off ** and a positive value means synchronous is on. */ if( sqlite3StrICmp(zLeft,"default_cache_size")==0 ){ static const VdbeOpList getCacheSize[] = { | > | | | | | > | 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 | ** database file. The cache size is actually the absolute value of ** this memory location. The sign of meta-value 2 determines the ** synchronous setting. A negative value means synchronous is off ** and a positive value means synchronous is on. */ if( sqlite3StrICmp(zLeft,"default_cache_size")==0 ){ static const VdbeOpList getCacheSize[] = { { OP_Transaction, 0, 0, 0}, /* 0 */ { OP_ReadCookie, 0, 1, BTREE_DEFAULT_CACHE_SIZE}, /* 1 */ { OP_IfPos, 1, 7, 0}, { OP_Integer, 0, 2, 0}, { OP_Subtract, 1, 2, 1}, { OP_IfPos, 1, 7, 0}, { OP_Integer, 0, 1, 0}, /* 6 */ { OP_ResultRow, 1, 1, 0}, }; int addr; if( sqlite3ReadSchema(pParse) ) goto pragma_out; sqlite3VdbeUsesBtree(v, iDb); if( !zRight ){ sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cache_size", SQLITE_STATIC); pParse->nMem += 2; addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize); sqlite3VdbeChangeP1(v, addr, iDb); sqlite3VdbeChangeP1(v, addr+1, iDb); sqlite3VdbeChangeP1(v, addr+6, SQLITE_DEFAULT_CACHE_SIZE); }else{ int size = atoi(zRight); if( size<0 ) size = -size; sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3VdbeAddOp2(v, OP_Integer, size, 1); sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, 2, BTREE_DEFAULT_CACHE_SIZE); addr = sqlite3VdbeAddOp2(v, OP_IfPos, 2, 0); |
︙ | ︙ | |||
958 959 960 961 962 963 964 | sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "on_update", SQLITE_STATIC); sqlite3VdbeSetColName(v, 6, COLNAME_NAME, "on_delete", SQLITE_STATIC); sqlite3VdbeSetColName(v, 7, COLNAME_NAME, "match", SQLITE_STATIC); while(pFK){ int j; for(j=0; j<pFK->nCol; j++){ char *zCol = pFK->aCol[j].zCol; | | | | 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 | sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "on_update", SQLITE_STATIC); sqlite3VdbeSetColName(v, 6, COLNAME_NAME, "on_delete", SQLITE_STATIC); sqlite3VdbeSetColName(v, 7, COLNAME_NAME, "match", SQLITE_STATIC); while(pFK){ int j; for(j=0; j<pFK->nCol; j++){ char *zCol = pFK->aCol[j].zCol; char *zOnDelete = (char *)actionName(pFK->aAction[0]); char *zOnUpdate = (char *)actionName(pFK->aAction[1]); sqlite3VdbeAddOp2(v, OP_Integer, i, 1); sqlite3VdbeAddOp2(v, OP_Integer, j, 2); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pFK->zTo, 0); sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, pTab->aCol[pFK->aCol[j].iFrom].zName, 0); sqlite3VdbeAddOp4(v, zCol ? OP_String8 : OP_Null, 0, 5, 0, zCol, 0); sqlite3VdbeAddOp4(v, OP_String8, 0, 6, 0, zOnUpdate, 0); |
︙ | ︙ | |||
1298 1299 1300 1301 1302 1303 1304 | sqlite3VdbeChangeP1(v, addr, iDb); sqlite3VdbeChangeP1(v, addr+1, atoi(zRight)); sqlite3VdbeChangeP1(v, addr+2, iDb); sqlite3VdbeChangeP2(v, addr+2, iCookie); }else{ /* Read the specified cookie value */ static const VdbeOpList readCookie[] = { | > | > | | 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 | sqlite3VdbeChangeP1(v, addr, iDb); sqlite3VdbeChangeP1(v, addr+1, atoi(zRight)); sqlite3VdbeChangeP1(v, addr+2, iDb); sqlite3VdbeChangeP2(v, addr+2, iCookie); }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} }; int addr = sqlite3VdbeAddOpList(v, ArraySize(readCookie), readCookie); sqlite3VdbeChangeP1(v, addr, iDb); sqlite3VdbeChangeP1(v, addr+1, iDb); sqlite3VdbeChangeP3(v, addr+1, iCookie); sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT); } }else #endif /* SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS */ #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) |
︙ | ︙ |
Changes to src/prepare.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 the implementation of the sqlite3_prepare() ** interface, and routines that contribute to loading the database schema ** from disk. | < < | | | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the implementation of the sqlite3_prepare() ** interface, and routines that contribute to loading the database schema ** from disk. */ #include "sqliteInt.h" /* ** 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 && (db->flags & SQLITE_RecoveryMode)==0 ){ if( zObj==0 ) zObj = "?"; sqlite3SetString(pData->pzErrMsg, db, "malformed database schema (%s)", zObj); if( zExtra ){ *pData->pzErrMsg = sqlite3MAppendf(db, *pData->pzErrMsg, "%s - %s", *pData->pzErrMsg, zExtra); } } pData->rc = db->mallocFailed ? SQLITE_NOMEM : SQLITE_CORRUPT; } /* ** This is the callback routine for the code that initializes the |
︙ | ︙ | |||
76 77 78 79 80 81 82 83 84 85 86 | ** structures that describe the table, index, or view. */ char *zErr; int rc; assert( db->init.busy ); db->init.iDb = iDb; db->init.newTnum = atoi(argv[1]); rc = sqlite3_exec(db, argv[2], 0, 0, &zErr); db->init.iDb = 0; assert( rc!=SQLITE_OK || zErr==0 ); if( SQLITE_OK!=rc ){ | > > > > | | | | | > | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | ** structures that describe the table, index, or view. */ char *zErr; int rc; assert( db->init.busy ); db->init.iDb = iDb; db->init.newTnum = atoi(argv[1]); db->init.orphanTrigger = 0; rc = sqlite3_exec(db, argv[2], 0, 0, &zErr); db->init.iDb = 0; assert( rc!=SQLITE_OK || zErr==0 ); if( SQLITE_OK!=rc ){ if( db->init.orphanTrigger ){ assert( iDb==1 ); }else{ pData->rc = rc; if( rc==SQLITE_NOMEM ){ db->mallocFailed = 1; }else if( rc!=SQLITE_INTERRUPT && rc!=SQLITE_LOCKED ){ corruptSchema(pData, argv[0], zErr); } } sqlite3DbFree(db, zErr); } }else if( argv[0]==0 ){ corruptSchema(pData, 0, 0); }else{ /* If the SQL column is blank it means this is an index that |
︙ | ︙ | |||
124 125 126 127 128 129 130 | ** database. iDb==1 should never be used. iDb>=2 is used for ** auxiliary databases. Return one of the SQLITE_ error codes to ** indicate success or failure. */ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ int rc; int i; | < > | 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | ** database. iDb==1 should never be used. iDb>=2 is used for ** auxiliary databases. Return one of the SQLITE_ error codes to ** indicate success or failure. */ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ int rc; int i; int size; Table *pTab; Db *pDb; char const *azArg[4]; int meta[5]; InitData initData; char const *zMasterSchema; char const *zMasterName = SCHEMA_TABLE(iDb); int openedTransaction = 0; /* ** The master database table has a structure like this */ static const char master_schema[] = "CREATE TABLE sqlite_master(\n" " type text,\n" |
︙ | ︙ | |||
206 207 208 209 210 211 212 | pDb = &db->aDb[iDb]; if( pDb->pBt==0 ){ if( !OMIT_TEMPDB && ALWAYS(iDb==1) ){ DbSetProperty(db, 1, DB_SchemaLoaded); } return SQLITE_OK; } | < < < < | > > > > | | > > > > > | | < < < < | 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 | pDb = &db->aDb[iDb]; if( pDb->pBt==0 ){ if( !OMIT_TEMPDB && ALWAYS(iDb==1) ){ DbSetProperty(db, 1, DB_SchemaLoaded); } return SQLITE_OK; } /* 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); if( rc!=SQLITE_OK ){ sqlite3SetString(pzErrMsg, db, "%s", sqlite3ErrStr(rc)); goto initone_error_out; } openedTransaction = 1; } /* Get the database meta information. ** ** Meta values are as follows: ** meta[0] Schema cookie. Changes with each schema change. ** meta[1] File format of schema layer. ** meta[2] Size of the page cache. ** meta[3] Largest rootpage (auto/incr_vacuum mode) ** meta[4] Db text encoding. 1:UTF-8 2:UTF-16LE 3:UTF-16BE ** meta[5] User version ** meta[6] Incremental vacuum mode ** meta[7] unused ** meta[8] unused ** meta[9] unused ** ** Note: The #defined SQLITE_UTF* symbols in sqliteInt.h correspond to ** the possible values of meta[4]. */ for(i=0; i<ArraySize(meta); i++){ sqlite3BtreeGetMeta(pDb->pBt, i+1, (u32 *)&meta[i]); } pDb->pSchema->schema_cookie = meta[BTREE_SCHEMA_VERSION-1]; /* 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. |
︙ | ︙ | |||
352 353 354 355 356 357 358 | } /* Jump here for an error that occurs after successfully allocating ** curMain and calling sqlite3BtreeEnter(). For an error that occurs ** before that point, jump to error_out. */ initone_error_out: | > | < > | 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 | } /* Jump here for an error that occurs after successfully allocating ** curMain and calling sqlite3BtreeEnter(). For an error that occurs ** before that point, jump to error_out. */ initone_error_out: if( openedTransaction ){ sqlite3BtreeCommit(pDb->pBt); } sqlite3BtreeLeave(pDb->pBt); error_out: if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ db->mallocFailed = 1; } return rc; |
︙ | ︙ | |||
431 432 433 434 435 436 437 | } return rc; } /* ** Check schema cookies in all databases. If any cookie is out | | > > | < < | < | | < > | | | > > > > | | | > | < | | < | > > | > > | | | > > | < < < | | < | 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 | } return rc; } /* ** Check schema cookies in all databases. If any cookie is out ** of date set pParse->rc to SQLITE_SCHEMA. If all schema cookies ** make no changes to pParse->rc. */ static void schemaIsValid(Parse *pParse){ sqlite3 *db = pParse->db; int iDb; int rc; int cookie; assert( pParse->checkSchema ); assert( sqlite3_mutex_held(db->mutex) ); for(iDb=0; iDb<db->nDb; iDb++){ 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); if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ db->mallocFailed = 1; } 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 the in-memory schema representation, ** set Parse.rc to SQLITE_SCHEMA. */ sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&cookie); if( cookie!=db->aDb[iDb].pSchema->schema_cookie ){ 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 |
︙ | ︙ | |||
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 | ** 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. */ int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ ){ Parse *pParse; /* Parsing context */ char *zErrMsg = 0; /* Error message */ int rc = SQLITE_OK; /* Result code */ int i; /* Loop counter */ /* Allocate the parsing context */ pParse = sqlite3StackAllocZero(db, sizeof(*pParse)); if( pParse==0 ){ rc = SQLITE_NOMEM; goto end_prepare; } if( sqlite3SafetyOn(db) ){ rc = SQLITE_MISUSE; goto end_prepare; } assert( ppStmt && *ppStmt==0 ); assert( !db->mallocFailed ); | > > | 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 | ** 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. */ int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */ Vdbe *pReprepare, /* VM being reprepared */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ ){ Parse *pParse; /* Parsing context */ char *zErrMsg = 0; /* Error message */ int rc = SQLITE_OK; /* Result code */ int i; /* Loop counter */ /* Allocate the parsing context */ pParse = sqlite3StackAllocZero(db, sizeof(*pParse)); if( pParse==0 ){ rc = SQLITE_NOMEM; goto end_prepare; } pParse->pReprepare = pReprepare; if( sqlite3SafetyOn(db) ){ rc = SQLITE_MISUSE; goto end_prepare; } assert( ppStmt && *ppStmt==0 ); assert( !db->mallocFailed ); |
︙ | ︙ | |||
571 572 573 574 575 576 577 578 579 580 581 582 583 584 | (void)sqlite3SafetyOff(db); testcase( db->flags & SQLITE_ReadUncommitted ); goto end_prepare; } } } pParse->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 ); | > | 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 | (void)sqlite3SafetyOff(db); testcase( db->flags & SQLITE_ReadUncommitted ); goto end_prepare; } } } sqlite3VtabUnlockList(db); pParse->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 ); |
︙ | ︙ | |||
600 601 602 603 604 605 606 | sqlite3RunParser(pParse, zSql, &zErrMsg); } if( db->mallocFailed ){ pParse->rc = SQLITE_NOMEM; } if( pParse->rc==SQLITE_DONE ) pParse->rc = SQLITE_OK; | | | | 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 | sqlite3RunParser(pParse, zSql, &zErrMsg); } if( db->mallocFailed ){ pParse->rc = SQLITE_NOMEM; } if( pParse->rc==SQLITE_DONE ) pParse->rc = SQLITE_OK; if( pParse->checkSchema ){ schemaIsValid(pParse); } if( pParse->rc==SQLITE_SCHEMA ){ sqlite3ResetInternalSchema(db, 0); } if( db->mallocFailed ){ pParse->rc = SQLITE_NOMEM; } |
︙ | ︙ | |||
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 | if( zErrMsg ){ sqlite3Error(db, rc, "%s", zErrMsg); sqlite3DbFree(db, zErrMsg); }else{ sqlite3Error(db, rc, 0); } end_prepare: sqlite3StackFree(db, pParse); rc = sqlite3ApiExit(db, rc); assert( (rc&db->errMask)==rc ); return rc; } static int sqlite3LockAndPrepare( sqlite3 *db, /* Database handle. */ const char *zSql, /* UTF-8 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ ){ int rc; assert( ppStmt!=0 ); *ppStmt = 0; if( !sqlite3SafetyCheckOk(db) ){ return SQLITE_MISUSE; } sqlite3_mutex_enter(db->mutex); sqlite3BtreeEnterAll(db); | > > > > > > > > > | | | 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 | if( zErrMsg ){ sqlite3Error(db, rc, "%s", zErrMsg); sqlite3DbFree(db, zErrMsg); }else{ sqlite3Error(db, rc, 0); } /* Delete any TriggerPrg structures allocated while parsing this statement. */ while( pParse->pTriggerPrg ){ TriggerPrg *pT = pParse->pTriggerPrg; pParse->pTriggerPrg = pT->pNext; sqlite3VdbeProgramDelete(db, pT->pProgram, 0); sqlite3DbFree(db, pT); } end_prepare: sqlite3StackFree(db, pParse); rc = sqlite3ApiExit(db, rc); assert( (rc&db->errMask)==rc ); return rc; } static int sqlite3LockAndPrepare( sqlite3 *db, /* Database handle. */ const char *zSql, /* UTF-8 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */ Vdbe *pOld, /* VM being reprepared */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ ){ int rc; assert( ppStmt!=0 ); *ppStmt = 0; if( !sqlite3SafetyCheckOk(db) ){ return SQLITE_MISUSE; } sqlite3_mutex_enter(db->mutex); sqlite3BtreeEnterAll(db); rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail); if( rc==SQLITE_SCHEMA ){ sqlite3_finalize(*ppStmt); rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail); } sqlite3BtreeLeaveAll(db); sqlite3_mutex_leave(db->mutex); return rc; } /* |
︙ | ︙ | |||
712 713 714 715 716 717 718 | sqlite3 *db; assert( sqlite3_mutex_held(sqlite3VdbeDb(p)->mutex) ); zSql = sqlite3_sql((sqlite3_stmt *)p); assert( zSql!=0 ); /* Reprepare only called for prepare_v2() statements */ db = sqlite3VdbeDb(p); assert( sqlite3_mutex_held(db->mutex) ); | | | 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 | sqlite3 *db; assert( sqlite3_mutex_held(sqlite3VdbeDb(p)->mutex) ); zSql = sqlite3_sql((sqlite3_stmt *)p); assert( zSql!=0 ); /* Reprepare only called for prepare_v2() statements */ db = sqlite3VdbeDb(p); assert( sqlite3_mutex_held(db->mutex) ); rc = sqlite3LockAndPrepare(db, zSql, -1, 0, p, &pNew, 0); if( rc ){ if( rc==SQLITE_NOMEM ){ db->mallocFailed = 1; } assert( pNew==0 ); return (rc==SQLITE_LOCKED) ? SQLITE_LOCKED : SQLITE_SCHEMA; }else{ |
︙ | ︙ | |||
746 747 748 749 750 751 752 | sqlite3 *db, /* Database handle. */ const char *zSql, /* UTF-8 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ ){ int rc; | | | | 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 | sqlite3 *db, /* Database handle. */ const char *zSql, /* UTF-8 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ ){ int rc; rc = sqlite3LockAndPrepare(db,zSql,nBytes,0,0,ppStmt,pzTail); assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */ return rc; } int sqlite3_prepare_v2( sqlite3 *db, /* Database handle. */ const char *zSql, /* UTF-8 encoded SQL statement. */ int nBytes, /* Length of zSql in bytes. */ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */ const char **pzTail /* OUT: End of parsed string */ ){ int rc; rc = sqlite3LockAndPrepare(db,zSql,nBytes,1,0,ppStmt,pzTail); assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */ return rc; } #ifndef SQLITE_OMIT_UTF16 /* |
︙ | ︙ | |||
792 793 794 795 796 797 798 | *ppStmt = 0; if( !sqlite3SafetyCheckOk(db) ){ return SQLITE_MISUSE; } sqlite3_mutex_enter(db->mutex); zSql8 = sqlite3Utf16to8(db, zSql, nBytes); if( zSql8 ){ | | | 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 | *ppStmt = 0; if( !sqlite3SafetyCheckOk(db) ){ return SQLITE_MISUSE; } sqlite3_mutex_enter(db->mutex); zSql8 = sqlite3Utf16to8(db, zSql, nBytes); if( zSql8 ){ rc = sqlite3LockAndPrepare(db, zSql8, -1, saveSqlFlag, 0, ppStmt, &zTail8); } if( zTail8 && pzTail ){ /* If sqlite3_prepare returns a tail pointer, we calculate the ** equivalent pointer into the UTF-16 string by counting the unicode ** characters between zSql8 and zTail8, and then returning a pointer ** the same number of characters into the UTF-16 string. |
︙ | ︙ |
Changes to src/printf.c.
1 2 3 4 5 6 7 | /* ** The "printf" code that follows dates from the 1980's. It is in ** the public domain. The original comments are included here for ** completeness. They are very out-of-date but might be useful as ** an historical reference. Most of the "enhancements" have been backed ** out so that the functionality is now the same as standard printf(). ** | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /* ** The "printf" code that follows dates from the 1980's. It is in ** the public domain. The original comments are included here for ** completeness. They are very out-of-date but might be useful as ** an historical reference. Most of the "enhancements" have been backed ** out so that the functionality is now the same as standard printf(). ** ************************************************************************** ** ** The following modules is an enhanced replacement for the "printf" subroutines ** found in the standard C library. The following enhancements are ** supported: ** ** + Additional functions. The standard set of "printf" functions |
︙ | ︙ |
Changes to src/random.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** This file contains code to implement a pseudo-random number ** generator (PRNG) for SQLite. ** ** Random numbers are used by some of the database backends in order ** to generate random integer keys for tables or random filenames. | < < | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** ************************************************************************* ** This file contains code to implement a pseudo-random number ** generator (PRNG) for SQLite. ** ** Random numbers are used by some of the database backends in order ** to generate random integer keys for tables or random filenames. */ #include "sqliteInt.h" /* All threads share a single random number generator. ** This structure is the current state of the generator. */ |
︙ | ︙ |
Changes to src/resolve.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains routines used for walking the parser tree and ** resolve all identifiers by associating them with a particular ** table and column. | < < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains routines used for walking the parser tree and ** resolve all identifiers by associating them with a particular ** table and column. */ #include "sqliteInt.h" #include <stdlib.h> #include <string.h> /* ** Turn the pExpr expression into an alias for the iCol-th column of the |
︙ | ︙ | |||
133 134 135 136 137 138 139 140 141 142 143 144 145 146 | int cnt = 0; /* Number of matching column names */ int cntTab = 0; /* Number of matching table names */ 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 */ assert( pNC ); /* the name context cannot be NULL. */ assert( zCol ); /* The Z in X.Y.Z cannot be NULL */ assert( ~ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_Reduced) ); /* Initialize the node to no-match */ pExpr->iTable = -1; | > | 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | int cnt = 0; /* Number of matching column names */ int cntTab = 0; /* Number of matching table names */ 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 isTrigger = 0; assert( pNC ); /* the name context cannot be NULL. */ assert( zCol ); /* The Z in X.Y.Z cannot be NULL */ assert( ~ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_Reduced) ); /* Initialize the node to no-match */ pExpr->iTable = -1; |
︙ | ︙ | |||
218 219 220 221 222 223 224 | } } #ifndef SQLITE_OMIT_TRIGGER /* If we have not already resolved the name, then maybe ** it is a new.* or old.* trigger argument reference */ | | | | | | < | < | | < | < < < > > > | > | > > > > > > > > | > | | < < < | | > > | < | 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 | } } #ifndef SQLITE_OMIT_TRIGGER /* If we have not already resolved the name, then maybe ** it is a new.* or old.* trigger argument reference */ if( zDb==0 && zTab!=0 && cnt==0 && pParse->pTriggerTab!=0 ){ int op = pParse->eTriggerOp; Table *pTab = 0; 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; } if( pTab ){ int iCol; pSchema = pTab->pSchema; cntTab++; if( sqlite3IsRowid(zCol) ){ iCol = -1; }else{ for(iCol=0; iCol<pTab->nCol; iCol++){ Column *pCol = &pTab->aCol[iCol]; if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ if( iCol==pTab->iPKey ){ iCol = -1; } break; } } } if( iCol<pTab->nCol ){ cnt++; 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)); } pExpr->iColumn = (i16)iCol; pExpr->pTab = pTab; isTrigger = 1; } } } #endif /* !defined(SQLITE_OMIT_TRIGGER) */ /* ** Perhaps the name is a reference to the ROWID |
︙ | ︙ | |||
365 366 367 368 369 370 371 | /* Clean up and return */ sqlite3ExprDelete(db, pExpr->pLeft); pExpr->pLeft = 0; sqlite3ExprDelete(db, pExpr->pRight); pExpr->pRight = 0; | | > > > > > > > > > > > > > > > > > > > > > | 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 | /* Clean up and return */ sqlite3ExprDelete(db, pExpr->pLeft); pExpr->pLeft = 0; sqlite3ExprDelete(db, pExpr->pRight); pExpr->pRight = 0; pExpr->op = (isTrigger ? TK_TRIGGER : TK_COLUMN); lookupname_end: if( cnt==1 ){ assert( pNC!=0 ); sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList); /* Increment the nRef value on all name contexts from TopNC up to ** the point where the name matched. */ for(;;){ assert( pTopNC!=0 ); pTopNC->nRef++; if( pTopNC==pNC ) break; pTopNC = pTopNC->pNext; } return WRC_Prune; } else { return WRC_Abort; } } /* ** Allocate and return a pointer to an expression to load the column iCol ** from datasource iSrc datasource 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->pTab = pItem->pTab; p->iTable = pItem->iCursor; if( p->pTab->iPKey==iCol ){ p->iColumn = -1; }else{ p->iColumn = (ynVar)iCol; pItem->colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol); } ExprSetProperty(p, EP_Resolved); } return p; } /* ** This routine is callback for sqlite3WalkExpr(). ** ** Resolve symbolic names into TK_COLUMN operators for the current ** node in the expression tree. Return 0 to continue the search down ** the tree or 2 to abort the tree walk. |
︙ | ︙ |
Changes to src/rowset.c.
︙ | ︙ | |||
55 56 57 58 59 60 61 | ** batch number is O(NlogN) where N is the number of elements in the RowSet. ** The cost of a TEST using the same batch number is O(logN). The cost ** of the first SMALLEST is O(NlogN). Second and subsequent SMALLEST ** primitives are constant time. The cost of DESTROY is O(N). ** ** There is an added cost of O(N) when switching between TEST and ** SMALLEST primitives. | < < | 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | ** batch number is O(NlogN) where N is the number of elements in the RowSet. ** The cost of a TEST using the same batch number is O(logN). The cost ** of the first SMALLEST is O(NlogN). Second and subsequent SMALLEST ** primitives are constant time. The cost of DESTROY is O(N). ** ** There is an added cost of O(N) when switching between TEST and ** SMALLEST primitives. */ #include "sqliteInt.h" /* ** Target size for allocation chunks. */ |
︙ | ︙ |
Changes to src/select.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. | < < | 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 contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. */ #include "sqliteInt.h" /* ** Delete all the content of a Select structure but do not deallocate ** the select structure itself. |
︙ | ︙ | |||
188 189 190 191 192 193 194 | for(i=0; i<pTab->nCol; i++){ if( sqlite3StrICmp(pTab->aCol[i].zName, zCol)==0 ) return i; } return -1; } /* | > | > | < < < | | > | | | | | | < | < < | > > | | | < | | | | | < | | < < < | | | | | | | | 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 | for(i=0; i<pTab->nCol; i++){ if( sqlite3StrICmp(pTab->aCol[i].zName, zCol)==0 ) return i; } return -1; } /* ** 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 iSrc, /* Index of first table to join in pSrc */ int iColLeft, /* Index of column in first table */ 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( pSrc->nSrc>(iSrc+1) ); assert( pSrc->a[iSrc].pTab ); assert( pSrc->a[iSrc+1].pTab ); pE1 = sqlite3CreateColumnExpr(db, pSrc, iSrc, iColLeft); pE2 = sqlite3CreateColumnExpr(db, pSrc, iSrc+1, iColRight); pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2, 0); if( pEq && isOuterJoin ){ ExprSetProperty(pEq, EP_FromJoin); assert( !ExprHasAnyProperty(pEq, EP_TokenOnly|EP_Reduced) ); ExprSetIrreducible(pEq); 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. ** |
︙ | ︙ | |||
314 315 316 317 318 319 320 | 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<pLeftTab->nCol; j++){ char *zName = pLeftTab->aCol[j].zName; | | < | < | | 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 | 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<pLeftTab->nCol; j++){ char *zName = pLeftTab->aCol[j].zName; int iRightCol = columnIndex(pRightTab, zName); if( iRightCol>=0 ){ addWhereTerm(pParse, pSrc, i, j, iRightCol, isOuter, &p->pWhere); } } } /* Disallow both ON and USING clauses in the same join */ if( pRight->pOn && pRight->pUsing ){ |
︙ | ︙ | |||
351 352 353 354 355 356 357 | ** 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 = pList->a[j].zName; | | > > | < < | 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 | ** 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 = pList->a[j].zName; int iLeftCol = columnIndex(pLeftTab, zName); int iRightCol = columnIndex(pRightTab, zName); if( iLeftCol<0 || iRightCol<0 ){ sqlite3ErrorMsg(pParse, "cannot join using column %s - column " "not present in both tables", zName); return 1; } addWhereTerm(pParse, pSrc, i, iLeftCol, iRightCol, isOuter, &p->pWhere); } } } return 0; } /* |
︙ | ︙ | |||
762 763 764 765 766 767 768 769 770 | int eDest = pDest->eDest; int iParm = pDest->iParm; int regRow; int regRowid; iTab = pOrderBy->iECursor; if( eDest==SRT_Output || eDest==SRT_Coroutine ){ pseudoTab = pParse->nTab++; | > | > > > < < | 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 | int eDest = pDest->eDest; int iParm = pDest->iParm; int regRow; int regRowid; iTab = pOrderBy->iECursor; regRow = sqlite3GetTempReg(pParse); if( eDest==SRT_Output || eDest==SRT_Coroutine ){ pseudoTab = pParse->nTab++; sqlite3VdbeAddOp3(v, OP_OpenPseudo, pseudoTab, regRow, nColumn); regRowid = 0; }else{ regRowid = sqlite3GetTempReg(pParse); } addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); codeOffset(v, p, addrContinue); sqlite3VdbeAddOp3(v, OP_Column, iTab, pOrderBy->nExpr + 1, regRow); switch( eDest ){ case SRT_Table: case SRT_EphemTab: { testcase( eDest==SRT_Table ); testcase( eDest==SRT_EphemTab ); sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, regRowid); |
︙ | ︙ | |||
801 802 803 804 805 806 807 | } #endif default: { int i; assert( eDest==SRT_Output || eDest==SRT_Coroutine ); testcase( eDest==SRT_Output ); testcase( eDest==SRT_Coroutine ); | < < > > > | 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 | } #endif default: { int i; assert( eDest==SRT_Output || eDest==SRT_Coroutine ); testcase( eDest==SRT_Output ); testcase( eDest==SRT_Coroutine ); for(i=0; i<nColumn; i++){ assert( regRow!=pDest->iMem+i ); sqlite3VdbeAddOp3(v, OP_Column, pseudoTab, i, pDest->iMem+i); if( i==0 ){ sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE); } } if( eDest==SRT_Output ){ sqlite3VdbeAddOp2(v, OP_ResultRow, pDest->iMem, nColumn); sqlite3ExprCacheAffinityChange(pParse, pDest->iMem, nColumn); }else{ sqlite3VdbeAddOp1(v, OP_Yield, pDest->iParm); } |
︙ | ︙ | |||
889 890 891 892 893 894 895 | pS = pTabList->a[j].pSelect; }else{ pNC = pNC->pNext; } } if( pTab==0 ){ | < | > | | | < > | | > > > | > | > > | | | 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 | pS = pTabList->a[j].pSelect; }else{ pNC = pNC->pNext; } } if( pTab==0 ){ /* At one time, code such as "SELECT new.x" within a trigger would ** cause this condition to run. Since then, we have restructured how ** trigger code is generated and so this condition is no longer ** possible. However, it can still be true for statements like ** the following: ** ** CREATE TABLE t1(col INTEGER); ** SELECT (SELECT t1.col) FROM FROM t1; ** ** when columnType() is called on the expression "t1.col" in the ** sub-select. In this case, set the column type to NULL, even ** though it should really be "INTEGER". ** ** 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->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( ALWAYS(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; sNC.pNext = pNC; sNC.pParse = pNC->pParse; zType = columnType(&sNC, p, &zOriginDb, &zOriginTab, &zOriginCol); } }else if( ALWAYS(pTab->pSchema) ){ /* A real table */ assert( !pS ); if( iCol<0 ) iCol = pTab->iPKey; |
︙ | ︙ | |||
2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 | if( pExpr->iColumn<0 ){ pExpr->op = TK_NULL; }else{ Expr *pNew; assert( pEList!=0 && pExpr->iColumn<pEList->nExpr ); assert( pExpr->pLeft==0 && pExpr->pRight==0 ); pNew = sqlite3ExprDup(db, pEList->a[pExpr->iColumn].pExpr, 0); sqlite3ExprDelete(db, pExpr); pExpr = pNew; } }else{ pExpr->pLeft = substExpr(db, pExpr->pLeft, iTable, pEList); pExpr->pRight = substExpr(db, pExpr->pRight, iTable, pEList); if( ExprHasProperty(pExpr, EP_xIsSelect) ){ | > > > | 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 | if( pExpr->iColumn<0 ){ pExpr->op = TK_NULL; }else{ Expr *pNew; assert( pEList!=0 && pExpr->iColumn<pEList->nExpr ); assert( pExpr->pLeft==0 && pExpr->pRight==0 ); pNew = sqlite3ExprDup(db, pEList->a[pExpr->iColumn].pExpr, 0); if( pNew && pExpr->pColl ){ pNew->pColl = pExpr->pColl; } sqlite3ExprDelete(db, pExpr); pExpr = pNew; } }else{ pExpr->pLeft = substExpr(db, pExpr->pLeft, iTable, pEList); pExpr->pRight = substExpr(db, pExpr->pRight, iTable, pEList); if( ExprHasProperty(pExpr, EP_xIsSelect) ){ |
︙ | ︙ | |||
2727 2728 2729 2730 2731 2732 2733 | ** 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->nRef==1 ){ | > | | | 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 | ** 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->nRef==1 ){ Parse *pToplevel = sqlite3ParseToplevel(pParse); pTabToDel->pNextZombie = pToplevel->pZombieTab; pToplevel->pZombieTab = pTabToDel; }else{ pTabToDel->nRef--; } pSubitem->pTab = 0; } /* The following loop runs once for each term in a compound-subquery |
︙ | ︙ |
Changes to src/shell.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code to implement the "sqlite" command line ** utility for accessing SQLite databases. | < < | 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 contains code to implement the "sqlite" command line ** utility for accessing SQLite databases. */ #if defined(_WIN32) || defined(WIN32) /* This needs to come before any includes for MSVC compiler */ #define _CRT_SECURE_NO_WARNINGS #endif #include <stdlib.h> |
︙ | ︙ | |||
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | struct rusage sEnd; getrusage(RUSAGE_SELF, &sEnd); printf("CPU Time: user %f sys %f\n", timeDiff(&sBegin.ru_utime, &sEnd.ru_utime), timeDiff(&sBegin.ru_stime, &sEnd.ru_stime)); } } #define BEGIN_TIMER beginTimer() #define END_TIMER endTimer() #define HAS_TIMER 1 #else #define BEGIN_TIMER #define END_TIMER #define HAS_TIMER 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 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 | struct rusage sEnd; getrusage(RUSAGE_SELF, &sEnd); printf("CPU Time: user %f sys %f\n", timeDiff(&sBegin.ru_utime, &sEnd.ru_utime), timeDiff(&sBegin.ru_stime, &sEnd.ru_stime)); } } #define BEGIN_TIMER beginTimer() #define END_TIMER endTimer() #define HAS_TIMER 1 #elif (defined(_WIN32) || defined(WIN32)) #include <windows.h> /* Saved resource information for the beginning of an operation */ static HANDLE hProcess; static FILETIME ftKernelBegin; static FILETIME ftUserBegin; typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME, LPFILETIME); static GETPROCTIMES getProcessTimesAddr = NULL; /* True if the timer is enabled */ static int enableTimer = 0; /* ** 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 */ static void beginTimer(void){ if( enableTimer && getProcessTimesAddr ){ FILETIME ftCreation, ftExit; getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelBegin, &ftUserBegin); } } /* Return the difference of two FILETIME structs in seconds */ static double timeDiff(FILETIME *pStart, FILETIME *pEnd){ sqlite_int64 i64Start = *((sqlite_int64 *) pStart); sqlite_int64 i64End = *((sqlite_int64 *) pEnd); return (double) ((i64End - i64Start) / 10000000.0); } /* ** Print the timing results. */ static void endTimer(void){ if( enableTimer && getProcessTimesAddr){ FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd; getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelEnd, &ftUserEnd); printf("CPU Time: user %f sys %f\n", timeDiff(&ftUserBegin, &ftUserEnd), timeDiff(&ftKernelBegin, &ftKernelEnd)); } } #define BEGIN_TIMER beginTimer() #define END_TIMER endTimer() #define HAS_TIMER hasTimer() #else #define BEGIN_TIMER #define END_TIMER #define HAS_TIMER 0 #endif /* |
︙ | ︙ | |||
193 194 195 196 197 198 199 | "CREATE TABLE x(" \ "database," /* Name of database (i.e. main, temp etc.) */ \ "triggername," /* Name of trigger */ \ "dummy" /* Unused */ \ ")" typedef struct SchemaTable SchemaTable; | | | 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 | "CREATE TABLE x(" \ "database," /* Name of database (i.e. main, temp etc.) */ \ "triggername," /* Name of trigger */ \ "dummy" /* Unused */ \ ")" typedef struct SchemaTable SchemaTable; static struct SchemaTable { const char *zName; const char *zObject; const char *zPragma; const char *zSchema; } aSchemaTable[] = { { "table_info", "table", "PRAGMA %Q.table_info(%Q)", SCHEMA }, { "foreign_key_list", "table", "PRAGMA %Q.foreign_key_list(%Q)", SCHEMA2 }, |
︙ | ︙ | |||
650 651 652 653 654 655 656 | static int invokeCallback(void *p, int nArg, char **azArg, char **azCol){ GenfkeyCb *pCb = (GenfkeyCb *)p; UNUSED_PARAMETER(nArg); UNUSED_PARAMETER(azCol); return pCb->xData(pCb->pCtx, pCb->eType, azArg[0]); } | | | 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 | static int invokeCallback(void *p, int nArg, char **azArg, char **azCol){ GenfkeyCb *pCb = (GenfkeyCb *)p; UNUSED_PARAMETER(nArg); UNUSED_PARAMETER(azCol); return pCb->xData(pCb->pCtx, pCb->eType, azArg[0]); } static int detectSchemaProblem( sqlite3 *db, /* Database connection */ const char *zMessage, /* English language error message */ const char *zSql, /* SQL statement to run */ GenfkeyCb *pCb ){ sqlite3_stmt *pStmt; int rc; |
︙ | ︙ | |||
847 848 849 850 851 852 853 | */ "CREATE TRIGGER /name/_delete_referenced BEFORE DELETE ON /ref/ WHEN\n" " EXISTS (SELECT 1 FROM /tbl/ WHERE /cond2/)\n" "BEGIN\n" " /delete_action/\n" "END;\n" | | | 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 | */ "CREATE TRIGGER /name/_delete_referenced BEFORE DELETE ON /ref/ WHEN\n" " EXISTS (SELECT 1 FROM /tbl/ WHERE /cond2/)\n" "BEGIN\n" " /delete_action/\n" "END;\n" /* The "AFTER UPDATE ON <referenced>" trigger. This trigger's job ** is to detect when the key columns of a row in the referenced table ** to which one or more rows in the referencing table correspond are ** updated. The action taken depends on the value of the 'ON UPDATE' ** clause. */ "CREATE TRIGGER /name/_update_referenced AFTER\n" " UPDATE OF /fkey_list/ ON /ref/ WHEN \n" |
︙ | ︙ | |||
872 873 874 875 876 877 878 | ", '/on_update/', on_update" ", '/name/', 'genfkey' || min(rowid)" ", '/tbl/', dq(from_tbl)" ", '/ref/', dq(to_tbl)" ", '/key_notnull/', sj('new.' || dq(from_col) || ' IS NOT NULL', ' AND ')" | | | | | | | | 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 | ", '/on_update/', on_update" ", '/name/', 'genfkey' || min(rowid)" ", '/tbl/', dq(from_tbl)" ", '/ref/', dq(to_tbl)" ", '/key_notnull/', sj('new.' || dq(from_col) || ' IS NOT NULL', ' AND ')" ", '/fkey_list/', sj(dq(to_col), ', ')" ", '/rkey_list/', sj(dq(from_col), ', ')" ", '/cond1/', sj(multireplace('new./from/ == /to/'" ", '/from/', dq(from_col)" ", '/to/', dq(to_col)" "), ' AND ')" ", '/cond2/', sj(multireplace('old./to/ == /from/'" ", '/from/', dq(from_col)" ", '/to/', dq(to_col)" "), ' AND ')" ", '/update_action/', CASE on_update " "WHEN 'SET NULL' THEN " "multireplace('UPDATE /tbl/ SET /setlist/ WHERE /where/;' " ", '/setlist/', sj(dq(from_col)||' = NULL',', ')" ", '/tbl/', dq(from_tbl)" ", '/where/', sj(dq(from_col)||' = old.'||dq(to_col),' AND ')" ")" "WHEN 'CASCADE' THEN " "multireplace('UPDATE /tbl/ SET /setlist/ WHERE /where/;' " ", '/setlist/', sj(dq(from_col)||' = new.'||dq(to_col),', ')" ", '/tbl/', dq(from_tbl)" ", '/where/', sj(dq(from_col)||' = old.'||dq(to_col),' AND ')" ")" "ELSE " " 'SELECT RAISE(ABORT, ''constraint failed'');'" "END " ", '/delete_action/', CASE on_delete " "WHEN 'SET NULL' THEN " "multireplace('UPDATE /tbl/ SET /setlist/ WHERE /where/;' " ", '/setlist/', sj(dq(from_col)||' = NULL',', ')" ", '/tbl/', dq(from_tbl)" ", '/where/', sj(dq(from_col)||' = old.'||dq(to_col),' AND ')" ")" "WHEN 'CASCADE' THEN " "multireplace('DELETE FROM /tbl/ WHERE /where/;' " ", '/tbl/', dq(from_tbl)" ", '/where/', sj(dq(from_col)||' = old.'||dq(to_col),' AND ')" ")" "ELSE " |
︙ | ︙ | |||
1178 1179 1180 1181 1182 1183 1184 | /* ** An pointer to an instance of this structure is passed from ** the main program to the callback. This is used to communicate ** state and mode information. */ struct callback_data { | | > | 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 | /* ** An pointer to an instance of this structure is passed from ** the main program to the callback. This is used to communicate ** state and mode information. */ struct callback_data { sqlite3 *db; /* The database */ int echoOn; /* True to echo input commands */ int cnt; /* Number of records displayed so far */ FILE *out; /* Write results here */ int mode; /* An output mode setting */ int writableSchema; /* True if PRAGMA writable_schema=ON */ int showHeader; /* True to show column names in List or Column mode */ char *zDestTable; /* Name of destination table when MODE_Insert */ char separator[20]; /* Separator character for MODE_List */ 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 */ struct previous_mode_data explainPrev; /* Holds the mode information just before ** .explain ON */ char outfile[FILENAME_MAX]; /* Filename for *out */ const char *zDbFilename; /* name of the database file */ sqlite3_stmt *pStmt; /* Current statement if any. */ }; /* ** These are the allowed modes. */ #define MODE_Line 0 /* One column per line. Blank line between records */ #define MODE_Column 1 /* One record per line in neat columns */ |
︙ | ︙ | |||
1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 | ** lower 30 bits of a 32-bit signed integer. */ static int strlen30(const char *z){ const char *z2 = z; while( *z2 ){ z2++; } return 0x3fffffff & (int)(z2 - z); } /* ** Output the given string as a quoted string using SQL quoting conventions. */ static void output_quoted_string(FILE *out, const char *z){ int i; int nSingle = 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 | ** lower 30 bits of a 32-bit signed integer. */ static int strlen30(const char *z){ const char *z2 = z; while( *z2 ){ z2++; } return 0x3fffffff & (int)(z2 - z); } /* ** 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; fprintf(out,"X'"); for(i=0; i<nBlob; i++){ fprintf(out,"%02x",zBlob[i]); } fprintf(out,"'"); } /* ** Output the given string as a quoted string using SQL quoting conventions. */ static void output_quoted_string(FILE *out, const char *z){ int i; int nSingle = 0; |
︙ | ︙ | |||
1303 1304 1305 1306 1307 1308 1309 | /* ** Output the given string with characters that are special to ** HTML escaped. */ static void output_html_string(FILE *out, const char *z){ int i; while( *z ){ | | > > > > > > > > > > > > | 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 | /* ** Output the given string with characters that are special to ** HTML escaped. */ static void output_html_string(FILE *out, const char *z){ int i; while( *z ){ for(i=0; z[i] && z[i]!='<' && z[i]!='&' && z[i]!='>' && z[i]!='\"' && z[i]!='\''; i++){} if( i>0 ){ fprintf(out,"%.*s",i,z); } if( z[i]=='<' ){ fprintf(out,"<"); }else if( z[i]=='&' ){ fprintf(out,"&"); }else if( z[i]=='>' ){ fprintf(out,">"); }else if( z[i]=='\"' ){ fprintf(out,"""); }else if( z[i]=='\'' ){ fprintf(out,"'"); }else{ break; } z += i + 1; } } |
︙ | ︙ | |||
1390 1391 1392 1393 1394 1395 1396 | UNUSED_PARAMETER(NotUsed); seenInterrupt = 1; if( db ) sqlite3_interrupt(db); } #endif /* | | | > > > > > | 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 | UNUSED_PARAMETER(NotUsed); seenInterrupt = 1; if( db ) sqlite3_interrupt(db); } #endif /* ** This is the callback routine that the shell ** invokes for each row of a query result. */ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int *aiType){ int i; struct callback_data *p = (struct callback_data*)pArg; if( p->echoOn && p->cnt==0 && p->pStmt){ printf("%s\n", sqlite3_sql(p->pStmt)); } switch( p->mode ){ 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; |
︙ | ︙ | |||
1491 1492 1493 1494 1495 1496 1497 | } break; } case MODE_Html: { if( p->cnt++==0 && p->showHeader ){ fprintf(p->out,"<TR>"); for(i=0; i<nArg; i++){ | | > > | 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 | } break; } case MODE_Html: { if( p->cnt++==0 && p->showHeader ){ fprintf(p->out,"<TR>"); for(i=0; i<nArg; i++){ fprintf(p->out,"<TH>"); output_html_string(p->out, azCol[i]); fprintf(p->out,"</TH>\n"); } fprintf(p->out,"</TR>\n"); } if( azArg==0 ) break; fprintf(p->out,"<TR>"); for(i=0; i<nArg; i++){ fprintf(p->out,"<TD>"); |
︙ | ︙ | |||
1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 | for(i=0; i<nArg; i++){ output_csv(p, azArg[i], i<nArg-1); } fprintf(p->out,"\n"); break; } case MODE_Insert: { if( azArg==0 ) break; fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable); for(i=0; i<nArg; i++){ char *zSep = i>0 ? ",": ""; | > | > > > > > > > > > > > > > > > > > > > | 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 | for(i=0; i<nArg; i++){ output_csv(p, azArg[i], i<nArg-1); } fprintf(p->out,"\n"); break; } case MODE_Insert: { p->cnt++; if( azArg==0 ) break; fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable); for(i=0; i<nArg; i++){ char *zSep = i>0 ? ",": ""; if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){ fprintf(p->out,"%sNULL",zSep); }else if( aiType && aiType[i]==SQLITE_TEXT ){ if( zSep[0] ) fprintf(p->out,"%s",zSep); output_quoted_string(p->out, azArg[i]); }else if( aiType && (aiType[i]==SQLITE_INTEGER || aiType[i]==SQLITE_FLOAT) ){ fprintf(p->out,"%s%s",zSep, azArg[i]); }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); if( zSep[0] ) fprintf(p->out,"%s",zSep); output_hex_blob(p->out, pBlob, nBlob); }else if( isNumber(azArg[i], 0) ){ fprintf(p->out,"%s%s",zSep, azArg[i]); }else{ if( zSep[0] ) fprintf(p->out,"%s",zSep); output_quoted_string(p->out, azArg[i]); } } fprintf(p->out,");\n"); break; } } return 0; } /* ** This is the callback routine that the SQLite library ** invokes for each row of a query result. */ static int callback(void *pArg, int nArg, char **azArg, char **azCol){ /* since we don't have type info, call the shell_callback with a NULL value */ return shell_callback(pArg, nArg, azArg, azCol, NULL); } /* ** Set the destination table field of the callback_data structure to ** the name of the table given. Escape any quote characters in the ** table name. */ static void set_table_name(struct callback_data *p, const char *zName){ |
︙ | ︙ | |||
1581 1582 1583 1584 1585 1586 1587 | needQuote = 1; if( zName[i]=='\'' ) n++; } } if( needQuote ) n += 2; z = p->zDestTable = malloc( n+1 ); if( z==0 ){ | | | 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 | needQuote = 1; if( zName[i]=='\'' ) n++; } } if( needQuote ) n += 2; z = p->zDestTable = malloc( n+1 ); if( z==0 ){ fprintf(stderr,"Error: out of memory\n"); exit(1); } n = 0; if( needQuote ) z[n++] = '\''; for(i=0; zName[i]; i++){ z[n++] = zName[i]; if( zName[i]=='\'' ) z[n++] = '\''; |
︙ | ︙ | |||
1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 | zFirstRow = 0; } fprintf(out, "%s;\n", sqlite3_column_text(pSelect, 0)); rc = sqlite3_step(pSelect); } return sqlite3_finalize(pSelect); } /* ** This is a different callback routine used for dumping the database. ** Each row received by this callback consists of a table name, ** the table type ("index" or "table") and SQL to create the table. ** This routine should print text sufficient to recreate the table. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | zFirstRow = 0; } fprintf(out, "%s;\n", sqlite3_column_text(pSelect, 0)); rc = sqlite3_step(pSelect); } return sqlite3_finalize(pSelect); } /* ** 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_malloc(nErrMsg); if( zErrMsg ){ memcpy(zErrMsg, sqlite3_errmsg(db), nErrMsg); } return zErrMsg; } /* ** Execute a statement or set of statements. Print ** any result rows/columns depending on the current mode ** set via the supplied callback. ** ** This is very similar to SQLite's built-in sqlite3_exec() ** function except it takes a slightly different callback ** and callback data argument. */ static int shell_exec( sqlite3 *db, /* An open database */ const char *zSql, /* SQL to be evaluated */ int (*xCallback)(void*,int,char**,char**,int*), /* Callback function */ /* (not the same as sqlite3_exec) */ struct callback_data *pArg, /* Pointer to struct callback_data */ char **pzErrMsg /* Error msg written here */ ){ sqlite3_stmt *pStmt = NULL; int rc = SQLITE_OK; int rc2; const char *zLeftover; /* Tail of unprocessed SQL */ if( pzErrMsg ){ *pzErrMsg = NULL; } while( zSql[0] && (SQLITE_OK == rc) ){ 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; } /* 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 ){ /* if we have a callback... */ if( xCallback ){ /* allocate space for col name ptr, value ptr, and type */ int nCol = sqlite3_column_count(pStmt); void *pData = sqlite3_malloc(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; 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); } /* save off the prepared statment handle and reset row count */ if( pArg ){ pArg->pStmt = pStmt; pArg->cnt = 0; } do{ /* extract the data and data types */ for(i=0; i<nCol; i++){ azVals[i] = (char *)sqlite3_column_text(pStmt, i); aiTypes[i] = sqlite3_column_type(pStmt, i); if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){ rc = SQLITE_NOMEM; break; /* from for */ } } /* end for */ /* if data and types extracted successfully... */ if( SQLITE_ROW == rc ){ /* call the supplied callback with the result row data */ if( xCallback(pArg, nCol, azVals, azCols, aiTypes) ){ rc = SQLITE_ABORT; }else{ rc = sqlite3_step(pStmt); } } } while( SQLITE_ROW == rc ); sqlite3_free(pData); if( pArg ){ pArg->pStmt = NULL; } } }else{ do{ rc = sqlite3_step(pStmt); } while( rc == SQLITE_ROW ); } } /* if the last sqlite3_step() didn't complete successfully... */ if( (SQLITE_OK != rc) && (SQLITE_DONE != rc) ){ if( pzErrMsg ){ *pzErrMsg = save_err_msg(db); } }else{ rc = SQLITE_OK; } rc2 = sqlite3_finalize(pStmt); /* if the last sqlite3_finalize() didn't complete successfully ** AND we don't have a saved error from sqlite3_step ... */ if( (SQLITE_OK != rc2) && (SQLITE_OK == rc) ){ rc = rc2; if( pzErrMsg ){ *pzErrMsg = save_err_msg(db); } } if( SQLITE_OK == rc ){ zSql = zLeftover; while( isspace(zSql[0]) ) zSql++; } } } /* end while */ return rc; } /* ** This is a different callback routine used for dumping the database. ** Each row received by this callback consists of a table name, ** the table type ("index" or "table") and SQL to create the table. ** This routine should print text sufficient to recreate the table. |
︙ | ︙ | |||
1860 1861 1862 1863 1864 1865 1866 1867 1868 | ** Text of a help message */ static char zHelp[] = ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n" ".bail ON|OFF Stop after hitting an error. Default OFF\n" ".databases List names and files of attached databases\n" ".dump ?TABLE? ... Dump the database in an SQL text format\n" ".echo ON|OFF Turn command echo on or off\n" ".exit Exit this program\n" | > > | > | > > | 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 | ** Text of a help message */ static char zHelp[] = ".backup ?DB? FILE Backup DB (default \"main\") to FILE\n" ".bail ON|OFF Stop after hitting an error. Default OFF\n" ".databases List names and files of attached databases\n" ".dump ?TABLE? ... Dump the database in an SQL text format\n" " If TABLE specified, only dump tables matching\n" " LIKE pattern TABLE.\n" ".echo ON|OFF Turn command echo on or off\n" ".exit Exit this program\n" ".explain ?ON|OFF? Turn output mode suitable for EXPLAIN on or off.\n" " With no args, it turns EXPLAIN on.\n" #if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_SUBQUERY) ".genfkey ?OPTIONS? Options are:\n" " --no-drop: Do not drop old fkey triggers.\n" " --ignore-errors: Ignore tables with fkey errors\n" " --exec: Execute generated SQL immediately\n" " See file tool/genfkey.README in the source \n" " distribution for further information.\n" #endif ".header(s) ON|OFF Turn display of headers on or off\n" ".help Show this message\n" ".import FILE TABLE Import data from FILE into TABLE\n" ".indices ?TABLE? Show names of all indices\n" " If TABLE specified, only show indices for tables\n" " matching LIKE pattern TABLE.\n" #ifdef SQLITE_ENABLE_IOTRACE ".iotrace FILE Enable I/O diagnostic logging to FILE\n" #endif #ifndef SQLITE_OMIT_LOAD_EXTENSION ".load FILE ?ENTRY? Load an extension library\n" #endif ".mode MODE ?TABLE? Set output mode where MODE is one of:\n" |
︙ | ︙ | |||
1898 1899 1900 1901 1902 1903 1904 1905 1906 | ".output FILENAME Send output to FILENAME\n" ".output stdout Send output to the screen\n" ".prompt MAIN CONTINUE Replace the standard prompts\n" ".quit Exit this program\n" ".read FILENAME Execute SQL in FILENAME\n" ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n" ".schema ?TABLE? Show the CREATE statements\n" ".separator STRING Change separator used by output mode and .import\n" ".show Show the current values for various settings\n" | > > | > > > > | > < < | | 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 | ".output FILENAME Send output to FILENAME\n" ".output stdout Send output to the screen\n" ".prompt MAIN CONTINUE Replace the standard prompts\n" ".quit Exit this program\n" ".read FILENAME Execute SQL in FILENAME\n" ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n" ".schema ?TABLE? Show the CREATE statements\n" " If TABLE specified, only show tables matching\n" " LIKE pattern TABLE.\n" ".separator STRING Change separator used by output mode and .import\n" ".show Show the current values for various settings\n" ".tables ?TABLE? List names of tables\n" " If TABLE specified, only list tables matching\n" " LIKE pattern TABLE.\n" ".timeout MS Try opening locked tables for MS milliseconds\n" ".width NUM1 NUM2 ... Set column widths for \"column\" mode\n" ; static char zTimerHelp[] = ".timer ON|OFF Turn the CPU timer measurement on or off\n" ; /* Forward reference */ static int process_input(struct callback_data *p, FILE *in); /* ** 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(struct callback_data *p){ if( p->db==0 ){ sqlite3_open(p->zDbFilename, &p->db); db = p->db; if( db && sqlite3_errcode(db)==SQLITE_OK ){ sqlite3_create_function(db, "shellstatic", 0, SQLITE_UTF8, 0, shellstaticFunc, 0, 0); } if( db==0 || SQLITE_OK!=sqlite3_errcode(db) ){ fprintf(stderr,"Error: unable to open database \"%s\": %s\n", p->zDbFilename, sqlite3_errmsg(db)); exit(1); } #ifndef SQLITE_OMIT_LOAD_EXTENSION sqlite3_enable_load_extension(p->db, 1); #endif } |
︙ | ︙ | |||
2025 2026 2027 2028 2029 2030 2031 | if( zLine[i] ) zLine[i++] = 0; resolve_backslashes(azArg[nArg-1]); } } /* Process the input line. */ | | | < | | > | | > | > > > > | 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 | if( zLine[i] ) zLine[i++] = 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]; if( c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0 && nArg>1 && nArg<4){ const char *zDestFile; const char *zDb; sqlite3 *pDest; sqlite3_backup *pBackup; if( nArg==2 ){ zDestFile = azArg[1]; zDb = "main"; }else{ zDestFile = azArg[2]; zDb = azArg[1]; } rc = sqlite3_open(zDestFile, &pDest); if( rc!=SQLITE_OK ){ fprintf(stderr, "Error: cannot open \"%s\"\n", zDestFile); sqlite3_close(pDest); return 1; } open_db(p); pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb); if( pBackup==0 ){ fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest)); sqlite3_close(pDest); return 1; } while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){} sqlite3_backup_finish(pBackup); if( rc==SQLITE_DONE ){ rc = 0; }else{ fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest)); rc = 1; } sqlite3_close(pDest); }else if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 && nArg>1 && nArg<3 ){ bail_on_error = booleanValue(azArg[1]); }else if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 && nArg==1 ){ struct callback_data data; char *zErrMsg = 0; open_db(p); memcpy(&data, p, sizeof(data)); data.showHeader = 1; data.mode = MODE_Column; data.colWidth[0] = 3; data.colWidth[1] = 15; data.colWidth[2] = 58; data.cnt = 0; sqlite3_exec(p->db, "PRAGMA database_list; ", callback, &data, &zErrMsg); if( zErrMsg ){ fprintf(stderr,"Error: %s\n", zErrMsg); sqlite3_free(zErrMsg); rc = 1; } }else if( c=='d' && strncmp(azArg[0], "dump", n)==0 && nArg<3 ){ char *zErrMsg = 0; open_db(p); /* 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. */ fprintf(p->out, "PRAGMA foreign_keys=OFF;\n"); fprintf(p->out, "BEGIN TRANSACTION;\n"); p->writableSchema = 0; sqlite3_exec(p->db, "PRAGMA writable_schema=ON", 0, 0, 0); if( nArg==1 ){ run_schema_dump_query(p, "SELECT name, type, sql FROM sqlite_master " "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'", 0 |
︙ | ︙ | |||
2135 2136 2137 2138 2139 2140 2141 | fprintf(stderr,"Error: %s\n", zErrMsg); sqlite3_free(zErrMsg); }else{ fprintf(p->out, "COMMIT;\n"); } }else | | | | | 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 | fprintf(stderr,"Error: %s\n", zErrMsg); sqlite3_free(zErrMsg); }else{ fprintf(p->out, "COMMIT;\n"); } }else if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 && nArg<3 ){ p->echoOn = booleanValue(azArg[1]); }else if( c=='e' && strncmp(azArg[0], "exit", n)==0 && nArg==1 ){ rc = 2; }else if( c=='e' && strncmp(azArg[0], "explain", n)==0 && nArg<3 ){ int val = nArg>=2 ? booleanValue(azArg[1]) : 1; if(val == 1) { if(!p->explainPrev.valid) { p->explainPrev.valid = 1; p->explainPrev.mode = p->mode; p->explainPrev.showHeader = p->showHeader; memcpy(p->explainPrev.colWidth,p->colWidth,sizeof(p->colWidth)); |
︙ | ︙ | |||
2190 2191 2192 2193 2194 2195 2196 | cmd.pCb = p; genfkey_create_triggers(p->db, "main", (void *)&cmd, genfkeyCmdCb); } }else #endif if( c=='h' && (strncmp(azArg[0], "header", n)==0 || | | > > > | | < | | | > > > > < | < < > > | | > > > | | | > > | | > | | > | | | | > > > > > > > > > > > | | | | | | | | | | | > > > > > | > < | | | | | | | | | | | | < < < | < | > > > > > > > > > > > > > | > | | > | | < | | | > > | | 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 | cmd.pCb = p; genfkey_create_triggers(p->db, "main", (void *)&cmd, genfkeyCmdCb); } }else #endif if( c=='h' && (strncmp(azArg[0], "header", n)==0 || strncmp(azArg[0], "headers", n)==0) && nArg>1 && nArg<3 ){ p->showHeader = booleanValue(azArg[1]); }else if( c=='h' && strncmp(azArg[0], "help", n)==0 ){ fprintf(stderr,"%s",zHelp); if( HAS_TIMER ){ fprintf(stderr,"%s",zTimerHelp); } }else if( c=='i' && strncmp(azArg[0], "import", n)==0 && nArg==3 ){ char *zTable = azArg[2]; /* Insert data into this table */ char *zFile = azArg[1]; /* The file from which to extract data */ 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 nSep; /* Number of bytes in p->separator[] */ char *zSql; /* An SQL statement */ char *zLine; /* A single line of input from the file */ char **azCol; /* zLine[] broken up into columns */ char *zCommit; /* How to commit changes */ FILE *in; /* The input file */ int lineno = 0; /* Line number of input file */ open_db(p); nSep = strlen30(p->separator); if( nSep==0 ){ fprintf(stderr, "Error: non-null separator required for import\n"); return 1; } zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable); if( zSql==0 ){ fprintf(stderr, "Error: out of memory\n"); return 1; } nByte = strlen30(zSql); rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0); sqlite3_free(zSql); if( rc ){ if (pStmt) sqlite3_finalize(pStmt); fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db)); return 1; } nCol = sqlite3_column_count(pStmt); sqlite3_finalize(pStmt); pStmt = 0; if( nCol==0 ) return 0; /* no columns, no error */ zSql = malloc( nByte + 20 + nCol*2 ); if( zSql==0 ){ fprintf(stderr, "Error: out of memory\n"); return 1; } sqlite3_snprintf(nByte+20, zSql, "INSERT INTO '%q' VALUES(?", zTable); j = strlen30(zSql); for(i=1; i<nCol; i++){ zSql[j++] = ','; zSql[j++] = '?'; } zSql[j++] = ')'; zSql[j] = 0; rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0); free(zSql); if( rc ){ fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db)); if (pStmt) sqlite3_finalize(pStmt); return 1; } in = fopen(zFile, "rb"); if( in==0 ){ fprintf(stderr, "Error: cannot open \"%s\"\n", zFile); sqlite3_finalize(pStmt); return 1; } azCol = malloc( sizeof(azCol[0])*(nCol+1) ); if( azCol==0 ){ fprintf(stderr, "Error: out of memory\n"); fclose(in); sqlite3_finalize(pStmt); return 1; } sqlite3_exec(p->db, "BEGIN", 0, 0, 0); zCommit = "COMMIT"; while( (zLine = local_getline(0, in))!=0 ){ char *z; i = 0; lineno++; azCol[0] = zLine; for(i=0, z=zLine; *z && *z!='\n' && *z!='\r'; z++){ if( *z==p->separator[0] && strncmp(z, p->separator, nSep)==0 ){ *z = 0; i++; if( i<nCol ){ azCol[i] = &z[nSep]; z += nSep-1; } } } /* end for */ *z = 0; if( i+1!=nCol ){ fprintf(stderr, "Error: %s line %d: expected %d columns of data but found %d\n", zFile, lineno, nCol, i+1); zCommit = "ROLLBACK"; free(zLine); rc = 1; break; /* from while */ } for(i=0; i<nCol; i++){ sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC); } sqlite3_step(pStmt); rc = sqlite3_reset(pStmt); free(zLine); if( rc!=SQLITE_OK ){ fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db)); zCommit = "ROLLBACK"; rc = 1; break; /* from while */ } } /* end while */ free(azCol); fclose(in); sqlite3_finalize(pStmt); sqlite3_exec(p->db, zCommit, 0, 0, 0); }else if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg<3 ){ struct callback_data data; char *zErrMsg = 0; open_db(p); memcpy(&data, p, sizeof(data)); data.showHeader = 0; data.mode = MODE_List; if( nArg==1 ){ rc = sqlite3_exec(p->db, "SELECT name FROM sqlite_master " "WHERE type='index' AND name NOT LIKE 'sqlite_%' " "UNION ALL " "SELECT name FROM sqlite_temp_master " "WHERE type='index' " "ORDER BY 1", callback, &data, &zErrMsg ); }else{ zShellStatic = azArg[1]; rc = sqlite3_exec(p->db, "SELECT name FROM sqlite_master " "WHERE type='index' AND tbl_name LIKE shellstatic() " "UNION ALL " "SELECT name FROM sqlite_temp_master " "WHERE type='index' AND tbl_name LIKE shellstatic() " "ORDER BY 1", callback, &data, &zErrMsg ); zShellStatic = 0; } if( zErrMsg ){ fprintf(stderr,"Error: %s\n", zErrMsg); sqlite3_free(zErrMsg); rc = 1; }else if( rc != SQLITE_OK ){ fprintf(stderr,"Error: querying sqlite_master and sqlite_temp_master\n"); rc = 1; } }else #ifdef SQLITE_ENABLE_IOTRACE if( c=='i' && strncmp(azArg[0], "iotrace", n)==0 ){ extern void (*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 ){ fprintf(stderr, "Error: cannot open \"%s\"\n", azArg[1]); sqlite3IoTrace = 0; rc = 1; }else{ sqlite3IoTrace = iotracePrintf; } } }else #endif #ifndef SQLITE_OMIT_LOAD_EXTENSION if( c=='l' && strncmp(azArg[0], "load", n)==0 && nArg>=2 ){ const char *zFile, *zProc; char *zErrMsg = 0; zFile = azArg[1]; zProc = nArg>=3 ? azArg[2] : 0; open_db(p); rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg); if( rc!=SQLITE_OK ){ fprintf(stderr, "Error: %s\n", zErrMsg); sqlite3_free(zErrMsg); rc = 1; } }else #endif if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg==2 ){ int n2 = strlen30(azArg[1]); if( (n2==4 && strncmp(azArg[1],"line",n2)==0) || (n2==5 && strncmp(azArg[1],"lines",n2)==0) ){ p->mode = MODE_Line; }else if( (n2==6 && strncmp(azArg[1],"column",n2)==0) || (n2==7 && strncmp(azArg[1],"columns",n2)==0) ){ p->mode = MODE_Column; }else if( n2==4 && strncmp(azArg[1],"list",n2)==0 ){ p->mode = MODE_List; }else if( n2==4 && strncmp(azArg[1],"html",n2)==0 ){ p->mode = MODE_Html; }else if( n2==3 && strncmp(azArg[1],"tcl",n2)==0 ){ p->mode = MODE_Tcl; }else if( n2==3 && strncmp(azArg[1],"csv",n2)==0 ){ p->mode = MODE_Csv; sqlite3_snprintf(sizeof(p->separator), p->separator, ","); }else if( n2==4 && strncmp(azArg[1],"tabs",n2)==0 ){ p->mode = MODE_List; sqlite3_snprintf(sizeof(p->separator), p->separator, "\t"); }else if( n2==6 && strncmp(azArg[1],"insert",n2)==0 ){ p->mode = MODE_Insert; set_table_name(p, "table"); }else { fprintf(stderr,"Error: mode should be one of: " "column csv html insert line list tabs tcl\n"); rc = 1; } }else if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg==3 ){ int n2 = strlen30(azArg[1]); if( n2==6 && strncmp(azArg[1],"insert",n2)==0 ){ p->mode = MODE_Insert; set_table_name(p, azArg[2]); }else { fprintf(stderr, "Error: invalid arguments: " " \"%s\". Enter \".help\" for help\n", azArg[2]); rc = 1; } }else if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 && nArg==2 ) { sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue, "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]); }else if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){ if( p->out!=stdout ){ fclose(p->out); } if( strcmp(azArg[1],"stdout")==0 ){ p->out = stdout; sqlite3_snprintf(sizeof(p->outfile), p->outfile, "stdout"); }else{ p->out = fopen(azArg[1], "wb"); if( p->out==0 ){ fprintf(stderr,"Error: cannot write to \"%s\"\n", azArg[1]); p->out = stdout; rc = 1; } else { sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]); } } }else if( c=='p' && strncmp(azArg[0], "prompt", n)==0 && (nArg==2 || nArg==3)){ 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 && nArg==1 ){ rc = 2; }else if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 && nArg==2 ){ FILE *alt = fopen(azArg[1], "rb"); if( alt==0 ){ fprintf(stderr,"Error: cannot open \"%s\"\n", azArg[1]); rc = 1; }else{ rc = process_input(p, alt); fclose(alt); } }else if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 && nArg>1 && nArg<4){ const char *zSrcFile; const char *zDb; sqlite3 *pSrc; sqlite3_backup *pBackup; int nTimeout = 0; if( nArg==2 ){ zSrcFile = azArg[1]; zDb = "main"; }else{ zSrcFile = azArg[2]; zDb = azArg[1]; } rc = sqlite3_open(zSrcFile, &pSrc); if( rc!=SQLITE_OK ){ fprintf(stderr, "Error: cannot open \"%s\"\n", zSrcFile); sqlite3_close(pSrc); return 1; } open_db(p); pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main"); if( pBackup==0 ){ fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); sqlite3_close(pSrc); return 1; } while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK || rc==SQLITE_BUSY ){ if( rc==SQLITE_BUSY ){ if( nTimeout++ >= 3 ) break; sqlite3_sleep(100); } } sqlite3_backup_finish(pBackup); if( rc==SQLITE_DONE ){ rc = 0; }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){ fprintf(stderr, "Error: source database is busy\n"); rc = 1; }else{ fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); rc = 1; } sqlite3_close(pSrc); }else if( c=='s' && strncmp(azArg[0], "schema", n)==0 && nArg<3 ){ struct callback_data data; char *zErrMsg = 0; open_db(p); memcpy(&data, p, sizeof(data)); data.showHeader = 0; data.mode = MODE_Semi; if( nArg>1 ){ |
︙ | ︙ | |||
2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 | " rootpage integer,\n" " sql text\n" ")"; new_argv[1] = 0; new_colv[0] = "sql"; new_colv[1] = 0; callback(&data, 1, new_argv, new_colv); }else if( strcmp(azArg[1],"sqlite_temp_master")==0 ){ char *new_argv[2], *new_colv[2]; new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n" " type text,\n" " name text,\n" " tbl_name text,\n" " rootpage integer,\n" " sql text\n" ")"; new_argv[1] = 0; new_colv[0] = "sql"; new_colv[1] = 0; callback(&data, 1, new_argv, new_colv); }else{ zShellStatic = azArg[1]; | > > | | > > > > > > | | | | | | < > | > > > < < | | < | < | | | < | > | 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 | " rootpage integer,\n" " sql text\n" ")"; new_argv[1] = 0; new_colv[0] = "sql"; new_colv[1] = 0; callback(&data, 1, new_argv, new_colv); rc = SQLITE_OK; }else if( strcmp(azArg[1],"sqlite_temp_master")==0 ){ char *new_argv[2], *new_colv[2]; new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n" " type text,\n" " name text,\n" " tbl_name text,\n" " rootpage integer,\n" " sql text\n" ")"; new_argv[1] = 0; new_colv[0] = "sql"; new_colv[1] = 0; callback(&data, 1, new_argv, new_colv); rc = SQLITE_OK; }else{ zShellStatic = azArg[1]; rc = sqlite3_exec(p->db, "SELECT sql FROM " " (SELECT sql sql, type type, tbl_name tbl_name, name name" " FROM sqlite_master UNION ALL" " SELECT sql, type, tbl_name, name FROM sqlite_temp_master) " "WHERE tbl_name LIKE shellstatic() AND type!='meta' AND sql NOTNULL " "ORDER BY substr(type,2,1), name", callback, &data, &zErrMsg); zShellStatic = 0; } }else{ rc = sqlite3_exec(p->db, "SELECT sql FROM " " (SELECT sql sql, type type, tbl_name tbl_name, name name" " FROM sqlite_master UNION ALL" " SELECT sql, type, tbl_name, name FROM sqlite_temp_master) " "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%'" "ORDER BY substr(type,2,1), name", callback, &data, &zErrMsg ); } if( zErrMsg ){ fprintf(stderr,"Error: %s\n", zErrMsg); sqlite3_free(zErrMsg); rc = 1; }else if( rc != SQLITE_OK ){ fprintf(stderr,"Error: querying schema information\n"); rc = 1; }else{ rc = 0; } }else if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){ sqlite3_snprintf(sizeof(p->separator), p->separator, "%.*s", (int)sizeof(p->separator)-1, azArg[1]); }else if( c=='s' && strncmp(azArg[0], "show", n)==0 && nArg==1 ){ int i; fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off"); fprintf(p->out,"%9.9s: %s\n","explain", p->explainPrev.valid ? "on" :"off"); fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off"); fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]); fprintf(p->out,"%9.9s: ", "nullvalue"); output_c_string(p->out, p->nullvalue); fprintf(p->out, "\n"); fprintf(p->out,"%9.9s: %s\n","output", strlen30(p->outfile) ? p->outfile : "stdout"); fprintf(p->out,"%9.9s: ", "separator"); output_c_string(p->out, p->separator); fprintf(p->out, "\n"); fprintf(p->out,"%9.9s: ","width"); for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) { fprintf(p->out,"%d ",p->colWidth[i]); } fprintf(p->out,"\n"); }else if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 && nArg<3 ){ char **azResult; int nRow; char *zErrMsg; open_db(p); if( nArg==1 ){ rc = sqlite3_get_table(p->db, "SELECT name FROM sqlite_master " "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%' " "UNION ALL " "SELECT name FROM sqlite_temp_master " "WHERE type IN ('table','view') " "ORDER BY 1", &azResult, &nRow, 0, &zErrMsg ); }else{ zShellStatic = azArg[1]; rc = sqlite3_get_table(p->db, "SELECT name FROM sqlite_master " "WHERE type IN ('table','view') AND name LIKE shellstatic() " "UNION ALL " "SELECT name FROM sqlite_temp_master " "WHERE type IN ('table','view') AND name LIKE shellstatic() " "ORDER BY 1", &azResult, &nRow, 0, &zErrMsg ); zShellStatic = 0; } if( zErrMsg ){ fprintf(stderr,"Error: %s\n", zErrMsg); sqlite3_free(zErrMsg); rc = 1; }else if( rc != SQLITE_OK ){ fprintf(stderr,"Error: querying sqlite_master and sqlite_temp_master\n"); rc = 1; }else{ int len, maxlen = 0; int i, j; int nPrintCol, nPrintRow; for(i=1; i<=nRow; i++){ if( azResult[i]==0 ) continue; len = strlen30(azResult[i]); if( len>maxlen ) maxlen = len; } nPrintCol = 80/(maxlen+2); if( nPrintCol<1 ) nPrintCol = 1; nPrintRow = (nRow + nPrintCol - 1)/nPrintCol; for(i=0; i<nPrintRow; i++){ for(j=i+1; j<=nRow; j+=nPrintRow){ char *zSp = j<=nPrintRow ? "" : " "; printf("%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : ""); } printf("\n"); } } sqlite3_free_table(azResult); }else if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 && nArg==2 ){ open_db(p); sqlite3_busy_timeout(p->db, atoi(azArg[1])); }else if( HAS_TIMER && c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 && nArg==2 ){ enableTimer = booleanValue(azArg[1]); }else if( c=='w' && strncmp(azArg[0], "width", n)==0 && nArg>1 ){ int j; assert( nArg<=ArraySize(azArg) ); for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){ p->colWidth[j-1] = atoi(azArg[j]); } }else { fprintf(stderr, "Error: unknown command or invalid arguments: " " \"%s\". Enter \".help\" for help\n", azArg[0]); rc = 1; } return rc; } /* ** Return TRUE if a semicolon occurs anywhere in the first N characters |
︙ | ︙ | |||
2769 2770 2771 2772 2773 2774 2775 | break; /* We have reached EOF */ } if( seenInterrupt ){ if( in!=0 ) break; seenInterrupt = 0; } lineno++; | < > | | | | | | | | | | 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 | break; /* We have reached EOF */ } if( seenInterrupt ){ if( in!=0 ) break; seenInterrupt = 0; } lineno++; if( (zSql==0 || zSql[0]==0) && _all_whitespace(zLine) ) continue; if( zLine && zLine[0]=='.' && nSql==0 ){ if( p->echoOn ) printf("%s\n", zLine); rc = do_meta_command(zLine, p); if( rc==2 ){ /* exit requested */ break; }else if( rc ){ errCnt++; } continue; } if( _is_command_terminator(zLine) && _is_complete(zSql, nSql) ){ memcpy(zLine,";",2); } nSqlPrior = nSql; if( zSql==0 ){ int i; for(i=0; zLine[i] && isspace((unsigned char)zLine[i]); i++){} if( zLine[i]!=0 ){ nSql = strlen30(zLine); zSql = malloc( nSql+3 ); if( zSql==0 ){ fprintf(stderr, "Error: out of memory\n"); exit(1); } memcpy(zSql, zLine, nSql+1); startline = lineno; } }else{ int len = strlen30(zLine); zSql = realloc( zSql, nSql + len + 4 ); if( zSql==0 ){ fprintf(stderr,"Error: out of memory\n"); exit(1); } zSql[nSql++] = '\n'; memcpy(&zSql[nSql], zLine, len+1); nSql += len; } if( zSql && _contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior) && sqlite3_complete(zSql) ){ p->cnt = 0; open_db(p); BEGIN_TIMER; rc = shell_exec(p->db, zSql, shell_callback, p, &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 ){ fprintf(stderr, "%s %s\n", zPrefix, zErrMsg); sqlite3_free(zErrMsg); zErrMsg = 0; }else{ fprintf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db)); } errCnt++; } free(zSql); zSql = 0; nSql = 0; } } if( zSql ){ if( !_all_whitespace(zSql) ) fprintf(stderr, "Error: incomplete SQL: %s\n", zSql); free(zSql); } free(zLine); return errCnt; } /* |
︙ | ︙ | |||
2910 2911 2912 2913 2914 2915 2916 2917 | return home_dir; } /* ** Read input from the file given by sqliterc_override. Or if that ** parameter is NULL, take input from ~/.sqliterc */ | > > | > | | | | | | | > | 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 | 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 int process_sqliterc( struct callback_data *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 *in = NULL; int nBuf; int rc = 0; if (sqliterc == NULL) { home_dir = find_home_dir(); if( home_dir==0 ){ #if !defined(__RTP__) && !defined(_WRS_KERNEL) fprintf(stderr,"%s: Error: cannot locate your home directory\n", Argv0); #endif return 1; } nBuf = strlen30(home_dir) + 16; zBuf = malloc( nBuf ); if( zBuf==0 ){ fprintf(stderr,"%s: Error: out of memory\n",Argv0); return 1; } sqlite3_snprintf(nBuf, zBuf,"%s/.sqliterc",home_dir); free(home_dir); sqliterc = (const char*)zBuf; } in = fopen(sqliterc,"rb"); if( in ){ if( stdin_is_interactive ){ fprintf(stderr,"-- Loading resources from %s\n",sqliterc); } rc = process_input(p,in); fclose(in); } free(zBuf); return rc; } /* ** Show available command line options */ static const char zOptions[] = " -help show this message\n" " -init filename read/process named file\n" " -echo print commands before execution\n" " -[no]header turn headers on or off\n" " -bail stop after hitting an error\n" " -interactive force interactive I/O\n" " -batch force batch I/O\n" " -column set output mode to 'column'\n" |
︙ | ︙ | |||
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 | z = argv[i]; if( z[0]=='-' && z[1]=='-' ) z++; if( strcmp(argv[i],"-separator")==0 || strcmp(argv[i],"-nullvalue")==0 ){ i++; }else if( strcmp(argv[i],"-init")==0 ){ i++; zInitFile = argv[i]; } } if( i<argc ){ #if defined(SQLITE_OS_OS2) && SQLITE_OS_OS2 data.zDbFilename = (const char *)convertCpPathToUtf8( argv[i++] ); #else data.zDbFilename = argv[i++]; #endif }else{ #ifndef SQLITE_OMIT_MEMORYDB data.zDbFilename = ":memory:"; #else data.zDbFilename = 0; #endif } if( i<argc ){ zFirstCmd = argv[i++]; } data.out = stdout; #ifdef SQLITE_OMIT_MEMORYDB if( data.zDbFilename==0 ){ | > > > > > > > > > > > | | | > > > | 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 | z = argv[i]; if( z[0]=='-' && z[1]=='-' ) z++; if( strcmp(argv[i],"-separator")==0 || strcmp(argv[i],"-nullvalue")==0 ){ i++; }else if( strcmp(argv[i],"-init")==0 ){ i++; zInitFile = argv[i]; /* 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. */ }else if( strcmp(argv[i],"-batch")==0 ){ stdin_is_interactive = 0; } } if( i<argc ){ #if defined(SQLITE_OS_OS2) && SQLITE_OS_OS2 data.zDbFilename = (const char *)convertCpPathToUtf8( argv[i++] ); #else data.zDbFilename = argv[i++]; #endif }else{ #ifndef SQLITE_OMIT_MEMORYDB data.zDbFilename = ":memory:"; #else data.zDbFilename = 0; #endif } if( i<argc ){ zFirstCmd = argv[i++]; } if( i<argc ){ fprintf(stderr,"%s: Error: too many options: \"%s\"\n", Argv0, argv[i]); fprintf(stderr,"Use -help for a list of options.\n"); return 1; } data.out = stdout; #ifdef SQLITE_OMIT_MEMORYDB if( data.zDbFilename==0 ){ fprintf(stderr,"%s: Error: no database filename specified\n", Argv0); return 1; } #endif /* 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); } /* 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. */ rc = process_sqliterc(&data,zInitFile); if( rc>0 ){ return rc; } /* 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 && argv[i][0]=='-'; i++){ |
︙ | ︙ | |||
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 | }else if( strcmp(z,"-column")==0 ){ data.mode = MODE_Column; }else if( strcmp(z,"-csv")==0 ){ data.mode = MODE_Csv; memcpy(data.separator,",",2); }else if( strcmp(z,"-separator")==0 ){ i++; sqlite3_snprintf(sizeof(data.separator), data.separator, "%.*s",(int)sizeof(data.separator)-1,argv[i]); }else if( strcmp(z,"-nullvalue")==0 ){ i++; sqlite3_snprintf(sizeof(data.nullvalue), data.nullvalue, "%.*s",(int)sizeof(data.nullvalue)-1,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 ){ data.echoOn = 1; }else if( strcmp(z,"-bail")==0 ){ bail_on_error = 1; }else if( strcmp(z,"-version")==0 ){ printf("%s\n", sqlite3_libversion()); 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,"-help")==0 || strcmp(z, "--help")==0 ){ usage(1); }else{ | > > > > > > > > > > | | | < | | | > > > | | 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 | }else if( strcmp(z,"-column")==0 ){ data.mode = MODE_Column; }else if( strcmp(z,"-csv")==0 ){ data.mode = MODE_Csv; memcpy(data.separator,",",2); }else if( strcmp(z,"-separator")==0 ){ i++; if(i>=argc){ fprintf(stderr,"%s: Error: missing argument for option: %s\n", Argv0, z); fprintf(stderr,"Use -help for a list of options.\n"); return 1; } sqlite3_snprintf(sizeof(data.separator), data.separator, "%.*s",(int)sizeof(data.separator)-1,argv[i]); }else if( strcmp(z,"-nullvalue")==0 ){ i++; if(i>=argc){ fprintf(stderr,"%s: Error: missing argument for option: %s\n", Argv0, z); fprintf(stderr,"Use -help for a list of options.\n"); return 1; } sqlite3_snprintf(sizeof(data.nullvalue), data.nullvalue, "%.*s",(int)sizeof(data.nullvalue)-1,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 ){ data.echoOn = 1; }else if( strcmp(z,"-bail")==0 ){ bail_on_error = 1; }else if( strcmp(z,"-version")==0 ){ printf("%s\n", sqlite3_libversion()); 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,"-help")==0 || strcmp(z, "--help")==0 ){ usage(1); }else{ fprintf(stderr,"%s: Error: unknown option: %s\n", Argv0, z); fprintf(stderr,"Use -help for a list of options.\n"); return 1; } } if( zFirstCmd ){ /* Run just the command that follows the database name */ if( zFirstCmd[0]=='.' ){ rc = do_meta_command(zFirstCmd, &data); return rc; }else{ open_db(&data); rc = shell_exec(data.db, zFirstCmd, shell_callback, &data, &zErrMsg); if( zErrMsg!=0 ){ fprintf(stderr,"Error: %s\n", zErrMsg); return rc!=0 ? rc : 1; }else if( rc!=0 ){ fprintf(stderr,"Error: unable to process SQL \"%s\"\n", zFirstCmd); return rc; } } }else{ /* Run commands received from standard input */ if( stdin_is_interactive ){ char *zHome; |
︙ | ︙ | |||
3175 3176 3177 3178 3179 3180 3181 | }else{ rc = process_input(&data, stdin); } } set_table_name(&data, 0); if( db ){ if( sqlite3_close(db)!=SQLITE_OK ){ | | > | 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 | }else{ rc = process_input(&data, stdin); } } set_table_name(&data, 0); if( db ){ if( sqlite3_close(db)!=SQLITE_OK ){ fprintf(stderr,"Error: cannot close database \"%s\"\n", sqlite3_errmsg(db)); rc++; } } return rc; } |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** or constant definition does not appear in this file, then it is ** not a published API of SQLite, is subject to change without ** notice, and should not be referenced by programs that use SQLite. ** ** Some of the definitions that are in this file are marked as ** "experimental". Experimental interfaces are normally new ** features recently added to SQLite. We do not anticipate changes | | | < < | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | ** or constant definition does not appear in this file, then it is ** not a published API of SQLite, is subject to change without ** notice, and should not be referenced by programs that use SQLite. ** ** Some of the definitions that are in this file are marked as ** "experimental". Experimental interfaces are normally new ** features recently added to SQLite. We do not anticipate changes ** to experimental interfaces but reserve the right to make minor changes ** if experience from use "in the wild" suggest such changes are prudent. ** ** The official C-language API documentation for SQLite is derived ** from comments in this file. This file is the authoritative source ** on how SQLite interfaces are suppose to operate. ** ** The name of this file under configuration management is "sqlite.h.in". ** The makefile makes some minor changes to this file (such as inserting ** the version number) and changes its name to "sqlite3.h" as ** part of the build process. */ #ifndef _SQLITE3_H_ #define _SQLITE3_H_ #include <stdarg.h> /* Needed for the definition of va_list */ /* ** Make sure we can call this stuff from C++. |
︙ | ︙ | |||
50 51 52 53 54 55 56 | #ifndef SQLITE_EXTERN # define SQLITE_EXTERN extern #endif /* ** These no-op macros are used in front of interfaces to mark those ** interfaces as either deprecated or experimental. New applications | | | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | #ifndef SQLITE_EXTERN # define SQLITE_EXTERN extern #endif /* ** These no-op macros are used in front of interfaces to mark those ** interfaces as either deprecated or experimental. New applications ** should not use deprecated interfaces - they are support for backwards ** compatibility only. Application writers should be aware that ** experimental interfaces are subject to change in point releases. ** ** These macros used to resolve to various kinds of compiler magic that ** would generate warning messages when they were used. But that ** compiler magic ended up generating such a flurry of bug reports ** that we have taken it all out and gone back to using simple |
︙ | ︙ | |||
80 81 82 83 84 85 86 | /* ** CAPI3REF: Compile-Time Library Version Numbers {H10010} <S60100> ** ** The SQLITE_VERSION and SQLITE_VERSION_NUMBER #defines in ** the sqlite3.h file specify the version of SQLite with which ** that header file is associated. ** | | < | | | | | > > > > > > > > > > > > > > > > | > > | | > | | | > > | > > > | > | > | > > > > > | | | 78 79 80 81 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 | /* ** CAPI3REF: Compile-Time Library Version Numbers {H10010} <S60100> ** ** The SQLITE_VERSION and SQLITE_VERSION_NUMBER #defines in ** the sqlite3.h file specify the version of SQLite with which ** that header file is associated. ** ** The "version" of SQLite is a string of the form "W.X.Y" or "W.X.Y.Z". ** The W value is major version number and is always 3 in SQLite3. ** The W value only changes when backwards compatibility is ** broken and we intend to never break backwards compatibility. ** The X value is the minor version number and only changes when ** there are major feature enhancements that are forwards compatible ** but not backwards compatible. ** The Y value is the release number and is incremented with ** each release but resets back to 0 whenever X is incremented. ** The Z value only appears on branch releases. ** ** The SQLITE_VERSION_NUMBER is an integer that is computed as ** follows: ** ** <blockquote><pre> ** SQLITE_VERSION_NUMBER = W*1000000 + X*1000 + Y ** </pre></blockquote> ** ** Since version 3.6.18, SQLite source code has been stored in the ** <a href="http://www.fossil-scm.org/">fossil configuration management ** system</a>. The SQLITE_SOURCE_ID ** macro is a string which identifies a particular check-in of SQLite ** within its configuration management system. The string contains the ** date and time of the check-in (UTC) and an SHA1 hash of the entire ** source tree. ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. ** ** Requirements: [H10011] [H10014] */ #define SQLITE_VERSION "--VERS--" #define SQLITE_VERSION_NUMBER --VERSION-NUMBER-- #define SQLITE_SOURCE_ID "--SOURCE-ID--" /* ** CAPI3REF: Run-Time Library Version Numbers {H10020} <S60100> ** KEYWORDS: sqlite3_version ** ** These interfaces provide the same information as the [SQLITE_VERSION], ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] #defines in the header, ** but are associated with the library instead of the header file. Cautious ** programmers might include assert() statements in their application to ** verify that values returned by these interfaces match the macros in ** the header, and thus insure that the application is ** compiled with matching library and header files. ** ** <blockquote><pre> ** assert( sqlite3_libversion_number()==SQLITE_VERSION_NUMBER ); ** assert( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)==0 ); ** assert( strcmp(sqlite3_libversion,SQLITE_VERSION)==0 ); ** </pre></blockquote> ** ** The sqlite3_libversion() function returns the same information as is ** in the sqlite3_version[] string constant. The function is provided ** for use in DLLs since DLL users usually do not have direct access to string ** constants within the DLL. Similarly, the sqlite3_sourceid() function ** returns the same information as is in the [SQLITE_SOURCE_ID] #define of ** the header file. ** ** See also: [sqlite_version()] and [sqlite_source_id()]. ** ** Requirements: [H10021] [H10022] [H10023] */ SQLITE_EXTERN const char sqlite3_version[]; const char *sqlite3_libversion(void); const char *sqlite3_sourceid(void); int sqlite3_libversion_number(void); /* ** CAPI3REF: Test To See If The Library Is Threadsafe {H10100} <S60100> ** ** 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. ** ** This interface can be used by an application to make sure that the ** version of SQLite that it is linking against was compiled with ** the desired setting of the [SQLITE_THREADSAFE] macro. ** ** This interface only reports on the compile-time mutex setting ** of the [SQLITE_THREADSAFE] flag. If SQLite is compiled with ** SQLITE_THREADSAFE=1 then mutexes are enabled by default but ** can be fully or partially disabled using a call to [sqlite3_config()] |
︙ | ︙ | |||
208 209 210 211 212 213 214 | #endif /* ** CAPI3REF: Closing A Database Connection {H12010} <S30100><S40200> ** ** This routine is the destructor for the [sqlite3] object. ** | | < < < < < < < < < < | 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | #endif /* ** CAPI3REF: Closing A Database Connection {H12010} <S30100><S40200> ** ** This routine is the destructor for the [sqlite3] object. ** ** Applications must [sqlite3_finalize | finalize] all [prepared statements] ** and [sqlite3_blob_close | close] all [BLOB handles] associated with ** the [sqlite3] object prior to attempting to close the object. ** ** If [sqlite3_close()] is invoked while a transaction is open, ** the transaction is automatically rolled back. ** ** The C parameter to [sqlite3_close(C)] must be either a NULL ** pointer or an [sqlite3] object pointer obtained ** from [sqlite3_open()], [sqlite3_open16()], or |
︙ | ︙ | |||
402 403 404 405 406 407 408 409 410 411 412 413 414 415 | #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() */ /* ** CAPI3REF: Device Characteristics {H10240} <H11120> ** ** The xDeviceCapabilities method of the [sqlite3_io_methods] ** object returns an integer which is a vector of the these ** bit values expressing I/O characteristics of the mass storage | > > | 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 | #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() */ /* ** CAPI3REF: Device Characteristics {H10240} <H11120> ** ** The xDeviceCapabilities method of the [sqlite3_io_methods] ** object returns an integer which is a vector of the these ** bit values expressing I/O characteristics of the mass storage |
︙ | ︙ | |||
469 470 471 472 473 474 475 | #define SQLITE_SYNC_NORMAL 0x00002 #define SQLITE_SYNC_FULL 0x00003 #define SQLITE_SYNC_DATAONLY 0x00010 /* ** CAPI3REF: OS Interface Open File Handle {H11110} <S20110> ** | | > | | 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 | #define SQLITE_SYNC_NORMAL 0x00002 #define SQLITE_SYNC_FULL 0x00003 #define SQLITE_SYNC_DATAONLY 0x00010 /* ** CAPI3REF: OS Interface Open File Handle {H11110} <S20110> ** ** An [sqlite3_file] object represents an open file in the ** [sqlite3_vfs | OS interface layer]. Individual OS interface ** implementations will ** want to subclass this object by appending additional fields ** for their own use. The pMethods entry is a pointer to an ** [sqlite3_io_methods] object that defines methods for performing ** I/O operations on the open file. */ typedef struct sqlite3_file sqlite3_file; struct sqlite3_file { |
︙ | ︙ | |||
795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 | /* ** CAPI3REF: Initialize The SQLite Library {H10130} <S20000><S30100> ** ** The sqlite3_initialize() routine initializes the ** SQLite library. The sqlite3_shutdown() routine ** deallocates any resources that were allocated by sqlite3_initialize(). ** ** A call to sqlite3_initialize() is an "effective" call if it is ** the first time sqlite3_initialize() is invoked during the lifetime of ** the process, or if it is the first time sqlite3_initialize() is invoked ** following a call to sqlite3_shutdown(). Only an effective call ** of sqlite3_initialize() does any initialization. All other calls ** are harmless no-ops. ** ** A call to sqlite3_shutdown() is an "effective" call if it is the first ** call to sqlite3_shutdown() since the last sqlite3_initialize(). Only ** an effective call to sqlite3_shutdown() does any deinitialization. | > > > | > > > > > > | | | 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 | /* ** CAPI3REF: Initialize The SQLite Library {H10130} <S20000><S30100> ** ** The sqlite3_initialize() routine initializes the ** SQLite library. The sqlite3_shutdown() routine ** deallocates any resources that were allocated by sqlite3_initialize(). ** These routines are designed to aid in process initialization and ** shutdown on embedded systems. Workstation applications using ** SQLite normally do not need to invoke either of these routines. ** ** A call to sqlite3_initialize() is an "effective" call if it is ** the first time sqlite3_initialize() is invoked during the lifetime of ** the process, or if it is the first time sqlite3_initialize() is invoked ** following a call to sqlite3_shutdown(). Only an effective call ** of sqlite3_initialize() does any initialization. All other calls ** are harmless no-ops. ** ** A call to sqlite3_shutdown() is an "effective" call if it is the first ** call to sqlite3_shutdown() since the last sqlite3_initialize(). Only ** an effective call to sqlite3_shutdown() does any deinitialization. ** All other valid calls to sqlite3_shutdown() are harmless no-ops. ** ** The sqlite3_initialize() interface is threadsafe, but sqlite3_shutdown() ** is not. The sqlite3_shutdown() interface must only be called from a ** single thread. All open [database connections] must be closed and all ** other SQLite resources must be deallocated prior to invoking ** sqlite3_shutdown(). ** ** Among other things, sqlite3_initialize() will invoke ** sqlite3_os_init(). Similarly, sqlite3_shutdown() ** will invoke sqlite3_os_end(). ** ** The sqlite3_initialize() routine returns [SQLITE_OK] on success. ** If for some reason, sqlite3_initialize() is unable to initialize ** the library (perhaps it is unable to allocate a needed resource such ** as a mutex) it returns an [error code] other than [SQLITE_OK]. ** ** The sqlite3_initialize() routine is called internally by many other |
︙ | ︙ | |||
846 847 848 849 850 851 852 | ** ** The application should never invoke either sqlite3_os_init() ** or sqlite3_os_end() directly. The application should only invoke ** sqlite3_initialize() and sqlite3_shutdown(). The sqlite3_os_init() ** interface is called automatically by sqlite3_initialize() and ** sqlite3_os_end() is called by sqlite3_shutdown(). Appropriate ** implementations for sqlite3_os_init() and sqlite3_os_end() | | > | | 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 | ** ** The application should never invoke either sqlite3_os_init() ** or sqlite3_os_end() directly. The application should only invoke ** sqlite3_initialize() and sqlite3_shutdown(). The sqlite3_os_init() ** interface is called automatically by sqlite3_initialize() and ** sqlite3_os_end() is called by sqlite3_shutdown(). Appropriate ** implementations for sqlite3_os_init() and sqlite3_os_end() ** are built into SQLite when it is compiled for Unix, Windows, or OS/2. ** When [custom builds | built for other platforms] ** (using the [SQLITE_OS_OTHER=1] compile-time ** option) the application must supply a suitable implementation for ** sqlite3_os_init() and sqlite3_os_end(). An application-supplied ** implementation of sqlite3_os_init() or sqlite3_os_end() ** must return [SQLITE_OK] on success and some other [error code] upon ** failure. */ int sqlite3_initialize(void); |
︙ | ︙ | |||
928 929 930 931 932 933 934 | ** ** 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 | > | | | > | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | ** ** 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] ** that are perfectly adequate for the overwhelming majority of applications ** and that this object is only useful to a tiny minority of applications ** with specialized memory allocation requirements. This object is ** also used during testing of SQLite in order to specify an alternative ** memory allocator that simulates memory out-of-memory conditions in ** order to verify that SQLite recovers gracefully from such ** conditions. ** ** The xMalloc and xFree methods must work like the ** malloc() and free() functions from the standard C library. ** The xRealloc method must work like realloc() from the standard C library ** with the exception that if the second argument to xRealloc is zero, ** xRealloc must be a no-op - it must not perform any allocation or ** deallocation. SQLite guaranteeds that the second argument to ** xRealloc is always a value returned by a prior call to xRoundup. ** And so in cases where xRoundup always returns a positive number, ** xRealloc can perform exactly as the standard library realloc() and ** still be in compliance with this specification. ** ** xSize should return the allocated size of a memory allocation ** previously obtained from xMalloc or xRealloc. The allocated size ** is always at least as big as the requested size but may be larger. ** ** The xRoundup method returns what would be the allocated size of ** a memory allocation given a particular requested size. Most memory ** 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 ** methods must be threadsafe or else make their own arrangements for ** serialization. ** ** SQLite will never invoke xInit() more than once without an intervening ** call to xShutdown(). */ typedef struct sqlite3_mem_methods sqlite3_mem_methods; struct sqlite3_mem_methods { void *(*xMalloc)(int); /* Memory allocation function */ void (*xFree)(void*); /* Free a prior allocation */ void *(*xRealloc)(void*,int); /* Resize an allocation */ int (*xSize)(void*); /* Return the size of an allocation */ |
︙ | ︙ | |||
1113 1114 1115 1116 1117 1118 1119 | ** structure is filled with the currently defined mutex routines. ** This option can be used to overload the default mutex allocation ** routines with a wrapper used to track mutex usage for performance ** profiling or testing, for example.</dd> ** ** <dt>SQLITE_CONFIG_LOOKASIDE</dt> ** <dd>This option takes two arguments that determine the default | | | > > > | 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 | ** structure is filled with the currently defined mutex routines. ** This option can be used to overload the default mutex allocation ** routines with a wrapper used to track mutex usage for performance ** profiling or testing, for example.</dd> ** ** <dt>SQLITE_CONFIG_LOOKASIDE</dt> ** <dd>This option takes two arguments that determine the default ** memory allocation lookaside optimization. The first argument is the ** size of each lookaside buffer slot and the second is the number of ** slots allocated to each database connection. This option sets the ** <i>default</i> lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] ** verb to [sqlite3_db_config()] can be used to change the lookaside ** configuration on individual connections.</dd> ** ** <dt>SQLITE_CONFIG_PCACHE</dt> ** <dd>This option takes a single argument which is a pointer to ** an [sqlite3_pcache_methods] object. This object specifies the interface ** to a custom page cache implementation. SQLite makes a copy of the ** object and uses it for page cache memory allocations.</dd> ** |
︙ | ︙ | |||
1165 1166 1167 1168 1169 1170 1171 | ** is invoked. ** ** <dl> ** <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 | | | > > > | 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 | ** is invoked. ** ** <dl> ** <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 an memory buffer to use for lookaside memory. ** The first argument 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 and 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 is not ** a multiple of 8, it is internally rounded down to the next smaller ** multiple of 8. See also: [SQLITE_CONFIG_LOOKASIDE]</dd> ** ** </dl> */ #define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */ /* |
︙ | ︙ | |||
1242 1243 1244 1245 1246 1247 1248 | ** CAPI3REF: Count The Number Of Rows Modified {H12240} <S10600> ** ** This function returns the number of database rows that were changed ** or inserted or deleted by the most recently completed SQL statement ** on the [database connection] specified by the first parameter. ** Only changes that are directly specified by the [INSERT], [UPDATE], ** or [DELETE] statement are counted. Auxiliary changes caused by | > | | | 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 | ** CAPI3REF: Count The Number Of Rows Modified {H12240} <S10600> ** ** This function returns the number of database rows that were changed ** or inserted or deleted by the most recently completed SQL statement ** on the [database connection] specified by the first parameter. ** Only changes that are directly specified by the [INSERT], [UPDATE], ** or [DELETE] statement are counted. Auxiliary changes caused by ** triggers or [foreign key actions] are not counted. Use the ** [sqlite3_total_changes()] function to find the total number of changes ** including changes caused by triggers and foreign key actions. ** ** Changes to a view that are simulated by an [INSTEAD OF trigger] ** are not counted. Only real table changes are counted. ** ** A "row change" is a change to a single row of a single table ** caused by an INSERT, DELETE, or UPDATE statement. Rows that ** are changed as side effects of [REPLACE] constraint resolution, |
︙ | ︙ | |||
1295 1296 1297 1298 1299 1300 1301 | int sqlite3_changes(sqlite3*); /* ** CAPI3REF: Total Number Of Rows Modified {H12260} <S10600> ** ** This function returns the number of row changes caused by [INSERT], ** [UPDATE] or [DELETE] statements since the [database connection] was opened. | | | | 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 | int sqlite3_changes(sqlite3*); /* ** CAPI3REF: Total Number Of Rows Modified {H12260} <S10600> ** ** This function returns the number of row changes caused by [INSERT], ** [UPDATE] or [DELETE] statements since the [database connection] was opened. ** The count includes all changes from all [CREATE TRIGGER | trigger] ** contexts and changes made by [foreign key actions]. However, ** the count does not include changes used to implement [REPLACE] constraints, ** do rollbacks or ABORT processing, or [DROP TABLE] processing. The ** count does not include rows of views that fire an [INSTEAD OF trigger], ** though if the INSTEAD OF trigger makes changes of its own, those changes ** are counted. ** The changes are counted as soon as the statement that makes them is ** completed (when the statement handle is passed to [sqlite3_reset()] or |
︙ | ︙ | |||
1574 1575 1576 1577 1578 1579 1580 | char **pzErrmsg /* Error msg written here */ ); void sqlite3_free_table(char **result); /* ** CAPI3REF: Formatted String Printing Functions {H17400} <S70000><S20000> ** | | | 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 | char **pzErrmsg /* Error msg written here */ ); void sqlite3_free_table(char **result); /* ** CAPI3REF: Formatted String Printing Functions {H17400} <S70000><S20000> ** ** These routines are work-alikes of the "printf()" family of functions ** from the standard C library. ** ** The sqlite3_mprintf() and sqlite3_vmprintf() routines write their ** results into memory obtained from [sqlite3_malloc()]. ** The strings returned by these two routines should be ** released by [sqlite3_free()]. Both routines return a ** NULL pointer if [sqlite3_malloc()] is unable to allocate enough |
︙ | ︙ | |||
1861 1862 1863 1864 1865 1866 1867 | ** ** The authorizer callback must not do anything that will modify ** the database connection that invoked the authorizer callback. ** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their ** database connections for the meaning of "modify" in this paragraph. ** ** When [sqlite3_prepare_v2()] is used to prepare a statement, the | | | 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 | ** ** The authorizer callback must not do anything that will modify ** the database connection that invoked the authorizer callback. ** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their ** database connections for the meaning of "modify" in this paragraph. ** ** When [sqlite3_prepare_v2()] is used to prepare a statement, the ** statement might be re-prepared during [sqlite3_step()] due to a ** schema change. Hence, the application should ensure that the ** correct authorizer callback remains in place during the [sqlite3_step()]. ** ** Note that the authorizer callback is invoked only during ** [sqlite3_prepare()] or its variants. Authorization is not ** performed during statement evaluation in [sqlite3_step()], unless ** as stated in the previous paragraph, sqlite3_step() invokes |
︙ | ︙ | |||
2028 2029 2030 2031 2032 2033 2034 | ** 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 can take one of ** the following three values, optionally combined with the | | > | > > > > > > | 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 | ** 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 can take one of ** the following three values, optionally combined with the ** [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], [SQLITE_OPEN_SHAREDCACHE], ** and/or [SQLITE_OPEN_PRIVATECACHE] 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 creates it 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 or one of the combinations shown above combined ** with the [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], ** [SQLITE_OPEN_SHAREDCACHE] and/or [SQLITE_OPEN_SHAREDCACHE] flags, ** 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. ** ** If the filename is ":memory:", then a private, temporary in-memory database ** is created for the connection. This in-memory database will vanish when ** the database connection is closed. Future versions of SQLite might ** make use of additional special filenames that begin with the ":" character. ** It is recommended that when a database filename actually does begin with ** a ":" character you should prefix the filename with a pathname such as |
︙ | ︙ | |||
2208 2209 2210 2211 2212 2213 2214 | ** Requirements: ** [H12762] [H12766] [H12769] */ int sqlite3_limit(sqlite3*, int id, int newVal); /* ** CAPI3REF: Run-Time Limit Categories {H12790} <H12760> | | | 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 | ** Requirements: ** [H12762] [H12766] [H12769] */ int sqlite3_limit(sqlite3*, int id, int newVal); /* ** CAPI3REF: Run-Time Limit Categories {H12790} <H12760> ** KEYWORDS: {limit category} {*limit categories} ** ** These constants define various performance limits ** that can be lowered at run-time using [sqlite3_limit()]. ** The synopsis of the meanings of the various limits is shown below. ** Additional information is available at [limits | Limits in SQLite]. ** ** <dl> |
︙ | ︙ | |||
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 | ** <dt>SQLITE_LIMIT_LIKE_PATTERN_LENGTH</dt> ** <dd>The maximum length of the pattern argument to the [LIKE] or ** [GLOB] operators.</dd> ** ** <dt>SQLITE_LIMIT_VARIABLE_NUMBER</dt> ** <dd>The maximum number of variables in an SQL statement that can ** be bound.</dd> ** </dl> */ #define SQLITE_LIMIT_LENGTH 0 #define SQLITE_LIMIT_SQL_LENGTH 1 #define SQLITE_LIMIT_COLUMN 2 #define SQLITE_LIMIT_EXPR_DEPTH 3 #define SQLITE_LIMIT_COMPOUND_SELECT 4 #define SQLITE_LIMIT_VDBE_OP 5 #define SQLITE_LIMIT_FUNCTION_ARG 6 #define SQLITE_LIMIT_ATTACHED 7 #define SQLITE_LIMIT_LIKE_PATTERN_LENGTH 8 #define SQLITE_LIMIT_VARIABLE_NUMBER 9 /* ** CAPI3REF: Compiling An SQL Statement {H13010} <S10000> ** KEYWORDS: {SQL statement compiler} ** ** To execute an SQL query, it must first be compiled into a byte-code ** program using one of these routines. | > > > > | 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 | ** <dt>SQLITE_LIMIT_LIKE_PATTERN_LENGTH</dt> ** <dd>The maximum length of the pattern argument to the [LIKE] or ** [GLOB] operators.</dd> ** ** <dt>SQLITE_LIMIT_VARIABLE_NUMBER</dt> ** <dd>The maximum number of variables in an SQL statement that can ** be bound.</dd> ** ** <dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt> ** <dd>The maximum depth of recursion for triggers.</dd> ** </dl> */ #define SQLITE_LIMIT_LENGTH 0 #define SQLITE_LIMIT_SQL_LENGTH 1 #define SQLITE_LIMIT_COLUMN 2 #define SQLITE_LIMIT_EXPR_DEPTH 3 #define SQLITE_LIMIT_COMPOUND_SELECT 4 #define SQLITE_LIMIT_VDBE_OP 5 #define SQLITE_LIMIT_FUNCTION_ARG 6 #define SQLITE_LIMIT_ATTACHED 7 #define SQLITE_LIMIT_LIKE_PATTERN_LENGTH 8 #define SQLITE_LIMIT_VARIABLE_NUMBER 9 #define SQLITE_LIMIT_TRIGGER_DEPTH 10 /* ** CAPI3REF: Compiling An SQL Statement {H13010} <S10000> ** KEYWORDS: {SQL statement compiler} ** ** To execute an SQL query, it must first be compiled into a byte-code ** program using one of these routines. |
︙ | ︙ | |||
2310 2311 2312 2313 2314 2315 2316 | ** ** The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are ** recommended for all new programs. The two older interfaces are retained ** for backwards compatibility, but their use is discouraged. ** In the "v2" interfaces, the prepared statement ** that is returned (the [sqlite3_stmt] object) contains a copy of the ** original SQL text. This causes the [sqlite3_step()] interface to | | | 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 | ** ** The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are ** recommended for all new programs. The two older interfaces are retained ** for backwards compatibility, but their use is discouraged. ** In the "v2" interfaces, the prepared statement ** that is returned (the [sqlite3_stmt] object) contains a copy of the ** original SQL text. This causes the [sqlite3_step()] interface to ** behave differently in three ways: ** ** <ol> ** <li> ** If the database schema changes, instead of returning [SQLITE_SCHEMA] as it ** always used to do, [sqlite3_step()] will automatically recompile the SQL ** statement and try to run it again. If the schema has changed in ** a way that makes the statement no longer valid, [sqlite3_step()] will still |
︙ | ︙ | |||
2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 | ** When an error occurs, [sqlite3_step()] will return one of the detailed ** [error codes] or [extended error codes]. The legacy behavior was that ** [sqlite3_step()] would only return a generic [SQLITE_ERROR] result code ** and you 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> ** </ol> ** ** Requirements: ** [H13011] [H13012] [H13013] [H13014] [H13015] [H13016] [H13019] [H13021] ** */ int sqlite3_prepare( | > > > > > > > > | 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 | ** When an error occurs, [sqlite3_step()] will return one of the detailed ** [error codes] or [extended error codes]. The legacy behavior was that ** [sqlite3_step()] would only return a generic [SQLITE_ERROR] result code ** and you 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 value of a [parameter | host parameter] in the WHERE clause might ** change the query plan for a statement, then the statement may 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 the [parameter]. ** </li> ** </ol> ** ** Requirements: ** [H13011] [H13012] [H13013] [H13014] [H13015] [H13016] [H13019] [H13021] ** */ int sqlite3_prepare( |
︙ | ︙ | |||
2438 2439 2440 2441 2442 2443 2444 | /* ** CAPI3REF: Binding Values To Prepared Statements {H13500} <S70300> ** KEYWORDS: {host parameter} {host parameters} {host parameter name} ** KEYWORDS: {SQL parameter} {SQL parameters} {parameter binding} ** ** In the SQL strings input to [sqlite3_prepare_v2()] and its variants, | | > | | | 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 | /* ** CAPI3REF: Binding Values To Prepared Statements {H13500} <S70300> ** KEYWORDS: {host parameter} {host parameters} {host parameter name} ** KEYWORDS: {SQL parameter} {SQL parameters} {parameter binding} ** ** In the SQL strings input to [sqlite3_prepare_v2()] and its variants, ** literals may be replaced by a [parameter] that matches one of following ** templates: ** ** <ul> ** <li> ? ** <li> ?NNN ** <li> :VVV ** <li> @VVV ** <li> $VVV ** </ul> ** ** In the templates above, NNN represents an integer literal, ** and VVV represents an alphanumeric identifer. The values of these ** parameters (also called "host parameter names" or "SQL parameters") ** can be set using the sqlite3_bind_*() routines defined here. ** ** The first argument to the sqlite3_bind_*() routines is always ** a pointer to the [sqlite3_stmt] object returned from ** [sqlite3_prepare_v2()] or its variants. ** |
︙ | ︙ | |||
2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 | ** ** These routines return information about a single column of the current ** result row of a query. In every case the first argument is a pointer ** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*] ** that was returned from [sqlite3_prepare_v2()] or one of its variants) ** and the second argument is the index of the column for which information ** should be returned. The leftmost column of the result set has the index 0. ** ** If the SQL statement does not currently point to a valid row, or if the ** column index is out of range, the result is undefined. ** These routines may only be called when the most recent call to ** [sqlite3_step()] has returned [SQLITE_ROW] and neither ** [sqlite3_reset()] nor [sqlite3_finalize()] have been called subsequently. ** If any of these routines are called after [sqlite3_reset()] or | > > | 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 | ** ** These routines return information about a single column of the current ** result row of a query. In every case the first argument is a pointer ** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*] ** that was returned from [sqlite3_prepare_v2()] or one of its variants) ** and the second argument is the index of the column for which information ** should be returned. The leftmost column of the result set has the index 0. ** The number of columns in the result can be determined using ** [sqlite3_column_count()]. ** ** If the SQL statement does not currently point to a valid row, or if the ** column index is out of range, the result is undefined. ** These routines may only be called when the most recent call to ** [sqlite3_step()] has returned [SQLITE_ROW] and neither ** [sqlite3_reset()] nor [sqlite3_finalize()] have been called subsequently. ** If any of these routines are called after [sqlite3_reset()] or |
︙ | ︙ | |||
3101 3102 3103 3104 3105 3106 3107 | ** parameter is less than -1 or greater than 127 then the behavior is ** undefined. ** ** The fourth parameter, eTextRep, specifies what ** [SQLITE_UTF8 | text encoding] this SQL function prefers for ** its parameters. Any SQL function implementation should be able to work ** work with UTF-8, UTF-16le, or UTF-16be. But some implementations may be | | | 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 | ** parameter is less than -1 or greater than 127 then the behavior is ** undefined. ** ** The fourth parameter, eTextRep, specifies what ** [SQLITE_UTF8 | text encoding] this SQL function prefers for ** its parameters. Any SQL function implementation should be able to work ** work with UTF-8, UTF-16le, or UTF-16be. But some implementations may be ** more efficient with one encoding than another. An application may ** invoke sqlite3_create_function() or sqlite3_create_function16() multiple ** times with the same function but with different values of eTextRep. ** When multiple implementations of the same function are available, SQLite ** will pick the one that involves the least amount of data conversion. ** If there is only a single implementation which does not care what text ** encoding is used, then the fourth argument should be [SQLITE_ANY]. ** |
︙ | ︙ | |||
3123 3124 3125 3126 3127 3128 3129 | ** parameters. An aggregate SQL function requires an implementation of xStep ** and xFinal and NULL should be passed for xFunc. To delete an existing ** SQL function or aggregate, pass NULL for all three function callbacks. ** ** It is permitted to register multiple implementations of the same ** functions with the same name but with either differing numbers of ** arguments or differing preferred text encodings. SQLite will use | | | 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 | ** parameters. An aggregate SQL function requires an implementation of xStep ** and xFinal and NULL should be passed for xFunc. To delete an existing ** SQL function or aggregate, pass NULL for all three function callbacks. ** ** It is permitted to register multiple implementations of the same ** functions with the same name but with either differing numbers of ** arguments or differing preferred text encodings. SQLite will use ** the implementation that most closely matches the way in which the ** SQL function is used. A function implementation with a non-negative ** nArg parameter is a better match than a function implementation with ** a negative nArg. A function where the preferred text encoding ** matches the database encoding is a better ** match than a function where the encoding is different. ** A function where the encoding difference is between UTF16le and UTF16be ** is a closer match than a function where the encoding difference is |
︙ | ︙ | |||
3471 3472 3473 3474 3475 3476 3477 | ** 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 4th parameter to the sqlite3_result_text* interfaces ** or sqlite3_result_blob is a non-NULL pointer, then SQLite calls that ** function as the destructor on the text or BLOB result when it has ** finished using that result. | | > | | 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 | ** 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 4th parameter to the sqlite3_result_text* interfaces ** or sqlite3_result_blob is a non-NULL pointer, then SQLite calls that ** function as the destructor on the text or BLOB result when it has ** finished using that result. ** If the 4th parameter to the sqlite3_result_text* interfaces or to ** sqlite3_result_blob is the special constant SQLITE_STATIC, then SQLite ** assumes that the text or BLOB result is in constant space and does not ** copy the content of the parameter nor call a destructor on the content ** when it has finished using that result. ** If the 4th parameter to the sqlite3_result_text* interfaces ** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT ** then SQLite makes a copy of the result into space obtained from ** from [sqlite3_malloc()] before it returns. ** ** The sqlite3_result_value() interface sets the result of ** the application-defined function to be a copy the |
︙ | ︙ | |||
3864 3865 3866 3867 3868 3869 3870 | sqlite3*, void(*)(void *,int ,char const *,char const *,sqlite3_int64), void* ); /* ** CAPI3REF: Enable Or Disable Shared Pager Cache {H10330} <S30900> | | | 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 | sqlite3*, void(*)(void *,int ,char const *,char const *,sqlite3_int64), void* ); /* ** CAPI3REF: Enable Or Disable Shared Pager Cache {H10330} <S30900> ** KEYWORDS: {shared 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. |
︙ | ︙ | |||
4327 4328 4329 4330 4331 4332 4333 | ** take care that any prior string is freed by a call to [sqlite3_free()] ** prior to assigning a new string to zErrMsg. After the error message ** is delivered up to the client application, the string will be automatically ** freed by sqlite3_free() and the zErrMsg field will be zeroed. */ struct sqlite3_vtab { const sqlite3_module *pModule; /* The module for this virtual table */ | | | 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 | ** take care that any prior string is freed by a call to [sqlite3_free()] ** prior to assigning a new string to zErrMsg. After the error message ** is delivered up to the client application, the string will be automatically ** freed by sqlite3_free() and the zErrMsg field will be zeroed. */ struct sqlite3_vtab { const sqlite3_module *pModule; /* The module for this virtual table */ int nRef; /* NO LONGER USED */ char *zErrMsg; /* Error message from sqlite3_mprintf() */ /* Virtual table implementations will typically add additional fields */ }; /* ** CAPI3REF: Virtual Table Cursor Object {H18020} <S20400> ** KEYWORDS: sqlite3_vtab_cursor {virtual table cursor} |
︙ | ︙ | |||
4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 | ** ** <pre> ** SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow; ** </pre> {END} ** ** If the flags parameter is non-zero, then the BLOB is opened for read ** and write access. If it is zero, the BLOB is opened for read access. ** ** Note that the database name is not the filename that contains ** the database but rather the symbolic name of the database that ** is assigned when the database is connected using [ATTACH]. ** For the main database file, the database name is "main". ** For TEMP tables, the database name is "temp". ** | > > > | 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 | ** ** <pre> ** SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow; ** </pre> {END} ** ** If the flags parameter is non-zero, then the BLOB is opened for read ** and write access. If it is zero, the BLOB is opened for read access. ** It is not possible to open a column that is part of an index or primary ** key for writing. ^If [foreign key constraints] are enabled, it is ** not possible to open a column that is part of a [child key] for writing. ** ** Note that the database name is not the filename that contains ** the database but rather the symbolic name of the database that ** is assigned when the database is connected using [ATTACH]. ** For the main database file, the database name is "main". ** For TEMP tables, the database name is "temp". ** |
︙ | ︙ | |||
4453 4454 4455 4456 4457 4458 4459 | ** a expired BLOB handle fail with an return code of [SQLITE_ABORT]. ** Changes written into a BLOB prior to the BLOB expiring are not ** rollback by the expiration of the BLOB. Such changes will eventually ** commit if the transaction continues to completion. ** ** Use the [sqlite3_blob_bytes()] interface to determine the size of ** the opened blob. The size of a blob may not be changed by this | | | 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 | ** a expired BLOB handle fail with an return code of [SQLITE_ABORT]. ** Changes written into a BLOB prior to the BLOB expiring are not ** rollback by the expiration of the BLOB. Such changes will eventually ** commit if the transaction continues to completion. ** ** Use the [sqlite3_blob_bytes()] interface to determine the size of ** the opened blob. The size of a blob may not be changed by this ** interface. Use the [UPDATE] SQL command to change the size of a ** blob. ** ** The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces ** and the built-in [zeroblob] SQL function can be used, if desired, ** to create an empty, zero-filled blob in which to read or write using ** this interface. ** |
︙ | ︙ | |||
4693 4694 4695 4696 4697 4698 4699 | ** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does ** not want to. {H17016} But SQLite will only request a recursive mutex in ** cases where it really needs one. {END} If a faster non-recursive mutex ** implementation is available on the host platform, the mutex subsystem ** might return such a mutex in response to SQLITE_MUTEX_FAST. ** ** {H17017} The other allowed parameters to sqlite3_mutex_alloc() each return | | | 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 | ** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does ** not want to. {H17016} But SQLite will only request a recursive mutex in ** cases where it really needs one. {END} If a faster non-recursive mutex ** implementation is available on the host platform, the mutex subsystem ** might return such a mutex in response to SQLITE_MUTEX_FAST. ** ** {H17017} The other allowed parameters to sqlite3_mutex_alloc() each return ** a pointer to a static preexisting mutex. {END} Six static mutexes are ** used by the current version of SQLite. Future versions of SQLite ** may add additional static mutexes. Static mutexes are for internal ** use by SQLite only. Applications that use SQLite mutexes should ** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or ** SQLITE_MUTEX_RECURSIVE. ** ** {H17018} Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST |
︙ | ︙ | |||
4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 | ** 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). */ typedef struct sqlite3_mutex_methods sqlite3_mutex_methods; struct sqlite3_mutex_methods { int (*xMutexInit)(void); int (*xMutexEnd)(void); sqlite3_mutex *(*xMutexAlloc)(int); void (*xMutexFree)(sqlite3_mutex *); | > > > > > > > > > > > > > > > | 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 | ** 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() mutiple times within the same process and without ** intervening calls to xMutexEnd(). Second and subsequent calls to ** xMutexInit() must be no-ops. ** ** xMutexInit() must not use SQLite memory allocation ([sqlite3_malloc()] ** and its associates). Similarly, xMutexAlloc() must not use SQLite memory ** allocation for a static mutex. However xMutexAlloc() may use SQLite ** memory allocation for a fast or recursive mutex. ** ** SQLite will invoke the xMutexEnd() method when [sqlite3_shutdown()] is ** called, but only if the prior call to xMutexInit returned SQLITE_OK. ** If xMutexInit fails in any way, it is expected to clean up after itself ** prior to returning. */ typedef struct sqlite3_mutex_methods sqlite3_mutex_methods; struct sqlite3_mutex_methods { int (*xMutexInit)(void); int (*xMutexEnd)(void); sqlite3_mutex *(*xMutexAlloc)(int); void (*xMutexFree)(sqlite3_mutex *); |
︙ | ︙ | |||
4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 | #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 /* ** CAPI3REF: SQLite Runtime Status {H17200} <S60200> ** EXPERIMENTAL ** ** This interface is used to retrieve runtime status information ** about the preformance of SQLite, and optionally to reset various | > | 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 | #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 /* ** CAPI3REF: SQLite Runtime Status {H17200} <S60200> ** EXPERIMENTAL ** ** This interface is used to retrieve runtime status information ** about the preformance of SQLite, and optionally to reset various |
︙ | ︙ | |||
4963 4964 4965 4966 4967 4968 4969 | ** nothing is written into *pHighwater and the resetFlag is ignored. ** Other parameters record only the highwater mark and not the current ** value. For these latter parameters nothing is written into *pCurrent. ** ** This routine returns SQLITE_OK on success and a non-zero ** [error code] on failure. ** | | | 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 | ** nothing is written into *pHighwater and the resetFlag is ignored. ** Other parameters record only the highwater mark and not the current ** value. For these latter parameters nothing is written into *pCurrent. ** ** This routine returns SQLITE_OK on success and a non-zero ** [error code] on failure. ** ** This routine is threadsafe but is not atomic. This routine can be ** called while other threads are running the same or different SQLite ** interfaces. However the values returned in *pCurrent and ** *pHighwater reflect the status of SQLite at different points in time ** and it is possible that another thread might change the parameter ** in between the times when *pCurrent and *pHighwater are written. ** ** See also: [sqlite3_db_status()] |
︙ | ︙ | |||
5086 5087 5088 5089 5090 5091 5092 | */ SQLITE_EXPERIMENTAL int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); /* ** CAPI3REF: Status Parameters for database connections {H17520} <H17500> ** EXPERIMENTAL ** | > > > > > | > > | 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 | */ SQLITE_EXPERIMENTAL int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); /* ** CAPI3REF: Status Parameters for database connections {H17520} <H17500> ** EXPERIMENTAL ** ** These constants are the available integer "verbs" that can be passed as ** the second argument to the [sqlite3_db_status()] interface. ** ** New verbs may be added in future releases of SQLite. Existing verbs ** might be discontinued. Applications should check the return code from ** [sqlite3_db_status()] to make sure that the call worked. ** The [sqlite3_db_status()] interface will return a non-zero error code ** if a discontinued or unsupported verb is invoked. ** ** <dl> ** <dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt> ** <dd>This parameter returns the number of lookaside memory slots currently ** checked out.</dd> ** </dl> */ |
︙ | ︙ | |||
5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 | ** ** See [sqlite3_pcache_methods] for additional information. */ typedef struct sqlite3_pcache sqlite3_pcache; /* ** CAPI3REF: Application Defined Page Cache. ** EXPERIMENTAL ** ** The [sqlite3_config]([SQLITE_CONFIG_PCACHE], ...) interface can ** register an alternative page cache implementation by passing in an ** instance of the sqlite3_pcache_methods structure. The majority of the | > | | | | | > > | > > | | > > > > > > > > > | > > | > > > > > > | | | | > > > | | | | | | | | | | < | < < < < < < | < | < < < | < < < < | > > > > > > > | < < < | 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 | ** ** See [sqlite3_pcache_methods] for additional information. */ typedef struct sqlite3_pcache sqlite3_pcache; /* ** CAPI3REF: Application Defined Page Cache. ** KEYWORDS: {page cache} ** EXPERIMENTAL ** ** The [sqlite3_config]([SQLITE_CONFIG_PCACHE], ...) interface can ** register an alternative page cache implementation by passing in an ** instance of the sqlite3_pcache_methods structure. The majority of the ** heap memory used by SQLite is used by the page cache to cache data read ** from, or ready to be written to, the database file. By implementing a ** custom page cache using this API, an application can control more ** precisely the amount of memory consumed by SQLite, the way in which ** that memory is allocated and released, and the policies used to ** determine exactly which parts of a database file are cached and for ** how long. ** ** The contents of the sqlite3_pcache_methods structure are copied to an ** internal buffer by SQLite within the call to [sqlite3_config]. Hence ** the application may discard the parameter after the call to ** [sqlite3_config()] returns. ** ** The xInit() method is called once for each call to [sqlite3_initialize()] ** (usually only once during the lifetime of the process). It is passed ** a copy of the sqlite3_pcache_methods.pArg value. It can be used to set ** up global structures and mutexes required by the custom page cache ** implementation. ** ** The xShutdown() method is called from within [sqlite3_shutdown()], ** if the application invokes this API. It can be used to clean up ** any outstanding resources before process shutdown, if required. ** ** SQLite holds a [SQLITE_MUTEX_RECURSIVE] 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. All other methods must be threadsafe ** in multithreaded applications. ** ** SQLite will never invoke xInit() more than once without an intervening ** call to xShutdown(). ** ** The xCreate() method is used to construct a new cache instance. SQLite ** will typically create one cache instance for each open database file, ** though this is not guaranteed. The ** first parameter, szPage, is the size in bytes of the pages that must ** be allocated by the cache. szPage will not be a power of two. szPage ** will the page size of the database file that is to be cached plus an ** increment (here called "R") of about 100 or 200. SQLite will use the ** extra R bytes on each page to store metadata about the underlying ** database page on disk. The value of R depends ** on the SQLite version, the target platform, and how SQLite was compiled. ** R is constant for a particular build of SQLite. The second argument to ** xCreate(), bPurgeable, is true if the cache being created will ** be used to cache database pages of a file stored on disk, or ** false if it is used for an in-memory database. The cache implementation ** does not have to do anything special based with the value of bPurgeable; ** it is purely advisory. On a cache where bPurgeable is false, SQLite will ** never invoke xUnpin() except to deliberately delete a page. ** In other words, a cache created with bPurgeable set to false will ** never contain any unpinned pages. ** ** The xCachesize() method may be called at any time by SQLite to set the ** suggested maximum cache-size (number of pages stored by) the cache ** instance passed as the first argument. This is the value configured using ** the SQLite "[PRAGMA cache_size]" command. As with the bPurgeable parameter, ** the implementation is not required to do anything with this ** value; it is advisory only. ** ** The xPagecount() method should return the number of pages currently ** stored in the cache. ** ** The xFetch() method is used to fetch a page and return a pointer to it. ** A 'page', in this context, is a buffer of szPage bytes aligned at an ** 8-byte boundary. The page to be fetched is determined by the key. The ** mimimum key value is 1. After it has been retrieved using xFetch, the page ** is considered to be "pinned". ** ** If the requested page is already in the page cache, then the page cache ** implementation must return a pointer to the page buffer with its content ** intact. If the requested page is not already in the cache, then the ** behavior of the cache implementation is determined by the value of the ** createFlag parameter passed to xFetch, according to the following table: ** ** <table border=1 width=85% align=center> ** <tr><th> createFlag <th> Behaviour when page is not already in cache ** <tr><td> 0 <td> Do not allocate a new page. Return NULL. ** <tr><td> 1 <td> Allocate a new page if it easy and convenient to do so. ** Otherwise return NULL. ** <tr><td> 2 <td> Make every effort to allocate a new page. Only return ** NULL if allocating a new page is effectively impossible. ** </table> ** ** SQLite will normally invoke xFetch() with a createFlag of 0 or 1. If ** a call to xFetch() with createFlag==1 returns NULL, then SQLite will ** attempt to unpin one or more cache pages by spilling the content of ** pinned pages to disk and synching the operating system disk cache. After ** attempting to unpin pages, the xFetch() method will be invoked again with ** a createFlag of 2. ** ** 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 should be evicted from the cache. In this case SQLite ** assumes that the next time the page is retrieved from the cache using ** the xFetch() method, it will be zeroed. If the discard parameter is ** zero, then the page is considered to be unpinned. The cache implementation ** may choose to evict unpinned pages at any time. ** ** The cache is not required to perform any reference counting. A single ** call to xUnpin() unpins the page regardless of the number of prior calls ** to xFetch(). ** ** The xRekey() method is used to change the key value associated with the ** page passed as the second argument from oldKey to newKey. If the cache |
︙ | ︙ | |||
5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 | */ int sqlite3_unlock_notify( sqlite3 *pBlocked, /* Waiting connection */ void (*xNotify)(void **apArg, int nArg), /* Callback function to invoke */ void *pNotifyArg /* Argument to pass to xNotify */ ); /* ** 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 | > > > > > > > > > > > > | 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 | */ int sqlite3_unlock_notify( sqlite3 *pBlocked, /* Waiting connection */ void (*xNotify)(void **apArg, int nArg), /* Callback function to invoke */ void *pNotifyArg /* Argument to pass to xNotify */ ); /* ** CAPI3REF: String Comparison ** EXPERIMENTAL ** ** The [sqlite3_strnicmp()] API allows applications and extensions to ** compare the contents of two buffers containing UTF-8 strings in a ** case-indendent fashion, using the same definition of case independence ** that SQLite uses internally when comparing identifiers. */ int sqlite3_strnicmp(const char *, const char *, int); /* ** 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 |
Changes to src/sqlite3ext.h.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** This header file defines the SQLite interface for use by ** shared libraries that want to be imported as extensions into ** an SQLite instance. Shared libraries that intend to be loaded ** as extensions by SQLite should #include this file instead of ** sqlite3.h. | < < | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** ************************************************************************* ** This header file defines the SQLite interface for use by ** shared libraries that want to be imported as extensions into ** an SQLite instance. Shared libraries that intend to be loaded ** as extensions by SQLite should #include this file instead of ** sqlite3.h. */ #ifndef _SQLITE3EXT_H_ #define _SQLITE3EXT_H_ #include "sqlite3.h" typedef struct sqlite3_api_routines sqlite3_api_routines; |
︙ | ︙ |
Changes to src/sqliteInt.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** | < > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | /* ** 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. ** ************************************************************************* ** Internal interface definitions for SQLite. ** */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ /* ** These #defines should enable >2GB file support on POSIX if the ** underlying operating system supports it. If the OS lacks ** large file support, or if the OS is windows, these should be no-ops. ** ** Ticket #2739: The _LARGEFILE_SOURCE macro must appear before any ** system #includes. Hence, this block of code must be the very first ** code in all source files. ** ** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch ** on the compiler command line. This is necessary if you are compiling ** on a recent machine (ex: Red Hat 7.2) but you want your code to work ** on an older machine (ex: Red Hat 6.0). If you compile on Red Hat 7.2 ** without this option, LFS is enable. But LFS does not exist in the kernel ** in Red Hat 6.0, so the code won't work. Hence, for maximum binary ** portability you should omit LFS. ** ** Similar is true for Mac OS X. LFS is only supported on Mac OS X 9 and later. */ #ifndef SQLITE_DISABLE_LFS # define _LARGE_FILE 1 # ifndef _FILE_OFFSET_BITS # define _FILE_OFFSET_BITS 64 # endif # define _LARGEFILE_SOURCE 1 #endif /* ** Include the configuration header output by 'configure' if we're using the ** autoconf-based build */ #ifdef _HAVE_SQLITE_CONFIG_H #include "config.h" #endif |
︙ | ︙ | |||
46 47 48 49 50 51 52 53 54 55 56 57 58 59 | #ifdef HAVE_STDINT_H #include <stdint.h> #endif #ifdef HAVE_INTTYPES_H #include <inttypes.h> #endif /* ** This macro is used to "hide" some ugliness in casting an int ** value to a ptr value under the MSVC 64-bit compiler. Casting ** non 64-bit values to ptr types results in a "hard" error with ** the MSVC 64-bit compiler which this attempts to avoid. ** ** A simple compiler pragma or casting sequence could not be found | > > | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | #ifdef HAVE_STDINT_H #include <stdint.h> #endif #ifdef HAVE_INTTYPES_H #include <inttypes.h> #endif #define SQLITE_INDEX_SAMPLES 10 /* ** This macro is used to "hide" some ugliness in casting an int ** value to a ptr value under the MSVC 64-bit compiler. Casting ** non 64-bit values to ptr types results in a "hard" error with ** the MSVC 64-bit compiler which this attempts to avoid. ** ** A simple compiler pragma or casting sequence could not be found |
︙ | ︙ | |||
78 79 80 81 82 83 84 | # define SQLITE_PTR_TO_INT(X) ((int)(X)) # endif #else # define SQLITE_INT_TO_PTR(X) ((void*)&((char*)0)[X]) # define SQLITE_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0)) #endif | < < < < < < < < < < < < < < < < < < < < < < < < < < < | 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | # define SQLITE_PTR_TO_INT(X) ((int)(X)) # endif #else # define SQLITE_INT_TO_PTR(X) ((void*)&((char*)0)[X]) # define SQLITE_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0)) #endif /* ** The SQLITE_THREADSAFE macro must be defined as either 0 or 1. ** Older versions of SQLite used an optional THREADSAFE macro. ** We support that for legacy */ #if !defined(SQLITE_THREADSAFE) |
︙ | ︙ | |||
301 302 303 304 305 306 307 | ** If compiling for a processor that lacks floating point support, ** substitute integer for floating-point */ #ifdef SQLITE_OMIT_FLOATING_POINT # define double sqlite_int64 # define LONGDOUBLE_TYPE sqlite_int64 # ifndef SQLITE_BIG_DBL | | | 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 | ** If compiling for a processor that lacks floating point support, ** substitute integer for floating-point */ #ifdef SQLITE_OMIT_FLOATING_POINT # define double sqlite_int64 # define LONGDOUBLE_TYPE sqlite_int64 # ifndef SQLITE_BIG_DBL # define SQLITE_BIG_DBL (((sqlite3_int64)1)<<50) # endif # define SQLITE_OMIT_DATETIME_FUNCS 1 # define SQLITE_OMIT_TRACE 1 # undef SQLITE_MIXED_ENDIAN_64BIT_FLOAT # undef SQLITE_HAVE_ISNAN #endif #ifndef SQLITE_BIG_DBL |
︙ | ︙ | |||
347 348 349 350 351 352 353 354 355 356 357 358 359 360 | ** the default file format for new databases and the maximum file format ** that the library can read. */ #define SQLITE_MAX_FILE_FORMAT 4 #ifndef SQLITE_DEFAULT_FILE_FORMAT # define SQLITE_DEFAULT_FILE_FORMAT 1 #endif /* ** Provide a default value for SQLITE_TEMP_STORE in case it is not specified ** on the command-line */ #ifndef SQLITE_TEMP_STORE # define SQLITE_TEMP_STORE 1 | > > > > | 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 | ** the default file format for new databases and the maximum file format ** that the library can read. */ #define SQLITE_MAX_FILE_FORMAT 4 #ifndef SQLITE_DEFAULT_FILE_FORMAT # define SQLITE_DEFAULT_FILE_FORMAT 1 #endif #ifndef SQLITE_DEFAULT_RECURSIVE_TRIGGERS # define SQLITE_DEFAULT_RECURSIVE_TRIGGERS 0 #endif /* ** Provide a default value for SQLITE_TEMP_STORE in case it is not specified ** on the command-line */ #ifndef SQLITE_TEMP_STORE # define SQLITE_TEMP_STORE 1 |
︙ | ︙ | |||
591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 | typedef struct ExprList ExprList; typedef struct ExprSpan ExprSpan; typedef struct FKey FKey; typedef struct FuncDef FuncDef; typedef struct FuncDefHash FuncDefHash; typedef struct IdList IdList; typedef struct Index Index; 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 Savepoint Savepoint; typedef struct Select Select; typedef struct SrcList SrcList; typedef struct StrAccum StrAccum; typedef struct Table Table; typedef struct TableLock TableLock; typedef struct Token Token; | > | > | 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 | typedef struct ExprList ExprList; typedef struct ExprSpan ExprSpan; typedef struct FKey FKey; typedef struct FuncDef FuncDef; typedef struct FuncDefHash FuncDefHash; typedef struct IdList IdList; typedef struct Index Index; typedef struct IndexSample IndexSample; typedef struct KeyClass KeyClass; typedef struct KeyInfo KeyInfo; typedef struct Lookaside Lookaside; typedef struct LookasideSlot LookasideSlot; typedef struct Module Module; typedef struct NameContext NameContext; typedef struct Parse Parse; typedef struct Savepoint Savepoint; typedef struct Select Select; typedef struct SrcList SrcList; typedef struct StrAccum StrAccum; typedef struct Table Table; typedef struct TableLock TableLock; typedef struct Token Token; typedef struct TriggerPrg TriggerPrg; typedef struct TriggerStep TriggerStep; typedef struct Trigger Trigger; typedef struct UnpackedRecord UnpackedRecord; typedef struct VTable VTable; typedef struct Walker Walker; typedef struct WherePlan WherePlan; typedef struct WhereInfo WhereInfo; typedef struct WhereLevel WhereLevel; /* ** Defer sourcing vdbe.h and btree.h until after the "u8" and |
︙ | ︙ | |||
659 660 661 662 663 664 665 666 667 668 669 670 671 672 | ** statements. */ struct Schema { int schema_cookie; /* Database schema version number for this file */ Hash tblHash; /* All tables indexed by name */ Hash idxHash; /* All (named) indices indexed by name */ Hash trigHash; /* All triggers indexed by name */ Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */ u8 file_format; /* Schema format version for this file */ u8 enc; /* Text encoding used by this database */ u16 flags; /* Flags associated with this schema */ int cache_size; /* Number of pages to use in the cache */ #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3 *db; /* "Owner" connection. See comment above */ | > | 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 | ** statements. */ struct Schema { int schema_cookie; /* Database schema version number for this file */ Hash tblHash; /* All tables indexed by name */ Hash idxHash; /* All (named) indices indexed by name */ Hash trigHash; /* All triggers indexed by name */ Hash fkeyHash; /* All foreign keys by referenced table name */ Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */ u8 file_format; /* Schema format version for this file */ u8 enc; /* Text encoding used by this database */ u16 flags; /* Flags associated with this schema */ int cache_size; /* Number of pages to use in the cache */ #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3 *db; /* "Owner" connection. See comment above */ |
︙ | ︙ | |||
696 697 698 699 700 701 702 | #define DB_UnresetViews 0x0002 /* Some views have defined column names */ #define DB_Empty 0x0004 /* The file is empty (length 0 bytes) */ /* ** The number of different kinds of things that can be limited ** using the sqlite3_limit() interface. */ | | | 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 | #define DB_UnresetViews 0x0002 /* Some views have defined column names */ #define DB_Empty 0x0004 /* The file is empty (length 0 bytes) */ /* ** The number of different kinds of things that can be limited ** using the sqlite3_limit() interface. */ #define SQLITE_N_LIMIT (SQLITE_LIMIT_TRIGGER_DEPTH+1) /* ** Lookaside malloc is a set of fixed-size buffers that can be used ** to satisfy small transient memory allocation requests for objects ** associated with a particular database connection. The use of ** lookaside malloc provides a significant performance enhancement ** (approx 10%) by avoiding numerous malloc/free requests while parsing |
︙ | ︙ | |||
795 796 797 798 799 800 801 802 803 804 805 806 807 808 | int nTotalChange; /* Value returned by sqlite3_total_changes() */ sqlite3_mutex *mutex; /* Connection mutex */ int aLimit[SQLITE_N_LIMIT]; /* Limits */ struct sqlite3InitInfo { /* Information used during initialization */ int iDb; /* When back is being initialized */ int newTnum; /* Rootpage of table being initialized */ u8 busy; /* TRUE if currently initializing */ } init; int nExtension; /* Number of loaded extensions */ void **aExtension; /* Array of shared library handles */ struct Vdbe *pVdbe; /* List of active virtual machines */ int activeVdbeCnt; /* Number of VDBEs currently executing */ int writeVdbeCnt; /* Number of active VDBEs that are writing */ void (*xTrace)(void*,const char*); /* Trace function */ | > | 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 | int nTotalChange; /* Value returned by sqlite3_total_changes() */ sqlite3_mutex *mutex; /* Connection mutex */ int aLimit[SQLITE_N_LIMIT]; /* Limits */ struct sqlite3InitInfo { /* Information used during initialization */ int iDb; /* When back is being initialized */ int newTnum; /* Rootpage of table being initialized */ u8 busy; /* TRUE if currently initializing */ u8 orphanTrigger; /* Last statement is orphaned TEMP trigger */ } init; int nExtension; /* Number of loaded extensions */ void **aExtension; /* Array of shared library handles */ struct Vdbe *pVdbe; /* List of active virtual machines */ int activeVdbeCnt; /* Number of VDBEs currently executing */ int writeVdbeCnt; /* Number of active VDBEs that are writing */ void (*xTrace)(void*,const char*); /* Trace function */ |
︙ | ︙ | |||
835 836 837 838 839 840 841 | int (*xProgress)(void *); /* The progress callback */ void *pProgressArg; /* Argument to the progress callback */ int nProgressOps; /* Number of opcodes for progress callback */ #endif #ifndef SQLITE_OMIT_VIRTUALTABLE Hash aModule; /* populated by sqlite3_create_module() */ Table *pVTab; /* vtab with active Connect/Create method */ | | > > | 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 | int (*xProgress)(void *); /* The progress callback */ void *pProgressArg; /* Argument to the progress callback */ int nProgressOps; /* Number of opcodes for progress callback */ #endif #ifndef SQLITE_OMIT_VIRTUALTABLE Hash aModule; /* populated by sqlite3_create_module() */ Table *pVTab; /* vtab with active Connect/Create method */ VTable **aVTrans; /* Virtual tables with open transactions */ int nVTrans; /* Allocated size of aVTrans */ VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */ #endif FuncDefHash aFunc; /* Hash table of connection functions */ Hash aCollSeq; /* All collating sequences */ BusyHandler busyHandler; /* Busy callback */ int busyTimeout; /* Busy handler timeout, in msec */ Db aDbStatic[2]; /* Static space for the 2 default backends */ Savepoint *pSavepoint; /* List of active savepoints */ int nSavepoint; /* Number of non-transaction savepoints */ int nStatement; /* Number of nested statement-transactions */ u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */ i64 nDeferredCons; /* Net deferred constraints this transaction. */ #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. |
︙ | ︙ | |||
901 902 903 904 905 906 907 | #define SQLITE_IgnoreChecks 0x00002000 /* Do not enforce check constraints */ #define SQLITE_ReadUncommitted 0x00004000 /* For shared-cache mode */ #define SQLITE_LegacyFileFmt 0x00008000 /* Create new databases in format 1 */ #define SQLITE_FullFSync 0x00010000 /* Use full fsync on the backend */ #define SQLITE_LoadExtension 0x00020000 /* Enable load_extension */ #define SQLITE_RecoveryMode 0x00040000 /* Ignore schema errors */ | | | | | 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 | #define SQLITE_IgnoreChecks 0x00002000 /* Do not enforce check constraints */ #define SQLITE_ReadUncommitted 0x00004000 /* For shared-cache mode */ #define SQLITE_LegacyFileFmt 0x00008000 /* Create new databases in format 1 */ #define SQLITE_FullFSync 0x00010000 /* Use full fsync on the backend */ #define SQLITE_LoadExtension 0x00020000 /* Enable load_extension */ #define SQLITE_RecoveryMode 0x00040000 /* Ignore schema errors */ #define SQLITE_ReverseOrder 0x00100000 /* Reverse unordered SELECTs */ #define SQLITE_RecTriggers 0x00200000 /* Enable recursive triggers */ #define SQLITE_ForeignKeys 0x00400000 /* Enforce foreign key constraints */ /* ** 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 */ |
︙ | ︙ | |||
944 945 946 947 948 949 950 951 952 953 954 955 956 957 | */ #define SQLITE_FUNC_LIKE 0x01 /* Candidate for the LIKE optimization */ #define SQLITE_FUNC_CASE 0x02 /* Case-sensitive LIKE-type function */ #define SQLITE_FUNC_EPHEM 0x04 /* Ephemeral. Delete with VDBE */ #define SQLITE_FUNC_NEEDCOLL 0x08 /* sqlite3GetFuncCollSeq() might be called */ #define SQLITE_FUNC_PRIVATE 0x10 /* Allowed for internal use only */ #define SQLITE_FUNC_COUNT 0x20 /* Built-in count(*) aggregate */ /* ** 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 | > | 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 | */ #define SQLITE_FUNC_LIKE 0x01 /* Candidate for the LIKE optimization */ #define SQLITE_FUNC_CASE 0x02 /* Case-sensitive LIKE-type function */ #define SQLITE_FUNC_EPHEM 0x04 /* Ephemeral. Delete with VDBE */ #define SQLITE_FUNC_NEEDCOLL 0x08 /* sqlite3GetFuncCollSeq() might be called */ #define SQLITE_FUNC_PRIVATE 0x10 /* Allowed for internal use only */ #define SQLITE_FUNC_COUNT 0x20 /* Built-in count(*) aggregate */ #define SQLITE_FUNC_COALESCE 0x40 /* Built-in coalesce() or ifnull() function */ /* ** 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 |
︙ | ︙ | |||
990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 | ** 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 ** OP_Savepoint instruction. */ struct Savepoint { char *zName; /* Savepoint name (nul-terminated) */ Savepoint *pNext; /* Parent savepoint (if any) */ }; /* ** The following are used as the second parameter to sqlite3Savepoint(), ** and as the P1 argument to the OP_Savepoint instruction. */ | > | 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 | ** 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 ** OP_Savepoint instruction. */ struct Savepoint { char *zName; /* Savepoint name (nul-terminated) */ i64 nDeferredCons; /* Number of deferred fk violations */ Savepoint *pNext; /* Parent savepoint (if any) */ }; /* ** The following are used as the second parameter to sqlite3Savepoint(), ** and as the P1 argument to the OP_Savepoint instruction. */ |
︙ | ︙ | |||
1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 | /* ** Additional bit values that can be ORed with an affinity without ** changing the affinity. */ #define SQLITE_JUMPIFNULL 0x08 /* jumps if either operand is NULL */ #define SQLITE_STOREP2 0x10 /* Store result in reg[P2] rather than jump */ /* ** Each SQL table is represented in memory by an instance of the ** following structure. ** ** Table.zName is the name of the table. The case of the original ** CREATE TABLE statement is stored, but case is not significant for | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* ** Additional bit values that can be ORed with an affinity without ** changing the affinity. */ #define SQLITE_JUMPIFNULL 0x08 /* jumps if either operand is NULL */ #define SQLITE_STOREP2 0x10 /* Store result in reg[P2] rather than jump */ #define SQLITE_NULLEQ 0x80 /* NULL=NULL */ /* ** An object of this type is created for each virtual table present in ** the database schema. ** ** If the database schema is shared, then there is one instance of this ** structure for each database connection (sqlite3*) that uses the shared ** schema. This is because each database connection requires its own unique ** instance of the sqlite3_vtab* handle used to access the virtual table ** implementation. sqlite3_vtab* handles can not be shared between ** database connections, even when the rest of the in-memory database ** schema is shared, as the implementation often stores the database ** connection handle passed to it via the xConnect() or xCreate() method ** during initialization internally. This database connection handle may ** then used by the virtual table implementation to access real tables ** within the database. So that they appear as part of the callers ** transaction, these accesses need to be made via the same database ** connection as that used to execute SQL operations on the virtual table. ** ** All VTable objects that correspond to a single table in a shared ** database schema are initially stored in a linked-list pointed to by ** the Table.pVTable member variable of the corresponding Table object. ** When an sqlite3_prepare() operation is required to access the virtual ** table, it searches the list for the VTable that corresponds to the ** database connection doing the preparing so as to use the correct ** sqlite3_vtab* handle in the compiled query. ** ** When an in-memory Table object is deleted (for example when the ** schema is being reloaded for some reason), the VTable objects are not ** deleted and the sqlite3_vtab* handles are not xDisconnect()ed ** immediately. Instead, they are moved from the Table.pVTable list to ** another linked list headed by the sqlite3.pDisconnect member of the ** corresponding sqlite3 structure. They are then deleted/xDisconnected ** next time a statement is prepared using said sqlite3*. This is done ** to avoid deadlock issues involving multiple sqlite3.mutex mutexes. ** Refer to comments above function sqlite3VtabUnlockList() for an ** explanation as to why it is safe to add an entry to an sqlite3.pDisconnect ** list without holding the corresponding sqlite3.mutex mutex. ** ** The memory for objects of this type is always allocated by ** sqlite3DbMalloc(), using the connection handle stored in VTable.db as ** the first argument. */ 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 */ VTable *pNext; /* Next in linked list (see above) */ }; /* ** Each SQL table is represented in memory by an instance of the ** following structure. ** ** Table.zName is the name of the table. The case of the original ** CREATE TABLE statement is stored, but case is not significant for |
︙ | ︙ | |||
1162 1163 1164 1165 1166 1167 1168 | #ifndef SQLITE_OMIT_CHECK Expr *pCheck; /* The AND of all CHECK constraints */ #endif #ifndef SQLITE_OMIT_ALTERTABLE int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */ #endif #ifndef SQLITE_OMIT_VIRTUALTABLE | | < | 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 | #ifndef SQLITE_OMIT_CHECK Expr *pCheck; /* The AND of all CHECK constraints */ #endif #ifndef SQLITE_OMIT_ALTERTABLE int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */ #endif #ifndef SQLITE_OMIT_VIRTUALTABLE VTable *pVTable; /* List of VTable objects. */ int nModuleArg; /* Number of arguments to the module */ char **azModuleArg; /* Text of all module args. [0] is module name */ #endif Trigger *pTrigger; /* List of triggers stored in pSchema */ Schema *pSchema; /* Schema that contains this table */ Table *pNextZombie; /* Next on the Parse.pZombieTab list */ }; |
︙ | ︙ | |||
1217 1218 1219 1220 1221 1222 1223 | ** For foreign key "fk1", the from-table is "ex1" and the to-table is "ex2". ** ** Each REFERENCES clause generates an instance of the following structure ** which is attached to the from-table. The to-table need not exist when ** the from-table is created. The existence of the to-table is not checked. */ struct FKey { | | | > > > | < < > | 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 | ** For foreign key "fk1", the from-table is "ex1" and the to-table is "ex2". ** ** Each REFERENCES clause generates an instance of the following structure ** which is attached to the from-table. The to-table need not exist when ** the from-table is created. The existence of the to-table is not checked. */ struct FKey { Table *pFrom; /* Table containing the REFERENCES clause (aka: Child) */ FKey *pNextFrom; /* Next foreign key in pFrom */ char *zTo; /* Name of table that the key points to (aka: Parent) */ FKey *pNextTo; /* Next foreign key on table named zTo */ FKey *pPrevTo; /* Previous foreign key on table named zTo */ int nCol; /* Number of columns in this key */ /* EV: R-30323-21917 */ u8 isDeferred; /* True if constraint checking is deferred till COMMIT */ u8 aAction[2]; /* ON DELETE and ON UPDATE actions, respectively */ Trigger *apTrigger[2]; /* Triggers for aAction[] actions */ struct sColMap { /* Mapping of columns in pFrom to columns in zTo */ int iFrom; /* Index of column in pFrom */ char *zCol; /* Name of column in zTo. If 0 use PRIMARY KEY */ } aCol[1]; /* One entry for each of nCol column s */ }; /* |
︙ | ︙ | |||
1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 | u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */ 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; /* Array of size Index.nColumn. True==DESC, False==ASC */ char **azColl; /* Array of collation sequence names for index */ }; /* ** Each token coming out of the lexer is an instance of ** this structure. Tokens are also used as part of an expression. ** ** Note if Token.z==0 then Token.dyn and Token.n are undefined and | > > > > > > > > > > > > > > | 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 | u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */ 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; /* Array of size Index.nColumn. True==DESC, False==ASC */ char **azColl; /* Array of collation sequence names for index */ IndexSample *aSample; /* Array of SQLITE_INDEX_SAMPLES samples */ }; /* ** Each sample stored in the sqlite_stat2 table is represented in memory ** using a structure of this type. */ struct IndexSample { union { char *z; /* Value if eType is SQLITE_TEXT or SQLITE_BLOB */ double r; /* Value if eType is SQLITE_FLOAT or SQLITE_INTEGER */ } u; u8 eType; /* SQLITE_NULL, SQLITE_INTEGER ... etc. */ u8 nByte; /* Size in byte of text or blob. */ }; /* ** Each token coming out of the lexer is an instance of ** this structure. Tokens are also used as part of an expression. ** ** Note if Token.z==0 then Token.dyn and Token.n are undefined and |
︙ | ︙ | |||
1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 | int iMem; /* Memory location that acts as accumulator */ int iDistinct; /* Ephemeral table used to enforce DISTINCT */ } *aFunc; int nFunc; /* Number of entries in aFunc[] */ int nFuncAlloc; /* Number of slots allocated for aFunc[] */ }; /* ** 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 | > > > > > > > > > > > > > > > > | 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 | int iMem; /* Memory location that acts as accumulator */ int iDistinct; /* Ephemeral table used to enforce DISTINCT */ } *aFunc; int nFunc; /* Number of entries in aFunc[] */ int nFuncAlloc; /* Number of slots allocated for 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 |
︙ | ︙ | |||
1506 1507 1508 1509 1510 1511 1512 | /* If the EP_Reduced flag is set in the Expr.flags mask, then no ** space is allocated for the fields below this point. An attempt to ** access them will result in a segfault or malfunction. *********************************************************************/ int iTable; /* TK_COLUMN: cursor number of table holding column | | > | > | > | 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 | /* If the EP_Reduced flag is set in the Expr.flags mask, then no ** space is allocated for the fields below this point. An attempt to ** access them will result in a segfault or malfunction. *********************************************************************/ int iTable; /* TK_COLUMN: cursor number of table holding column ** TK_REGISTER: register number ** TK_TRIGGER: 1 -> new, 0 -> old */ ynVar iColumn; /* TK_COLUMN: column index. -1 for rowid. ** TK_VARIABLE: variable number (always >= 1). */ i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */ i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */ u8 flags2; /* Second set of flags. EP2_... */ u8 op2; /* If a TK_REGISTER, the original value of Expr.op */ AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */ Table *pTab; /* Table for TK_COLUMN expressions. */ #if SQLITE_MAX_EXPR_DEPTH>0 int nHeight; /* Height of the tree headed by this node */ #endif }; |
︙ | ︙ | |||
1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 | /* ** Size of the column cache */ #ifndef SQLITE_N_COLCACHE # define SQLITE_N_COLCACHE 10 #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 | > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* ** Size of the column cache */ #ifndef SQLITE_N_COLCACHE # define SQLITE_N_COLCACHE 10 #endif /* ** At least one instance of the following structure is created for each ** trigger that may be fired while parsing an INSERT, UPDATE or DELETE ** statement. All such objects are stored in the linked list headed at ** Parse.pTriggerPrg and deleted once statement compilation has been ** completed. ** ** A Vdbe sub-program that implements the body and WHEN clause of trigger ** TriggerPrg.pTrigger, assuming a default ON CONFLICT clause of ** TriggerPrg.orconf, is stored in the TriggerPrg.pProgram variable. ** The Parse.pTriggerPrg list never contains two entries with the same ** values for both pTrigger and orconf. ** ** The TriggerPrg.oldmask variable is set to a mask of old.* columns ** accessed (or set to 0 for triggers fired as a result of INSERT ** statements). */ struct TriggerPrg { Trigger *pTrigger; /* Trigger this program was coded from */ int orconf; /* Default ON CONFLICT policy */ SubProgram *pProgram; /* Program implementing pTrigger/orconf */ u32 oldmask; /* Mask of old.* columns accessed */ TriggerPrg *pNext; /* Next entry in Parse.pTriggerPrg list */ }; /* ** 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 |
︙ | ︙ | |||
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 | u8 tempReg; /* iReg is a temp register that needs to be freed */ int iLevel; /* Nesting level */ int iReg; /* Reg with value of this column. 0 means none. */ int lru; /* Least recently used entry has the smallest value */ } aColCache[SQLITE_N_COLCACHE]; /* One for each column cache entry */ u32 writeMask; /* Start a write transaction on these databases */ u32 cookieMask; /* Bitmask of schema verified databases */ int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */ int cookieValue[SQLITE_MAX_ATTACHED+2]; /* Values of cookies to verify */ #ifndef SQLITE_OMIT_SHARED_CACHE int nTableLock; /* Number of locks in aTableLock */ TableLock *aTableLock; /* Required table locks for shared-cache mode */ #endif int regRowid; /* Register holding rowid of CREATE TABLE entry */ int regRoot; /* Register holding root page number for new objects */ AutoincInfo *pAinc; /* Information about AUTOINCREMENT counters */ /* Above is constant between recursions. Below is reset before and after ** each recursion */ int nVar; /* Number of '?' variables seen in the SQL so far */ int nVarExpr; /* Number of used slots in apVarExpr[] */ int nVarExprAlloc; /* Number of allocated slots in apVarExpr[] */ Expr **apVarExpr; /* Pointers to :aaa and $aaaa wildcard expressions */ int nAlias; /* Number of aliased result set columns */ int nAliasAlloc; /* Number of allocated slots for aAlias[] */ int *aAlias; /* Register used to hold aliased result */ u8 explain; /* True if the EXPLAIN flag is found on the query */ | > > > > > > > > > > > > < < < > | | | | | > | | 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 | u8 tempReg; /* iReg is a temp register that needs to be freed */ int iLevel; /* Nesting level */ int iReg; /* Reg with value of this column. 0 means none. */ int lru; /* Least recently used entry has the smallest value */ } aColCache[SQLITE_N_COLCACHE]; /* One for each column cache entry */ u32 writeMask; /* Start a write transaction on these databases */ u32 cookieMask; /* Bitmask of schema verified databases */ u8 isMultiWrite; /* True if statement may affect/insert multiple rows */ u8 mayAbort; /* True if statement may throw an ABORT exception */ int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */ int cookieValue[SQLITE_MAX_ATTACHED+2]; /* Values of cookies to verify */ #ifndef SQLITE_OMIT_SHARED_CACHE int nTableLock; /* Number of locks in aTableLock */ TableLock *aTableLock; /* Required table locks for shared-cache mode */ #endif int regRowid; /* Register holding rowid of CREATE TABLE entry */ int regRoot; /* Register holding root page number for new objects */ AutoincInfo *pAinc; /* Information about AUTOINCREMENT counters */ int nMaxArg; /* Max args passed to user function by sub-program */ /* Information used while coding trigger programs. */ Parse *pToplevel; /* Parse structure for main program (or NULL) */ Table *pTriggerTab; /* Table triggers are being coded for */ u32 oldmask; /* Mask of old.* 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 */ /* Above is constant between recursions. Below is reset before and after ** each recursion */ int nVar; /* Number of '?' variables seen in the SQL so far */ int nVarExpr; /* Number of used slots in apVarExpr[] */ int nVarExprAlloc; /* Number of allocated slots in apVarExpr[] */ Expr **apVarExpr; /* Pointers to :aaa and $aaaa wildcard expressions */ Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */ int nAlias; /* Number of aliased result set columns */ int nAliasAlloc; /* Number of allocated slots for aAlias[] */ int *aAlias; /* Register used to hold aliased result */ u8 explain; /* True if the EXPLAIN flag is found on the query */ Token sNameToken; /* Token with unqualified schema object name */ Token sLastToken; /* The last token parsed */ const char *zTail; /* All SQL text past the last semicolon parsed */ Table *pNewTable; /* A table being constructed by CREATE TABLE */ 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 */ u8 declareVtab; /* True if inside sqlite3_declare_vtab() */ int nVtabLock; /* Number of virtual tables to lock */ Table **apVtabLock; /* Pointer to virtual tables needing locking */ #endif int nHeight; /* Expression tree height of current sub-select */ Table *pZombieTab; /* List of Table objects to delete after code gen */ TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */ }; #ifdef SQLITE_OMIT_VIRTUALTABLE #define IN_DECLARE_VTAB 0 #else #define IN_DECLARE_VTAB (pParse->declareVtab) #endif /* ** An instance of the following structure can be declared on a stack and used ** to save the Parse.zAuthContext value so that it can be restored later. */ struct AuthContext { const char *zAuthContext; /* Put saved Parse.zAuthContext here */ Parse *pParse; /* The Parse structure */ }; /* ** Bitfield flags for P5 value in OP_Insert and OP_Delete */ #define OPFLAG_NCHANGE 0x01 /* Set to update db->nChange */ #define OPFLAG_LASTROWID 0x02 /* Set to update db->lastRowid */ #define OPFLAG_ISUPDATE 0x04 /* This OP_Insert is an sql UPDATE */ #define OPFLAG_APPEND 0x08 /* This is likely to be an append */ #define OPFLAG_USESEEKRESULT 0x10 /* Try to avoid a seek in BtreeInsert() */ #define OPFLAG_CLEARCACHE 0x20 /* Clear pseudo-table cache in OP_Column */ /* * 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 */ |
︙ | ︙ | |||
2137 2138 2139 2140 2141 2142 2143 | * 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 { | | | < | < | | | < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | * 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 statment or RHS of INSERT INTO .. SELECT ... */ Token target; /* Target table for DELETE, UPDATE, INSERT */ Expr *pWhere; /* The WHERE clause for DELETE or UPDATE steps */ ExprList *pExprList; /* SET clause for UPDATE. VALUES clause for INSERT */ IdList *pIdList; /* Column names for INSERT */ 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 { |
︙ | ︙ | |||
2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 | int nPage; /* Number of pages in pPage[] */ int mxParserStack; /* maximum depth of the parser stack */ int sharedCacheEnabled; /* true if shared-cache mode enabled */ /* The above might be initialized to non-zero. The following need to always ** initially be zero, however. */ int isInit; /* True after initialization has finished */ int inProgress; /* True while initialization in progress */ int isMallocInit; /* True after malloc is initialized */ sqlite3_mutex *pInitMutex; /* Mutex used by sqlite3_initialize() */ int nRefInitMutex; /* Number of users of pInitMutex */ }; /* ** Context pointer passed down through the tree-walk. */ | > > | 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 | int nPage; /* Number of pages in pPage[] */ int mxParserStack; /* maximum depth of the parser stack */ int sharedCacheEnabled; /* true if shared-cache mode enabled */ /* The above might be initialized to non-zero. The following need to always ** initially be zero, however. */ int isInit; /* True after initialization has finished */ int inProgress; /* True while initialization in progress */ int isMutexInit; /* True after mutexes are initialized */ int isMallocInit; /* True after malloc is initialized */ int isPCacheInit; /* True after malloc is initialized */ sqlite3_mutex *pInitMutex; /* Mutex used by sqlite3_initialize() */ int nRefInitMutex; /* Number of users of pInitMutex */ }; /* ** Context pointer passed down through the tree-walk. */ |
︙ | ︙ | |||
2353 2354 2355 2356 2357 2358 2359 | # define sqlite3Tolower(x) tolower((unsigned char)(x)) #endif /* ** Internal function prototypes */ int sqlite3StrICmp(const char *, const char *); | < > | 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 | # define sqlite3Tolower(x) tolower((unsigned char)(x)) #endif /* ** Internal function prototypes */ int sqlite3StrICmp(const char *, const char *); int sqlite3IsNumber(const char*, int*, u8); int sqlite3Strlen30(const char*); #define sqlite3StrNICmp sqlite3_strnicmp int sqlite3MallocInit(void); void sqlite3MallocEnd(void); void *sqlite3Malloc(int); void *sqlite3MallocZero(int); void *sqlite3DbMallocZero(sqlite3*, int); void *sqlite3DbMallocRaw(sqlite3*, int); |
︙ | ︙ | |||
2515 2516 2517 2518 2519 2520 2521 | Token*, Select*, Expr*, IdList*); void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *); int sqlite3IndexedByLookup(Parse *, struct SrcList_item *); void sqlite3SrcListShiftJoinType(SrcList*); void sqlite3SrcListAssignCursors(Parse*, SrcList*); void sqlite3IdListDelete(sqlite3*, IdList*); void sqlite3SrcListDelete(sqlite3*, SrcList*); | | | 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 | Token*, Select*, Expr*, IdList*); void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *); int sqlite3IndexedByLookup(Parse *, struct SrcList_item *); void sqlite3SrcListShiftJoinType(SrcList*); void sqlite3SrcListAssignCursors(Parse*, SrcList*); void sqlite3IdListDelete(sqlite3*, IdList*); void sqlite3SrcListDelete(sqlite3*, SrcList*); Index *sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, Token*, int, int); void sqlite3DropIndex(Parse*, SrcList*, int); int sqlite3Select(Parse*, Select*, SelectDest*); Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*, Expr*,ExprList*,int,Expr*,Expr*); void sqlite3SelectDelete(sqlite3*, Select*); Table *sqlite3SrcListLookup(Parse*, SrcList*); |
︙ | ︙ | |||
2562 2563 2564 2565 2566 2567 2568 | void sqlite3Vacuum(Parse*); int sqlite3RunVacuum(char**, sqlite3*); char *sqlite3NameFromToken(sqlite3*, Token*); int sqlite3ExprCompare(Expr*, Expr*); void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); Vdbe *sqlite3GetVdbe(Parse*); | < | | > > > | 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 | void sqlite3Vacuum(Parse*); int sqlite3RunVacuum(char**, sqlite3*); char *sqlite3NameFromToken(sqlite3*, Token*); int sqlite3ExprCompare(Expr*, Expr*); void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); Vdbe *sqlite3GetVdbe(Parse*); void sqlite3PrngSaveState(void); void sqlite3PrngRestoreState(void); void sqlite3PrngResetState(void); void sqlite3RollbackAll(sqlite3*); void sqlite3CodeVerifySchema(Parse*, int); void sqlite3BeginTransaction(Parse*, int); void sqlite3CommitTransaction(Parse*); void sqlite3RollbackTransaction(Parse*); void sqlite3Savepoint(Parse*, int, Token*); void sqlite3CloseSavepoints(sqlite3 *); int sqlite3ExprIsConstant(Expr*); int sqlite3ExprIsConstantNotJoin(Expr*); int sqlite3ExprIsConstantOrFunction(Expr*); int sqlite3ExprIsInteger(Expr*, int*); int sqlite3IsRowid(const char*); void sqlite3GenerateRowDelete(Parse*, Table*, int, int, int, Trigger *, int); void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int*); int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int); void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int, int*,int,int,int,int,int*); void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*, int, int, int); int sqlite3OpenTableAndIndices(Parse*, Table*, int, int); void sqlite3BeginWriteOperation(Parse*, int, int); void sqlite3MultiWrite(Parse*); void sqlite3MayAbort(Parse*); void sqlite3HaltConstraint(Parse*, int, char*, int); Expr *sqlite3ExprDup(sqlite3*,Expr*,int); ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int); SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int); IdList *sqlite3IdListDup(sqlite3*,IdList*); Select *sqlite3SelectDup(sqlite3*,Select*,int); void sqlite3FuncDefInsert(FuncDefHash*, FuncDef*); FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,int,u8,int); |
︙ | ︙ | |||
2619 2620 2621 2622 2623 2624 2625 | void sqlite3BeginTrigger(Parse*, Token*,Token*,int,int,IdList*,SrcList*, Expr*,int, int); void sqlite3FinishTrigger(Parse*, TriggerStep*, Token*); void sqlite3DropTrigger(Parse*, SrcList*, int); void sqlite3DropTriggerPtr(Parse*, Trigger*); Trigger *sqlite3TriggersExist(Parse *, Table*, int, ExprList*, int *pMask); Trigger *sqlite3TriggerList(Parse *, Table *); | | | > | | > > | > > > > | | 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 | void sqlite3BeginTrigger(Parse*, Token*,Token*,int,int,IdList*,SrcList*, Expr*,int, int); void sqlite3FinishTrigger(Parse*, TriggerStep*, Token*); void sqlite3DropTrigger(Parse*, SrcList*, int); void sqlite3DropTriggerPtr(Parse*, Trigger*); Trigger *sqlite3TriggersExist(Parse *, Table*, int, ExprList*, int *pMask); Trigger *sqlite3TriggerList(Parse *, Table *); void sqlite3CodeRowTrigger(Parse*, Trigger *, int, ExprList*, int, Table *, int, int, int); void sqlite3CodeRowTriggerDirect(Parse *, Trigger *, Table *, int, int, int); void sqliteViewTriggers(Parse*, Table*, Expr*, int, ExprList*); void sqlite3DeleteTriggerStep(sqlite3*, TriggerStep*); TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*); TriggerStep *sqlite3TriggerInsertStep(sqlite3*,Token*, IdList*, ExprList*,Select*,u8); TriggerStep *sqlite3TriggerUpdateStep(sqlite3*,Token*,ExprList*, Expr*, u8); TriggerStep *sqlite3TriggerDeleteStep(sqlite3*,Token*, Expr*); void sqlite3DeleteTrigger(sqlite3*, Trigger*); void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*); u32 sqlite3TriggerOldmask(Parse*,Trigger*,ExprList*,Table*,int); # define sqlite3ParseToplevel(p) ((p)->pToplevel ? (p)->pToplevel : (p)) #else # define sqlite3TriggersExist(B,C,D,E,F) 0 # define sqlite3DeleteTrigger(A,B) # define sqlite3DropTriggerPtr(A,B) # define sqlite3UnlinkAndDeleteTrigger(A,B,C) # define sqlite3CodeRowTrigger(A,B,C,D,E,F,G,H,I) # define sqlite3CodeRowTriggerDirect(A,B,C,D,E,F) # define sqlite3TriggerList(X, Y) 0 # define sqlite3ParseToplevel(p) p # define sqlite3TriggerOldmask(A,B,C,D,E) 0 #endif int sqlite3JoinType(Parse*, Token*, Token*, Token*); 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*); int sqlite3BtreeFactory(sqlite3 *db, const char *zFilename, int omitJournal, int nCache, int flags, Btree **ppBtree); int 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*); |
︙ | ︙ | |||
2706 2707 2708 2709 2710 2711 2712 | */ #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 : sqlite3PutVarint32((A), (B))) #define getVarint sqlite3GetVarint #define putVarint sqlite3PutVarint | | | 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 | */ #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 : sqlite3PutVarint32((A), (B))) #define getVarint sqlite3GetVarint #define putVarint sqlite3PutVarint const char *sqlite3IndexAffinityStr(Vdbe *, Index *); void sqlite3TableAffinityStr(Vdbe *, Table *); char sqlite3CompareAffinity(Expr *pExpr, char aff2); int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); char sqlite3ExprAffinity(Expr *pExpr); int sqlite3Atoi64(const char*, i64*); void sqlite3Error(sqlite3*, int, const char*,...); void *sqlite3HexToBlob(sqlite3*, const char *z, int n); |
︙ | ︙ | |||
2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 | const void *sqlite3ValueText(sqlite3_value*, u8); int sqlite3ValueBytes(sqlite3_value*, u8); void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*)); void sqlite3ValueFree(sqlite3_value*); sqlite3_value *sqlite3ValueNew(sqlite3 *); char *sqlite3Utf16to8(sqlite3 *, const void*, int); int sqlite3ValueFromExpr(sqlite3 *, Expr *, u8, u8, sqlite3_value **); void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8); #ifndef SQLITE_AMALGAMATION extern const unsigned char sqlite3UpperToLower[]; extern const unsigned char sqlite3CtypeMap[]; extern SQLITE_WSD struct Sqlite3Config sqlite3Config; extern SQLITE_WSD FuncDefHash sqlite3GlobalFunctions; extern int sqlite3PendingByte; #endif void sqlite3RootPageMoved(Db*, int, int); void sqlite3Reindex(Parse*, Token*, Token*); void sqlite3AlterFunctions(sqlite3*); void sqlite3AlterRenameTable(Parse*, SrcList*, Token*); int sqlite3GetToken(const unsigned char *, int *); void sqlite3NestedParse(Parse*, const char*, ...); void sqlite3ExpirePreparedStatements(sqlite3*); | > > > | | | > > | 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 | const void *sqlite3ValueText(sqlite3_value*, u8); int sqlite3ValueBytes(sqlite3_value*, u8); void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*)); void sqlite3ValueFree(sqlite3_value*); sqlite3_value *sqlite3ValueNew(sqlite3 *); char *sqlite3Utf16to8(sqlite3 *, const void*, int); #ifdef SQLITE_ENABLE_STAT2 char *sqlite3Utf8to16(sqlite3 *, u8, char *, int, int *); #endif int sqlite3ValueFromExpr(sqlite3 *, Expr *, u8, u8, sqlite3_value **); void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8); #ifndef SQLITE_AMALGAMATION extern const unsigned char sqlite3UpperToLower[]; extern const unsigned char sqlite3CtypeMap[]; extern SQLITE_WSD struct Sqlite3Config sqlite3Config; extern SQLITE_WSD FuncDefHash sqlite3GlobalFunctions; extern int sqlite3PendingByte; #endif void sqlite3RootPageMoved(Db*, int, int); void sqlite3Reindex(Parse*, Token*, Token*); void sqlite3AlterFunctions(sqlite3*); void sqlite3AlterRenameTable(Parse*, SrcList*, Token*); int sqlite3GetToken(const unsigned char *, int *); void sqlite3NestedParse(Parse*, const char*, ...); void sqlite3ExpirePreparedStatements(sqlite3*); int sqlite3CodeSubselect(Parse *, Expr *, int, int); void sqlite3SelectPrep(Parse*, Select*, NameContext*); int sqlite3ResolveExprNames(NameContext*, Expr*); void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*); int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*); void sqlite3ColumnDefault(Vdbe *, Table *, int, int); void sqlite3AlterFinishAddColumn(Parse *, Token *); void sqlite3AlterBeginAddColumn(Parse *, SrcList *); CollSeq *sqlite3GetCollSeq(sqlite3*, u8, CollSeq *, const char*); char sqlite3AffinityType(const char*); void sqlite3Analyze(Parse*, Token*, Token*); int sqlite3InvokeBusyHandler(BusyHandler*); int sqlite3FindDb(sqlite3*, Token*); int sqlite3FindDbName(sqlite3 *, const char *); int sqlite3AnalysisLoad(sqlite3*,int iDB); void sqlite3DeleteIndexSamples(Index*); void sqlite3DefaultRowEst(Index*); void sqlite3RegisterLikeFunctions(sqlite3*, int); int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*); void sqlite3MinimumFileFormat(Parse*, int, int); void sqlite3SchemaFree(void *); Schema *sqlite3SchemaGet(sqlite3 *, Btree *); int sqlite3SchemaToIndex(sqlite3 *db, Schema *); KeyInfo *sqlite3IndexKeyinfo(Parse *, Index *); int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *, void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*)); int sqlite3ApiExit(sqlite3 *db, int); int sqlite3OpenTempDatabase(Parse *); void sqlite3StrAccumInit(StrAccum*, char*, int, int); void sqlite3StrAccumAppend(StrAccum*,const char*,int); char *sqlite3StrAccumFinish(StrAccum*); void sqlite3StrAccumReset(StrAccum*); void sqlite3SelectDestInit(SelectDest*,int,int); Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int); void sqlite3BackupRestart(sqlite3_backup *); void sqlite3BackupUpdate(sqlite3_backup *, Pgno, const u8 *); /* ** The interface to the LEMON-generated parser */ |
︙ | ︙ | |||
2814 2815 2816 2817 2818 2819 2820 | #endif #ifdef SQLITE_TEST int sqlite3Utf8To8(unsigned char*); #endif #ifdef SQLITE_OMIT_VIRTUALTABLE | | > > > > > > < < | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | #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) #else void sqlite3VtabClear(Table*); int sqlite3VtabSync(sqlite3 *db, char **); int sqlite3VtabRollback(sqlite3 *db); int sqlite3VtabCommit(sqlite3 *db); void sqlite3VtabLock(VTable *); void sqlite3VtabUnlock(VTable *); void sqlite3VtabUnlockList(sqlite3*); # define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0) #endif void sqlite3VtabMakeWritable(Parse*,Table*); void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*); 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*); void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**); int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *); int sqlite3Reprepare(Vdbe*); void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*); CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *); int sqlite3TempInMemory(const sqlite3*); VTable *sqlite3GetVTable(sqlite3*, Table*); /* 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); void sqlite3FkDropTable(Parse*, SrcList *, Table*); void sqlite3FkActions(Parse*, Table*, ExprList*, int); int sqlite3FkRequired(Parse*, Table*, int*, int); u32 sqlite3FkOldmask(Parse*, Table*); FKey *sqlite3FkReferences(Table *); #else #define sqlite3FkActions(a,b,c,d) #define sqlite3FkCheck(a,b,c,d) #define sqlite3FkDropTable(a,b,c) #define sqlite3FkOldmask(a,b) 0 #define sqlite3FkRequired(a,b,c,d) 0 #endif #ifndef SQLITE_OMIT_FOREIGN_KEY void sqlite3FkDelete(Table*); #else #define sqlite3FkDelete(a) #endif /* ** Available fault injectors. Should be numbered beginning with 0. */ #define SQLITE_FAULTINJECTOR_MALLOC 0 #define SQLITE_FAULTINJECTOR_COUNT 1 |
︙ | ︙ |
Changes to src/sqliteLimit.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2007 May 7 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you 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 defines various limits of what SQLite can process. | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* ** 2007 May 7 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you 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 defines various limits of what SQLite can process. */ /* ** The maximum length of a TEXT or BLOB in bytes. This also ** limits the size of a row in a table or index. ** ** The hard limit is the ability of a 32-bit signed integer |
︙ | ︙ | |||
184 185 186 187 188 189 190 | /* ** Maximum length (in bytes) of the pattern in a LIKE or GLOB ** operator. */ #ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH # define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000 #endif | > > > > > > > > > > > | 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | /* ** Maximum length (in bytes) of the pattern in a LIKE or GLOB ** operator. */ #ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH # define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000 #endif /* ** Maximum depth of recursion for triggers. ** ** A value of 1 means that a trigger program will not be able to itself ** fire any triggers. A value of 0 means that no trigger programs at all ** may be executed. */ #ifndef SQLITE_MAX_TRIGGER_DEPTH # define SQLITE_MAX_TRIGGER_DEPTH 1000 #endif |
Changes to src/status.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This module implements the sqlite3_status() interface and related ** functionality. | < < | 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. ** ************************************************************************* ** ** This module implements the sqlite3_status() interface and related ** functionality. */ #include "sqliteInt.h" /* ** Variables in which to record status information. */ typedef struct sqlite3StatType sqlite3StatType; |
︙ | ︙ |
Changes to src/table.c.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ************************************************************************* ** This file contains the sqlite3_get_table() and sqlite3_free_table() ** interface routines. These are just wrappers around the main ** interface routine of sqlite3_exec(). ** ** These routines are in a separate files so that they will not be linked ** if they are not used. | < < | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ************************************************************************* ** This file contains the sqlite3_get_table() and sqlite3_free_table() ** interface routines. These are just wrappers around the main ** interface routine of sqlite3_exec(). ** ** These routines are in a separate files so that they will not be linked ** if they are not used. */ #include "sqliteInt.h" #include <stdlib.h> #include <string.h> #ifndef SQLITE_OMIT_GET_TABLE |
︙ | ︙ |
Changes to src/tclsqlite.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. ** ************************************************************************* ** A TCL Interface to SQLite. Append this file to sqlite3.c and ** compile the whole thing to build a TCL-enabled version of SQLite. ** | | > > > > > > > > > > > < > | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** A TCL Interface to SQLite. Append this file to sqlite3.c and ** compile the whole thing to build a TCL-enabled version of SQLite. ** ** Compile-time options: ** ** -DTCLSH=1 Add a "main()" routine that works as a tclsh. ** ** -DSQLITE_TCLMD5 When used in conjuction with -DTCLSH=1, add ** four new commands to the TCL interpreter for ** generating MD5 checksums: md5, md5file, ** md5-10x8, and md5file-10x8. ** ** -DSQLITE_TEST When used in conjuction with -DTCLSH=1, add ** hundreds of new commands used for testing ** SQLite. This option implies -DSQLITE_TCLMD5. */ #include "tcl.h" #include <errno.h> /* ** Some additional include files are needed if this file is not ** appended to the amalgamation. */ #ifndef SQLITE_AMALGAMATION # include "sqliteInt.h" # include <stdlib.h> # include <string.h> # include <assert.h> #endif #include <ctype.h> /* * Windows needs to know which symbols to export. Unix does not. * BUILD_sqlite should be undefined for Unix. */ #ifdef BUILD_sqlite #undef TCL_STORAGE_CLASS |
︙ | ︙ | |||
82 83 84 85 86 87 88 89 90 91 92 93 94 95 | typedef struct SqlPreparedStmt SqlPreparedStmt; struct SqlPreparedStmt { SqlPreparedStmt *pNext; /* Next in linked list */ SqlPreparedStmt *pPrev; /* Previous on the list */ sqlite3_stmt *pStmt; /* The prepared statement */ int nSql; /* chars in zSql[] */ const char *zSql; /* Text of the SQL statement */ }; typedef struct IncrblobChannel IncrblobChannel; /* ** There is one instance of this structure for each SQLite database ** that has been opened by the SQLite TCL interface. | > > | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | typedef struct SqlPreparedStmt SqlPreparedStmt; struct SqlPreparedStmt { SqlPreparedStmt *pNext; /* Next in linked list */ SqlPreparedStmt *pPrev; /* Previous on the list */ sqlite3_stmt *pStmt; /* The prepared statement */ int nSql; /* chars in zSql[] */ const char *zSql; /* Text of the SQL statement */ int nParm; /* Size of apParm array */ Tcl_Obj **apParm; /* Array of referenced object pointers */ }; typedef struct IncrblobChannel IncrblobChannel; /* ** There is one instance of this structure for each SQLite database ** that has been opened by the SQLite TCL interface. |
︙ | ︙ | |||
753 754 755 756 757 758 759 | if( rc && rc!=TCL_RETURN ){ sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); }else{ Tcl_Obj *pVar = Tcl_GetObjResult(p->interp); int n; u8 *data; | | | 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 | if( rc && rc!=TCL_RETURN ){ sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); }else{ Tcl_Obj *pVar = Tcl_GetObjResult(p->interp); int n; u8 *data; const char *zType = (pVar->typePtr ? pVar->typePtr->name : ""); char c = zType[0]; if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){ /* Only return a BLOB type if the Tcl variable is a bytearray and ** has no string representation. */ data = Tcl_GetByteArrayFromObj(pVar, &n); sqlite3_result_blob(context, data, n, SQLITE_TRANSIENT); }else if( c=='b' && strcmp(zType,"boolean")==0 ){ |
︙ | ︙ | |||
930 931 932 933 934 935 936 | } zLine = realloc( zLine, n+1 ); return zLine; } /* | > > > > > > > > > > > > > > > > > > > > > | > > | > > > > > > > | > > > > > > > > > > > | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | | | < | | | | > > > > | > > > | > > > > > > > > > > > > > > > > > | | < | | | | > > | > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < | | 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 | } zLine = realloc( zLine, n+1 ); return zLine; } /* ** This function is part of the implementation of the command: ** ** $db transaction [-deferred|-immediate|-exclusive] SCRIPT ** ** It is invoked after evaluating the script SCRIPT to commit or rollback ** the transaction or savepoint opened by the [transaction] command. */ static int DbTransPostCmd( ClientData data[], /* data[0] is the Sqlite3Db* for $db */ Tcl_Interp *interp, /* Tcl interpreter */ int result /* Result of evaluating SCRIPT */ ){ static const char *azEnd[] = { "RELEASE _tcl_transaction", /* rc==TCL_ERROR, nTransaction!=0 */ "COMMIT", /* rc!=TCL_ERROR, nTransaction==0 */ "ROLLBACK TO _tcl_transaction ; RELEASE _tcl_transaction", "ROLLBACK" /* rc==TCL_ERROR, nTransaction==0 */ }; SqliteDb *pDb = (SqliteDb*)data[0]; int rc = result; const char *zEnd; pDb->nTransaction--; zEnd = azEnd[(rc==TCL_ERROR)*2 + (pDb->nTransaction==0)]; pDb->disableAuth++; if( sqlite3_exec(pDb->db, zEnd, 0, 0, 0) ){ /* This is a tricky scenario to handle. The most likely cause of an ** error is that the exec() above was an attempt to commit the ** top-level transaction that returned SQLITE_BUSY. Or, less likely, ** that an IO-error has occured. In either case, throw a Tcl exception ** and try to rollback the transaction. ** ** But it could also be that the user executed one or more BEGIN, ** COMMIT, SAVEPOINT, RELEASE or ROLLBACK commands that are confusing ** this method's logic. Not clear how this would be best handled. */ if( rc!=TCL_ERROR ){ Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), 0); rc = TCL_ERROR; } sqlite3_exec(pDb->db, "ROLLBACK", 0, 0, 0); } pDb->disableAuth--; return rc; } /* ** Search the cache for a prepared-statement object that implements the ** first SQL statement in the buffer pointed to by parameter zIn. If ** no such prepared-statement can be found, allocate and prepare a new ** one. In either case, bind the current values of the relevant Tcl ** variables to any $var, :var or @var variables in the statement. Before ** returning, set *ppPreStmt to point to the prepared-statement object. ** ** Output parameter *pzOut is set to point to the next SQL statement in ** buffer zIn, or to the '\0' byte at the end of zIn if there is no ** next statement. ** ** If successful, TCL_OK is returned. Otherwise, TCL_ERROR is returned ** and an error message loaded into interpreter pDb->interp. */ static int dbPrepareAndBind( SqliteDb *pDb, /* Database object */ char const *zIn, /* SQL to compile */ char const **pzOut, /* OUT: Pointer to next SQL statement */ SqlPreparedStmt **ppPreStmt /* OUT: Object used to cache statement */ ){ const char *zSql = zIn; /* Pointer to first SQL statement in zIn */ sqlite3_stmt *pStmt; /* Prepared statement object */ SqlPreparedStmt *pPreStmt; /* Pointer to cached statement */ int nSql; /* Length of zSql in bytes */ int nVar; /* Number of variables in statement */ int iParm = 0; /* Next free entry in apParm */ int i; Tcl_Interp *interp = pDb->interp; *ppPreStmt = 0; /* Trim spaces from the start of zSql and calculate the remaining length. */ while( isspace(zSql[0]) ){ zSql++; } nSql = strlen30(zSql); for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pPreStmt->pNext){ int n = pPreStmt->nSql; if( nSql>=n && memcmp(pPreStmt->zSql, zSql, n)==0 && (zSql[n]==0 || zSql[n-1]==';') ){ pStmt = pPreStmt->pStmt; *pzOut = &zSql[pPreStmt->nSql]; /* When a prepared statement is found, unlink it from the ** cache list. It will later be added back to the beginning ** of the cache list in order to implement LRU replacement. */ if( pPreStmt->pPrev ){ pPreStmt->pPrev->pNext = pPreStmt->pNext; }else{ pDb->stmtList = pPreStmt->pNext; } if( pPreStmt->pNext ){ pPreStmt->pNext->pPrev = pPreStmt->pPrev; }else{ pDb->stmtLast = pPreStmt->pPrev; } pDb->nStmt--; nVar = sqlite3_bind_parameter_count(pStmt); break; } } /* If no prepared statement was found. Compile the SQL text. Also allocate ** a new SqlPreparedStmt structure. */ if( pPreStmt==0 ){ int nByte; if( SQLITE_OK!=sqlite3_prepare_v2(pDb->db, zSql, -1, &pStmt, pzOut) ){ Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db))); return TCL_ERROR; } if( pStmt==0 ){ if( SQLITE_OK!=sqlite3_errcode(pDb->db) ){ /* A compile-time error in the statement. */ Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db))); return TCL_ERROR; }else{ /* The statement was a no-op. Continue to the next statement ** in the SQL string. */ return TCL_OK; } } assert( pPreStmt==0 ); nVar = sqlite3_bind_parameter_count(pStmt); nByte = sizeof(SqlPreparedStmt) + nVar*sizeof(Tcl_Obj *); pPreStmt = (SqlPreparedStmt*)Tcl_Alloc(nByte); memset(pPreStmt, 0, nByte); pPreStmt->pStmt = pStmt; pPreStmt->nSql = (*pzOut - zSql); pPreStmt->zSql = sqlite3_sql(pStmt); pPreStmt->apParm = (Tcl_Obj **)&pPreStmt[1]; } assert( pPreStmt ); assert( strlen30(pPreStmt->zSql)==pPreStmt->nSql ); assert( 0==memcmp(pPreStmt->zSql, zSql, pPreStmt->nSql) ); /* Bind values to parameters that begin with $ or : */ for(i=1; i<=nVar; i++){ const char *zVar = sqlite3_bind_parameter_name(pStmt, i); if( zVar!=0 && (zVar[0]=='$' || zVar[0]==':' || zVar[0]=='@') ){ Tcl_Obj *pVar = Tcl_GetVar2Ex(interp, &zVar[1], 0, 0); if( pVar ){ int n; u8 *data; const char *zType = (pVar->typePtr ? pVar->typePtr->name : ""); char c = zType[0]; if( zVar[0]=='@' || (c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0) ){ /* Load a BLOB type if the Tcl variable is a bytearray and ** it has no string representation or the host ** parameter name begins with "@". */ data = Tcl_GetByteArrayFromObj(pVar, &n); sqlite3_bind_blob(pStmt, i, data, n, SQLITE_STATIC); Tcl_IncrRefCount(pVar); pPreStmt->apParm[iParm++] = pVar; }else if( c=='b' && strcmp(zType,"boolean")==0 ){ Tcl_GetIntFromObj(interp, pVar, &n); sqlite3_bind_int(pStmt, i, n); }else if( c=='d' && strcmp(zType,"double")==0 ){ double r; Tcl_GetDoubleFromObj(interp, pVar, &r); sqlite3_bind_double(pStmt, i, r); }else if( (c=='w' && strcmp(zType,"wideInt")==0) || (c=='i' && strcmp(zType,"int")==0) ){ Tcl_WideInt v; Tcl_GetWideIntFromObj(interp, pVar, &v); sqlite3_bind_int64(pStmt, i, v); }else{ data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n); sqlite3_bind_text(pStmt, i, (char *)data, n, SQLITE_STATIC); Tcl_IncrRefCount(pVar); pPreStmt->apParm[iParm++] = pVar; } }else{ sqlite3_bind_null(pStmt, i); } } } pPreStmt->nParm = iParm; *ppPreStmt = pPreStmt; return TCL_OK; } /* ** Release a statement reference obtained by calling dbPrepareAndBind(). ** There should be exactly one call to this function for each call to ** dbPrepareAndBind(). ** ** If the discard parameter is non-zero, then the statement is deleted ** immediately. Otherwise it is added to the LRU list and may be returned ** by a subsequent call to dbPrepareAndBind(). */ static void dbReleaseStmt( SqliteDb *pDb, /* Database handle */ SqlPreparedStmt *pPreStmt, /* Prepared statement handle to release */ int discard /* True to delete (not cache) the pPreStmt */ ){ int i; /* Free the bound string and blob parameters */ for(i=0; i<pPreStmt->nParm; i++){ Tcl_DecrRefCount(pPreStmt->apParm[i]); } pPreStmt->nParm = 0; if( pDb->maxStmt<=0 || discard ){ /* If the cache is turned off, deallocated the statement */ sqlite3_finalize(pPreStmt->pStmt); Tcl_Free((char *)pPreStmt); }else{ /* Add the prepared statement to the beginning of the cache list. */ pPreStmt->pNext = pDb->stmtList; pPreStmt->pPrev = 0; if( pDb->stmtList ){ pDb->stmtList->pPrev = pPreStmt; } pDb->stmtList = pPreStmt; if( pDb->stmtLast==0 ){ assert( pDb->nStmt==0 ); pDb->stmtLast = pPreStmt; }else{ assert( pDb->nStmt>0 ); } pDb->nStmt++; /* If we have too many statement in cache, remove the surplus from ** the end of the cache list. */ while( pDb->nStmt>pDb->maxStmt ){ sqlite3_finalize(pDb->stmtLast->pStmt); pDb->stmtLast = pDb->stmtLast->pPrev; Tcl_Free((char*)pDb->stmtLast->pNext); pDb->stmtLast->pNext = 0; pDb->nStmt--; } } } /* ** Structure used with dbEvalXXX() functions: ** ** dbEvalInit() ** dbEvalStep() ** dbEvalFinalize() ** dbEvalRowInfo() ** dbEvalColumnValue() */ typedef struct DbEvalContext DbEvalContext; struct DbEvalContext { SqliteDb *pDb; /* Database handle */ Tcl_Obj *pSql; /* Object holding string zSql */ const char *zSql; /* Remaining SQL to execute */ SqlPreparedStmt *pPreStmt; /* Current statement */ int nCol; /* Number of columns returned by pStmt */ Tcl_Obj *pArray; /* Name of array variable */ Tcl_Obj **apColName; /* Array of column names */ }; /* ** Release any cache of column names currently held as part of ** the DbEvalContext structure passed as the first argument. */ static void dbReleaseColumnNames(DbEvalContext *p){ if( p->apColName ){ int i; for(i=0; i<p->nCol; i++){ Tcl_DecrRefCount(p->apColName[i]); } Tcl_Free((char *)p->apColName); p->apColName = 0; } p->nCol = 0; } /* ** Initialize a DbEvalContext structure. ** ** If pArray is not NULL, then it contains the name of a Tcl array ** variable. The "*" member of this array is set to a list containing ** the names of the columns returned by the statement as part of each ** call to dbEvalStep(), in order from left to right. e.g. if the names ** of the returned columns are a, b and c, it does the equivalent of the ** tcl command: ** ** set ${pArray}(*) {a b c} */ static void dbEvalInit( DbEvalContext *p, /* Pointer to structure to initialize */ SqliteDb *pDb, /* Database handle */ Tcl_Obj *pSql, /* Object containing SQL script */ Tcl_Obj *pArray /* Name of Tcl array to set (*) element of */ ){ memset(p, 0, sizeof(DbEvalContext)); p->pDb = pDb; p->zSql = Tcl_GetString(pSql); p->pSql = pSql; Tcl_IncrRefCount(pSql); if( pArray ){ p->pArray = pArray; Tcl_IncrRefCount(pArray); } } /* ** Obtain information about the row that the DbEvalContext passed as the ** first argument currently points to. */ static void dbEvalRowInfo( DbEvalContext *p, /* Evaluation context */ int *pnCol, /* OUT: Number of column names */ Tcl_Obj ***papColName /* OUT: Array of column names */ ){ /* Compute column names */ if( 0==p->apColName ){ sqlite3_stmt *pStmt = p->pPreStmt->pStmt; int i; /* Iterator variable */ int nCol; /* Number of columns returned by pStmt */ Tcl_Obj **apColName = 0; /* Array of column names */ p->nCol = nCol = sqlite3_column_count(pStmt); if( nCol>0 && (papColName || p->pArray) ){ apColName = (Tcl_Obj**)Tcl_Alloc( sizeof(Tcl_Obj*)*nCol ); for(i=0; i<nCol; i++){ apColName[i] = dbTextToObj(sqlite3_column_name(pStmt,i)); Tcl_IncrRefCount(apColName[i]); } p->apColName = apColName; } /* If results are being stored in an array variable, then create ** the array(*) entry for that array */ if( p->pArray ){ Tcl_Interp *interp = p->pDb->interp; Tcl_Obj *pColList = Tcl_NewObj(); Tcl_Obj *pStar = Tcl_NewStringObj("*", -1); for(i=0; i<nCol; i++){ Tcl_ListObjAppendElement(interp, pColList, apColName[i]); } Tcl_IncrRefCount(pStar); Tcl_ObjSetVar2(interp, p->pArray, pStar, pColList, 0); Tcl_DecrRefCount(pStar); } } if( papColName ){ *papColName = p->apColName; } if( pnCol ){ *pnCol = p->nCol; } } /* ** Return one of TCL_OK, TCL_BREAK or TCL_ERROR. If TCL_ERROR is ** returned, then an error message is stored in the interpreter before ** returning. ** ** A return value of TCL_OK means there is a row of data available. The ** data may be accessed using dbEvalRowInfo() and dbEvalColumnValue(). This ** is analogous to a return of SQLITE_ROW from sqlite3_step(). If TCL_BREAK ** is returned, then the SQL script has finished executing and there are ** no further rows available. This is similar to SQLITE_DONE. */ static int dbEvalStep(DbEvalContext *p){ while( p->zSql[0] || p->pPreStmt ){ int rc; if( p->pPreStmt==0 ){ rc = dbPrepareAndBind(p->pDb, p->zSql, &p->zSql, &p->pPreStmt); if( rc!=TCL_OK ) return rc; }else{ int rcs; SqliteDb *pDb = p->pDb; SqlPreparedStmt *pPreStmt = p->pPreStmt; sqlite3_stmt *pStmt = pPreStmt->pStmt; rcs = sqlite3_step(pStmt); if( rcs==SQLITE_ROW ){ return TCL_OK; } if( p->pArray ){ dbEvalRowInfo(p, 0, 0); } rcs = sqlite3_reset(pStmt); pDb->nStep = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_FULLSCAN_STEP,1); pDb->nSort = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_SORT,1); dbReleaseColumnNames(p); p->pPreStmt = 0; if( rcs!=SQLITE_OK ){ /* If a run-time error occurs, report the error and stop reading ** the SQL. */ Tcl_SetObjResult(pDb->interp, dbTextToObj(sqlite3_errmsg(pDb->db))); dbReleaseStmt(pDb, pPreStmt, 1); return TCL_ERROR; }else{ dbReleaseStmt(pDb, pPreStmt, 0); } } } /* Finished */ return TCL_BREAK; } /* ** Free all resources currently held by the DbEvalContext structure passed ** as the first argument. There should be exactly one call to this function ** for each call to dbEvalInit(). */ static void dbEvalFinalize(DbEvalContext *p){ if( p->pPreStmt ){ sqlite3_reset(p->pPreStmt->pStmt); dbReleaseStmt(p->pDb, p->pPreStmt, 0); p->pPreStmt = 0; } 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. */ static Tcl_Obj *dbEvalColumnValue(DbEvalContext *p, int iCol){ sqlite3_stmt *pStmt = p->pPreStmt->pStmt; switch( sqlite3_column_type(pStmt, iCol) ){ case SQLITE_BLOB: { int bytes = sqlite3_column_bytes(pStmt, iCol); const char *zBlob = sqlite3_column_blob(pStmt, iCol); if( !zBlob ) bytes = 0; return Tcl_NewByteArrayObj((u8*)zBlob, bytes); } case SQLITE_INTEGER: { sqlite_int64 v = sqlite3_column_int64(pStmt, iCol); if( v>=-2147483647 && v<=2147483647 ){ return Tcl_NewIntObj(v); }else{ return Tcl_NewWideIntObj(v); } } case SQLITE_FLOAT: { return Tcl_NewDoubleObj(sqlite3_column_double(pStmt, iCol)); } case SQLITE_NULL: { return dbTextToObj(p->pDb->zNull); } } return dbTextToObj((char *)sqlite3_column_text(pStmt, iCol)); } /* ** If using Tcl version 8.6 or greater, use the NR functions to avoid ** recursive evalution of scripts by the [db eval] and [db trans] ** commands. Even if the headers used while compiling the extension ** are 8.6 or newer, the code still tests the Tcl version at runtime. ** This allows stubs-enabled builds to be used with older Tcl libraries. */ #if TCL_MAJOR_VERSION>8 || (TCL_MAJOR_VERSION==8 && TCL_MINOR_VERSION>=6) # define SQLITE_TCL_NRE 1 static int DbUseNre(void){ int major, minor; Tcl_GetVersion(&major, &minor, 0, 0); return( (major==8 && minor>=6) || major>8 ); } #else /* ** Compiling using headers earlier than 8.6. In this case NR cannot be ** used, so DbUseNre() to always return zero. Add #defines for the other ** Tcl_NRxxx() functions to prevent them from causing compilation errors, ** even though the only invocations of them are within conditional blocks ** of the form: ** ** if( DbUseNre() ) { ... } */ # define SQLITE_TCL_NRE 0 # define DbUseNre() 0 # define Tcl_NRAddCallback(a,b,c,d,e,f) 0 # define Tcl_NREvalObj(a,b,c) 0 # define Tcl_NRCreateCommand(a,b,c,d,e,f) 0 #endif /* ** This function is part of the implementation of the command: ** ** $db eval SQL ?ARRAYNAME? SCRIPT */ static int DbEvalNextCmd( ClientData data[], /* data[0] is the (DbEvalContext*) */ Tcl_Interp *interp, /* Tcl interpreter */ int result /* Result so far */ ){ int rc = result; /* Return code */ /* The first element of the data[] array is a pointer to a DbEvalContext ** structure allocated using Tcl_Alloc(). The second element of data[] ** is a pointer to a Tcl_Obj containing the script to run for each row ** returned by the queries encapsulated in data[0]. */ DbEvalContext *p = (DbEvalContext *)data[0]; Tcl_Obj *pScript = (Tcl_Obj *)data[1]; Tcl_Obj *pArray = p->pArray; while( (rc==TCL_OK || rc==TCL_CONTINUE) && TCL_OK==(rc = dbEvalStep(p)) ){ int i; int nCol; Tcl_Obj **apColName; dbEvalRowInfo(p, &nCol, &apColName); for(i=0; i<nCol; i++){ Tcl_Obj *pVal = dbEvalColumnValue(p, i); if( pArray==0 ){ Tcl_ObjSetVar2(interp, apColName[i], 0, pVal, 0); }else{ Tcl_ObjSetVar2(interp, pArray, apColName[i], pVal, 0); } } /* The required interpreter variables are now populated with the data ** from the current row. If using NRE, schedule callbacks to evaluate ** script pScript, then to invoke this function again to fetch the next ** row (or clean up if there is no next row or the script throws an ** exception). After scheduling the callbacks, return control to the ** caller. ** ** If not using NRE, evaluate pScript directly and continue with the ** next iteration of this while(...) loop. */ if( DbUseNre() ){ Tcl_NRAddCallback(interp, DbEvalNextCmd, (void*)p, (void*)pScript, 0, 0); return Tcl_NREvalObj(interp, pScript, 0); }else{ rc = Tcl_EvalObjEx(interp, pScript, 0); } } Tcl_DecrRefCount(pScript); dbEvalFinalize(p); Tcl_Free((char *)p); if( rc==TCL_OK || rc==TCL_BREAK ){ Tcl_ResetResult(interp); rc = TCL_OK; } return rc; } /* ** The "sqlite" command below creates a new Tcl command for each ** connection it opens to an SQLite database. This routine is invoked ** whenever one of those connection-specific commands is executed ** in Tcl. For example, if you run Tcl code like this: |
︙ | ︙ | |||
1598 1599 1600 1601 1602 1603 1604 | ** Return the numeric error code that was returned by the most recent ** call to sqlite3_exec(). */ case DB_ERRORCODE: { Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_errcode(pDb->db))); break; } | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < < | < < < < < < < < < < < < < < | | | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | < < < | < | < < < > > | < < < < < < | > > | < < < < < < | < < | < < | < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < | | < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < | < < | | > < < < | | < < < | < < | | < < < < < > | < | < < < | < < < < < | < | < < < < | < < | < < < < | 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 | ** Return the numeric error code that was returned by the most recent ** 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 */ case DB_EXISTS: case DB_ONECOLUMN: { DbEvalContext sEval; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "SQL"); return TCL_ERROR; } dbEvalInit(&sEval, pDb, objv[2], 0); rc = dbEvalStep(&sEval); if( choice==DB_ONECOLUMN ){ if( rc==TCL_OK ){ Tcl_SetObjResult(interp, dbEvalColumnValue(&sEval, 0)); } }else if( rc==TCL_BREAK || rc==TCL_OK ){ Tcl_SetObjResult(interp, Tcl_NewBooleanObj(rc==TCL_OK)); } dbEvalFinalize(&sEval); if( rc==TCL_BREAK ){ rc = TCL_OK; } break; } /* ** $db eval $sql ?array? ?{ ...code... }? ** ** The SQL statement in $sql is evaluated. For each row, the values are ** placed in elements of the array named "array" and ...code... is executed. ** If "array" and "code" are omitted, then no callback is every invoked. ** If "array" is an empty string, then the values are placed in variables ** that have the same name as the fields extracted by the query. */ case DB_EVAL: { if( objc<3 || objc>5 ){ Tcl_WrongNumArgs(interp, 2, objv, "SQL ?ARRAY-NAME? ?SCRIPT?"); return TCL_ERROR; } if( objc==3 ){ DbEvalContext sEval; Tcl_Obj *pRet = Tcl_NewObj(); Tcl_IncrRefCount(pRet); dbEvalInit(&sEval, pDb, objv[2], 0); while( TCL_OK==(rc = dbEvalStep(&sEval)) ){ int i; int nCol; dbEvalRowInfo(&sEval, &nCol, 0); for(i=0; i<nCol; i++){ Tcl_ListObjAppendElement(interp, pRet, dbEvalColumnValue(&sEval, i)); } } dbEvalFinalize(&sEval); if( rc==TCL_BREAK ){ Tcl_SetObjResult(interp, pRet); rc = TCL_OK; } Tcl_DecrRefCount(pRet); }else{ ClientData cd[2]; DbEvalContext *p; Tcl_Obj *pArray = 0; Tcl_Obj *pScript; if( objc==5 && *(char *)Tcl_GetString(objv[3]) ){ pArray = objv[3]; } pScript = objv[objc-1]; Tcl_IncrRefCount(pScript); p = (DbEvalContext *)Tcl_Alloc(sizeof(DbEvalContext)); dbEvalInit(p, pDb, objv[2], pArray); cd[0] = (void *)p; cd[1] = (void *)pScript; rc = DbEvalNextCmd(cd, interp, TCL_OK); } break; } /* ** $db function NAME [-argcount N] SCRIPT ** |
︙ | ︙ | |||
2119 2120 2121 2122 2123 2124 2125 | rowid = sqlite3_last_insert_rowid(pDb->db); pResult = Tcl_GetObjResult(interp); Tcl_SetWideIntObj(pResult, rowid); break; } /* | | | 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 | rowid = sqlite3_last_insert_rowid(pDb->db); pResult = Tcl_GetObjResult(interp); Tcl_SetWideIntObj(pResult, rowid); break; } /* ** The DB_ONECOLUMN method is implemented together with DB_EXISTS. */ /* $db progress ?N CALLBACK? ** ** Invoke the given callback every N virtual machine opcodes while executing ** queries. */ |
︙ | ︙ | |||
2398 2399 2400 2401 2402 2403 2404 | ** ** This command was inspired by Dave Thomas's talk on Ruby at the ** 2005 O'Reilly Open Source Convention (OSCON). */ case DB_TRANSACTION: { Tcl_Obj *pScript; const char *zBegin = "SAVEPOINT _tcl_transaction"; | < | < < > < < < < > | > | > | > | < < < < < < < | < < < < < < < < < < < < < < < | < < < < | 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 | ** ** This command was inspired by Dave Thomas's talk on Ruby at the ** 2005 O'Reilly Open Source Convention (OSCON). */ case DB_TRANSACTION: { Tcl_Obj *pScript; const char *zBegin = "SAVEPOINT _tcl_transaction"; if( objc!=3 && objc!=4 ){ Tcl_WrongNumArgs(interp, 2, objv, "[TYPE] SCRIPT"); return TCL_ERROR; } if( pDb->nTransaction==0 && objc==4 ){ static const char *TTYPE_strs[] = { "deferred", "exclusive", "immediate", 0 }; enum TTYPE_enum { TTYPE_DEFERRED, TTYPE_EXCLUSIVE, TTYPE_IMMEDIATE }; int ttype; if( Tcl_GetIndexFromObj(interp, objv[2], TTYPE_strs, "transaction type", 0, &ttype) ){ return TCL_ERROR; } switch( (enum TTYPE_enum)ttype ){ case TTYPE_DEFERRED: /* no-op */; break; case TTYPE_EXCLUSIVE: zBegin = "BEGIN EXCLUSIVE"; break; case TTYPE_IMMEDIATE: zBegin = "BEGIN IMMEDIATE"; break; } } pScript = objv[objc-1]; /* Run the SQLite BEGIN command to open a transaction or savepoint. */ pDb->disableAuth++; rc = sqlite3_exec(pDb->db, zBegin, 0, 0, 0); pDb->disableAuth--; if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), 0); return TCL_ERROR; } 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); Tcl_NREvalObj(interp, pScript, 0); }else{ rc = DbTransPostCmd(&cd, interp, Tcl_EvalObjEx(interp, pScript, 0)); } break; } /* ** $db unlock_notify ?script? */ case DB_UNLOCK_NOTIFY: { |
︙ | ︙ | |||
2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 | } } /* End of the SWITCH statement */ return rc; } /* ** 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. ** | > > > > > > > > > > > > > > > | 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 | } } /* End of the SWITCH statement */ return rc; } #if SQLITE_TCL_NRE /* ** Adaptor that provides an objCmd interface to the NRE-enabled ** interface implementation. */ static int DbObjCmdAdaptor( void *cd, Tcl_Interp *interp, int objc, Tcl_Obj *const*objv ){ return Tcl_NRCallObjProc(interp, DbObjCmd, cd, objc, objv); } #endif /* SQLITE_TCL_NRE */ /* ** 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. ** |
︙ | ︙ | |||
2709 2710 2711 2712 2713 2714 2715 | Tcl_Free((char*)p); sqlite3_free(zErrMsg); return TCL_ERROR; } p->maxStmt = NUM_PREPARED_STMTS; p->interp = interp; zArg = Tcl_GetStringFromObj(objv[1], 0); | > > > > | > | 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 | Tcl_Free((char*)p); sqlite3_free(zErrMsg); return TCL_ERROR; } p->maxStmt = NUM_PREPARED_STMTS; 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. */ |
︙ | ︙ | |||
2770 2771 2772 2773 2774 2775 2776 | EXTERN int Tclsqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; } EXTERN int Sqlite_SafeUnload(Tcl_Interp *interp, int flags){ return TCL_OK; } EXTERN int Tclsqlite_SafeUnload(Tcl_Interp *interp, int flags){ return TCL_OK;} #endif #ifdef TCLSH /***************************************************************************** | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | EXTERN int Tclsqlite_Unload(Tcl_Interp *interp, int flags){ return TCL_OK; } EXTERN int Sqlite_SafeUnload(Tcl_Interp *interp, int flags){ return TCL_OK; } EXTERN int Tclsqlite_SafeUnload(Tcl_Interp *interp, int flags){ return TCL_OK;} #endif #ifdef TCLSH /***************************************************************************** ** All of the code that follows is used to build standalone TCL interpreters ** that are statically linked with SQLite. Enable these by compiling ** with -DTCLSH=n where n can be 1 or 2. An n of 1 generates a standard ** tclsh but with SQLite built in. An n of 2 generates the SQLite space ** analysis program. */ #if defined(SQLITE_TEST) || defined(SQLITE_TCLMD5) /* * This code implements the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was * written by Colin Plumb in 1993, no copyright is claimed. * This code is in the public domain; do with it what you wish. * * Equivalent code is available from RSA Data Security, Inc. * This code has been tested against that, and is equivalent, * except that you don't need to include two pages of legalese * with every copy. * * To compute the message digest of a chunk of bytes, declare an * MD5Context structure, pass it to MD5Init, call MD5Update as * needed on buffers full of bytes, and then call MD5Final, which * will fill a supplied 16-byte array with the digest. */ /* * If compiled on a machine that doesn't have a 32-bit integer, * you just set "uint32" to the appropriate datatype for an * unsigned 32-bit integer. For example: * * cc -Duint32='unsigned long' md5.c * */ #ifndef uint32 # define uint32 unsigned int #endif struct MD5Context { int isInit; uint32 buf[4]; uint32 bits[2]; unsigned char in[64]; }; typedef struct MD5Context MD5Context; /* * Note: this code is harmless on little-endian machines. */ static void byteReverse (unsigned char *buf, unsigned longs){ uint32 t; do { t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 | ((unsigned)buf[1]<<8 | buf[0]); *(uint32 *)buf = t; buf += 4; } while (--longs); } /* The four core functions - F1 is optimized somewhat */ /* #define F1(x, y, z) (x & y | ~x & z) */ #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) #define F4(x, y, z) (y ^ (x | ~z)) /* This is the central step in the MD5 algorithm. */ #define MD5STEP(f, w, x, y, z, data, s) \ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ static void MD5Transform(uint32 buf[4], const uint32 in[16]){ register uint32 a, b, c, d; a = buf[0]; b = buf[1]; c = buf[2]; d = buf[3]; MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7); MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12); MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17); MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22); MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7); MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12); MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17); MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22); MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7); MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12); MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17); MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22); MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7); MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12); MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17); MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22); MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5); MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9); MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14); MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20); MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5); MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9); MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14); MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20); MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5); MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9); MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14); MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20); MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5); MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9); MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14); MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20); MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4); MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11); MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16); MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23); MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4); MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11); MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16); MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23); MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4); MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11); MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16); MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23); MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4); MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11); MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16); MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23); MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6); MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10); MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15); MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21); MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6); MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10); MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15); MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21); MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6); MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10); MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15); MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21); MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6); MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10); MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21); buf[0] += a; buf[1] += b; buf[2] += c; buf[3] += d; } /* * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * initialization constants. */ static void MD5Init(MD5Context *ctx){ ctx->isInit = 1; ctx->buf[0] = 0x67452301; ctx->buf[1] = 0xefcdab89; ctx->buf[2] = 0x98badcfe; ctx->buf[3] = 0x10325476; ctx->bits[0] = 0; ctx->bits[1] = 0; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ static void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){ uint32 t; /* Update bitcount */ t = ctx->bits[0]; if ((ctx->bits[0] = t + ((uint32)len << 3)) < t) ctx->bits[1]++; /* Carry from low to high */ ctx->bits[1] += len >> 29; t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ /* Handle any leading odd-sized chunks */ if ( t ) { unsigned char *p = (unsigned char *)ctx->in + t; t = 64-t; if (len < t) { memcpy(p, buf, len); return; } memcpy(p, buf, t); byteReverse(ctx->in, 16); MD5Transform(ctx->buf, (uint32 *)ctx->in); buf += t; len -= t; } /* Process data in 64-byte chunks */ while (len >= 64) { memcpy(ctx->in, buf, 64); byteReverse(ctx->in, 16); MD5Transform(ctx->buf, (uint32 *)ctx->in); buf += 64; len -= 64; } /* Handle any remaining bytes of data. */ memcpy(ctx->in, buf, len); } /* * Final wrapup - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ static void MD5Final(unsigned char digest[16], MD5Context *ctx){ unsigned count; unsigned char *p; /* Compute number of bytes mod 64 */ count = (ctx->bits[0] >> 3) & 0x3F; /* Set the first char of padding to 0x80. This is safe since there is always at least one byte free */ p = ctx->in + count; *p++ = 0x80; /* Bytes of padding needed to make 64 bytes */ count = 64 - 1 - count; /* Pad out to 56 mod 64 */ if (count < 8) { /* Two lots of padding: Pad the first block to 64 bytes */ memset(p, 0, count); byteReverse(ctx->in, 16); MD5Transform(ctx->buf, (uint32 *)ctx->in); /* Now fill the next block with 56 bytes */ memset(ctx->in, 0, 56); } else { /* Pad block to 56 bytes */ memset(p, 0, count-8); } byteReverse(ctx->in, 14); /* Append length in bits and transform */ ((uint32 *)ctx->in)[ 14 ] = ctx->bits[0]; ((uint32 *)ctx->in)[ 15 ] = ctx->bits[1]; MD5Transform(ctx->buf, (uint32 *)ctx->in); byteReverse((unsigned char *)ctx->buf, 4); memcpy(digest, ctx->buf, 16); memset(ctx, 0, sizeof(ctx)); /* In case it is sensitive */ } /* ** Convert a 128-bit MD5 digest into a 32-digit base-16 number. */ static void MD5DigestToBase16(unsigned char *digest, char *zBuf){ static char const zEncode[] = "0123456789abcdef"; int i, j; for(j=i=0; i<16; i++){ int a = digest[i]; zBuf[j++] = zEncode[(a>>4)&0xf]; zBuf[j++] = zEncode[a & 0xf]; } zBuf[j] = 0; } /* ** Convert a 128-bit MD5 digest into sequency of eight 5-digit integers ** each representing 16 bits of the digest and separated from each ** other by a "-" character. */ static void MD5DigestToBase10x8(unsigned char digest[16], char zDigest[50]){ int i, j; unsigned int x; for(i=j=0; i<16; i+=2){ x = digest[i]*256 + digest[i+1]; if( i>0 ) zDigest[j++] = '-'; sprintf(&zDigest[j], "%05u", x); j += 5; } zDigest[j] = 0; } /* ** A TCL command for md5. The argument is the text to be hashed. The ** Result is the hash in base64. */ static int md5_cmd(void*cd, Tcl_Interp *interp, int argc, const char **argv){ MD5Context ctx; unsigned char digest[16]; char zBuf[50]; void (*converter)(unsigned char*, char*); if( argc!=2 ){ Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0], " TEXT\"", 0); return TCL_ERROR; } MD5Init(&ctx); MD5Update(&ctx, (unsigned char*)argv[1], (unsigned)strlen(argv[1])); MD5Final(digest, &ctx); converter = (void(*)(unsigned char*,char*))cd; converter(digest, zBuf); Tcl_AppendResult(interp, zBuf, (char*)0); return TCL_OK; } /* ** A TCL command to take the md5 hash of a file. The argument is the ** name of the file. */ static int md5file_cmd(void*cd, Tcl_Interp*interp, int argc, const char **argv){ FILE *in; MD5Context ctx; void (*converter)(unsigned char*, char*); unsigned char digest[16]; char zBuf[10240]; if( argc!=2 ){ Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0], " FILENAME\"", 0); return TCL_ERROR; } in = fopen(argv[1],"rb"); if( in==0 ){ Tcl_AppendResult(interp,"unable to open file \"", argv[1], "\" for reading", 0); return TCL_ERROR; } MD5Init(&ctx); for(;;){ int n; n = fread(zBuf, 1, sizeof(zBuf), in); if( n<=0 ) break; MD5Update(&ctx, (unsigned char*)zBuf, (unsigned)n); } fclose(in); MD5Final(digest, &ctx); converter = (void(*)(unsigned char*,char*))cd; converter(digest, zBuf); Tcl_AppendResult(interp, zBuf, (char*)0); return TCL_OK; } /* ** Register the four new TCL commands for generating MD5 checksums ** with the TCL interpreter. */ int Md5_Init(Tcl_Interp *interp){ Tcl_CreateCommand(interp, "md5", (Tcl_CmdProc*)md5_cmd, MD5DigestToBase16, 0); Tcl_CreateCommand(interp, "md5-10x8", (Tcl_CmdProc*)md5_cmd, MD5DigestToBase10x8, 0); Tcl_CreateCommand(interp, "md5file", (Tcl_CmdProc*)md5file_cmd, MD5DigestToBase16, 0); Tcl_CreateCommand(interp, "md5file-10x8", (Tcl_CmdProc*)md5file_cmd, MD5DigestToBase10x8, 0); return TCL_OK; } #endif /* defined(SQLITE_TEST) || defined(SQLITE_TCLMD5) */ #if defined(SQLITE_TEST) /* ** During testing, the special md5sum() aggregate function is available. ** inside SQLite. The following routines implement that function. */ static void md5step(sqlite3_context *context, int argc, sqlite3_value **argv){ MD5Context *p; int i; if( argc<1 ) return; p = sqlite3_aggregate_context(context, sizeof(*p)); if( p==0 ) return; if( !p->isInit ){ MD5Init(p); } for(i=0; i<argc; i++){ const char *zData = (char*)sqlite3_value_text(argv[i]); if( zData ){ MD5Update(p, (unsigned char*)zData, strlen(zData)); } } } static void md5finalize(sqlite3_context *context){ MD5Context *p; unsigned char digest[16]; char zBuf[33]; p = sqlite3_aggregate_context(context, sizeof(*p)); MD5Final(digest,p); MD5DigestToBase16(digest, zBuf); sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); } int Md5_Register(sqlite3 *db){ int rc = sqlite3_create_function(db, "md5sum", -1, SQLITE_UTF8, 0, 0, md5step, md5finalize); sqlite3_overload_function(db, "md5sum", -1); /* To exercise this API */ return rc; } #endif /* defined(SQLITE_TEST) */ /* ** If the macro TCLSH is one, then put in code this for the ** "main" routine that will initialize Tcl and take input from ** standard input, or if a file is named on the command line ** the TCL interpreter reads and evaluates that file. */ |
︙ | ︙ | |||
2805 2806 2807 2808 2809 2810 2811 | "} else {\n" "append line \\n\n" "}\n" "}\n" ; #endif | < < < < < < < < < < > > > < > > < > > | | | | 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 | "} else {\n" "append line \\n\n" "}\n" "}\n" ; #endif #define TCLSH_MAIN main /* Needed to fake out mktclapp */ int TCLSH_MAIN(int argc, char **argv){ Tcl_Interp *interp; /* Call sqlite3_shutdown() once before doing anything else. This is to ** test that sqlite3_shutdown() can be safely called by a process before ** sqlite3_initialize() is. */ sqlite3_shutdown(); Tcl_FindExecutable(argv[0]); interp = Tcl_CreateInterp(); Sqlite3_Init(interp); #if defined(SQLITE_TEST) || defined(SQLITE_TCLMD5) Md5_Init(interp); #endif #ifdef SQLITE_TEST { 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_func_Init(Tcl_Interp*); extern int Sqlitetest_hexio_Init(Tcl_Interp*); extern int Sqlitetest_init_Init(Tcl_Interp*); extern int Sqlitetest_malloc_Init(Tcl_Interp*); extern int Sqlitetest_mutex_Init(Tcl_Interp*); extern int Sqlitetestschema_Init(Tcl_Interp*); extern int Sqlitetestsse_Init(Tcl_Interp*); extern int Sqlitetesttclvar_Init(Tcl_Interp*); 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*); 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_func_Init(interp); Sqlitetest_hexio_Init(interp); Sqlitetest_init_Init(interp); Sqlitetest_malloc_Init(interp); Sqlitetest_mutex_Init(interp); Sqlitetestschema_Init(interp); Sqlitetesttclvar_Init(interp); SqlitetestThread_Init(interp); SqlitetestOnefile_Init(interp); SqlitetestOsinst_Init(interp); Sqlitetestbackup_Init(interp); Sqlitetestintarray_Init(interp); #ifdef SQLITE_SSE Sqlitetestsse_Init(interp); #endif } #endif if( argc>=2 ){ int i; char zArgc[32]; sqlite3_snprintf(sizeof(zArgc), zArgc, "%d", argc-(3-TCLSH)); Tcl_SetVar(interp,"argc", zArgc, TCL_GLOBAL_ONLY); Tcl_SetVar(interp,"argv0",argv[1],TCL_GLOBAL_ONLY); Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY); for(i=3-TCLSH; i<argc; i++){ Tcl_SetVar(interp, "argv", argv[i], TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE); } if( Tcl_EvalFile(interp, argv[1])!=TCL_OK ){ const char *zInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY); if( zInfo==0 ) zInfo = Tcl_GetStringResult(interp); fprintf(stderr,"%s: %s\n", *argv, zInfo); return 1; } } if( argc<=1 ){ Tcl_GlobalEval(interp, zMainloop); } return 0; } #endif /* TCLSH */ |
Changes to src/test1.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. ** ************************************************************************* ** Code for testing all sorts of SQLite interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. | < < | 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. ** ************************************************************************* ** Code for testing all sorts of SQLite interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. */ #include "sqliteInt.h" #include "tcl.h" #include <stdlib.h> #include <string.h> /* |
︙ | ︙ | |||
1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 | sqlite3_result_error(context, "x_count totals to 42", -1); }else{ sqlite3_result_int(context, p ? p->n : 0); } } } static void legacyCountStep( sqlite3_context *context, int argc, sqlite3_value **argv ){ /* no-op */ } | > < | 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 | sqlite3_result_error(context, "x_count totals to 42", -1); }else{ sqlite3_result_int(context, p ? p->n : 0); } } } #ifndef SQLITE_OMIT_DEPRECATED static void legacyCountStep( sqlite3_context *context, int argc, sqlite3_value **argv ){ /* no-op */ } static void legacyCountFinalize(sqlite3_context *context){ sqlite3_result_int(context, sqlite3_aggregate_count(context)); } #endif /* ** Usage: sqlite3_create_aggregate DB |
︙ | ︙ | |||
2305 2306 2307 2308 2309 2310 2311 2312 | case SQLITE_UTF16BE: Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj("UTF-16BE",-1)); break; default: assert(0); } pVal = sqlite3ValueNew(0); | > > | | | | | | | | | > > | 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 | case SQLITE_UTF16BE: Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj("UTF-16BE",-1)); break; default: assert(0); } sqlite3BeginBenignMalloc(); pVal = sqlite3ValueNew(0); if( pVal ){ sqlite3ValueSetStr(pVal, nA, zA, encin, SQLITE_STATIC); n = sqlite3_value_bytes(pVal); Tcl_ListObjAppendElement(i,pX, Tcl_NewStringObj((char*)sqlite3_value_text(pVal),n)); sqlite3ValueSetStr(pVal, nB, zB, encin, SQLITE_STATIC); n = sqlite3_value_bytes(pVal); Tcl_ListObjAppendElement(i,pX, Tcl_NewStringObj((char*)sqlite3_value_text(pVal),n)); sqlite3ValueFree(pVal); } sqlite3EndBenignMalloc(); Tcl_EvalObjEx(i, pX, 0); Tcl_DecrRefCount(pX); Tcl_GetIntFromObj(i, Tcl_GetObjResult(i), &res); return res; } static int test_collate( |
︙ | ︙ | |||
3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 | return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; zSql = Tcl_GetString(objv[2]); if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR; rc = sqlite3_prepare(db, zSql, bytes, &pStmt, objc>=5 ? &zTail : 0); if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; if( zTail && objc>=5 ){ if( bytes>=0 ){ bytes = bytes - (zTail-zSql); } if( strlen(zTail)<bytes ){ bytes = strlen(zTail); | > | 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 | return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; zSql = Tcl_GetString(objv[2]); if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR; rc = sqlite3_prepare(db, zSql, bytes, &pStmt, objc>=5 ? &zTail : 0); Tcl_ResetResult(interp); if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; if( zTail && objc>=5 ){ if( bytes>=0 ){ bytes = bytes - (zTail-zSql); } if( strlen(zTail)<bytes ){ bytes = strlen(zTail); |
︙ | ︙ | |||
3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 | } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; zSql = Tcl_GetString(objv[2]); if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR; rc = sqlite3_prepare_v2(db, zSql, bytes, &pStmt, objc>=5 ? &zTail : 0); assert(rc==SQLITE_OK || pStmt==0); if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; if( zTail && objc>=5 ){ if( bytes>=0 ){ bytes = bytes - (zTail-zSql); } Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0); } | > | 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 | } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; zSql = Tcl_GetString(objv[2]); if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR; rc = sqlite3_prepare_v2(db, zSql, bytes, &pStmt, objc>=5 ? &zTail : 0); assert(rc==SQLITE_OK || pStmt==0); Tcl_ResetResult(interp); if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; if( zTail && objc>=5 ){ if( bytes>=0 ){ bytes = bytes - (zTail-zSql); } Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0); } |
︙ | ︙ | |||
4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 | { "SQLITE_LIMIT_EXPR_DEPTH", SQLITE_LIMIT_EXPR_DEPTH }, { "SQLITE_LIMIT_COMPOUND_SELECT", SQLITE_LIMIT_COMPOUND_SELECT }, { "SQLITE_LIMIT_VDBE_OP", SQLITE_LIMIT_VDBE_OP }, { "SQLITE_LIMIT_FUNCTION_ARG", SQLITE_LIMIT_FUNCTION_ARG }, { "SQLITE_LIMIT_ATTACHED", SQLITE_LIMIT_ATTACHED }, { "SQLITE_LIMIT_LIKE_PATTERN_LENGTH", SQLITE_LIMIT_LIKE_PATTERN_LENGTH }, { "SQLITE_LIMIT_VARIABLE_NUMBER", SQLITE_LIMIT_VARIABLE_NUMBER }, /* Out of range test cases */ { "SQLITE_LIMIT_TOOSMALL", -1, }, | > | | 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 | { "SQLITE_LIMIT_EXPR_DEPTH", SQLITE_LIMIT_EXPR_DEPTH }, { "SQLITE_LIMIT_COMPOUND_SELECT", SQLITE_LIMIT_COMPOUND_SELECT }, { "SQLITE_LIMIT_VDBE_OP", SQLITE_LIMIT_VDBE_OP }, { "SQLITE_LIMIT_FUNCTION_ARG", SQLITE_LIMIT_FUNCTION_ARG }, { "SQLITE_LIMIT_ATTACHED", SQLITE_LIMIT_ATTACHED }, { "SQLITE_LIMIT_LIKE_PATTERN_LENGTH", SQLITE_LIMIT_LIKE_PATTERN_LENGTH }, { "SQLITE_LIMIT_VARIABLE_NUMBER", SQLITE_LIMIT_VARIABLE_NUMBER }, { "SQLITE_LIMIT_TRIGGER_DEPTH", SQLITE_LIMIT_TRIGGER_DEPTH }, /* Out of range test cases */ { "SQLITE_LIMIT_TOOSMALL", -1, }, { "SQLITE_LIMIT_TOOBIG", SQLITE_LIMIT_TRIGGER_DEPTH+1 }, }; int i, id; int val; const char *zId; if( objc!=4 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", |
︙ | ︙ | |||
4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 | } rc = sqlite3_unlock_notify(db, test_unlock_notify_cb, (void *)interp); Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC); return TCL_OK; } #endif /* ** Register commands with the TCL interpreter. */ int Sqlitetest1_Init(Tcl_Interp *interp){ extern int sqlite3_search_count; extern int sqlite3_interrupt_count; extern int sqlite3_open_file_count; extern int sqlite3_sort_count; extern int sqlite3_current_time; #if SQLITE_OS_UNIX && defined(__APPLE__) extern int sqlite3_hostid_num; #endif | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } rc = sqlite3_unlock_notify(db, test_unlock_notify_cb, (void *)interp); Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC); return TCL_OK; } #endif /* ** tcl_objproc COMMANDNAME ARGS... ** ** Run a TCL command using its objProc interface. Throw an error if ** the command has no objProc interface. */ static int runAsObjProc( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ Tcl_CmdInfo cmdInfo; if( objc<2 ){ Tcl_WrongNumArgs(interp, 1, objv, "COMMAND ..."); return TCL_ERROR; } if( !Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &cmdInfo) ){ Tcl_AppendResult(interp, "command not found: ", Tcl_GetString(objv[1]), (char*)0); return TCL_ERROR; } if( cmdInfo.objProc==0 ){ Tcl_AppendResult(interp, "command has no objProc: ", Tcl_GetString(objv[1]), (char*)0); return TCL_ERROR; } return cmdInfo.objProc(cmdInfo.objClientData, interp, objc-1, objv+1); } /* ** Register commands with the TCL interpreter. */ int Sqlitetest1_Init(Tcl_Interp *interp){ extern int sqlite3_search_count; extern int sqlite3_found_count; extern int sqlite3_interrupt_count; extern int sqlite3_open_file_count; extern int sqlite3_sort_count; extern int sqlite3_current_time; #if SQLITE_OS_UNIX && defined(__APPLE__) extern int sqlite3_hostid_num; #endif |
︙ | ︙ | |||
4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 | { "sqlite3_enable_load_extension", test_enable_load, 0}, { "sqlite3_extended_result_codes", test_extended_result_codes, 0}, { "sqlite3_limit", test_limit, 0}, { "save_prng_state", save_prng_state, 0 }, { "restore_prng_state", restore_prng_state, 0 }, { "reset_prng_state", reset_prng_state, 0 }, /* sqlite3_column_*() API */ { "sqlite3_column_count", test_column_count ,0 }, { "sqlite3_data_count", test_data_count ,0 }, { "sqlite3_column_type", test_column_type ,0 }, { "sqlite3_column_blob", test_column_blob ,0 }, { "sqlite3_column_double", test_column_double ,0 }, | > | 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 | { "sqlite3_enable_load_extension", test_enable_load, 0}, { "sqlite3_extended_result_codes", test_extended_result_codes, 0}, { "sqlite3_limit", test_limit, 0}, { "save_prng_state", save_prng_state, 0 }, { "restore_prng_state", restore_prng_state, 0 }, { "reset_prng_state", reset_prng_state, 0 }, { "tcl_objproc", runAsObjProc, 0 }, /* sqlite3_column_*() API */ { "sqlite3_column_count", test_column_count ,0 }, { "sqlite3_data_count", test_data_count ,0 }, { "sqlite3_column_type", test_column_type ,0 }, { "sqlite3_column_blob", test_column_blob ,0 }, { "sqlite3_column_double", test_column_double ,0 }, |
︙ | ︙ | |||
5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 | } for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, aObjCmd[i].clientData, 0); } Tcl_LinkVar(interp, "sqlite_search_count", (char*)&sqlite3_search_count, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite_sort_count", (char*)&sqlite3_sort_count, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite3_max_blobsize", (char*)&sqlite3_max_blobsize, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite_like_count", (char*)&sqlite3_like_count, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite_interrupt_count", | > > | 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 | } for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, aObjCmd[i].clientData, 0); } Tcl_LinkVar(interp, "sqlite_search_count", (char*)&sqlite3_search_count, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite_found_count", (char*)&sqlite3_found_count, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite_sort_count", (char*)&sqlite3_sort_count, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite3_max_blobsize", (char*)&sqlite3_max_blobsize, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite_like_count", (char*)&sqlite3_like_count, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite_interrupt_count", |
︙ | ︙ |
Changes to src/test2.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. ** ************************************************************************* ** Code for testing the pager.c module in SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. | < < | 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. ** ************************************************************************* ** Code for testing the pager.c module in SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. */ #include "sqliteInt.h" #include "tcl.h" #include <stdlib.h> #include <string.h> #include <ctype.h> |
︙ | ︙ | |||
51 52 53 54 55 56 57 58 59 60 61 62 63 64 | return zName; } /* ** Page size and reserved size used for testing. */ static int test_pagesize = 1024; /* ** Usage: pager_open FILENAME N-PAGE ** ** Open a new pager */ static int pager_open( | > > > > > > > | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | return zName; } /* ** Page size and reserved size used for testing. */ static int test_pagesize = 1024; /* ** Dummy page reinitializer */ static void pager_test_reiniter(DbPage *pNotUsed){ return; } /* ** Usage: pager_open FILENAME N-PAGE ** ** Open a new pager */ static int pager_open( |
︙ | ︙ | |||
75 76 77 78 79 80 81 | if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " FILENAME N-PAGE\"", 0); return TCL_ERROR; } if( Tcl_GetInt(interp, argv[2], &nPage) ) return TCL_ERROR; rc = sqlite3PagerOpen(sqlite3_vfs_find(0), &pPager, argv[1], 0, 0, | | > | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " FILENAME N-PAGE\"", 0); return TCL_ERROR; } if( Tcl_GetInt(interp, argv[2], &nPage) ) return TCL_ERROR; rc = sqlite3PagerOpen(sqlite3_vfs_find(0), &pPager, argv[1], 0, 0, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB, pager_test_reiniter); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; } sqlite3PagerSetCachesize(pPager, nPage); pageSize = test_pagesize; sqlite3PagerSetPagesize(pPager, &pageSize, -1); |
︙ | ︙ | |||
338 339 340 341 342 343 344 | if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID PGNO\"", 0); return TCL_ERROR; } pPager = sqlite3TestTextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR; | > > | > | 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 | if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID PGNO\"", 0); return TCL_ERROR; } pPager = sqlite3TestTextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR; rc = sqlite3PagerSharedLock(pPager); if( rc==SQLITE_OK ){ rc = sqlite3PagerGet(pPager, pgno, &pPage); } if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; } sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPage); Tcl_AppendResult(interp, zBuf, 0); return TCL_OK; |
︙ | ︙ | |||
619 620 621 622 623 624 625 | int Sqlitetest2_Init(Tcl_Interp *interp){ extern int sqlite3_io_error_persist; extern int sqlite3_io_error_pending; extern int sqlite3_io_error_hit; extern int sqlite3_io_error_hardhit; extern int sqlite3_diskfull_pending; extern int sqlite3_diskfull; | < | 628 629 630 631 632 633 634 635 636 637 638 639 640 641 | int Sqlitetest2_Init(Tcl_Interp *interp){ extern int sqlite3_io_error_persist; extern int sqlite3_io_error_pending; extern int sqlite3_io_error_hit; extern int sqlite3_io_error_hardhit; extern int sqlite3_diskfull_pending; extern int sqlite3_diskfull; static struct { char *zName; Tcl_CmdProc *xProc; } aCmd[] = { { "pager_open", (Tcl_CmdProc*)pager_open }, { "pager_close", (Tcl_CmdProc*)pager_close }, { "pager_commit", (Tcl_CmdProc*)pager_commit }, |
︙ | ︙ | |||
664 665 666 667 668 669 670 | (char*)&sqlite3_io_error_hardhit, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite_diskfull_pending", (char*)&sqlite3_diskfull_pending, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite_diskfull", (char*)&sqlite3_diskfull, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite_pending_byte", (char*)&sqlite3PendingByte, TCL_LINK_INT | TCL_LINK_READ_ONLY); | < < | 672 673 674 675 676 677 678 679 680 | (char*)&sqlite3_io_error_hardhit, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite_diskfull_pending", (char*)&sqlite3_diskfull_pending, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite_diskfull", (char*)&sqlite3_diskfull, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite_pending_byte", (char*)&sqlite3PendingByte, TCL_LINK_INT | TCL_LINK_READ_ONLY); return TCL_OK; } |
Changes to src/test3.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. ** ************************************************************************* ** Code for testing the btree.c module in SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. | < < | 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. ** ************************************************************************* ** Code for testing the btree.c module in SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. */ #include "sqliteInt.h" #include "btreeInt.h" #include "tcl.h" #include <stdlib.h> #include <string.h> |
︙ | ︙ | |||
153 154 155 156 157 158 159 | if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; } return TCL_OK; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; } return TCL_OK; } /* ** Usage: btree_pager_stats ID ** ** Returns pager statistics */ static int btree_pager_stats( void *NotUsed, |
︙ | ︙ | |||
522 523 524 525 526 527 528 | sqlite3BtreeLeave(pBt); /* Release the mutex on the SQLite handle that controls this b-tree */ sqlite3_mutex_leave(pBt->db->mutex); return TCL_OK; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | sqlite3BtreeLeave(pBt); /* Release the mutex on the SQLite handle that controls this b-tree */ sqlite3_mutex_leave(pBt->db->mutex); return TCL_OK; } /* ** Usage: btree_cursor ID TABLENUM WRITEABLE ** ** Create a new cursor. Return the ID for the cursor. */ static int btree_cursor( void *NotUsed, |
︙ | ︙ | |||
622 623 624 625 626 627 628 | } pBt = sqlite3TestTextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR; pCur = (BtCursor *)ckalloc(sqlite3BtreeCursorSize()); memset(pCur, 0, sqlite3BtreeCursorSize()); sqlite3BtreeEnter(pBt); | > > | > | 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | } pBt = sqlite3TestTextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR; pCur = (BtCursor *)ckalloc(sqlite3BtreeCursorSize()); memset(pCur, 0, sqlite3BtreeCursorSize()); sqlite3BtreeEnter(pBt); rc = sqlite3BtreeLockTable(pBt, iTable, wrFlag); if( rc==SQLITE_OK ){ rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, pCur); } sqlite3BtreeLeave(pBt); if( rc ){ ckfree((char *)pCur); Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; } sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur); |
︙ | ︙ | |||
667 668 669 670 671 672 673 | if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; } return SQLITE_OK; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 278 279 280 281 282 283 284 285 286 287 288 289 290 291 | if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; } return SQLITE_OK; } /* ** Usage: btree_next ID ** ** Move the cursor to the next entry in the table. Return 0 on success ** or 1 if the cursor was already on the last entry in the table or if ** the table is empty. */ |
︙ | ︙ | |||
824 825 826 827 828 829 830 | return TCL_ERROR; } pCur = sqlite3TestTextToPtr(argv[1]); sqlite3BtreeEnter(pCur->pBtree); rc = sqlite3BtreeNext(pCur, &res); sqlite3BtreeLeave(pCur->pBtree); if( rc ){ | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | return TCL_ERROR; } pCur = sqlite3TestTextToPtr(argv[1]); sqlite3BtreeEnter(pCur->pBtree); rc = sqlite3BtreeNext(pCur, &res); sqlite3BtreeLeave(pCur->pBtree); if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; } sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); Tcl_AppendResult(interp, zBuf, 0); return SQLITE_OK; } |
︙ | ︙ | |||
903 904 905 906 907 908 909 | return TCL_ERROR; } sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); Tcl_AppendResult(interp, zBuf, 0); return SQLITE_OK; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 349 350 351 352 353 354 355 356 357 358 359 360 361 362 | return TCL_ERROR; } sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); Tcl_AppendResult(interp, zBuf, 0); return SQLITE_OK; } /* ** Usage: btree_eof ID ** ** Return TRUE if the given cursor is not pointing at a valid entry. ** Return FALSE if the cursor does point to a valid entry. */ static int btree_eof( |
︙ | ︙ | |||
968 969 970 971 972 973 974 | rc = sqlite3BtreeEof(pCur); sqlite3BtreeLeave(pCur->pBtree); sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", rc); Tcl_AppendResult(interp, zBuf, 0); return SQLITE_OK; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 379 380 381 382 383 384 385 386 387 388 389 390 391 392 | rc = sqlite3BtreeEof(pCur); sqlite3BtreeLeave(pCur->pBtree); sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", rc); Tcl_AppendResult(interp, zBuf, 0); return SQLITE_OK; } /* ** Usage: btree_payload_size ID ** ** Return the number of bytes of payload */ static int btree_payload_size( void *NotUsed, |
︙ | ︙ | |||
1187 1188 1189 1190 1191 1192 1193 | if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; } pCur = sqlite3TestTextToPtr(argv[1]); sqlite3BtreeEnter(pCur->pBtree); | | > > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 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 | if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; } pCur = sqlite3TestTextToPtr(argv[1]); sqlite3BtreeEnter(pCur->pBtree); /* The cursor may be in "require-seek" state. If this is the case, the ** call to BtreeDataSize() will fix it. */ sqlite3BtreeDataSize(pCur, (u32*)&n2); if( pCur->apPage[pCur->iPage]->intKey ){ n1 = 0; }else{ sqlite3BtreeKeySize(pCur, (i64*)&n1); } sqlite3BtreeLeave(pCur->pBtree); sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", (int)(n1+n2)); Tcl_AppendResult(interp, zBuf, 0); return SQLITE_OK; } /* ** usage: varint_test START MULTIPLIER COUNT INCREMENT ** ** This command tests the putVarint() and getVarint() ** routines, both for accuracy and for speed. ** ** An integer is written using putVarint() and read back with |
︙ | ︙ | |||
1480 1481 1482 1483 1484 1485 1486 | pBt = db->aDb[iDb].pBt; sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt); Tcl_SetResult(interp, zBuf, TCL_VOLATILE); return TCL_OK; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 545 546 547 548 549 550 551 552 553 554 555 556 557 558 | pBt = db->aDb[iDb].pBt; sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt); Tcl_SetResult(interp, zBuf, TCL_VOLATILE); return TCL_OK; } /* ** Usage: btree_ismemdb ID ** ** Return true if the B-Tree is in-memory. */ static int btree_ismemdb( void *NotUsed, |
︙ | ︙ | |||
1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 | res = sqlite3PagerIsMemdb(sqlite3BtreePager(pBt)); sqlite3BtreeLeave(pBt); sqlite3_mutex_leave(pBt->db->mutex); Tcl_SetObjResult(interp, Tcl_NewBooleanObj(res)); return SQLITE_OK; } /* ** Register commands with the TCL interpreter. */ int Sqlitetest3_Init(Tcl_Interp *interp){ static struct { char *zName; Tcl_CmdProc *xProc; } aCmd[] = { { "btree_open", (Tcl_CmdProc*)btree_open }, { "btree_close", (Tcl_CmdProc*)btree_close }, { "btree_begin_transaction", (Tcl_CmdProc*)btree_begin_transaction }, | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < < < < < < < < < < < < < < < < < < < < < < < > < < < < < | 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 | res = sqlite3PagerIsMemdb(sqlite3BtreePager(pBt)); sqlite3BtreeLeave(pBt); sqlite3_mutex_leave(pBt->db->mutex); Tcl_SetObjResult(interp, Tcl_NewBooleanObj(res)); return SQLITE_OK; } /* ** usage: btree_set_cache_size ID NCACHE ** ** Set the size of the cache used by btree $ID. */ static int btree_set_cache_size( 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 nCache; Btree *pBt; if( argc!=3 ){ Tcl_AppendResult( interp, "wrong # args: should be \"", argv[0], " BT NCACHE\"", 0); return TCL_ERROR; } pBt = sqlite3TestTextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR; sqlite3_mutex_enter(pBt->db->mutex); sqlite3BtreeEnter(pBt); sqlite3BtreeSetCacheSize(pBt, nCache); sqlite3BtreeLeave(pBt); sqlite3_mutex_leave(pBt->db->mutex); return TCL_OK; } /* ** Register commands with the TCL interpreter. */ int Sqlitetest3_Init(Tcl_Interp *interp){ static struct { char *zName; Tcl_CmdProc *xProc; } aCmd[] = { { "btree_open", (Tcl_CmdProc*)btree_open }, { "btree_close", (Tcl_CmdProc*)btree_close }, { "btree_begin_transaction", (Tcl_CmdProc*)btree_begin_transaction }, { "btree_pager_stats", (Tcl_CmdProc*)btree_pager_stats }, { "btree_cursor", (Tcl_CmdProc*)btree_cursor }, { "btree_close_cursor", (Tcl_CmdProc*)btree_close_cursor }, { "btree_next", (Tcl_CmdProc*)btree_next }, { "btree_eof", (Tcl_CmdProc*)btree_eof }, { "btree_payload_size", (Tcl_CmdProc*)btree_payload_size }, { "btree_first", (Tcl_CmdProc*)btree_first }, { "btree_varint_test", (Tcl_CmdProc*)btree_varint_test }, { "btree_from_db", (Tcl_CmdProc*)btree_from_db }, { "btree_ismemdb", (Tcl_CmdProc*)btree_ismemdb }, { "btree_set_cache_size", (Tcl_CmdProc*)btree_set_cache_size } }; 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; } |
Changes to src/test4.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 2003 December 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. ** ************************************************************************* ** Code for testing the the SQLite library in a multithreaded environment. | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2003 December 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. ** ************************************************************************* ** Code for testing the the SQLite library in a multithreaded environment. */ #include "sqliteInt.h" #include "tcl.h" #if defined(SQLITE_OS_UNIX) && OS_UNIX==1 && SQLITE_THREADSAFE #include <stdlib.h> #include <string.h> #include <pthread.h> |
︙ | ︙ | |||
645 646 647 648 649 650 651 652 653 654 655 656 657 658 | } thread_wait(&threadset[i]); sqlite3TestMakePointerStr(interp, zBuf, threadset[i].db); threadset[i].db = 0; Tcl_AppendResult(interp, zBuf, (char*)0); return TCL_OK; } /* ** Usage: thread_stmt_get ID ** ** Return the database stmt pointer for the given thread. Then ** remove the pointer from the thread itself. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } thread_wait(&threadset[i]); sqlite3TestMakePointerStr(interp, zBuf, threadset[i].db); threadset[i].db = 0; Tcl_AppendResult(interp, zBuf, (char*)0); return TCL_OK; } /* ** Usage: thread_db_put ID DB ** */ static int tcl_thread_db_put( 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; extern int sqlite3TestMakePointerStr(Tcl_Interp*, char*, void*); extern void *sqlite3TestTextToPtr(const char *); if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID DB", 0); return TCL_ERROR; } i = parse_thread_id(interp, argv[1]); if( i<0 ) return TCL_ERROR; if( !threadset[i].busy ){ Tcl_AppendResult(interp, "no such thread", 0); return TCL_ERROR; } thread_wait(&threadset[i]); assert( !threadset[i].db ); threadset[i].db = (sqlite3*)sqlite3TestTextToPtr(argv[2]); return TCL_OK; } /* ** Usage: thread_stmt_get ID ** ** Return the database stmt pointer for the given thread. Then ** remove the pointer from the thread itself. */ |
︙ | ︙ | |||
700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 | { "thread_result", (Tcl_CmdProc*)tcl_thread_result }, { "thread_error", (Tcl_CmdProc*)tcl_thread_error }, { "thread_compile", (Tcl_CmdProc*)tcl_thread_compile }, { "thread_step", (Tcl_CmdProc*)tcl_thread_step }, { "thread_finalize", (Tcl_CmdProc*)tcl_thread_finalize }, { "thread_swap", (Tcl_CmdProc*)tcl_thread_swap }, { "thread_db_get", (Tcl_CmdProc*)tcl_thread_db_get }, { "thread_stmt_get", (Tcl_CmdProc*)tcl_thread_stmt_get }, }; 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 Sqlitetest4_Init(Tcl_Interp *interp){ return TCL_OK; } #endif /* SQLITE_OS_UNIX */ | > | 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 | { "thread_result", (Tcl_CmdProc*)tcl_thread_result }, { "thread_error", (Tcl_CmdProc*)tcl_thread_error }, { "thread_compile", (Tcl_CmdProc*)tcl_thread_compile }, { "thread_step", (Tcl_CmdProc*)tcl_thread_step }, { "thread_finalize", (Tcl_CmdProc*)tcl_thread_finalize }, { "thread_swap", (Tcl_CmdProc*)tcl_thread_swap }, { "thread_db_get", (Tcl_CmdProc*)tcl_thread_db_get }, { "thread_db_put", (Tcl_CmdProc*)tcl_thread_db_put }, { "thread_stmt_get", (Tcl_CmdProc*)tcl_thread_stmt_get }, }; 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 Sqlitetest4_Init(Tcl_Interp *interp){ return TCL_OK; } #endif /* SQLITE_OS_UNIX */ |
Changes to src/test5.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** Code for testing the utf.c module in SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. Specifically, the code in this file ** is used for testing the SQLite routines for converting between ** the various supported unicode encodings. | < < | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** ************************************************************************* ** Code for testing the utf.c module in SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. Specifically, the code in this file ** is used for testing the SQLite routines for converting between ** the various supported unicode encodings. */ #include "sqliteInt.h" #include "vdbeInt.h" #include "tcl.h" #include <stdlib.h> #include <string.h> |
︙ | ︙ |
Changes to src/test6.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains code that modified the OS layer in order to simulate ** the effect on the database file of an OS crash or power failure. This ** is used to test the ability of SQLite to recover from those situations. | < < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains code that modified the OS layer in order to simulate ** the effect on the database file of an OS crash or power failure. This ** is used to test the ability of SQLite to recover from those situations. */ #if SQLITE_TEST /* This file is used for testing only */ #include "sqliteInt.h" #include "tcl.h" #ifndef SQLITE_OMIT_DISKIO /* This file is a no-op if disk I/O is disabled */ |
︙ | ︙ |
Changes to src/test7.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 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. | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* ** 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" #include "tcl.h" /* ** This test only works on UNIX with a SQLITE_THREADSAFE build that includes ** the SQLITE_SERVER option. |
︙ | ︙ |
Changes to src/test8.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. ** ************************************************************************* ** Code for testing the virtual table interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. | < < | 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. ** ************************************************************************* ** Code for testing the virtual table interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. */ #include "sqliteInt.h" #include "tcl.h" #include <stdlib.h> #include <string.h> #ifndef SQLITE_OMIT_VIRTUALTABLE |
︙ | ︙ |
Changes to src/test9.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains obscure tests of the C-interface required ** for completeness. Test code is written in C for these cases ** as there is not much point in binding to Tcl. | < < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains obscure tests of the C-interface required ** for completeness. Test code is written in C for these cases ** as there is not much point in binding to Tcl. */ #include "sqliteInt.h" #include "tcl.h" #include <stdlib.h> #include <string.h> /* |
︙ | ︙ |
Changes to src/test_async.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 2005 December 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 | /* ** 2005 December 14 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains a binding of the asynchronous IO extension interface ** (defined in ext/async/sqlite3async.h) to Tcl. */ #define TCL_THREADS #include <tcl.h> |
︙ | ︙ |
Changes to src/test_autoext.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 2006 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. ** ************************************************************************* ** Test extension for testing the sqlite3_auto_extension() function. | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2006 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. ** ************************************************************************* ** Test extension for testing the sqlite3_auto_extension() function. */ #include "tcl.h" #include "sqlite3ext.h" #ifndef SQLITE_OMIT_LOAD_EXTENSION static SQLITE_EXTENSION_INIT1 |
︙ | ︙ |
Changes to src/test_backup.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 2009 January 28 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** | > < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* ** 2009 January 28 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains test logic for the sqlite3_backup() interface. ** */ #include "tcl.h" #include <sqlite3.h> #include <assert.h> /* These functions are implemented in test1.c. */ |
︙ | ︙ |
Changes to src/test_btree.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. ** ************************************************************************* ** Code for testing the btree.c module in SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. | < < | 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. ** ************************************************************************* ** Code for testing the btree.c module in SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. */ #include "btreeInt.h" #include <tcl.h> /* ** Usage: sqlite3_shared_cache_report ** |
︙ | ︙ | |||
58 59 60 61 62 63 64 | pCur, pCur->pgnoRoot, zMode, pPage ? pPage->pgno : 0, pCur->aiIdx[pCur->iPage], (pCur->eState==CURSOR_VALID) ? "" : " eof" ); } #endif } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 56 57 58 59 60 61 62 | pCur, pCur->pgnoRoot, zMode, pPage ? pPage->pgno : 0, pCur->aiIdx[pCur->iPage], (pCur->eState==CURSOR_VALID) ? "" : " eof" ); } #endif } |
Changes to src/test_config.c.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ************************************************************************* ** ** This file contains code used for testing the SQLite system. ** None of the code in this file goes into a deliverable build. ** ** The focus of this file is providing the TCL testing layer ** access to compile-time constants. | < < | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ************************************************************************* ** ** This file contains code used for testing the SQLite system. ** None of the code in this file goes into a deliverable build. ** ** The focus of this file is providing the TCL testing layer ** access to compile-time constants. */ #include "sqliteLimit.h" #include "sqliteInt.h" #include "tcl.h" #include <stdlib.h> |
︙ | ︙ | |||
391 392 393 394 395 396 397 398 399 400 401 402 403 404 | #endif #ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS Tcl_SetVar2(interp, "sqlite_options", "schema_version", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "schema_version", "1", TCL_GLOBAL_ONLY); #endif #if !defined(SQLITE_ENABLE_LOCKING_STYLE) # if defined(__APPLE__) # define SQLITE_ENABLE_LOCKING_STYLE 1 # else # define SQLITE_ENABLE_LOCKING_STYLE 0 # endif | > > > > > > | 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 | #endif #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_STAT2 Tcl_SetVar2(interp, "sqlite_options", "stat2", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "stat2", "0", TCL_GLOBAL_ONLY); #endif #if !defined(SQLITE_ENABLE_LOCKING_STYLE) # if defined(__APPLE__) # define SQLITE_ENABLE_LOCKING_STYLE 1 # else # define SQLITE_ENABLE_LOCKING_STYLE 0 # endif |
︙ | ︙ | |||
527 528 529 530 531 532 533 534 535 536 537 538 539 540 | LINKVAR( MAX_COMPOUND_SELECT ); LINKVAR( MAX_VDBE_OP ); LINKVAR( MAX_FUNCTION_ARG ); LINKVAR( MAX_VARIABLE_NUMBER ); LINKVAR( MAX_PAGE_SIZE ); LINKVAR( MAX_PAGE_COUNT ); LINKVAR( MAX_LIKE_PATTERN_LENGTH ); LINKVAR( DEFAULT_TEMP_CACHE_SIZE ); LINKVAR( DEFAULT_CACHE_SIZE ); LINKVAR( DEFAULT_PAGE_SIZE ); LINKVAR( DEFAULT_FILE_FORMAT ); LINKVAR( MAX_ATTACHED ); { | > | 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 | LINKVAR( MAX_COMPOUND_SELECT ); LINKVAR( MAX_VDBE_OP ); LINKVAR( MAX_FUNCTION_ARG ); LINKVAR( MAX_VARIABLE_NUMBER ); LINKVAR( MAX_PAGE_SIZE ); LINKVAR( MAX_PAGE_COUNT ); LINKVAR( MAX_LIKE_PATTERN_LENGTH ); LINKVAR( MAX_TRIGGER_DEPTH ); LINKVAR( DEFAULT_TEMP_CACHE_SIZE ); LINKVAR( DEFAULT_CACHE_SIZE ); LINKVAR( DEFAULT_PAGE_SIZE ); LINKVAR( DEFAULT_FILE_FORMAT ); LINKVAR( MAX_ATTACHED ); { |
︙ | ︙ |
Changes to src/test_devsym.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains code that modified the OS layer in order to simulate ** different device types (by overriding the return values of the ** xDeviceCharacteristics() and xSectorSize() methods). | < < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains code that modified the OS layer in order to simulate ** different device types (by overriding the return values of the ** xDeviceCharacteristics() and xSectorSize() methods). */ #if SQLITE_TEST /* This file is used for testing only */ #include "sqlite3.h" #include "sqliteInt.h" /* |
︙ | ︙ |
Changes to src/test_func.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2008 March 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. ** ************************************************************************* ** Code for testing all sorts of SQLite interfaces. This code ** implements new SQL functions used by the test scripts. | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* ** 2008 March 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. ** ************************************************************************* ** Code for testing all sorts of SQLite interfaces. This code ** implements new SQL functions used by the test scripts. */ #include "sqlite3.h" #include "tcl.h" #include <stdlib.h> #include <string.h> #include <assert.h> |
︙ | ︙ | |||
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | ** API function. */ void sqlite3BeginBenignMalloc(void); void sqlite3EndBenignMalloc(void); static void test_agg_errmsg16_step(sqlite3_context *a, int b,sqlite3_value **c){ } static void test_agg_errmsg16_final(sqlite3_context *ctx){ const void *z; sqlite3 * db = sqlite3_context_db_handle(ctx); sqlite3_aggregate_context(ctx, 2048); sqlite3BeginBenignMalloc(); z = sqlite3_errmsg16(db); sqlite3EndBenignMalloc(); sqlite3_result_text16(ctx, z, -1, SQLITE_TRANSIENT); } /* ** Routines for testing the sqlite3_get_auxdata() and sqlite3_set_auxdata() ** interface. ** ** The test_auxdata() SQL function attempts to register each of its arguments | > > | 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | ** API function. */ void sqlite3BeginBenignMalloc(void); void sqlite3EndBenignMalloc(void); static void test_agg_errmsg16_step(sqlite3_context *a, int b,sqlite3_value **c){ } static void test_agg_errmsg16_final(sqlite3_context *ctx){ #ifndef SQLITE_OMIT_UTF16 const void *z; sqlite3 * db = sqlite3_context_db_handle(ctx); sqlite3_aggregate_context(ctx, 2048); sqlite3BeginBenignMalloc(); z = sqlite3_errmsg16(db); sqlite3EndBenignMalloc(); sqlite3_result_text16(ctx, z, -1, SQLITE_TRANSIENT); #endif } /* ** Routines for testing the sqlite3_get_auxdata() and sqlite3_set_auxdata() ** interface. ** ** The test_auxdata() SQL function attempts to register each of its arguments |
︙ | ︙ | |||
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 | assert( pStmt==0 ); zErr = sqlite3_mprintf("sqlite3_prepare_v2() error: %s",sqlite3_errmsg(db)); sqlite3_result_text(pCtx, zErr, -1, sqlite3_free); sqlite3_result_error_code(pCtx, rc); } } static int registerTestFunctions(sqlite3 *db){ static const struct { char *zName; signed char nArg; unsigned char eTextRep; /* 1: UTF-16. 0: UTF-8 */ void (*xFunc)(sqlite3_context*,int,sqlite3_value **); } aFuncs[] = { { "randstr", 2, SQLITE_UTF8, randStr }, { "test_destructor", 1, SQLITE_UTF8, test_destructor}, #ifndef SQLITE_OMIT_UTF16 { "test_destructor16", 1, SQLITE_UTF8, test_destructor16}, #endif { "test_destructor_count", 0, SQLITE_UTF8, test_destructor_count}, { "test_auxdata", -1, SQLITE_UTF8, test_auxdata}, { "test_error", 1, SQLITE_UTF8, test_error}, { "test_error", 2, SQLITE_UTF8, test_error}, { "test_eval", 1, SQLITE_UTF8, test_eval}, { "test_isolation", 2, SQLITE_UTF8, test_isolation}, { "test_counter", 1, SQLITE_UTF8, counterFunc}, | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | assert( pStmt==0 ); zErr = sqlite3_mprintf("sqlite3_prepare_v2() error: %s",sqlite3_errmsg(db)); sqlite3_result_text(pCtx, zErr, -1, sqlite3_free); sqlite3_result_error_code(pCtx, rc); } } /* ** convert one character from hex to binary */ static int testHexChar(char c){ if( c>='0' && c<='9' ){ return c - '0'; }else if( c>='a' && c<='f' ){ return c - 'a' + 10; }else if( c>='A' && c<='F' ){ return c - 'A' + 10; } return 0; } /* ** Convert hex to binary. */ static void testHexToBin(const char *zIn, char *zOut){ while( zIn[0] && zIn[1] ){ *(zOut++) = (testHexChar(zIn[0])<<4) + testHexChar(zIn[1]); zIn += 2; } } /* ** hex_to_utf16be(HEX) ** ** Convert the input string from HEX into binary. Then return the ** result using sqlite3_result_text16le(). */ static void testHexToUtf16be( sqlite3_context *pCtx, int nArg, sqlite3_value **argv ){ int n; const char *zIn; char *zOut; assert( nArg==1 ); n = sqlite3_value_bytes(argv[0]); zIn = (const char*)sqlite3_value_text(argv[0]); zOut = sqlite3_malloc( n/2 ); if( zOut==0 ){ sqlite3_result_error_nomem(pCtx); }else{ testHexToBin(zIn, zOut); sqlite3_result_text16be(pCtx, zOut, n/2, sqlite3_free); } } /* ** hex_to_utf8(HEX) ** ** Convert the input string from HEX into binary. Then return the ** result using sqlite3_result_text16le(). */ static void testHexToUtf8( sqlite3_context *pCtx, int nArg, sqlite3_value **argv ){ int n; const char *zIn; char *zOut; assert( nArg==1 ); n = sqlite3_value_bytes(argv[0]); zIn = (const char*)sqlite3_value_text(argv[0]); zOut = sqlite3_malloc( n/2 ); if( zOut==0 ){ sqlite3_result_error_nomem(pCtx); }else{ testHexToBin(zIn, zOut); sqlite3_result_text(pCtx, zOut, n/2, sqlite3_free); } } /* ** hex_to_utf16le(HEX) ** ** Convert the input string from HEX into binary. Then return the ** result using sqlite3_result_text16le(). */ static void testHexToUtf16le( sqlite3_context *pCtx, int nArg, sqlite3_value **argv ){ int n; const char *zIn; char *zOut; assert( nArg==1 ); n = sqlite3_value_bytes(argv[0]); zIn = (const char*)sqlite3_value_text(argv[0]); zOut = sqlite3_malloc( n/2 ); if( zOut==0 ){ sqlite3_result_error_nomem(pCtx); }else{ testHexToBin(zIn, zOut); sqlite3_result_text16le(pCtx, zOut, n/2, sqlite3_free); } } static int registerTestFunctions(sqlite3 *db){ static const struct { char *zName; signed char nArg; unsigned char eTextRep; /* 1: UTF-16. 0: UTF-8 */ void (*xFunc)(sqlite3_context*,int,sqlite3_value **); } aFuncs[] = { { "randstr", 2, SQLITE_UTF8, randStr }, { "test_destructor", 1, SQLITE_UTF8, test_destructor}, #ifndef SQLITE_OMIT_UTF16 { "test_destructor16", 1, SQLITE_UTF8, test_destructor16}, { "hex_to_utf16be", 1, SQLITE_UTF8, testHexToUtf16be}, { "hex_to_utf16le", 1, SQLITE_UTF8, testHexToUtf16le}, #endif { "hex_to_utf8", 1, SQLITE_UTF8, testHexToUtf8}, { "test_destructor_count", 0, SQLITE_UTF8, test_destructor_count}, { "test_auxdata", -1, SQLITE_UTF8, test_auxdata}, { "test_error", 1, SQLITE_UTF8, test_error}, { "test_error", 2, SQLITE_UTF8, test_error}, { "test_eval", 1, SQLITE_UTF8, test_eval}, { "test_isolation", 2, SQLITE_UTF8, test_isolation}, { "test_counter", 1, SQLITE_UTF8, counterFunc}, |
︙ | ︙ | |||
440 441 442 443 444 445 446 | return TCL_OK; abuse_err: Tcl_AppendResult(interp, "sqlite3_create_function abused test failed", (char*)0); return TCL_ERROR; } | < < | 545 546 547 548 549 550 551 552 553 554 555 556 557 558 | return TCL_OK; abuse_err: Tcl_AppendResult(interp, "sqlite3_create_function abused test failed", (char*)0); return TCL_ERROR; } /* ** Register commands with the TCL interpreter. */ int Sqlitetest_func_Init(Tcl_Interp *interp){ static struct { char *zName; |
︙ | ︙ |
Changes to src/test_hexio.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 | ** Code for testing all sorts of SQLite interfaces. This code ** implements TCL commands for reading and writing the binary ** database files and displaying the content of those files as ** hexadecimal. We could, in theory, use the built-in "binary" ** command of TCL to do a lot of this, but there are some issues ** with historical versions of the "binary" command. So it seems ** easier and safer to build our own mechanism. | < < | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ** Code for testing all sorts of SQLite interfaces. This code ** implements TCL commands for reading and writing the binary ** database files and displaying the content of those files as ** hexadecimal. We could, in theory, use the built-in "binary" ** command of TCL to do a lot of this, but there are some issues ** with historical versions of the "binary" command. So it seems ** easier and safer to build our own mechanism. */ #include "sqliteInt.h" #include "tcl.h" #include <stdlib.h> #include <string.h> #include <assert.h> |
︙ | ︙ |
Added src/test_init.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 | /* ** 2009 August 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. ** ************************************************************************* ** ** The code in this file is used for testing SQLite. It is not part of ** the source code used in production systems. ** ** Specifically, this file tests the effect of errors while initializing ** the various pluggable sub-systems from within sqlite3_initialize(). ** If an error occurs in sqlite3_initialize() the following should be ** true: ** ** 1) An error code is returned to the user, and ** 2) A subsequent call to sqlite3_shutdown() calls the shutdown method ** of those subsystems that were initialized, and ** 3) A subsequent call to sqlite3_initialize() attempts to initialize ** the remaining, uninitialized, subsystems. */ #include "sqliteInt.h" #include <string.h> #include <tcl.h> static struct Wrapped { sqlite3_pcache_methods pcache; sqlite3_mem_methods mem; sqlite3_mutex_methods mutex; int mem_init; /* True if mem subsystem is initalized */ int mem_fail; /* True to fail mem subsystem inialization */ int mutex_init; /* True if mutex subsystem is initalized */ int mutex_fail; /* True to fail mutex subsystem inialization */ int pcache_init; /* True if pcache subsystem is initalized */ int pcache_fail; /* True to fail pcache subsystem inialization */ } wrapped; static int wrMemInit(void *pAppData){ int rc; if( wrapped.mem_fail ){ rc = SQLITE_ERROR; }else{ rc = wrapped.mem.xInit(wrapped.mem.pAppData); } if( rc==SQLITE_OK ){ wrapped.mem_init = 1; } return rc; } static void wrMemShutdown(void *pAppData){ wrapped.mem.xShutdown(wrapped.mem.pAppData); wrapped.mem_init = 0; } static void *wrMemMalloc(int n) {return wrapped.mem.xMalloc(n);} static void wrMemFree(void *p) {wrapped.mem.xFree(p);} static void *wrMemRealloc(void *p, int n) {return wrapped.mem.xRealloc(p, n);} static int wrMemSize(void *p) {return wrapped.mem.xSize(p);} static int wrMemRoundup(int n) {return wrapped.mem.xRoundup(n);} static int wrMutexInit(void){ int rc; if( wrapped.mutex_fail ){ rc = SQLITE_ERROR; }else{ rc = wrapped.mutex.xMutexInit(); } if( rc==SQLITE_OK ){ wrapped.mutex_init = 1; } return rc; } static int wrMutexEnd(void){ wrapped.mutex.xMutexEnd(); wrapped.mutex_init = 0; return SQLITE_OK; } static sqlite3_mutex *wrMutexAlloc(int e){ return wrapped.mutex.xMutexAlloc(e); } static void wrMutexFree(sqlite3_mutex *p){ wrapped.mutex.xMutexFree(p); } static void wrMutexEnter(sqlite3_mutex *p){ wrapped.mutex.xMutexEnter(p); } static int wrMutexTry(sqlite3_mutex *p){ return wrapped.mutex.xMutexTry(p); } static void wrMutexLeave(sqlite3_mutex *p){ wrapped.mutex.xMutexLeave(p); } static int wrMutexHeld(sqlite3_mutex *p){ return wrapped.mutex.xMutexHeld(p); } static int wrMutexNotheld(sqlite3_mutex *p){ return wrapped.mutex.xMutexNotheld(p); } static int wrPCacheInit(void *pArg){ int rc; if( wrapped.pcache_fail ){ rc = SQLITE_ERROR; }else{ rc = wrapped.pcache.xInit(wrapped.pcache.pArg); } if( rc==SQLITE_OK ){ wrapped.pcache_init = 1; } return rc; } static void wrPCacheShutdown(void *pArg){ wrapped.pcache.xShutdown(wrapped.pcache.pArg); wrapped.pcache_init = 0; } static sqlite3_pcache *wrPCacheCreate(int a, int b){ return wrapped.pcache.xCreate(a, b); } static void wrPCacheCachesize(sqlite3_pcache *p, int n){ wrapped.pcache.xCachesize(p, n); } static int wrPCachePagecount(sqlite3_pcache *p){ return wrapped.pcache.xPagecount(p); } static void *wrPCacheFetch(sqlite3_pcache *p, unsigned a, int b){ return wrapped.pcache.xFetch(p, a, b); } static void wrPCacheUnpin(sqlite3_pcache *p, void *a, int b){ wrapped.pcache.xUnpin(p, a, b); } static void wrPCacheRekey(sqlite3_pcache *p, void *a, unsigned b, unsigned c){ wrapped.pcache.xRekey(p, a, b, c); } static void wrPCacheTruncate(sqlite3_pcache *p, unsigned a){ wrapped.pcache.xTruncate(p, a); } static void wrPCacheDestroy(sqlite3_pcache *p){ wrapped.pcache.xDestroy(p); } static void installInitWrappers(void){ sqlite3_mutex_methods mutexmethods = { wrMutexInit, wrMutexEnd, wrMutexAlloc, wrMutexFree, wrMutexEnter, wrMutexTry, wrMutexLeave, wrMutexHeld, wrMutexNotheld }; sqlite3_pcache_methods pcachemethods = { 0, wrPCacheInit, wrPCacheShutdown, wrPCacheCreate, wrPCacheCachesize, wrPCachePagecount, wrPCacheFetch, wrPCacheUnpin, wrPCacheRekey, wrPCacheTruncate, wrPCacheDestroy }; sqlite3_mem_methods memmethods = { wrMemMalloc, wrMemFree, wrMemRealloc, wrMemSize, wrMemRoundup, wrMemInit, wrMemShutdown, 0 }; memset(&wrapped, 0, sizeof(wrapped)); sqlite3_shutdown(); sqlite3_config(SQLITE_CONFIG_GETMUTEX, &wrapped.mutex); sqlite3_config(SQLITE_CONFIG_GETMALLOC, &wrapped.mem); sqlite3_config(SQLITE_CONFIG_GETPCACHE, &wrapped.pcache); sqlite3_config(SQLITE_CONFIG_MUTEX, &mutexmethods); sqlite3_config(SQLITE_CONFIG_MALLOC, &memmethods); sqlite3_config(SQLITE_CONFIG_PCACHE, &pcachemethods); } static int init_wrapper_install( ClientData clientData, /* Unused */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ int i; installInitWrappers(); for(i=1; i<objc; i++){ char *z = Tcl_GetString(objv[i]); if( strcmp(z, "mem")==0 ){ wrapped.mem_fail = 1; }else if( strcmp(z, "mutex")==0 ){ wrapped.mutex_fail = 1; }else if( strcmp(z, "pcache")==0 ){ wrapped.pcache_fail = 1; }else{ Tcl_AppendResult(interp, "Unknown argument: \"", z, "\""); return TCL_ERROR; } } return TCL_OK; } static int init_wrapper_uninstall( ClientData clientData, /* Unused */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ if( objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, ""); return TCL_ERROR; } memset(&wrapped, 0, sizeof(&wrapped)); sqlite3_shutdown(); sqlite3_config(SQLITE_CONFIG_MUTEX, &wrapped.mutex); sqlite3_config(SQLITE_CONFIG_MALLOC, &wrapped.mem); sqlite3_config(SQLITE_CONFIG_PCACHE, &wrapped.pcache); return TCL_OK; } static int init_wrapper_clear( ClientData clientData, /* Unused */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ if( objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, ""); return TCL_ERROR; } wrapped.mem_fail = 0; wrapped.mutex_fail = 0; wrapped.pcache_fail = 0; return TCL_OK; } static int init_wrapper_query( ClientData clientData, /* Unused */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ Tcl_Obj *pRet; if( objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, ""); return TCL_ERROR; } pRet = Tcl_NewObj(); if( wrapped.mutex_init ){ Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("mutex", -1)); } if( wrapped.mem_init ){ Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("mem", -1)); } if( wrapped.pcache_init ){ Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("pcache", -1)); } Tcl_SetObjResult(interp, pRet); return TCL_OK; } int Sqlitetest_init_Init(Tcl_Interp *interp){ static struct { char *zName; Tcl_ObjCmdProc *xProc; } aObjCmd[] = { {"init_wrapper_install", init_wrapper_install}, {"init_wrapper_query", init_wrapper_query }, {"init_wrapper_uninstall", init_wrapper_uninstall}, {"init_wrapper_clear", init_wrapper_clear} }; 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; } |
Added src/test_intarray.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 | /* ** 2009 November 10 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file implements a read-only VIRTUAL TABLE that contains the ** content of a C-language array of integer values. See the corresponding ** header file for full details. */ #include "test_intarray.h" #include <string.h> #include <assert.h> /* ** Definition of the sqlite3_intarray object. ** ** The internal representation of an intarray object is subject ** to change, is not externally visible, and should be used by ** the implementation of intarray only. This object is opaque ** to users. */ struct sqlite3_intarray { int n; /* Number of elements in the array */ sqlite3_int64 *a; /* Contents of the array */ void (*xFree)(void*); /* Function used to free a[] */ }; /* Objects used internally by the virtual table implementation */ typedef struct intarray_vtab intarray_vtab; typedef struct intarray_cursor intarray_cursor; /* A intarray table object */ struct intarray_vtab { sqlite3_vtab base; /* Base class */ sqlite3_intarray *pContent; /* Content of the integer array */ }; /* A intarray cursor object */ struct intarray_cursor { sqlite3_vtab_cursor base; /* Base class */ int i; /* Current cursor position */ }; /* ** None of this works unless we have virtual tables. */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Free an sqlite3_intarray object. */ static void intarrayFree(sqlite3_intarray *p){ if( p->xFree ){ p->xFree(p->a); } sqlite3_free(p); } /* ** Table destructor for the intarray module. */ static int intarrayDestroy(sqlite3_vtab *p){ intarray_vtab *pVtab = (intarray_vtab*)p; sqlite3_free(pVtab); return 0; } /* ** Table constructor for the intarray module. */ static int intarrayCreate( sqlite3 *db, /* Database where module is created */ void *pAux, /* clientdata for the module */ int argc, /* Number of arguments */ const char *const*argv, /* Value for all arguments */ sqlite3_vtab **ppVtab, /* Write the new virtual table object here */ char **pzErr /* Put error message text here */ ){ int rc = SQLITE_NOMEM; intarray_vtab *pVtab = sqlite3_malloc(sizeof(intarray_vtab)); if( pVtab ){ memset(pVtab, 0, sizeof(intarray_vtab)); pVtab->pContent = (sqlite3_intarray*)pAux; rc = sqlite3_declare_vtab(db, "CREATE TABLE x(value INTEGER PRIMARY KEY)"); } *ppVtab = (sqlite3_vtab *)pVtab; return rc; } /* ** Open a new cursor on the intarray table. */ static int intarrayOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ int rc = SQLITE_NOMEM; intarray_cursor *pCur; pCur = sqlite3_malloc(sizeof(intarray_cursor)); if( pCur ){ memset(pCur, 0, sizeof(intarray_cursor)); *ppCursor = (sqlite3_vtab_cursor *)pCur; rc = SQLITE_OK; } return rc; } /* ** Close a intarray table cursor. */ static int intarrayClose(sqlite3_vtab_cursor *cur){ intarray_cursor *pCur = (intarray_cursor *)cur; sqlite3_free(pCur); return SQLITE_OK; } /* ** Retrieve a column of data. */ static int intarrayColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ intarray_cursor *pCur = (intarray_cursor*)cur; intarray_vtab *pVtab = (intarray_vtab*)cur->pVtab; if( pCur->i>=0 && pCur->i<pVtab->pContent->n ){ sqlite3_result_int64(ctx, pVtab->pContent->a[pCur->i]); } return SQLITE_OK; } /* ** Retrieve the current rowid. */ static int intarrayRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ intarray_cursor *pCur = (intarray_cursor *)cur; *pRowid = pCur->i; return SQLITE_OK; } static int intarrayEof(sqlite3_vtab_cursor *cur){ intarray_cursor *pCur = (intarray_cursor *)cur; intarray_vtab *pVtab = (intarray_vtab *)cur->pVtab; return pCur->i>=pVtab->pContent->n; } /* ** Advance the cursor to the next row. */ static int intarrayNext(sqlite3_vtab_cursor *cur){ intarray_cursor *pCur = (intarray_cursor *)cur; pCur->i++; return SQLITE_OK; } /* ** Reset a intarray table cursor. */ static int intarrayFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ intarray_cursor *pCur = (intarray_cursor *)pVtabCursor; pCur->i = 0; return SQLITE_OK; } /* ** Analyse the WHERE condition. */ static int intarrayBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ return SQLITE_OK; } /* ** A virtual table module that merely echos method calls into TCL ** variables. */ static sqlite3_module intarrayModule = { 0, /* iVersion */ intarrayCreate, /* xCreate - create a new virtual table */ intarrayCreate, /* xConnect - connect to an existing vtab */ intarrayBestIndex, /* xBestIndex - find the best query index */ intarrayDestroy, /* xDisconnect - disconnect a vtab */ intarrayDestroy, /* xDestroy - destroy a vtab */ intarrayOpen, /* xOpen - open a cursor */ intarrayClose, /* xClose - close a cursor */ intarrayFilter, /* xFilter - configure scan constraints */ intarrayNext, /* xNext - advance a cursor */ intarrayEof, /* xEof */ intarrayColumn, /* xColumn - read data */ intarrayRowid, /* xRowid - read data */ 0, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ }; #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */ /* ** Invoke this routine to create a specific instance of an intarray object. ** The new intarray object is returned by the 3rd parameter. ** ** Each intarray object corresponds to a virtual table in the TEMP table ** with a name of zName. ** ** Destroy the intarray object by dropping the virtual table. If not done ** explicitly by the application, the virtual table will be dropped implicitly ** by the system when the database connection is closed. */ int sqlite3_intarray_create( sqlite3 *db, const char *zName, sqlite3_intarray **ppReturn ){ int rc; sqlite3_intarray *p; *ppReturn = p = sqlite3_malloc( sizeof(*p) ); if( p==0 ){ return SQLITE_NOMEM; } memset(p, 0, sizeof(*p)); rc = sqlite3_create_module_v2(db, zName, &intarrayModule, p, (void(*)(void*))intarrayFree); if( rc==SQLITE_OK ){ char *zSql; zSql = sqlite3_mprintf("CREATE VIRTUAL TABLE temp.%Q USING %Q", zName, zName); rc = sqlite3_exec(db, zSql, 0, 0, 0); sqlite3_free(zSql); } return rc; } /* ** Bind a new array array of integers to a specific intarray object. ** ** The array of integers bound must be unchanged for the duration of ** any query against the corresponding virtual table. If the integer ** array does change or is deallocated undefined behavior will result. */ int sqlite3_intarray_bind( sqlite3_intarray *pIntArray, /* The intarray object to bind to */ int nElements, /* Number of elements in the intarray */ sqlite3_int64 *aElements, /* Content of the intarray */ void (*xFree)(void*) /* How to dispose of the intarray when done */ ){ if( pIntArray->xFree ){ pIntArray->xFree(pIntArray->a); } pIntArray->n = nElements; pIntArray->a = aElements; pIntArray->xFree = xFree; return SQLITE_OK; } /***************************************************************************** ** Everything below is interface for testing this module. */ #ifdef SQLITE_TEST #include <tcl.h> /* ** Routines to encode and decode pointers */ extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); extern int sqlite3TestTextToPtr(const char*); extern int sqlite3TestMakePointerStr(Tcl_Interp*, char *zPtr, void*); extern const char *sqlite3TestErrorName(int); /* ** sqlite3_intarray_create DB NAME ** ** Invoke the sqlite3_intarray_create interface. A string that becomes ** the first parameter to sqlite3_intarray_bind. */ static int test_intarray_create( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3 *db; const char *zName; sqlite3_intarray *pArray; int rc; char zPtr[100]; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; zName = Tcl_GetString(objv[2]); rc = sqlite3_intarray_create(db, zName, &pArray); if( rc!=SQLITE_OK ){ assert( pArray==0 ); Tcl_AppendResult(interp, sqlite3TestErrorName(rc), (char*)0); return TCL_ERROR; } sqlite3TestMakePointerStr(interp, zPtr, pArray); Tcl_AppendResult(interp, zPtr, (char*)0); return TCL_OK; } /* ** sqlite3_intarray_bind INTARRAY ?VALUE ...? ** ** Invoke the sqlite3_intarray_bind interface on the given array of integers. */ static int test_intarray_bind( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3_intarray *pArray; int rc; int i, n; sqlite3_int64 *a; if( objc<2 ){ Tcl_WrongNumArgs(interp, 1, objv, "INTARRAY"); return TCL_ERROR; } pArray = (sqlite3_intarray*)sqlite3TestTextToPtr(Tcl_GetString(objv[1])); n = objc - 2; a = sqlite3_malloc( sizeof(a[0])*n ); if( a==0 ){ Tcl_AppendResult(interp, "SQLITE_NOMEM", (char*)0); return TCL_ERROR; } for(i=0; i<n; i++){ a[i] = 0; Tcl_GetWideIntFromObj(0, objv[i+2], &a[i]); } rc = sqlite3_intarray_bind(pArray, n, a, sqlite3_free); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite3TestErrorName(rc), (char*)0); return TCL_ERROR; } return TCL_OK; } /* ** Register commands with the TCL interpreter. */ int Sqlitetestintarray_Init(Tcl_Interp *interp){ static struct { char *zName; Tcl_ObjCmdProc *xProc; void *clientData; } aObjCmd[] = { { "sqlite3_intarray_create", test_intarray_create, 0 }, { "sqlite3_intarray_bind", test_intarray_bind, 0 }, }; int i; for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, aObjCmd[i].clientData, 0); } return TCL_OK; } #endif /* SQLITE_TEST */ |
Added src/test_intarray.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 | /* ** 2009 November 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 the C-language interface definition for the "intarray" or ** integer array virtual table for SQLite. ** ** The intarray virtual table is designed to facilitate using an ** array of integers as the right-hand side of an IN operator. So ** instead of doing a prepared statement like this: ** ** SELECT * FROM table WHERE x IN (?,?,?,...,?); ** ** And then binding indivdual integers to each of ? slots, a C-language ** application can create an intarray object (named "ex1" in the following ** example), prepare a statement like this: ** ** SELECT * FROM table WHERE x IN ex1; ** ** Then bind an ordinary C/C++ array of integer values to the ex1 object ** to run the statement. ** ** USAGE: ** ** One or more intarray objects can be created as follows: ** ** sqlite3_intarray *p1, *p2, *p3; ** sqlite3_intarray_create(db, "ex1", &p1); ** sqlite3_intarray_create(db, "ex2", &p2); ** sqlite3_intarray_create(db, "ex3", &p3); ** ** Each call to sqlite3_intarray_create() generates a new virtual table ** module and a singleton of that virtual table module in the TEMP ** database. Both the module and the virtual table instance use the ** name given by the second parameter. The virtual tables can then be ** used in prepared statements: ** ** SELECT * FROM t1, t2, t3 ** WHERE t1.x IN ex1 ** AND t2.y IN ex2 ** AND t3.z IN ex3; ** ** Each integer array is initially empty. New arrays can be bound to ** an integer array as follows: ** ** sqlite3_int64 a1[] = { 1, 2, 3, 4 }; ** sqlite3_int64 a2[] = { 5, 6, 7, 8, 9, 10, 11 }; ** sqlite3_int64 *a3 = sqlite3_malloc( 100*sizeof(sqlite3_int64) ); ** // Fill in content of a3[] ** sqlite3_intarray_bind(p1, 4, a1, 0); ** sqlite3_intarray_bind(p2, 7, a2, 0); ** sqlite3_intarray_bind(p3, 100, a3, sqlite3_free); ** ** A single intarray object can be rebound multiple times. But do not ** attempt to change the bindings of an intarray while it is in the middle ** of a query. ** ** The array that holds the integers is automatically freed by the function ** in the fourth parameter to sqlite3_intarray_bind() when the array is no ** longer needed. The application must not change the intarray values ** while an intarray is in the middle of a query. ** ** The intarray object is automatically destroyed when its corresponding ** virtual table is dropped. Since the virtual tables are created in the ** TEMP database, they are automatically dropped when the database connection ** closes so the application does not normally need to take any special ** action to free the intarray objects. */ #include "sqlite3.h" /* ** An sqlite3_intarray is an abstract type to stores an instance of ** an integer array. */ typedef struct sqlite3_intarray sqlite3_intarray; /* ** Invoke this routine to create a specific instance of an intarray object. ** The new intarray object is returned by the 3rd parameter. ** ** Each intarray object corresponds to a virtual table in the TEMP table ** with a name of zName. ** ** Destroy the intarray object by dropping the virtual table. If not done ** explicitly by the application, the virtual table will be dropped implicitly ** by the system when the database connection is closed. */ int sqlite3_intarray_create( sqlite3 *db, const char *zName, sqlite3_intarray **ppReturn ); /* ** Bind a new array array of integers to a specific intarray object. ** ** The array of integers bound must be unchanged for the duration of ** any query against the corresponding virtual table. If the integer ** array does change or is deallocated undefined behavior will result. */ int sqlite3_intarray_bind( sqlite3_intarray *pIntArray, /* The intarray object to bind to */ int nElements, /* Number of elements in the intarray */ sqlite3_int64 *aElements, /* Content of the intarray */ void (*xFree)(void*) /* How to dispose of the intarray when done */ ); |
Changes to src/test_journal.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ****************************************************************************** ** ** This file contains code for a VFS layer that acts as a wrapper around ** an existing VFS. The code in this file attempts to verify that SQLite ** correctly populates and syncs a journal file before writing to a ** corresponding database file. | < < | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** ****************************************************************************** ** ** This file contains code for a VFS layer that acts as a wrapper around ** an existing VFS. The code in this file attempts to verify that SQLite ** correctly populates and syncs a journal file before writing to a ** corresponding database file. */ #if SQLITE_TEST /* This file is used for testing only */ #include "sqlite3.h" #include "sqliteInt.h" /* |
︙ | ︙ |
Changes to src/test_loadext.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 2006 June 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. ** ************************************************************************* ** Test extension for testing the sqlite3_load_extension() function. | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2006 June 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. ** ************************************************************************* ** Test extension for testing the sqlite3_load_extension() function. */ #include <string.h> #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 /* ** The half() SQL function returns half of its input value. |
︙ | ︙ |
Changes to src/test_malloc.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 code used to implement test interfaces to the ** memory allocation subsystem. | < < | 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. ** ************************************************************************* ** ** This file contains code used to implement test interfaces to the ** memory allocation subsystem. */ #include "sqliteInt.h" #include "tcl.h" #include <stdlib.h> #include <string.h> #include <assert.h> |
︙ | ︙ | |||
1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 | if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){ return TCL_ERROR; } rc = faultsimInstall(isInstall); Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); return TCL_OK; } /* ** Register commands with the TCL interpreter. */ int Sqlitetest_malloc_Init(Tcl_Interp *interp){ static struct { char *zName; | > > > > > > > > > > > > > > > > > > | 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 | if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[1], &isInstall) ){ return TCL_ERROR; } rc = faultsimInstall(isInstall); Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); return TCL_OK; } /* ** sqlite3_install_memsys3 */ static int test_install_memsys3( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int rc = SQLITE_MISUSE; #ifdef SQLITE_ENABLE_MEMSYS3 const sqlite3_mem_methods *sqlite3MemGetMemsys3(void); rc = sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetMemsys3()); #endif Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); return TCL_OK; } /* ** Register commands with the TCL interpreter. */ int Sqlitetest_malloc_Init(Tcl_Interp *interp){ static struct { char *zName; |
︙ | ︙ | |||
1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 | { "sqlite3_config_heap", test_config_heap ,0 }, { "sqlite3_config_memstatus", test_config_memstatus ,0 }, { "sqlite3_config_lookaside", test_config_lookaside ,0 }, { "sqlite3_config_error", test_config_error ,0 }, { "sqlite3_db_config_lookaside",test_db_config_lookaside ,0 }, { "sqlite3_dump_memsys3", test_dump_memsys3 ,3 }, { "sqlite3_dump_memsys5", test_dump_memsys3 ,5 }, }; int i; for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ ClientData c = (ClientData)aObjCmd[i].clientData; Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, c, 0); } return TCL_OK; } #endif | > | 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 | { "sqlite3_config_heap", test_config_heap ,0 }, { "sqlite3_config_memstatus", test_config_memstatus ,0 }, { "sqlite3_config_lookaside", test_config_lookaside ,0 }, { "sqlite3_config_error", test_config_error ,0 }, { "sqlite3_db_config_lookaside",test_db_config_lookaside ,0 }, { "sqlite3_dump_memsys3", test_dump_memsys3 ,3 }, { "sqlite3_dump_memsys5", test_dump_memsys3 ,5 }, { "sqlite3_install_memsys3", test_install_memsys3 ,0 }, }; int i; for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ ClientData c = (ClientData)aObjCmd[i].clientData; Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, c, 0); } return TCL_OK; } #endif |
Deleted src/test_md5.c.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/test_mutex.c.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2008 June 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. ** ************************************************************************* | < | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2008 June 18 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains test logic for the sqlite3_mutex interfaces. */ #include "tcl.h" #include "sqlite3.h" #include "sqliteInt.h" #include <stdlib.h> #include <assert.h> |
︙ | ︙ |
Changes to src/test_onefile.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 2007 September 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 | /* ** 2007 September 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. ** ************************************************************************* ** ** OVERVIEW: ** ** This file contains some example code demonstrating how the SQLite ** vfs feature can be used to have SQLite operate directly on an ** embedded media, without using an intermediate file system. ** ** Because this is only a demo designed to run on a workstation, the |
︙ | ︙ |
Changes to src/test_osinst.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains the implementation of an SQLite vfs wrapper that ** adds instrumentation to all vfs and file methods. C and Tcl interfaces ** are provided to control the instrumentation. | < < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This file contains the implementation of an SQLite vfs wrapper that ** adds instrumentation to all vfs and file methods. C and Tcl interfaces ** are provided to control the instrumentation. */ #ifdef SQLITE_ENABLE_INSTVFS /* ** C interface: ** ** sqlite3_instvfs_create() |
︙ | ︙ |
Changes to src/test_pcache.c.
︙ | ︙ | |||
16 17 18 19 20 21 22 | ** This file contains an application-defined pager cache ** implementation that can be plugged in in place of the ** default pcache. This alternative pager cache will throw ** some errors that the default cache does not. ** ** This pagecache implementation is designed for simplicity ** not speed. | < < | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | ** This file contains an application-defined pager cache ** implementation that can be plugged in in place of the ** default pcache. This alternative pager cache will throw ** some errors that the default cache does not. ** ** This pagecache implementation is designed for simplicity ** not speed. */ #include "sqlite3.h" #include <string.h> #include <assert.h> /* ** Global data used by this test implementation. There is no |
︙ | ︙ |
Changes to src/test_schema.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. ** ************************************************************************* ** Code for testing the virtual table interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. | < < | 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. ** ************************************************************************* ** Code for testing the virtual table interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. */ /* The code in this file defines a sqlite3 virtual-table module that ** provides a read-only view of the current database schema. There is one ** row in the schema table for each column in the database schema. */ #define SCHEMA \ |
︙ | ︙ |
Changes to src/test_server.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 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. ** ****************************************************************************** ** | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 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 |
︙ | ︙ |
Changes to src/test_tclvar.c.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ************************************************************************* ** Code for testing the virtual table interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** ** The emphasis of this file is a virtual table that provides ** access to TCL variables. | < < | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ************************************************************************* ** Code for testing the virtual table interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** ** The emphasis of this file is a virtual table that provides ** access to TCL variables. */ #include "sqliteInt.h" #include "tcl.h" #include <stdlib.h> #include <string.h> #ifndef SQLITE_OMIT_VIRTUALTABLE |
︙ | ︙ |
Changes to src/test_thread.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains the implementation of some Tcl commands used to ** test that sqlite3 database handles may be concurrently accessed by ** multiple threads. Right now this only works on unix. | < < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains the implementation of some Tcl commands used to ** test that sqlite3 database handles may be concurrently accessed by ** multiple threads. Right now this only works on unix. */ #include "sqliteInt.h" #include <tcl.h> #if SQLITE_THREADSAFE |
︙ | ︙ |
Changes to src/test_wsd.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** The code in this file contains sample implementations of the ** sqlite3_wsd_init() and sqlite3_wsd_find() functions required if the ** SQLITE_OMIT_WSD symbol is defined at build time. | < < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** The code in this file contains sample implementations of the ** sqlite3_wsd_init() and sqlite3_wsd_find() functions required if the ** SQLITE_OMIT_WSD symbol is defined at build time. */ #if defined(SQLITE_OMIT_WSD) && defined(SQLITE_TEST) #include "sqliteInt.h" #define PLS_HASHSIZE 43 |
︙ | ︙ |
Changes to src/tokenize.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** An tokenizer for SQL ** ** This file contains C code that splits an SQL input string up into ** individual tokens and sends those tokens one-by-one over to the ** parser for analysis. | < < | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** ************************************************************************* ** An tokenizer for SQL ** ** This file contains C code that splits an SQL input string up into ** individual tokens and sends those tokens one-by-one over to the ** parser for analysis. */ #include "sqliteInt.h" #include <stdlib.h> /* ** The charMap() macro maps alphabetic characters into their ** lower-case ASCII equivalent. On ASCII machines, this is just |
︙ | ︙ | |||
406 407 408 409 410 411 412 | mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH]; if( db->activeVdbeCnt==0 ){ db->u1.isInterrupted = 0; } pParse->rc = SQLITE_OK; | | | 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 | mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH]; if( db->activeVdbeCnt==0 ){ db->u1.isInterrupted = 0; } pParse->rc = SQLITE_OK; pParse->zTail = zSql; i = 0; assert( pzErrMsg!=0 ); pEngine = sqlite3ParserAlloc((void*(*)(size_t))sqlite3Malloc); if( pEngine==0 ){ db->mallocFailed = 1; return SQLITE_NOMEM; } |
︙ | ︙ |
Changes to src/trigger.c.
1 2 3 4 5 6 7 8 9 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. ** ************************************************************************* | | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | /* ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the implementation for TRIGGERs */ #include "sqliteInt.h" #ifndef SQLITE_OMIT_TRIGGER /* ** Delete a linked list of TriggerStep structures. */ |
︙ | ︙ | |||
45 46 47 48 49 50 51 52 53 54 55 56 57 58 | ** 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( pTmpSchema!=pTab->pSchema ){ HashElem *p; 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) | > > > > | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | ** 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; 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) |
︙ | ︙ | |||
82 83 84 85 86 87 88 | int op, /* One of TK_INSERT, TK_UPDATE, TK_DELETE */ IdList *pColumns, /* column list if this is an UPDATE OF trigger */ SrcList *pTableName,/* The name of the table/view the trigger applies to */ Expr *pWhen, /* WHEN clause */ int isTemp, /* True if the TEMPORARY keyword is present */ int noErr /* Suppress errors if the trigger already exists */ ){ | | | | | | | 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | int op, /* One of TK_INSERT, TK_UPDATE, TK_DELETE */ IdList *pColumns, /* column list if this is an UPDATE OF trigger */ SrcList *pTableName,/* The name of the table/view the trigger applies to */ Expr *pWhen, /* WHEN clause */ int isTemp, /* True if the TEMPORARY keyword is present */ int noErr /* Suppress errors if the trigger already exists */ ){ Trigger *pTrigger = 0; /* The new trigger */ Table *pTab; /* Table that the trigger fires off of */ char *zName = 0; /* Name of the trigger */ sqlite3 *db = pParse->db; /* The database connection */ int iDb; /* The database to store the trigger in */ Token *pName; /* The unqualified db name */ DbFixer sFix; /* State vector for the DB fixer */ int iTabDb; /* Index of the database holding pTab */ assert( pName1!=0 ); /* pName1->z might be NULL, but not pName1 itself */ assert( pName2!=0 ); assert( op==TK_INSERT || op==TK_UPDATE || op==TK_DELETE ); assert( op>0 && op<0xff ); if( isTemp ){ /* If TEMP was specified, then the trigger name may not be qualified. */ |
︙ | ︙ | |||
134 135 136 137 138 139 140 141 142 143 144 145 146 147 | if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName) && sqlite3FixSrcList(&sFix, pTableName) ){ goto trigger_cleanup; } pTab = sqlite3SrcListLookup(pParse, pTableName); if( !pTab ){ /* The table does not exist. */ goto trigger_cleanup; } if( IsVirtual(pTab) ){ sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables"); goto trigger_cleanup; } | > > > > > > > > > > > | 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 | if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", pName) && 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; } |
︙ | ︙ | |||
204 205 206 207 208 209 210 | if (tr_tm == TK_INSTEAD){ tr_tm = TK_BEFORE; } /* Build the Trigger object */ pTrigger = (Trigger*)sqlite3DbMallocZero(db, sizeof(Trigger)); if( pTrigger==0 ) goto trigger_cleanup; | | | 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | if (tr_tm == TK_INSTEAD){ tr_tm = TK_BEFORE; } /* Build the Trigger object */ pTrigger = (Trigger*)sqlite3DbMallocZero(db, sizeof(Trigger)); if( pTrigger==0 ) goto trigger_cleanup; pTrigger->zName = zName; zName = 0; pTrigger->table = sqlite3DbStrDup(db, pTableName->a[0].zName); pTrigger->pSchema = db->aDb[iDb].pSchema; pTrigger->pTabSchema = pTab->pSchema; pTrigger->op = (u8)op; pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER; pTrigger->pWhen = sqlite3ExprDup(db, pWhen, EXPRDUP_REDUCE); |
︙ | ︙ | |||
247 248 249 250 251 252 253 | DbFixer sFix; int iDb; /* Database containing the trigger */ Token nameToken; /* Trigger name for error reporting */ pTrig = pParse->pNewTrigger; pParse->pNewTrigger = 0; if( NEVER(pParse->nErr) || !pTrig ) goto triggerfinish_cleanup; | | | | 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 | DbFixer sFix; int iDb; /* Database containing the trigger */ Token nameToken; /* Trigger name for error reporting */ pTrig = pParse->pNewTrigger; pParse->pNewTrigger = 0; if( NEVER(pParse->nErr) || !pTrig ) goto triggerfinish_cleanup; zName = pTrig->zName; iDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema); pTrig->step_list = pStepList; while( pStepList ){ pStepList->pTrig = pTrig; pStepList = pStepList->pNext; } nameToken.z = pTrig->zName; nameToken.n = sqlite3Strlen30(nameToken.z); if( sqlite3FixInit(&sFix, pParse, iDb, "trigger", &nameToken) && sqlite3FixTriggerStep(&sFix, pTrig->step_list) ){ goto triggerfinish_cleanup; } /* if we are not initializing, and this trigger is not on a TEMP table, |
︙ | ︙ | |||
333 334 335 336 337 338 339 | ** Allocate space to hold a new trigger step. The allocated space ** holds both the TriggerStep object and the TriggerStep.target.z string. ** ** If an OOM error occurs, NULL is returned and db->mallocFailed is set. */ static TriggerStep *triggerStepAllocate( sqlite3 *db, /* Database connection */ | | | 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 | ** Allocate space to hold a new trigger step. The allocated space ** holds both the TriggerStep object and the TriggerStep.target.z string. ** ** If an OOM error occurs, NULL is returned and db->mallocFailed is set. */ static TriggerStep *triggerStepAllocate( sqlite3 *db, /* Database connection */ u8 op, /* Trigger opcode */ Token *pName /* The target name */ ){ TriggerStep *pTriggerStep; pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep) + pName->n); if( pTriggerStep ){ char *z = (char*)&pTriggerStep[1]; |
︙ | ︙ | |||
362 363 364 365 366 367 368 | */ TriggerStep *sqlite3TriggerInsertStep( sqlite3 *db, /* The database connection */ Token *pTableName, /* Name of the table into which we insert */ IdList *pColumn, /* List of columns in pTableName to insert into */ ExprList *pEList, /* The VALUE clause: a list of values to be inserted */ Select *pSelect, /* A SELECT statement that supplies values */ | | | 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 | */ TriggerStep *sqlite3TriggerInsertStep( sqlite3 *db, /* The database connection */ Token *pTableName, /* Name of the table into which we insert */ IdList *pColumn, /* List of columns in pTableName to insert into */ ExprList *pEList, /* The VALUE clause: a list of values to be inserted */ Select *pSelect, /* A SELECT statement that supplies values */ u8 orconf /* The conflict algorithm (OE_Abort, OE_Replace, etc.) */ ){ TriggerStep *pTriggerStep; assert(pEList == 0 || pSelect == 0); assert(pEList != 0 || pSelect != 0 || db->mallocFailed); pTriggerStep = triggerStepAllocate(db, TK_INSERT, pTableName); |
︙ | ︙ | |||
394 395 396 397 398 399 400 | ** sees an UPDATE statement inside the body of a CREATE TRIGGER. */ TriggerStep *sqlite3TriggerUpdateStep( sqlite3 *db, /* The database connection */ 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 */ | | | 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 | ** sees an UPDATE statement inside the body of a CREATE TRIGGER. */ TriggerStep *sqlite3TriggerUpdateStep( sqlite3 *db, /* The database connection */ 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) */ ){ TriggerStep *pTriggerStep; pTriggerStep = triggerStepAllocate(db, TK_UPDATE, pTableName); if( pTriggerStep ){ pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE); pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE); |
︙ | ︙ | |||
436 437 438 439 440 441 442 | /* ** Recursively delete a Trigger structure */ void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){ if( pTrigger==0 ) return; sqlite3DeleteTriggerStep(db, pTrigger->step_list); | | | 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 | /* ** 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); } /* |
︙ | ︙ | |||
516 517 518 519 520 521 522 | assert( pTable->pSchema==pTrigger->pSchema || iDb==1 ); #ifndef SQLITE_OMIT_AUTHORIZATION { int code = SQLITE_DROP_TRIGGER; const char *zDb = db->aDb[iDb].zName; const char *zTab = SCHEMA_TABLE(iDb); if( iDb==1 ) code = SQLITE_DROP_TEMP_TRIGGER; | | | 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 | assert( pTable->pSchema==pTrigger->pSchema || iDb==1 ); #ifndef SQLITE_OMIT_AUTHORIZATION { int code = SQLITE_DROP_TRIGGER; const char *zDb = db->aDb[iDb].zName; 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. |
︙ | ︙ | |||
543 544 545 546 547 548 549 | { OP_Delete, 0, 0, 0}, { OP_Next, 0, ADDR(1), 0}, /* 8 */ }; sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3OpenMasterTable(pParse, iDb); base = sqlite3VdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger); | | | | 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 | { OP_Delete, 0, 0, 0}, { OP_Next, 0, ADDR(1), 0}, /* 8 */ }; sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3OpenMasterTable(pParse, iDb); base = sqlite3VdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger); sqlite3VdbeChangeP4(v, base+1, pTrigger->zName, 0); sqlite3VdbeChangeP4(v, base+4, "trigger", P4_STATIC); sqlite3ChangeCookie(pParse, iDb); sqlite3VdbeAddOp2(v, OP_Close, 0, 0); sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->zName, 0); if( pParse->nMem<3 ){ pParse->nMem = 3; } } } /* |
︙ | ︙ | |||
651 652 653 654 655 656 657 | pSrc->a[pSrc->nSrc-1].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName); } } return pSrc; } /* | | | | | < > | < | > > > > | < > > > > > > > > | | | < < < | > | | < > > < < < | > | | | < > > < < < | > | < > | < < | | | | | < | > | < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | > < | > < | | | > < | > | > | > > > > > < > | > | < < > | > > > > > > | | < | < < | < < < < | < | | < < | > < | | | | < < < | < < < < < | < | | > | > > | > | < > > > > > > > | | < > | < < < < < | | > | < | | | < > | < | < | < < < < < | | < | | > > > | < < < | < | | < < | > | 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 | pSrc->a[pSrc->nSrc-1].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName); } } return pSrc; } /* ** Generate VDBE code for the statements inside the body of a single ** trigger. */ static int codeTriggerProgram( Parse *pParse, /* The parser context */ TriggerStep *pStepList, /* List of statements inside the trigger body */ int orconf /* Conflict algorithm. (OE_Abort, etc) */ ){ TriggerStep *pStep; Vdbe *v = pParse->pVdbe; sqlite3 *db = pParse->db; assert( pParse->pTriggerTab && pParse->pToplevel ); assert( pStepList ); assert( v!=0 ); for(pStep=pStepList; pStep; pStep=pStep->pNext){ /* Figure out the ON CONFLICT policy that will be used for this step ** of the trigger program. If the statement that caused this trigger ** to fire had an explicit ON CONFLICT, then use it. Otherwise, use ** the ON CONFLICT policy that was specified as part of the trigger ** step statement. Example: ** ** CREATE TRIGGER AFTER INSERT ON t1 BEGIN; ** INSERT OR REPLACE INTO t2 VALUES(new.a, new.b); ** END; ** ** INSERT INTO t1 ... ; -- insert into t2 uses REPLACE policy ** INSERT OR IGNORE INTO t1 ... ; -- insert into t2 uses IGNORE policy */ pParse->eOrconf = (orconf==OE_Default)?pStep->orconf:(u8)orconf; switch( pStep->op ){ case TK_UPDATE: { sqlite3Update(pParse, targetSrcList(pParse, pStep), sqlite3ExprListDup(db, pStep->pExprList, 0), sqlite3ExprDup(db, pStep->pWhere, 0), pParse->eOrconf ); break; } case TK_INSERT: { sqlite3Insert(pParse, targetSrcList(pParse, pStep), sqlite3ExprListDup(db, pStep->pExprList, 0), sqlite3SelectDup(db, pStep->pSelect, 0), sqlite3IdListDup(db, pStep->pIdList), pParse->eOrconf ); break; } case TK_DELETE: { sqlite3DeleteFrom(pParse, targetSrcList(pParse, pStep), sqlite3ExprDup(db, pStep->pWhere, 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_DEBUG /* ** This function is used to add VdbeComment() annotations to a VDBE ** program. It is not used in production code, only for debugging. */ static const char *onErrorText(int onError){ switch( onError ){ case OE_Abort: return "abort"; case OE_Rollback: return "rollback"; case OE_Fail: return "fail"; case OE_Replace: return "replace"; case OE_Ignore: return "ignore"; case OE_Default: return "default"; } return "n/a"; } #endif /* ** Parse context structure pFrom has just been used to create a sub-vdbe ** (trigger program). If an error has occurred, transfer error information ** from pFrom to pTo. */ static void transferParseError(Parse *pTo, Parse *pFrom){ assert( pFrom->zErrMsg==0 || pFrom->nErr ); assert( pTo->zErrMsg==0 || pTo->nErr ); if( pTo->nErr==0 ){ pTo->zErrMsg = pFrom->zErrMsg; pTo->nErr = pFrom->nErr; }else{ sqlite3DbFree(pFrom->db, pFrom->zErrMsg); } } /* ** Create and populate a new TriggerPrg object with a sub-program ** implementing trigger pTrigger with ON CONFLICT policy orconf. */ static TriggerPrg *codeRowTrigger( Parse *pParse, /* Current parse context */ Trigger *pTrigger, /* Trigger to code */ Table *pTab, /* The table pTrigger is attached to */ int orconf /* ON CONFLICT policy to code trigger program with */ ){ 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) ); /* 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. */ pPrg = sqlite3DbMallocZero(db, sizeof(TriggerPrg)); if( !pPrg ) return 0; pPrg->pNext = pTop->pTriggerPrg; pTop->pTriggerPrg = pPrg; pPrg->pProgram = pProgram = sqlite3DbMallocZero(db, sizeof(SubProgram)); if( !pProgram ) return 0; pProgram->nRef = 1; pPrg->pTrigger = pTrigger; pPrg->orconf = orconf; pPrg->oldmask = 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; 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" : ""), pTab->zName )); #ifndef SQLITE_OMIT_TRACE sqlite3VdbeChangeP4(v, -1, sqlite3MPrintf(db, "-- TRIGGER %s", pTrigger->zName), P4_DYNAMIC ); #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(v); 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 ){ pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pTop->nMaxArg); } pProgram->nMem = pSubParse->nMem; pProgram->nCsr = pSubParse->nTab; pProgram->token = (void *)pTrigger; pPrg->oldmask = pSubParse->oldmask; sqlite3VdbeDelete(v); } assert( !pSubParse->pAinc && !pSubParse->pZombieTab ); assert( !pSubParse->pTriggerPrg && !pSubParse->nMaxArg ); 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 ** being returned. */ static TriggerPrg *getRowTrigger( Parse *pParse, /* Current parse context */ Trigger *pTrigger, /* Trigger to code */ Table *pTab, /* The table trigger pTrigger is attached to */ int orconf /* ON CONFLICT algorithm. */ ){ Parse *pRoot = sqlite3ParseToplevel(pParse); TriggerPrg *pPrg; assert( pTrigger->zName==0 || pTab==tableOfTrigger(pTrigger) ); /* It may be that this trigger has already been coded (or is in the ** process of being coded). If this is the case, then an entry with ** a matching TriggerPrg.pTrigger field will be present somewhere ** in the Parse.pTriggerPrg list. Search for such an entry. */ for(pPrg=pRoot->pTriggerPrg; 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 ** table pTab. The reg, orconf and ignoreJump parameters passed to this ** function are the same as those described in the header function for ** sqlite3CodeRowTrigger() */ void sqlite3CodeRowTriggerDirect( Parse *pParse, /* Parse context */ Trigger *p, /* Trigger to code */ Table *pTab, /* The table to code triggers from */ 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 ){ sqlite3VdbeAddOp3(v, OP_Program, reg, ignoreJump, ++pParse->nMem); pPrg->pProgram->nRef++; sqlite3VdbeChangeP4(v, -1, (const char *)pPrg->pProgram, P4_SUBPROGRAM); VdbeComment( (v, "Call: %s.%s", (p->zName?p->zName:"fkey"), onErrorText(orconf))); /* Set the P5 operand of the OP_Program instruction to non-zero if ** recursive invocation of this trigger program is disallowed. Recursive ** invocation is disallowed if (a) the sub-program is really a trigger, ** not a foreign key action, and (b) the flag to enable recursive triggers ** is clear. */ sqlite3VdbeChangeP5(v, (u8)(p->zName && !(pParse->db->flags&SQLITE_RecTriggers))); } } /* ** This is called to code the required FOR EACH ROW triggers for an operation ** on table pTab. The operation to code triggers for (INSERT, UPDATE or DELETE) ** is given by the op paramater. The tr_tm parameter determines whether the ** BEFORE or AFTER triggers are coded. If the operation is an UPDATE, then ** parameter pChanges is passed the list of columns being modified. ** ** If there are no triggers that fire at the specified time for the specified ** operation on pTab, this function is a no-op. ** ** The reg argument is the address of the first in an array of registers ** that contain the values substituted for the new.* and old.* references ** in the trigger program. If N is the number of columns in table pTab ** (a copy of pTab->nCol), then registers are populated as follows: ** ** 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 ** are never accessed, and so are not allocated by the caller. So, for an ** ON INSERT trigger, the value passed to this function as parameter reg ** is not a readable register, although registers (reg+N) through ** (reg+N+N+1) are. ** ** Parameter orconf is the default conflict resolution algorithm for the ** trigger program to use (REPLACE, IGNORE etc.). Parameter ignoreJump ** is the instruction that control should jump to if a trigger program ** raises an IGNORE exception. */ void sqlite3CodeRowTrigger( Parse *pParse, /* Parse context */ Trigger *pTrigger, /* List of triggers on table pTab */ int op, /* One of TK_UPDATE, TK_INSERT, TK_DELETE */ ExprList *pChanges, /* Changes list for any UPDATE OF triggers */ int tr_tm, /* One of TRIGGER_BEFORE, TRIGGER_AFTER */ Table *pTab, /* The table to code triggers from */ int reg, /* The first in an array of registers (see above) */ int orconf, /* ON CONFLICT policy */ int ignoreJump /* Instruction to jump to for RAISE(IGNORE) */ ){ Trigger *p; /* Used to iterate through pTrigger list */ assert( op==TK_UPDATE || op==TK_INSERT || op==TK_DELETE ); assert( tr_tm==TRIGGER_BEFORE || tr_tm==TRIGGER_AFTER ); assert( (op==TK_UPDATE)==(pChanges!=0) ); for(p=pTrigger; p; p=p->pNext){ /* Sanity checking: The schema for the trigger and for the table are ** 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 fired by UPDATE or DELETE statements may access values stored ** in the old.* pseudo-table. This function returns a 32-bit bitmask ** indicating which columns of the old.* table actually are used by ** triggers. This information may be used by the caller to avoid having ** to load the entire old.* record into memory when executing an UPDATE ** or DELETE command. ** ** Bit 0 of the returned mask is set if the left-most column of the ** table may be accessed using an old.<col> reference. Bit 1 is set if ** the second leftmost column value is required, and so on. If there ** are more than 32 columns in the table, and at least one of the columns ** with an index greater than 32 may be accessed, 0xffffffff is returned. ** ** It is not possible to determine if the old.rowid column is accessed ** by triggers. The caller must always assume that it is. ** ** There is no equivalent function for new.* references. */ u32 sqlite3TriggerOldmask( Parse *pParse, /* Parse context */ Trigger *pTrigger, /* List of triggers on table pTab */ ExprList *pChanges, /* Changes list for any UPDATE OF triggers */ Table *pTab, /* The table to code triggers from */ int orconf /* Default ON CONFLICT policy for trigger steps */ ){ const int op = pChanges ? TK_UPDATE : TK_DELETE; u32 mask = 0; Trigger *p; for(p=pTrigger; p; p=p->pNext){ if( p->op==op && checkColumnOverlap(p->pColumns,pChanges) ){ TriggerPrg *pPrg; pPrg = getRowTrigger(pParse, p, pTab, orconf); if( pPrg ){ mask |= pPrg->oldmask; } } } return mask; } #endif /* !defined(SQLITE_OMIT_TRIGGER) */ |
Changes to src/update.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. | < < | 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 contains C code routines that are called by the parser ** to handle UPDATE statements. */ #include "sqliteInt.h" #ifndef SQLITE_OMIT_VIRTUALTABLE /* Forward declaration */ static void updateVirtualTable( Parse *pParse, /* The parsing context */ |
︙ | ︙ | |||
49 50 51 52 53 54 55 56 | ** 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. */ | > > > > > | > > > > > | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | ** 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; 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 ){ sqlite3VdbeChangeP4(v, -1, (const char *)pValue, P4_MEM); } #ifndef SQLITE_OMIT_FLOATING_POINT if( iReg>=0 && pTab->aCol[i].affinity==SQLITE_AFF_REAL ){ sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg); } #endif } } /* ** Process an UPDATE statement. ** ** UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL; |
︙ | ︙ | |||
101 102 103 104 105 106 107 108 109 110 111 112 | Expr *pRowidExpr = 0; /* Expression defining the new record number */ int openAll = 0; /* True if all indices need to be opened */ AuthContext sContext; /* The authorization context */ NameContext sNC; /* The name-context to resolve expressions in */ int iDb; /* Database containing the table being updated */ int j1; /* Addresses of jump instructions */ int okOnePass; /* True for one-pass algorithm without the FIFO */ #ifndef SQLITE_OMIT_TRIGGER int isView; /* Trying to update a view */ Trigger *pTrigger; /* List of triggers on pTab, if required */ #endif | > < < < < < < < < < | > > | | | | < < < < < < < < | 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 | Expr *pRowidExpr = 0; /* Expression defining the new record number */ int openAll = 0; /* True if all indices need to be opened */ AuthContext sContext; /* The authorization context */ NameContext sNC; /* The name-context to resolve expressions in */ int iDb; /* Database containing the table being updated */ int j1; /* Addresses of jump instructions */ int okOnePass; /* True for one-pass algorithm without the FIFO */ int hasFK; /* True if foreign key processing is required */ #ifndef SQLITE_OMIT_TRIGGER int isView; /* Trying to update a view */ Trigger *pTrigger; /* List of triggers on pTab, if required */ #endif /* Register Allocations */ int regRowCount = 0; /* A count of rows changed */ int regOldRowid; /* The old rowid */ int regNewRowid; /* The new rowid */ int regNew; int regOld = 0; int regRowSet = 0; /* Rowset of rows to be updated */ int regRec; /* Register used for new table record to insert */ 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, 0); isView = pTab->pSelect!=0; #else # define pTrigger 0 # define isView 0 #endif #ifdef SQLITE_OMIT_VIEW # undef isView # define isView 0 #endif if( sqlite3ViewGetColumnNames(pParse, pTab) ){ goto update_cleanup; } if( sqlite3IsReadOnly(pParse, pTab, (pTrigger?1:0)) ){ goto update_cleanup; } aXRef = sqlite3DbMallocRaw(db, sizeof(int) * pTab->nCol ); if( aXRef==0 ) goto update_cleanup; for(i=0; i<pTab->nCol; i++) aXRef[i] = -1; /* Allocate a cursors for the main database table and for all indices. ** The index cursors might not be used, but if they are used they ** need to occur right after the database cursor. So go ahead and ** allocate enough space, just in case. */ pTabList->a[0].iCursor = iCur = pParse->nTab++; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ |
︙ | ︙ | |||
227 228 229 230 231 232 233 234 235 236 237 238 239 240 | goto update_cleanup; }else if( rc==SQLITE_IGNORE ){ aXRef[j] = -1; } } #endif } /* Allocate memory for the array aRegIdx[]. There is one entry in the ** array for each index associated with table being updated. Fill in ** the value with a register number for indices that are to be used ** and with zero for unused indices. */ for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){} | > > | 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | goto update_cleanup; }else if( rc==SQLITE_IGNORE ){ aXRef[j] = -1; } } #endif } hasFK = sqlite3FkRequired(pParse, pTab, aXRef, chngRowid); /* Allocate memory for the array aRegIdx[]. There is one entry in the ** array for each index associated with table being updated. Fill in ** the value with a register number for indices that are to be used ** and with zero for unused indices. */ for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){} |
︙ | ︙ | |||
254 255 256 257 258 259 260 | break; } } } aRegIdx[j] = reg; } | < < < < < < < < < < < < < < < < | < | < < < < | < < | < | < < | < | < < | | < < < | < < | | < < > | < > > | | 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 | break; } } } aRegIdx[j] = reg; } /* Begin generating code. */ v = sqlite3GetVdbe(pParse); if( v==0 ) goto update_cleanup; if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); sqlite3BeginWriteOperation(pParse, 1, iDb); #ifndef SQLITE_OMIT_VIRTUALTABLE /* Virtual tables must be handled separately */ if( IsVirtual(pTab) ){ updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef, pWhere); pWhere = 0; pTabList = 0; goto update_cleanup; } #endif /* Allocate required registers. */ regOldRowid = regNewRowid = ++pParse->nMem; if( pTrigger || hasFK ){ regOld = pParse->nMem + 1; pParse->nMem += pTab->nCol; } if( chngRowid || pTrigger || hasFK ){ regNewRowid = ++pParse->nMem; } regNew = pParse->nMem + 1; pParse->nMem += pTab->nCol; regRec = ++pParse->nMem; /* Start the view context. */ if( isView ){ sqlite3AuthContextPush(pParse, &sContext, pTab->zName); } /* If we are trying to update a view, realize that view into ** a ephemeral table. */ #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) if( isView ){ sqlite3MaterializeView(pParse, pTab, pWhere, iCur); } |
︙ | ︙ | |||
360 361 362 363 364 365 366 | /* End the database scan loop. */ sqlite3WhereEnd(pWInfo); /* Initialize the count of updated rows */ | | | 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 | /* End the database scan loop. */ sqlite3WhereEnd(pWInfo); /* Initialize the count of updated rows */ if( (db->flags & SQLITE_CountRows) && !pParse->pTriggerTab ){ regRowCount = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount); } if( !isView ){ /* ** Open every index that needs updating. Note that if any |
︙ | ︙ | |||
393 394 395 396 397 398 399 | KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); sqlite3VdbeAddOp4(v, OP_OpenWrite, iCur+i+1, pIdx->tnum, iDb, (char*)pKey, P4_KEYINFO_HANDOFF); assert( pParse->nTab>iCur+i+1 ); } } } | < < < < < < < < < < | < < | < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | > | < > | | | | | > > > > > > > > > > > > > > > > | > > > > | | | < | | | | | > > > > > > > > > > > > > > > > > > > | < < | | > > > | > | | < | > > > > | < | | > > > > > > | < < < | < < < > < < < < | | > > > > > > > > > | 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 | KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); sqlite3VdbeAddOp4(v, OP_OpenWrite, iCur+i+1, pIdx->tnum, iDb, (char*)pKey, P4_KEYINFO_HANDOFF); assert( pParse->nTab>iCur+i+1 ); } } } /* Top of the update loop */ if( okOnePass ){ int a1 = sqlite3VdbeAddOp1(v, OP_NotNull, regOldRowid); addr = sqlite3VdbeAddOp0(v, OP_Goto); sqlite3VdbeJumpHere(v, a1); }else{ addr = sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowSet, 0, regOldRowid); } /* Make cursor iCur point to the record that is being updated. If ** this record does not exist for some reason (deleted by a trigger, ** for example, then jump to the next iteration of the RowSet loop. */ sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid); /* If the record number will change, set register regNewRowid to ** contain the new value. If the record number is not being modified, ** then regNewRowid is the same register as regOldRowid, which is ** already populated. */ assert( chngRowid || pTrigger || hasFK || regOldRowid==regNewRowid ); if( chngRowid ){ sqlite3ExprCode(pParse, pRowidExpr, regNewRowid); sqlite3VdbeAddOp1(v, OP_MustBeInt, regNewRowid); } /* If there are triggers on this table, populate an array of registers ** with the required old.* column data. */ if( hasFK || pTrigger ){ u32 oldmask = (hasFK ? sqlite3FkOldmask(pParse, pTab) : 0); oldmask |= sqlite3TriggerOldmask(pParse, pTrigger, pChanges, pTab, onError); for(i=0; i<pTab->nCol; i++){ if( aXRef[i]<0 || oldmask==0xffffffff || (oldmask & (1<<i)) ){ sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regOld+i); sqlite3ColumnDefault(v, pTab, i, regOld+i); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, regOld+i); } } if( chngRowid==0 ){ sqlite3VdbeAddOp2(v, OP_Copy, regOldRowid, regNewRowid); } } /* Populate the array of registers beginning at regNew with the new ** row data. This array is used to check constaints, create the new ** table and index records, and as the values for any new.* references ** made by triggers. */ 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 ){ sqlite3VdbeAddOp3(v, OP_Column, iCur, i, regNew+i); sqlite3ColumnDefault(v, pTab, i, regNew+i); }else{ sqlite3ExprCode(pParse, pChanges->a[j].pExpr, regNew+i); } } } /* Fire any BEFORE UPDATE triggers. This happens before constraints are ** verified. One could argue that this is wrong. */ if( pTrigger ){ sqlite3VdbeAddOp2(v, OP_Affinity, regNew, pTab->nCol); sqlite3TableAffinityStr(v, pTab); sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, TRIGGER_BEFORE, pTab, regOldRowid, onError, addr); /* The row-trigger may have deleted the row being updated. In this ** case, jump to the next row. No updates or AFTER triggers are ** required. This behaviour - what happens when the row being updated ** is deleted or renamed by a BEFORE trigger - is left undefined in the ** documentation. */ sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, regOldRowid); } if( !isView ){ /* Do constraint checks. */ sqlite3GenerateConstraintChecks(pParse, pTab, iCur, regNewRowid, aRegIdx, (chngRowid?regOldRowid:0), 1, onError, addr, 0); /* Do FK constraint checks. */ if( hasFK ){ sqlite3FkCheck(pParse, pTab, regOldRowid, 0); } /* Delete the index entries associated with the current record. */ j1 = sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regOldRowid); sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, aRegIdx); /* If changing the record number, delete the old record. */ if( hasFK || chngRowid ){ sqlite3VdbeAddOp2(v, OP_Delete, iCur, 0); } sqlite3VdbeJumpHere(v, j1); if( hasFK ){ sqlite3FkCheck(pParse, pTab, 0, regNewRowid); } /* Insert the new index entries and the new record. */ sqlite3CompleteInsertion(pParse, pTab, iCur, regNewRowid, aRegIdx, 1, 0, 0); /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to ** handle rows (possibly in other tables) that refer via a foreign key ** to the row just updated. */ if( hasFK ){ sqlite3FkActions(pParse, pTab, pChanges, regOldRowid); } } /* Increment the row counter */ if( (db->flags & SQLITE_CountRows) && !pParse->pTriggerTab){ sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1); } sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges, TRIGGER_AFTER, pTab, regOldRowid, onError, addr); /* Repeat the above with the next record to be updated, until ** all record selected by the WHERE clause have been updated. */ sqlite3VdbeAddOp2(v, OP_Goto, 0, addr); sqlite3VdbeJumpHere(v, addr); /* Close all tables */ for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ if( openAll || aRegIdx[i]>0 ){ sqlite3VdbeAddOp2(v, OP_Close, iCur+i+1, 0); } } sqlite3VdbeAddOp2(v, OP_Close, iCur, 0); /* 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 that were changed. If this routine is ** generating code because of a call to sqlite3NestedParse(), do not ** invoke the callback function. */ if( (db->flags&SQLITE_CountRows) && !pParse->pTriggerTab && !pParse->nested ){ sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1); sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", SQLITE_STATIC); } update_cleanup: sqlite3AuthContextPop(&sContext); sqlite3DbFree(db, aRegIdx); sqlite3DbFree(db, aXRef); sqlite3SrcListDelete(db, pTabList); sqlite3ExprListDelete(db, pChanges); sqlite3ExprDelete(db, pWhere); return; } /* Make sure "isView" and other macros defined above are undefined. Otherwise ** thely 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 #endif #ifdef pTrigger #undef pTrigger #endif #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Generate code for an UPDATE of a virtual table. ** ** The strategy is that we create an ephemerial table that contains ** for each row to be changed: |
︙ | ︙ | |||
627 628 629 630 631 632 633 | Select *pSelect = 0; /* The SELECT statement */ Expr *pExpr; /* Temporary expression */ int ephemTab; /* Table holding the result of the SELECT */ int i; /* Loop counter */ int addr; /* Address of top of loop */ int iReg; /* First register in set passed to OP_VUpdate */ sqlite3 *db = pParse->db; /* Database connection */ | | | < | | 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 | Select *pSelect = 0; /* The SELECT statement */ Expr *pExpr; /* Temporary expression */ int ephemTab; /* Table holding the result of the SELECT */ int i; /* Loop counter */ int addr; /* Address of top of loop */ int iReg; /* First register in set passed to OP_VUpdate */ sqlite3 *db = pParse->db; /* Database connection */ const char *pVTab = (const char*)sqlite3GetVTable(db, pTab); SelectDest dest; /* Construct the SELECT statement that will find the new values for ** all updated rows. */ pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ID, "_rowid_")); if( pRowid ){ pEList = sqlite3ExprListAppend(pParse, pEList, sqlite3ExprDup(db, pRowid, 0)); } assert( pTab->iPKey<0 ); for(i=0; i<pTab->nCol; i++){ if( aXRef[i]>=0 ){ pExpr = sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr, 0); }else{ pExpr = sqlite3Expr(db, TK_ID, pTab->aCol[i].zName); } pEList = sqlite3ExprListAppend(pParse, pEList, pExpr); } pSelect = sqlite3SelectNew(pParse, pEList, pSrc, pWhere, 0, 0, 0, 0, 0, 0); /* Create the ephemeral table into which the update results will ** be stored. |
︙ | ︙ | |||
672 673 674 675 676 677 678 | addr = sqlite3VdbeAddOp2(v, OP_Rewind, ephemTab, 0); sqlite3VdbeAddOp3(v, OP_Column, ephemTab, 0, iReg); sqlite3VdbeAddOp3(v, OP_Column, ephemTab, (pRowid?1:0), iReg+1); for(i=0; i<pTab->nCol; i++){ sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i+1+(pRowid!=0), iReg+2+i); } sqlite3VtabMakeWritable(pParse, pTab); | | > < < < < < | 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 | addr = sqlite3VdbeAddOp2(v, OP_Rewind, ephemTab, 0); sqlite3VdbeAddOp3(v, OP_Column, ephemTab, 0, iReg); sqlite3VdbeAddOp3(v, OP_Column, ephemTab, (pRowid?1:0), iReg+1); for(i=0; i<pTab->nCol; i++){ sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i+1+(pRowid!=0), iReg+2+i); } sqlite3VtabMakeWritable(pParse, pTab); sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab->nCol+2, iReg, pVTab, P4_VTAB); sqlite3MayAbort(pParse); sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1); sqlite3VdbeJumpHere(v, addr); sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0); /* Cleanup */ sqlite3SelectDelete(db, pSelect); } #endif /* SQLITE_OMIT_VIRTUALTABLE */ |
Changes to src/utf.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 routines used to translate between UTF-8, ** UTF-16, UTF-16BE, and UTF-16LE. ** | < < | 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. ** ************************************************************************* ** This file contains routines used to translate between UTF-8, ** UTF-16, UTF-16BE, and UTF-16LE. ** ** Notes on UTF-8: ** ** Byte-0 Byte-1 Byte-2 Byte-3 Value ** 0xxxxxxx 00000000 00000000 0xxxxxxx ** 110yyyyy 10xxxxxx 00000000 00000yyy yyxxxxxx ** 1110zzzz 10yyyyyy 10xxxxxx 00000000 zzzzyyyy yyxxxxxx ** 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx 000uuuuu zzzzyyyy yyxxxxxx |
︙ | ︙ | |||
103 104 105 106 107 108 109 | *zOut++ = (u8)(0x00D8 + (((c-0x10000)>>18)&0x03)); \ *zOut++ = (u8)(((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \ *zOut++ = (u8)(0x00DC + ((c>>8)&0x03)); \ *zOut++ = (u8)(c&0x00FF); \ } \ } | | | | | | 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | *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); \ } \ } /* |
︙ | ︙ | |||
301 302 303 304 305 306 307 | 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 ){ | | | | 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | 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 ); |
︙ | ︙ | |||
451 452 453 454 455 456 457 | } assert( (m.flags & MEM_Term)!=0 || db->mallocFailed ); assert( (m.flags & MEM_Str)!=0 || db->mallocFailed ); return (m.flags & MEM_Dyn)!=0 ? m.z : sqlite3DbStrDup(db, m.z); } /* | > > > > > > > > > > > > > > > > > > > > > > > > > > | > < < < < < < < < < | | | 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 | } assert( (m.flags & MEM_Term)!=0 || db->mallocFailed ); assert( (m.flags & MEM_Str)!=0 || db->mallocFailed ); return (m.flags & MEM_Dyn)!=0 ? m.z : sqlite3DbStrDup(db, m.z); } /* ** Convert a UTF-8 string to the UTF-16 encoding specified by parameter ** enc. A pointer to the new string is returned, and the value of *pnOut ** is set to the length of the returned string in bytes. The call should ** arrange to call sqlite3DbFree() on the returned pointer when it is ** no longer required. ** ** If a malloc failure occurs, NULL is returned and the db.mallocFailed ** flag set. */ #ifdef SQLITE_ENABLE_STAT2 char *sqlite3Utf8to16(sqlite3 *db, u8 enc, char *z, int n, int *pnOut){ Mem m; memset(&m, 0, sizeof(m)); m.db = db; sqlite3VdbeMemSetStr(&m, z, n, SQLITE_UTF8, SQLITE_STATIC); if( sqlite3VdbeMemTranslate(&m, enc) ){ assert( db->mallocFailed ); return 0; } assert( m.z==m.zMalloc ); *pnOut = m.n; return m.z; } #endif /* ** zIn is a UTF-16 encoded unicode string at least nChar characters long. ** Return the number of bytes in the first nChar unicode characters ** 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) |
︙ | ︙ | |||
517 518 519 520 521 522 523 | 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; | | | | 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 | 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.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** Utility functions used throughout sqlite. ** ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** | < | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** ************************************************************************* ** Utility functions used throughout sqlite. ** ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** */ #include "sqliteInt.h" #include <stdarg.h> #ifdef SQLITE_HAVE_ISNAN # include <math.h> #endif |
︙ | ︙ | |||
221 222 223 224 225 226 227 | int sqlite3StrICmp(const char *zLeft, const char *zRight){ register unsigned char *a, *b; a = (unsigned char *)zLeft; b = (unsigned char *)zRight; while( *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; } return UpperToLower[*a] - UpperToLower[*b]; } | | | 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | int sqlite3StrICmp(const char *zLeft, const char *zRight){ register unsigned char *a, *b; a = (unsigned char *)zLeft; b = (unsigned char *)zRight; while( *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; } return UpperToLower[*a] - UpperToLower[*b]; } int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){ register unsigned char *a, *b; 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]; } |
︙ | ︙ | |||
269 270 271 272 273 274 275 | while( sqlite3Isdigit(*z) ){ z += incr; } *realnum = 1; } return *z==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 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 | while( sqlite3Isdigit(*z) ){ z += incr; } *realnum = 1; } return *z==0; } /* ** The string z[] is an ASCII representation of a real number. ** Convert this string to a double. ** ** This routine assumes that z[] really is a valid number. If it ** is not, the result is undefined. ** ** This routine is used instead of the library atof() function because ** the library atof() might want to use "," as the decimal point instead ** of "." depending on how locale is set. But that would cause problems ** for SQL. So this routine always uses "." regardless of locale. */ int sqlite3AtoF(const char *z, double *pResult){ #ifndef SQLITE_OMIT_FLOATING_POINT const char *zBegin = z; /* 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 */ double result; int nDigits = 0; /* skip leading spaces */ while( sqlite3Isspace(*z) ) z++; /* get sign of significand */ if( *z=='-' ){ sign = -1; z++; }else if( *z=='+' ){ z++; } /* skip leading zeroes */ while( z[0]=='0' ) z++, nDigits++; /* copy max significant digits to significand */ while( sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){ s = s*10 + (*z - '0'); z++, nDigits++; } /* skip non-significant significand digits ** (increase exponent by d to shift decimal left) */ while( sqlite3Isdigit(*z) ) z++, nDigits++, d++; /* if decimal point is present */ if( *z=='.' ){ z++; /* copy digits from after decimal to significand ** (decrease exponent by d to shift decimal right) */ while( sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){ s = s*10 + (*z - '0'); z++, nDigits++, d--; } /* skip non-significant digits */ while( sqlite3Isdigit(*z) ) z++, nDigits++; } /* if exponent is present */ if( *z=='e' || *z=='E' ){ z++; /* get sign of exponent */ if( *z=='-' ){ esign = -1; z++; }else if( *z=='+' ){ z++; } /* copy digits to exponent */ while( sqlite3Isdigit(*z) ){ e = e*10 + (*z - '0'); z++; } } /* adjust exponent by d, and update sign */ e = (e*esign) + d; if( e<0 ) { esign = -1; e *= -1; } else { esign = 1; } /* if 0 significand */ if( !s ) { /* In the IEEE 754 standard, zero is signed. ** Add the sign if we've seen at least one digit */ result = (sign<0 && nDigits) ? -(double)0 : (double)0; } else { /* attempt to reduce exponent */ if( esign>0 ){ while( s<(LARGEST_INT64/10) && e>0 ) e--,s*=10; }else{ while( !(s%10) && e>0 ) e--,s/=10; } /* adjust the sign of significand */ s = sign<0 ? -s : s; /* if exponent, scale significand as appropriate ** and store in result. */ if( e ){ double scale = 1.0; /* attempt to handle extremely small/large numbers better */ if( e>307 && e<342 ){ while( e%308 ) { scale *= 1.0e+1; e -= 1; } if( esign<0 ){ result = s / scale; result /= 1.0e+308; }else{ result = s * scale; result *= 1.0e+308; } }else{ /* 1.0e+22 is the largest power of 10 than can be ** represented exactly. */ while( e%22 ) { scale *= 1.0e+1; e -= 1; } while( e>0 ) { scale *= 1.0e+22; e -= 22; } if( esign<0 ){ result = s / scale; }else{ result = s * scale; } } } else { result = (double)s; } } /* store the result */ *pResult = result; /* return number of characters used */ return (int)(z - zBegin); #else return sqlite3Atoi64(z, pResult); #endif /* SQLITE_OMIT_FLOATING_POINT */ } /* |
︙ | ︙ | |||
900 901 902 903 904 905 906 | } #if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) /* ** Translate a single byte of Hex into an integer. | | | 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 | } #if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) /* ** Translate a single byte of Hex into an integer. ** This routine only works if h really is a valid hexadecimal ** character: 0..9a..fA..F */ static u8 hexToInt(int h){ assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') ); #ifdef SQLITE_ASCII h += 9*(1&(h>>6)); #endif |
︙ | ︙ |
Changes to src/vacuum.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to implement the VACUUM command. ** ** Most of the code in this file may be omitted by defining the ** SQLITE_OMIT_VACUUM macro. | < < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to implement the VACUUM command. ** ** Most of the code in this file may be omitted by defining the ** SQLITE_OMIT_VACUUM macro. */ #include "sqliteInt.h" #include "vdbeInt.h" #if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH) /* ** Execute zSql on database db. Return an error code. |
︙ | ︙ | |||
93 94 95 96 97 98 99 | int nRes; if( !db->autoCommit ){ sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction"); return SQLITE_ERROR; } | | > > > | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | int nRes; if( !db->autoCommit ){ sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction"); return SQLITE_ERROR; } /* Save the current value of the database flags so that it can be ** restored before returning. Then set the writable-schema flag, and ** disable CHECK and foreign key constraints. */ saved_flags = db->flags; saved_nChange = db->nChange; saved_nTotalChange = db->nTotalChange; db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks; db->flags &= ~SQLITE_ForeignKeys; pMain = db->aDb[0].pBt; isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain)); /* Attach the temporary database as 'vacuum_db'. The synchronous pragma ** can be set to 'off' for this file, as it is not recovered if a crash ** occurs anyway. The integrity of the database is maintained by a |
︙ | ︙ | |||
122 123 124 125 126 127 128 129 130 131 132 133 134 135 | */ zSql = "ATTACH '' AS vacuum_db;"; rc = execSql(db, zSql); if( rc!=SQLITE_OK ) goto end_of_vacuum; pDb = &db->aDb[db->nDb-1]; assert( strcmp(db->aDb[db->nDb-1].zName,"vacuum_db")==0 ); pTemp = db->aDb[db->nDb-1].pBt; nRes = sqlite3BtreeGetReserve(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*); | > > > > > > | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | */ zSql = "ATTACH '' AS vacuum_db;"; rc = execSql(db, zSql); if( rc!=SQLITE_OK ) goto end_of_vacuum; pDb = &db->aDb[db->nDb-1]; assert( strcmp(db->aDb[db->nDb-1].zName,"vacuum_db")==0 ); pTemp = db->aDb[db->nDb-1].pBt; /* The call to execSql() to attach the temp database has left the file ** locked (as there was more than one active statement when the transaction ** to read the schema was concluded. Unlock it here so that this doesn't ** cause problems for the call to BtreeSetPageSize() below. */ sqlite3BtreeCommit(pTemp); nRes = sqlite3BtreeGetReserve(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*); |
︙ | ︙ | |||
176 177 178 179 180 181 182 | if( rc!=SQLITE_OK ) goto end_of_vacuum; rc = execExecSql(db, "SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21) " " FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'"); if( rc!=SQLITE_OK ) goto end_of_vacuum; /* Loop through the tables in the main database. For each, do | | | | | | | 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 | if( rc!=SQLITE_OK ) goto end_of_vacuum; rc = execExecSql(db, "SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21) " " FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'"); if( rc!=SQLITE_OK ) goto end_of_vacuum; /* 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 = 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" ); if( rc!=SQLITE_OK ) goto end_of_vacuum; /* Copy over the sequence table */ rc = execExecSql(db, "SELECT 'DELETE FROM vacuum_db.' || quote(name) || ';' " "FROM vacuum_db.sqlite_master WHERE name='sqlite_sequence' " ); if( rc!=SQLITE_OK ) goto end_of_vacuum; rc = execExecSql(db, "SELECT 'INSERT INTO vacuum_db.' || quote(name) " "|| ' SELECT * FROM main.' || quote(name) || ';' " "FROM vacuum_db.sqlite_master WHERE name=='sqlite_sequence';" ); 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 = 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)" ); if( rc ) goto end_of_vacuum; /* At this point, unless the main db was completely empty, there is now a ** transaction open on the vacuum database, but not on the main database. |
︙ | ︙ | |||
250 251 252 253 254 255 256 | assert( 1==sqlite3BtreeIsInTrans(pTemp) ); assert( 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. */ | | < | 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 | assert( 1==sqlite3BtreeIsInTrans(pTemp) ); assert( 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]); if( NEVER(rc!=SQLITE_OK) ) goto end_of_vacuum; } rc = sqlite3BtreeCopyFile(pMain, pTemp); if( rc!=SQLITE_OK ) goto end_of_vacuum; rc = sqlite3BtreeCommit(pTemp); |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
38 39 40 41 42 43 44 | ** a program instruction by instruction. ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. | < < | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | ** a program instruction by instruction. ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. */ #include "sqliteInt.h" #include "vdbeInt.h" /* ** The following global variable is incremented every time a cursor ** moves, either by the OP_SeekXX, OP_Next, or OP_Prev opcodes. The test |
︙ | ︙ | |||
94 95 96 97 98 99 100 101 102 103 104 105 106 107 | static void updateMaxBlobsize(Mem *p){ if( (p->flags & (MEM_Str|MEM_Blob))!=0 && p->n>sqlite3_max_blobsize ){ sqlite3_max_blobsize = p->n; } } #endif /* ** Test a register to see if it exceeds the current maximum blob size. ** If it does, record the new maximum blob size. */ #if defined(SQLITE_TEST) && !defined(SQLITE_OMIT_BUILTIN_TEST) # define UPDATE_MAX_BLOBSIZE(P) updateMaxBlobsize(P) #else | > > > > > > > > > > > | 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 | static void updateMaxBlobsize(Mem *p){ if( (p->flags & (MEM_Str|MEM_Blob))!=0 && p->n>sqlite3_max_blobsize ){ sqlite3_max_blobsize = p->n; } } #endif /* ** The next global variable is incremented each type the OP_Found opcode ** is executed. This is used to test whether or not the foreign key ** operation implemented using OP_FkIsZero is working. This variable ** has no function other than to help verify the correct operation of the ** library. */ #ifdef SQLITE_TEST int sqlite3_found_count = 0; #endif /* ** Test a register to see if it exceeds the current maximum blob size. ** If it does, record the new maximum blob size. */ #if defined(SQLITE_TEST) && !defined(SQLITE_OMIT_BUILTIN_TEST) # define UPDATE_MAX_BLOBSIZE(P) updateMaxBlobsize(P) #else |
︙ | ︙ | |||
136 137 138 139 140 141 142 | ** P if required. */ #define ExpandBlob(P) (((P)->flags&MEM_Zero)?sqlite3VdbeMemExpandBlob(P):0) /* ** Argument pMem points at a register that will be passed to a ** user-defined function or returned to the user as the result of a query. | < | | < | | 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | ** P if required. */ #define ExpandBlob(P) (((P)->flags&MEM_Zero)?sqlite3VdbeMemExpandBlob(P):0) /* ** Argument pMem points at a register that will be passed to a ** user-defined function or returned to the user as the result of a query. ** This routine sets the pMem->type variable used by the sqlite3_value_*() ** routines. */ void sqlite3VdbeMemStoreType(Mem *pMem){ int flags = pMem->flags; if( flags & MEM_Null ){ pMem->type = SQLITE_NULL; } else if( flags & MEM_Int ){ pMem->type = SQLITE_INTEGER; } |
︙ | ︙ | |||
185 186 187 188 189 190 191 | ** 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, /* When database the cursor belongs to, or -1 */ | | | 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | ** 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, /* When database the cursor belongs to, or -1 */ int isBtreeCursor /* True for B-Tree. False for pseudo-table or vtab */ ){ /* 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: ** ** * Sometimes cursor numbers are used for a couple of different |
︙ | ︙ | |||
312 313 314 315 316 317 318 | ** loss of information and return the revised type of the argument. ** ** This is an EXPERIMENTAL api and is subject to change or removal. */ int sqlite3_value_numeric_type(sqlite3_value *pVal){ Mem *pMem = (Mem*)pVal; applyNumericAffinity(pMem); | | | 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 | ** loss of information and return the revised type of the argument. ** ** This is an EXPERIMENTAL api and is subject to change or removal. */ int sqlite3_value_numeric_type(sqlite3_value *pVal){ Mem *pMem = (Mem*)pVal; applyNumericAffinity(pMem); sqlite3VdbeMemStoreType(pMem); return pMem->type; } /* ** Exported version of applyAffinity(). This one works on sqlite3_value*, ** not the internal Mem* type. */ |
︙ | ︙ | |||
696 697 698 699 700 701 702 | pIn1 = &p->aMem[pOp->p1]; REGISTER_TRACE(pOp->p1, pIn1); if( (opProperty & OPFLG_IN2)!=0 ){ assert( pOp->p2>0 ); assert( pOp->p2<=p->nMem ); pIn2 = &p->aMem[pOp->p2]; REGISTER_TRACE(pOp->p2, pIn2); | > > | | | | < | 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 | pIn1 = &p->aMem[pOp->p1]; REGISTER_TRACE(pOp->p1, pIn1); if( (opProperty & OPFLG_IN2)!=0 ){ assert( pOp->p2>0 ); assert( pOp->p2<=p->nMem ); pIn2 = &p->aMem[pOp->p2]; REGISTER_TRACE(pOp->p2, pIn2); /* As currently implemented, in2 implies out3. There is no reason ** why this has to be, it just worked out that way. */ assert( (opProperty & OPFLG_OUT3)!=0 ); assert( pOp->p3>0 ); assert( pOp->p3<=p->nMem ); pOut = &p->aMem[pOp->p3]; }else if( (opProperty & OPFLG_IN3)!=0 ){ assert( pOp->p3>0 ); assert( pOp->p3<=p->nMem ); pIn3 = &p->aMem[pOp->p3]; REGISTER_TRACE(pOp->p3, pIn3); } }else if( (opProperty & OPFLG_IN2)!=0 ){ |
︙ | ︙ | |||
842 843 844 845 846 847 848 849 | ** If P4 is not null then it is an error message string. ** ** There is an implied "Halt 0 0 0" instruction inserted at the very end of ** every program. So a jump past the last instruction of the program ** is the same as executing Halt. */ case OP_Halt: { p->rc = pOp->p1; | > > > > > > > > > > > > > > > > > > < > | > > | 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 | ** If P4 is not null then it is an error message string. ** ** There is an implied "Halt 0 0 0" instruction inserted at the very end of ** every program. So a jump past the last instruction of the program ** is the same as executing Halt. */ case OP_Halt: { if( pOp->p1==SQLITE_OK && p->pFrame ){ /* Halt the sub-program. Return control to the parent frame. */ VdbeFrame *pFrame = p->pFrame; p->pFrame = pFrame->pParent; p->nFrame--; sqlite3VdbeSetChanges(db, p->nChange); pc = sqlite3VdbeFrameRestore(pFrame); if( pOp->p2==OE_Ignore ){ /* Instruction pc is the OP_Program that invoked the sub-program ** currently being halted. If the p2 instruction of this OP_Halt ** instruction is set to OE_Ignore, then the sub-program is throwing ** an IGNORE exception. In this case jump to the address specified ** as the p2 of the calling OP_Program. */ pc = p->aOp[pc].p2-1; } break; } p->rc = pOp->p1; p->errorAction = (u8)pOp->p2; p->pc = pc; if( pOp->p4.z ){ sqlite3SetString(&p->zErrMsg, db, "%s", pOp->p4.z); } rc = sqlite3VdbeHalt(p); assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR ); if( rc==SQLITE_BUSY ){ p->rc = rc = SQLITE_BUSY; }else{ assert( rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT ); assert( rc==SQLITE_OK || db->nDeferredCons>0 ); rc = p->rc ? SQLITE_ERROR : SQLITE_DONE; } goto vdbe_return; } /* Opcode: Integer P1 P2 * * * ** |
︙ | ︙ | |||
985 986 987 988 989 990 991 | Mem *pVar; /* Value being transferred */ p1 = pOp->p1 - 1; p2 = pOp->p2; n = pOp->p3; assert( p1>=0 && p1+n<=p->nVar ); assert( p2>=1 && p2+n-1<=p->nMem ); | | | 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 | Mem *pVar; /* Value being transferred */ p1 = pOp->p1 - 1; p2 = pOp->p2; n = pOp->p3; assert( p1>=0 && p1+n<=p->nVar ); assert( p2>=1 && p2+n-1<=p->nMem ); assert( pOp->p4.z==0 || pOp->p3==1 || pOp->p3==0 ); while( n-- > 0 ){ pVar = &p->aVar[p1++]; if( sqlite3VdbeMemTooBig(pVar) ){ goto too_big; } pOut = &p->aMem[p2++]; |
︙ | ︙ | |||
1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 | */ case OP_ResultRow: { Mem *pMem; int i; assert( p->nResColumn==pOp->p2 ); assert( pOp->p1>0 ); assert( pOp->p1+pOp->p2<=p->nMem+1 ); /* 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 | > > > > > > > > > | 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 | */ case OP_ResultRow: { Mem *pMem; int i; assert( p->nResColumn==pOp->p2 ); assert( pOp->p1>0 ); assert( pOp->p1+pOp->p2<=p->nMem+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 ); break; } /* 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 |
︙ | ︙ | |||
1123 1124 1125 1126 1127 1128 1129 | /* Make sure the results of the current row are \000 terminated ** and have an assigned type. The results are de-ephemeralized as ** as side effect. */ pMem = p->pResultSet = &p->aMem[pOp->p1]; for(i=0; i<pOp->p2; i++){ sqlite3VdbeMemNulTerminate(&pMem[i]); | | | 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 | /* Make sure the results of the current row are \000 terminated ** and have an assigned type. The results are de-ephemeralized as ** as side effect. */ pMem = p->pResultSet = &p->aMem[pOp->p1]; for(i=0; i<pOp->p2; i++){ sqlite3VdbeMemNulTerminate(&pMem[i]); sqlite3VdbeMemStoreType(&pMem[i]); REGISTER_TRACE(pOp->p1+i, &pMem[i]); } if( db->mallocFailed ) goto no_mem; /* Return SQLITE_ROW */ p->pc = pc + 1; |
︙ | ︙ | |||
1201 1202 1203 1204 1205 1206 1207 | ** Subtract the value in register P1 from the value in register P2 ** and store the result in register P3. ** If either input is NULL, the result is NULL. */ /* Opcode: Divide P1 P2 P3 * * ** ** Divide the value in register P1 by the value in register P2 | | | | | 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 | ** Subtract the value in register P1 from the value in register P2 ** and store the result in register P3. ** If either input is NULL, the result is NULL. */ /* Opcode: Divide P1 P2 P3 * * ** ** Divide the value in register P1 by the value in register P2 ** and store the result in register P3 (P3=P2/P1). If the value in ** register P1 is zero, then the result is NULL. If either input is ** NULL, the result is NULL. */ /* Opcode: Remainder P1 P2 P3 * * ** ** Compute the remainder after integer division of the value in ** register P1 by the value in register P2 and store the result in P3. ** If the value in register P2 is zero the result is NULL. ** If either operand is NULL, the result is NULL. |
︙ | ︙ | |||
1342 1343 1344 1345 1346 1347 1348 | assert( apVal || n==0 ); assert( n==0 || (pOp->p2>0 && pOp->p2+n<=p->nMem+1) ); assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n ); pArg = &p->aMem[pOp->p2]; for(i=0; i<n; i++, pArg++){ apVal[i] = pArg; | | | 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 | assert( apVal || n==0 ); assert( n==0 || (pOp->p2>0 && pOp->p2+n<=p->nMem+1) ); assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n ); pArg = &p->aMem[pOp->p2]; for(i=0; i<n; i++, pArg++){ apVal[i] = pArg; sqlite3VdbeMemStoreType(pArg); REGISTER_TRACE(pOp->p2, pArg); } assert( pOp->p4type==P4_FUNCDEF || pOp->p4type==P4_VDBEFUNC ); if( pOp->p4type==P4_FUNCDEF ){ ctx.pFunc = pOp->p4.pFunc; ctx.pVdbeFunc = 0; |
︙ | ︙ | |||
1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 | ** store a boolean result (either 0, or 1, or NULL) in register P2. */ /* Opcode: Ne P1 P2 P3 P4 P5 ** ** This works just like the Lt opcode except that the jump is taken if ** the operands in registers P1 and P3 are not equal. See the Lt opcode for ** additional information. */ /* Opcode: Eq P1 P2 P3 P4 P5 ** ** This works just like the Lt opcode except that the jump is taken if ** the operands in registers P1 and P3 are equal. ** See the Lt opcode for additional information. */ /* Opcode: Le P1 P2 P3 P4 P5 ** ** 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. */ | > > > > > > > > > > > > | 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 | ** store a boolean result (either 0, or 1, or NULL) in register P2. */ /* Opcode: Ne P1 P2 P3 P4 P5 ** ** This works just like the Lt opcode except that the jump is taken if ** the operands in registers P1 and P3 are not equal. See the Lt opcode for ** additional information. ** ** 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 false. If either operand is NULL then the result is true. ** If neither operand is NULL the the result is the same as it would be if ** the SQLITE_NULLEQ flag were omitted from P5. */ /* Opcode: Eq P1 P2 P3 P4 P5 ** ** This works just like the Lt opcode except that the jump is taken if ** the operands in registers P1 and P3 are equal. ** See the Lt opcode for additional information. ** ** 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 the result is the same as it would be if ** the SQLITE_NULLEQ flag were omitted from P5. */ /* Opcode: Le P1 P2 P3 P4 P5 ** ** 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. */ |
︙ | ︙ | |||
1686 1687 1688 1689 1690 1691 1692 | */ case OP_Eq: /* same as TK_EQ, jump, in1, in3 */ case OP_Ne: /* same as TK_NE, jump, in1, in3 */ case OP_Lt: /* same as TK_LT, jump, in1, in3 */ case OP_Le: /* same as TK_LE, jump, in1, in3 */ case OP_Gt: /* same as TK_GT, jump, in1, in3 */ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ | < | | | | > > > > > > | > > | | | | | | | | | | | | | > | | | | | | | | | | > | 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 | */ case OP_Eq: /* same as TK_EQ, jump, in1, in3 */ case OP_Ne: /* same as TK_NE, jump, in1, in3 */ case OP_Lt: /* same as TK_LT, jump, in1, in3 */ case OP_Le: /* same as TK_LE, jump, in1, in3 */ case OP_Gt: /* same as TK_GT, jump, in1, in3 */ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ int res; /* Result of the comparison of pIn1 against pIn3 */ char affinity; /* Affinity to use for comparison */ if( (pIn1->flags | pIn3->flags)&MEM_Null ){ /* One or both operands are NULL */ if( pOp->p5 & SQLITE_NULLEQ ){ /* If SQLITE_NULLEQ is set (which will only happen if the operator is ** OP_Eq or OP_Ne) then take the jump or not depending on whether ** or not both operands are null. */ assert( pOp->opcode==OP_Eq || pOp->opcode==OP_Ne ); res = (pIn1->flags & pIn3->flags & MEM_Null)==0; }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 = &p->aMem[pOp->p2]; MemSetTypeFlag(pOut, MEM_Null); REGISTER_TRACE(pOp->p2, pOut); }else if( pOp->p5 & SQLITE_JUMPIFNULL ){ pc = pOp->p2-1; } break; } }else{ /* Neither operand is NULL. Do a comparison. */ affinity = pOp->p5 & SQLITE_AFF_MASK; if( affinity ){ applyAffinity(pIn1, affinity, encoding); applyAffinity(pIn3, affinity, encoding); if( db->mallocFailed ) goto no_mem; } assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 ); ExpandBlob(pIn1); ExpandBlob(pIn3); res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl); } switch( pOp->opcode ){ case OP_Eq: res = res==0; break; case OP_Ne: res = res!=0; break; case OP_Lt: res = res<0; break; case OP_Le: res = res<=0; break; case OP_Gt: res = res>0; break; default: res = res>=0; break; |
︙ | ︙ | |||
1782 1783 1784 1785 1786 1787 1788 | int bRev; /* True for DESCENDING sort order */ n = pOp->p3; pKeyInfo = pOp->p4.pKeyInfo; assert( n>0 ); assert( pKeyInfo!=0 ); p1 = pOp->p1; | < > > > > > > > > | > > | 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 | int bRev; /* True for DESCENDING sort order */ n = pOp->p3; pKeyInfo = pOp->p4.pKeyInfo; assert( n>0 ); assert( pKeyInfo!=0 ); p1 = pOp->p1; p2 = pOp->p2; #if 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 ); assert( p2>0 && p2+mx<=p->nMem+1 ); }else{ assert( p1>0 && p1+n<=p->nMem+1 ); assert( p2>0 && p2+n<=p->nMem+1 ); } #endif /* SQLITE_DEBUG */ for(i=0; i<n; i++){ idx = aPermute ? aPermute[i] : i; REGISTER_TRACE(p1+idx, &p->aMem[p1+idx]); REGISTER_TRACE(p2+idx, &p->aMem[p2+idx]); assert( i<pKeyInfo->nField ); pColl = pKeyInfo->aColl[i]; bRev = pKeyInfo->aSortOrder[i]; |
︙ | ︙ | |||
1953 1954 1955 1956 1957 1958 1959 | case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */ if( (pIn1->flags & MEM_Null)==0 ){ pc = pOp->p2 - 1; } break; } | < < < < < < < < < < < < < < < < < < < < < < | > > > > > | 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 | case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */ if( (pIn1->flags & MEM_Null)==0 ){ pc = pOp->p2 - 1; } break; } /* Opcode: Column P1 P2 P3 P4 P5 ** ** 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 column 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. */ case OP_Column: { u32 payloadSize; /* Number of bytes in the record */ i64 payloadSize64; /* Number of bytes in the record */ int p1; /* P1 value of the opcode */ int p2; /* column number to retrieve */ VdbeCursor *pC; /* The VDBE cursor */ |
︙ | ︙ | |||
2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 | Mem sMem; /* For storing the record being decoded */ u8 *zIdx; /* Index into header */ u8 *zEndHdr; /* Pointer to first byte after the header */ u32 offset; /* Offset into the data */ u64 offset64; /* 64-bit offset. 64 bits needed to catch overflow */ int szHdr; /* Size of the header size field at start of record */ int avail; /* Number of bytes of available data */ p1 = pOp->p1; p2 = pOp->p2; pC = 0; memset(&sMem, 0, sizeof(sMem)); assert( p1<p->nCursor ); | > | 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 | Mem sMem; /* For storing the record being decoded */ u8 *zIdx; /* Index into header */ u8 *zEndHdr; /* Pointer to first byte after the header */ u32 offset; /* Offset into the data */ u64 offset64; /* 64-bit offset. 64 bits needed to catch overflow */ int szHdr; /* Size of the header size field at start of record */ int avail; /* Number of bytes of available data */ Mem *pReg; /* PseudoTable input register */ p1 = pOp->p1; p2 = pOp->p2; pC = 0; memset(&sMem, 0, sizeof(sMem)); assert( p1<p->nCursor ); |
︙ | ︙ | |||
2051 2052 2053 2054 2055 2056 2057 | if( rc ) goto abort_due_to_error; if( pC->nullRow ){ payloadSize = 0; }else if( pC->cacheStatus==p->cacheCtr ){ payloadSize = pC->payloadSize; zRec = (char*)pC->aRow; }else if( pC->isIndex ){ | > | > > | > | | > | | | | 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 | if( rc ) goto abort_due_to_error; if( pC->nullRow ){ payloadSize = 0; }else if( pC->cacheStatus==p->cacheCtr ){ payloadSize = pC->payloadSize; zRec = (char*)pC->aRow; }else if( pC->isIndex ){ assert( sqlite3BtreeCursorIsValid(pCrsr) ); rc = sqlite3BtreeKeySize(pCrsr, &payloadSize64); assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */ /* sqlite3BtreeParseCellPtr() uses getVarint32() to extract the ** payload size, so it is impossible for payloadSize64 to be ** larger than 32 bits. */ assert( (payloadSize64 & SQLITE_MAX_U32)==(u64)payloadSize64 ); payloadSize = (u32)payloadSize64; }else{ assert( sqlite3BtreeCursorIsValid(pCrsr) ); rc = sqlite3BtreeDataSize(pCrsr, &payloadSize); assert( rc==SQLITE_OK ); /* DataSize() cannot fail */ } }else if( pC->pseudoTableReg>0 ){ pReg = &p->aMem[pC->pseudoTableReg]; assert( pReg->flags & MEM_Blob ); payloadSize = pReg->n; zRec = pReg->z; pC->cacheStatus = (pOp->p5&OPFLAG_CLEARCACHE) ? CACHE_STALE : p->cacheCtr; assert( payloadSize==0 || zRec!=0 ); }else{ /* Consider the row to be NULL */ payloadSize = 0; } /* If payloadSize is 0, then just store a NULL */ |
︙ | ︙ | |||
2440 2441 2442 2443 2444 2445 2446 | } pOut->flags = MEM_Int; pOut->u.i = nEntry; break; } #endif | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 | } pOut->flags = MEM_Int; 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: { |
︙ | ︙ | |||
2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 | }else{ db->nSavepoint++; } /* Link the new savepoint into the database handle's list. */ pNew->pNext = db->pSavepoint; db->pSavepoint = pNew; } } }else{ iSavepoint = 0; /* Find the named savepoint. If there is no such savepoint, then an ** an error is returned to the user. */ | > | 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 | }else{ db->nSavepoint++; } /* Link the new savepoint into the database handle's list. */ pNew->pNext = db->pSavepoint; db->pSavepoint = pNew; pNew->nDeferredCons = db->nDeferredCons; } } }else{ iSavepoint = 0; /* Find the named savepoint. If there is no such savepoint, then an ** an error is returned to the user. */ |
︙ | ︙ | |||
2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 | /* Determine whether or not this is a transaction savepoint. If so, ** and this is a RELEASE command, then the current transaction ** is committed. */ int isTransaction = pSavepoint->pNext==0 && db->isTransactionSavepoint; if( isTransaction && p1==SAVEPOINT_RELEASE ){ db->autoCommit = 1; if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){ p->pc = pc; db->autoCommit = 0; p->rc = rc = SQLITE_BUSY; goto vdbe_return; } | > > > | 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 | /* Determine whether or not this is a transaction savepoint. If so, ** and this is a RELEASE command, then the current transaction ** is committed. */ int isTransaction = pSavepoint->pNext==0 && db->isTransactionSavepoint; if( isTransaction && p1==SAVEPOINT_RELEASE ){ if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){ goto vdbe_return; } db->autoCommit = 1; if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){ p->pc = pc; db->autoCommit = 0; p->rc = rc = SQLITE_BUSY; goto vdbe_return; } |
︙ | ︙ | |||
2605 2606 2607 2608 2609 2610 2611 | while( db->pSavepoint!=pSavepoint ){ pTmp = db->pSavepoint; db->pSavepoint = pTmp->pNext; sqlite3DbFree(db, pTmp); db->nSavepoint--; } | | > > > > > | 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 | while( db->pSavepoint!=pSavepoint ){ pTmp = db->pSavepoint; db->pSavepoint = pTmp->pNext; sqlite3DbFree(db, pTmp); db->nSavepoint--; } /* If it is a RELEASE, then destroy the savepoint being operated on ** too. If it is a ROLLBACK TO, then set the number of deferred ** constraint violations present in the database to the value stored ** when the savepoint was created. */ if( p1==SAVEPOINT_RELEASE ){ assert( pSavepoint==db->pSavepoint ); db->pSavepoint = pSavepoint->pNext; sqlite3DbFree(db, pSavepoint); if( !isTransaction ){ db->nSavepoint--; } }else{ db->nDeferredCons = pSavepoint->nDeferredCons; } } } break; } |
︙ | ︙ | |||
2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 | "SQL statements in progress"); rc = SQLITE_BUSY; }else if( desiredAutoCommit!=db->autoCommit ){ if( iRollback ){ assert( desiredAutoCommit==1 ); sqlite3RollbackAll(db); db->autoCommit = 1; }else{ db->autoCommit = (u8)desiredAutoCommit; if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){ p->pc = pc; db->autoCommit = (u8)(1-desiredAutoCommit); p->rc = rc = SQLITE_BUSY; goto vdbe_return; | > > | 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 | "SQL statements in progress"); rc = SQLITE_BUSY; }else if( desiredAutoCommit!=db->autoCommit ){ if( iRollback ){ assert( desiredAutoCommit==1 ); sqlite3RollbackAll(db); db->autoCommit = 1; }else if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){ goto vdbe_return; }else{ db->autoCommit = (u8)desiredAutoCommit; if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){ p->pc = pc; db->autoCommit = (u8)(1-desiredAutoCommit); p->rc = rc = SQLITE_BUSY; goto vdbe_return; |
︙ | ︙ | |||
2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 | ** If P2 is non-zero, then a write-transaction is started. A RESERVED lock is ** obtained on the database file when a write-transaction is started. No ** other process can start another write transaction while this transaction is ** underway. Starting a write transaction also creates a rollback journal. A ** write transaction must be started before any changes can be made to the ** database. If P2 is 2 or greater then an EXCLUSIVE lock is also obtained ** on the file. ** ** If P2 is zero, then a read-lock is obtained on the database file. */ case OP_Transaction: { Btree *pBt; assert( pOp->p1>=0 && pOp->p1<db->nDb ); assert( (p->btreeMask & (1<<pOp->p1))!=0 ); pBt = db->aDb[pOp->p1].pBt; if( pBt ){ rc = sqlite3BtreeBeginTrans(pBt, pOp->p2); if( rc==SQLITE_BUSY ){ p->pc = pc; p->rc = rc = SQLITE_BUSY; goto vdbe_return; } | > > > > > > > > > > | > > > > > > > > > > > > > > > > > | 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 | ** If P2 is non-zero, then a write-transaction is started. A RESERVED lock is ** obtained on the database file when a write-transaction is started. No ** other process can start another write transaction while this transaction is ** underway. Starting a write transaction also creates a rollback journal. A ** write transaction must be started before any changes can be made to the ** database. If P2 is 2 or greater then an EXCLUSIVE lock is also obtained ** on the file. ** ** If a write-transaction is started and the Vdbe.usesStmtJournal flag is ** true (this flag is set if the Vdbe may modify more than one row and may ** throw an ABORT exception), a statement transaction may also be opened. ** More specifically, a statement transaction is opened iff the database ** connection is currently not in autocommit mode, or if there are other ** active statements. A statement transaction allows the affects of this ** VDBE to be rolled back after an error without having to roll back the ** entire transaction. If no error is encountered, the statement transaction ** will automatically commit when the VDBE halts. ** ** If P2 is zero, then a read-lock is obtained on the database file. */ case OP_Transaction: { Btree *pBt; assert( pOp->p1>=0 && pOp->p1<db->nDb ); assert( (p->btreeMask & (1<<pOp->p1))!=0 ); pBt = db->aDb[pOp->p1].pBt; if( pBt ){ rc = sqlite3BtreeBeginTrans(pBt, pOp->p2); if( rc==SQLITE_BUSY ){ p->pc = pc; p->rc = rc = SQLITE_BUSY; goto vdbe_return; } if( rc!=SQLITE_OK ){ goto abort_due_to_error; } if( pOp->p2 && p->usesStmtJournal && (db->autoCommit==0 || db->activeVdbeCnt>1) ){ assert( sqlite3BtreeIsInTrans(pBt) ); if( p->iStatement==0 ){ assert( db->nStatement>=0 && db->nSavepoint>=0 ); db->nStatement++; p->iStatement = db->nSavepoint + db->nStatement; } 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; } } break; } /* Opcode: ReadCookie P1 P2 P3 * * ** ** Read cookie number P3 from database P1 and write it into register P2. |
︙ | ︙ | |||
2755 2756 2757 2758 2759 2760 2761 | iDb = pOp->p1; iCookie = pOp->p3; assert( pOp->p3<SQLITE_N_BTREE_META ); assert( iDb>=0 && iDb<db->nDb ); assert( db->aDb[iDb].pBt!=0 ); assert( (p->btreeMask & (1<<iDb))!=0 ); | | | 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 | iDb = pOp->p1; iCookie = pOp->p3; assert( pOp->p3<SQLITE_N_BTREE_META ); assert( iDb>=0 && iDb<db->nDb ); assert( db->aDb[iDb].pBt!=0 ); assert( (p->btreeMask & (1<<iDb))!=0 ); sqlite3BtreeGetMeta(db->aDb[iDb].pBt, iCookie, (u32 *)&iMeta); pOut->u.i = iMeta; MemSetTypeFlag(pOut, MEM_Int); break; } /* Opcode: SetCookie P1 P2 P3 * * ** |
︙ | ︙ | |||
2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 | /* Record changes in the file format */ pDb->pSchema->file_format = (u8)pIn3->u.i; } if( pOp->p1==1 ){ /* Invalidate all prepared statements whenever the TEMP database ** schema is changed. Ticket #1644 */ sqlite3ExpirePreparedStatements(db); } break; } /* Opcode: VerifyCookie P1 P2 * ** ** Check the value of global database parameter number 0 (the | > | 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 | /* Record changes in the file format */ pDb->pSchema->file_format = (u8)pIn3->u.i; } if( pOp->p1==1 ){ /* Invalidate all prepared statements whenever the TEMP database ** schema is changed. Ticket #1644 */ sqlite3ExpirePreparedStatements(db); p->expired = 0; } break; } /* Opcode: VerifyCookie P1 P2 * ** ** Check the value of global database parameter number 0 (the |
︙ | ︙ | |||
2820 2821 2822 2823 2824 2825 2826 | case OP_VerifyCookie: { int iMeta; Btree *pBt; assert( pOp->p1>=0 && pOp->p1<db->nDb ); assert( (p->btreeMask & (1<<pOp->p1))!=0 ); pBt = db->aDb[pOp->p1].pBt; if( pBt ){ | | < | | 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 | case OP_VerifyCookie: { int iMeta; Btree *pBt; assert( pOp->p1>=0 && pOp->p1<db->nDb ); assert( (p->btreeMask & (1<<pOp->p1))!=0 ); pBt = db->aDb[pOp->p1].pBt; if( pBt ){ sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta); }else{ iMeta = 0; } if( iMeta!=pOp->p2 ){ sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed"); /* If the schema-cookie from the database file matches the cookie ** stored with the in-memory representation of the schema, do ** not reload the schema from the database file. ** ** If virtual-tables are in use, this is not just an optimization. |
︙ | ︙ | |||
2910 2911 2912 2913 2914 2915 2916 | KeyInfo *pKeyInfo; int p2; int iDb; int wrFlag; Btree *pX; VdbeCursor *pCur; Db *pDb; | | > > > > | 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 | KeyInfo *pKeyInfo; int p2; int iDb; int wrFlag; Btree *pX; VdbeCursor *pCur; Db *pDb; if( p->expired ){ rc = SQLITE_ABORT; break; } nField = 0; pKeyInfo = 0; p2 = pOp->p2; iDb = pOp->p3; assert( iDb>=0 && iDb<db->nDb ); assert( (p->btreeMask & (1<<iDb))!=0 ); |
︙ | ︙ | |||
2958 2959 2960 2961 2962 2963 2964 | assert( pOp->p1>=0 ); pCur = allocateCursor(p, pOp->p1, nField, iDb, 1); if( pCur==0 ) goto no_mem; pCur->nullRow = 1; rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->pCursor); pCur->pKeyInfo = pKeyInfo; | < < < | < < < < < | < > > | < | | < < < < < < < | < | < | < > > > > | | < < < < < < < < < | 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 | assert( pOp->p1>=0 ); pCur = allocateCursor(p, pOp->p1, nField, iDb, 1); if( pCur==0 ) goto no_mem; pCur->nullRow = 1; rc = sqlite3BtreeCursor(pX, p2, wrFlag, pKeyInfo, pCur->pCursor); pCur->pKeyInfo = pKeyInfo; /* Since it performs no memory allocation or IO, the only values that ** sqlite3BtreeCursor() may return are SQLITE_EMPTY and SQLITE_OK. ** SQLITE_EMPTY is only returned when attempting to open the table ** rooted at page 1 of a zero-byte database. */ assert( rc==SQLITE_EMPTY || rc==SQLITE_OK ); if( rc==SQLITE_EMPTY ){ pCur->pCursor = 0; rc = SQLITE_OK; } /* Set the VdbeCursor.isTable and isIndex variables. 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; pCur->isIndex = !pCur->isTable; break; } /* Opcode: OpenEphemeral P1 P2 * P4 * ** ** Open a new cursor P1 to a transient table. ** The cursor is always opened read/write even if |
︙ | ︙ | |||
3066 3067 3068 3069 3070 3071 3072 | pCx->isIndex = !pCx->isTable; break; } /* Opcode: OpenPseudo P1 P2 P3 * * ** ** Open a new cursor that points to a fake table that contains a single | | | | | < | < < | < < < < < | < | 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 | pCx->isIndex = !pCx->isTable; break; } /* Opcode: OpenPseudo P1 P2 P3 * * ** ** Open a new cursor that points to a fake table that contains a single ** row of data. The content of that one row in the content of memory ** register P2. In other words, cursor P1 becomes an alias for the ** MEM_Blob content contained in register P2. ** ** A pseudo-table created by this opcode is used to hold the a single ** row output from the sorter so that the row can be decomposed into ** individual columns using the OP_Column opcode. The OP_Column opcode ** is the only cursor opcode that works with a pseudo-table. ** ** P3 is the number of fields in the records that will be stored by ** the pseudo-table. */ case OP_OpenPseudo: { VdbeCursor *pCx; assert( pOp->p1>=0 ); pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, 0); if( pCx==0 ) goto no_mem; pCx->nullRow = 1; pCx->pseudoTableReg = pOp->p2; pCx->isTable = 1; pCx->isIndex = 0; break; } /* Opcode: Close P1 * * * * ** |
︙ | ︙ | |||
3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 | int nField; i64 iKey; /* The rowid we are to seek to */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( pOp->p2!=0 ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); if( pC->pCursor!=0 ){ oc = pOp->opcode; pC->nullRow = 0; if( pC->isTable ){ /* 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 covert it. */ | > | 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 | int nField; i64 iKey; /* The rowid we are to seek to */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( pOp->p2!=0 ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->pseudoTableReg==0 ); if( pC->pCursor!=0 ){ oc = pOp->opcode; pC->nullRow = 0; if( pC->isTable ){ /* 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 covert it. */ |
︙ | ︙ | |||
3292 3293 3294 3295 3296 3297 3298 | pc = pOp->p2 - 1; } }else{ /* This happens when attempting to open the sqlite3_master table ** for read access returns SQLITE_EMPTY. In this case always ** take the jump (since there are no records in the table). */ | < | 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 | pc = pOp->p2 - 1; } }else{ /* This happens when attempting to open the sqlite3_master table ** for read access returns SQLITE_EMPTY. In this case always ** take the jump (since there are no records in the table). */ pc = pOp->p2 - 1; } break; } /* Opcode: Seek P1 P2 * * * ** |
︙ | ︙ | |||
3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 | case OP_NotFound: /* jump, in3 */ case OP_Found: { /* jump, in3 */ int alreadyExists; VdbeCursor *pC; int res; UnpackedRecord *pIdxKey; char aTempRec[ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*3 + 7]; alreadyExists = 0; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); if( ALWAYS(pC->pCursor!=0) ){ assert( pC->isTable==0 ); assert( pIn3->flags & MEM_Blob ); pIdxKey = sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, aTempRec, sizeof(aTempRec)); if( pIdxKey==0 ){ goto no_mem; } if( pOp->opcode==OP_Found ){ pIdxKey->flags |= UNPACKED_PREFIX_MATCH; | > > > > > | 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 | case OP_NotFound: /* jump, in3 */ case OP_Found: { /* jump, in3 */ int alreadyExists; VdbeCursor *pC; int res; UnpackedRecord *pIdxKey; char aTempRec[ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*3 + 7]; #ifdef SQLITE_TEST sqlite3_found_count++; #endif alreadyExists = 0; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); if( ALWAYS(pC->pCursor!=0) ){ assert( pC->isTable==0 ); assert( pIn3->flags & MEM_Blob ); ExpandBlob(pIn3); pIdxKey = sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, aTempRec, sizeof(aTempRec)); if( pIdxKey==0 ){ goto no_mem; } if( pOp->opcode==OP_Found ){ pIdxKey->flags |= UNPACKED_PREFIX_MATCH; |
︙ | ︙ | |||
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 | u64 iKey; assert( pIn3->flags & MEM_Int ); assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->isTable ); pCrsr = pC->pCursor; if( pCrsr!=0 ){ res = 0; iKey = pIn3->u.i; rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res); pC->lastRowid = pIn3->u.i; pC->rowidIsValid = res==0 ?1:0; pC->nullRow = 0; pC->cacheStatus = CACHE_STALE; pC->deferredMoveto = 0; if( res!=0 ){ pc = pOp->p2 - 1; assert( pC->rowidIsValid==0 ); } pC->seekResult = res; }else{ /* This happens when an attempt to open a read cursor on the ** sqlite_master table returns SQLITE_EMPTY. */ | > < < | 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 | u64 iKey; assert( pIn3->flags & MEM_Int ); assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->isTable ); assert( pC->pseudoTableReg==0 ); pCrsr = pC->pCursor; if( pCrsr!=0 ){ res = 0; iKey = pIn3->u.i; rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res); pC->lastRowid = pIn3->u.i; pC->rowidIsValid = res==0 ?1:0; pC->nullRow = 0; pC->cacheStatus = CACHE_STALE; pC->deferredMoveto = 0; if( res!=0 ){ pc = pOp->p2 - 1; assert( pC->rowidIsValid==0 ); } pC->seekResult = res; }else{ /* This happens when an attempt to open a read cursor on the ** sqlite_master table returns SQLITE_EMPTY. */ pc = pOp->p2 - 1; assert( pC->rowidIsValid==0 ); pC->seekResult = 0; } break; } |
︙ | ︙ | |||
3553 3554 3555 3556 3557 3558 3559 | /* Opcode: NewRowid P1 P2 P3 * * ** ** Get a new integer record number (a.k.a "rowid") used as the key to a table. ** The record number is not previously used as a key in the database ** table that cursor P1 points to. The new record number is written ** written to register P2. ** | | | | | | > | 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 | /* Opcode: NewRowid P1 P2 P3 * * ** ** Get a new integer record number (a.k.a "rowid") used as the key to a table. ** The record number is not previously used as a key in the database ** table that cursor P1 points to. The new record number is written ** written to register P2. ** ** If P3>0 then P3 is a register in the root frame of this VDBE that holds ** the largest previously generated record number. No new record numbers are ** allowed to be less than this value. When this value reaches its maximum, ** a SQLITE_FULL error is generated. The P3 register is updated with the ' ** generated record number. This P3 mechanism is used to help implement the ** AUTOINCREMENT feature. */ case OP_NewRowid: { /* out2-prerelease */ 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; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); if( NEVER(pC->pCursor==0) ){ |
︙ | ︙ | |||
3611 3612 3613 3614 3615 3616 3617 | rc = sqlite3BtreeLast(pC->pCursor, &res); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } if( res ){ v = 1; }else{ | > | > > | > > > > > > > > | > > | | 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 | rc = sqlite3BtreeLast(pC->pCursor, &res); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } if( res ){ v = 1; }else{ assert( sqlite3BtreeCursorIsValid(pC->pCursor) ); rc = sqlite3BtreeKeySize(pC->pCursor, &v); assert( rc==SQLITE_OK ); /* Cannot fail following BtreeLast() */ if( v==MAX_ROWID ){ pC->useRandomRowid = 1; }else{ v++; } } } #ifndef SQLITE_OMIT_AUTOINCREMENT if( pOp->p3 ){ /* Assert that P3 is a valid memory cell. */ assert( pOp->p3>0 ); if( p->pFrame ){ for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent); /* Assert that P3 is a valid memory cell. */ assert( pOp->p3<=pFrame->nMem ); pMem = &pFrame->aMem[pOp->p3]; }else{ /* Assert that P3 is a valid memory cell. */ assert( pOp->p3<=p->nMem ); pMem = &p->aMem[pOp->p3]; } REGISTER_TRACE(pOp->p3, pMem); sqlite3VdbeMemIntegerify(pMem); assert( (pMem->flags & MEM_Int)!=0 ); /* mem(P3) holds an integer */ if( pMem->u.i==MAX_ROWID || pC->useRandomRowid ){ rc = SQLITE_FULL; goto abort_due_to_error; } if( v<pMem->u.i+1 ){ |
︙ | ︙ | |||
3673 3674 3675 3676 3677 3678 3679 | break; } /* Opcode: Insert P1 P2 P3 P4 P5 ** ** Write an entry into the table of cursor P1. A new entry is ** created if it doesn't already exist or the data for an existing | | | > > > > > > > > > > > > > > > > > > > | | | | | | | | | | < | | > > > > | > > > > | | | < < < < < < < < < < < < < < < < < < < < < < | | | | | | | | | | | < < | 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 | break; } /* Opcode: Insert P1 P2 P3 P4 P5 ** ** Write an entry into the table of cursor P1. A new entry is ** created if it doesn't already exist or the data for an existing ** entry is overwritten. The data is the value MEM_Blob stored in register ** number P2. The key is stored in register P3. The key must ** be a MEM_Int. ** ** If the OPFLAG_NCHANGE flag of P5 is set, then the row change count is ** incremented (otherwise not). If the OPFLAG_LASTROWID flag of P5 is set, ** then rowid is stored for subsequent return by the ** sqlite3_last_insert_rowid() function (otherwise it is unmodified). ** ** If the OPFLAG_USESEEKRESULT flag of P5 is set and if the result of ** the last seek operation (OP_NotExists) was a success, then this ** operation will not attempt to find the appropriate row before doing ** the insert but will instead overwrite the row that the cursor is ** currently pointing to. Presumably, the prior OP_NotExists opcode ** has already positioned the cursor correctly. This is an optimization ** that boosts performance by avoiding redundant seeks. ** ** If the OPFLAG_ISUPDATE flag is set, then this opcode is part of an ** UPDATE operation. Otherwise (if the flag is clear) then this opcode ** is part of an INSERT operation. The difference is only important to ** the update hook. ** ** Parameter P4 may point to a string containing the table-name, or ** may be NULL. If it is not NULL, then the update-hook ** (sqlite3.xUpdateCallback) is invoked following a successful insert. ** ** (WARNING/TODO: If P1 is a pseudo-cursor and P2 is dynamically ** allocated, then ownership of P2 is transferred to the pseudo-cursor ** and register P2 becomes ephemeral. If the cursor is changed, the ** value of register P2 will then change. Make sure this does not ** cause any problems.) ** ** This instruction only works on tables. The equivalent instruction ** for indices is OP_IdxInsert. */ /* Opcode: InsertInt P1 P2 P3 P4 P5 ** ** This works exactly like OP_Insert except that the key is the ** integer value P3, not the value of the integer stored in register P3. */ case OP_Insert: case OP_InsertInt: { Mem *pData; /* MEM cell holding data for the record to be inserted */ Mem *pKey; /* MEM cell holding key for the record */ i64 iKey; /* The integer ROWID or key for the record to be inserted */ VdbeCursor *pC; /* Cursor to table into which insert is written */ int nZero; /* Number of zero-bytes to append */ int seekResult; /* Result of prior seek or 0 if no USESEEKRESULT flag */ const char *zDb; /* database name - used by the update hook */ const char *zTbl; /* Table name - used by the opdate hook */ int op; /* Opcode for update hook: SQLITE_UPDATE or SQLITE_INSERT */ pData = &p->aMem[pOp->p2]; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->pCursor!=0 ); assert( pC->pseudoTableReg==0 ); assert( pC->isTable ); REGISTER_TRACE(pOp->p2, pData); if( pOp->opcode==OP_Insert ){ pKey = &p->aMem[pOp->p3]; assert( pKey->flags & MEM_Int ); REGISTER_TRACE(pOp->p3, pKey); iKey = pKey->u.i; }else{ assert( pOp->opcode==OP_InsertInt ); iKey = pOp->p3; } if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = iKey; if( pData->flags & MEM_Null ){ pData->z = 0; pData->n = 0; }else{ assert( pData->flags & (MEM_Blob|MEM_Str) ); } seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0); if( pData->flags & MEM_Zero ){ nZero = pData->u.nZero; }else{ nZero = 0; } sqlite3BtreeSetCachedRowid(pC->pCursor, 0); rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey, pData->z, pData->n, nZero, pOp->p5 & OPFLAG_APPEND, seekResult ); pC->rowidIsValid = 0; pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; /* Invoke the update-hook if required. */ if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){ zDb = db->aDb[pC->iDb].zName; |
︙ | ︙ | |||
3841 3842 3843 3844 3845 3846 3847 | const char *zTbl = pOp->p4.z; db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, zTbl, iKey); assert( pC->iDb>=0 ); } if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++; break; } | < | < | | > | < | < | 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 | const char *zTbl = pOp->p4.z; db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, zTbl, iKey); assert( pC->iDb>=0 ); } if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++; break; } /* Opcode: ResetCount * * * * * ** ** The value of the change counter is copied to the database handle ** change counter (returned by subsequent calls to sqlite3_changes()). ** Then the VMs internal change counter resets to 0. ** This is used by trigger programs. */ case OP_ResetCount: { sqlite3VdbeSetChanges(db, p->nChange); p->nChange = 0; break; } /* Opcode: RowData P1 P2 * * * ** ** Write into register P2 the complete row data for cursor P1. |
︙ | ︙ | |||
3893 3894 3895 3896 3897 3898 3899 | /* Note that RowKey and RowData are really exactly the same instruction */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC->isTable || pOp->opcode==OP_RowKey ); assert( pC->isIndex || pOp->opcode==OP_RowData ); assert( pC!=0 ); assert( pC->nullRow==0 ); | | > | > | > | 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 | /* Note that RowKey and RowData are really exactly the same instruction */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC->isTable || pOp->opcode==OP_RowKey ); assert( pC->isIndex || pOp->opcode==OP_RowData ); assert( pC!=0 ); assert( pC->nullRow==0 ); assert( pC->pseudoTableReg==0 ); assert( pC->pCursor!=0 ); pCrsr = pC->pCursor; assert( sqlite3BtreeCursorIsValid(pCrsr) ); /* The OP_RowKey and OP_RowData opcodes always follow OP_NotExists or ** OP_Rewind/Op_Next with no intervening instructions that might invalidate ** the cursor. Hence the following sqlite3VdbeCursorMoveto() call is always ** a no-op and can never fail. But we leave it in place as a safety. */ assert( pC->deferredMoveto==0 ); rc = sqlite3VdbeCursorMoveto(pC); if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error; if( pC->isIndex ){ assert( !pC->isTable ); rc = sqlite3BtreeKeySize(pCrsr, &n64); assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */ if( n64>db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } n = (u32)n64; }else{ rc = sqlite3BtreeDataSize(pCrsr, &n); assert( rc==SQLITE_OK ); /* DataSize() cannot fail */ if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } } if( sqlite3VdbeMemGrow(pOut, n, 0) ){ goto no_mem; } |
︙ | ︙ | |||
3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 | i64 v; sqlite3_vtab *pVtab; const sqlite3_module *pModule; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); if( pC->nullRow ){ /* Do nothing so that reg[P2] remains NULL */ break; }else if( pC->deferredMoveto ){ v = pC->movetoTarget; | > < < > < | > | 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 | i64 v; sqlite3_vtab *pVtab; const sqlite3_module *pModule; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->pseudoTableReg==0 ); if( pC->nullRow ){ /* Do nothing so that reg[P2] remains NULL */ break; }else if( pC->deferredMoveto ){ v = pC->movetoTarget; #ifndef SQLITE_OMIT_VIRTUALTABLE }else if( pC->pVtabCursor ){ pVtab = pC->pVtabCursor->pVtab; pModule = pVtab->pModule; assert( pModule->xRowid ); if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; rc = pModule->xRowid(pC->pVtabCursor, &v); sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = pVtab->zErrMsg; pVtab->zErrMsg = 0; if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; #endif /* SQLITE_OMIT_VIRTUALTABLE */ }else{ assert( pC->pCursor!=0 ); rc = sqlite3VdbeCursorMoveto(pC); if( rc ) goto abort_due_to_error; if( pC->rowidIsValid ){ v = pC->lastRowid; }else{ rc = sqlite3BtreeKeySize(pC->pCursor, &v); assert( rc==SQLITE_OK ); /* Always so because of CursorMoveto() above */ } } pOut->u.i = v; MemSetTypeFlag(pOut, MEM_Int); break; } |
︙ | ︙ | |||
4741 4742 4743 4744 4745 4746 4747 | sqlite3RowSetInsert(pIn1->u.pRowSet, pIn3->u.i); } break; } #ifndef SQLITE_OMIT_TRIGGER | > | < | | > > > > > > > > | | < > > > > > > > | > | | > > > > > > > > > > > | > > > > | > > > > > | > > > > > > > > > > > > | > > > | | > > > | | > > > > > > | > > > | > > > > | > > > > > | | < < < < < < < | | | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | > > > > > > > > | 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 | sqlite3RowSetInsert(pIn1->u.pRowSet, pIn3->u.i); } break; } #ifndef SQLITE_OMIT_TRIGGER /* Opcode: Program P1 P2 P3 P4 * ** ** Execute the trigger program passed as P4 (type P4_SUBPROGRAM). ** ** P1 contains the address of the memory cell that contains the first memory ** cell in an array of values used as arguments to the sub-program. P2 ** contains the address to jump to if the sub-program throws an IGNORE ** exception using the RAISE() function. Register P3 contains the address ** of a memory cell in this (the parent) VM that is used to allocate the ** memory required by the sub-vdbe at runtime. ** ** P4 is a pointer to the VM containing the trigger program. */ case OP_Program: { /* jump */ int nMem; /* Number of memory registers for sub-program */ int nByte; /* Bytes of runtime space required for sub-program */ Mem *pRt; /* Register to allocate runtime space */ Mem *pMem; /* Used to iterate through memory cells */ Mem *pEnd; /* Last memory cell in new array */ VdbeFrame *pFrame; /* New vdbe frame to execute in */ SubProgram *pProgram; /* Sub-program to execute */ void *t; /* Token identifying trigger */ pProgram = pOp->p4.pProgram; pRt = &p->aMem[pOp->p3]; assert( pProgram->nOp>0 ); /* If the p5 flag is clear, then recursive invocation of triggers is ** disabled for backwards compatibility (p5 is set if this sub-program ** is really a trigger, not a foreign key action, and the flag set ** and cleared by the "PRAGMA recursive_triggers" command is clear). ** ** It is recursive invocation of triggers, at the SQL level, that is ** disabled. In some cases a single trigger may generate more than one ** SubProgram (if the trigger may be executed with more than one different ** ON CONFLICT algorithm). SubProgram structures associated with a ** single trigger all have the same value for the SubProgram.token ** variable. */ if( pOp->p5 ){ t = pProgram->token; for(pFrame=p->pFrame; pFrame && pFrame->token!=t; pFrame=pFrame->pParent); if( pFrame ) break; } if( p->nFrame>=db->aLimit[SQLITE_LIMIT_TRIGGER_DEPTH] ){ rc = SQLITE_ERROR; sqlite3SetString(&p->zErrMsg, db, "too many levels of trigger recursion"); break; } /* Register pRt is used to store the memory required to save the state ** of the current program, and the memory required at runtime to execute ** the trigger program. If this trigger has been fired before, then pRt ** is already allocated. Otherwise, it must be initialized. */ if( (pRt->flags&MEM_Frame)==0 ){ /* SubProgram.nMem is set to the number of memory cells used by the ** program stored in SubProgram.aOp. As well as these, one memory ** cell is required for each cursor used by the program. Set local ** variable nMem (and later, VdbeFrame.nChildMem) to this value. */ nMem = pProgram->nMem + pProgram->nCsr; nByte = ROUND8(sizeof(VdbeFrame)) + nMem * sizeof(Mem) + pProgram->nCsr * sizeof(VdbeCursor *); pFrame = sqlite3DbMallocZero(db, nByte); if( !pFrame ){ goto no_mem; } sqlite3VdbeMemRelease(pRt); pRt->flags = MEM_Frame; pRt->u.pFrame = pFrame; pFrame->v = p; pFrame->nChildMem = nMem; pFrame->nChildCsr = pProgram->nCsr; pFrame->pc = pc; 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; pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem]; for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){ pMem->flags = MEM_Null; pMem->db = db; } }else{ pFrame = pRt->u.pFrame; assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem ); assert( pProgram->nCsr==pFrame->nChildCsr ); assert( pc==pFrame->pc ); } p->nFrame++; pFrame->pParent = p->pFrame; pFrame->lastRowid = db->lastRowid; pFrame->nChange = p->nChange; p->nChange = 0; p->pFrame = pFrame; p->aMem = &VdbeFrameMem(pFrame)[-1]; p->nMem = pFrame->nChildMem; p->nCursor = (u16)pFrame->nChildCsr; p->apCsr = (VdbeCursor **)&p->aMem[p->nMem+1]; p->aOp = pProgram->aOp; p->nOp = pProgram->nOp; pc = -1; break; } /* Opcode: Param P1 P2 * * * ** ** This opcode is only ever present in sub-programs called via the ** OP_Program instruction. Copy a value currently stored in a memory ** cell of the calling (parent) frame to cell P2 in the current frames ** address space. This is used by trigger programs to access the new.* ** and old.* values. ** ** The address of the cell in the parent frame is determined by adding ** the value of the P1 argument to the value of the P1 argument to the ** calling OP_Program instruction. */ case OP_Param: { /* out2-prerelease */ VdbeFrame *pFrame; Mem *pIn; pFrame = p->pFrame; pIn = &pFrame->aMem[pOp->p1 + pFrame->aOp[pFrame->pc].p1]; sqlite3VdbeMemShallowCopy(pOut, pIn, MEM_Ephem); break; } #endif /* #ifndef SQLITE_OMIT_TRIGGER */ #ifndef SQLITE_OMIT_FOREIGN_KEY /* Opcode: FkCounter P1 P2 * * * ** ** Increment a "constraint counter" by P2 (P2 may be negative or positive). ** If P1 is non-zero, the database constraint counter is incremented ** (deferred foreign key constraints). Otherwise, if P1 is zero, the ** statement counter is incremented (immediate foreign key constraints). */ case OP_FkCounter: { if( pOp->p1 ){ db->nDeferredCons += pOp->p2; }else{ p->nFkConstraint += pOp->p2; } break; } /* Opcode: FkIfZero P1 P2 * * * ** ** This opcode tests if a foreign key constraint-counter is currently zero. ** If so, jump to instruction P2. Otherwise, fall through to the next ** instruction. ** ** If P1 is non-zero, then the jump is taken if the database constraint-counter ** is zero (the one that counts deferred constraint violations). If P1 is ** zero, the jump is taken if the statement constraint-counter is zero ** (immediate foreign key constraint violations). */ case OP_FkIfZero: { /* jump */ if( pOp->p1 ){ if( db->nDeferredCons==0 ) pc = pOp->p2-1; }else{ if( p->nFkConstraint==0 ) pc = pOp->p2-1; } break; } #endif /* #ifndef SQLITE_OMIT_FOREIGN_KEY */ #ifndef SQLITE_OMIT_AUTOINCREMENT /* Opcode: MemMax P1 P2 * * * ** ** P1 is a register in the root frame of this VM (the root frame is ** different from the current frame if this instruction is being executed ** within a sub-program). Set the value of register P1 to the maximum of ** its current value and the value in register P2. ** ** This instruction throws an error if the memory cell is not initially ** an integer. */ case OP_MemMax: { /* in2 */ Mem *pIn1; VdbeFrame *pFrame; if( p->pFrame ){ for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent); pIn1 = &pFrame->aMem[pOp->p1]; }else{ pIn1 = &p->aMem[pOp->p1]; } sqlite3VdbeMemIntegerify(pIn1); sqlite3VdbeMemIntegerify(pIn2); if( pIn1->u.i<pIn2->u.i){ pIn1->u.i = pIn2->u.i; } break; } |
︙ | ︙ | |||
4871 4872 4873 4874 4875 4876 4877 | n = pOp->p5; assert( n>=0 ); pRec = &p->aMem[pOp->p2]; apVal = p->apArg; assert( apVal || n==0 ); for(i=0; i<n; i++, pRec++){ apVal[i] = pRec; | | | 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 | n = pOp->p5; assert( n>=0 ); pRec = &p->aMem[pOp->p2]; apVal = p->apArg; assert( apVal || n==0 ); for(i=0; i<n; i++, pRec++){ apVal[i] = pRec; sqlite3VdbeMemStoreType(pRec); } ctx.pFunc = pOp->p4.pFunc; assert( pOp->p3>0 && pOp->p3<=p->nMem ); ctx.pMem = pMem = &p->aMem[pOp->p3]; pMem->n++; ctx.s.flags = MEM_Null; ctx.s.z = 0; |
︙ | ︙ | |||
4990 4991 4992 4993 4994 4995 4996 | #ifndef SQLITE_OMIT_SHARED_CACHE /* Opcode: TableLock P1 P2 P3 P4 * ** ** Obtain a lock on a particular table. This instruction is only used when ** the shared-cache feature is enabled. ** | | < | | | < | | | | | | | > | | | | | | | 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 | #ifndef SQLITE_OMIT_SHARED_CACHE /* Opcode: TableLock P1 P2 P3 P4 * ** ** Obtain a lock on a particular table. This instruction is only used when ** the shared-cache feature is enabled. ** ** P1 is the index of the database in sqlite3.aDb[] of the database ** on which the lock is acquired. A readlock is obtained if P3==0 or ** a write lock if P3==1. ** ** P2 contains the root-page of the table to lock. ** ** P4 contains a pointer to the name of the table being locked. This is only ** used to generate an error message if the lock cannot be obtained. */ case OP_TableLock: { u8 isWriteLock = (u8)pOp->p3; if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommitted) ){ int p1 = pOp->p1; assert( p1>=0 && p1<db->nDb ); assert( (p->btreeMask & (1<<p1))!=0 ); assert( isWriteLock==0 || isWriteLock==1 ); rc = sqlite3BtreeLockTable(db->aDb[p1].pBt, pOp->p2, isWriteLock); if( (rc&0xFF)==SQLITE_LOCKED ){ const char *z = pOp->p4.z; sqlite3SetString(&p->zErrMsg, db, "database table is locked: %s", z); } } break; } #endif /* SQLITE_OMIT_SHARED_CACHE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VBegin * * * P4 * ** ** P4 may be a pointer to an sqlite3_vtab structure. If so, call the ** xBegin method for that table. ** ** Also, whether or not P4 is set, check that this is not being called from ** within a callback to a virtual table xSync() method. If it is, the error ** code will be set to SQLITE_LOCKED. */ case OP_VBegin: { VTable *pVTab; pVTab = pOp->p4.pVtab; rc = sqlite3VtabBegin(db, pVTab); if( pVTab ){ sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = pVTab->pVtab->zErrMsg; pVTab->pVtab->zErrMsg = 0; } break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VCreate P1 * * P4 * |
︙ | ︙ | |||
5081 5082 5083 5084 5085 5086 5087 | VdbeCursor *pCur; sqlite3_vtab_cursor *pVtabCursor; sqlite3_vtab *pVtab; sqlite3_module *pModule; pCur = 0; pVtabCursor = 0; | | | 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 | VdbeCursor *pCur; sqlite3_vtab_cursor *pVtabCursor; sqlite3_vtab *pVtab; sqlite3_module *pModule; pCur = 0; pVtabCursor = 0; pVtab = pOp->p4.pVtab->pVtab; pModule = (sqlite3_module *)pVtab->pModule; assert(pVtab && pModule); if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; rc = pModule->xOpen(pVtab, &pVtabCursor); sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = pVtab->zErrMsg; pVtab->zErrMsg = 0; |
︙ | ︙ | |||
5160 5161 5162 5163 5164 5165 5166 | /* Invoke the xFilter method */ { res = 0; apArg = p->apArg; for(i = 0; i<nArg; i++){ apArg[i] = &pArgc[i+1]; | | < < | 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 | /* Invoke the xFilter method */ { res = 0; apArg = p->apArg; for(i = 0; i<nArg; i++){ apArg[i] = &pArgc[i+1]; sqlite3VdbeMemStoreType(apArg[i]); } if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; p->inVtabMethod = 1; rc = pModule->xFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg); p->inVtabMethod = 0; sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = pVtab->zErrMsg; pVtab->zErrMsg = 0; if( rc==SQLITE_OK ){ res = pModule->xEof(pVtabCursor); } if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; if( res ){ pc = pOp->p2 - 1; |
︙ | ︙ | |||
5279 5280 5281 5282 5283 5284 5285 | /* Invoke the xNext() method of the module. There is no way for the ** underlying implementation to return an error if one occurs during ** xNext(). Instead, if an error occurs, true is returned (indicating that ** data is available) and the error code returned when xColumn or ** some other method is next invoked on the save virtual table cursor. */ if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; | < < | 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 | /* Invoke the xNext() method of the module. There is no way for the ** underlying implementation to return an error if one occurs during ** xNext(). Instead, if an error occurs, true is returned (indicating that ** data is available) and the error code returned when xColumn or ** some other method is next invoked on the save virtual table cursor. */ if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; p->inVtabMethod = 1; rc = pModule->xNext(pCur->pVtabCursor); p->inVtabMethod = 0; sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = pVtab->zErrMsg; pVtab->zErrMsg = 0; if( rc==SQLITE_OK ){ res = pModule->xEof(pCur->pVtabCursor); } if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; if( !res ){ /* If there is data, jump to P2 */ |
︙ | ︙ | |||
5311 5312 5313 5314 5315 5316 5317 | ** This opcode invokes the corresponding xRename method. The value ** in register P1 is passed as the zName argument to the xRename method. */ case OP_VRename: { sqlite3_vtab *pVtab; Mem *pName; | | < < | 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 | ** This opcode invokes the corresponding xRename method. The value ** in register P1 is passed as the zName argument to the xRename method. */ case OP_VRename: { sqlite3_vtab *pVtab; Mem *pName; pVtab = pOp->p4.pVtab->pVtab; pName = &p->aMem[pOp->p1]; assert( pVtab->pModule->xRename ); REGISTER_TRACE(pOp->p1, pName); assert( pName->flags & MEM_Str ); if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; rc = pVtab->pModule->xRename(pVtab, pName->z); sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = pVtab->zErrMsg; pVtab->zErrMsg = 0; if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; break; } #endif #ifndef SQLITE_OMIT_VIRTUALTABLE |
︙ | ︙ | |||
5362 5363 5364 5365 5366 5367 5368 | sqlite3_module *pModule; int nArg; int i; sqlite_int64 rowid; Mem **apArg; Mem *pX; | | | < < | 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 | sqlite3_module *pModule; int nArg; int i; sqlite_int64 rowid; Mem **apArg; Mem *pX; pVtab = pOp->p4.pVtab->pVtab; pModule = (sqlite3_module *)pVtab->pModule; nArg = pOp->p2; assert( pOp->p4type==P4_VTAB ); if( ALWAYS(pModule->xUpdate) ){ apArg = p->apArg; pX = &p->aMem[pOp->p3]; for(i=0; i<nArg; i++){ sqlite3VdbeMemStoreType(pX); apArg[i] = pX; pX++; } if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid); sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = pVtab->zErrMsg; pVtab->zErrMsg = 0; if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; if( rc==SQLITE_OK && pOp->p1 ){ assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) ); db->lastRowid = rowid; } p->nChange++; } |
︙ | ︙ |
Changes to src/vdbe.h.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** Header file for the Virtual DataBase Engine (VDBE) ** ** This header defines the interface to the virtual database engine ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. | < < > | | > > > > > > > > > > > > > > | > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 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 | ** ************************************************************************* ** Header file for the Virtual DataBase Engine (VDBE) ** ** This header defines the interface to the virtual database engine ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ #include <stdio.h> /* ** A single VDBE is an opaque structure named "Vdbe". Only routines ** in the source file sqliteVdbe.c are allowed to see the insides ** of this structure. */ typedef struct Vdbe Vdbe; /* ** The names of the following types declared in vdbeInt.h are required ** for the VdbeOp definition. */ typedef struct VdbeFunc VdbeFunc; typedef struct Mem Mem; typedef struct SubProgram SubProgram; /* ** A single instruction of the virtual machine has an opcode ** and as many as three operands. The instruction is recorded ** as an instance of the following structure: */ struct VdbeOp { u8 opcode; /* What operation to perform */ signed char p4type; /* One of the P4_xxx constants for p4 */ u8 opflags; /* Not currently used */ u8 p5; /* Fifth parameter is an unsigned character */ int p1; /* First operand */ int p2; /* Second parameter (often the jump destination) */ int p3; /* The third parameter */ union { /* fourth parameter */ int i; /* Integer value if p4type==P4_INT32 */ void *p; /* Generic pointer */ char *z; /* Pointer to data for string (char array) types */ i64 *pI64; /* Used when p4type is P4_INT64 */ double *pReal; /* Used when p4type is P4_REAL */ FuncDef *pFunc; /* Used when p4type is P4_FUNCDEF */ VdbeFunc *pVdbeFunc; /* Used when p4type is P4_VDBEFUNC */ 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 */ } p4; #ifdef SQLITE_DEBUG char *zComment; /* Comment to improve readability */ #endif #ifdef VDBE_PROFILE int cnt; /* Number of times this instruction was executed */ u64 cycles; /* Total time spent executing this instruction */ #endif }; typedef struct VdbeOp VdbeOp; /* ** A sub-routine used to implement a trigger program. */ struct SubProgram { VdbeOp *aOp; /* Array of opcodes for sub-program */ int nOp; /* Elements in aOp[] */ int nMem; /* Number of memory cells required */ int nCsr; /* Number of cursors required */ int nRef; /* Number of pointers to this structure */ void *token; /* id that may be used to recursive triggers */ }; /* ** A smaller version of VdbeOp used for the VdbeAddOpList() function because ** it takes up less space. */ struct VdbeOpList { u8 opcode; /* What operation to perform */ signed char p1; /* First operand */ signed char p2; /* Second parameter (often the jump destination) */ signed char p3; /* Third parameter */ }; typedef struct VdbeOpList VdbeOpList; /* ** Allowed values of VdbeOp.p4type */ #define P4_NOTUSED 0 /* The P4 parameter is not used */ #define P4_DYNAMIC (-1) /* Pointer to a string obtained from sqliteMalloc() */ #define P4_STATIC (-2) /* Pointer to a static string */ #define P4_COLLSEQ (-4) /* P4 is a pointer to a CollSeq structure */ #define P4_FUNCDEF (-5) /* P4 is a pointer to a FuncDef structure */ #define P4_KEYINFO (-6) /* P4 is a pointer to a KeyInfo structure */ #define P4_VDBEFUNC (-7) /* P4 is a pointer to a VdbeFunc structure */ #define P4_MEM (-8) /* P4 is a pointer to a Mem* structure */ #define P4_TRANSIENT (-9) /* P4 is a pointer to a transient string */ #define P4_VTAB (-10) /* P4 is a pointer to an sqlite3_vtab structure */ #define P4_MPRINTF (-11) /* P4 is a string obtained from sqlite3_mprintf() */ #define P4_REAL (-12) /* P4 is a 64-bit floating point value */ #define P4_INT64 (-13) /* P4 is a 64-bit signed integer */ #define P4_INT32 (-14) /* P4 is a 32-bit signed integer */ #define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */ #define P4_SUBPROGRAM (-18) /* P4 is a pointer to a SubProgram structure */ /* When adding a P4 argument using P4_KEYINFO, a copy of the KeyInfo structure ** is made. That copy is freed when the Vdbe is finalized. But if the ** argument is P4_KEYINFO_HANDOFF, the passed in pointer is used. It still ** gets freed when the Vdbe is finalized so it still should be obtained ** from a single sqliteMalloc(). But no copy is made and the calling ** function should *not* try to free the KeyInfo. |
︙ | ︙ | |||
164 165 166 167 168 169 170 | void sqlite3VdbeJumpHere(Vdbe*, int addr); void sqlite3VdbeChangeToNoop(Vdbe*, int addr, int N); void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N); void sqlite3VdbeUsesBtree(Vdbe*, int); VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); int sqlite3VdbeMakeLabel(Vdbe*); void sqlite3VdbeDelete(Vdbe*); | | > > > > > < < < | 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 | void sqlite3VdbeJumpHere(Vdbe*, int addr); void sqlite3VdbeChangeToNoop(Vdbe*, int addr, int N); void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N); void sqlite3VdbeUsesBtree(Vdbe*, int); VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); int sqlite3VdbeMakeLabel(Vdbe*); void sqlite3VdbeDelete(Vdbe*); void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int,int,int); int sqlite3VdbeFinalize(Vdbe*); void sqlite3VdbeResolveLabel(Vdbe*, int); int sqlite3VdbeCurrentAddr(Vdbe*); #ifdef SQLITE_DEBUG int sqlite3VdbeAssertMayAbort(Vdbe *, int); void sqlite3VdbeTrace(Vdbe*,FILE*); #endif void sqlite3VdbeResetStepResult(Vdbe*); int sqlite3VdbeReset(Vdbe*); void sqlite3VdbeSetNumCols(Vdbe*,int); int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, void(*)(void*)); void sqlite3VdbeCountChanges(Vdbe*); sqlite3 *sqlite3VdbeDb(Vdbe*); void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, int); void sqlite3VdbeSwap(Vdbe*,Vdbe*); VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int*); void sqlite3VdbeProgramDelete(sqlite3 *, SubProgram *, int); sqlite3_value *sqlite3VdbeGetValue(Vdbe*, int, u8); void sqlite3VdbeSetVarmask(Vdbe*, int); UnpackedRecord *sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,char*,int); void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord*); int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*); #ifndef NDEBUG void sqlite3VdbeComment(Vdbe*, const char*, ...); |
︙ | ︙ |
Changes to src/vdbeInt.h.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** This is the header file for information that is private to the ** VDBE. This information used to all be at the top of the single ** source code file "vdbe.c". When that file became too big (over ** 6000 lines long) it was split up into several smaller files and ** this header information was factored out. | < < | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** ************************************************************************* ** This is the header file for information that is private to the ** VDBE. This information used to all be at the top of the single ** source code file "vdbe.c". When that file became too big (over ** 6000 lines long) it was split up into several smaller files and ** this header information was factored out. */ #ifndef _VDBEINT_H_ #define _VDBEINT_H_ /* ** SQL is translated into a sequence of instructions to be ** executed by a virtual machine. Each instruction is an instance |
︙ | ︙ | |||
52 53 54 55 56 57 58 | int iDb; /* Index of cursor database in db->aDb[] (or -1) */ i64 lastRowid; /* Last rowid from a Next or NextIdx operation */ Bool zeroed; /* True if zeroed out and ready for reuse */ Bool rowidIsValid; /* True if lastRowid is valid */ Bool atFirst; /* True if pointing to first entry */ Bool useRandomRowid; /* Generate new record numbers semi-randomly */ Bool nullRow; /* True if pointing to a row with no data */ | < < < | < | > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 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 | int iDb; /* Index of cursor database in db->aDb[] (or -1) */ i64 lastRowid; /* Last rowid from a Next or NextIdx operation */ Bool zeroed; /* True if zeroed out and ready for reuse */ Bool rowidIsValid; /* True if lastRowid is valid */ Bool atFirst; /* True if pointing to first entry */ Bool useRandomRowid; /* Generate new record numbers semi-randomly */ Bool nullRow; /* True if pointing to a row with no data */ Bool deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */ Bool isTable; /* True if a table requiring integer keys */ Bool isIndex; /* True if an index containing keys only - no data */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ Btree *pBt; /* Separate file holding temporary table */ int pseudoTableReg; /* Register holding pseudotable content. */ KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */ int nField; /* Number of fields in the header */ i64 seqCount; /* Sequence counter */ sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */ const sqlite3_module *pModule; /* Module for cursor pVtabCursor */ /* Result of last sqlite3BtreeMoveto() done by an OP_NotExists or ** OP_IsUnique opcode on this cursor. */ int seekResult; /* Cached information about the header for the data record that the ** cursor is currently pointing to. Only valid if cacheStatus matches ** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of ** CACHE_STALE and so setting cacheStatus=CACHE_STALE guarantees that ** the cache is out of date. ** ** aRow might point to (ephemeral) data for the current row, or it might ** be NULL. */ u32 cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */ int payloadSize; /* Total number of bytes in the record */ u32 *aType; /* Type values for all entries in the record */ u32 *aOffset; /* Cached offsets to the start of each columns data */ u8 *aRow; /* Data for the current row, if all on one page */ }; typedef struct VdbeCursor VdbeCursor; /* ** When a sub-program is executed (OP_Program), a structure of this type ** is allocated to store the current value of the program counter, as ** well as the current memory cell array and various other frame specific ** values stored in the Vdbe struct. When the sub-program is finished, ** these values are copied back to the Vdbe from the VdbeFrame structure, ** restoring the state of the VM to as it was before the sub-program ** began executing. ** ** Frames are stored in a linked list headed at Vdbe.pParent. Vdbe.pParent ** is the parent of the current frame, or zero if the current frame ** is the main Vdbe program. */ typedef struct VdbeFrame VdbeFrame; struct VdbeFrame { Vdbe *v; /* VM this frame belongs to */ int pc; /* Program Counter */ Op *aOp; /* Program instructions */ int nOp; /* Size of aOp array */ Mem *aMem; /* Array of memory cells */ int nMem; /* Number of entries in aMem */ VdbeCursor **apCsr; /* Element of Vdbe cursors */ u16 nCursor; /* Number of entries in apCsr */ void *token; /* Copy of SubProgram.token */ int nChildMem; /* Number of memory cells for child frame */ int nChildCsr; /* Number of cursors for child frame */ i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */ int nChange; /* Statement changes (Vdbe.nChanges) */ VdbeFrame *pParent; /* Parent of this frame */ }; #define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))]) /* ** A value for VdbeCursor.cacheValid that means the cache is always invalid. */ #define CACHE_STALE 0 /* ** Internally, the vdbe manipulates nearly all SQL values as Mem |
︙ | ︙ | |||
107 108 109 110 111 112 113 114 115 116 117 118 119 120 | */ struct Mem { union { i64 i; /* Integer value. */ int nZero; /* Used when bit MEM_Zero is set in flags */ FuncDef *pDef; /* Used only when flags==MEM_Agg */ RowSet *pRowSet; /* Used only when flags==MEM_RowSet */ } u; double r; /* Real value */ sqlite3 *db; /* The associated database connection */ char *z; /* String or BLOB value */ int n; /* Number of characters in string value, excluding '\0' */ u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */ u8 type; /* One of SQLITE_NULL, SQLITE_TEXT, SQLITE_INTEGER, etc */ | > | 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | */ struct Mem { union { i64 i; /* Integer value. */ int nZero; /* Used when bit MEM_Zero is set in flags */ FuncDef *pDef; /* Used only when flags==MEM_Agg */ RowSet *pRowSet; /* Used only when flags==MEM_RowSet */ VdbeFrame *pFrame; /* Used when flags==MEM_Frame */ } u; double r; /* Real value */ sqlite3 *db; /* The associated database connection */ char *z; /* String or BLOB value */ int n; /* Number of characters in string value, excluding '\0' */ u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */ u8 type; /* One of SQLITE_NULL, SQLITE_TEXT, SQLITE_INTEGER, etc */ |
︙ | ︙ | |||
140 141 142 143 144 145 146 147 148 149 150 151 152 153 | */ #define MEM_Null 0x0001 /* Value is NULL */ #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_RowSet 0x0020 /* Value is a RowSet object */ #define MEM_TypeMask 0x00ff /* 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 */ | > | 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | */ #define MEM_Null 0x0001 /* Value is NULL */ #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_RowSet 0x0020 /* Value is a RowSet object */ #define MEM_Frame 0x0040 /* Value is a VdbeFrame object */ #define MEM_TypeMask 0x00ff /* 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 */ |
︙ | ︙ | |||
219 220 221 222 223 224 225 | */ typedef struct Set Set; struct Set { Hash hash; /* A set is just a hash table */ HashElem *prev; /* Previously accessed hash elemen */ }; | < < < < < < < < < < < < < < < | 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | */ typedef struct Set Set; struct Set { Hash hash; /* A set is just a hash table */ HashElem *prev; /* Previously accessed hash elemen */ }; /* ** An instance of the virtual machine. This structure contains the complete ** state of the virtual machine. ** ** The "sqlite3_stmt" structure pointer that is returned by sqlite3_compile() ** is really a pointer to an instance of this structure. ** |
︙ | ︙ | |||
266 267 268 269 270 271 272 | Mem *aColName; /* Column names to return */ Mem *pResultSet; /* Pointer to an array of results */ u16 nResColumn; /* Number of columns in one row of the result set */ u16 nCursor; /* Number of slots in apCsr[] */ VdbeCursor **apCsr; /* One element of this array for each open cursor */ u8 errorAction; /* Recovery action to do in case of an error */ u8 okVar; /* True if azVar[] has been initialized */ | | | < < < > > > > > | 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 | Mem *aColName; /* Column names to return */ Mem *pResultSet; /* Pointer to an array of results */ u16 nResColumn; /* Number of columns in one row of the result set */ u16 nCursor; /* Number of slots in apCsr[] */ VdbeCursor **apCsr; /* One element of this array for each open cursor */ u8 errorAction; /* Recovery action to do in case of an error */ u8 okVar; /* True if azVar[] has been initialized */ ynVar nVar; /* Number of entries in aVar[] */ Mem *aVar; /* Values for the OP_Variable opcode. */ char **azVar; /* Name of variables */ u32 magic; /* Magic number for sanity checking */ int nMem; /* Number of memory locations currently allocated */ Mem *aMem; /* The memory locations */ u32 cacheCtr; /* VdbeCursor row cache generation counter */ int pc; /* The program counter */ int rc; /* Value to return */ char *zErrMsg; /* Error message written here */ u8 explain; /* True if EXPLAIN present on SQL command */ u8 changeCntOn; /* True to update the change-counter */ u8 expired; /* True if the VM needs to be recompiled */ u8 minWriteFileFormat; /* Minimum file format for writable database files */ u8 inVtabMethod; /* See comments above */ u8 usesStmtJournal; /* True if uses a statement journal */ u8 readOnly; /* True for read-only statements */ u8 isPrepareV2; /* True if prepared with prepare_v2() */ int nChange; /* Number of db changes made since last reset */ int btreeMask; /* Bitmask of db->aDb[] entries referenced */ i64 startTime; /* Time when query started - used for profiling */ BtreeMutexArray aMutex; /* An array of Btree used here and needing locks */ int aCounter[2]; /* Counters used by sqlite3_stmt_status() */ char *zSql; /* Text of the SQL statement that generated this */ void *pFree; /* Free this when deleting the vdbe */ i64 nFkConstraint; /* Number of imm. FK constraints this VM */ i64 nStmtDefCons; /* Number of def. constraints when stmt started */ int iStatement; /* Statement number (or 0 if has not opened stmt) */ #ifdef SQLITE_DEBUG FILE *trace; /* Write an execution trace here, if not NULL */ #endif VdbeFrame *pFrame; /* Parent frame */ int nFrame; /* Number of frames in pFrame list */ u32 expmask; /* Binding to these vars invalidates VM */ }; /* ** The following are allowed values for Vdbe.magic */ #define VDBE_MAGIC_INIT 0x26bceaa5 /* Building a VDBE program */ #define VDBE_MAGIC_RUN 0xbdf20da3 /* VDBE is ready to execute */ |
︙ | ︙ | |||
358 359 360 361 362 363 364 | void sqlite3VdbeMemRelease(Mem *p); void sqlite3VdbeMemReleaseExternal(Mem *p); int sqlite3VdbeMemFinalize(Mem*, FuncDef*); const char *sqlite3OpcodeName(int); int sqlite3VdbeOpcodeHasProperty(int, int); int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); int sqlite3VdbeCloseStatement(Vdbe *, int); | > > > | > | > > | 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 | void sqlite3VdbeMemRelease(Mem *p); void sqlite3VdbeMemReleaseExternal(Mem *p); int sqlite3VdbeMemFinalize(Mem*, FuncDef*); const char *sqlite3OpcodeName(int); int sqlite3VdbeOpcodeHasProperty(int, int); int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); int sqlite3VdbeCloseStatement(Vdbe *, int); void sqlite3VdbeFrameDelete(VdbeFrame*); int sqlite3VdbeFrameRestore(VdbeFrame *); void sqlite3VdbeMemStoreType(Mem *pMem); #ifndef SQLITE_OMIT_FOREIGN_KEY int sqlite3VdbeCheckFk(Vdbe *, int); #else # define sqlite3VdbeCheckFk(p,i) 0 #endif #ifndef SQLITE_OMIT_SHARED_CACHE void sqlite3VdbeMutexArrayEnter(Vdbe *p); #else # define sqlite3VdbeMutexArrayEnter(p) #endif |
︙ | ︙ |
Changes to src/vdbeapi.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 code use to implement APIs that are part of the ** VDBE. | < < | 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. ** ************************************************************************* ** ** 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 |
︙ | ︙ | |||
72 73 74 75 76 77 78 | int rc; if( pStmt==0 ){ rc = SQLITE_OK; }else{ Vdbe *v = (Vdbe*)pStmt; sqlite3_mutex_enter(v->db->mutex); rc = sqlite3VdbeReset(v); | | | 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | int rc; if( pStmt==0 ){ rc = SQLITE_OK; }else{ Vdbe *v = (Vdbe*)pStmt; sqlite3_mutex_enter(v->db->mutex); rc = sqlite3VdbeReset(v); sqlite3VdbeMakeReady(v, -1, 0, 0, 0, 0, 0); assert( (rc & (v->db->errMask))==rc ); rc = sqlite3ApiExit(v->db, rc); sqlite3_mutex_leave(v->db->mutex); } return rc; } |
︙ | ︙ | |||
94 95 96 97 98 99 100 101 102 103 104 105 106 107 | #if SQLITE_THREADSAFE sqlite3_mutex *mutex = ((Vdbe*)pStmt)->db->mutex; #endif sqlite3_mutex_enter(mutex); for(i=0; i<p->nVar; i++){ sqlite3VdbeMemRelease(&p->aVar[i]); p->aVar[i].flags = MEM_Null; } sqlite3_mutex_leave(mutex); return rc; } /**************************** sqlite3_value_ ******************************* | > > > | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | #if SQLITE_THREADSAFE sqlite3_mutex *mutex = ((Vdbe*)pStmt)->db->mutex; #endif sqlite3_mutex_enter(mutex); for(i=0; i<p->nVar; i++){ sqlite3VdbeMemRelease(&p->aVar[i]); p->aVar[i].flags = MEM_Null; } if( p->isPrepareV2 && p->expmask ){ p->expired = 1; } sqlite3_mutex_leave(mutex); return rc; } /**************************** sqlite3_value_ ******************************* |
︙ | ︙ | |||
300 301 302 303 304 305 306 | /* Assert that malloc() has not failed */ db = p->db; if( db->mallocFailed ){ return SQLITE_NOMEM; } if( p->pc<=0 && p->expired ){ | | > > | 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 | /* Assert that malloc() has not failed */ db = p->db; if( db->mallocFailed ){ return SQLITE_NOMEM; } if( p->pc<=0 && p->expired ){ if( ALWAYS(p->rc==SQLITE_OK || p->rc==SQLITE_SCHEMA) ){ p->rc = SQLITE_SCHEMA; } rc = SQLITE_ERROR; goto end_of_step; } if( sqlite3SafetyOn(db) ){ p->rc = SQLITE_MISUSE; return SQLITE_MISUSE; } 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->activeVdbeCnt==0 ){ db->u1.isInterrupted = 0; } assert( db->writeVdbeCnt>0 || db->autoCommit==0 || db->nDeferredCons==0 ); #ifndef SQLITE_OMIT_TRACE if( db->xProfile && !db->init.busy ){ double rNow; sqlite3OsCurrentTime(db->pVfs, &rNow); p->startTime = (u64)((rNow - (int)rNow)*3600.0*24.0*1000000000.0); } |
︙ | ︙ | |||
908 909 910 911 912 913 914 915 916 917 918 919 920 921 | return SQLITE_RANGE; } i--; pVar = &p->aVar[i]; sqlite3VdbeMemRelease(pVar); pVar->flags = MEM_Null; sqlite3Error(p->db, SQLITE_OK, 0); return SQLITE_OK; } /* ** Bind a text or BLOB value. */ static int bindText( | > > > > > > > > > | 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 | return SQLITE_RANGE; } i--; pVar = &p->aVar[i]; sqlite3VdbeMemRelease(pVar); pVar->flags = MEM_Null; sqlite3Error(p->db, SQLITE_OK, 0); /* 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. */ if( p->isPrepareV2 && ((i<32 && p->expmask & ((u32)1 << i)) || p->expmask==0xffffffff) ){ p->expired = 1; } return SQLITE_OK; } /* ** Bind a text or BLOB value. */ static int bindText( |
︙ | ︙ | |||
1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 | ** SQLITE_OK is returned. */ int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){ Vdbe *pFrom = (Vdbe*)pFromStmt; Vdbe *pTo = (Vdbe*)pToStmt; if( pFrom->nVar!=pTo->nVar ){ return SQLITE_ERROR; } return sqlite3TransferBindings(pFromStmt, pToStmt); } #endif /* ** Return the sqlite3* database handle to which the prepared statement given | > > > > > > | 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 | ** SQLITE_OK is returned. */ int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){ Vdbe *pFrom = (Vdbe*)pFromStmt; Vdbe *pTo = (Vdbe*)pToStmt; if( pFrom->nVar!=pTo->nVar ){ return SQLITE_ERROR; } if( pTo->isPrepareV2 && pTo->expmask ){ pTo->expired = 1; } if( pFrom->isPrepareV2 && pFrom->expmask ){ pFrom->expired = 1; } return sqlite3TransferBindings(pFromStmt, pToStmt); } #endif /* ** Return the sqlite3* database handle to which the prepared statement given |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used for creating, destroying, and populating ** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) Prior ** to version 2.8.7, all this code was combined into the vdbe.c source file. ** But that file was getting too big so this subroutines were split out. | < < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used for creating, destroying, and populating ** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) Prior ** to version 2.8.7, all this code was combined into the vdbe.c source file. ** But that file was getting too big so this subroutines were split out. */ #include "sqliteInt.h" #include "vdbeInt.h" /* |
︙ | ︙ | |||
49 50 51 52 53 54 55 56 57 58 59 60 61 | return p; } /* ** Remember the SQL string for a prepared statement. */ void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){ if( p==0 ) return; #ifdef SQLITE_OMIT_TRACE if( !isPrepareV2 ) return; #endif assert( p->zSql==0 ); p->zSql = sqlite3DbStrNDup(p->db, z, n); | > | | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | return p; } /* ** Remember the SQL string for a prepared statement. */ void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){ assert( isPrepareV2==1 || isPrepareV2==0 ); if( p==0 ) return; #ifdef SQLITE_OMIT_TRACE if( !isPrepareV2 ) return; #endif assert( p->zSql==0 ); p->zSql = sqlite3DbStrNDup(p->db, z, n); p->isPrepareV2 = (u8)isPrepareV2; } /* ** Return the SQL associated with a prepared statement */ const char *sqlite3_sql(sqlite3_stmt *pStmt){ Vdbe *p = (Vdbe *)pStmt; |
︙ | ︙ | |||
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | assert( p->magic==VDBE_MAGIC_INIT ); assert( j>=0 && j<p->nLabel ); if( p->aLabel ){ p->aLabel[j] = p->nOp; } } /* ** Loop through the program looking for P2 values that are negative ** on jump instructions. Each such value is a label. Resolve the ** label by setting the P2 value to its correct non-zero value. ** ** This routine is called once after all opcodes have been inserted. ** ** Variable *pMaxFuncArgs is set to the maximum value of any P2 argument ** to an OP_Function, OP_AggStep or OP_VFilter opcode. This is used by ** sqlite3VdbeMakeReady() to size the Vdbe.apArg[] array. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > > > > > > > > > > > > > > > > > > > > > > > | 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 | assert( p->magic==VDBE_MAGIC_INIT ); assert( j>=0 && j<p->nLabel ); if( p->aLabel ){ p->aLabel[j] = p->nOp; } } #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 ** invoke directly or indirectly. It should be used as follows: ** ** Op *pOp; ** VdbeOpIter sIter; ** ** memset(&sIter, 0, sizeof(sIter)); ** sIter.v = v; // v is of type Vdbe* ** while( (pOp = opIterNext(&sIter)) ){ ** // Do something with pOp ** } ** sqlite3DbFree(v->db, sIter.apSub); ** */ typedef struct VdbeOpIter VdbeOpIter; struct VdbeOpIter { Vdbe *v; /* Vdbe to iterate through the opcodes of */ SubProgram **apSub; /* Array of subprograms */ int nSub; /* Number of entries in apSub */ int iAddr; /* Address of next instruction to return */ int iSub; /* 0 = main program, 1 = first sub-program etc. */ }; static Op *opIterNext(VdbeOpIter *p){ Vdbe *v = p->v; Op *pRet = 0; Op *aOp; int nOp; if( p->iSub<=p->nSub ){ if( p->iSub==0 ){ aOp = v->aOp; nOp = v->nOp; }else{ aOp = p->apSub[p->iSub-1]->aOp; nOp = p->apSub[p->iSub-1]->nOp; } assert( p->iAddr<nOp ); pRet = &aOp[p->iAddr]; p->iAddr++; if( p->iAddr==nOp ){ p->iSub++; p->iAddr = 0; } if( pRet->p4type==P4_SUBPROGRAM ){ int nByte = (p->nSub+1)*sizeof(SubProgram*); int j; for(j=0; j<p->nSub; j++){ if( p->apSub[j]==pRet->p4.pProgram ) break; } if( j==p->nSub ){ p->apSub = sqlite3DbReallocOrFree(v->db, p->apSub, nByte); if( !p->apSub ){ pRet = 0; }else{ p->apSub[p->nSub++] = pRet->p4.pProgram; } } } } return pRet; } /* ** Check if the program stored in the VM associated with pParse may ** throw an ABORT exception (causing the statement, but not entire transaction ** 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) ** ** 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; 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 #ifndef SQLITE_OMIT_FOREIGN_KEY || (opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1) #endif || ((opcode==OP_Halt || opcode==OP_HaltIfNull) && (pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort)) ){ hasAbort = 1; break; } } sqlite3DbFree(v->db, sIter.apSub); /* Return true if hasAbort==mayAbort. Or if a malloc failure occured. ** If malloc failed, then the while() loop above may not have iterated ** through all opcodes and hasAbort may be set incorrectly. Return ** true for this case to prevent the assert() in the callers frame ** from failing. */ return ( v->db->mallocFailed || hasAbort==mayAbort ); } #endif /* SQLITE_DEBUG - the sqlite3AssertMayAbort() function */ /* ** Loop through the program looking for P2 values that are negative ** on jump instructions. Each such value is a label. Resolve the ** label by setting the P2 value to its correct non-zero value. ** ** This routine is called once after all opcodes have been inserted. ** ** Variable *pMaxFuncArgs is set to the maximum value of any P2 argument ** to an OP_Function, OP_AggStep or OP_VFilter opcode. This is used by ** sqlite3VdbeMakeReady() to size the Vdbe.apArg[] array. */ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ int i; int nMaxArgs = *pMaxFuncArgs; Op *pOp; int *aLabel = p->aLabel; p->readOnly = 1; for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){ u8 opcode = pOp->opcode; if( opcode==OP_Function || opcode==OP_AggStep ){ if( pOp->p5>nMaxArgs ) nMaxArgs = pOp->p5; #ifndef SQLITE_OMIT_VIRTUALTABLE }else if( opcode==OP_VUpdate ){ if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2; #endif }else if( opcode==OP_Transaction && pOp->p2!=0 ){ p->readOnly = 0; #ifndef SQLITE_OMIT_VIRTUALTABLE }else if( opcode==OP_VFilter ){ int n; assert( p->nOp - i >= 3 ); assert( pOp[-1].opcode==OP_Integer ); n = pOp[-1].p1; if( n>nMaxArgs ) nMaxArgs = n; #endif } if( sqlite3VdbeOpcodeHasProperty(opcode, OPFLG_JUMP) && pOp->p2<0 ){ assert( -1-pOp->p2<p->nLabel ); pOp->p2 = aLabel[-1-pOp->p2]; } } sqlite3DbFree(p->db, p->aLabel); p->aLabel = 0; *pMaxFuncArgs = nMaxArgs; } /* ** Return the address of the next instruction to be inserted. */ int sqlite3VdbeCurrentAddr(Vdbe *p){ assert( p->magic==VDBE_MAGIC_INIT ); return p->nOp; } /* ** This function returns a pointer to the array of opcodes associated with ** the Vdbe passed as the first argument. It is the callers responsibility ** to arrange for the returned array to be eventually freed using the ** vdbeFreeOpArray() function. ** ** Before returning, *pnOp is set to the number of entries in the returned ** array. Also, *pnMaxArg is set to the larger of its current value and ** the number of entries in the Vdbe.apArg[] array required to execute the ** returned program. */ VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg){ VdbeOp *aOp = p->aOp; assert( aOp && !p->db->mallocFailed ); /* Check that sqlite3VdbeUsesBtree() was not called on this VM */ assert( p->aMutex.nMutex==0 ); resolveP2Values(p, pnMaxArg); *pnOp = p->nOp; p->aOp = 0; return aOp; } /* ** Add a whole list of operations to the operation stack. Return the ** address of the first operation added. */ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){ int addr; |
︙ | ︙ | |||
474 475 476 477 478 479 480 481 482 483 484 485 486 487 | freeEphemeralFunction(db, (FuncDef*)p4); break; } case P4_MEM: { sqlite3ValueFree((sqlite3_value*)p4); break; } } } } /* ** Change N opcodes starting at addr to No-ops. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | freeEphemeralFunction(db, (FuncDef*)p4); break; } case P4_MEM: { sqlite3ValueFree((sqlite3_value*)p4); break; } case P4_VTAB : { sqlite3VtabUnlock((VTable *)p4); break; } case P4_SUBPROGRAM : { sqlite3VdbeProgramDelete(db, (SubProgram *)p4, 1); break; } } } } /* ** 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; pOp<&aOp[nOp]; pOp++){ freeP4(db, pOp->p4type, pOp->p4.p); #ifdef SQLITE_DEBUG sqlite3DbFree(db, pOp->zComment); #endif } } sqlite3DbFree(db, aOp); } /* ** Decrement the ref-count on the SubProgram structure passed as the ** second argument. If the ref-count reaches zero, free the structure. ** ** The array of VDBE opcodes stored as SubProgram.aOp is freed if ** either the ref-count reaches zero or parameter freeop is non-zero. ** ** Since the array of opcodes pointed to by SubProgram.aOp may directly ** or indirectly contain a reference to the SubProgram structure itself. ** By passing a non-zero freeop parameter, the caller may ensure that all ** SubProgram structures and their aOp arrays are freed, even when there ** are such circular references. */ void sqlite3VdbeProgramDelete(sqlite3 *db, SubProgram *p, int freeop){ if( p ){ assert( p->nRef>0 ); if( freeop || p->nRef==1 ){ Op *aOp = p->aOp; p->aOp = 0; vdbeFreeOpArray(db, aOp, p->nOp); p->nOp = 0; } p->nRef--; if( p->nRef==0 ){ sqlite3DbFree(db, p); } } } /* ** Change N opcodes starting at addr to No-ops. |
︙ | ︙ | |||
527 528 529 530 531 532 533 | 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 ); if( p->aOp==0 || db->mallocFailed ){ | | | 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 | 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 ); if( p->aOp==0 || db->mallocFailed ){ if ( n!=P4_KEYINFO && n!=P4_VTAB ) { freeP4(db, n, (void*)*(char**)&zP4); } return; } assert( p->nOp>0 ); assert( addr<p->nOp ); if( addr<0 ){ |
︙ | ︙ | |||
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 | }else{ p->db->mallocFailed = 1; pOp->p4type = P4_NOTUSED; } }else if( n==P4_KEYINFO_HANDOFF ){ pOp->p4.p = (void*)zP4; pOp->p4type = P4_KEYINFO; }else if( n<0 ){ pOp->p4.p = (void*)zP4; pOp->p4type = (signed char)n; }else{ if( n==0 ) n = sqlite3Strlen30(zP4); pOp->p4.z = sqlite3DbStrNDup(p->db, zP4, n); pOp->p4type = P4_DYNAMIC; } } #ifndef NDEBUG /* ** Change the comment on the 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. */ void sqlite3VdbeComment(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 ){ char **pz = &p->aOp[p->nOp-1].zComment; va_start(ap, zFormat); sqlite3DbFree(p->db, *pz); *pz = sqlite3VMPrintf(p->db, zFormat, ap); va_end(ap); } } void sqlite3VdbeNoopComment(Vdbe *p, const char *zFormat, ...){ va_list ap; sqlite3VdbeAddOp0(p, OP_Noop); assert( p->nOp>0 || p->aOp==0 ); assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->db->mallocFailed ); if( p->nOp ){ char **pz = &p->aOp[p->nOp-1].zComment; va_start(ap, zFormat); sqlite3DbFree(p->db, *pz); | > > > > > > > | 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 | }else{ p->db->mallocFailed = 1; pOp->p4type = P4_NOTUSED; } }else if( n==P4_KEYINFO_HANDOFF ){ pOp->p4.p = (void*)zP4; pOp->p4type = P4_KEYINFO; }else if( n==P4_VTAB ){ pOp->p4.p = (void*)zP4; pOp->p4type = P4_VTAB; sqlite3VtabLock((VTable *)zP4); assert( ((VTable *)zP4)->db==p->db ); }else if( n<0 ){ pOp->p4.p = (void*)zP4; pOp->p4type = (signed char)n; }else{ if( n==0 ) n = sqlite3Strlen30(zP4); pOp->p4.z = sqlite3DbStrNDup(p->db, zP4, n); pOp->p4type = P4_DYNAMIC; } } #ifndef NDEBUG /* ** Change the comment on the 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. */ void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){ va_list ap; if( !p ) return; assert( p->nOp>0 || p->aOp==0 ); assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->db->mallocFailed ); if( p->nOp ){ char **pz = &p->aOp[p->nOp-1].zComment; va_start(ap, zFormat); sqlite3DbFree(p->db, *pz); *pz = sqlite3VMPrintf(p->db, zFormat, ap); va_end(ap); } } void sqlite3VdbeNoopComment(Vdbe *p, const char *zFormat, ...){ va_list ap; if( !p ) return; sqlite3VdbeAddOp0(p, OP_Noop); assert( p->nOp>0 || p->aOp==0 ); assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->db->mallocFailed ); if( p->nOp ){ char **pz = &p->aOp[p->nOp-1].zComment; va_start(ap, zFormat); sqlite3DbFree(p->db, *pz); |
︙ | ︙ | |||
722 723 724 725 726 727 728 729 730 731 732 733 | assert( (pMem->flags & MEM_Null)==0 ); if( pMem->flags & MEM_Str ){ zP4 = pMem->z; }else if( pMem->flags & MEM_Int ){ sqlite3_snprintf(nTemp, zTemp, "%lld", pMem->u.i); }else if( pMem->flags & MEM_Real ){ sqlite3_snprintf(nTemp, zTemp, "%.16g", pMem->r); } break; } #ifndef SQLITE_OMIT_VIRTUALTABLE case P4_VTAB: { | > > > | > > > > < | 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 | assert( (pMem->flags & MEM_Null)==0 ); if( pMem->flags & MEM_Str ){ zP4 = pMem->z; }else if( pMem->flags & MEM_Int ){ sqlite3_snprintf(nTemp, zTemp, "%lld", pMem->u.i); }else if( pMem->flags & MEM_Real ){ sqlite3_snprintf(nTemp, zTemp, "%.16g", pMem->r); }else{ assert( pMem->flags & MEM_Blob ); zP4 = "(blob)"; } break; } #ifndef SQLITE_OMIT_VIRTUALTABLE case P4_VTAB: { sqlite3_vtab *pVtab = pOp->p4.pVtab->pVtab; sqlite3_snprintf(nTemp, zTemp, "vtab:%p:%p", pVtab, pVtab->pModule); break; } #endif case P4_INTARRAY: { sqlite3_snprintf(nTemp, zTemp, "intarray"); break; } case P4_SUBPROGRAM: { sqlite3_snprintf(nTemp, zTemp, "program"); break; } default: { zP4 = pOp->p4.z; if( zP4==0 ){ zP4 = zTemp; zTemp[0] = 0; } } } assert( zP4!=0 ); return zP4; } #endif /* ** Declare to the Vdbe that the BTree object at db->aDb[i] is used. */ void sqlite3VdbeUsesBtree(Vdbe *p, int i){ int mask; assert( i>=0 && i<p->db->nDb && i<sizeof(u32)*8 ); assert( i<(int)sizeof(p->btreeMask)*8 ); mask = ((u32)1)<<i; if( (p->btreeMask & mask)==0 ){ |
︙ | ︙ | |||
810 811 812 813 814 815 816 | ** callgrind, this causes a certain test case to hit the CPU 4.7 ** percent less (x86 linux, gcc version 4.1.2, -O6) than if ** 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. */ | | < > > > > | | < < < | | | < < < < | | < > | < > > > > | | > > > > > > > > > > > > > > | | > > | > > > > > > > > > > > > > > > > > > > > > > | 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 | ** callgrind, this causes a certain test case to hit the CPU 4.7 ** percent less (x86 linux, gcc version 4.1.2, -O6) than if ** 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. */ if( p->flags&(MEM_Agg|MEM_Dyn|MEM_Frame|MEM_RowSet) ){ sqlite3VdbeMemRelease(p); }else if( p->zMalloc ){ sqlite3DbFree(db, p->zMalloc); p->zMalloc = 0; } p->flags = MEM_Null; } db->mallocFailed = malloc_failed; } } /* ** 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]; for(i=0; i<p->nChildCsr; i++){ sqlite3VdbeFreeCursor(p->v, apCsr[i]); } releaseMemArray(aMem, p->nChildMem); sqlite3DbFree(p->v->db, p); } #ifndef SQLITE_OMIT_EXPLAIN /* ** Give a listing of the program in the virtual machine. ** ** The interface is the same as sqlite3VdbeExec(). But instead of ** running the code, it invokes the callback once for each instruction. ** This feature is used to implement "EXPLAIN". ** ** When p->explain==1, each instruction is listed. When ** p->explain==2, only OP_Explain instructions are listed and these ** are shown in a different format. p->explain==2 is used to implement ** EXPLAIN QUERY PLAN. */ int sqlite3VdbeList( Vdbe *p /* The VDBE */ ){ int nRow; /* Total number of rows to return */ int nSub = 0; /* Number of sub-vdbes seen so far */ SubProgram **apSub = 0; /* Array of sub-vdbes */ Mem *pSub = 0; sqlite3 *db = p->db; int i; int rc = SQLITE_OK; Mem *pMem = p->pResultSet = &p->aMem[1]; assert( p->explain ); assert( p->magic==VDBE_MAGIC_RUN ); assert( db->magic==SQLITE_MAGIC_BUSY ); 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); if( p->rc==SQLITE_NOMEM ){ /* This happens if a malloc() inside a call to sqlite3_column_text() or ** sqlite3_column_text16() failed. */ db->mallocFailed = 1; return SQLITE_ERROR; } /* Figure out total number of rows that will be returned by this ** EXPLAIN program. */ nRow = p->nOp; if( p->explain==1 ){ pSub = &p->aMem[9]; if( pSub->flags&MEM_Blob ){ nSub = pSub->n/sizeof(Vdbe*); apSub = (SubProgram **)pSub->z; } for(i=0; i<nSub; i++){ nRow += apSub[i]->nOp; } } do{ i = p->pc++; }while( i<nRow && p->explain==2 && p->aOp[i].opcode!=OP_Explain ); if( i>=nRow ){ p->rc = SQLITE_OK; rc = SQLITE_DONE; }else if( db->u1.isInterrupted ){ p->rc = SQLITE_INTERRUPT; rc = SQLITE_ERROR; sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3ErrStr(p->rc)); }else{ char *z; Op *pOp; if( i<p->nOp ){ pOp = &p->aOp[i]; }else{ int j; i -= p->nOp; for(j=0; i>=apSub[j]->nOp; j++){ i -= apSub[j]->nOp; } pOp = &apSub[j]->aOp[i]; } if( p->explain==1 ){ pMem->flags = MEM_Int; pMem->type = SQLITE_INTEGER; 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->type = SQLITE_TEXT; pMem->enc = SQLITE_UTF8; pMem++; if( 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 && SQLITE_OK==sqlite3VdbeMemGrow(pSub, nByte, 1) ){ apSub = (SubProgram **)pSub->z; apSub[nSub++] = pOp->p4.pProgram; pSub->flags |= MEM_Blob; pSub->n = nSub*sizeof(SubProgram*); } } } pMem->flags = MEM_Int; pMem->u.i = pOp->p1; /* P1 */ pMem->type = SQLITE_INTEGER; pMem++; |
︙ | ︙ | |||
1051 1052 1053 1054 1055 1056 1057 | u8 **ppFrom, /* IN/OUT: Allocate from *ppFrom */ u8 *pEnd, /* Pointer to 1 byte past the end of *ppFrom buffer */ int *pnByte /* If allocation cannot be made, increment *pnByte */ ){ assert( EIGHT_BYTE_ALIGNMENT(*ppFrom) ); if( (*(void**)pp)==0 ){ nByte = ROUND8(nByte); | | | 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 | u8 **ppFrom, /* IN/OUT: Allocate from *ppFrom */ u8 *pEnd, /* Pointer to 1 byte past the end of *ppFrom buffer */ int *pnByte /* If allocation cannot be made, increment *pnByte */ ){ assert( EIGHT_BYTE_ALIGNMENT(*ppFrom) ); if( (*(void**)pp)==0 ){ nByte = ROUND8(nByte); if( &(*ppFrom)[nByte] <= pEnd ){ *(void**)pp = (void *)*ppFrom; *ppFrom += nByte; }else{ *pnByte += nByte; } } } |
︙ | ︙ | |||
1082 1083 1084 1085 1086 1087 1088 | ** is passed -1 and nMem, nCursor and isExplain are all passed zero. */ void sqlite3VdbeMakeReady( Vdbe *p, /* The VDBE */ int nVar, /* Number of '?' see in the SQL statement */ int nMem, /* Number of memory cells to allocate */ int nCursor, /* Number of cursors to allocate */ | > | > | 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 | ** is passed -1 and nMem, nCursor and isExplain are all passed zero. */ void sqlite3VdbeMakeReady( Vdbe *p, /* The VDBE */ int nVar, /* Number of '?' see in the SQL statement */ int nMem, /* Number of memory cells to allocate */ int nCursor, /* Number of cursors to allocate */ int nArg, /* Maximum number of args in SubPrograms */ int isExplain, /* True if the EXPLAIN keywords is present */ int usesStmtJournal /* True to set Vdbe.usesStmtJournal */ ){ int n; sqlite3 *db = p->db; assert( p!=0 ); assert( p->magic==VDBE_MAGIC_INIT ); |
︙ | ︙ | |||
1113 1114 1115 1116 1117 1118 1119 | nMem += nCursor; /* Allocate space for memory registers, SQL variables, VDBE cursors and ** an array to marshal SQL function arguments in. This is only done the ** first time this function is called for a given VDBE, not when it is ** being called from sqlite3_reset() to reset the virtual machine. */ | | < > > < < | | | 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 | nMem += nCursor; /* Allocate space for memory registers, SQL variables, VDBE cursors and ** an array to marshal SQL function arguments in. This is only done the ** first time this function is called for a given VDBE, not when it is ** being called from sqlite3_reset() to reset the virtual machine. */ if( nVar>=0 && ALWAYS(db->mallocFailed==0) ){ u8 *zCsr = (u8 *)&p->aOp[p->nOp]; u8 *zEnd = (u8 *)&p->aOp[p->nOpAlloc]; int nByte; resolveP2Values(p, &nArg); p->usesStmtJournal = (u8)usesStmtJournal; if( isExplain && nMem<10 ){ nMem = 10; } memset(zCsr, 0, zEnd-zCsr); zCsr += (zCsr - (u8*)0)&7; assert( EIGHT_BYTE_ALIGNMENT(zCsr) ); do { nByte = 0; allocSpace((char*)&p->aMem, nMem*sizeof(Mem), &zCsr, zEnd, &nByte); allocSpace((char*)&p->aVar, nVar*sizeof(Mem), &zCsr, zEnd, &nByte); allocSpace((char*)&p->apArg, nArg*sizeof(Mem*), &zCsr, zEnd, &nByte); allocSpace((char*)&p->azVar, nVar*sizeof(char*), &zCsr, zEnd, &nByte); allocSpace((char*)&p->apCsr, nCursor*sizeof(VdbeCursor*), &zCsr, zEnd, &nByte ); if( nByte ){ p->pFree = sqlite3DbMallocZero(db, nByte); } zCsr = p->pFree; zEnd = &zCsr[nByte]; }while( nByte && !db->mallocFailed ); p->nCursor = (u16)nCursor; if( p->aVar ){ p->nVar = (ynVar)nVar; for(n=0; n<nVar; n++){ p->aVar[n].flags = MEM_Null; p->aVar[n].db = db; } } if( p->aMem ){ p->aMem--; /* aMem[] goes from 1..nMem */ |
︙ | ︙ | |||
1212 1213 1214 1215 1216 1217 1218 | p->inVtabMethod = 1; (void)sqlite3SafetyOff(p->db); pModule->xClose(pVtabCursor); (void)sqlite3SafetyOn(p->db); p->inVtabMethod = 0; } #endif | < < | | > > > > > > > > > > > > > > > > | > | | > > > > | > > > > > > > | | > | | | | | | > > > > < < < < < < | < < > > > > > | | < | < < < | 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 | p->inVtabMethod = 1; (void)sqlite3SafetyOff(p->db); pModule->xClose(pVtabCursor); (void)sqlite3SafetyOn(p->db); p->inVtabMethod = 0; } #endif } /* ** 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; 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; v->nChange = pFrame->nChange; return pFrame->pc; } /* ** Close all cursors. ** ** Also release any dynamic memory held by the VM in the Vdbe.aMem memory ** cell array. This is necessary as the memory cell array may contain ** pointers to VdbeFrame objects, which may in turn contain pointers to ** open cursors. */ static void closeAllCursors(Vdbe *p){ if( p->pFrame ){ VdbeFrame *pFrame = p->pFrame; for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent); sqlite3VdbeFrameRestore(pFrame); } p->pFrame = 0; p->nFrame = 0; 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; } } } if( p->aMem ){ releaseMemArray(&p->aMem[1], p->nMem); } } /* ** Clean up the VM after execution. ** ** This routine will automatically close any cursors, lists, and/or ** sorters that were left open. It also deletes the values of ** variables in the aVar[] array. */ static void Cleanup(Vdbe *p){ sqlite3 *db = p->db; #ifdef SQLITE_DEBUG /* Execute assert() statements to ensure that the Vdbe.apCsr[] and ** Vdbe.aMem[] arrays have already been cleaned up. */ int i; for(i=0; i<p->nCursor; i++) assert( p->apCsr==0 || p->apCsr[i]==0 ); for(i=1; i<=p->nMem; i++) assert( p->aMem==0 || p->aMem[i].flags==MEM_Null ); #endif sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = 0; p->pResultSet = 0; } /* ** Set the number of result columns that will be returned by this SQL |
︙ | ︙ | |||
1365 1366 1367 1368 1369 1370 1371 | needXcommit = 1; if( i!=1 ) nTrans++; } } /* If there are any write-transactions at all, invoke the commit hook */ if( needXcommit && db->xCommitCallback ){ | < < < | 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 | needXcommit = 1; if( i!=1 ) nTrans++; } } /* If there are any write-transactions at all, invoke the commit hook */ if( needXcommit && db->xCommitCallback ){ (void)sqlite3SafetyOff(db); rc = db->xCommitCallback(db->pCommitArg); (void)sqlite3SafetyOn(db); if( rc ){ return SQLITE_CONSTRAINT; } } /* The simple case - no more than one database file (not counting the ** TEMP database) has a transaction active. There is no need for the |
︙ | ︙ | |||
1613 1614 1615 1616 1617 1618 1619 | ** ** If an IO error occurs, an SQLITE_IOERR_XXX error code is returned. ** Otherwise SQLITE_OK. */ int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){ sqlite3 *const db = p->db; int rc = SQLITE_OK; | > > > > > > | | 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 | ** ** If an IO error occurs, an SQLITE_IOERR_XXX error code is returned. ** Otherwise SQLITE_OK. */ int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){ sqlite3 *const db = p->db; int rc = SQLITE_OK; /* If p->iStatement is greater than zero, then this Vdbe opened a ** statement transaction that should be closed here. The only exception ** is that an IO error may have occured, causing an emergency rollback. ** In this case (db->nStatement==0), and there is nothing to do. */ if( db->nStatement && p->iStatement ){ int i; const int iSavepoint = p->iStatement-1; assert( eOp==SAVEPOINT_ROLLBACK || eOp==SAVEPOINT_RELEASE); assert( db->nStatement>0 ); assert( p->iStatement==(db->nStatement+db->nSavepoint) ); |
︙ | ︙ | |||
1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 | if( rc==SQLITE_OK ){ rc = rc2; } } } db->nStatement--; p->iStatement = 0; } return rc; } /* ** If SQLite is compiled to support shared-cache mode and to be threadsafe, ** this routine obtains the mutex associated with each BtShared structure | > > > > > > > | 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 | if( rc==SQLITE_OK ){ rc = rc2; } } } db->nStatement--; p->iStatement = 0; /* If the statement transaction is being rolled back, also restore the ** database handles deferred constraint counter to the value it had when ** the statement transaction was opened. */ if( eOp==SAVEPOINT_ROLLBACK ){ db->nDeferredCons = p->nStmtDefCons; } } return rc; } /* ** If SQLite is compiled to support shared-cache mode and to be threadsafe, ** this routine obtains the mutex associated with each BtShared structure |
︙ | ︙ | |||
1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 | sqlite3BtreeMutexArrayEnter(&p->aMutex); #else sqlite3BtreeEnterAll(p->db); #endif } #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 | > > > > > > > > > > > > > > > > > > > > > > > | 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 | sqlite3BtreeMutexArrayEnter(&p->aMutex); #else sqlite3BtreeEnterAll(p->db); #endif } #endif /* ** This function is called when a transaction opened by the database ** handle associated with the VM passed as an argument is about to be ** committed. If there are outstanding deferred foreign key constraint ** violations, return SQLITE_ERROR. Otherwise, SQLITE_OK. ** ** If there are outstanding FK violations and this function returns ** SQLITE_ERROR, set the result of the VM to SQLITE_CONSTRAINT and write ** an error message to it. Then return SQLITE_ERROR. */ #ifndef SQLITE_OMIT_FOREIGN_KEY int sqlite3VdbeCheckFk(Vdbe *p, int deferred){ sqlite3 *db = p->db; if( (deferred && db->nDeferredCons>0) || (!deferred && p->nFkConstraint>0) ){ p->rc = SQLITE_CONSTRAINT; p->errorAction = OE_Abort; sqlite3SetString(&p->zErrMsg, db, "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 |
︙ | ︙ | |||
1705 1706 1707 1708 1709 1710 1711 | ** state. We need to rollback the statement transaction, if there is ** one, or the complete transaction if there is no statement transaction. */ if( p->db->mallocFailed ){ p->rc = SQLITE_NOMEM; } | | > < < < | < > > > > > < > > > > | | > | < > | 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 | ** state. We need to rollback the statement transaction, if there is ** one, or the complete transaction if there is no statement transaction. */ if( p->db->mallocFailed ){ p->rc = SQLITE_NOMEM; } closeAllCursors(p); if( p->magic!=VDBE_MAGIC_RUN ){ return SQLITE_OK; } checkActiveVdbeCnt(db); /* No commit or rollback needed if the program never started */ if( p->pc>=0 ){ 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 */ sqlite3VdbeMutexArrayEnter(p); /* Check for one of the special errors */ mrc = p->rc & 0xff; assert( p->rc!=SQLITE_IOERR_BLOCKED ); /* This error no longer exists */ isSpecialError = mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR || mrc==SQLITE_INTERRUPT || mrc==SQLITE_FULL; if( isSpecialError ){ /* If the query was read-only, we need do no rollback at all. Otherwise, ** proceed with the special handling. */ if( !p->readOnly || mrc!=SQLITE_INTERRUPT ){ if( (mrc==SQLITE_NOMEM || mrc==SQLITE_FULL) && p->usesStmtJournal ){ eStatementOp = SAVEPOINT_ROLLBACK; }else{ /* We are forced to roll back the active transaction. Before doing ** so, abort any other statements this handle currently has active. */ invalidateCursorsOnModifiedBtrees(db); sqlite3RollbackAll(db); sqlite3CloseSavepoints(db); db->autoCommit = 1; } } } /* 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 ** above has occurred. */ if( !sqlite3VtabInSync(db) && db->autoCommit && db->writeVdbeCnt==(p->readOnly==0) ){ if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){ if( sqlite3VdbeCheckFk(p, 1) ){ sqlite3BtreeMutexArrayLeave(&p->aMutex); return SQLITE_ERROR; } /* 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); if( rc==SQLITE_BUSY ){ sqlite3BtreeMutexArrayLeave(&p->aMutex); return SQLITE_BUSY; }else if( rc!=SQLITE_OK ){ p->rc = rc; sqlite3RollbackAll(db); }else{ db->nDeferredCons = 0; sqlite3CommitInternalChanges(db); } }else{ sqlite3RollbackAll(db); } db->nStatement = 0; }else if( eStatementOp==0 ){ |
︙ | ︙ | |||
1808 1809 1810 1811 1812 1813 1814 | p->zErrMsg = 0; } } /* If this was an INSERT, UPDATE or DELETE and no statement transaction ** has been rolled back, update the database connection change-counter. */ | | | 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 | p->zErrMsg = 0; } } /* If this was an INSERT, UPDATE or DELETE and no statement transaction ** has been rolled back, update the database connection change-counter. */ if( p->changeCntOn ){ if( eStatementOp!=SAVEPOINT_ROLLBACK ){ sqlite3VdbeSetChanges(db, p->nChange); }else{ sqlite3VdbeSetChanges(db, 0); } p->nChange = 0; } |
︙ | ︙ | |||
1955 1956 1957 1958 1959 1960 1961 | ** 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 ); | < < | 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 | ** 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; } /* ** Call the destructor for each auxdata entry in pVdbeFunc for which |
︙ | ︙ | |||
1985 1986 1987 1988 1989 1990 1991 | } } /* ** Delete an entire VDBE. */ void sqlite3VdbeDelete(Vdbe *p){ | < | < < < < < < < < < < > > < | 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 | } } /* ** Delete an entire VDBE. */ void sqlite3VdbeDelete(Vdbe *p){ sqlite3 *db; if( NEVER(p==0) ) return; db = p->db; 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; } releaseMemArray(p->aVar, p->nVar); releaseMemArray(p->aColName, p->nResColumn*COLNAME_N); vdbeFreeOpArray(db, p->aOp, p->nOp); sqlite3DbFree(db, p->aLabel); sqlite3DbFree(db, p->aColName); sqlite3DbFree(db, p->zSql); p->magic = VDBE_MAGIC_DEAD; sqlite3DbFree(db, p->pFree); sqlite3DbFree(db, p); } /* ** 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 |
︙ | ︙ | |||
2052 2053 2054 2055 2056 2057 2058 | if( rc ) return rc; } #ifdef SQLITE_TEST sqlite3_search_count++; #endif p->deferredMoveto = 0; p->cacheStatus = CACHE_STALE; | | | 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 | if( rc ) return rc; } #ifdef SQLITE_TEST sqlite3_search_count++; #endif p->deferredMoveto = 0; p->cacheStatus = CACHE_STALE; }else if( ALWAYS(p->pCursor) ){ int hasMoved; int rc = sqlite3BtreeCursorHasMoved(p->pCursor, &hasMoved); if( rc ) return rc; if( hasMoved ){ p->cacheStatus = CACHE_STALE; p->nullRow = 1; } |
︙ | ︙ | |||
2425 2426 2427 2428 2429 2430 2431 | p->pKeyInfo = pKeyInfo; p->nField = pKeyInfo->nField + 1; p->aMem = pMem = (Mem*)&((char*)p)[ROUND8(sizeof(UnpackedRecord))]; assert( EIGHT_BYTE_ALIGNMENT(pMem) ); idx = getVarint32(aKey, szHdr); d = szHdr; u = 0; | | < | 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 | p->pKeyInfo = pKeyInfo; p->nField = pKeyInfo->nField + 1; p->aMem = pMem = (Mem*)&((char*)p)[ROUND8(sizeof(UnpackedRecord))]; assert( EIGHT_BYTE_ALIGNMENT(pMem) ); idx = getVarint32(aKey, szHdr); d = szHdr; u = 0; while( idx<szHdr && u<p->nField && d<=nKey ){ u32 serial_type; idx += getVarint32(&aKey[idx], serial_type); pMem->enc = pKeyInfo->enc; pMem->db = pKeyInfo->db; pMem->flags = 0; pMem->zMalloc = 0; d += sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem); pMem++; u++; |
︙ | ︙ | |||
2453 2454 2455 2456 2457 2458 2459 | void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord *p){ int i; Mem *pMem; assert( p!=0 ); assert( p->flags & UNPACKED_NEED_DESTROY ); for(i=0, pMem=p->aMem; i<p->nField; i++, pMem++){ | | > > > > | < | 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 | void sqlite3VdbeDeleteUnpackedRecord(UnpackedRecord *p){ int i; Mem *pMem; assert( p!=0 ); assert( p->flags & UNPACKED_NEED_DESTROY ); for(i=0, pMem=p->aMem; i<p->nField; i++, pMem++){ /* The unpacked record is always constructed by the ** sqlite3VdbeUnpackRecord() function above, which makes all ** strings and blobs static. And none of the elements are ** ever transformed, so there is never anything to delete. */ if( NEVER(pMem->zMalloc) ) sqlite3VdbeMemRelease(pMem); } if( p->flags & UNPACKED_NEED_FREE ){ sqlite3DbFree(p->pKeyInfo->db, p); } } /* |
︙ | ︙ | |||
2535 2536 2537 2538 2539 2540 2541 | rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i], i<nField ? pKeyInfo->aColl[i] : 0); if( rc!=0 ){ break; } i++; } | > > | | 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 | rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i], i<nField ? pKeyInfo->aColl[i] : 0); if( rc!=0 ){ break; } i++; } /* No memory allocation is ever used on mem1. */ if( NEVER(mem1.zMalloc) ) sqlite3VdbeMemRelease(&mem1); /* If the PREFIX_SEARCH flag is set and all fields except the final ** rowid field were equal, then clear the PREFIX_SEARCH flag and set ** pPKey2->rowid to the value of the rowid field in (pKey1, nKey1). ** This is used by the OP_IsUnique opcode. */ if( (pPKey2->flags & UNPACKED_PREFIX_SEARCH) && i==(pPKey2->nField-1) ){ |
︙ | ︙ | |||
2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 | int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){ i64 nCellKey = 0; int rc; u32 szHdr; /* Size of the header */ u32 typeRowid; /* Serial type of the rowid */ u32 lenRowid; /* Size of the rowid */ Mem m, v; /* Get the size of the index entry. Only indices entries of less ** than 2GiB are support - anything large must be database corruption. ** Any corruption is detected in sqlite3BtreeParseCellPtr(), though, so | > > | > > | > | < < | 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 | int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){ i64 nCellKey = 0; int rc; u32 szHdr; /* Size of the header */ u32 typeRowid; /* Serial type of the rowid */ u32 lenRowid; /* Size of the rowid */ Mem m, v; UNUSED_PARAMETER(db); /* Get the size of the index entry. Only indices entries of less ** than 2GiB are support - anything large must be database corruption. ** Any corruption is detected in sqlite3BtreeParseCellPtr(), though, so ** this code can safely assume that nCellKey is 32-bits */ assert( sqlite3BtreeCursorIsValid(pCur) ); rc = sqlite3BtreeKeySize(pCur, &nCellKey); assert( rc==SQLITE_OK ); /* pCur is always valid so KeySize cannot fail */ assert( (nCellKey & SQLITE_MAX_U32)==(u64)nCellKey ); /* Read in the complete content of the index entry */ memset(&m, 0, sizeof(m)); rc = sqlite3VdbeMemFromBtree(pCur, 0, (int)nCellKey, 1, &m); if( rc ){ return rc; } /* The index entry must begin with a header size */ (void)getVarint32((u8*)m.z, szHdr); |
︙ | ︙ | |||
2629 2630 2631 2632 2633 2634 2635 | testcase( typeRowid==6 ); testcase( typeRowid==8 ); testcase( typeRowid==9 ); if( unlikely(typeRowid<1 || typeRowid>9 || typeRowid==7) ){ goto idx_rowid_corruption; } lenRowid = sqlite3VdbeSerialTypeLen(typeRowid); | | | | | | | < < < | > | > > > | | < < | 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 | testcase( typeRowid==6 ); testcase( typeRowid==8 ); testcase( typeRowid==9 ); if( unlikely(typeRowid<1 || typeRowid>9 || typeRowid==7) ){ goto idx_rowid_corruption; } lenRowid = sqlite3VdbeSerialTypeLen(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.zMalloc!=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, ** or greater than pUnpacked. Return SQLITE_OK on success. ** ** pUnpacked is either created without a rowid or is truncated so that it ** omits the rowid at the end. The rowid at the end of the index entry ** is ignored as well. Hence, this routine only compares the prefixes ** of the keys prior to the final rowid, not the entire key. */ int sqlite3VdbeIdxKeyCompare( VdbeCursor *pC, /* The cursor to compare against */ UnpackedRecord *pUnpacked, /* Unpacked version of key to compare against */ int *res /* Write the comparison result here */ ){ i64 nCellKey = 0; int rc; BtCursor *pCur = pC->pCursor; Mem m; assert( sqlite3BtreeCursorIsValid(pCur) ); rc = sqlite3BtreeKeySize(pCur, &nCellKey); assert( rc==SQLITE_OK ); /* pCur is always valid so KeySize cannot fail */ /* nCellKey will always be between 0 and 0xffffffff because of the say ** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */ if( nCellKey<=0 || nCellKey>0x7fffffff ){ *res = 0; return SQLITE_CORRUPT; } memset(&m, 0, sizeof(m)); rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, (int)nCellKey, 1, &m); if( rc ){ return rc; } assert( pUnpacked->flags & UNPACKED_IGNORE_ROWID ); *res = sqlite3VdbeRecordCompare(m.n, m.z, pUnpacked); sqlite3VdbeMemRelease(&m); |
︙ | ︙ | |||
2731 2732 2733 2734 2735 2736 2737 | /* ** Return the database associated with the Vdbe. */ sqlite3 *sqlite3VdbeDb(Vdbe *v){ return v->db; } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* ** Return the database associated with the Vdbe. */ sqlite3 *sqlite3VdbeDb(Vdbe *v){ return v->db; } /* ** Return a pointer to an sqlite3_value structure containing the value bound ** parameter iVar of VM v. Except, if the value is an SQL NULL, return ** 0 instead. Unless it is NULL, apply affinity aff (one of the SQLITE_AFF_* ** constants) to the value before returning it. ** ** The returned value must be freed by the caller using sqlite3ValueFree(). */ sqlite3_value *sqlite3VdbeGetValue(Vdbe *v, int iVar, u8 aff){ assert( iVar>0 ); if( v ){ Mem *pMem = &v->aVar[iVar-1]; if( 0==(pMem->flags & MEM_Null) ){ sqlite3_value *pRet = sqlite3ValueNew(v->db); if( pRet ){ sqlite3VdbeMemCopy((Mem *)pRet, pMem); sqlite3ValueApplyAffinity(pRet, aff, SQLITE_UTF8); sqlite3VdbeMemStoreType((Mem *)pRet); } return pRet; } } return 0; } /* ** Configure SQL variable iVar so that binding a new value to it signals ** to sqlite3_reoptimize() that re-preparing the statement may result ** in a better query plan. */ void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){ assert( iVar>0 ); if( iVar>32 ){ v->expmask = 0xffffffff; }else{ v->expmask |= ((u32)1 << (iVar-1)); } } |
Changes to src/vdbeblob.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2007 May 1 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains code used to implement incremental BLOB I/O. | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* ** 2007 May 1 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains code used to implement incremental BLOB I/O. */ #include "sqliteInt.h" #include "vdbeInt.h" #ifndef SQLITE_OMIT_INCRBLOB |
︙ | ︙ | |||
62 63 64 65 66 67 68 69 | ** The sqlite3_blob_close() function finalizes the vdbe program, ** which closes the b-tree cursor and (possibly) commits the ** transaction. */ static const VdbeOpList openBlob[] = { {OP_Transaction, 0, 0, 0}, /* 0: Start a transaction */ {OP_VerifyCookie, 0, 0, 0}, /* 1: Check the schema cookie */ | > | < < | | | | | | | | | 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | ** The sqlite3_blob_close() function finalizes the vdbe program, ** which closes the b-tree cursor and (possibly) commits the ** transaction. */ static const VdbeOpList openBlob[] = { {OP_Transaction, 0, 0, 0}, /* 0: Start a transaction */ {OP_VerifyCookie, 0, 0, 0}, /* 1: Check the schema cookie */ {OP_TableLock, 0, 0, 0}, /* 2: Acquire a read or write lock */ /* One of the following two instructions is replaced by an OP_Noop. */ {OP_OpenRead, 0, 0, 0}, /* 3: Open cursor 0 for reading */ {OP_OpenWrite, 0, 0, 0}, /* 4: Open cursor 0 for read/write */ {OP_Variable, 1, 1, 1}, /* 5: Push the rowid to the stack */ {OP_NotExists, 0, 9, 1}, /* 6: Seek the cursor */ {OP_Column, 0, 0, 1}, /* 7 */ {OP_ResultRow, 1, 0, 0}, /* 8 */ {OP_Close, 0, 0, 0}, /* 9 */ {OP_Halt, 0, 0, 0}, /* 10 */ }; Vdbe *v = 0; int rc = SQLITE_OK; char *zErr = 0; Table *pTab; Parse *pParse; |
︙ | ︙ | |||
141 142 143 144 145 146 147 | rc = SQLITE_ERROR; (void)sqlite3SafetyOff(db); sqlite3BtreeLeaveAll(db); goto blob_open_out; } /* If the value is being opened for writing, check that the | > | | < > > > > > > > > > > > > > > > > > > < < | < < < < > > > > > > > > > | > > > > > > | < < | | | | | | | 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 | rc = SQLITE_ERROR; (void)sqlite3SafetyOff(db); sqlite3BtreeLeaveAll(db); goto blob_open_out; } /* If the value is being opened for writing, check that the ** column is not indexed, and that it is not part of a foreign key. ** It is against the rules to open a column to which either of these ** descriptions applies for writing. */ if( flags ){ const char *zFault = 0; Index *pIdx; #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"; } } } } #endif for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int j; for(j=0; j<pIdx->nColumn; j++){ if( pIdx->aiColumn[j]==iCol ){ zFault = "indexed"; } } } if( zFault ){ sqlite3DbFree(db, zErr); zErr = sqlite3MPrintf(db, "cannot open %s column for writing", zFault); rc = SQLITE_ERROR; (void)sqlite3SafetyOff(db); sqlite3BtreeLeaveAll(db); goto blob_open_out; } } v = sqlite3VdbeCreate(db); if( v ){ int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); sqlite3VdbeAddOpList(v, sizeof(openBlob)/sizeof(VdbeOpList), openBlob); flags = !!flags; /* flags = (flags ? 1 : 0); */ /* Configure the OP_Transaction */ sqlite3VdbeChangeP1(v, 0, iDb); sqlite3VdbeChangeP2(v, 0, flags); /* Configure the OP_VerifyCookie */ sqlite3VdbeChangeP1(v, 1, iDb); sqlite3VdbeChangeP2(v, 1, pTab->pSchema->schema_cookie); /* Make sure a mutex is held on the table to be accessed */ sqlite3VdbeUsesBtree(v, iDb); /* Configure the OP_TableLock instruction */ sqlite3VdbeChangeP1(v, 2, iDb); sqlite3VdbeChangeP2(v, 2, pTab->tnum); sqlite3VdbeChangeP3(v, 2, flags); sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT); /* Remove either the OP_OpenWrite or OpenRead. Set the P2 ** parameter of the other to pTab->tnum. */ sqlite3VdbeChangeToNoop(v, 4 - flags, 1); sqlite3VdbeChangeP2(v, 3 + flags, pTab->tnum); sqlite3VdbeChangeP3(v, 3 + flags, iDb); /* Configure the number of columns. Configure the cursor to ** think that the table has one more column than it really ** does. An OP_Column to retrieve this imaginary column will ** always return an SQL NULL. This is useful because it means ** we can invoke OP_Column to fill in the vdbe cursors type ** and offset cache without causing any IO. */ sqlite3VdbeChangeP4(v, 3+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32); sqlite3VdbeChangeP2(v, 7, pTab->nCol); if( !db->mallocFailed ){ sqlite3VdbeMakeReady(v, 1, 1, 1, 0, 0, 0); } } sqlite3BtreeLeaveAll(db); rc = sqlite3SafetyOff(db); if( NEVER(rc!=SQLITE_OK) || db->mallocFailed ){ goto blob_open_out; |
︙ | ︙ |
Changes to src/vdbemem.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** ** This file contains code use to manipulate "Mem" structure. A "Mem" ** 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 | < < | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** ************************************************************************* ** ** This file contains code use to manipulate "Mem" structure. A "Mem" ** 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" /* ** Call sqlite3VdbeMemExpandBlob() on the supplied value (type Mem*) ** P if required. |
︙ | ︙ | |||
266 267 268 269 270 271 272 | /* ** If the memory cell contains a string value that must be freed by ** invoking an external callback, free it now. Calling this function ** does not free any Mem.zMalloc buffer. */ void sqlite3VdbeMemReleaseExternal(Mem *p){ assert( p->db==0 || sqlite3_mutex_held(p->db->mutex) ); | > > > > | > > | 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 | /* ** If the memory cell contains a string value that must be freed by ** invoking an external callback, free it now. Calling this function ** does not free any Mem.zMalloc buffer. */ void sqlite3VdbeMemReleaseExternal(Mem *p){ assert( p->db==0 || sqlite3_mutex_held(p->db->mutex) ); testcase( p->flags & MEM_Agg ); testcase( p->flags & MEM_Dyn ); testcase( p->flags & MEM_RowSet ); testcase( p->flags & MEM_Frame ); if( p->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame) ){ if( p->flags&MEM_Agg ){ sqlite3VdbeMemFinalize(p, p->u.pDef); assert( (p->flags & MEM_Agg)==0 ); sqlite3VdbeMemRelease(p); }else if( p->flags&MEM_Dyn && p->xDel ){ assert( (p->flags&MEM_RowSet)==0 ); p->xDel((void *)p->z); p->xDel = 0; }else if( p->flags&MEM_RowSet ){ sqlite3RowSetClear(p->u.pRowSet); }else if( p->flags&MEM_Frame ){ sqlite3VdbeMemSetNull(p); } } } /* ** Release any memory held by the Mem. This may leave the Mem in an ** inconsistent state, for example with (Mem.z==0) and |
︙ | ︙ | |||
414 415 416 417 418 419 420 | /* 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) ** | | | | > > | > | 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 | /* 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. On x86 hardware, the third term is always ** true and could be omitted. But we leave it in because other ** architectures might behave differently. */ if( pMem->r==(double)pMem->u.i && pMem->u.i>SMALLEST_INT64 && ALWAYS(pMem->u.i<LARGEST_INT64) ){ pMem->flags |= MEM_Int; } } /* ** Convert pMem to type integer. Invalidate any prior representations. */ |
︙ | ︙ | |||
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 | return SQLITE_OK; } /* ** Delete any previous value and set the value stored in *pMem to NULL. */ void sqlite3VdbeMemSetNull(Mem *pMem){ if( pMem->flags & MEM_RowSet ){ sqlite3RowSetClear(pMem->u.pRowSet); } MemSetTypeFlag(pMem, MEM_Null); pMem->type = SQLITE_NULL; } /* ** 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->type = SQLITE_BLOB; pMem->n = 0; if( n<0 ) n = 0; pMem->u.nZero = n; pMem->enc = SQLITE_UTF8; } /* ** Delete any previous value and set the value stored in *pMem to val, ** manifest type INTEGER. */ void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){ | > > > > > > > > > > > | 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 | return SQLITE_OK; } /* ** Delete any previous value and set the value stored in *pMem to NULL. */ void sqlite3VdbeMemSetNull(Mem *pMem){ if( pMem->flags & MEM_Frame ){ sqlite3VdbeFrameDelete(pMem->u.pFrame); } if( pMem->flags & MEM_RowSet ){ sqlite3RowSetClear(pMem->u.pRowSet); } MemSetTypeFlag(pMem, MEM_Null); pMem->type = SQLITE_NULL; } /* ** 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->type = SQLITE_BLOB; pMem->n = 0; if( n<0 ) n = 0; pMem->u.nZero = n; pMem->enc = SQLITE_UTF8; #ifdef SQLITE_OMIT_INCRBLOB sqlite3VdbeMemGrow(pMem, n, 0); if( pMem->z ){ pMem->n = n; memset(pMem->z, 0, n); } #endif } /* ** Delete any previous value and set the value stored in *pMem to val, ** manifest type INTEGER. */ void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){ |
︙ | ︙ | |||
862 863 864 865 866 867 868 869 870 871 872 873 874 875 | int amt, /* Number of bytes to return. */ int key, /* If true, retrieve from the btree key, not data. */ Mem *pMem /* OUT: Return data in this Mem structure. */ ){ char *zData; /* Data from the btree layer */ int available = 0; /* Number of bytes available on the local btree page */ int rc = SQLITE_OK; /* Return code */ /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert() ** that both the BtShared and database handle mutexes are held. */ assert( (pMem->flags & MEM_RowSet)==0 ); if( key ){ zData = (char *)sqlite3BtreeKeyFetch(pCur, &available); }else{ | > > | 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 | int amt, /* Number of bytes to return. */ int key, /* If true, retrieve from the btree key, not data. */ Mem *pMem /* OUT: Return data in this Mem structure. */ ){ char *zData; /* Data from the btree layer */ int available = 0; /* Number of bytes available on the local btree page */ int rc = SQLITE_OK; /* Return code */ assert( sqlite3BtreeCursorIsValid(pCur) ); /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert() ** that both the BtShared and database handle mutexes are held. */ assert( (pMem->flags & MEM_RowSet)==0 ); if( key ){ zData = (char *)sqlite3BtreeKeyFetch(pCur, &available); }else{ |
︙ | ︙ | |||
982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 | sqlite3_value *pVal = 0; if( !pExpr ){ *ppVal = 0; return SQLITE_OK; } op = pExpr->op; if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){ pVal = sqlite3ValueNew(db); if( pVal==0 ) goto no_mem; if( ExprHasProperty(pExpr, EP_IntValue) ){ sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue); }else{ zVal = sqlite3DbStrDup(db, pExpr->u.zToken); if( zVal==0 ) goto no_mem; sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC); } if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_NONE ){ sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8); }else{ sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8); } if( enc!=SQLITE_UTF8 ){ | > > > > | 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 | sqlite3_value *pVal = 0; if( !pExpr ){ *ppVal = 0; return SQLITE_OK; } op = pExpr->op; if( op==TK_REGISTER ){ op = pExpr->op2; /* This only happens with SQLITE_ENABLE_STAT2 */ } if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){ pVal = sqlite3ValueNew(db); if( pVal==0 ) goto no_mem; if( ExprHasProperty(pExpr, EP_IntValue) ){ sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue); }else{ zVal = sqlite3DbStrDup(db, pExpr->u.zToken); if( zVal==0 ) goto no_mem; sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC); if( op==TK_FLOAT ) pVal->type = SQLITE_FLOAT; } if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_NONE ){ sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8); }else{ sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8); } if( enc!=SQLITE_UTF8 ){ |
︙ | ︙ | |||
1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 | nVal = sqlite3Strlen30(zVal)-1; assert( zVal[nVal]=='\'' ); sqlite3VdbeMemSetStr(pVal, sqlite3HexToBlob(db, zVal, nVal), nVal/2, 0, SQLITE_DYNAMIC); } #endif *ppVal = pVal; return SQLITE_OK; no_mem: db->mallocFailed = 1; sqlite3DbFree(db, zVal); sqlite3ValueFree(pVal); | > > > | 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 | nVal = sqlite3Strlen30(zVal)-1; assert( zVal[nVal]=='\'' ); sqlite3VdbeMemSetStr(pVal, sqlite3HexToBlob(db, zVal, nVal), nVal/2, 0, SQLITE_DYNAMIC); } #endif if( pVal ){ sqlite3VdbeMemStoreType(pVal); } *ppVal = pVal; return SQLITE_OK; no_mem: db->mallocFailed = 1; sqlite3DbFree(db, zVal); sqlite3ValueFree(pVal); |
︙ | ︙ |
Changes to src/vtab.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 2006 June 10 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to help implement virtual tables. | < < | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | /* ** 2006 June 10 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to help implement virtual tables. */ #ifndef SQLITE_OMIT_VIRTUALTABLE #include "sqliteInt.h" /* ** 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, nName; Module *pMod; sqlite3_mutex_enter(db->mutex); nName = sqlite3Strlen30(zName); pMod = (Module *)sqlite3DbMallocRaw(db, sizeof(Module) + nName + 1); if( pMod ){ |
︙ | ︙ | |||
89 90 91 92 93 94 95 | ** 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. */ | | | > > > > > > > > > > > > > | | | | | < | < | > > | > > | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < | < < < < | | | 87 88 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 | ** 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. */ void sqlite3VtabLock(VTable *pVTab){ pVTab->nRef++; } /* ** 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( sqlite3SafetyCheckOk(db) ); pVTab->nRef--; if( pVTab->nRef==0 ){ sqlite3_vtab *p = pVTab->pVtab; if( p ){ #ifdef SQLITE_DEBUG if( pVTab->db->magic==SQLITE_MAGIC_BUSY ){ (void)sqlite3SafetyOff(db); p->pModule->xDisconnect(p); (void)sqlite3SafetyOn(db); } else #endif { 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 || sqlite3BtreeHoldsMutex(db->aDb[sqlite3SchemaToIndex(db, p->pSchema)].pBt) ); 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; } assert( !db || pRet ); return pRet; } /* ** Disconnect all the virtual table objects in the sqlite3.pDisconnect list. ** ** This function may only be called when the mutexes associated with all ** shared b-tree databases opened using connection db are held by the ** caller. This is done to protect the sqlite3.pDisconnect list. The ** sqlite3.pDisconnect list is accessed only as follows: ** ** 1) By this function. In this case, all BtShared mutexes and the mutex ** associated with the database handle itself must be held. ** ** 2) By function vtabDisconnectAll(), when it adds a VTable entry to ** the sqlite3.pDisconnect list. In this case either the BtShared mutex ** associated with the database the virtual table is stored in is held ** or, if the virtual table is stored in a non-sharable database, then ** 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); do { VTable *pNext = p->pNext; sqlite3VtabUnlock(p); p = pNext; }while( p ); } } /* ** Clear any and all virtual-table information from the Table record. ** This routine is called, for example, just before deleting the Table ** record. ** ** Since it is a virtual-table, the Table structure contains a pointer ** to the head of a linked list of VTable structures. Each VTable ** structure is associated with a single sqlite3* user of the schema. ** 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(Table *p){ vtabDisconnectAll(0, p); if( p->azModuleArg ){ int i; for(i=0; i<p->nModuleArg; i++){ sqlite3DbFree(p->dbMem, p->azModuleArg[i]); } sqlite3DbFree(p->dbMem, 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 |
︙ | ︙ | |||
183 184 185 186 187 188 189 | Token *pName2, /* Name of new table or NULL */ Token *pModuleName /* Name of the module for the virtual table */ ){ int iDb; /* The database the table is being created in */ Table *pTable; /* The new virtual table */ sqlite3 *db; /* Database connection */ | < < < < < | 278 279 280 281 282 283 284 285 286 287 288 289 290 291 | Token *pName2, /* Name of new table or NULL */ Token *pModuleName /* Name of the module for the virtual table */ ){ int iDb; /* The database the table is being created in */ Table *pTable; /* The new virtual table */ sqlite3 *db; /* Database connection */ sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, 0); pTable = pParse->pNewTable; if( pTable==0 ) return; assert( 0==pTable->pIndex ); db = pParse->db; iDb = sqlite3SchemaToIndex(db, pTable->pSchema); |
︙ | ︙ | |||
236 237 238 239 240 241 242 | } /* ** The parser calls this routine after the CREATE VIRTUAL TABLE statement ** has been completely parsed. */ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ | | | < < > < < < < < < < < < | 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 | } /* ** The parser calls this routine after the CREATE VIRTUAL TABLE statement ** has been completely parsed. */ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){ Table *pTab = pParse->pNewTable; /* The table being constructed */ sqlite3 *db = pParse->db; /* The database connection */ if( pTab==0 ) return; 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. */ |
︙ | ︙ | |||
303 304 305 306 307 308 309 | zWhere = sqlite3MPrintf(db, "name='%q'", pTab->zName); sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 1, 0, zWhere, P4_DYNAMIC); sqlite3VdbeAddOp4(v, OP_VCreate, iDb, 0, 0, pTab->zName, sqlite3Strlen30(pTab->zName) + 1); } /* If we are rereading the sqlite_master table create the in-memory | | | | > | 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 | zWhere = sqlite3MPrintf(db, "name='%q'", pTab->zName); sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 1, 0, zWhere, P4_DYNAMIC); sqlite3VdbeAddOp4(v, OP_VCreate, iDb, 0, 0, pTab->zName, sqlite3Strlen30(pTab->zName) + 1); } /* 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; int nName = sqlite3Strlen30(zName); pOld = sqlite3HashInsert(&pSchema->tblHash, zName, nName, pTab); if( pOld ){ |
︙ | ︙ | |||
359 360 361 362 363 364 365 366 | static int vtabCallConstructor( sqlite3 *db, Table *pTab, Module *pMod, int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**), char **pzErr ){ int rc; | > < < > > > > > > > > < > > | < | | < < < < < < < > > > > > > | | | > | | < < < < < | | > | | | > > | < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > > > | | > | > > | < | | | | | | | | > | > | | | | 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 | static int vtabCallConstructor( sqlite3 *db, Table *pTab, Module *pMod, int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**), char **pzErr ){ VTable *pVTable; int rc; const char *const*azArg = (const char *const*)pTab->azModuleArg; int nArg = pTab->nModuleArg; char *zErr = 0; char *zModuleName = sqlite3MPrintf(db, "%s", pTab->zName); if( !zModuleName ){ return SQLITE_NOMEM; } pVTable = sqlite3DbMallocZero(db, sizeof(VTable)); if( !pVTable ){ sqlite3DbFree(db, zModuleName); return SQLITE_NOMEM; } pVTable->db = db; pVTable->pMod = pMod; assert( !db->pVTab ); assert( xConstruct ); db->pVTab = pTab; /* Invoke the virtual table constructor */ (void)sqlite3SafetyOff(db); rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr); (void)sqlite3SafetyOn(db); if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; if( SQLITE_OK!=rc ){ if( zErr==0 ){ *pzErr = sqlite3MPrintf(db, "vtable constructor failed: %s", zModuleName); }else { *pzErr = sqlite3MPrintf(db, "%s", zErr); sqlite3DbFree(db, zErr); } sqlite3DbFree(db, pVTable); }else if( ALWAYS(pVTable->pVtab) ){ /* Justification of ALWAYS(): A correct vtab constructor must allocate ** the sqlite3_vtab object if successful. */ pVTable->pVtab->pModule = pMod->pModule; pVTable->nRef = 1; if( db->pVTab ){ const char *zFormat = "vtable constructor did not declare schema: %s"; *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName); sqlite3VtabUnlock(pVTable); rc = SQLITE_ERROR; }else{ int iCol; /* 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.isHidden 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 = pTab->aCol[iCol].zType; int nType; int i = 0; if( !zType ) continue; nType = sqlite3Strlen30(zType); if( sqlite3StrNICmp("hidden", zType, 6)||(zType[6] && zType[6]!=' ') ){ for(i=0; i<nType; i++){ if( (0==sqlite3StrNICmp(" hidden", &zType[i], 7)) && (zType[i+7]=='\0' || zType[i+7]==' ') ){ i++; break; } } } if( i<nType ){ int j; int nDel = 6 + (zType[i+6] ? 1 : 0); for(j=i; (j+nDel)<=nType; j++){ zType[j] = zType[j+nDel]; } if( zType[i]=='\0' && i>0 ){ assert(zType[i-1]==' '); zType[i-1] = '\0'; } pTab->aCol[iCol].isHidden = 1; } } } } sqlite3DbFree(db, zModuleName); db->pVTab = 0; return rc; } /* ** This function is invoked by the parser to call the xConnect() method ** of the virtual table pTab. If an error occurs, an error code is returned ** and an error left in pParse. ** ** This call is a no-op if table pTab is not a virtual table. */ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){ sqlite3 *db = pParse->db; const char *zMod; Module *pMod; int rc; assert( pTab ); if( (pTab->tabFlags & TF_Virtual)==0 || sqlite3GetVTable(db, pTab) ){ return SQLITE_OK; } /* Locate the required virtual table module */ zMod = pTab->azModuleArg[0]; pMod = (Module*)sqlite3HashFind(&db->aModule, zMod, sqlite3Strlen30(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); } sqlite3DbFree(db, zErr); } return rc; } /* ** Add the virtual table pVTab to the array sqlite3.aVTrans[]. */ static int addToVTrans(sqlite3 *db, VTable *pVTab){ const int ARRAY_INCR = 5; /* Grow the sqlite3.aVTrans array if required */ if( (db->nVTrans%ARRAY_INCR)==0 ){ VTable **aVTrans; int nBytes = sizeof(sqlite3_vtab *) * (db->nVTrans + ARRAY_INCR); aVTrans = sqlite3DbRealloc(db, (void *)db->aVTrans, nBytes); if( !aVTrans ){ return SQLITE_NOMEM; } memset(&aVTrans[db->nVTrans], 0, sizeof(sqlite3_vtab *)*ARRAY_INCR); db->aVTrans = aVTrans; } /* Add pVtab to the end of sqlite3.aVTrans */ db->aVTrans[db->nVTrans++] = pVTab; sqlite3VtabLock(pVTab); return SQLITE_OK; } /* ** This function is invoked by the vdbe to call the xCreate method ** of the virtual table named zTab in database iDb. ** ** If an error occurs, *pzErr is set to point an an English language ** description of the error and an SQLITE_XXX error code is returned. ** In this case the caller must call sqlite3DbFree(db, ) on *pzErr. */ 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].zName); assert( pTab && (pTab->tabFlags & TF_Virtual)!=0 && !pTab->pVTable ); /* Locate the required virtual table module */ zMod = pTab->azModuleArg[0]; pMod = (Module*)sqlite3HashFind(&db->aModule, zMod, sqlite3Strlen30(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 ){ *pzErr = sqlite3MPrintf(db, "no such module: %s", zMod); rc = SQLITE_ERROR; }else{ rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xCreate, pzErr); } /* Justification of ALWAYS(): The xConstructor method is required to ** create a valid sqlite3_vtab if it returns SQLITE_OK. */ if( rc==SQLITE_OK && ALWAYS(sqlite3GetVTable(db, pTab)) ){ rc = addToVTrans(db, sqlite3GetVTable(db, pTab)); } return rc; } /* ** This function is used to set the schema of a virtual table. It is only |
︙ | ︙ | |||
562 563 564 565 566 567 568 | sqlite3_mutex_enter(db->mutex); pTab = db->pVTab; if( !pTab ){ sqlite3Error(db, SQLITE_MISUSE, 0); sqlite3_mutex_leave(db->mutex); return SQLITE_MISUSE; } | | > | | | | > | 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 | sqlite3_mutex_enter(db->mutex); pTab = db->pVTab; if( !pTab ){ sqlite3Error(db, SQLITE_MISUSE, 0); sqlite3_mutex_leave(db->mutex); return SQLITE_MISUSE; } assert( (pTab->tabFlags & TF_Virtual)!=0 ); pParse = sqlite3StackAllocZero(db, sizeof(*pParse)); if( pParse==0 ){ rc = SQLITE_NOMEM; }else{ pParse->declareVtab = 1; pParse->db = db; if( SQLITE_OK == sqlite3RunParser(pParse, zCreateTable, &zErr) && pParse->pNewTable && !pParse->pNewTable->pSelect && (pParse->pNewTable->tabFlags & TF_Virtual)==0 ){ if( !pTab->aCol ){ pTab->aCol = pParse->pNewTable->aCol; pTab->nCol = pParse->pNewTable->nCol; pParse->pNewTable->nCol = 0; pParse->pNewTable->aCol = 0; } db->pVTab = 0; } else { sqlite3Error(db, SQLITE_ERROR, zErr); sqlite3DbFree(db, zErr); rc = SQLITE_ERROR; } pParse->declareVtab = 0; |
︙ | ︙ | |||
614 615 616 617 618 619 620 | ** 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].zName); | | > | | > > < < | < < < < | > > | > > | < < | | > | | < | | < | 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 | ** 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].zName); if( ALWAYS(pTab!=0 && pTab->pVTable!=0) ){ VTable *p = vtabDisconnectAll(db, pTab); rc = sqlite3SafetyOff(db); assert( rc==SQLITE_OK ); rc = p->pMod->pModule->xDestroy(p->pVtab); (void)sqlite3SafetyOn(db); /* 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 ** of each of the virtual tables in the sqlite3.aVTrans array. The method ** called is identified by the second argument, "offset", which is ** the offset of the method to call in the sqlite3_module structure. ** ** The array is cleared after invoking the callbacks. */ static void callFinaliser(sqlite3 *db, int offset){ int i; if( db->aVTrans ){ for(i=0; i<db->nVTrans; i++){ VTable *pVTab = db->aVTrans[i]; sqlite3_vtab *p = pVTab->pVtab; if( p ){ int (*x)(sqlite3_vtab *); x = *(int (**)(sqlite3_vtab *))((char *)p->pModule + offset); if( x ) x(p); } sqlite3VtabUnlock(pVTab); } sqlite3DbFree(db, db->aVTrans); db->nVTrans = 0; db->aVTrans = 0; } } /* ** Invoke the xSync method of all virtual tables in the sqlite3.aVTrans ** array. Return the error code for the first error that occurs, or ** SQLITE_OK if all xSync operations are successful. ** ** Set *pzErrmsg to point to a buffer that should be released using ** sqlite3DbFree() containing an error message, if one is available. */ int sqlite3VtabSync(sqlite3 *db, char **pzErrmsg){ int i; int rc = SQLITE_OK; int rcsafety; VTable **aVTrans = db->aVTrans; rc = sqlite3SafetyOff(db); db->aVTrans = 0; for(i=0; rc==SQLITE_OK && i<db->nVTrans; i++){ int (*x)(sqlite3_vtab *); sqlite3_vtab *pVtab = aVTrans[i]->pVtab; if( pVtab && (x = pVtab->pModule->xSync)!=0 ){ rc = x(pVtab); sqlite3DbFree(db, *pzErrmsg); *pzErrmsg = pVtab->zErrMsg; pVtab->zErrMsg = 0; } } db->aVTrans = aVTrans; |
︙ | ︙ | |||
724 725 726 727 728 729 730 | ** If the virtual table pVtab supports the transaction interface ** (xBegin/xRollback/xCommit and optionally xSync) and a transaction is ** not currently open, invoke the xBegin method now. ** ** If the xBegin call is successful, place the sqlite3_vtab pointer ** in the sqlite3.aVTrans array. */ | | | | | | | | 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 | ** If the virtual table pVtab supports the transaction interface ** (xBegin/xRollback/xCommit and optionally xSync) and a transaction is ** not currently open, invoke the xBegin method now. ** ** If the xBegin call is successful, place the sqlite3_vtab pointer ** in the sqlite3.aVTrans array. */ int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){ int rc = SQLITE_OK; const sqlite3_module *pModule; /* Special case: If db->aVTrans is NULL and db->nVTrans is greater ** than zero, then this function is being called from within a ** virtual module xSync() callback. It is illegal to write to ** virtual module tables in this case, so return SQLITE_LOCKED. */ if( sqlite3VtabInSync(db) ){ return SQLITE_LOCKED; } if( !pVTab ){ return SQLITE_OK; } pModule = pVTab->pVtab->pModule; if( pModule->xBegin ){ int i; /* If pVtab is already in the aVTrans array, return early */ for(i=0; i<db->nVTrans; i++){ if( db->aVTrans[i]==pVTab ){ return SQLITE_OK; } } /* Invoke the xBegin method */ rc = pModule->xBegin(pVTab->pVtab); if( rc==SQLITE_OK ){ rc = addToVTrans(db, pVTab); } } return rc; } /* ** The first parameter (pDef) is a function implementation. The |
︙ | ︙ | |||
797 798 799 800 801 802 803 | /* 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->pTab; if( NEVER(pTab==0) ) return pDef; if( (pTab->tabFlags & TF_Virtual)==0 ) return pDef; | | | 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 | /* 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->pTab; if( NEVER(pTab==0) ) return pDef; if( (pTab->tabFlags & TF_Virtual)==0 ) 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; /* Call the xFindFunction method on the virtual table implementation ** to see if the implementation wants to overload this function |
︙ | ︙ | |||
821 822 823 824 825 826 827 | if( rc==0 ){ return pDef; } /* Create a new ephemeral function definition for the overloaded ** function */ pNew = sqlite3DbMallocZero(db, sizeof(*pNew) | | > | | | | | | | | 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 | if( rc==0 ){ return pDef; } /* Create a new ephemeral function definition for the overloaded ** function */ pNew = sqlite3DbMallocZero(db, sizeof(*pNew) + sqlite3Strlen30(pDef->zName) + 1); if( pNew==0 ){ return pDef; } *pNew = *pDef; pNew->zName = (char *)&pNew[1]; memcpy(pNew->zName, pDef->zName, sqlite3Strlen30(pDef->zName)+1); pNew->xFunc = xFunc; pNew->pUserData = pArg; pNew->flags |= SQLITE_FUNC_EPHEM; return pNew; } /* ** Make sure virtual table pTab is contained in the pParse->apVirtualLock[] ** array so that an OP_VBegin will get generated for it. Add pTab to the ** array if it is missing. If pTab is already in the array, this routine ** is a no-op. */ void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){ Parse *pToplevel = sqlite3ParseToplevel(pParse); int i, n; 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_realloc(pToplevel->apVtabLock, n); if( apVtabLock ){ pToplevel->apVtabLock = apVtabLock; pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab; }else{ pToplevel->db->mallocFailed = 1; } } #endif /* SQLITE_OMIT_VIRTUALTABLE */ |
Changes to src/walker.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2008 August 16 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for walking the parser tree for ** an SQL statement. | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* ** 2008 August 16 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for walking the parser tree for ** an SQL statement. */ #include "sqliteInt.h" #include <stdlib.h> #include <string.h> /* |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ************************************************************************* ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. This module is responsible for ** generating the code that loops through a table looking for applicable ** rows. Indices are selected and used to speed the search when doing ** so is applicable. Because this module is responsible for selecting ** indices, you might also think of this module as the "query optimizer". | < < | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ************************************************************************* ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. This module is responsible for ** generating the code that loops through a table looking for applicable ** rows. Indices are selected and used to speed the search when doing ** so is applicable. Because this module is responsible for selecting ** indices, you might also think of this module as the "query optimizer". */ #include "sqliteInt.h" /* ** Trace output macros */ #if defined(SQLITE_TEST) || defined(SQLITE_DEBUG) |
︙ | ︙ | |||
191 192 193 194 195 196 197 198 199 200 201 202 203 204 | ** A WhereCost object records a lookup strategy and the estimated ** cost of pursuing that strategy. */ struct WhereCost { WherePlan plan; /* The lookup strategy */ double rCost; /* Overall cost of pursuing this search strategy */ double nRow; /* Estimated number of output rows */ }; /* ** Bitmasks for the operators that indices are able to exploit. An ** OR-ed combination of these values can be used when searching for ** terms in the where clause. */ | > | 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | ** A WhereCost object records a lookup strategy and the estimated ** cost of pursuing that strategy. */ struct WhereCost { WherePlan plan; /* The lookup strategy */ double rCost; /* Overall cost of pursuing this search strategy */ double nRow; /* Estimated number of output rows */ Bitmask used; /* Bitmask of cursors used by this plan */ }; /* ** Bitmasks for the operators that indices are able to exploit. An ** OR-ed combination of these values can be used when searching for ** terms in the where clause. */ |
︙ | ︙ | |||
620 621 622 623 624 625 626 | ** ** In order for the operator to be optimizible, the RHS must be a string ** literal that does not begin with a wildcard. */ static int isLikeOrGlob( Parse *pParse, /* Parsing and code generating context */ Expr *pExpr, /* Test this expression */ | | | > > < < < < | > > > | < > > > > > > > | > > > > > > > > > > > > > > | > | > > > | > > > > > > > > > > > > > > > > | > > > | | 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 | ** ** In order for the operator to be optimizible, the RHS must be a string ** literal that does not begin with a wildcard. */ static int isLikeOrGlob( Parse *pParse, /* Parsing and code generating context */ Expr *pExpr, /* Test this expression */ Expr **ppPrefix, /* Pointer to TK_STRING expression with pattern prefix */ int *pisComplete, /* True if the only wildcard is % in the last character */ int *pnoCase /* True if uppercase is equivalent to lowercase */ ){ const char *z = 0; /* String on RHS of LIKE operator */ Expr *pRight, *pLeft; /* Right and left size of LIKE operator */ ExprList *pList; /* List of operands to the LIKE operator */ int c; /* One character in z[] */ int cnt; /* Number of non-wildcard prefix characters */ char wc[3]; /* Wildcard characters */ CollSeq *pColl; /* Collating sequence for LHS */ sqlite3 *db = pParse->db; /* Database connection */ sqlite3_value *pVal = 0; int op; /* Opcode of pRight */ if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, wc) ){ return 0; } #ifdef SQLITE_EBCDIC if( *pnoCase ) return 0; #endif pList = pExpr->x.pList; pLeft = pList->a[1].pExpr; if( pLeft->op!=TK_COLUMN || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT ){ /* IMP: R-02065-49465 The left-hand side of the LIKE or GLOB operator must ** be the name of an indexed column with TEXT affinity. */ return 0; } assert( pLeft->iColumn!=(-1) ); /* Because IPK never has AFF_TEXT */ pColl = sqlite3ExprCollSeq(pParse, pLeft); assert( pColl!=0 ); /* Every non-IPK column has a collating sequence */ if( (pColl->type!=SQLITE_COLL_BINARY || *pnoCase) && (pColl->type!=SQLITE_COLL_NOCASE || !*pnoCase) ){ /* IMP: R-09003-32046 For the GLOB operator, the column must use the ** default BINARY collating sequence. ** IMP: R-41408-28306 For the LIKE operator, if case_sensitive_like mode ** is enabled then the column must use the default BINARY collating ** sequence, or if case_sensitive_like mode is disabled then the column ** must use the built-in NOCASE collating sequence. */ return 0; } pRight = pList->a[0].pExpr; op = pRight->op; if( op==TK_REGISTER ){ op = pRight->op2; } if( op==TK_VARIABLE ){ Vdbe *pReprepare = pParse->pReprepare; pVal = sqlite3VdbeGetValue(pReprepare, pRight->iColumn, SQLITE_AFF_NONE); if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){ z = (char *)sqlite3_value_text(pVal); } sqlite3VdbeSetVarmask(pParse->pVdbe, pRight->iColumn); assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER ); }else if( op==TK_STRING ){ z = pRight->u.zToken; } if( z ){ cnt = 0; while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){ cnt++; } if( cnt!=0 && c!=0 && 255!=(u8)z[cnt-1] ){ Expr *pPrefix; *pisComplete = z[cnt]==wc[0] && z[cnt+1]==0; pPrefix = sqlite3Expr(db, TK_STRING, z); if( pPrefix ) pPrefix->u.zToken[cnt] = 0; *ppPrefix = pPrefix; 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 workaround them, add a dummy OP_Variable here. */ int r1 = sqlite3GetTempReg(pParse); sqlite3ExprCodeTarget(pParse, pRight, r1); sqlite3VdbeChangeP3(v, sqlite3VdbeCurrentAddr(v)-1, 0); sqlite3ReleaseTempReg(pParse, r1); } } }else{ z = 0; } } sqlite3ValueFree(pVal); return (z!=0); } #endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Check to see if the given expression is of the form |
︙ | ︙ | |||
1049 1050 1051 1052 1053 1054 1055 | int idxTerm /* Index of the term to be analyzed */ ){ WhereTerm *pTerm; /* The term to be analyzed */ WhereMaskSet *pMaskSet; /* Set of table index masks */ Expr *pExpr; /* The expression to be analyzed */ Bitmask prereqLeft; /* Prerequesites of the pExpr->pLeft */ Bitmask prereqAll; /* Prerequesites of pExpr */ | | | | | | 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 | int idxTerm /* Index of the term to be analyzed */ ){ WhereTerm *pTerm; /* The term to be analyzed */ WhereMaskSet *pMaskSet; /* Set of table index masks */ Expr *pExpr; /* The expression to be analyzed */ Bitmask prereqLeft; /* Prerequesites of the pExpr->pLeft */ Bitmask prereqAll; /* Prerequesites of pExpr */ Bitmask extraRight = 0; /* */ Expr *pStr1 = 0; /* RHS of LIKE/GLOB operator */ int isComplete = 0; /* RHS of LIKE/GLOB ends with wildcard */ int noCase = 0; /* LIKE/GLOB distinguishes case */ int op; /* Top-level operator. pExpr->op */ Parse *pParse = pWC->pParse; /* Parsing context */ sqlite3 *db = pParse->db; /* Database connection */ if( db->mallocFailed ){ return; } |
︙ | ︙ | |||
1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 | #if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY) /* Analyze a term that is composed of two or more subterms connected by ** an OR operator. */ else if( pExpr->op==TK_OR ){ assert( pWC->op==TK_AND ); exprAnalyzeOrTerm(pSrc, pWC, 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". */ | > < | > > | > | | | > < < < | | 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 | #if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY) /* Analyze a term that is composed of two or more subterms connected by ** an OR operator. */ 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( 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; pLeft = pExpr->x.pList->a[1].pExpr; pStr2 = sqlite3ExprDup(db, pStr1, 0); if( !db->mallocFailed ){ u8 c, *pC; /* Last character before the first wildcard */ pC = (u8*)&pStr2->u.zToken[sqlite3Strlen30(pStr2->u.zToken)-1]; c = *pC; if( noCase ){ /* The point is to increment the last character before the first ** wildcard. But if we increment '@', that will push it into the ** alphabetic range where case conversions will mess up the ** inequality. To avoid this, make sure to also run the full ** LIKE on all candidate expressions by clearing the isComplete flag |
︙ | ︙ | |||
1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 | struct ExprList_item *pTerm; /* A term of the ORDER BY clause */ sqlite3 *db = pParse->db; assert( pOrderBy!=0 ); nTerm = pOrderBy->nExpr; assert( nTerm>0 ); /* Match terms of the ORDER BY clause against columns of ** the index. ** ** Note that indices have pIdx->nColumn regular columns plus ** one additional column containing the rowid. The rowid column ** of the index is also allowed to match against the ORDER BY ** clause. | > > > > > | 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 | struct ExprList_item *pTerm; /* A term of the ORDER BY clause */ sqlite3 *db = pParse->db; assert( pOrderBy!=0 ); nTerm = pOrderBy->nExpr; assert( nTerm>0 ); /* Argument pIdx must either point to a 'real' named index structure, ** or an index structure allocated on the stack by bestBtreeIndex() to ** represent the rowid index that is part of every table. */ assert( pIdx->zName || (pIdx->nColumn==1 && pIdx->aiColumn[0]==-1) ); /* Match terms of the ORDER BY clause against columns of ** the index. ** ** Note that indices have pIdx->nColumn regular columns plus ** one additional column containing the rowid. The rowid column ** of the index is also allowed to match against the ORDER BY ** clause. |
︙ | ︙ | |||
1359 1360 1361 1362 1363 1364 1365 | ** left-most table of the FROM clause */ break; } pColl = sqlite3ExprCollSeq(pParse, pExpr); if( !pColl ){ pColl = db->pDfltColl; } | | | 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 | ** left-most table of the FROM clause */ break; } pColl = sqlite3ExprCollSeq(pParse, pExpr); if( !pColl ){ pColl = db->pDfltColl; } if( pIdx->zName && i<pIdx->nColumn ){ iColumn = pIdx->aiColumn[i]; if( iColumn==pIdx->pTable->iPKey ){ iColumn = -1; } iSortOrder = pIdx->aSortOrder[i]; zColl = pIdx->azColl[i]; }else{ |
︙ | ︙ | |||
1388 1389 1390 1391 1392 1393 1394 | }else{ /* If an index column fails to match and is not constrained by == ** then the index cannot satisfy the ORDER BY constraint. */ return 0; } } | | | 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 | }else{ /* If an index column fails to match and is not constrained by == ** then the index cannot satisfy the ORDER BY constraint. */ return 0; } } assert( pIdx->aSortOrder!=0 || iColumn==-1 ); assert( pTerm->sortOrder==0 || pTerm->sortOrder==1 ); assert( iSortOrder==0 || iSortOrder==1 ); termSortOrder = iSortOrder ^ pTerm->sortOrder; if( i>nEqCol ){ if( termSortOrder!=sortOrder ){ /* Indices can only be used if all ORDER BY terms past the ** equality constraints are all either DESC or ASC. */ |
︙ | ︙ | |||
1428 1429 1430 1431 1432 1433 1434 | && !referencesOtherTables(pOrderBy, pMaskSet, j, base) ){ /* All terms of this index match some prefix of the ORDER BY clause ** and the index is UNIQUE and no terms on the tail of the ORDER BY ** clause reference other tables in a join. If this is all true then ** the order by clause is superfluous. */ return 1; } | < < < < < < < < < < < < < < < < < < < < < < < < | 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 | && !referencesOtherTables(pOrderBy, pMaskSet, j, base) ){ /* All terms of this index match some prefix of the ORDER BY clause ** and the index is UNIQUE and no terms on the tail of the ORDER BY ** clause reference other tables in a join. If this is all true then ** the order by clause is superfluous. */ return 1; } return 0; } /* ** Prepare a crude estimate of the logarithm of the input value. ** The results need not be exact. This is only used for estimating ** the total cost of performing operations with O(logN) or O(NlogN) |
︙ | ︙ | |||
1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 | ){ WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc; WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm]; WhereTerm *pOrTerm; int flags = WHERE_MULTI_OR; double rTotal = 0; double nRow = 0; for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){ WhereCost sTermCost; WHERETRACE(("... Multi-index OR testing for term %d of %d....\n", (pOrTerm - pOrWC->a), (pTerm - pWC->a) )); if( pOrTerm->eOperator==WO_AND ){ | > | 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 | ){ WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc; WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm]; WhereTerm *pOrTerm; int flags = WHERE_MULTI_OR; double rTotal = 0; double nRow = 0; Bitmask used = 0; for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){ WhereCost sTermCost; WHERETRACE(("... Multi-index OR testing for term %d of %d....\n", (pOrTerm - pOrWC->a), (pTerm - pWC->a) )); if( pOrTerm->eOperator==WO_AND ){ |
︙ | ︙ | |||
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 | tempWC.nTerm = 1; bestIndex(pParse, &tempWC, pSrc, notReady, 0, &sTermCost); }else{ continue; } rTotal += sTermCost.rCost; nRow += sTermCost.nRow; if( rTotal>=pCost->rCost ) break; } /* If there is an ORDER BY clause, increase the scan cost to account ** for the cost of the sort. */ if( pOrderBy!=0 ){ rTotal += nRow*estLog(nRow); WHERETRACE(("... sorting increases OR cost to %.9g\n", rTotal)); } /* If the cost of scanning using this OR term for optimization is ** less than the current cost stored in pCost, replace the contents ** of pCost. */ WHERETRACE(("... multi-index OR cost=%.9g nrow=%.9g\n", rTotal, nRow)); if( rTotal<pCost->rCost ){ pCost->rCost = rTotal; pCost->nRow = nRow; pCost->plan.wsFlags = flags; pCost->plan.u.pTerm = pTerm; } } } #endif /* SQLITE_OMIT_OR_OPTIMIZATION */ } | > > | 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 | tempWC.nTerm = 1; bestIndex(pParse, &tempWC, pSrc, notReady, 0, &sTermCost); }else{ continue; } rTotal += sTermCost.rCost; nRow += sTermCost.nRow; used |= sTermCost.used; if( rTotal>=pCost->rCost ) break; } /* If there is an ORDER BY clause, increase the scan cost to account ** for the cost of the sort. */ if( pOrderBy!=0 ){ rTotal += nRow*estLog(nRow); WHERETRACE(("... sorting increases OR cost to %.9g\n", rTotal)); } /* If the cost of scanning using this OR term for optimization is ** less than the current cost stored in pCost, replace the contents ** of pCost. */ WHERETRACE(("... multi-index OR cost=%.9g nrow=%.9g\n", rTotal, nRow)); if( rTotal<pCost->rCost ){ pCost->rCost = rTotal; pCost->nRow = nRow; pCost->used = used; pCost->plan.wsFlags = flags; pCost->plan.u.pTerm = pTerm; } } } #endif /* SQLITE_OMIT_OR_OPTIMIZATION */ } |
︙ | ︙ | |||
1722 1723 1724 1725 1726 1727 1728 | ** part of the sqlite3_index_info structure is left populated. ** ** 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){ | | | 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 | ** part of the sqlite3_index_info structure is left populated. ** ** 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 i; int rc; (void)sqlite3SafetyOff(pParse->db); WHERETRACE(("xBestIndex for %s\n", pTab->zName)); TRACE_IDX_INPUTS(p); rc = pVtab->pModule->xBestIndex(pVtab, p); |
︙ | ︙ | |||
1819 1820 1821 1822 1823 1824 1825 | */ /* The module name must be defined. Also, by this point there must ** be a pointer to an sqlite3_vtab structure. Otherwise ** sqlite3ViewGetColumnNames() would have picked up the error. */ assert( pTab->azModuleArg && pTab->azModuleArg[0] ); | | | 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 | */ /* The module name must be defined. Also, by this point there must ** be a pointer to an sqlite3_vtab structure. Otherwise ** sqlite3ViewGetColumnNames() would have picked up the error. */ assert( pTab->azModuleArg && pTab->azModuleArg[0] ); assert( sqlite3GetVTable(pParse->db, pTab) ); /* Set the aConstraint[].usable fields and initialize all ** output variables to zero. ** ** aConstraint[].usable is true for constraints where the right-hand ** side contains only references to tables to the left of the current ** table. In other words, if the constraint is of the form: |
︙ | ︙ | |||
1846 1847 1848 1849 1850 1851 1852 | ** each time. */ pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; pUsage = pIdxInfo->aConstraintUsage; for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){ j = pIdxCons->iTermOffset; pTerm = &pWC->a[j]; | | > > > > > > > | 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 | ** each time. */ pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; pUsage = pIdxInfo->aConstraintUsage; for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){ j = pIdxCons->iTermOffset; pTerm = &pWC->a[j]; pIdxCons->usable = (pTerm->prereqRight¬Ready) ? 0 : 1; } memset(pUsage, 0, sizeof(pUsage[0])*pIdxInfo->nConstraint); if( pIdxInfo->needToFreeIdxStr ){ sqlite3_free(pIdxInfo->idxStr); } pIdxInfo->idxStr = 0; pIdxInfo->idxNum = 0; pIdxInfo->needToFreeIdxStr = 0; pIdxInfo->orderByConsumed = 0; /* ((double)2) In case of SQLITE_OMIT_FLOATING_POINT... */ pIdxInfo->estimatedCost = SQLITE_BIG_DBL / ((double)2); nOrderBy = pIdxInfo->nOrderBy; if( !pOrderBy ){ pIdxInfo->nOrderBy = 0; } if( vtabBestIndex(pParse, pTab, pIdxInfo) ){ return; } pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; for(i=0; i<pIdxInfo->nConstraint; i++){ if( pUsage[i].argvIndex>0 ){ pCost->used |= pWC->a[pIdxCons[i].iTermOffset].prereqRight; } } /* The cost is not allowed to be larger than SQLITE_BIG_DBL (the ** inital value of lowestCost in this loop. If it is, then the ** (cost<lowestCost) test below will never be true. ** ** Use "(double)2" instead of "2.0" in case OMIT_FLOATING_POINT ** is defined. |
︙ | ︙ | |||
1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 | /* Try to find a more efficient access pattern by using multiple indexes ** to optimize an OR expression within the WHERE clause. */ bestOrClauseIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost); } #endif /* SQLITE_OMIT_VIRTUALTABLE */ /* ** Find the query plan for accessing a particular table. Write the ** best query plan and its cost into the WhereCost object supplied as the ** last parameter. ** ** The lowest cost plan wins. The cost is an estimate of the amount of | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* Try to find a more efficient access pattern by using multiple indexes ** to optimize an OR expression within the WHERE clause. */ bestOrClauseIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost); } #endif /* SQLITE_OMIT_VIRTUALTABLE */ /* ** Argument pIdx is a pointer to an index structure that has an array of ** SQLITE_INDEX_SAMPLES evenly spaced samples of the first indexed column ** stored in Index.aSample. The domain of values stored in said column ** may be thought of as divided into (SQLITE_INDEX_SAMPLES+1) regions. ** Region 0 contains all values smaller than the first sample value. Region ** 1 contains values larger than or equal to the value of the first sample, ** but smaller than the value of the second. And so on. ** ** If successful, this function determines which of the regions value ** pVal lies in, sets *piRegion to the region index (a value between 0 ** and SQLITE_INDEX_SAMPLES+1, inclusive) and returns SQLITE_OK. ** Or, if an OOM occurs while converting text values between encodings, ** SQLITE_NOMEM is returned and *piRegion is undefined. */ #ifdef SQLITE_ENABLE_STAT2 static int whereRangeRegion( Parse *pParse, /* Database connection */ Index *pIdx, /* Index to consider domain of */ sqlite3_value *pVal, /* Value to consider */ int *piRegion /* OUT: Region of domain in which value lies */ ){ if( ALWAYS(pVal) ){ IndexSample *aSample = pIdx->aSample; int i = 0; int eType = sqlite3_value_type(pVal); if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){ double r = sqlite3_value_double(pVal); for(i=0; i<SQLITE_INDEX_SAMPLES; i++){ if( aSample[i].eType==SQLITE_NULL ) continue; if( aSample[i].eType>=SQLITE_TEXT || aSample[i].u.r>r ) break; } }else{ sqlite3 *db = pParse->db; CollSeq *pColl; const u8 *z; int n; /* pVal comes from sqlite3ValueFromExpr() so the type cannot be NULL */ assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB ); if( eType==SQLITE_BLOB ){ z = (const u8 *)sqlite3_value_blob(pVal); pColl = db->pDfltColl; assert( pColl->enc==SQLITE_UTF8 ); }else{ pColl = sqlite3GetCollSeq(db, SQLITE_UTF8, 0, *pIdx->azColl); if( pColl==0 ){ sqlite3ErrorMsg(pParse, "no such collation sequence: %s", *pIdx->azColl); return SQLITE_ERROR; } z = (const u8 *)sqlite3ValueText(pVal, pColl->enc); if( !z ){ return SQLITE_NOMEM; } assert( z && pColl && pColl->xCmp ); } n = sqlite3ValueBytes(pVal, pColl->enc); for(i=0; i<SQLITE_INDEX_SAMPLES; i++){ int r; int eSampletype = aSample[i].eType; if( eSampletype==SQLITE_NULL || eSampletype<eType ) continue; if( (eSampletype!=eType) ) break; #ifndef SQLITE_OMIT_UTF16 if( pColl->enc!=SQLITE_UTF8 ){ int nSample; char *zSample = sqlite3Utf8to16( db, pColl->enc, aSample[i].u.z, aSample[i].nByte, &nSample ); if( !zSample ){ assert( db->mallocFailed ); return SQLITE_NOMEM; } r = pColl->xCmp(pColl->pUser, nSample, zSample, n, z); sqlite3DbFree(db, zSample); }else #endif { r = pColl->xCmp(pColl->pUser, aSample[i].nByte, aSample[i].u.z, n, z); } if( r>0 ) break; } } assert( i>=0 && i<=SQLITE_INDEX_SAMPLES ); *piRegion = i; } return SQLITE_OK; } #endif /* #ifdef SQLITE_ENABLE_STAT2 */ /* ** If expression pExpr represents a literal value, set *pp to point to ** an sqlite3_value structure containing the same value, with affinity ** aff applied to it, before returning. It is the responsibility of the ** caller to eventually release this structure by passing it to ** sqlite3ValueFree(). ** ** If the current parse is a recompile (sqlite3Reprepare()) and pExpr ** is an SQL variable that currently has a non-NULL value bound to it, ** create an sqlite3_value structure containing this value, again with ** affinity aff applied to it, instead. ** ** If neither of the above apply, set *pp to NULL. ** ** If an error occurs, return an error code. Otherwise, SQLITE_OK. */ #ifdef SQLITE_ENABLE_STAT2 static int valueFromExpr( Parse *pParse, Expr *pExpr, u8 aff, sqlite3_value **pp ){ /* The evalConstExpr() function will have already converted any TK_VARIABLE ** expression involved in an comparison into a TK_REGISTER. */ assert( pExpr->op!=TK_VARIABLE ); if( pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE ){ int iVar = pExpr->iColumn; sqlite3VdbeSetVarmask(pParse->pVdbe, iVar); *pp = sqlite3VdbeGetValue(pParse->pReprepare, iVar, aff); return SQLITE_OK; } return sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, aff, pp); } #endif /* ** 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): ** ** ... FROM t1 WHERE a > ? AND a < ? ... ** |_____| |_____| ** | | ** pLower pUpper ** ** If either of the upper or lower bound is not present, then NULL is passed in ** place of the corresponding WhereTerm. ** ** The nEq parameter is passed the index of the index column subject to the ** range constraint. Or, equivalently, the number of equality constraints ** optimized by the proposed index scan. For example, assuming index p is ** on t1(a, b), and the SQL query is: ** ** ... FROM t1 WHERE a = ? AND b > ? AND b < ? ... ** ** then nEq should be passed the value 1 (as the range restricted column, ** b, is the second left-most column of the index). Or, if the query is: ** ** ... FROM t1 WHERE a > ? AND a < ? ... ** ** then nEq should be passed 0. ** ** The returned value is an integer between 1 and 100, inclusive. A return ** value of 1 indicates that the proposed range scan is expected to visit ** approximately 1/100th (1%) of the rows selected by the nEq equality ** constraints (if any). A return value of 100 indicates that it is expected ** that the range scan will visit every row (100%) selected by the equality ** constraints. ** ** In the absence of sqlite_stat2 ANALYZE data, each range inequality ** reduces the search space by 2/3rds. Hence a single constraint (x>?) ** results in a return of 33 and a range constraint (x>? AND x<?) results ** in a return of 11. */ static int whereRangeScanEst( Parse *pParse, /* Parsing & code generating context */ Index *p, /* The index containing the range-compared column; "x" */ int nEq, /* index into p->aCol[] of the range-compared column */ WhereTerm *pLower, /* Lower bound on the range. ex: "x>123" Might be NULL */ WhereTerm *pUpper, /* Upper bound on the range. ex: "x<455" Might be NULL */ int *piEst /* OUT: Return value */ ){ int rc = SQLITE_OK; #ifdef SQLITE_ENABLE_STAT2 if( nEq==0 && p->aSample ){ sqlite3_value *pLowerVal = 0; sqlite3_value *pUpperVal = 0; int iEst; int iLower = 0; int iUpper = SQLITE_INDEX_SAMPLES; u8 aff = p->pTable->aCol[p->aiColumn[0]].affinity; if( pLower ){ Expr *pExpr = pLower->pExpr->pRight; rc = valueFromExpr(pParse, pExpr, aff, &pLowerVal); } if( rc==SQLITE_OK && pUpper ){ Expr *pExpr = pUpper->pExpr->pRight; rc = valueFromExpr(pParse, pExpr, aff, &pUpperVal); } if( rc!=SQLITE_OK || (pLowerVal==0 && pUpperVal==0) ){ sqlite3ValueFree(pLowerVal); sqlite3ValueFree(pUpperVal); goto range_est_fallback; }else if( pLowerVal==0 ){ rc = whereRangeRegion(pParse, p, pUpperVal, &iUpper); if( pLower ) iLower = iUpper/2; }else if( pUpperVal==0 ){ rc = whereRangeRegion(pParse, p, pLowerVal, &iLower); if( pUpper ) iUpper = (iLower + SQLITE_INDEX_SAMPLES + 1)/2; }else{ rc = whereRangeRegion(pParse, p, pUpperVal, &iUpper); if( rc==SQLITE_OK ){ rc = whereRangeRegion(pParse, p, pLowerVal, &iLower); } } iEst = iUpper - iLower; testcase( iEst==SQLITE_INDEX_SAMPLES ); assert( iEst<=SQLITE_INDEX_SAMPLES ); if( iEst<1 ){ iEst = 1; } sqlite3ValueFree(pLowerVal); sqlite3ValueFree(pUpperVal); *piEst = (iEst * 100)/SQLITE_INDEX_SAMPLES; return rc; } range_est_fallback: #else UNUSED_PARAMETER(pParse); UNUSED_PARAMETER(p); UNUSED_PARAMETER(nEq); #endif assert( pLower || pUpper ); if( pLower && pUpper ){ *piEst = 11; }else{ *piEst = 33; } return rc; } /* ** Find the query plan for accessing a particular table. Write the ** best query plan and its cost into the WhereCost object supplied as the ** last parameter. ** ** The lowest cost plan wins. The cost is an estimate of the amount of |
︙ | ︙ | |||
1929 1930 1931 1932 1933 1934 1935 | Parse *pParse, /* The parsing context */ WhereClause *pWC, /* The WHERE clause */ struct SrcList_item *pSrc, /* The FROM clause term to search */ Bitmask notReady, /* Mask of cursors that are not available */ ExprList *pOrderBy, /* The ORDER BY clause */ WhereCost *pCost /* Lowest cost query plan */ ){ | < < | | | | < > | | < < < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | < < > | > > > > > > > > > > > > > > > > | < < | > > > > > > > > | | > > > > > | | > > > > > > > > > | < < > > | > > | < > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > | > | | | | | | > | < | < | | > > > | > > > | < > | > > > > | < < < < < < < < < > > | < < < < < < < < < < < < < < | < < | < < < | < | < | < < < < < < < < | | < > > > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < | > | > > > > > > | > | > | < | > > > > > > > > > > > > > > > > > | < > > | > > > | | > | > | | 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 | Parse *pParse, /* The parsing context */ WhereClause *pWC, /* The WHERE clause */ struct SrcList_item *pSrc, /* The FROM clause term to search */ Bitmask notReady, /* Mask of cursors that are not available */ ExprList *pOrderBy, /* The ORDER BY clause */ WhereCost *pCost /* Lowest cost query plan */ ){ int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */ Index *pProbe; /* An index we are evaluating */ Index *pIdx; /* Copy of pProbe, or zero for IPK index */ int eqTermMask; /* Current mask of valid equality operators */ int idxEqTermMask; /* Index mask of valid equality operators */ Index sPk; /* A fake index object for the primary key */ unsigned int aiRowEstPk[2]; /* The aiRowEst[] value for the sPk index */ int aiColumnPk = -1; /* The aColumn[] value for the sPk index */ int wsFlagMask; /* Allowed flags in pCost->plan.wsFlag */ /* Initialize the cost to a worst-case value */ memset(pCost, 0, sizeof(*pCost)); pCost->rCost = SQLITE_BIG_DBL; /* If the pSrc table is the right table of a LEFT JOIN then we may not ** use an index to satisfy IS NULL constraints on that table. This is ** because columns might end up being NULL if the table does not match - ** a circumstance which the index cannot help us discover. Ticket #2177. */ if( pSrc->jointype & JT_LEFT ){ idxEqTermMask = WO_EQ|WO_IN; }else{ idxEqTermMask = WO_EQ|WO_IN|WO_ISNULL; } if( pSrc->pIndex ){ /* An INDEXED BY clause specifies a particular index to use */ pIdx = pProbe = pSrc->pIndex; wsFlagMask = ~(WHERE_ROWID_EQ|WHERE_ROWID_RANGE); eqTermMask = idxEqTermMask; }else{ /* There is no INDEXED BY clause. Create a fake Index object to ** represent the primary key */ Index *pFirst; /* Any other index on the table */ memset(&sPk, 0, sizeof(Index)); sPk.nColumn = 1; sPk.aiColumn = &aiColumnPk; sPk.aiRowEst = aiRowEstPk; aiRowEstPk[1] = 1; sPk.onError = OE_Replace; sPk.pTable = pSrc->pTab; pFirst = pSrc->pTab->pIndex; if( pSrc->notIndexed==0 ){ sPk.pNext = pFirst; } /* The aiRowEstPk[0] is an estimate of the total number of rows in the ** table. Get this information from the ANALYZE information if it is ** available. If not available, assume the table 1 million rows in size. */ if( pFirst ){ assert( pFirst->aiRowEst!=0 ); /* Allocated together with pFirst */ aiRowEstPk[0] = pFirst->aiRowEst[0]; }else{ aiRowEstPk[0] = 1000000; } pProbe = &sPk; wsFlagMask = ~( WHERE_COLUMN_IN|WHERE_COLUMN_EQ|WHERE_COLUMN_NULL|WHERE_COLUMN_RANGE ); eqTermMask = WO_EQ|WO_IN; pIdx = 0; } /* Loop over all indices looking for the best one to use */ for(; pProbe; pIdx=pProbe=pProbe->pNext){ const unsigned int * const aiRowEst = pProbe->aiRowEst; double cost; /* Cost of using pProbe */ double nRow; /* Estimated number of rows in result set */ int rev; /* True to scan in reverse order */ int wsFlags = 0; Bitmask used = 0; /* The following variables are populated based on the properties of ** scan being evaluated. They are then used to determine the expected ** cost and number of rows returned. ** ** nEq: ** Number of equality terms that can be implemented using the index. ** ** nInMul: ** The "in-multiplier". This is an estimate of how many seek operations ** SQLite must perform on the index in question. For example, if the ** WHERE clause is: ** ** WHERE a IN (1, 2, 3) AND b IN (4, 5, 6) ** ** SQLite must perform 9 lookups on an index on (a, b), so nInMul is ** set to 9. Given the same schema and either of the following WHERE ** clauses: ** ** WHERE a = 1 ** WHERE a >= 2 ** ** nInMul is set to 1. ** ** If there exists a WHERE term of the form "x IN (SELECT ...)", then ** the sub-select is assumed to return 25 rows for the purposes of ** determining nInMul. ** ** bInEst: ** Set to true if there was at least one "x IN (SELECT ...)" term used ** in determining the value of nInMul. ** ** nBound: ** An estimate on the amount of the table that must be searched. A ** value of 100 means the entire table is searched. Range constraints ** might reduce this to a value less than 100 to indicate that only ** a fraction of the table needs searching. In the absence of ** sqlite_stat2 ANALYZE data, a single inequality reduces the search ** space to 1/3rd its original size. So an x>? constraint reduces ** nBound to 33. Two constraints (x>? AND x<?) reduce nBound to 11. ** ** bSort: ** Boolean. True if there is an ORDER BY clause that will require an ** external sort (i.e. scanning the index being evaluated will not ** correctly order records). ** ** bLookup: ** Boolean. True if for each index entry visited a lookup on the ** corresponding table b-tree is required. This is always false ** for the rowid index. For other indexes, it is true unless all the ** columns of the table used by the SELECT statement are present in ** the index (such an index is sometimes described as a covering index). ** For example, given the index on (a, b), the second of the following ** two queries requires table b-tree lookups, but the first does not. ** ** SELECT a, b FROM tbl WHERE a = 1; ** SELECT a, b, c FROM tbl WHERE a = 1; */ int nEq; int bInEst = 0; int nInMul = 1; int nBound = 100; int bSort = 0; int bLookup = 0; /* Determine the values of nEq and nInMul */ for(nEq=0; nEq<pProbe->nColumn; nEq++){ WhereTerm *pTerm; /* A single term of the WHERE clause */ int j = pProbe->aiColumn[nEq]; pTerm = findTerm(pWC, iCur, j, notReady, eqTermMask, pIdx); if( pTerm==0 ) break; wsFlags |= (WHERE_COLUMN_EQ|WHERE_ROWID_EQ); if( pTerm->eOperator & WO_IN ){ Expr *pExpr = pTerm->pExpr; wsFlags |= WHERE_COLUMN_IN; if( ExprHasProperty(pExpr, EP_xIsSelect) ){ nInMul *= 25; bInEst = 1; }else if( pExpr->x.pList ){ nInMul *= pExpr->x.pList->nExpr + 1; } }else if( pTerm->eOperator & WO_ISNULL ){ wsFlags |= WHERE_COLUMN_NULL; } used |= pTerm->prereqRight; } /* Determine the value of nBound. */ if( nEq<pProbe->nColumn ){ int j = pProbe->aiColumn[nEq]; if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE|WO_GT|WO_GE, pIdx) ){ WhereTerm *pTop = findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pIdx); WhereTerm *pBtm = findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pIdx); whereRangeScanEst(pParse, pProbe, nEq, pBtm, pTop, &nBound); if( pTop ){ wsFlags |= WHERE_TOP_LIMIT; used |= pTop->prereqRight; } if( pBtm ){ wsFlags |= WHERE_BTM_LIMIT; used |= pBtm->prereqRight; } wsFlags |= (WHERE_COLUMN_RANGE|WHERE_ROWID_RANGE); } }else if( pProbe->onError!=OE_None ){ testcase( wsFlags & WHERE_COLUMN_IN ); testcase( wsFlags & WHERE_COLUMN_NULL ); if( (wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_NULL))==0 ){ wsFlags |= WHERE_UNIQUE; } } /* If there is an ORDER BY clause and the index being considered will ** naturally scan rows in the required order, set the appropriate flags ** in wsFlags. Otherwise, if there is an ORDER BY clause but the index ** will scan rows in a different order, set the bSort variable. */ if( pOrderBy ){ if( (wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_NULL))==0 && isSortingIndex(pParse,pWC->pMaskSet,pProbe,iCur,pOrderBy,nEq,&rev) ){ wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_ORDERBY; wsFlags |= (rev ? WHERE_REVERSE : 0); }else{ bSort = 1; } } /* If currently calculating the cost of using an index (not the IPK ** index), determine if all required column data may be obtained without ** seeking to entries in the main table (i.e. if the index is a covering ** index for this query). If it is, set the WHERE_IDX_ONLY flag in ** wsFlags. Otherwise, set the bLookup variable to true. */ if( pIdx && wsFlags ){ Bitmask m = pSrc->colUsed; int j; for(j=0; j<pIdx->nColumn; j++){ int x = pIdx->aiColumn[j]; if( x<BMS-1 ){ m &= ~(((Bitmask)1)<<x); } } if( m==0 ){ wsFlags |= WHERE_IDX_ONLY; }else{ bLookup = 1; } } /**** Begin adding up the cost of using this index (Needs improvements) ** ** Estimate the number of rows of output. For an IN operator, ** do not let the estimate exceed half the rows in the table. */ nRow = (double)(aiRowEst[nEq] * nInMul); if( bInEst && nRow*2>aiRowEst[0] ){ nRow = aiRowEst[0]/2; nInMul = (int)(nRow / aiRowEst[nEq]); } /* Assume constant cost to access a row and logarithmic cost to ** do a binary search. Hence, the initial cost is the number of output ** rows plus log2(table-size) times the number of binary searches. */ cost = nRow + nInMul*estLog(aiRowEst[0]); /* Adjust the number of rows and the cost downward to reflect rows ** that are excluded by range constraints. */ nRow = (nRow * (double)nBound) / (double)100; cost = (cost * (double)nBound) / (double)100; /* Add in the estimated cost of sorting the result */ if( bSort ){ cost += cost*estLog(cost); } /* If all information can be taken directly from the index, we avoid ** doing table lookups. This reduces the cost by half. (Not really - ** this needs to be fixed.) */ if( pIdx && bLookup==0 ){ cost /= (double)2; } /**** Cost of using this index has now been computed ****/ WHERETRACE(( "tbl=%s idx=%s nEq=%d nInMul=%d nBound=%d bSort=%d bLookup=%d" " wsFlags=%d (nRow=%.2f cost=%.2f)\n", pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk"), nEq, nInMul, nBound, bSort, bLookup, wsFlags, nRow, cost )); /* If this index is the best we have seen so far, then record this ** index and its cost in the pCost structure. */ if( (!pIdx || wsFlags) && cost<pCost->rCost ){ pCost->rCost = cost; pCost->nRow = nRow; pCost->used = used; pCost->plan.wsFlags = (wsFlags&wsFlagMask); pCost->plan.nEq = nEq; pCost->plan.u.pIdx = pIdx; } /* If there was an INDEXED BY clause, then only that one index is ** considered. */ if( pSrc->pIndex ) break; /* Reset masks for the next index in the loop */ wsFlagMask = ~(WHERE_ROWID_EQ|WHERE_ROWID_RANGE); eqTermMask = idxEqTermMask; } /* If there is no ORDER BY clause and the SQLITE_ReverseOrder flag ** is set, then reverse the order that the index will be scanned ** in. This is used for application testing, to help find cases ** where application behaviour depends on the (undefined) order that ** SQLite outputs rows in in the absence of an ORDER BY clause. */ if( !pOrderBy && pParse->db->flags & SQLITE_ReverseOrder ){ pCost->plan.wsFlags |= WHERE_REVERSE; } assert( pOrderBy || (pCost->plan.wsFlags&WHERE_ORDERBY)==0 ); assert( pCost->plan.u.pIdx==0 || (pCost->plan.wsFlags&WHERE_ROWID_EQ)==0 ); assert( pSrc->pIndex==0 || pCost->plan.u.pIdx==0 || pCost->plan.u.pIdx==pSrc->pIndex ); WHERETRACE(("best index is: %s\n", (pCost->plan.u.pIdx ? pCost->plan.u.pIdx->zName : "ipk") )); bestOrClauseIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost); pCost->plan.wsFlags |= eqTermMask; } /* ** Find the query plan for accessing table pSrc->pTab. Write the ** best query plan and its cost into the WhereCost object supplied ** as the last parameter. This function may calculate the cost of ** both real and virtual table scans. |
︙ | ︙ | |||
2283 2284 2285 2286 2287 2288 2289 | disableTerm(pLevel, pOther); } } } } /* | | | > > > > | < | | | | | < | 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 | disableTerm(pLevel, pOther); } } } } /* ** Code an OP_Affinity opcode to apply the column affinity string zAff ** to the n registers starting at base. ** ** Buffer zAff was allocated using sqlite3DbMalloc(). It is the ** responsibility of this function to arrange for it to be eventually ** freed using sqlite3DbFree(). */ static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){ Vdbe *v = pParse->pVdbe; assert( v!=0 ); sqlite3VdbeAddOp2(v, OP_Affinity, base, n); sqlite3VdbeChangeP4(v, -1, zAff, P4_DYNAMIC); sqlite3ExprCacheAffinityChange(pParse, base, n); } /* ** Generate code for a single equality term of the WHERE clause. An equality ** term can be either X=expr or X IN (...). pTerm is the term to be ** coded. |
︙ | ︙ | |||
2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 | ** ** This routine always allocates at least one memory cell and returns ** the index of that memory cell. The code that ** calls this routine will use that memory cell to store the termination ** key value of the loop. If one or more IN operators appear, then ** this routine allocates an additional nEq memory cells for internal ** use. */ static int codeAllEqualityTerms( Parse *pParse, /* Parsing context */ WhereLevel *pLevel, /* Which nested loop of the FROM we are coding */ WhereClause *pWC, /* The WHERE clause */ Bitmask notReady, /* Which parts of FROM have not yet been coded */ | > > > > > > > > > > > > > > > | > > > > > > > | 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 | ** ** This routine always allocates at least one memory cell and returns ** the index of that memory cell. The code that ** calls this routine will use that memory cell to store the termination ** key value of the loop. If one or more IN operators appear, then ** this routine allocates an additional nEq memory cells for internal ** use. ** ** Before returning, *pzAff is set to point to a buffer containing a ** copy of the column affinity string of the index allocated using ** sqlite3DbMalloc(). Except, entries in the copy of the string associated ** with equality constraints that use NONE affinity are set to ** SQLITE_AFF_NONE. This is to deal with SQL such as the following: ** ** CREATE TABLE t1(a TEXT PRIMARY KEY, b); ** SELECT ... FROM t1 AS t2, t1 WHERE t1.a = t2.b; ** ** In the example above, the index on t1(a) has TEXT affinity. But since ** the right hand side of the equality constraint (t2.b) has NONE affinity, ** no conversion should be attempted before using a t2.b value as part of ** a key to search the index. Hence the first byte in the returned affinity ** string in this example would be set to SQLITE_AFF_NONE. */ static int codeAllEqualityTerms( Parse *pParse, /* Parsing context */ WhereLevel *pLevel, /* Which nested loop of the FROM we are coding */ WhereClause *pWC, /* The WHERE clause */ Bitmask notReady, /* Which parts of FROM have not yet been coded */ int nExtraReg, /* Number of extra registers to allocate */ char **pzAff /* OUT: Set to point to affinity string */ ){ int nEq = pLevel->plan.nEq; /* The number of == or IN constraints to code */ Vdbe *v = pParse->pVdbe; /* The vm under construction */ Index *pIdx; /* The index being used for this loop */ int iCur = pLevel->iTabCur; /* The cursor of the table */ WhereTerm *pTerm; /* A single constraint term */ int j; /* Loop counter */ int regBase; /* Base register */ int nReg; /* Number of registers to allocate */ char *zAff; /* Affinity string to return */ /* This module is only called on query plans that use an index. */ assert( pLevel->plan.wsFlags & WHERE_INDEXED ); pIdx = pLevel->plan.u.pIdx; /* Figure out how many memory cells we will need then allocate them. */ regBase = pParse->nMem + 1; nReg = pLevel->plan.nEq + nExtraReg; pParse->nMem += nReg; zAff = sqlite3DbStrDup(pParse->db, sqlite3IndexAffinityStr(v, pIdx)); if( !zAff ){ pParse->db->mallocFailed = 1; } /* Evaluate the equality constraints */ assert( pIdx->nColumn>=nEq ); for(j=0; j<nEq; j++){ int r1; int k = pIdx->aiColumn[j]; |
︙ | ︙ | |||
2433 2434 2435 2436 2437 2438 2439 | sqlite3VdbeAddOp2(v, OP_SCopy, r1, regBase+j); } } testcase( pTerm->eOperator & WO_ISNULL ); testcase( pTerm->eOperator & WO_IN ); if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){ sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk); | > > > > | | > > | 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 | sqlite3VdbeAddOp2(v, OP_SCopy, r1, regBase+j); } } testcase( pTerm->eOperator & WO_ISNULL ); testcase( pTerm->eOperator & WO_IN ); if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){ sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk); if( zAff && sqlite3CompareAffinity(pTerm->pExpr->pRight, zAff[j])==SQLITE_AFF_NONE ){ zAff[j] = SQLITE_AFF_NONE; } } } *pzAff = zAff; return regBase; } /* ** Generate code for the start of the iLevel-th loop in the WHERE clause ** implementation described by pWInfo. */ |
︙ | ︙ | |||
2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 | int endEq; /* True if range end uses ==, >= or <= */ int start_constraints; /* Start of range is constrained */ int nConstraint; /* Number of constraint terms */ Index *pIdx; /* The index we will be using */ int iIdxCur; /* The VDBE cursor for the index */ int nExtraReg = 0; /* Number of extra registers needed */ int op; /* Instruction opcode */ pIdx = pLevel->plan.u.pIdx; iIdxCur = pLevel->iIdxCur; k = pIdx->aiColumn[nEq]; /* Column for inequality constraints */ /* If this loop satisfies a sort order (pOrderBy) request that ** was passed to this function to implement a "SELECT min(x) ..." | > | 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 | int endEq; /* True if range end uses ==, >= or <= */ int start_constraints; /* Start of range is constrained */ int nConstraint; /* Number of constraint terms */ Index *pIdx; /* The index we will be using */ int iIdxCur; /* The VDBE cursor for the index */ int nExtraReg = 0; /* Number of extra registers needed */ int op; /* Instruction opcode */ char *zAff; pIdx = pLevel->plan.u.pIdx; iIdxCur = pLevel->iIdxCur; k = pIdx->aiColumn[nEq]; /* Column for inequality constraints */ /* If this loop satisfies a sort order (pOrderBy) request that ** was passed to this function to implement a "SELECT min(x) ..." |
︙ | ︙ | |||
2729 2730 2731 2732 2733 2734 2735 | nExtraReg = 1; } /* 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. */ | | > > < > | > > > > > > > > | > | > > > > > > > > > | | 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 | nExtraReg = 1; } /* 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. */ regBase = codeAllEqualityTerms( pParse, pLevel, pWC, notReady, nExtraReg, &zAff ); addrNxt = pLevel->addrNxt; /* 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( bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC) ){ SWAP(WhereTerm *, pRangeEnd, pRangeStart); } testcase( pRangeStart && pRangeStart->eOperator & WO_LE ); testcase( pRangeStart && pRangeStart->eOperator & WO_GE ); testcase( pRangeEnd && pRangeEnd->eOperator & WO_LE ); testcase( pRangeEnd && pRangeEnd->eOperator & WO_GE ); startEq = !pRangeStart || pRangeStart->eOperator & (WO_LE|WO_GE); endEq = !pRangeEnd || pRangeEnd->eOperator & (WO_LE|WO_GE); start_constraints = pRangeStart || nEq>0; /* Seek the index cursor to the start of the range. */ nConstraint = nEq; if( pRangeStart ){ Expr *pRight = pRangeStart->pExpr->pRight; sqlite3ExprCode(pParse, pRight, regBase+nEq); sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt); if( zAff && sqlite3CompareAffinity(pRight, zAff[nConstraint])==SQLITE_AFF_NONE ){ /* Since the comparison is to be performed with no conversions applied ** to the operands, set the affinity to apply to pRight to ** SQLITE_AFF_NONE. */ zAff[nConstraint] = SQLITE_AFF_NONE; } nConstraint++; }else if( isMinQuery ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); nConstraint++; startEq = 0; start_constraints = 1; } codeApplyAffinity(pParse, regBase, nConstraint, zAff); op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev]; assert( op!=0 ); testcase( op==OP_Rewind ); testcase( op==OP_Last ); testcase( op==OP_SeekGt ); testcase( op==OP_SeekGe ); testcase( op==OP_SeekLe ); testcase( op==OP_SeekLt ); sqlite3VdbeAddOp4(v, op, iIdxCur, addrNxt, regBase, SQLITE_INT_TO_PTR(nConstraint), P4_INT32); /* Load the value for the inequality constraint at the end of the ** range (if any). */ nConstraint = nEq; if( pRangeEnd ){ Expr *pRight = pRangeEnd->pExpr->pRight; sqlite3ExprCacheRemove(pParse, regBase+nEq); sqlite3ExprCode(pParse, pRight, regBase+nEq); sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt); zAff = sqlite3DbStrDup(pParse->db, zAff); if( zAff && sqlite3CompareAffinity(pRight, zAff[nConstraint])==SQLITE_AFF_NONE ){ /* Since the comparison is to be performed with no conversions applied ** to the operands, set the affinity to apply to pRight to ** SQLITE_AFF_NONE. */ zAff[nConstraint] = SQLITE_AFF_NONE; } codeApplyAffinity(pParse, regBase, nEq+1, zAff); nConstraint++; } /* Top of the loop body */ pLevel->p2 = sqlite3VdbeCurrentAddr(v); /* Check if the index cursor is past the end of the range. */ |
︙ | ︙ | |||
3266 3267 3268 3269 3270 3271 3272 | pLevel = pWInfo->a; andFlags = ~0; WHERETRACE(("*** Optimizer Start ***\n")); for(i=iFrom=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){ WhereCost bestPlan; /* Most efficient plan seen so far */ Index *pIdx; /* Index for FROM table at pTabItem */ int j; /* For looping over FROM tables */ | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | | | | | | | | | | | > > > | < > | | | | | > | | 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 | pLevel = pWInfo->a; andFlags = ~0; WHERETRACE(("*** Optimizer Start ***\n")); for(i=iFrom=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){ WhereCost bestPlan; /* Most efficient plan seen so far */ Index *pIdx; /* Index for FROM table at pTabItem */ int j; /* For looping over FROM tables */ int bestJ = -1; /* The value of j */ Bitmask m; /* Bitmask value for j or bestJ */ int isOptimal; /* Iterator for optimal/non-optimal search */ memset(&bestPlan, 0, sizeof(bestPlan)); bestPlan.rCost = SQLITE_BIG_DBL; /* Loop through the remaining entries in the FROM clause to find the ** next nested loop. The FROM clause entries may be iterated through ** either once or twice. ** ** The first iteration, which is always performed, searches for the ** FROM clause entry that permits the lowest-cost, "optimal" scan. In ** this context an optimal scan is one that uses the same strategy ** for the given FROM clause entry as would be selected if the entry ** were used as the innermost nested loop. In other words, a table ** is chosen such that the cost of running that table cannot be reduced ** by waiting for other tables to run first. ** ** The second iteration is only performed if no optimal scan strategies ** were found by the first. This iteration is used to search for the ** lowest cost scan overall. ** ** Previous versions of SQLite performed only the second iteration - ** the next outermost loop was always that with the lowest overall ** cost. However, this meant that SQLite could select the wrong plan ** for scripts such as the following: ** ** CREATE TABLE t1(a, b); ** CREATE TABLE t2(c, d); ** SELECT * FROM t2, t1 WHERE t2.rowid = t1.a; ** ** The best strategy is to iterate through table t1 first. However it ** is not possible to determine this with a simple greedy algorithm. ** However, since the cost of a linear scan through table t2 is the same ** as the cost of a linear scan through table t1, a simple greedy ** algorithm may choose to use t2 for the outer loop, which is a much ** costlier approach. */ for(isOptimal=1; isOptimal>=0 && bestJ<0; isOptimal--){ Bitmask mask = (isOptimal ? 0 : notReady); assert( (pTabList->nSrc-iFrom)>1 || isOptimal ); for(j=iFrom, pTabItem=&pTabList->a[j]; j<pTabList->nSrc; j++, pTabItem++){ int doNotReorder; /* True if this table should not be reordered */ WhereCost sCost; /* Cost information from best[Virtual]Index() */ ExprList *pOrderBy; /* ORDER BY clause for index to optimize */ doNotReorder = (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0; if( j!=iFrom && doNotReorder ) break; m = getMask(pMaskSet, pTabItem->iCursor); if( (m & notReady)==0 ){ if( j==iFrom ) iFrom++; continue; } pOrderBy = ((i==0 && ppOrderBy )?*ppOrderBy:0); assert( pTabItem->pTab ); #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pTabItem->pTab) ){ sqlite3_index_info **pp = &pWInfo->a[j].pIdxInfo; bestVirtualIndex(pParse, pWC, pTabItem, mask, pOrderBy, &sCost, pp); }else #endif { bestBtreeIndex(pParse, pWC, pTabItem, mask, pOrderBy, &sCost); } assert( isOptimal || (sCost.used¬Ready)==0 ); if( (sCost.used¬Ready)==0 && (j==iFrom || sCost.rCost<bestPlan.rCost) ){ bestPlan = sCost; bestJ = j; } if( doNotReorder ) break; } } assert( bestJ>=0 ); assert( notReady & getMask(pMaskSet, pTabList->a[bestJ].iCursor) ); WHERETRACE(("*** Optimizer selects table %d for loop %d\n", bestJ, pLevel-pWInfo->a)); if( (bestPlan.plan.wsFlags & WHERE_ORDERBY)!=0 ){ *ppOrderBy = 0; } andFlags &= bestPlan.plan.wsFlags; |
︙ | ︙ | |||
3400 3401 3402 3403 3404 3405 3406 | zMsg = sqlite3MAppendf(db, zMsg, "%s ORDER BY", zMsg); } sqlite3VdbeAddOp4(v, OP_Explain, i, pLevel->iFrom, 0, zMsg, P4_DYNAMIC); } #endif /* SQLITE_OMIT_EXPLAIN */ pTabItem = &pTabList->a[pLevel->iFrom]; pTab = pTabItem->pTab; | | > | < | 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 | zMsg = sqlite3MAppendf(db, zMsg, "%s ORDER BY", zMsg); } sqlite3VdbeAddOp4(v, OP_Explain, i, pLevel->iFrom, 0, zMsg, P4_DYNAMIC); } #endif /* SQLITE_OMIT_EXPLAIN */ pTabItem = &pTabList->a[pLevel->iFrom]; pTab = pTabItem->pTab; iDb = sqlite3SchemaToIndex(db, pTab->pSchema); if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ) continue; #ifndef SQLITE_OMIT_VIRTUALTABLE if( (pLevel->plan.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 #endif if( (pLevel->plan.wsFlags & WHERE_IDX_ONLY)==0 && (wctrlFlags & WHERE_OMIT_OPEN)==0 ){ int op = pWInfo->okOnePass ? OP_OpenWrite : OP_OpenRead; sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, op); if( !pWInfo->okOnePass && pTab->nCol<BMS ){ |
︙ | ︙ |
Added test/analyze2.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 | # 2009 August 06 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # This file implements regression tests for SQLite library. This file # implements tests for the extra functionality provided by the ANALYZE # command when the library is compiled with SQLITE_ENABLE_STAT2 defined. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !stat2 { finish_test return } #-------------------------------------------------------------------- # Test organization: # # analyze2-1.*: Tests to verify that ANALYZE creates and populates the # sqlite_stat2 table as expected. # # analyze2-2.*: Test that when a table has two indexes on it and either # index may be used for the scan, the index suggested by # the contents of sqlite_stat2 table is prefered. # # analyze2-3.*: Similar to the previous block of tests, but using tables # that contain a mixture of NULL, numeric, text and blob # values. # # analyze2-4.*: Check that when an indexed column uses a collation other # than BINARY, the collation is taken into account when # using the contents of sqlite_stat2 to estimate the cost # of a range scan. # # analyze2-5.*: Check that collation sequences are used as described above # even when the only available version of the collation # function require UTF-16 encoded arguments. # # analyze2-6.*: Check that the library behaves correctly when one of the # sqlite_stat2 or sqlite_stat1 tables are missing. # # analyze2-7.*: Check that in a shared-schema situation, nothing goes # wrong if sqlite_stat2 data is read by one connection, # and freed by another. # proc eqp {sql {db db}} { uplevel execsql [list "EXPLAIN QUERY PLAN $sql"] $db } do_test analyze2-1.1 { execsql { CREATE TABLE t1(x PRIMARY KEY) } for {set i 0} {$i < 1000} {incr i} { execsql { INSERT INTO t1 VALUES($i) } } execsql { ANALYZE; SELECT * FROM sqlite_stat2; } } [list t1 sqlite_autoindex_t1_1 0 50 \ t1 sqlite_autoindex_t1_1 1 149 \ t1 sqlite_autoindex_t1_1 2 249 \ t1 sqlite_autoindex_t1_1 3 349 \ t1 sqlite_autoindex_t1_1 4 449 \ t1 sqlite_autoindex_t1_1 5 549 \ t1 sqlite_autoindex_t1_1 6 649 \ t1 sqlite_autoindex_t1_1 7 749 \ t1 sqlite_autoindex_t1_1 8 849 \ t1 sqlite_autoindex_t1_1 9 949 \ ] do_test analyze2-1.2 { execsql { DELETE FROM t1 WHERe x>9; ANALYZE; SELECT tbl, idx, group_concat(sample, ' ') FROM sqlite_stat2; } } {t1 sqlite_autoindex_t1_1 {0 1 2 3 4 5 6 7 8 9}} do_test analyze2-1.3 { execsql { DELETE FROM t1 WHERE x>8; ANALYZE; SELECT * FROM sqlite_stat2; } } {} do_test analyze2-1.4 { execsql { DELETE FROM t1; ANALYZE; SELECT * FROM sqlite_stat2; } } {} do_test analyze2-2.1 { execsql { BEGIN; DROP TABLE t1; CREATE TABLE t1(x, y); CREATE INDEX t1_x ON t1(x); CREATE INDEX t1_y ON t1(y); } for {set i 0} {$i < 1000} {incr i} { execsql { INSERT INTO t1 VALUES($i, $i) } } execsql COMMIT execsql ANALYZE } {} do_test analyze2-2.2 { eqp "SELECT * FROM t1 WHERE x>500 AND y>700" } {0 0 {TABLE t1 WITH INDEX t1_y}} do_test analyze2-2.3 { eqp "SELECT * FROM t1 WHERE x>700 AND y>500" } {0 0 {TABLE t1 WITH INDEX t1_x}} do_test analyze2-2.3 { eqp "SELECT * FROM t1 WHERE y>700 AND x>500" } {0 0 {TABLE t1 WITH INDEX t1_y}} do_test analyze2-2.4 { eqp "SELECT * FROM t1 WHERE y>500 AND x>700" } {0 0 {TABLE t1 WITH INDEX t1_x}} do_test analyze2-2.5 { eqp "SELECT * FROM t1 WHERE x BETWEEN 100 AND 200 AND y BETWEEN 400 AND 700" } {0 0 {TABLE t1 WITH INDEX t1_x}} do_test analyze2-2.6 { eqp "SELECT * FROM t1 WHERE x BETWEEN 100 AND 500 AND y BETWEEN 400 AND 700" } {0 0 {TABLE t1 WITH INDEX t1_y}} do_test analyze2-2.7 { eqp "SELECT * FROM t1 WHERE x BETWEEN -400 AND -300 AND y BETWEEN 100 AND 300" } {0 0 {TABLE t1 WITH INDEX t1_x}} do_test analyze2-2.8 { eqp "SELECT * FROM t1 WHERE x BETWEEN 100 AND 300 AND y BETWEEN -400 AND -300" } {0 0 {TABLE t1 WITH INDEX t1_y}} do_test analyze2-2.9 { eqp "SELECT * FROM t1 WHERE x BETWEEN 500 AND 100 AND y BETWEEN 100 AND 300" } {0 0 {TABLE t1 WITH INDEX t1_x}} do_test analyze2-2.10 { eqp "SELECT * FROM t1 WHERE x BETWEEN 100 AND 300 AND y BETWEEN 500 AND 100" } {0 0 {TABLE t1 WITH INDEX t1_y}} do_test analyze2-3.1 { set alphabet [list a b c d e f g h i j] execsql BEGIN for {set i 0} {$i < 1000} {incr i} { set str [lindex $alphabet [expr ($i/100)%10]] append str [lindex $alphabet [expr ($i/ 10)%10]] append str [lindex $alphabet [expr ($i/ 1)%10]] execsql { INSERT INTO t1 VALUES($str, $str) } } execsql COMMIT execsql ANALYZE execsql { SELECT tbl,idx,group_concat(sample,' ') FROM sqlite_stat2 WHERE idx = 't1_x' GROUP BY tbl,idx } } {t1 t1_x {100 299 499 699 899 ajj cjj ejj gjj ijj}} do_test analyze2-3.2 { execsql { SELECT tbl,idx,group_concat(sample,' ') FROM sqlite_stat2 WHERE idx = 't1_y' GROUP BY tbl,idx } } {t1 t1_y {100 299 499 699 899 ajj cjj ejj gjj ijj}} do_test analyze2-3.3 { eqp "SELECT * FROM t1 WHERE x BETWEEN 100 AND 500 AND y BETWEEN 'a' AND 'b'" } {0 0 {TABLE t1 WITH INDEX t1_y}} do_test analyze2-3.4 { eqp "SELECT * FROM t1 WHERE x BETWEEN 100 AND 400 AND y BETWEEN 'a' AND 'h'" } {0 0 {TABLE t1 WITH INDEX t1_x}} do_test analyze2-3.5 { eqp "SELECT * FROM t1 WHERE x<'a' AND y>'h'" } {0 0 {TABLE t1 WITH INDEX t1_y}} do_test analyze2-3.6 { eqp "SELECT * FROM t1 WHERE x<444 AND y>'h'" } {0 0 {TABLE t1 WITH INDEX t1_y}} do_test analyze2-3.7 { eqp "SELECT * FROM t1 WHERE x<221 AND y>'g'" } {0 0 {TABLE t1 WITH INDEX t1_x}} do_test analyze2-4.1 { execsql { CREATE TABLE t3(a COLLATE nocase, b) } execsql { CREATE INDEX t3a ON t3(a) } execsql { CREATE INDEX t3b ON t3(b) } set alphabet [list A b C d E f G h I j] execsql BEGIN for {set i 0} {$i < 1000} {incr i} { set str [lindex $alphabet [expr ($i/100)%10]] append str [lindex $alphabet [expr ($i/ 10)%10]] append str [lindex $alphabet [expr ($i/ 1)%10]] execsql { INSERT INTO t3 VALUES($str, $str) } } execsql COMMIT execsql ANALYZE } {} do_test analyze2-4.2 { execsql { SELECT tbl,idx,group_concat(sample,' ') FROM sqlite_stat2 WHERE idx = 't3a' GROUP BY tbl,idx } } {t3 t3a {AfA bEj CEj dEj EEj fEj GEj hEj IEj jEj}} do_test analyze2-4.3 { execsql { SELECT tbl,idx,group_concat(sample,' ') FROM sqlite_stat2 WHERE idx = 't3b' GROUP BY tbl,idx } } {t3 t3b {AbA CIj EIj GIj IIj bIj dIj fIj hIj jIj}} do_test analyze2-4.4 { eqp "SELECT * FROM t3 WHERE a > 'A' AND a < 'C' AND b > 'A' AND b < 'C'" } {0 0 {TABLE t3 WITH INDEX t3b}} do_test analyze2-4.5 { eqp "SELECT * FROM t3 WHERE a > 'A' AND a < 'c' AND b > 'A' AND b < 'c'" } {0 0 {TABLE t3 WITH INDEX t3a}} ifcapable utf16 { proc test_collate {enc lhs rhs} { # puts $enc return [string compare $lhs $rhs] } do_test analyze2-5.1 { add_test_collate db 0 0 1 execsql { CREATE TABLE t4(x COLLATE test_collate) } execsql { CREATE INDEX t4x ON t4(x) } set alphabet [list a b c d e f g h i j] execsql BEGIN for {set i 0} {$i < 1000} {incr i} { set str [lindex $alphabet [expr ($i/100)%10]] append str [lindex $alphabet [expr ($i/ 10)%10]] append str [lindex $alphabet [expr ($i/ 1)%10]] execsql { INSERT INTO t4 VALUES($str) } } execsql COMMIT execsql ANALYZE } {} do_test analyze2-5.2 { execsql { SELECT tbl,idx,group_concat(sample,' ') FROM sqlite_stat2 WHERE tbl = 't4' GROUP BY tbl,idx } } {t4 t4x {afa bej cej dej eej fej gej hej iej jej}} do_test analyze2-5.3 { eqp "SELECT * FROM t4 WHERE x>'ccc'" } {0 0 {TABLE t4 WITH INDEX t4x}} do_test analyze2-5.4 { eqp "SELECT * FROM t4 AS t41, t4 AS t42 WHERE t41.x>'ccc' AND t42.x>'ggg'" } {0 1 {TABLE t4 AS t42 WITH INDEX t4x} 1 0 {TABLE t4 AS t41 WITH INDEX t4x}} do_test analyze2-5.5 { eqp "SELECT * FROM t4 AS t41, t4 AS t42 WHERE t41.x>'ddd' AND t42.x>'ccc'" } {0 0 {TABLE t4 AS t41 WITH INDEX t4x} 1 1 {TABLE t4 AS t42 WITH INDEX t4x}} } #-------------------------------------------------------------------- # These tests, analyze2-6.*, verify that the library behaves correctly # when one of the sqlite_stat1 and sqlite_stat2 tables is missing. # # If the sqlite_stat1 table is not present, then the sqlite_stat2 # table is not read. However, if it is the sqlite_stat2 table that # is missing, the data in the sqlite_stat1 table is still used. # # Tests analyze2-6.1.* test the libary when the sqlite_stat2 table # is missing. Tests analyze2-6.2.* test the library when sqlite_stat1 # is not present. # do_test analyze2-6.0 { execsql { DROP TABLE IF EXISTS t4; CREATE TABLE t5(a, b); CREATE INDEX t5i ON t5(a, b); CREATE TABLE t6(a, b); CREATE INDEX t6i ON t6(a, b); } for {set ii 0} {$ii < 20} {incr ii} { execsql { INSERT INTO t5 VALUES($ii, $ii); INSERT INTO t6 VALUES($ii/10, $ii/10); } } execsql { CREATE TABLE master AS SELECT * FROM sqlite_master WHERE name LIKE 'sqlite_stat%' } } {} do_test analyze2-6.1.1 { eqp {SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND t5.a = 1 AND t6.a = 1 AND t6.b = 1 } } {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}} do_test analyze2-6.1.2 { db cache flush execsql ANALYZE eqp {SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND t5.a = 1 AND t6.a = 1 AND t6.b = 1 } } {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}} do_test analyze2-6.1.3 { sqlite3 db test.db eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND t5.a = 1 AND t6.a = 1 AND t6.b = 1 } } {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}} do_test analyze2-6.1.4 { execsql { PRAGMA writable_schema = 1; DELETE FROM sqlite_master WHERE tbl_name = 'sqlite_stat2'; } sqlite3 db test.db eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND t5.a = 1 AND t6.a = 1 AND t6.b = 1 } } {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}} do_test analyze2-6.1.5 { execsql { PRAGMA writable_schema = 1; DELETE FROM sqlite_master WHERE tbl_name = 'sqlite_stat1'; } sqlite3 db test.db eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND t5.a = 1 AND t6.a = 1 AND t6.b = 1 } } {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}} do_test analyze2-6.1.6 { execsql { PRAGMA writable_schema = 1; INSERT INTO sqlite_master SELECT * FROM master; } sqlite3 db test.db eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND t5.a = 1 AND t6.a = 1 AND t6.b = 1 } } {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}} do_test analyze2-6.2.1 { execsql { DELETE FROM sqlite_stat1; DELETE FROM sqlite_stat2; } sqlite3 db test.db eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND t5.a>1 AND t5.a<15 AND t6.a>1 } } {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}} do_test analyze2-6.2.2 { db cache flush execsql ANALYZE eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND t5.a>1 AND t5.a<15 AND t6.a>1 } } {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}} do_test analyze2-6.2.3 { sqlite3 db test.db eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND t5.a>1 AND t5.a<15 AND t6.a>1 } } {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}} do_test analyze2-6.2.4 { execsql { PRAGMA writable_schema = 1; DELETE FROM sqlite_master WHERE tbl_name = 'sqlite_stat1'; } sqlite3 db test.db eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND t5.a>1 AND t5.a<15 AND t6.a>1 } } {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}} do_test analyze2-6.2.5 { execsql { PRAGMA writable_schema = 1; DELETE FROM sqlite_master WHERE tbl_name = 'sqlite_stat2'; } sqlite3 db test.db eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND t5.a>1 AND t5.a<15 AND t6.a>1 } } {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}} do_test analyze2-6.2.6 { execsql { PRAGMA writable_schema = 1; INSERT INTO sqlite_master SELECT * FROM master; } sqlite3 db test.db execsql ANALYZE eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND t5.a>1 AND t5.a<15 AND t6.a>1 } } {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}} #-------------------------------------------------------------------- # These tests, analyze2-7.*, test that the sqlite_stat2 functionality # works in shared-cache mode. Note that these tests reuse the database # created for the analyze2-6.* tests. # ifcapable shared_cache { db close set ::enable_shared_cache [sqlite3_enable_shared_cache 1] proc incr_schema_cookie {zDb} { foreach iOffset {24 40} { set cookie [hexio_get_int [hexio_read $zDb $iOffset 4]] incr cookie hexio_write $zDb $iOffset [hexio_render_int32 $cookie] } } do_test analyze2-7.1 { sqlite3 db1 test.db sqlite3 db2 test.db db1 cache size 0 db2 cache size 0 execsql { SELECT count(*) FROM t5 } db1 } {20} do_test analyze2-7.2 { incr_schema_cookie test.db execsql { SELECT count(*) FROM t5 } db2 } {20} do_test analyze2-7.3 { incr_schema_cookie test.db execsql { SELECT count(*) FROM t5 } db1 } {20} do_test analyze2-7.4 { incr_schema_cookie test.db execsql { SELECT count(*) FROM t5 } db2 } {20} do_test analyze2-7.5 { eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND t5.a>1 AND t5.a<15 AND t6.a>1 } db1 } {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}} do_test analyze2-7.6 { incr_schema_cookie test.db execsql { SELECT * FROM sqlite_master } db2 eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND t5.a>1 AND t5.a<15 AND t6.a>1 } db2 } {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}} do_test analyze2-7.7 { incr_schema_cookie test.db execsql { SELECT * FROM sqlite_master } db1 eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND t5.a>1 AND t5.a<15 AND t6.a>1 } db1 } {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}} do_test analyze2-7.8 { execsql { DELETE FROM sqlite_stat2 } db2 execsql { SELECT * FROM sqlite_master } db1 eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND t5.a>1 AND t5.a<15 AND t6.a>1 } db1 } {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}} do_test analyze2-7.9 { execsql { SELECT * FROM sqlite_master } db2 eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND t5.a>1 AND t5.a<15 AND t6.a>1 } db2 } {0 1 {TABLE t6 WITH INDEX t6i} 1 0 {TABLE t5 USING PRIMARY KEY}} do_test analyze2-7.10 { incr_schema_cookie test.db execsql { SELECT * FROM sqlite_master } db1 eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND t5.a>1 AND t5.a<15 AND t6.a>1 } db1 } {0 0 {TABLE t5 WITH INDEX t5i} 1 1 {TABLE t6 USING PRIMARY KEY}} db1 close db2 close sqlite3_enable_shared_cache $::enable_shared_cache } finish_test |
Added test/analyze3.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 | # 2009 August 06 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # This file implements regression tests for SQLite library. This file # implements tests for range and LIKE constraints that use bound variables # instead of literal constant arguments. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !stat2 { finish_test return } #---------------------------------------------------------------------- # Test Organization: # # analyze3-1.*: Test that the values of bound parameters are considered # in the same way as constants when planning queries that # use range constraints. # # analyze3-2.*: Test that the values of bound parameters are considered # in the same way as constants when planning queries that # use LIKE expressions in the WHERE clause. # # analyze3-3.*: Test that binding to a variable does not invalidate the # query plan when there is no way in which replanning the # query may produce a superior outcome. # # analyze3-4.*: Test that SQL or authorization callback errors occuring # within sqlite3Reprepare() are handled correctly. # # analyze3-5.*: Check that the query plans of applicable statements are # invalidated if the values of SQL parameter are modified # using the clear_bindings() or transfer_bindings() APIs. # proc getvar {varname} { uplevel #0 set $varname } db function var getvar proc eqp {sql {db db}} { uplevel execsql [list "EXPLAIN QUERY PLAN $sql"] $db } proc sf_execsql {sql {db db}} { set ::sqlite_search_count 0 set r [uplevel [list execsql $sql $db]] concat $::sqlite_search_count [$db status step] $r } #------------------------------------------------------------------------- # # analyze3-1.1.1: # Create a table with two columns. Populate the first column (affinity # INTEGER) with integer values from 100 to 1100. Create an index on this # column. ANALYZE the table. # # analyze3-1.1.2 - 3.1.3 # Show that there are two possible plans for querying the table with # a range constraint on the indexed column - "full table scan" or "use # the index". When the range is specified using literal values, SQLite # is able to pick the best plan based on the samples in sqlite_stat2. # # analyze3-1.1.4 - 3.1.9 # Show that using SQL variables produces the same results as using # literal values to constrain the range scan. # # These tests also check that the compiler code considers column # affinities when estimating the number of rows scanned by the "use # index strategy". # do_test analyze3-1.1.1 { execsql { BEGIN; CREATE TABLE t1(x INTEGER, y); CREATE INDEX i1 ON t1(x); } for {set i 0} {$i < 1000} {incr i} { execsql { INSERT INTO t1 VALUES($i+100, $i) } } execsql { COMMIT; ANALYZE; } } {} do_test analyze3-1.1.2 { eqp { SELECT sum(y) FROM t1 WHERE x>200 AND x<300 } } {0 0 {TABLE t1 WITH INDEX i1}} do_test analyze3-1.1.3 { eqp { SELECT sum(y) FROM t1 WHERE x>0 AND x<1100 } } {0 0 {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] sf_execsql { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u } } {199 0 14850} do_test analyze3-1.1.6 { set l [expr int(200)] set u [expr int(300)] sf_execsql { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u } } {199 0 14850} do_test analyze3-1.1.7 { sf_execsql { SELECT sum(y) FROM t1 WHERE x>0 AND x<1100 } } {999 999 499500} do_test analyze3-1.1.8 { set l [string range "0" 0 end] set u [string range "1100" 0 end] sf_execsql { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u } } {999 999 499500} do_test analyze3-1.1.9 { set l [expr int(0)] set u [expr int(1100)] sf_execsql { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u } } {999 999 499500} # The following tests are similar to the block above. The difference is # that the indexed column has TEXT affinity in this case. In the tests # above the affinity is INTEGER. # do_test analyze3-1.2.1 { execsql { BEGIN; CREATE TABLE t2(x TEXT, y); INSERT INTO t2 SELECT * FROM t1; CREATE INDEX i2 ON t2(x); COMMIT; ANALYZE; } } {} do_test analyze3-1.2.2 { eqp { SELECT sum(y) FROM t2 WHERE x>1 AND x<2 } } {0 0 {TABLE t2 WITH INDEX i2}} do_test analyze3-1.2.3 { eqp { SELECT sum(y) FROM t2 WHERE x>0 AND x<99 } } {0 0 {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] sf_execsql {SELECT typeof($l), typeof($u), sum(y) FROM t2 WHERE x>$l AND x<$u} } {161 0 text text 4760} do_test analyze3-1.2.6 { set l [expr int(12)] set u [expr int(20)] sf_execsql {SELECT typeof($l), typeof($u), sum(y) FROM t2 WHERE x>$l AND x<$u} } {161 0 integer integer 4760} do_test analyze3-1.2.7 { sf_execsql { SELECT sum(y) FROM t2 WHERE x>0 AND x<99 } } {999 999 490555} do_test analyze3-1.2.8 { set l [string range "0" 0 end] set u [string range "99" 0 end] sf_execsql {SELECT typeof($l), typeof($u), sum(y) FROM t2 WHERE x>$l AND x<$u} } {999 999 text text 490555} do_test analyze3-1.2.9 { set l [expr int(0)] set u [expr int(99)] sf_execsql {SELECT typeof($l), typeof($u), sum(y) FROM t2 WHERE x>$l AND x<$u} } {999 999 integer integer 490555} # Same tests a third time. This time, column x has INTEGER affinity and # is not the leftmost column of the table. This triggered a bug causing # SQLite to use sub-optimal query plans in 3.6.18 and earlier. # do_test analyze3-1.3.1 { execsql { BEGIN; CREATE TABLE t3(y TEXT, x INTEGER); INSERT INTO t3 SELECT y, x FROM t1; CREATE INDEX i3 ON t3(x); COMMIT; ANALYZE; } } {} do_test analyze3-1.3.2 { eqp { SELECT sum(y) FROM t3 WHERE x>200 AND x<300 } } {0 0 {TABLE t3 WITH INDEX i3}} do_test analyze3-1.3.3 { eqp { SELECT sum(y) FROM t3 WHERE x>0 AND x<1100 } } {0 0 {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] sf_execsql { SELECT sum(y) FROM t3 WHERE x>$l AND x<$u } } {199 0 14850} do_test analyze3-1.3.6 { set l [expr int(200)] set u [expr int(300)] sf_execsql { SELECT sum(y) FROM t3 WHERE x>$l AND x<$u } } {199 0 14850} do_test analyze3-1.3.7 { sf_execsql { SELECT sum(y) FROM t3 WHERE x>0 AND x<1100 } } {999 999 499500} do_test analyze3-1.3.8 { set l [string range "0" 0 end] set u [string range "1100" 0 end] sf_execsql { SELECT sum(y) FROM t3 WHERE x>$l AND x<$u } } {999 999 499500} do_test analyze3-1.3.9 { set l [expr int(0)] set u [expr int(1100)] sf_execsql { SELECT sum(y) FROM t3 WHERE x>$l AND x<$u } } {999 999 499500} #------------------------------------------------------------------------- # Test that the values of bound SQL variables may be used for the LIKE # optimization. # drop_all_tables do_test analyze3-2.1 { execsql { PRAGMA case_sensitive_like=off; BEGIN; CREATE TABLE t1(a, b TEXT COLLATE nocase); CREATE INDEX i1 ON t1(b); } for {set i 0} {$i < 1000} {incr i} { set t "" append t [lindex {a b c d e f g h i j} [expr $i/100]] append t [lindex {a b c d e f g h i j} [expr ($i/10)%10]] 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_test analyze3-2.2 { eqp { SELECT count(a) FROM t1 WHERE b LIKE 'a%' } } {0 0 {TABLE t1 WITH INDEX i1}} do_test analyze3-2.3 { eqp { SELECT count(a) FROM t1 WHERE b LIKE '%a' } } {0 0 {TABLE t1}} do_test analyze3-2.4 { sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE 'a%' } } {101 0 100} do_test analyze3-2.5 { sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE '%a' } } {999 999 100} do_test analyze3-2.4 { set like "a%" sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE $like } } {101 0 100} do_test analyze3-2.5 { set like "%a" sf_execsql { SELECT count(*) FROM t1 WHERE b LIKE $like } } {999 999 100} #------------------------------------------------------------------------- # This block of tests checks that statements are correctly marked as # expired when the values bound to any parameters that may affect the # query plan are modified. # drop_all_tables db auth auth proc auth {args} { set ::auth 1 return SQLITE_OK } do_test analyze3-3.1 { execsql { BEGIN; CREATE TABLE t1(a, b, c); CREATE INDEX i1 ON t1(b); } for {set i 0} {$i < 100} {incr i} { execsql { INSERT INTO t1 VALUES($i, $i, $i) } } execsql COMMIT execsql ANALYZE } {} do_test analyze3-3.2.1 { set S [sqlite3_prepare_v2 db "SELECT * FROM t1 WHERE b>?" -1 dummy] sqlite3_expired $S } {0} do_test analyze3-3.2.2 { sqlite3_bind_text $S 1 "abc" 3 sqlite3_expired $S } {1} do_test analyze3-3.2.4 { sqlite3_finalize $S } {SQLITE_OK} do_test analyze3-3.2.5 { set S [sqlite3_prepare_v2 db "SELECT * FROM t1 WHERE b=?" -1 dummy] sqlite3_expired $S } {0} do_test analyze3-3.2.6 { sqlite3_bind_text $S 1 "abc" 3 sqlite3_expired $S } {0} do_test analyze3-3.2.7 { sqlite3_finalize $S } {SQLITE_OK} do_test analyze3-3.4.1 { set S [sqlite3_prepare_v2 db "SELECT * FROM t1 WHERE a=? AND b>?" -1 dummy] sqlite3_expired $S } {0} do_test analyze3-3.4.2 { sqlite3_bind_text $S 1 "abc" 3 sqlite3_expired $S } {0} do_test analyze3-3.4.3 { sqlite3_bind_text $S 2 "def" 3 sqlite3_expired $S } {1} do_test analyze3-3.4.4 { sqlite3_bind_text $S 2 "ghi" 3 sqlite3_expired $S } {1} do_test analyze3-3.4.5 { sqlite3_expired $S } {1} do_test analyze3-3.4.6 { sqlite3_finalize $S } {SQLITE_OK} do_test analyze3-3.5.1 { set S [sqlite3_prepare_v2 db { SELECT * FROM t1 WHERE a 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 ) AND b>?32; } -1 dummy] sqlite3_expired $S } {0} do_test analyze3-3.5.2 { sqlite3_bind_text $S 31 "abc" 3 sqlite3_expired $S } {0} do_test analyze3-3.5.3 { sqlite3_bind_text $S 32 "def" 3 sqlite3_expired $S } {1} do_test analyze3-3.5.5 { sqlite3_finalize $S } {SQLITE_OK} do_test analyze3-3.6.1 { set S [sqlite3_prepare_v2 db { SELECT * FROM t1 WHERE a 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 ) AND b>?33; } -1 dummy] sqlite3_expired $S } {0} do_test analyze3-3.6.2 { sqlite3_bind_text $S 32 "abc" 3 sqlite3_expired $S } {1} do_test analyze3-3.6.3 { sqlite3_bind_text $S 33 "def" 3 sqlite3_expired $S } {1} do_test analyze3-3.6.5 { sqlite3_finalize $S } {SQLITE_OK} do_test analyze3-3.7.1 { breakpoint set S [sqlite3_prepare_v2 db { SELECT * FROM t1 WHERE a IN ( ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?33, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18, ?19, ?20, ?21, ?22, ?23, ?24, ?25, ?26, ?27, ?28, ?29, ?30, ?31, ?32 ) AND b>?10; } -1 dummy] sqlite3_expired $S } {0} do_test analyze3-3.7.2 { sqlite3_bind_text $S 32 "abc" 3 sqlite3_expired $S } {0} do_test analyze3-3.7.3 { sqlite3_bind_text $S 33 "def" 3 sqlite3_expired $S } {0} do_test analyze3-3.7.4 { sqlite3_bind_text $S 10 "def" 3 sqlite3_expired $S } {1} do_test analyze3-3.7.6 { sqlite3_finalize $S } {SQLITE_OK} do_test analyze3-3.8.1 { execsql { CREATE TABLE t4(x, y TEXT COLLATE NOCASE); CREATE INDEX i4 ON t4(y); } } {} do_test analyze3-3.8.2 { set S [sqlite3_prepare_v2 db { SELECT * FROM t4 WHERE x != ? AND y LIKE ? } -1 dummy] sqlite3_expired $S } {0} do_test analyze3-3.8.3 { sqlite3_bind_text $S 1 "abc" 3 sqlite3_expired $S } {0} do_test analyze3-3.8.4 { sqlite3_bind_text $S 2 "def" 3 sqlite3_expired $S } {1} do_test analyze3-3.8.7 { sqlite3_bind_text $S 2 "ghi%" 4 sqlite3_expired $S } {1} do_test analyze3-3.8.8 { sqlite3_expired $S } {1} do_test analyze3-3.8.9 { sqlite3_bind_text $S 2 "ghi%def" 7 sqlite3_expired $S } {1} do_test analyze3-3.8.10 { sqlite3_expired $S } {1} do_test analyze3-3.8.11 { sqlite3_bind_text $S 2 "%ab" 3 sqlite3_expired $S } {1} do_test analyze3-3.8.12 { sqlite3_expired $S } {1} do_test analyze3-3.8.12 { sqlite3_bind_text $S 2 "%de" 3 sqlite3_expired $S } {1} do_test analyze3-3.8.13 { sqlite3_expired $S } {1} do_test analyze3-3.8.14 { sqlite3_finalize $S } {SQLITE_OK} #------------------------------------------------------------------------- # These tests check that errors encountered while repreparing an SQL # statement within sqlite3Reprepare() are handled correctly. # # Check a schema error. # do_test analyze3-4.1.1 { set S [sqlite3_prepare_v2 db "SELECT * FROM t1 WHERE a=? AND b>?" -1 dummy] sqlite3_step $S } {SQLITE_DONE} do_test analyze3-4.1.2 { sqlite3_reset $S sqlite3_bind_text $S 2 "abc" 3 execsql { DROP TABLE t1 } sqlite3_step $S } {SQLITE_SCHEMA} do_test analyze3-4.1.3 { sqlite3_finalize $S } {SQLITE_SCHEMA} # Check an authorization error. # do_test analyze3-4.2.1 { execsql { BEGIN; CREATE TABLE t1(a, b, c); CREATE INDEX i1 ON t1(b); } for {set i 0} {$i < 100} {incr i} { execsql { INSERT INTO t1 VALUES($i, $i, $i) } } execsql COMMIT execsql ANALYZE set S [sqlite3_prepare_v2 db "SELECT * FROM t1 WHERE a=? AND b>?" -1 dummy] sqlite3_step $S } {SQLITE_DONE} db auth auth proc auth {args} { if {[lindex $args 0] == "SQLITE_READ"} {return SQLITE_DENY} return SQLITE_OK } do_test analyze3-4.2.2 { sqlite3_reset $S sqlite3_bind_text $S 2 "abc" 3 sqlite3_step $S } {SQLITE_SCHEMA} do_test analyze3-4.2.4 { sqlite3_finalize $S } {SQLITE_SCHEMA} # Check the effect of an authorization error that occurs in a re-prepare # performed by sqlite3_step() is the same as one that occurs within # sqlite3Reprepare(). # do_test analyze3-4.3.1 { db auth {} set S [sqlite3_prepare_v2 db "SELECT * FROM t1 WHERE a=? AND b>?" -1 dummy] execsql { CREATE TABLE t2(d, e, f) } db auth auth sqlite3_step $S } {SQLITE_SCHEMA} do_test analyze3-4.3.2 { sqlite3_finalize $S } {SQLITE_SCHEMA} db auth {} #------------------------------------------------------------------------- # Test that modifying bound variables using the clear_bindings() or # transfer_bindings() APIs works. # # analyze3-5.1.*: sqlite3_clear_bindings() # analyze3-5.2.*: sqlite3_transfer_bindings() # do_test analyze3-5.1.1 { drop_all_tables execsql { CREATE TABLE t1(x TEXT COLLATE NOCASE); CREATE INDEX i1 ON t1(x); INSERT INTO t1 VALUES('aaa'); INSERT INTO t1 VALUES('abb'); INSERT INTO t1 VALUES('acc'); INSERT INTO t1 VALUES('baa'); INSERT INTO t1 VALUES('bbb'); INSERT INTO t1 VALUES('bcc'); } set S [sqlite3_prepare_v2 db "SELECT * FROM t1 WHERE x LIKE ?" -1 dummy] sqlite3_bind_text $S 1 "a%" 2 set R [list] while { "SQLITE_ROW" == [sqlite3_step $S] } { lappend R [sqlite3_column_text $S 0] } concat [sqlite3_reset $S] $R } {SQLITE_OK aaa abb acc} do_test analyze3-5.1.2 { sqlite3_clear_bindings $S set R [list] while { "SQLITE_ROW" == [sqlite3_step $S] } { lappend R [sqlite3_column_text $S 0] } concat [sqlite3_reset $S] $R } {SQLITE_OK} do_test analyze3-5.1.3 { sqlite3_finalize $S } {SQLITE_OK} do_test analyze3-5.1.1 { set S1 [sqlite3_prepare_v2 db "SELECT * FROM t1 WHERE x LIKE ?" -1 dummy] sqlite3_bind_text $S1 1 "b%" 2 set R [list] while { "SQLITE_ROW" == [sqlite3_step $S1] } { lappend R [sqlite3_column_text $S1 0] } concat [sqlite3_reset $S1] $R } {SQLITE_OK baa bbb bcc} do_test analyze3-5.1.2 { set S2 [sqlite3_prepare_v2 db "SELECT * FROM t1 WHERE x = ?" -1 dummy] sqlite3_bind_text $S2 1 "a%" 2 sqlite3_transfer_bindings $S2 $S1 set R [list] while { "SQLITE_ROW" == [sqlite3_step $S1] } { lappend R [sqlite3_column_text $S1 0] } concat [sqlite3_reset $S1] $R } {SQLITE_OK aaa abb acc} do_test analyze3-5.1.3 { sqlite3_finalize $S2 sqlite3_finalize $S1 } {SQLITE_OK} finish_test |
Added test/async5.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 | # 2009 July 19 # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file tests that asynchronous IO is compatible with multi-file # transactions. # # $Id: async5.test,v 1.1 2009/07/18 11:52:04 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl if {[info commands sqlite3async_initialize] eq ""} { # The async logic is not built into this system finish_test return } db close file delete -force test2.db sqlite3async_initialize "" 1 sqlite3async_control halt never sqlite3 db test.db do_test async5-1.1 { execsql { ATTACH 'test2.db' AS next; CREATE TABLE main.t1(a, b); CREATE TABLE next.t2(a, b); BEGIN; INSERT INTO t1 VALUES(1, 2); INSERT INTO t2 VALUES(3, 4); COMMIT; } } {} do_test async5-1.2 { execsql { SELECT * FROM t1 } } {1 2} do_test async5-1.3 { execsql { SELECT * FROM t2 } } {3 4} do_test async5-1.4 { execsql { BEGIN; INSERT INTO t1 VALUES('a', 'b'); INSERT INTO t2 VALUES('c', 'd'); COMMIT; } } {} do_test async5-1.5 { execsql { SELECT * FROM t1 } } {1 2 a b} do_test async5-1.6 { execsql { SELECT * FROM t2 } } {3 4 c d} db close sqlite3async_control halt idle sqlite3async_start sqlite3async_wait sqlite3async_control halt never sqlite3async_shutdown set sqlite3async_trace 0 finish_test |
Changes to test/attach3.test.
︙ | ︙ | |||
18 19 20 21 22 23 24 25 26 27 28 29 30 31 | set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !attach { finish_test return } # Create tables t1 and t2 in the main database execsql { CREATE TABLE t1(a, b); CREATE TABLE t2(c, d); } | > > > > > | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !attach { 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 # recursive triggers for this file. catchsql { pragma recursive_triggers = off } # Create tables t1 and t2 in the main database execsql { CREATE TABLE t1(a, b); CREATE TABLE t2(c, d); } |
︙ | ︙ | |||
313 314 315 316 317 318 319 320 321 322 323 324 325 326 | do_test attach3-12.9 { execsql { ATTACH DATABASE '' AS NULL } db_list } {main temp {}} do_test attach3-12.10 { execsql { DETACH ? } db_list } {main temp} do_test attach3-12.11 { catchsql { | > | 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 | do_test attach3-12.9 { execsql { ATTACH DATABASE '' AS NULL } db_list } {main temp {}} do_test attach3-12.10 { breakpoint execsql { DETACH ? } db_list } {main temp} do_test attach3-12.11 { catchsql { |
︙ | ︙ |
Changes to test/auth.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 testing the sqlite3_set_authorizer() API # and related functionality. # | | | 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 script is testing the sqlite3_set_authorizer() API # and related functionality. # # $Id: auth.test,v 1.46 2009/07/02 18:40:35 danielk1977 Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl # disable this test if the SQLITE_OMIT_AUTHORIZATION macro is # defined during compilation. |
︙ | ︙ | |||
2244 2245 2246 2247 2248 2249 2250 | set authargs {} execsql { UPDATE v1 SET x=1 WHERE x=117 } set authargs } [list \ SQLITE_UPDATE v1 x main {} \ | < < < > > > > < < > > | 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 | set authargs {} execsql { UPDATE v1 SET x=1 WHERE x=117 } set authargs } [list \ SQLITE_UPDATE v1 x main {} \ SQLITE_SELECT {} {} {} v1 \ SQLITE_READ t2 a main v1 \ SQLITE_READ t2 b main v1 \ SQLITE_SELECT {} {} {} {} \ SQLITE_READ v1 x main v1 \ SQLITE_INSERT v1chng {} main r2 \ SQLITE_READ v1 x main r2 \ SQLITE_READ v1 x main r2 \ ] do_test auth-4.4 { execsql { CREATE TRIGGER r3 INSTEAD OF DELETE ON v1 BEGIN INSERT INTO v1chng VALUES(OLD.x,NULL); END; SELECT * FROM v1; } } {115 117} do_test auth-4.5 { set authargs {} execsql { DELETE FROM v1 WHERE x=117 } set authargs } [list \ SQLITE_DELETE v1 {} main {} \ SQLITE_SELECT {} {} {} v1 \ SQLITE_READ t2 a main v1 \ SQLITE_READ t2 b main v1 \ SQLITE_SELECT {} {} {} {} \ SQLITE_READ v1 x main v1 \ SQLITE_INSERT v1chng {} main r3 \ SQLITE_READ v1 x main r3 \ ] } ;# ifcapable view && trigger # Ticket #1338: Make sure authentication works in the presence of an AS # clause. # |
︙ | ︙ | |||
2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 | DROP TABLE tx; } ifcapable view { execsql { DROP TABLE v1chng; } } } do_test auth-5.2 { execsql { SELECT name FROM ( SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type='table' ORDER BY name } | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | DROP TABLE tx; } ifcapable view { execsql { DROP TABLE v1chng; } } } ifcapable stat2 { set stat2 "sqlite_stat2 " } else { set stat2 "" } do_test auth-5.2 { execsql { SELECT name FROM ( SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type='table' ORDER BY name } } "sqlite_stat1 ${stat2}t1 t2 t3 t4" } # Ticket #3944 # ifcapable trigger { do_test auth-5.3.1 { execsql { CREATE TABLE t5 ( x ); CREATE TRIGGER t5_tr1 AFTER INSERT ON t5 BEGIN UPDATE t5 SET x = 1 WHERE NEW.x = 0; END; } } {} set ::authargs [list] proc auth {args} { eval lappend ::authargs $args return SQLITE_OK } do_test auth-5.3.2 { execsql { INSERT INTO t5 (x) values(0) } set ::authargs } [list SQLITE_INSERT t5 {} main {} \ SQLITE_UPDATE t5 x main t5_tr1 \ SQLITE_READ t5 x main t5_tr1 \ ] do_test auth-5.3.2 { execsql { SELECT * FROM t5 } } {1} } rename proc {} rename proc_real proc finish_test |
Changes to test/autoinc.test.
︙ | ︙ | |||
21 22 23 24 25 26 27 28 29 30 31 32 33 34 | # skip all tests in this file. # ifcapable {!autoinc} { finish_test return } # The database is initially empty. # do_test autoinc-1.1 { execsql { SELECT name FROM sqlite_master WHERE type='table'; } } {} | > > | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | # skip all tests in this file. # ifcapable {!autoinc} { finish_test return } sqlite3_db_config_lookaside db 0 0 0 # The database is initially empty. # do_test autoinc-1.1 { execsql { SELECT name FROM sqlite_master WHERE type='table'; } } {} |
︙ | ︙ | |||
552 553 554 555 556 557 558 | CREATE TABLE t3(a INTEGER PRIMARY KEY AUTOINCREMENT, b); INSERT INTO t3 SELECT * FROM t2 WHERE y>1; SELECT * FROM sqlite_sequence WHERE name='t3'; } } {t3 0} | > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | CREATE TABLE t3(a INTEGER PRIMARY KEY AUTOINCREMENT, b); INSERT INTO t3 SELECT * FROM t2 WHERE y>1; SELECT * FROM sqlite_sequence WHERE name='t3'; } } {t3 0} ifcapable trigger { catchsql { pragma recursive_triggers = off } # Ticket #3928. Make sure that triggers to not make extra slots in # the SQLITE_SEQUENCE table. # do_test autoinc-3928.1 { db eval { CREATE TABLE t3928(a INTEGER PRIMARY KEY AUTOINCREMENT, b); CREATE TRIGGER t3928r1 BEFORE INSERT ON t3928 BEGIN INSERT INTO t3928(b) VALUES('before1'); INSERT INTO t3928(b) VALUES('before2'); END; CREATE TRIGGER t3928r2 AFTER INSERT ON t3928 BEGIN INSERT INTO t3928(b) VALUES('after1'); INSERT INTO t3928(b) VALUES('after2'); END; INSERT INTO t3928(b) VALUES('test'); SELECT * FROM t3928 ORDER BY a; } } {1 before1 2 after1 3 after2 4 before2 5 after1 6 after2 7 test 8 before1 9 before2 10 after1 11 before1 12 before2 13 after2} do_test autoinc-3928.2 { db eval { SELECT * FROM sqlite_sequence WHERE name='t3928' } } {t3928 13} do_test autoinc-3928.3 { db eval { DROP TRIGGER t3928r1; DROP TRIGGER t3928r2; CREATE TRIGGER t3928r3 BEFORE UPDATE ON t3928 WHEN typeof(new.b)=='integer' BEGIN INSERT INTO t3928(b) VALUES('before-int-' || new.b); END; CREATE TRIGGER t3928r4 AFTER UPDATE ON t3928 WHEN typeof(new.b)=='integer' BEGIN INSERT INTO t3928(b) VALUES('after-int-' || new.b); END; DELETE FROM t3928 WHERE a!=1; UPDATE t3928 SET b=456 WHERE a=1; SELECT * FROM t3928 ORDER BY a; } } {1 456 14 before-int-456 15 after-int-456} do_test autoinc-3928.4 { db eval { SELECT * FROM sqlite_sequence WHERE name='t3928' } } {t3928 15} do_test autoinc-3928.5 { db eval { CREATE TABLE t3928b(x); INSERT INTO t3928b VALUES(100); INSERT INTO t3928b VALUES(200); INSERT INTO t3928b VALUES(300); DELETE FROM t3928; CREATE TABLE t3928c(y INTEGER PRIMARY KEY AUTOINCREMENT, z); CREATE TRIGGER t3928br1 BEFORE DELETE ON t3928b BEGIN INSERT INTO t3928(b) VALUES('before-del-'||old.x); INSERT INTO t3928c(z) VALUES('before-del-'||old.x); END; CREATE TRIGGER t3928br2 AFTER DELETE ON t3928b BEGIN INSERT INTO t3928(b) VALUES('after-del-'||old.x); INSERT INTO t3928c(z) VALUES('after-del-'||old.x); END; DELETE FROM t3928b; SELECT * FROM t3928 ORDER BY a; } } {16 before-del-100 17 after-del-100 18 before-del-200 19 after-del-200 20 before-del-300 21 after-del-300} do_test autoinc-3928.6 { db eval { SELECT * FROM t3928c ORDER BY y; } } {1 before-del-100 2 after-del-100 3 before-del-200 4 after-del-200 5 before-del-300 6 after-del-300} do_test autoinc-3928.7 { db eval { SELECT * FROM sqlite_sequence WHERE name LIKE 't3928%' ORDER BY name; } } {t3928 21 t3928c 6} # Ticket [a696379c1f0886615541a48b35bd8181a80e88f8] do_test autoinc-a69637.1 { db eval { CREATE TABLE ta69637_1(x INTEGER PRIMARY KEY AUTOINCREMENT, y); CREATE TABLE ta69637_2(z); CREATE TRIGGER ra69637_1 AFTER INSERT ON ta69637_2 BEGIN INSERT INTO ta69637_1(y) VALUES(new.z+1); END; INSERT INTO ta69637_2 VALUES(123); SELECT * FROM ta69637_1; } } {1 124} do_test autoinc-a69637.2 { db eval { CREATE VIEW va69637_2 AS SELECT * FROM ta69637_2; CREATE TRIGGER ra69637_2 INSTEAD OF INSERT ON va69637_2 BEGIN INSERT INTO ta69637_1(y) VALUES(new.z+10000); END; INSERT INTO va69637_2 VALUES(123); SELECT * FROM ta69637_1; } } {1 124 2 10123} } finish_test |
Changes to test/bind.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2003 September 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 # focus of this script testing the sqlite_bind API. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2003 September 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 # focus of this script testing the sqlite_bind API. # # $Id: bind.test,v 1.48 2009/07/22 07:27:57 danielk1977 Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl proc sqlite_step {stmt N VALS COLS} { upvar VALS vals |
︙ | ︙ | |||
287 288 289 290 291 292 293 | sqlite3_bind_text $VM 2 hello\000there\000 11 sqlite3_bind_text $VM 3 hello\000there\000 -1 sqlite_step $VM N VALUES COLNAMES sqlite3_reset $VM execsql {SELECT * FROM t1} } {hello hello hello} set enc [db eval {PRAGMA encoding}] | | | 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 | sqlite3_bind_text $VM 2 hello\000there\000 11 sqlite3_bind_text $VM 3 hello\000there\000 -1 sqlite_step $VM N VALUES COLNAMES sqlite3_reset $VM execsql {SELECT * FROM t1} } {hello hello hello} set enc [db eval {PRAGMA encoding}] if {$enc=="UTF-8" || $enc==""} { do_test bind-6.5 { execsql {SELECT hex(a), hex(b), hex(c) FROM t1} } {68656C6C6F00746865726500 68656C6C6F007468657265 68656C6C6F} } elseif {$enc=="UTF-16le"} { do_test bind-6.5 { execsql {SELECT hex(a), hex(b), hex(c) FROM t1} } {680065006C006C006F000000740068006500720065000000 680065006C006C006F00000074006800650072006500 680065006C006C006F00} |
︙ | ︙ |
Changes to test/boundary4.tcl.
︙ | ︙ | |||
16 17 18 19 20 21 22 23 24 25 26 27 28 29 | # $Id: boundary4.tcl,v 1.3 2009/01/02 15:45:48 shane Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Many of the boundary tests depend on a working 64-bit implementation. if {![working_64bit_int]} { finish_test; return } } expr srand(0) # Generate interesting boundary numbers # foreach x { | > | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | # $Id: boundary4.tcl,v 1.3 2009/01/02 15:45:48 shane Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Many of the boundary tests depend on a working 64-bit implementation. if {![working_64bit_int]} { finish_test; return } ifcapable !altertable { finish_test; return } } expr srand(0) # Generate interesting boundary numbers # foreach x { |
︙ | ︙ |
Changes to test/boundary4.test.
︙ | ︙ | |||
16 17 18 19 20 21 22 23 24 25 26 27 28 29 | # $Id: boundary4.test,v 1.2 2009/01/02 15:45:48 shane Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Many of the boundary tests depend on a working 64-bit implementation. if {![working_64bit_int]} { finish_test; return } do_test boundary4-1.1 { db eval { CREATE TABLE t1(a,x); INSERT INTO t1(oid,a,x) VALUES(549755813887,1,'0000007fffffffff'); INSERT INTO t1(oid,a,x) VALUES(-8388608,2,'ffffffffff800000'); INSERT INTO t1(oid,a,x) VALUES(0,3,'0000000000000000'); | > | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | # $Id: boundary4.test,v 1.2 2009/01/02 15:45:48 shane Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Many of the boundary tests depend on a working 64-bit implementation. if {![working_64bit_int]} { finish_test; return } ifcapable !altertable { finish_test; return } do_test boundary4-1.1 { db eval { CREATE TABLE t1(a,x); INSERT INTO t1(oid,a,x) VALUES(549755813887,1,'0000007fffffffff'); INSERT INTO t1(oid,a,x) VALUES(-8388608,2,'ffffffffff800000'); INSERT INTO t1(oid,a,x) VALUES(0,3,'0000000000000000'); |
︙ | ︙ |
Changes to test/capi3c.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # This file implements regression tests for SQLite library. # # This is a copy of the capi3.test file that has been adapted to # test the new sqlite3_prepare_v2 interface. # | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # #*********************************************************************** # This file implements regression tests for SQLite library. # # This is a copy of the capi3.test file that has been adapted to # test the new sqlite3_prepare_v2 interface. # # $Id: capi3c.test,v 1.23 2009/07/22 07:27:57 danielk1977 Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl # Return the UTF-16 representation of the supplied UTF-8 string $str. # If $nt is true, append two 0x00 bytes as a nul terminator. |
︙ | ︙ | |||
1288 1289 1290 1291 1292 1293 1294 | sqlite3_finalize $STMT # For a multi-column result set where the same table column is repeated # in multiple columns of the output, verify that doing a UTF-8 to UTF-16 # conversion (or vice versa) on one column does not change the value of # the second. # | > | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | sqlite3_finalize $STMT # For a multi-column result set where the same table column is repeated # in multiple columns of the output, verify that doing a UTF-8 to UTF-16 # conversion (or vice versa) on one column does not change the value of # the second. # ifcapable utf16 { do_test capi3c-23.1 { set STMT [sqlite3_prepare_v2 db {SELECT b,b,b,b FROM t1} -1 TAIL] sqlite3_step $STMT } {SQLITE_ROW} do_test capi3c-23.2 { sqlite3_column_text16 $STMT 0 sqlite3_column_text $STMT 1 } {one} do_test capi3c-23.3 { sqlite3_column_text16 $STMT 2 sqlite3_column_text $STMT 3 } {one} sqlite3_finalize $STMT do_test capi3c-23.4 { set STMT [sqlite3_prepare_v2 db {SELECT b||'x',b,b,b FROM t1} -1 TAIL] sqlite3_step $STMT } {SQLITE_ROW} do_test capi3c-23.5 { sqlite3_column_text16 $STMT 0 sqlite3_column_text $STMT 1 } {one} do_test capi3c-23.6 { sqlite3_column_text16 $STMT 2 sqlite3_column_text $STMT 3 } {one} sqlite3_finalize $STMT } # Test decltype on some SELECT statements that contain sub-selects. # proc decltype {zSql} { set ret [list] set STMT [sqlite3_prepare_v2 db $zSql -1 TAIL] for {set i 0} {$i < [sqlite3_column_count $STMT]} {incr i} { lappend ret [sqlite3_column_decltype $STMT $i] } sqlite3_finalize $STMT return $ret } do_test capi3c-24.1 { execsql { CREATE TABLE t5(a INTEGER, b STRING, c DATETIME) } decltype {SELECT * FROM t5} } {INTEGER STRING DATETIME} do_test capi3c-24.2 { decltype {SELECT (SELECT c) FROM t5} } {DATETIME} do_test capi3c-24.3 { decltype {SELECT (SELECT * FROM (SELECT c)) FROM t5} } {DATETIME} do_test capi3c-24.4 { decltype {SELECT * FROM (SELECT * FROM t5 ORDER BY c LIMIT 1) ORDER BY b} } {INTEGER STRING DATETIME} do_test capi3c-24.5 { decltype { SELECT (SELECT x FROM (SELECT c AS x)) FROM (SELECT * FROM t5 ORDER BY c LIMIT 1) ORDER BY b } } {DATETIME} do_test capi3c-24.3 { decltype {SELECT (SELECT x FROM (SELECT t5.a AS x)) FROM t5} } {INTEGER} finish_test |
Added test/coalesce.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 | # 2009 November 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. # #*********************************************************************** # Additional test cases for the COALESCE() and IFNULL() functions. # set testdir [file dirname $argv0] source $testdir/tester.tcl do_test coalesce-1.0 { db eval { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d); INSERT INTO t1 VALUES(1, null, null, null); INSERT INTO t1 VALUES(2, 2, 99, 99); INSERT INTO t1 VALUES(3, null, 3, 99); INSERT INTO t1 VALUES(4, null, null, 4); INSERT INTO t1 VALUES(5, null, null, null); INSERT INTO t1 VALUES(6, 22, 99, 99); INSERT INTO t1 VALUES(7, null, 33, 99); INSERT INTO t1 VALUES(8, null, null, 44); SELECT coalesce(b,c,d) FROM t1 ORDER BY a; } } {{} 2 3 4 {} 22 33 44} do_test coalesce-1.1 { db eval { SELECT coalesce(d+c+b,d+c,d) FROM t1 ORDER BY a; } } {{} 200 102 4 {} 220 132 44} do_test coalesce-1.2 { db eval { SELECT ifnull(d+c+b,ifnull(d+c,d)) FROM t1 ORDER BY a; } } {{} 200 102 4 {} 220 132 44} do_test coalesce-1.3 { db eval { SELECT ifnull(ifnull(d+c+b,d+c),d) FROM t1 ORDER BY a; } } {{} 200 102 4 {} 220 132 44} do_test coalesce-1.4 { db eval { SELECT ifnull(ifnull(b,c),d) FROM t1 ORDER BY a; } } {{} 2 3 4 {} 22 33 44} do_test coalesce-1.5 { db eval { SELECT ifnull(b,ifnull(c,d)) FROM t1 ORDER BY a; } } {{} 2 3 4 {} 22 33 44} do_test coalesce-1.6 { db eval { SELECT coalesce(b,NOT b,-b,abs(b),lower(b),length(b),min(b,5),b*123,c) FROM t1 ORDER BY a; } } {{} 2 3 {} {} 22 33 {}} do_test coalesce-1.7 { db eval { SELECT ifnull(nullif(a,4),99) FROM t1 ORDER BY a; } } {1 2 3 99 5 6 7 8} do_test coalesce-1.8 { db eval { pragma vdbe_listing=on; SELECT coalesce( CASE WHEN b=2 THEN 123 END, CASE WHEN b=3 THEN 234 END, CASE WHEN c=3 THEN 345 WHEN c=33 THEN 456 END, d ) FROM t1 ORDER BY a; } } {{} 123 345 4 {} 99 456 44} finish_test |
Changes to test/corrupt.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests to make sure SQLite does not crash or # segfault if it sees a corrupt database file. # | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # #*********************************************************************** # 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: corrupt.test,v 1.12 2009/07/13 09:41:45 danielk1977 Exp $ catch {file delete -force test.db test.db-journal test.bu} set testdir [file dirname $argv0] source $testdir/tester.tcl # Construct a large database for testing. |
︙ | ︙ | |||
170 171 172 173 174 175 176 177 | db close sqlite3 db test.db catchsql { SELECT * FROM t1 WHERE x = 'abcde'; } } {1 {database disk image is malformed}} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | db close sqlite3 db test.db catchsql { SELECT * FROM t1 WHERE x = 'abcde'; } } {1 {database disk image is malformed}} do_test corrupt-4.1 { db close file delete -force test.db test.db-journal sqlite3 db test.db execsql { PRAGMA page_size = 1024; CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT); } for {set i 0} {$i < 10} {incr i} { set text [string repeat $i 220] execsql { INSERT INTO t1 VALUES($i, $text) } } execsql { CREATE INDEX i1 ON t1(b) } } {} do_test corrupt-4.2 { set iRoot [db one {SELECT rootpage FROM sqlite_master WHERE name = 'i1'}] set iOffset [hexio_get_int [hexio_read test.db [expr 12+($iRoot-1)*1024] 2]] set data [hexio_render_int32 [expr $iRoot - 1]] hexio_write test.db [expr ($iRoot-1)*1024 + $iOffset] $data db close sqlite3 db test.db # The following DELETE statement attempts to delete a cell stored on the # root page of index i1. After this cell is deleted it must be replaced # by a cell retrieved from the child page (a leaf) of the deleted cell. # This will fail, as the block modified the database image so that the # child page of the deleted cell is from a table (intkey) b-tree, not an # index b-tree as expected. At one point this was causing an assert() # to fail. catchsql { DELETE FROM t1 WHERE rowid = 3 } } {1 {database disk image is malformed}} do_test corrupt-5.1 { db close file delete -force test.db test.db-journal sqlite3 db test.db execsql { PRAGMA page_size = 1024 } set ct "CREATE TABLE t1(c0 " set i 0 while {[string length $ct] < 950} { append ct ", c[incr i]" } append ct ")" execsql $ct } {} do_test corrupt-5.2 { db close hexio_write test.db 108 00000000 sqlite3 db test.db catchsql { SELECT * FROM sqlite_master } } {1 {database disk image is malformed}} # At one point, the specific corruption caused by this test case was # causing a buffer overwrite. Although a crash was never demonstrated, # running this testcase under valgrind revealed the problem. do_test corrupt-6.1 { db close file delete -force test.db test.db-journal sqlite3 db test.db execsql { PRAGMA page_size = 1024; CREATE TABLE t1(x); } # The root page of t1 is 1024 bytes in size. The header is 8 bytes, and # each of the cells inserted by the following INSERT statements consume # 16 bytes (including the 2 byte cell-offset array entry). So the page # can contain up to 63 cells. for {set i 0} {$i < 63} {incr i} { execsql { INSERT INTO t1 VALUES( randomblob(10) ) } } # Free the cell stored right at the end of the page (at offset pgsz-14). execsql { DELETE FROM t1 WHERE rowid=1 } set rootpage [db one {SELECT rootpage FROM sqlite_master WHERE name = 't1'}] db close set offset [expr ($rootpage * 1024)-14+2] hexio_write test.db $offset 00FF sqlite3 db test.db catchsql { INSERT INTO t1 VALUES( randomblob(10) ) } } {1 {database disk image is malformed}} finish_test |
Changes to test/corrupt7.test.
︙ | ︙ | |||
10 11 12 13 14 15 16 | #*********************************************************************** # 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. It specifically focuses # on corrupt cell offsets in a btree page. # | | | 10 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 to make sure SQLite does not crash or # segfault if it sees a corrupt database file. It specifically focuses # on corrupt cell offsets in a btree page. # # $Id: corrupt7.test,v 1.8 2009/08/10 10:18:08 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # We must have the page_size pragma for these tests to work. # ifcapable !pager_pragmas { |
︙ | ︙ | |||
63 64 65 66 67 68 69 | ifcapable oversize_cell_check { do_test corrupt7-2.1 { db close hexio_write test.db 1062 FF sqlite3 db test.db db eval {PRAGMA integrity_check(1)} } {{*** in database main *** | | | | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | ifcapable oversize_cell_check { do_test corrupt7-2.1 { db close hexio_write test.db 1062 FF sqlite3 db test.db db eval {PRAGMA integrity_check(1)} } {{*** in database main *** Page 2: btreeInitPage() returns error code 11}} do_test corrupt7-2.2 { db close hexio_write test.db 1062 04 sqlite3 db test.db db eval {PRAGMA integrity_check(1)} } {{*** in database main *** Page 2: btreeInitPage() returns error code 11}} } else { do_test corrupt7-2.1 { db close hexio_write test.db 1062 FF sqlite3 db test.db db eval {PRAGMA integrity_check(1)} } {{*** in database main *** |
︙ | ︙ |
Changes to test/corruptB.test.
︙ | ︙ | |||
16 17 18 19 20 21 22 | # when there exists a page that is both an a descendent or ancestor of # itself. # # Also test that an SQLITE_CORRUPT error is returned if a B-Tree page # contains a (corrupt) reference to a page greater than the configured # maximum page number. # | | | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | # when there exists a page that is both an a descendent or ancestor of # itself. # # Also test that an SQLITE_CORRUPT error is returned if a B-Tree page # contains a (corrupt) reference to a page greater than the configured # maximum page number. # # $Id: corruptB.test,v 1.4 2009/07/21 19:25:24 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl do_test corruptB-1.1 { execsql { |
︙ | ︙ | |||
150 151 152 153 154 155 156 | db close file copy -force bak.db test.db hexio_write test.db [expr $offset+8] [hexio_render_int32 0x6FFFFFFF] } {4} do_test corruptB-2.1.2 { sqlite3 db test.db catchsql { SELECT * FROM t1 } | | | 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | db close file copy -force bak.db test.db hexio_write test.db [expr $offset+8] [hexio_render_int32 0x6FFFFFFF] } {4} do_test corruptB-2.1.2 { sqlite3 db test.db catchsql { SELECT * FROM t1 } } {1 {database or disk is full}} #--------------------------------------------------------------------------- # Corrupt the header-size field of a database record. # do_test corruptB-3.1.1 { db close |
︙ | ︙ |
Changes to test/corruptC.test.
︙ | ︙ | |||
11 12 13 14 15 16 17 | # 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. It creates a base # data base file, then tests that single byte corruptions in # increasingly larger quantities are handled gracefully. # | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # This file implements regression tests for SQLite library. # # This file implements tests to make sure SQLite does not crash or # segfault if it sees a corrupt database file. It creates a base # data base file, then tests that single byte corruptions in # increasingly larger quantities are handled gracefully. # # $Id: corruptC.test,v 1.14 2009/07/11 06:55:34 danielk1977 Exp $ catch {file delete -force test.db test.db-journal test.bu} set testdir [file dirname $argv0] source $testdir/tester.tcl # Construct a compact, dense database for testing. |
︙ | ︙ | |||
150 151 152 153 154 155 156 | hexio_write test.db 3119 [format %02x 0xdf] hexio_write test.db 4073 [format %02x 0xbf] sqlite3 db test.db catchsql {BEGIN; UPDATE t2 SET y='abcdef-uvwxyz'; ROLLBACK;} catchsql {PRAGMA integrity_check} } {0 {{*** in database main *** | > > > | | | | 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | hexio_write test.db 3119 [format %02x 0xdf] hexio_write test.db 4073 [format %02x 0xbf] sqlite3 db test.db catchsql {BEGIN; UPDATE t2 SET y='abcdef-uvwxyz'; ROLLBACK;} catchsql {PRAGMA integrity_check} } {0 {{*** in database main *** Page 4: btreeInitPage() returns error code 11}}} # {0 {{*** in database main *** # Corruption detected in cell 710 on page 4 # Multiple uses for byte 661 of page 4 # Fragmented space is 249 byte reported as 21 on page 4}}} # test that a corrupt free cell size is handled (seed 169595) do_test corruptC-2.6 { db close copy_file test.bu test.db # insert corrupt byte(s) |
︙ | ︙ |
Added test/e_fkey.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 | # 2009 October 7 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you 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 to verify the "testable statements" in the # foreignkeys.in document. # # The tests in this file are arranged to mirror the structure of # foreignkey.in, with one exception: The statements in section 2, which # deals with enabling/disabling foreign key support, is tested first, # before section 1. This is because some statements in section 2 deal # with builds that do not include complete foreign key support (because # either SQLITE_OMIT_TRIGGER or SQLITE_OMIT_FOREIGN_KEY was defined # at build time). # set testdir [file dirname $argv0] source $testdir/tester.tcl proc eqp {sql {db db}} { uplevel execsql [list "EXPLAIN QUERY PLAN $sql"] $db } ########################################################################### ### SECTION 2: Enabling Foreign Key Support ########################################################################### #------------------------------------------------------------------------- # /* EV: R-33710-56344 */ # # Test builds neither OMIT_FOREIGN_KEY or OMIT_TRIGGER defined have # foreign key functionality. # ifcapable trigger&&foreignkey { do_test e_fkey-49 { execsql { PRAGMA foreign_keys = ON; CREATE TABLE p(i PRIMARY KEY); CREATE TABLE c(j REFERENCES p ON UPDATE CASCADE); INSERT INTO p VALUES('hello'); INSERT INTO c VALUES('hello'); UPDATE p SET i = 'world'; SELECT * FROM c; } } {world} } #------------------------------------------------------------------------- # /* EV: R-44697-61543 */ # # Test the effects of defining OMIT_TRIGGER but not OMIT_FOREIGN_KEY. # # /* EV: R-22567-44039 */ # /* EV: R-41784-13339 */ # # Specifically, test that "PRAGMA foreign_keys" is a no-op in this case. # When using the pragma to query the current setting, 0 rows are returned. # reset_db ifcapable !trigger&&foreignkey { do_test e_fkey-51.1 { execsql { PRAGMA foreign_keys = ON; CREATE TABLE p(i PRIMARY KEY); CREATE TABLE c(j REFERENCES p ON UPDATE CASCADE); INSERT INTO p VALUES('hello'); INSERT INTO c VALUES('hello'); UPDATE p SET i = 'world'; SELECT * FROM c; } } {hello} do_test e_fkey-51.2 { execsql { PRAGMA foreign_key_list(c) } } {0 0 p j {} CASCADE {NO ACTION} NONE} do_test e_fkey-51.3 { execsql { PRAGMA foreign_keys } } {} } #------------------------------------------------------------------------- # /* EV: R-58428-36660 */ # # Test the effects of defining OMIT_FOREIGN_KEY. # # /* EV: R-58428-36660 */ # # Specifically, test that foreign key constraints cannot even be parsed # in such a build. # reset_db ifcapable !foreignkey { do_test e_fkey-52.1 { execsql { CREATE TABLE p(i PRIMARY KEY) } catchsql { CREATE TABLE c(j REFERENCES p ON UPDATE CASCADE) } } {1 {near "ON": syntax error}} do_test e_fkey-52.2 { # This is allowed, as in this build, "REFERENCES" is not a keyword. # The declared datatype of column j is "REFERENCES p". execsql { CREATE TABLE c(j REFERENCES p) } } {} do_test e_fkey-52.3 { execsql { PRAGMA table_info(c) } } {0 j {REFERENCES p} 0 {} 0} do_test e_fkey-52.4 { execsql { PRAGMA foreign_key_list(c) } } {} do_test e_fkey-52.5 { execsql { PRAGMA foreign_keys } } {} } ifcapable !foreignkey||!trigger { finish_test ; return } reset_db #------------------------------------------------------------------------- # /* EV: R-07280-60510 */ # # Test that even if foreign keys are supported by the build, they must # be enabled using "PRAGMA foreign_keys = ON" (or similar). # # /* EV: R-59578-04990 */ # # This also tests that foreign key constraints are disabled by default. # drop_all_tables do_test e_fkey-53.1 { execsql { CREATE TABLE p(i PRIMARY KEY); CREATE TABLE c(j REFERENCES p ON UPDATE CASCADE); INSERT INTO p VALUES('hello'); INSERT INTO c VALUES('hello'); UPDATE p SET i = 'world'; SELECT * FROM c; } } {hello} do_test e_fkey-53.2 { execsql { DELETE FROM c; DELETE FROM p; PRAGMA foreign_keys = ON; INSERT INTO p VALUES('hello'); INSERT INTO c VALUES('hello'); UPDATE p SET i = 'world'; SELECT * FROM c; } } {world} #------------------------------------------------------------------------- # /* EV: R-15278-54456 */ # /* EV: R-11255-19907 */ # # Test that the application can use "PRAGMA foreign_keys" to query for # whether or not foreign keys are currently enabled. This also tests # the example code in section 2 of foreignkeys.in. # reset_db do_test e_fkey-54.1 { execsql { PRAGMA foreign_keys } } {0} do_test e_fkey-54.2 { execsql { PRAGMA foreign_keys = ON; PRAGMA foreign_keys; } } {1} do_test e_fkey-54.3 { execsql { PRAGMA foreign_keys = OFF; PRAGMA foreign_keys; } } {0} #------------------------------------------------------------------------- # /* EV: R-46649-58537 */ # # Test that it is not possible to enable or disable foreign key support # while not in auto-commit mode. # reset_db do_test e_fkey-55.1 { execsql { PRAGMA foreign_keys = ON; CREATE TABLE t1(a UNIQUE, b); CREATE TABLE t2(c, d REFERENCES t1(a)); INSERT INTO t1 VALUES(1, 2); INSERT INTO t2 VALUES(2, 1); BEGIN; PRAGMA foreign_keys = OFF; } catchsql { DELETE FROM t1 } } {1 {foreign key constraint failed}} do_test e_fkey-55.2 { execsql { PRAGMA foreign_keys } } {1} do_test e_fkey-55.3 { execsql { COMMIT; PRAGMA foreign_keys = OFF; BEGIN; PRAGMA foreign_keys = ON; DELETE FROM t1; PRAGMA foreign_keys; } } {0} do_test e_fkey-55.4 { execsql COMMIT } {} ########################################################################### ### SECTION 1: Introduction to Foreign Key Constraints ########################################################################### execsql "PRAGMA foreign_keys = ON" #------------------------------------------------------------------------- # /* EV: R-04042-24825 */ # # Verify that the syntax in the first example in section 1 is valid. # do_test e_fkey-38.1 { execsql { CREATE TABLE artist( artistid INTEGER PRIMARY KEY, artistname TEXT ); CREATE TABLE track( trackid INTEGER, trackname TEXT, trackartist INTEGER, FOREIGN KEY(trackartist) REFERENCES artist(artistid) ); } } {} #------------------------------------------------------------------------- # /* EV: R-61362-32087 */ # # Attempting to insert a row into the 'track' table that corresponds # to no row in the 'artist' table fails. # do_test e_fkey-39.1 { catchsql { INSERT INTO track VALUES(1, 'track 1', 1) } } {1 {foreign key constraint failed}} do_test e_fkey-39.2 { execsql { INSERT INTO artist VALUES(2, 'artist 1') } catchsql { INSERT INTO track VALUES(1, 'track 1', 1) } } {1 {foreign key constraint failed}} do_test e_fkey-39.2 { execsql { INSERT INTO track VALUES(1, 'track 1', 2) } } {} #------------------------------------------------------------------------- # /* EV: R-24401-52400 */ # # Attempting to delete a row from the 'artist' table while there are # dependent rows in the track table also fails. # do_test e_fkey-40.1 { catchsql { DELETE FROM artist WHERE artistid = 2 } } {1 {foreign key constraint failed}} do_test e_fkey-40.2 { execsql { DELETE FROM track WHERE trackartist = 2; DELETE FROM artist WHERE artistid = 2; } } {} #------------------------------------------------------------------------- # /* EV: R-23980-48859 */ # # If the foreign key column (trackartist) in table 'track' is set to NULL, # there is no requirement for a matching row in the 'artist' table. # do_test e_fkey-41.1 { execsql { INSERT INTO track VALUES(1, 'track 1', NULL); INSERT INTO track VALUES(2, 'track 2', NULL); } } {} do_test e_fkey-41.2 { execsql { SELECT * FROM artist } } {} do_test e_fkey-41.3 { # Setting the trackid to a non-NULL value fails, of course. catchsql { UPDATE track SET trackartist = 5 WHERE trackid = 1 } } {1 {foreign key constraint failed}} do_test e_fkey-41.4 { execsql { INSERT INTO artist VALUES(5, 'artist 5'); UPDATE track SET trackartist = 5 WHERE trackid = 1; } catchsql { DELETE FROM artist WHERE artistid = 5} } {1 {foreign key constraint failed}} do_test e_fkey-41.5 { execsql { UPDATE track SET trackartist = NULL WHERE trackid = 1; DELETE FROM artist WHERE artistid = 5; } } {} #------------------------------------------------------------------------- # /* EV: R-52486-21352 */ # # Test that the following is true fo all rows in the track table: # # trackartist IS NULL OR # EXISTS(SELECT 1 FROM artist WHERE artistid=trackartist) # # This procedure executes a test case to check that statement # R-52486-21352 is true after executing the SQL statement passed. # as the second argument. proc test_r52486_21352 {tn sql} { set res [catchsql $sql] set results { {0 {}} {1 {PRIMARY KEY must be unique}} {1 {foreign key constraint failed}} } if {[lsearch $results $res]<0} { error $res } do_test e_fkey-42.$tn { execsql { SELECT count(*) FROM track WHERE NOT ( trackartist IS NULL OR EXISTS(SELECT 1 FROM artist WHERE artistid=trackartist) ) } } {0} } # Execute a series of random INSERT, UPDATE and DELETE operations # (some of which may fail due to FK or PK constraint violations) on # the two tables in the example schema. Test that R-52486-21352 # is true after executing each operation. # set Template { {INSERT INTO track VALUES($t, 'track $t', $a)} {DELETE FROM track WHERE trackid = $t} {UPDATE track SET trackartist = $a WHERE trackid = $t} {INSERT INTO artist VALUES($a, 'artist $a')} {DELETE FROM artist WHERE artistid = $a} {UPDATE artist SET artistid = $a2 WHERE artistid = $a} } for {set i 0} {$i < 500} {incr i} { set a [expr int(rand()*10)] set a2 [expr int(rand()*10)] set t [expr int(rand()*50)] set sql [subst [lindex $Template [expr int(rand()*6)]]] test_r52486_21352 $i $sql } #------------------------------------------------------------------------- # /* EV: R-42412-59321 */ # # Check that a NOT NULL constraint can be added to the example schema # to prohibit NULL child keys from being inserted. # drop_all_tables do_test e_fkey-48.1 { execsql { CREATE TABLE artist( artistid INTEGER PRIMARY KEY, artistname TEXT ); CREATE TABLE track( trackid INTEGER, trackname TEXT, trackartist INTEGER NOT NULL, FOREIGN KEY(trackartist) REFERENCES artist(artistid) ); } } {} do_test e_fkey-48.2 { catchsql { INSERT INTO track VALUES(14, 'Mr. Bojangles', NULL) } } {1 {track.trackartist may not be NULL}} #------------------------------------------------------------------------- # /* EV: R-17902-59250 */ # # Test an example from foreignkeys.html. # drop_all_tables do_test e_fkey-43.1 { execsql { CREATE TABLE artist( artistid INTEGER PRIMARY KEY, artistname TEXT ); CREATE TABLE track( trackid INTEGER, trackname TEXT, trackartist INTEGER, FOREIGN KEY(trackartist) REFERENCES artist(artistid) ); INSERT INTO artist VALUES(1, 'Dean Martin'); INSERT INTO artist VALUES(2, 'Frank Sinatra'); INSERT INTO track VALUES(11, 'That''s Amore', 1); INSERT INTO track VALUES(12, 'Christmas Blues', 1); INSERT INTO track VALUES(13, 'My Way', 2); } } {} do_test e_fkey-43.2 { catchsql { INSERT INTO track VALUES(14, 'Mr. Bojangles', 3) } } {1 {foreign key constraint failed}} do_test e_fkey-43.3 { execsql { INSERT INTO track VALUES(14, 'Mr. Bojangles', NULL) } } {} do_test e_fkey-43.4 { catchsql { UPDATE track SET trackartist = 3 WHERE trackname = 'Mr. Bojangles'; } } {1 {foreign key constraint failed}} do_test e_fkey-43.5 { execsql { INSERT INTO artist VALUES(3, 'Sammy Davis Jr.'); UPDATE track SET trackartist = 3 WHERE trackname = 'Mr. Bojangles'; INSERT INTO track VALUES(15, 'Boogie Woogie', 3); } } {} #------------------------------------------------------------------------- # /* EV: R-15034-64331 */ # # Test the second example from the first section of foreignkeys.html. # do_test e_fkey-44.1 { catchsql { DELETE FROM artist WHERE artistname = 'Frank Sinatra'; } } {1 {foreign key constraint failed}} do_test e_fkey-44.2 { execsql { DELETE FROM track WHERE trackname = 'My Way'; DELETE FROM artist WHERE artistname = 'Frank Sinatra'; } } {} do_test e_fkey-44.3 { catchsql { UPDATE artist SET artistid=4 WHERE artistname = 'Dean Martin'; } } {1 {foreign key constraint failed}} do_test e_fkey-44.4 { execsql { DELETE FROM track WHERE trackname IN('That''s Amore', 'Christmas Blues'); UPDATE artist SET artistid=4 WHERE artistname = 'Dean Martin'; } } {} #------------------------------------------------------------------------- # /* EV: R-56032-24923 */ # # Test that a foreign key constraint is satisifed if "for each row in the child # table either one or more of the child key columns are NULL, or there exists a # row in the parent table for which each parent key column contains a value # equal to the value in its associated child key column". # # /* EV: R-57765-12380 */ # # Test also that the comparison rules are used when testing if there # is a matching row in the parent table of a foreign key constraint. # drop_all_tables do_test e_fkey-45.1 { execsql { CREATE TABLE par(p PRIMARY KEY); CREATE TABLE chi(c REFERENCES par); INSERT INTO par VALUES(1); INSERT INTO par VALUES('1'); INSERT INTO par VALUES(X'31'); SELECT typeof(p) FROM par; } } {integer text blob} proc test_efkey_45 {tn isError sql} { do_test e_fkey-45.$tn.1 " catchsql {$sql} " [lindex {{0 {}} {1 {foreign key constraint failed}}} $isError] do_test e_fkey-45.$tn.2 { execsql { SELECT * FROM chi WHERE c IS NOT NULL AND c NOT IN (SELECT p FROM par) } } {} } test_efkey_45 1 0 "INSERT INTO chi VALUES(1)" test_efkey_45 2 1 "INSERT INTO chi VALUES('1.0')" test_efkey_45 3 0 "INSERT INTO chi VALUES('1')" test_efkey_45 4 1 "DELETE FROM par WHERE p = '1'" test_efkey_45 5 0 "DELETE FROM chi WHERE c = '1'" test_efkey_45 6 0 "DELETE FROM par WHERE p = '1'" test_efkey_45 7 1 "INSERT INTO chi VALUES('1')" test_efkey_45 8 0 "INSERT INTO chi VALUES(X'31')" test_efkey_45 9 1 "INSERT INTO chi VALUES(X'32')" #------------------------------------------------------------------------- # /* EV: R-15796-47513 */ # # Specifically, test that when comparing child and parent key values the # default collation sequence of the parent key column is used. # drop_all_tables do_test e_fkey-46.1 { execsql { CREATE TABLE t1(a COLLATE nocase PRIMARY KEY); CREATE TABLE t2(b REFERENCES t1); } } {} do_test e_fkey-46.2 { execsql { INSERT INTO t1 VALUES('oNe'); INSERT INTO t2 VALUES('one'); INSERT INTO t2 VALUES('ONE'); UPDATE t2 SET b = 'OnE'; UPDATE t1 SET a = 'ONE'; } } {} do_test e_fkey-46.3 { catchsql { UPDATE t2 SET b = 'two' WHERE rowid = 1 } } {1 {foreign key constraint failed}} do_test e_fkey-46.4 { catchsql { DELETE FROM t1 WHERE rowid = 1 } } {1 {foreign key constraint failed}} #------------------------------------------------------------------------- # /* EV: R-04240-13860 */ # # Specifically, test that when comparing child and parent key values the # affinity of the parent key column is applied to the child key value # before the comparison takes place. # drop_all_tables do_test e_fkey-47.1 { execsql { CREATE TABLE t1(a NUMERIC PRIMARY KEY); CREATE TABLE t2(b TEXT REFERENCES t1); } } {} do_test e_fkey-47.2 { execsql { INSERT INTO t1 VALUES(1); INSERT INTO t1 VALUES(2); INSERT INTO t1 VALUES('three'); INSERT INTO t2 VALUES('2.0'); SELECT b, typeof(b) FROM t2; } } {2.0 text} do_test e_fkey-47.3 { execsql { SELECT typeof(a) FROM t1 } } {integer integer text} do_test e_fkey-47.4 { catchsql { DELETE FROM t1 WHERE rowid = 2 } } {1 {foreign key constraint failed}} ########################################################################### ### SECTION 3: Required and Suggested Database Indexes ########################################################################### #------------------------------------------------------------------------- # /* EV: R-13435-26311 */ # # A parent key must be either a PRIMARY KEY, subject to a UNIQUE # constraint, or have a UNIQUE index created on it. # # /* EV: R-00376-39212 */ # # Also test that if a parent key is not subject to a PRIMARY KEY or UNIQUE # constraint, but does have a UNIQUE index created on it, then the UNIQUE index # must use the default collation sequences associated with the parent key # columns. # drop_all_tables do_test e_fkey-57.1 { execsql { CREATE TABLE t2(a REFERENCES t1(x)); } } {} proc test_efkey_57 {tn isError sql} { catchsql { DROP TABLE t1 } execsql $sql do_test e_fkey-57.$tn { catchsql { INSERT INTO t2 VALUES(NULL) } } [lindex {{0 {}} {1 {foreign key mismatch}}} $isError] } test_efkey_57 2 0 { CREATE TABLE t1(x PRIMARY KEY) } test_efkey_57 3 0 { CREATE TABLE t1(x UNIQUE) } test_efkey_57 4 0 { CREATE TABLE t1(x); CREATE UNIQUE INDEX t1i ON t1(x) } test_efkey_57 5 1 { CREATE TABLE t1(x); CREATE UNIQUE INDEX t1i ON t1(x COLLATE nocase); } test_efkey_57 6 1 { CREATE TABLE t1(x) } test_efkey_57 7 1 { CREATE TABLE t1(x, y, PRIMARY KEY(x, y)) } test_efkey_57 8 1 { CREATE TABLE t1(x, y, UNIQUE(x, y)) } test_efkey_57 9 1 { CREATE TABLE t1(x, y); CREATE UNIQUE INDEX t1i ON t1(x, y); } #------------------------------------------------------------------------- # This block tests an example in foreignkeys.html. Several testable # statements refer to this example, as follows # # /* EV: R-27484-01467 */ # # FK Constraints on child1, child2 and child3 are Ok. # # /* EV: R-51039-44840 */ # # Problem with FK on child4. # # /* EV: R-01060-48788 */ # # Problem with FK on child5. # # /* EV: R-63088-37469 */ # # Problem with FK on child6 and child7. # drop_all_tables do_test e_fkey-56.1 { execsql { CREATE TABLE parent(a PRIMARY KEY, b UNIQUE, c, d, e, f); CREATE UNIQUE INDEX i1 ON parent(c, d); CREATE INDEX i2 ON parent(e); CREATE UNIQUE INDEX i3 ON parent(f COLLATE nocase); CREATE TABLE child1(f, g REFERENCES parent(a)); -- Ok CREATE TABLE child2(h, i REFERENCES parent(b)); -- Ok CREATE TABLE child3(j, k, FOREIGN KEY(j, k) REFERENCES parent(c, d)); -- Ok CREATE TABLE child4(l, m REFERENCES parent(e)); -- Err CREATE TABLE child5(n, o REFERENCES parent(f)); -- Err CREATE TABLE child6(p, q, FOREIGN KEY(p,q) REFERENCES parent(b, c)); -- Err CREATE TABLE child7(r REFERENCES parent(c)); -- Err } } {} do_test e_fkey-56.2 { execsql { INSERT INTO parent VALUES(1, 2, 3, 4, 5, 6); INSERT INTO child1 VALUES('xxx', 1); INSERT INTO child2 VALUES('xxx', 2); INSERT INTO child3 VALUES(3, 4); } } {} do_test e_fkey-56.2 { catchsql { INSERT INTO child4 VALUES('xxx', 5) } } {1 {foreign key mismatch}} do_test e_fkey-56.3 { catchsql { INSERT INTO child5 VALUES('xxx', 6) } } {1 {foreign key mismatch}} do_test e_fkey-56.4 { catchsql { INSERT INTO child6 VALUES(2, 3) } } {1 {foreign key mismatch}} do_test e_fkey-56.5 { catchsql { INSERT INTO child7 VALUES(3) } } {1 {foreign key mismatch}} #------------------------------------------------------------------------- # /* EV: R-45488-08504 */ # /* EV: R-48391-38472 */ # /* EV: R-03108-63659 */ # /* EV: R-60781-26576 */ # # Test errors in the database schema that are detected while preparing # DML statements. The error text for these messages always matches # either "foreign key mismatch" or "no such table*" (using [string match]). # do_test e_fkey-66.1 { execsql { CREATE TABLE c1(c REFERENCES nosuchtable, d); CREATE TABLE p2(a, b, UNIQUE(a, b)); CREATE TABLE c2(c, d, FOREIGN KEY(c, d) REFERENCES p2(a, x)); CREATE TABLE p3(a PRIMARY KEY, b); CREATE TABLE c3(c REFERENCES p3(b), d); CREATE TABLE p4(a PRIMARY KEY, b); CREATE UNIQUE INDEX p4i ON p4(b COLLATE nocase); CREATE TABLE c4(c REFERENCES p4(b), d); CREATE TABLE p5(a PRIMARY KEY, b COLLATE nocase); CREATE UNIQUE INDEX p5i ON p5(b COLLATE binary); CREATE TABLE c5(c REFERENCES p5(b), d); CREATE TABLE p6(a PRIMARY KEY, b); CREATE TABLE c6(c, d, FOREIGN KEY(c, d) REFERENCES p6); CREATE TABLE p7(a, b, PRIMARY KEY(a, b)); CREATE TABLE c7(c, d REFERENCES p7); } } {} foreach {tn tbl ptbl err} { 2 c1 {} "no such table: main.nosuchtable" 3 c2 p2 "foreign key mismatch" 4 c3 p3 "foreign key mismatch" 5 c4 p4 "foreign key mismatch" 6 c5 p5 "foreign key mismatch" 7 c6 p6 "foreign key mismatch" 8 c7 p7 "foreign key mismatch" } { do_test e_fkey-66.$tn.1 { catchsql "INSERT INTO $tbl VALUES('a', 'b')" } [list 1 $err] do_test e_fkey-66.$tn.2 { catchsql "UPDATE $tbl SET c = ?, d = ?" } [list 1 $err] do_test e_fkey-66.$tn.3 { catchsql "INSERT INTO $tbl SELECT ?, ?" } [list 1 $err] if {$ptbl ne ""} { do_test e_fkey-66.$tn.4 { catchsql "DELETE FROM $ptbl" } [list 1 $err] do_test e_fkey-66.$tn.5 { catchsql "UPDATE $ptbl SET a = ?, b = ?" } [list 1 $err] do_test e_fkey-66.$tn.6 { catchsql "INSERT INTO $ptbl SELECT ?, ?" } [list 1 $err] } } #------------------------------------------------------------------------- # /* EV: R-19353-43643 */ # # Test the example of foreign key mismatch errors caused by implicitly # mapping a child key to the primary key of the parent table when the # child key consists of a different number of columns to that primary key. # drop_all_tables do_test e_fkey-58.1 { execsql { CREATE TABLE parent2(a, b, PRIMARY KEY(a,b)); CREATE TABLE child8(x, y, FOREIGN KEY(x,y) REFERENCES parent2); -- Ok CREATE TABLE child9(x REFERENCES parent2); -- Err CREATE TABLE child10(x,y,z, FOREIGN KEY(x,y,z) REFERENCES parent2); -- Err } } {} do_test e_fkey-58.2 { execsql { INSERT INTO parent2 VALUES('I', 'II'); INSERT INTO child8 VALUES('I', 'II'); } } {} do_test e_fkey-58.3 { catchsql { INSERT INTO child9 VALUES('I') } } {1 {foreign key mismatch}} do_test e_fkey-58.4 { catchsql { INSERT INTO child9 VALUES('II') } } {1 {foreign key mismatch}} do_test e_fkey-58.5 { catchsql { INSERT INTO child9 VALUES(NULL) } } {1 {foreign key mismatch}} do_test e_fkey-58.6 { catchsql { INSERT INTO child10 VALUES('I', 'II', 'III') } } {1 {foreign key mismatch}} do_test e_fkey-58.7 { catchsql { INSERT INTO child10 VALUES(1, 2, 3) } } {1 {foreign key mismatch}} do_test e_fkey-58.8 { catchsql { INSERT INTO child10 VALUES(NULL, NULL, NULL) } } {1 {foreign key mismatch}} #------------------------------------------------------------------------- # /* EV: R-23682-59820 */ # # Test errors that are reported when creating the child table. # Specifically: # # * different number of child and parent key columns, and # * child columns that do not exist. # # /* EV: R-33883-28833 */ # # These errors are reported whether or not FK support is enabled. # drop_all_tables foreach fk [list OFF ON] { execsql "PRAGMA foreign_keys = $fk" set i 0 foreach {sql error} { "CREATE TABLE child1(a, b, FOREIGN KEY(a, b) REFERENCES p(c))" {number of columns in foreign key does not match the number of columns in the referenced table} "CREATE TABLE child2(a, b, FOREIGN KEY(a, b) REFERENCES p(c, d, e))" {number of columns in foreign key does not match the number of columns in the referenced table} "CREATE TABLE child2(a, b, FOREIGN KEY(a, c) REFERENCES p(c, d))" {unknown column "c" in foreign key definition} "CREATE TABLE child2(a, b, FOREIGN KEY(c, b) REFERENCES p(c, d))" {unknown column "c" in foreign key definition} } { do_test e_fkey-59.$fk.[incr i] { catchsql $sql } [list 1 $error] } } #------------------------------------------------------------------------- # /* EV: R-47109-40581 */ # # Test that a REFERENCING clause that does not specify parent key columns # implicitly maps to the primary key of the parent table. # do_test e_fkey-60.1 { execsql { CREATE TABLE p1(a, b, PRIMARY KEY(a, b)); CREATE TABLE p2(a, b PRIMARY KEY); CREATE TABLE c1(c, d, FOREIGN KEY(c, d) REFERENCES p1); CREATE TABLE c2(a, b REFERENCES p2); } } {} proc test_efkey_60 {tn isError sql} { do_test e_fkey-60.$tn " catchsql {$sql} " [lindex {{0 {}} {1 {foreign key constraint failed}}} $isError] } test_efkey_60 2 1 "INSERT INTO c1 VALUES(239, 231)" test_efkey_60 3 0 "INSERT INTO p1 VALUES(239, 231)" test_efkey_60 4 0 "INSERT INTO c1 VALUES(239, 231)" test_efkey_60 5 1 "INSERT INTO c2 VALUES(239, 231)" test_efkey_60 6 0 "INSERT INTO p2 VALUES(239, 231)" test_efkey_60 7 0 "INSERT INTO c2 VALUES(239, 231)" #------------------------------------------------------------------------- # /* EV: R-15417-28014 */ # # Test that an index on on the child key columns of an FK constraint # is optional. # # /* EV: R-15741-50893 */ # # Also test that if an index is created on the child key columns, it does # not make a difference whether or not it is a UNIQUE index. # drop_all_tables do_test e_fkey-61.1 { execsql { CREATE TABLE parent(x, y, UNIQUE(y, x)); CREATE TABLE c1(a, b, FOREIGN KEY(a, b) REFERENCES parent(x, y)); CREATE TABLE c2(a, b, FOREIGN KEY(a, b) REFERENCES parent(x, y)); CREATE TABLE c3(a, b, FOREIGN KEY(a, b) REFERENCES parent(x, y)); CREATE INDEX c2i ON c2(a, b); CREATE UNIQUE INDEX c3i ON c2(b, a); } } {} proc test_efkey_61 {tn isError sql} { do_test e_fkey-61.$tn " catchsql {$sql} " [lindex {{0 {}} {1 {foreign key constraint failed}}} $isError] } foreach {tn c} [list 2 c1 3 c2 4 c3] { test_efkey_61 $tn.1 1 "INSERT INTO $c VALUES(1, 2)" test_efkey_61 $tn.2 0 "INSERT INTO parent VALUES(1, 2)" test_efkey_61 $tn.3 0 "INSERT INTO $c VALUES(1, 2)" execsql "DELETE FROM $c ; DELETE FROM parent" } #------------------------------------------------------------------------- # /* EV: R-00279-52283 */ # # Test an example showing that when a row is deleted from the parent # table, the child table is queried for orphaned rows as follows: # # SELECT rowid FROM track WHERE trackartist = ? # # /* EV: R-23302-30956 */ # # Also test that if the SELECT above would return any rows, a foreign # key constraint is violated. # do_test e_fkey-62.1 { execsql { CREATE TABLE artist( artistid INTEGER PRIMARY KEY, artistname TEXT ); CREATE TABLE track( trackid INTEGER, trackname TEXT, trackartist INTEGER, FOREIGN KEY(trackartist) REFERENCES artist(artistid) ); } } {} do_test e_fkey-62.2 { execsql { PRAGMA foreign_keys = OFF; EXPLAIN QUERY PLAN DELETE FROM artist WHERE 1; EXPLAIN QUERY PLAN SELECT rowid FROM track WHERE trackartist = ?; } } {0 0 {TABLE artist} 0 0 {TABLE track}} do_test e_fkey-62.3 { execsql { PRAGMA foreign_keys = ON; EXPLAIN QUERY PLAN DELETE FROM artist WHERE 1; } } {0 0 {TABLE artist} 0 0 {TABLE track}} do_test e_fkey-62.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); INSERT INTO track VALUES(2, 'track 2', 6); } } {} do_test e_fkey-62.5 { concat \ [execsql { SELECT rowid FROM track WHERE trackartist = 5 }] \ [catchsql { DELETE FROM artist WHERE artistid = 5 }] } {1 1 {foreign key constraint failed}} do_test e_fkey-62.6 { concat \ [execsql { SELECT rowid FROM track WHERE trackartist = 7 }] \ [catchsql { DELETE FROM artist WHERE artistid = 7 }] } {0 {}} do_test e_fkey-62.7 { concat \ [execsql { SELECT rowid FROM track WHERE trackartist = 6 }] \ [catchsql { DELETE FROM artist WHERE artistid = 6 }] } {2 1 {foreign key constraint failed}} #------------------------------------------------------------------------- # /* EV: R-54172-55848 */ # # Test that when a row is deleted from the parent table of an FK # constraint, the child table is queried for orphaned rows. The # query is equivalent to: # # SELECT rowid FROM <child-table> WHERE <child-key> = :parent_key_value # # /* EV: R-61616-46700 */ # # Also test that when a row is inserted into the parent table, or when the # parent key values of an existing row are modified, a query equivalent # to the following is planned. In some cases it is not executed, but it # is always planned. # # SELECT rowid FROM <child-table> WHERE <child-key> = :parent_key_value # # drop_all_tables do_test e_fkey-64.1 { execsql { CREATE TABLE parent(x, y, UNIQUE(y, x)) } } {} foreach {tn sql} { 2 { CREATE TABLE child(a, b, FOREIGN KEY(a, b) REFERENCES parent(x, y)) } 3 { CREATE TABLE child(a, b, FOREIGN KEY(a, b) REFERENCES parent(x, y)); CREATE INDEX childi ON child(a, b); } 4 { CREATE TABLE child(a, b, FOREIGN KEY(a, b) REFERENCES parent(x, y)); CREATE UNIQUE INDEX childi ON child(b, a); } } { execsql $sql execsql {PRAGMA foreign_keys = OFF} set delete [concat \ [eqp "DELETE FROM parent WHERE 1"] \ [eqp "SELECT rowid FROM child WHERE a = ? AND b = ?"] ] set update [concat \ [eqp "UPDATE parent SET x=?, y=?"] \ [eqp "SELECT rowid FROM child WHERE a = ? AND b = ?"] \ [eqp "SELECT rowid FROM child WHERE a = ? AND b = ?"] ] execsql {PRAGMA foreign_keys = ON} do_test e_fkey-64.$tn.1 { eqp "DELETE FROM parent WHERE 1" } $delete do_test e_fkey-64.$tn.2 { eqp "UPDATE parent set x=?, y=?" } $update execsql {DROP TABLE child} } #------------------------------------------------------------------------- # /* EV: R-14553-34013 */ # # Test the example schema at the end of section 3. Also test that is # is "efficient". In this case "efficient" means that foreign key # related operations on the parent table do not provoke linear scans. # drop_all_tables do_test e_fkey-63.1 { execsql { CREATE TABLE artist( artistid INTEGER PRIMARY KEY, artistname TEXT ); CREATE TABLE track( trackid INTEGER, trackname TEXT, trackartist INTEGER REFERENCES artist ); CREATE INDEX trackindex ON track(trackartist); } } {} do_test e_fkey-63.2 { eqp { INSERT INTO artist VALUES(?, ?) } } {} do_test e_fkey-63.3 { eqp { UPDATE artist SET artistid = ?, artistname = ? } } [list \ 0 0 {TABLE artist} \ 0 0 {TABLE track WITH INDEX trackindex} \ 0 0 {TABLE track WITH INDEX trackindex} ] do_test e_fkey-63.4 { eqp { DELETE FROM artist } } [list \ 0 0 {TABLE artist} \ 0 0 {TABLE track WITH INDEX trackindex} ] ########################################################################### ### SECTION 4.1: Composite Foreign Key Constraints ########################################################################### #------------------------------------------------------------------------- # /* EV: R-41062-34431 */ # # Check that parent and child keys must have the same number of columns. # foreach {tn sql err} { 1 "CREATE TABLE c(jj REFERENCES p(x, y))" {foreign key on jj should reference only one column of table p} 2 "CREATE TABLE c(jj REFERENCES p())" {near ")": syntax error} 3 "CREATE TABLE c(jj, FOREIGN KEY(jj) REFERENCES p(x, y))" {number of columns in foreign key does not match the number of columns in the referenced table} 4 "CREATE TABLE c(jj, FOREIGN KEY(jj) REFERENCES p())" {near ")": syntax error} 5 "CREATE TABLE c(ii, jj, FOREIGN KEY(jj, ii) REFERENCES p())" {near ")": syntax error} 6 "CREATE TABLE c(ii, jj, FOREIGN KEY(jj, ii) REFERENCES p(x))" {number of columns in foreign key does not match the number of columns in the referenced table} 7 "CREATE TABLE c(ii, jj, FOREIGN KEY(jj, ii) REFERENCES p(x,y,z))" {number of columns in foreign key does not match the number of columns in the referenced table} } { drop_all_tables do_test e_fkey-65.$tn [list catchsql $sql] [list 1 $err] } do_test e_fkey-65.8 { drop_all_tables execsql { CREATE TABLE p(x PRIMARY KEY); CREATE TABLE c(a, b, FOREIGN KEY(a,b) REFERENCES p); } catchsql {DELETE FROM p} } {1 {foreign key mismatch}} do_test e_fkey-65.9 { drop_all_tables execsql { CREATE TABLE p(x, y, PRIMARY KEY(x,y)); CREATE TABLE c(a REFERENCES p); } catchsql {DELETE FROM p} } {1 {foreign key mismatch}} #------------------------------------------------------------------------- # /* EV: R-24676-09859 */ # # Test the example schema in the "Composite Foreign Key Constraints" # section. # do_test e_fkey-36.1 { execsql { CREATE TABLE album( albumartist TEXT, albumname TEXT, albumcover BINARY, PRIMARY KEY(albumartist, albumname) ); CREATE TABLE song( songid INTEGER, songartist TEXT, songalbum TEXT, songname TEXT, FOREIGN KEY(songartist, songalbum) REFERENCES album(albumartist,albumname) ); } } {} do_test e_fkey-36.2 { execsql { INSERT INTO album VALUES('Elvis Presley', 'Elvis'' Christmas Album', NULL); INSERT INTO song VALUES( 1, 'Elvis Presley', 'Elvis'' Christmas Album', 'Here Comes Santa Clause' ); } } {} do_test e_fkey-36.3 { catchsql { INSERT INTO song VALUES(2, 'Elvis Presley', 'Elvis Is Back!', 'Fever'); } } {1 {foreign key constraint failed}} #------------------------------------------------------------------------- # /* EV: R-33626-48418 */ # # Check that if any of the child key columns in the above schema are NULL, # there is no requirement for a corresponding parent key. # do_test e_fkey-37.1 { execsql { INSERT INTO song VALUES(2, 'Elvis Presley', NULL, 'Fever'); INSERT INTO song VALUES(3, NULL, 'Elvis Is Back', 'Soldier Boy'); } } {} ########################################################################### ### SECTION 4.2: Deferred Foreign Key Constraints ########################################################################### #------------------------------------------------------------------------- # Note: R-35290-16460 is tested below. # # TODO: R-30323-21917 #------------------------------------------------------------------------- # /* EV: R-09323-30470 */ # # Test that if a statement violates an immediate FK constraint, and the # database does not satisfy the FK constraint once all effects of the # statement have been applied, an error is reported and the effects of # the statement rolled back. # drop_all_tables do_test e_fkey-33.1 { execsql { CREATE TABLE king(a, b, PRIMARY KEY(a)); CREATE TABLE prince(c REFERENCES king, d); } } {} do_test e_fkey-33.2 { # Execute a statement that violates the immediate FK constraint. catchsql { INSERT INTO prince VALUES(1, 2) } } {1 {foreign key constraint failed}} do_test e_fkey-33.3 { # This time, use a trigger to fix the constraint violation before the # statement has finished executing. Then execute the same statement as # in the previous test case. This time, no error. execsql { CREATE TRIGGER kt AFTER INSERT ON prince WHEN NOT EXISTS (SELECT a FROM king WHERE a = new.c) BEGIN INSERT INTO king VALUES(new.c, NULL); END } execsql { INSERT INTO prince VALUES(1, 2) } } {} # Test that operating inside a transaction makes no difference to # immediate constraint violation handling. do_test e_fkey-33.4 { execsql { BEGIN; INSERT INTO prince VALUES(2, 3); DROP TRIGGER kt; } catchsql { INSERT INTO prince VALUES(3, 4) } } {1 {foreign key constraint failed}} do_test e_fkey-33.5 { execsql { COMMIT; SELECT * FROM king; } } {1 {} 2 {}} #------------------------------------------------------------------------- # /* EV: R-49178-21358 */ # /* EV: R-39692-12488 */ # /* EV: R-55147-47664 */ # /* EV: R-29604-30395 */ # # Test that if a deferred constraint is violated within a transaction, # nothing happens immediately and the database is allowed to persist # in a state that does not satisfy the FK constraint. However attempts # to COMMIT the transaction fail until the FK constraint is satisfied. # proc test_efkey_34 {tn isError sql} { do_test e_fkey-34.$tn " catchsql {$sql} " [lindex {{0 {}} {1 {foreign key constraint failed}}} $isError] } drop_all_tables test_efkey_34 1 0 { CREATE TABLE ll(k PRIMARY KEY); CREATE TABLE kk(c REFERENCES ll DEFERRABLE INITIALLY DEFERRED); } test_efkey_34 2 0 "BEGIN" test_efkey_34 3 0 "INSERT INTO kk VALUES(5)" test_efkey_34 4 0 "INSERT INTO kk VALUES(10)" test_efkey_34 5 1 "COMMIT" test_efkey_34 6 0 "INSERT INTO ll VALUES(10)" test_efkey_34 7 1 "COMMIT" test_efkey_34 8 0 "INSERT INTO ll VALUES(5)" test_efkey_34 9 0 "COMMIT" #------------------------------------------------------------------------- # /* EV: R-56844-61705 */ # # When not running inside a transaction, a deferred constraint is similar # to an immediate constraint (violations are reported immediately). # drop_all_tables proc test_efkey_35 {tn isError sql} { do_test e_fkey-35.$tn " catchsql {$sql} " [lindex {{0 {}} {1 {foreign key constraint failed}}} $isError] } do_test e_fkey-35.1 { execsql { CREATE TABLE parent(x, y); CREATE UNIQUE INDEX pi ON parent(x, y); CREATE TABLE child(a, b, FOREIGN KEY(a, b) REFERENCES parent(x, y) DEFERRABLE INITIALLY DEFERRED ); } } {} test_efkey_35 2 1 "INSERT INTO child VALUES('x', 'y')" test_efkey_35 3 0 "INSERT INTO parent VALUES('x', 'y')" test_efkey_35 4 0 "INSERT INTO child VALUES('x', 'y')" #------------------------------------------------------------------------- # /* EV: R-12782-61841 */ # # Test that an FK constraint is made deferred by adding the following # to the definition: # # DEFERRABLE INITIALLY DEFERRED # # /* EV: R-09005-28791 */ # # Also test that adding any of the following to a foreign key definition # makes the constraint IMMEDIATE: # # NOT DEFERRABLE INITIALLY DEFERRED # NOT DEFERRABLE INITIALLY IMMEDIATE # NOT DEFERRABLE # DEFERRABLE INITIALLY IMMEDIATE # DEFERRABLE # # /* EV: R-35290-16460 */ # # Foreign keys are IMMEDIATE by default (if there is no DEFERRABLE or NOT # DEFERRABLE clause). # # /* EV: R-30323-21917 */ FKs are either IMMEDIATE or DEFERRED. # drop_all_tables do_test e_fkey-29.1 { execsql { CREATE TABLE parent(x, y, z, PRIMARY KEY(x,y,z)); CREATE TABLE c1(a, b, c, FOREIGN KEY(a, b, c) REFERENCES parent NOT DEFERRABLE INITIALLY DEFERRED ); CREATE TABLE c2(a, b, c, FOREIGN KEY(a, b, c) REFERENCES parent NOT DEFERRABLE INITIALLY IMMEDIATE ); CREATE TABLE c3(a, b, c, FOREIGN KEY(a, b, c) REFERENCES parent NOT DEFERRABLE ); CREATE TABLE c4(a, b, c, FOREIGN KEY(a, b, c) REFERENCES parent DEFERRABLE INITIALLY IMMEDIATE ); CREATE TABLE c5(a, b, c, FOREIGN KEY(a, b, c) REFERENCES parent DEFERRABLE ); CREATE TABLE c6(a, b, c, FOREIGN KEY(a, b, c) REFERENCES parent); -- This FK constraint is the only deferrable one. CREATE TABLE c7(a, b, c, FOREIGN KEY(a, b, c) REFERENCES parent DEFERRABLE INITIALLY DEFERRED ); INSERT INTO parent VALUES('a', 'b', 'c'); INSERT INTO parent VALUES('d', 'e', 'f'); INSERT INTO parent VALUES('g', 'h', 'i'); INSERT INTO parent VALUES('j', 'k', 'l'); INSERT INTO parent VALUES('m', 'n', 'o'); INSERT INTO parent VALUES('p', 'q', 'r'); INSERT INTO parent VALUES('s', 't', 'u'); INSERT INTO c1 VALUES('a', 'b', 'c'); INSERT INTO c2 VALUES('d', 'e', 'f'); INSERT INTO c3 VALUES('g', 'h', 'i'); INSERT INTO c4 VALUES('j', 'k', 'l'); INSERT INTO c5 VALUES('m', 'n', 'o'); INSERT INTO c6 VALUES('p', 'q', 'r'); INSERT INTO c7 VALUES('s', 't', 'u'); } } {} proc test_efkey_29 {tn sql isError} { do_test e_fkey-29.$tn "catchsql {$sql}" [ lindex {{0 {}} {1 {foreign key constraint failed}}} $isError ] } test_efkey_29 2 "BEGIN" 0 test_efkey_29 3 "DELETE FROM parent WHERE x = 'a'" 1 test_efkey_29 4 "DELETE FROM parent WHERE x = 'd'" 1 test_efkey_29 5 "DELETE FROM parent WHERE x = 'g'" 1 test_efkey_29 6 "DELETE FROM parent WHERE x = 'j'" 1 test_efkey_29 7 "DELETE FROM parent WHERE x = 'm'" 1 test_efkey_29 8 "DELETE FROM parent WHERE x = 'p'" 1 test_efkey_29 9 "DELETE FROM parent WHERE x = 's'" 0 test_efkey_29 10 "COMMIT" 1 test_efkey_29 11 "ROLLBACK" 0 test_efkey_29 9 "BEGIN" 0 test_efkey_29 10 "UPDATE parent SET z = 'z' WHERE z = 'c'" 1 test_efkey_29 11 "UPDATE parent SET z = 'z' WHERE z = 'f'" 1 test_efkey_29 12 "UPDATE parent SET z = 'z' WHERE z = 'i'" 1 test_efkey_29 13 "UPDATE parent SET z = 'z' WHERE z = 'l'" 1 test_efkey_29 14 "UPDATE parent SET z = 'z' WHERE z = 'o'" 1 test_efkey_29 15 "UPDATE parent SET z = 'z' WHERE z = 'r'" 1 test_efkey_29 16 "UPDATE parent SET z = 'z' WHERE z = 'u'" 0 test_efkey_29 17 "COMMIT" 1 test_efkey_29 18 "ROLLBACK" 0 test_efkey_29 17 "BEGIN" 0 test_efkey_29 18 "INSERT INTO c1 VALUES(1, 2, 3)" 1 test_efkey_29 19 "INSERT INTO c2 VALUES(1, 2, 3)" 1 test_efkey_29 20 "INSERT INTO c3 VALUES(1, 2, 3)" 1 test_efkey_29 21 "INSERT INTO c4 VALUES(1, 2, 3)" 1 test_efkey_29 22 "INSERT INTO c5 VALUES(1, 2, 3)" 1 test_efkey_29 22 "INSERT INTO c6 VALUES(1, 2, 3)" 1 test_efkey_29 22 "INSERT INTO c7 VALUES(1, 2, 3)" 0 test_efkey_29 23 "COMMIT" 1 test_efkey_29 24 "INSERT INTO parent VALUES(1, 2, 3)" 0 test_efkey_29 25 "COMMIT" 0 test_efkey_29 26 "BEGIN" 0 test_efkey_29 27 "UPDATE c1 SET a = 10" 1 test_efkey_29 28 "UPDATE c2 SET a = 10" 1 test_efkey_29 29 "UPDATE c3 SET a = 10" 1 test_efkey_29 30 "UPDATE c4 SET a = 10" 1 test_efkey_29 31 "UPDATE c5 SET a = 10" 1 test_efkey_29 31 "UPDATE c6 SET a = 10" 1 test_efkey_29 31 "UPDATE c7 SET a = 10" 0 test_efkey_29 32 "COMMIT" 1 test_efkey_29 33 "ROLLBACK" 0 #------------------------------------------------------------------------- # /* EV: R-35043-01546 */ # # Test an example from foreignkeys.html dealing with a deferred foreign # key constraint. # do_test e_fkey-28.1 { drop_all_tables execsql { CREATE TABLE artist( artistid INTEGER PRIMARY KEY, artistname TEXT ); CREATE TABLE track( trackid INTEGER, trackname TEXT, trackartist INTEGER REFERENCES artist(artistid) DEFERRABLE INITIALLY DEFERRED ); } } {} do_test e_fkey-28.2 { execsql { BEGIN; INSERT INTO track VALUES(1, 'White Christmas', 5); } catchsql COMMIT } {1 {foreign key constraint failed}} do_test e_fkey-28.3 { execsql { INSERT INTO artist VALUES(5, 'Bing Crosby'); COMMIT; } } {} #------------------------------------------------------------------------- # /* EV: R-07223-48323 */ # # Verify that a nested savepoint may be released without satisfying # deferred foreign key constraints. # drop_all_tables do_test e_fkey-30.1 { execsql { CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1 DEFERRABLE INITIALLY DEFERRED ); INSERT INTO t1 VALUES(1, 1); INSERT INTO t1 VALUES(2, 2); INSERT INTO t1 VALUES(3, 3); } } {} do_test e_fkey-30.2 { execsql { BEGIN; SAVEPOINT one; INSERT INTO t1 VALUES(4, 5); RELEASE one; } } {} do_test e_fkey-30.3 { catchsql COMMIT } {1 {foreign key constraint failed}} do_test e_fkey-30.4 { execsql { UPDATE t1 SET a = 5 WHERE a = 4; COMMIT; } } {} #------------------------------------------------------------------------- # /* EV: R-44295-13823 */ # # Check that a transaction savepoint (an outermost savepoint opened when # the database was in auto-commit mode) cannot be released without # satisfying deferred foreign key constraints. It may be rolled back. # do_test e_fkey-31.1 { execsql { SAVEPOINT one; SAVEPOINT two; INSERT INTO t1 VALUES(6, 7); RELEASE two; } } {} do_test e_fkey-31.2 { catchsql {RELEASE one} } {1 {foreign key constraint failed}} do_test e_fkey-31.3 { execsql { UPDATE t1 SET a = 7 WHERE a = 6; RELEASE one; } } {} do_test e_fkey-31.4 { execsql { SAVEPOINT one; SAVEPOINT two; INSERT INTO t1 VALUES(9, 10); RELEASE two; } } {} do_test e_fkey-31.5 { catchsql {RELEASE one} } {1 {foreign key constraint failed}} do_test e_fkey-31.6 { execsql {ROLLBACK TO one ; RELEASE one} } {} #------------------------------------------------------------------------- # /* EV: R-37736-42616 */ # # Test that if a COMMIT operation fails due to deferred foreign key # constraints, any nested savepoints remain open. # do_test e_fkey-32.1 { execsql { DELETE FROM t1 WHERE a>3; SELECT * FROM t1; } } {1 1 2 2 3 3} do_test e_fkey-32.2 { execsql { BEGIN; INSERT INTO t1 VALUES(4, 4); SAVEPOINT one; INSERT INTO t1 VALUES(5, 6); SELECT * FROM t1; } } {1 1 2 2 3 3 4 4 5 6} do_test e_fkey-32.3 { catchsql COMMIT } {1 {foreign key constraint failed}} do_test e_fkey-32.4 { execsql { ROLLBACK TO one; COMMIT; SELECT * FROM t1; } } {1 1 2 2 3 3 4 4} do_test e_fkey-32.5 { execsql { SAVEPOINT a; INSERT INTO t1 VALUES(5, 5); SAVEPOINT b; INSERT INTO t1 VALUES(6, 7); SAVEPOINT c; INSERT INTO t1 VALUES(7, 8); } } {} do_test e_fkey-32.6 { catchsql {RELEASE a} } {1 {foreign key constraint failed}} do_test e_fkey-32.7 { execsql {ROLLBACK TO c} catchsql {RELEASE a} } {1 {foreign key constraint failed}} do_test e_fkey-32.8 { execsql { ROLLBACK TO b; RELEASE a; SELECT * FROM t1; } } {1 1 2 2 3 3 4 4 5 5} ########################################################################### ### SECTION 4.3: ON DELETE and ON UPDATE Actions ########################################################################### #------------------------------------------------------------------------- # /* EV: R-48270-44282 */ # # Test that configured ON DELETE and ON UPDATE actions take place when # deleting or modifying rows of the parent table, respectively. # # /* EV: R-48124-63225 */ # # Test that a single FK constraint may have different actions configured # for ON DELETE and ON UPDATE. # do_test e_fkey-16.1 { execsql { CREATE TABLE p(a, b PRIMARY KEY, c); CREATE TABLE c1(d, e, f DEFAULT 'k0' REFERENCES p ON UPDATE SET DEFAULT ON DELETE SET NULL ); INSERT INTO p VALUES(0, 'k0', ''); INSERT INTO p VALUES(1, 'k1', 'I'); INSERT INTO p VALUES(2, 'k2', 'II'); INSERT INTO p VALUES(3, 'k3', 'III'); INSERT INTO c1 VALUES(1, 'xx', 'k1'); INSERT INTO c1 VALUES(2, 'xx', 'k2'); INSERT INTO c1 VALUES(3, 'xx', 'k3'); } } {} do_test e_fkey-16.2 { execsql { UPDATE p SET b = 'k4' WHERE a = 1; SELECT * FROM c1; } } {1 xx k0 2 xx k2 3 xx k3} do_test e_fkey-16.3 { execsql { DELETE FROM p WHERE a = 2; SELECT * FROM c1; } } {1 xx k0 2 xx {} 3 xx k3} do_test e_fkey-16.4 { execsql { CREATE UNIQUE INDEX pi ON p(c); REPLACE INTO p VALUES(5, 'k5', 'III'); SELECT * FROM c1; } } {1 xx k0 2 xx {} 3 xx {}} #------------------------------------------------------------------------- # /* EV: R-33326-45252 */ # # Each foreign key in the system has an ON UPDATE and ON DELETE action, # either "NO ACTION", "RESTRICT", "SET NULL", "SET DEFAULT" or "CASCADE". # # /* EV: R-19803-45884 */ # # If none is specified explicitly, "NO ACTION" is the default. # drop_all_tables do_test e_fkey-17.1 { execsql { CREATE TABLE parent(x PRIMARY KEY, y); CREATE TABLE child1(a, b REFERENCES parent ON UPDATE NO ACTION ON DELETE RESTRICT ); CREATE TABLE child2(a, b REFERENCES parent ON UPDATE RESTRICT ON DELETE SET NULL ); CREATE TABLE child3(a, b REFERENCES parent ON UPDATE SET NULL ON DELETE SET DEFAULT ); CREATE TABLE child4(a, b REFERENCES parent ON UPDATE SET DEFAULT ON DELETE CASCADE ); -- Create some foreign keys that use the default action - "NO ACTION" CREATE TABLE child5(a, b REFERENCES parent ON UPDATE CASCADE); CREATE TABLE child6(a, b REFERENCES parent ON DELETE RESTRICT); CREATE TABLE child7(a, b REFERENCES parent ON DELETE NO ACTION); CREATE TABLE child8(a, b REFERENCES parent ON UPDATE NO ACTION); } } {} foreach {tn zTab lRes} { 2 child1 {0 0 parent b {} {NO ACTION} RESTRICT NONE} 3 child2 {0 0 parent b {} RESTRICT {SET NULL} NONE} 4 child3 {0 0 parent b {} {SET NULL} {SET DEFAULT} NONE} 5 child4 {0 0 parent b {} {SET DEFAULT} CASCADE NONE} 6 child5 {0 0 parent b {} CASCADE {NO ACTION} NONE} 7 child6 {0 0 parent b {} {NO ACTION} RESTRICT NONE} 8 child7 {0 0 parent b {} {NO ACTION} {NO ACTION} NONE} 9 child8 {0 0 parent b {} {NO ACTION} {NO ACTION} NONE} } { do_test e_fkey-17.$tn { execsql "PRAGMA foreign_key_list($zTab)" } $lRes } #------------------------------------------------------------------------- # /* EV: R-19971-54976 */ # # Test that "NO ACTION" means that nothing happens to a child row when # it's parent row is updated or deleted. # drop_all_tables do_test e_fkey-18.1 { execsql { CREATE TABLE parent(p1, p2, PRIMARY KEY(p1, p2)); CREATE TABLE child(c1, c2, FOREIGN KEY(c1, c2) REFERENCES parent ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED ); INSERT INTO parent VALUES('j', 'k'); INSERT INTO parent VALUES('l', 'm'); INSERT INTO child VALUES('j', 'k'); INSERT INTO child VALUES('l', 'm'); } } {} do_test e_fkey-18.2 { execsql { BEGIN; UPDATE parent SET p1='k' WHERE p1='j'; DELETE FROM parent WHERE p1='l'; SELECT * FROM child; } } {j k l m} do_test e_fkey-18.3 { catchsql COMMIT } {1 {foreign key constraint failed}} do_test e_fkey-18.4 { execsql ROLLBACK } {} #------------------------------------------------------------------------- # /* EV: R-04272-38653 */ # # Test that "RESTRICT" means the application is prohibited from deleting # or updating a parent table row when there exists one or more child keys # mapped to it. # drop_all_tables do_test e_fkey-18.1 { execsql { CREATE TABLE parent(p1, p2); CREATE UNIQUE INDEX parent_i ON parent(p1, p2); CREATE TABLE child1(c1, c2, FOREIGN KEY(c2, c1) REFERENCES parent(p1, p2) ON DELETE RESTRICT ); CREATE TABLE child2(c1, c2, FOREIGN KEY(c2, c1) REFERENCES parent(p1, p2) ON UPDATE RESTRICT ); } } {} do_test e_fkey-18.2 { execsql { INSERT INTO parent VALUES('a', 'b'); INSERT INTO parent VALUES('c', 'd'); INSERT INTO child1 VALUES('b', 'a'); INSERT INTO child2 VALUES('d', 'c'); } } {} do_test e_fkey-18.3 { catchsql { DELETE FROM parent WHERE p1 = 'a' } } {1 {foreign key constraint failed}} do_test e_fkey-18.4 { catchsql { UPDATE parent SET p2 = 'e' WHERE p1 = 'c' } } {1 {foreign key constraint failed}} #------------------------------------------------------------------------- # /* EV: R-37997-42187 */ # # Test that RESTRICT is slightly different from NO ACTION for IMMEDIATE # constraints, in that it is enforced immediately, not at the end of the # statement. # drop_all_tables do_test e_fkey-19.1 { execsql { CREATE TABLE parent(x PRIMARY KEY); CREATE TABLE child1(c REFERENCES parent ON UPDATE RESTRICT); CREATE TABLE child2(c REFERENCES parent ON UPDATE NO ACTION); INSERT INTO parent VALUES('key1'); INSERT INTO parent VALUES('key2'); INSERT INTO child1 VALUES('key1'); INSERT INTO child2 VALUES('key2'); CREATE TRIGGER parent_t AFTER UPDATE ON parent BEGIN UPDATE child1 set c = new.x WHERE c = old.x; UPDATE child2 set c = new.x WHERE c = old.x; END; } } {} do_test e_fkey-19.2 { catchsql { UPDATE parent SET x = 'key one' WHERE x = 'key1' } } {1 {foreign key constraint failed}} do_test e_fkey-19.3 { execsql { UPDATE parent SET x = 'key two' WHERE x = 'key2'; SELECT * FROM child2; } } {{key two}} drop_all_tables do_test e_fkey-19.4 { execsql { CREATE TABLE parent(x PRIMARY KEY); CREATE TABLE child1(c REFERENCES parent ON DELETE RESTRICT); CREATE TABLE child2(c REFERENCES parent ON DELETE NO ACTION); INSERT INTO parent VALUES('key1'); INSERT INTO parent VALUES('key2'); INSERT INTO child1 VALUES('key1'); INSERT INTO child2 VALUES('key2'); CREATE TRIGGER parent_t AFTER DELETE ON parent BEGIN UPDATE child1 SET c = NULL WHERE c = old.x; UPDATE child2 SET c = NULL WHERE c = old.x; END; } } {} do_test e_fkey-19.5 { catchsql { DELETE FROM parent WHERE x = 'key1' } } {1 {foreign key constraint failed}} do_test e_fkey-19.6 { execsql { DELETE FROM parent WHERE x = 'key2'; SELECT * FROM child2; } } {{}} drop_all_tables do_test e_fkey-19.7 { execsql { CREATE TABLE parent(x PRIMARY KEY); CREATE TABLE child1(c REFERENCES parent ON DELETE RESTRICT); CREATE TABLE child2(c REFERENCES parent ON DELETE NO ACTION); INSERT INTO parent VALUES('key1'); INSERT INTO parent VALUES('key2'); INSERT INTO child1 VALUES('key1'); INSERT INTO child2 VALUES('key2'); } } {} do_test e_fkey-19.8 { catchsql { REPLACE INTO parent VALUES('key1') } } {1 {foreign key constraint failed}} do_test e_fkey-19.9 { execsql { REPLACE INTO parent VALUES('key2'); SELECT * FROM child2; } } {key2} #------------------------------------------------------------------------- # /* EV: R-24179-60523 */ # # Test that RESTRICT is enforced immediately, even for a DEFERRED constraint. # drop_all_tables do_test e_fkey-20.1 { execsql { CREATE TABLE parent(x PRIMARY KEY); CREATE TABLE child1(c REFERENCES parent ON UPDATE RESTRICT DEFERRABLE INITIALLY DEFERRED ); CREATE TABLE child2(c REFERENCES parent ON UPDATE NO ACTION DEFERRABLE INITIALLY DEFERRED ); INSERT INTO parent VALUES('key1'); INSERT INTO parent VALUES('key2'); INSERT INTO child1 VALUES('key1'); INSERT INTO child2 VALUES('key2'); BEGIN; } } {} do_test e_fkey-20.2 { catchsql { UPDATE parent SET x = 'key one' WHERE x = 'key1' } } {1 {foreign key constraint failed}} do_test e_fkey-20.3 { execsql { UPDATE parent SET x = 'key two' WHERE x = 'key2' } } {} do_test e_fkey-20.4 { catchsql COMMIT } {1 {foreign key constraint failed}} do_test e_fkey-20.5 { execsql { UPDATE child2 SET c = 'key two'; COMMIT; } } {} drop_all_tables do_test e_fkey-20.6 { execsql { CREATE TABLE parent(x PRIMARY KEY); CREATE TABLE child1(c REFERENCES parent ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED ); CREATE TABLE child2(c REFERENCES parent ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED ); INSERT INTO parent VALUES('key1'); INSERT INTO parent VALUES('key2'); INSERT INTO child1 VALUES('key1'); INSERT INTO child2 VALUES('key2'); BEGIN; } } {} do_test e_fkey-20.7 { catchsql { DELETE FROM parent WHERE x = 'key1' } } {1 {foreign key constraint failed}} do_test e_fkey-20.8 { execsql { DELETE FROM parent WHERE x = 'key2' } } {} do_test e_fkey-20.9 { catchsql COMMIT } {1 {foreign key constraint failed}} do_test e_fkey-20.10 { execsql { UPDATE child2 SET c = NULL; COMMIT; } } {} #------------------------------------------------------------------------- # /* EV: R-03353-05327 */ # # Test SET NULL actions. # drop_all_tables do_test e_fkey-21.1 { execsql { CREATE TABLE pA(x PRIMARY KEY); CREATE TABLE cA(c REFERENCES pA ON DELETE SET NULL); CREATE TABLE cB(c REFERENCES pA ON UPDATE SET NULL); INSERT INTO pA VALUES(X'ABCD'); INSERT INTO pA VALUES(X'1234'); INSERT INTO cA VALUES(X'ABCD'); INSERT INTO cB VALUES(X'1234'); } } {} do_test e_fkey-21.2 { execsql { DELETE FROM pA WHERE rowid = 1; SELECT quote(x) FROM pA; } } {X'1234'} do_test e_fkey-21.3 { execsql { SELECT quote(c) FROM cA; } } {NULL} do_test e_fkey-21.4 { execsql { UPDATE pA SET x = X'8765' WHERE rowid = 2; SELECT quote(x) FROM pA; } } {X'8765'} do_test e_fkey-21.5 { execsql { SELECT quote(c) FROM cB } } {NULL} #------------------------------------------------------------------------- # /* EV: R-43054-54832 */ # # Test SET DEFAULT actions. # drop_all_tables do_test e_fkey-22.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); INSERT INTO pA(rowid, x) VALUES(1, X'0000'); INSERT INTO pA(rowid, x) VALUES(2, X'9999'); INSERT INTO pA(rowid, x) VALUES(3, X'ABCD'); INSERT INTO pA(rowid, x) VALUES(4, X'1234'); INSERT INTO cA VALUES(X'ABCD'); INSERT INTO cB VALUES(X'1234'); } } {} do_test e_fkey-22.2 { execsql { DELETE FROM pA WHERE rowid = 3; SELECT quote(x) FROM pA; } } {X'0000' X'9999' X'1234'} do_test e_fkey-22.3 { execsql { SELECT quote(c) FROM cA } } {X'0000'} do_test e_fkey-22.4 { execsql { UPDATE pA SET x = X'8765' WHERE rowid = 4; SELECT quote(x) FROM pA; } } {X'0000' X'9999' X'8765'} do_test e_fkey-22.5 { execsql { SELECT quote(c) FROM cB } } {X'9999'} #------------------------------------------------------------------------- # /* EV: R-61376-57267 */ # /* EV: R-61809-62207 */ # # Test ON DELETE CASCADE actions. # drop_all_tables do_test e_fkey-23.1 { execsql { CREATE TABLE p1(a, b UNIQUE); CREATE TABLE c1(c REFERENCES p1(b) ON DELETE CASCADE, d); INSERT INTO p1 VALUES(NULL, NULL); INSERT INTO p1 VALUES(4, 4); INSERT INTO p1 VALUES(5, 5); INSERT INTO c1 VALUES(NULL, NULL); INSERT INTO c1 VALUES(4, 4); INSERT INTO c1 VALUES(5, 5); SELECT count(*) FROM c1; } } {3} do_test e_fkey-23.2 { execsql { DELETE FROM p1 WHERE a = 4; SELECT d, c FROM c1; } } {{} {} 5 5} do_test e_fkey-23.3 { execsql { DELETE FROM p1; SELECT d, c FROM c1; } } {{} {}} do_test e_fkey-23.4 { execsql { SELECT * FROM p1 } } {} #------------------------------------------------------------------------- # /* EV: R-61376-57267 */ # /* EV: R-13877-64542 */ # # Test ON UPDATE CASCADE actions. # drop_all_tables do_test e_fkey-24.1 { execsql { CREATE TABLE p1(a, b UNIQUE); CREATE TABLE c1(c REFERENCES p1(b) ON UPDATE CASCADE, d); INSERT INTO p1 VALUES(NULL, NULL); INSERT INTO p1 VALUES(4, 4); INSERT INTO p1 VALUES(5, 5); INSERT INTO c1 VALUES(NULL, NULL); INSERT INTO c1 VALUES(4, 4); INSERT INTO c1 VALUES(5, 5); SELECT count(*) FROM c1; } } {3} do_test e_fkey-24.2 { execsql { UPDATE p1 SET b = 10 WHERE b = 5; SELECT d, c FROM c1; } } {{} {} 4 4 5 10} do_test e_fkey-24.3 { execsql { UPDATE p1 SET b = 11 WHERE b = 4; SELECT d, c FROM c1; } } {{} {} 4 11 5 10} do_test e_fkey-24.4 { execsql { UPDATE p1 SET b = 6 WHERE b IS NULL; SELECT d, c FROM c1; } } {{} {} 4 11 5 10} do_test e_fkey-23.5 { execsql { SELECT * FROM p1 } } {{} 6 4 11 5 10} #------------------------------------------------------------------------- # /* EV: R-51329-33438 */ # # Test an example from the "ON DELETE and ON UPDATE Actions" section # of foreignkeys.html. # drop_all_tables do_test e_fkey-15.1 { execsql { CREATE TABLE artist( artistid INTEGER PRIMARY KEY, artistname TEXT ); CREATE TABLE track( trackid INTEGER, trackname TEXT, trackartist INTEGER REFERENCES artist(artistid) ON UPDATE CASCADE ); INSERT INTO artist VALUES(1, 'Dean Martin'); INSERT INTO artist VALUES(2, 'Frank Sinatra'); INSERT INTO track VALUES(11, 'That''s Amore', 1); INSERT INTO track VALUES(12, 'Christmas Blues', 1); INSERT INTO track VALUES(13, 'My Way', 2); } } {} do_test e_fkey-15.2 { execsql { UPDATE artist SET artistid = 100 WHERE artistname = 'Dean Martin'; } } {} do_test e_fkey-15.3 { execsql { SELECT * FROM artist } } {2 {Frank Sinatra} 100 {Dean Martin}} do_test e_fkey-15.4 { execsql { SELECT * FROM track } } {11 {That's Amore} 100 12 {Christmas Blues} 100 13 {My Way} 2} #------------------------------------------------------------------------- # /* EV: R-53968-51642 */ # # Verify that adding an FK action does not absolve the user of the # requirement not to violate the foreign key constraint. # drop_all_tables do_test e_fkey-25.1 { execsql { CREATE TABLE parent(a COLLATE nocase, b, c, PRIMARY KEY(c, a)); CREATE TABLE child(d DEFAULT 'a', e, f DEFAULT 'c', FOREIGN KEY(f, d) REFERENCES parent ON UPDATE SET DEFAULT ); INSERT INTO parent VALUES('A', 'b', 'c'); INSERT INTO parent VALUES('ONE', 'two', 'three'); INSERT INTO child VALUES('one', 'two', 'three'); } } {} do_test e_fkey-25.2 { execsql { BEGIN; UPDATE parent SET a = '' WHERE a = 'oNe'; SELECT * FROM child; } } {a two c} do_test e_fkey-25.3 { execsql { ROLLBACK; DELETE FROM parent WHERE a = 'A'; SELECT * FROM parent; } } {ONE two three} do_test e_fkey-25.4 { catchsql { UPDATE parent SET a = '' WHERE a = 'oNe' } } {1 {foreign key constraint failed}} #------------------------------------------------------------------------- # /* EV: R-07065-59588 */ # /* EV: R-28220-46694 */ # # Test an example from the "ON DELETE and ON UPDATE Actions" section # of foreignkeys.html. This example shows that adding an "ON DELETE DEFAULT" # clause does not abrogate the need to satisfy the foreign key constraint # (R-28220-46694). # drop_all_tables do_test e_fkey-14.1 { execsql { CREATE TABLE artist( artistid INTEGER PRIMARY KEY, artistname TEXT ); CREATE TABLE track( trackid INTEGER, trackname TEXT, trackartist INTEGER DEFAULT 0 REFERENCES artist(artistid) ON DELETE SET DEFAULT ); INSERT INTO artist VALUES(3, 'Sammy Davis Jr.'); INSERT INTO track VALUES(14, 'Mr. Bojangles', 3); } } {} do_test e_fkey-14.2 { catchsql { DELETE FROM artist WHERE artistname = 'Sammy Davis Jr.' } } {1 {foreign key constraint failed}} do_test e_fkey-14.3 { execsql { INSERT INTO artist VALUES(0, 'Unknown Artist'); DELETE FROM artist WHERE artistname = 'Sammy Davis Jr.'; } } {} do_test e_fkey-14.4 { execsql { SELECT * FROM artist } } {0 {Unknown Artist}} do_test e_fkey-14.5 { execsql { SELECT * FROM track } } {14 {Mr. Bojangles} 0} #------------------------------------------------------------------------- # /* EV: R-09564-22170 */ # # Check that the order of steps in an UPDATE or DELETE on a parent # table is as follows: # # 1. Execute applicable BEFORE trigger programs, # 2. Check local (non foreign key) constraints, # 3. Update or delete the row in the parent table, # 4. Perform any required foreign key actions, # 5. Execute applicable AFTER trigger programs. # drop_all_tables do_test e_fkey-27.1 { proc maxparent {args} { db one {SELECT max(x) FROM parent} } db func maxparent maxparent execsql { CREATE TABLE parent(x PRIMARY KEY); CREATE TRIGGER bu BEFORE UPDATE ON parent BEGIN INSERT INTO parent VALUES(new.x-old.x); END; CREATE TABLE child( a DEFAULT (maxparent()) REFERENCES parent ON UPDATE SET DEFAULT ); CREATE TRIGGER au AFTER UPDATE ON parent BEGIN INSERT INTO parent VALUES(new.x+old.x); END; INSERT INTO parent VALUES(1); INSERT INTO child VALUES(1); } } {} do_test e_fkey-27.2 { execsql { UPDATE parent SET x = 22; SELECT * FROM parent UNION ALL SELECT 'xxx' UNION ALL SELECT a FROM child; } } {22 21 23 xxx 22} do_test e_fkey-27.3 { execsql { DELETE FROM child; DELETE FROM parent; INSERT INTO parent VALUES(-1); INSERT INTO child VALUES(-1); UPDATE parent SET x = 22; SELECT * FROM parent UNION ALL SELECT 'xxx' UNION ALL SELECT a FROM child; } } {22 23 21 xxx 23} #------------------------------------------------------------------------- # /* EV: R-27383-10246 */ # # Verify that ON UPDATE actions only actually take place if the parent key # is set to a new value that is distinct from the old value. The default # collation sequence and affinity are used to determine if the new value # is 'distinct' from the old or not. # drop_all_tables do_test e_fkey-26.1 { execsql { CREATE TABLE zeus(a INTEGER COLLATE NOCASE, b, PRIMARY KEY(a, b)); CREATE TABLE apollo(c, d, FOREIGN KEY(c, d) REFERENCES zeus ON UPDATE CASCADE ); INSERT INTO zeus VALUES('abc', 'xyz'); INSERT INTO apollo VALUES('ABC', 'xyz'); } execsql { UPDATE zeus SET a = 'aBc'; SELECT * FROM apollo; } } {ABC xyz} do_test e_fkey-26.2 { execsql { UPDATE zeus SET a = 1, b = 1; SELECT * FROM apollo; } } {1 1} do_test e_fkey-26.3 { execsql { UPDATE zeus SET a = 1, b = 1; SELECT typeof(c), c, typeof(d), d FROM apollo; } } {integer 1 integer 1} do_test e_fkey-26.4 { execsql { UPDATE zeus SET a = '1'; SELECT typeof(c), c, typeof(d), d FROM apollo; } } {integer 1 integer 1} do_test e_fkey-26.5 { execsql { UPDATE zeus SET b = '1'; SELECT typeof(c), c, typeof(d), d FROM apollo; } } {integer 1 text 1} do_test e_fkey-26.6 { execsql { UPDATE zeus SET b = NULL; SELECT typeof(c), c, typeof(d), d FROM apollo; } } {integer 1 null {}} #------------------------------------------------------------------------- # /* EV: R-58589-50781 */ # # Test an example from the "ON DELETE and ON UPDATE Actions" section # of foreignkeys.html. This example demonstrates that ON UPDATE actions # only take place if at least one parent key column is set to a value # that is distinct from its previous value. # drop_all_tables do_test e_fkey-13.1 { execsql { CREATE TABLE parent(x PRIMARY KEY); CREATE TABLE child(y REFERENCES parent ON UPDATE SET NULL); INSERT INTO parent VALUES('key'); INSERT INTO child VALUES('key'); } } {} do_test e_fkey-13.2 { execsql { UPDATE parent SET x = 'key'; SELECT IFNULL(y, 'null') FROM child; } } {key} do_test e_fkey-13.3 { execsql { UPDATE parent SET x = 'key2'; SELECT IFNULL(y, 'null') FROM child; } } {null} ########################################################################### ### SECTION 5: CREATE, ALTER and DROP TABLE commands ########################################################################### #------------------------------------------------------------------------- # /* EV: R-36018-21755 */ # /* EV: R-25384-39337 */ # # Test that parent keys are not checked when tables are created. # # Child keys are checked to ensure all component columns exist. If parent # key columns are explicitly specified, SQLite checks to make sure there # are the same number of columns in the child and parent keys. (TODO: This # is tested but does not correspond to any testable statement.) # # /* EV: R-08908-23439 */ # # Also test that the above statements are true regardless of whether or not # foreign keys are enabled: "A CREATE TABLE command operates the same whether # or not foreign key constraints are enabled." # foreach {tn zCreateTbl lRes} { 1 "CREATE TABLE t1(a, b REFERENCES t1)" {0 {}} 2 "CREATE TABLE t1(a, b REFERENCES t2)" {0 {}} 3 "CREATE TABLE t1(a, b, FOREIGN KEY(a,b) REFERENCES t1)" {0 {}} 4 "CREATE TABLE t1(a, b, FOREIGN KEY(a,b) REFERENCES t2)" {0 {}} 5 "CREATE TABLE t1(a, b, FOREIGN KEY(a,b) REFERENCES t2)" {0 {}} 6 "CREATE TABLE t1(a, b, FOREIGN KEY(a,b) REFERENCES t2(n,d))" {0 {}} 7 "CREATE TABLE t1(a, b, FOREIGN KEY(a,b) REFERENCES t1(a,b))" {0 {}} A "CREATE TABLE t1(a, b, FOREIGN KEY(c,b) REFERENCES t2)" {1 {unknown column "c" in foreign key definition}} B "CREATE TABLE t1(a, b, FOREIGN KEY(c,b) REFERENCES t2(d))" {1 {number of columns in foreign key does not match the number of columns in the referenced table}} } { do_test e_fkey-5.$tn.off { drop_all_tables execsql {PRAGMA foreign_keys = OFF} catchsql $zCreateTbl } $lRes do_test e_fkey-5.$tn.on { drop_all_tables execsql {PRAGMA foreign_keys = ON} catchsql $zCreateTbl } $lRes } #------------------------------------------------------------------------- # /* EV: R-47952-62498 */ # proc test_efkey_6 {tn zAlter isError} { drop_all_tables do_test e_fkey-6.$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 #------------------------------------------------------------------------- # /* EV: R-47080-02069 */ # # Test that ALTER TABLE adjusts REFERENCES clauses when the parent table # is RENAMED. # # /* EV: R-63827-54774 */ # # Test that these adjustments are visible in the sqlite_master table. # do_test e_fkey-7.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); CREATE TABLE c3(e, 'f col 2', FOREIGN KEY('f col 2') REFERENCES 'p 1 "parent one"' ON UPDATE CASCADE); INSERT INTO 'p 1 "parent one"' VALUES(1, 1); INSERT INTO c1 VALUES(1, 1); INSERT INTO c2 VALUES(1, 1); INSERT INTO c3 VALUES(1, 1); -- CREATE TABLE q(a, b, PRIMARY KEY(b)); } } {} do_test e_fkey-7.2 { execsql { ALTER TABLE 'p 1 "parent one"' RENAME TO p } } {} do_test e_fkey-7.3 { execsql { UPDATE p SET a = 'xxx', b = 'xxx'; SELECT * FROM p; SELECT * FROM c1; SELECT * FROM c2; SELECT * FROM c3; } } {xxx xxx 1 xxx 1 xxx 1 xxx} do_test e_fkey-7.4 { 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)} \ ] #------------------------------------------------------------------------- # /* EV: R-14208-23986 */ # /* EV: R-11078-03945 */ # # Check that a DROP TABLE does an implicit DELETE FROM. Which does not # cause any triggers to fire, but does fire foreign key actions. # do_test e_fkey-8.1 { drop_all_tables execsql { CREATE TABLE p(a, b, PRIMARY KEY(a, b)); CREATE TABLE c1(c, d, FOREIGN KEY(c, d) REFERENCES p ON DELETE SET NULL); CREATE TABLE c2(c, d, FOREIGN KEY(c, d) REFERENCES p ON DELETE SET DEFAULT); CREATE TABLE c3(c, d, FOREIGN KEY(c, d) REFERENCES p ON DELETE CASCADE); CREATE TABLE c4(c, d, FOREIGN KEY(c, d) REFERENCES p ON DELETE RESTRICT); CREATE TABLE c5(c, d, FOREIGN KEY(c, d) REFERENCES p ON DELETE NO ACTION); CREATE TABLE c6(c, d, FOREIGN KEY(c, d) REFERENCES p ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED ); CREATE TABLE c7(c, d, FOREIGN KEY(c, d) REFERENCES p ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED ); CREATE TABLE log(msg); CREATE TRIGGER tt AFTER DELETE ON p BEGIN INSERT INTO log VALUES('delete ' || old.rowid); END; } } {} do_test e_fkey-8.2 { execsql { INSERT INTO p VALUES('a', 'b'); INSERT INTO c1 VALUES('a', 'b'); INSERT INTO c2 VALUES('a', 'b'); INSERT INTO c3 VALUES('a', 'b'); BEGIN; DROP TABLE p; SELECT * FROM c1; } } {{} {}} do_test e_fkey-8.3 { execsql { SELECT * FROM c2 } } {{} {}} do_test e_fkey-8.4 { execsql { SELECT * FROM c3 } } {} do_test e_fkey-8.5 { execsql { SELECT * FROM log } } {} do_test e_fkey-8.6 { execsql ROLLBACK } {} do_test e_fkey-8.7 { execsql { BEGIN; DELETE FROM p; SELECT * FROM log; ROLLBACK; } } {{delete 1}} #------------------------------------------------------------------------- # /* EV: R-32768-47925 */ # # If an IMMEDIATE foreign key fails as a result of a DROP TABLE, the # DROP TABLE command fails. # do_test e_fkey-9.1 { execsql { DELETE FROM c1; DELETE FROM c2; DELETE FROM c3; } execsql { INSERT INTO c5 VALUES('a', 'b') } catchsql { DROP TABLE p } } {1 {foreign key constraint failed}} do_test e_fkey-9.2 { execsql { SELECT * FROM p } } {a b} do_test e_fkey-9.3 { catchsql { BEGIN; DROP TABLE p; } } {1 {foreign key constraint failed}} do_test e_fkey-9.4 { execsql { SELECT * FROM p; SELECT * FROM c5; ROLLBACK; } } {a b a b} #------------------------------------------------------------------------- # /* EV: R-05903-08460 */ # # If a DEFERRED foreign key fails as a result of a DROP TABLE, attempting # to commit the transaction fails unless the violation is fixed. # do_test e_fkey-10.1 { execsql { DELETE FROM c1 ; DELETE FROM c2 ; DELETE FROM c3 ; DELETE FROM c4 ; DELETE FROM c5 ; DELETE FROM c6 ; DELETE FROM c7 } } {} do_test e_fkey-10.2 { execsql { INSERT INTO c7 VALUES('a', 'b') } execsql { BEGIN; DROP TABLE p; } } {} do_test e_fkey-10.3 { catchsql COMMIT } {1 {foreign key constraint failed}} do_test e_fkey-10.4 { execsql { CREATE TABLE p(a, b, PRIMARY KEY(a, b)) } catchsql COMMIT } {1 {foreign key constraint failed}} do_test e_fkey-10.5 { execsql { INSERT INTO p VALUES('a', 'b') } execsql COMMIT } {} #------------------------------------------------------------------------- # /* EV: R-57242-37005 */ # # Any "foreign key mismatch" errors encountered while running an implicit # "DELETE FROM tbl" are ignored. # drop_all_tables do_test e_fkey-11.1 { execsql { PRAGMA foreign_keys = OFF; CREATE TABLE p(a PRIMARY KEY, b REFERENCES nosuchtable); CREATE TABLE c1(c, d, FOREIGN KEY(c, d) REFERENCES a); CREATE TABLE c2(c REFERENCES p(b), d); CREATE TABLE c3(c REFERENCES p ON DELETE SET NULL, d); INSERT INTO p VALUES(1, 2); INSERT INTO c1 VALUES(1, 2); INSERT INTO c2 VALUES(1, 2); INSERT INTO c3 VALUES(1, 2); } } {} do_test e_fkey-11.2 { execsql { PRAGMA foreign_keys = ON } catchsql { DELETE FROM p } } {1 {no such table: main.nosuchtable}} do_test e_fkey-11.3 { execsql { BEGIN; DROP TABLE p; SELECT * FROM c3; ROLLBACK; } } {{} 2} do_test e_fkey-11.4 { execsql { CREATE TABLE nosuchtable(x PRIMARY KEY) } catchsql { DELETE FROM p } } {1 {foreign key mismatch}} do_test e_fkey-11.5 { execsql { DROP TABLE c1 } catchsql { DELETE FROM p } } {1 {foreign key mismatch}} do_test e_fkey-11.6 { execsql { DROP TABLE c2 } execsql { DELETE FROM p } } {} #------------------------------------------------------------------------- # /* EV: R-54142-41346 */ # # Test that the special behaviours of ALTER and DROP TABLE are only # activated when foreign keys are enabled. Special behaviours are: # # 1. ADD COLUMN not allowing a REFERENCES clause with a non-NULL # default value. # 2. Modifying foreign key definitions when a parent table is RENAMEd. # 3. Running an implicit DELETE FROM command as part of DROP TABLE. # do_test e_fkey-12.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-12.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)}} do_test e_fkey-12.1.3 { execsql { PRAGMA foreign_keys = ON } } {} do_test e_fkey-12.2.1 { drop_all_tables execsql { CREATE TABLE p(a UNIQUE); CREATE TABLE c(b REFERENCES p(a)); BEGIN; ALTER TABLE p RENAME TO parent; SELECT sql FROM sqlite_master WHERE name = 'c'; ROLLBACK; } } {{CREATE TABLE c(b REFERENCES "parent"(a))}} do_test e_fkey-12.2.2 { execsql { PRAGMA foreign_keys = OFF; ALTER TABLE p RENAME TO parent; SELECT sql FROM sqlite_master WHERE name = 'c'; } } {{CREATE TABLE c(b REFERENCES p(a))}} do_test e_fkey-12.2.3 { execsql { PRAGMA foreign_keys = ON } } {} do_test e_fkey-12.3.1 { drop_all_tables execsql { CREATE TABLE p(a UNIQUE); CREATE TABLE c(b REFERENCES p(a) ON DELETE SET NULL); INSERT INTO p VALUES('x'); INSERT INTO c VALUES('x'); BEGIN; DROP TABLE p; SELECT * FROM c; ROLLBACK; } } {{}} do_test e_fkey-12.3.2 { execsql { PRAGMA foreign_keys = OFF; DROP TABLE p; SELECT * FROM c; } } {x} do_test e_fkey-12.3.3 { execsql { PRAGMA foreign_keys = ON } } {} ########################################################################### ### SECTION 6: Limits and Unsupported Features ########################################################################### #------------------------------------------------------------------------- # /* EV: R-24728-13230 */ # /* EV: R-24450-46174 */ # # Test that MATCH clauses are parsed, but SQLite treats every foreign key # constraint as if it were "MATCH SIMPLE". # foreach zMatch [list SIMPLE PARTIAL FULL Simple parTIAL FuLL ] { drop_all_tables do_test e_fkey-1.$zMatch.1 { execsql " CREATE TABLE p(a, b, c, PRIMARY KEY(b, c)); CREATE TABLE c(d, e, f, FOREIGN KEY(e, f) REFERENCES p MATCH $zMatch); " } {} do_test e_fkey-1.$zMatch.2 { execsql { INSERT INTO p VALUES(1, 2, 3) } # MATCH SIMPLE behaviour: Allow any child key that contains one or more # NULL value to be inserted. Non-NULL values do not have to map to any # parent key values, so long as at least one field of the child key is # NULL. execsql { INSERT INTO c VALUES('w', 2, 3) } execsql { INSERT INTO c VALUES('x', 'x', NULL) } execsql { INSERT INTO c VALUES('y', NULL, 'x') } execsql { INSERT INTO c VALUES('z', NULL, NULL) } # Check that the FK is enforced properly if there are no NULL values # in the child key columns. catchsql { INSERT INTO c VALUES('a', 2, 4) } } {1 {foreign key constraint failed}} } #------------------------------------------------------------------------- # /* EV: R-21599-16038 */ # # Test that SQLite does not support the SET CONSTRAINT statement. And # that it is possible to create both immediate and deferred constraints. # drop_all_tables do_test e_fkey-2.1 { catchsql { SET CONSTRAINTS ALL IMMEDIATE } } {1 {near "SET": syntax error}} do_test e_fkey-2.2 { catchsql { SET CONSTRAINTS ALL DEFERRED } } {1 {near "SET": syntax error}} do_test e_fkey-2.3 { execsql { CREATE TABLE p(a, b, PRIMARY KEY(a, b)); CREATE TABLE cd(c, d, FOREIGN KEY(c, d) REFERENCES p DEFERRABLE INITIALLY DEFERRED); CREATE TABLE ci(c, d, FOREIGN KEY(c, d) REFERENCES p DEFERRABLE INITIALLY IMMEDIATE); BEGIN; } } {} do_test e_fkey-2.4 { catchsql { INSERT INTO ci VALUES('x', 'y') } } {1 {foreign key constraint failed}} do_test e_fkey-2.5 { catchsql { INSERT INTO cd VALUES('x', 'y') } } {0 {}} do_test e_fkey-2.6 { catchsql { COMMIT } } {1 {foreign key constraint failed}} do_test e_fkey-2.7 { execsql { DELETE FROM cd; COMMIT; } } {} #------------------------------------------------------------------------- # /* EV: R-42264-30503 */ # # Test that the maximum recursion depth of foreign key action programs is # governed by the SQLITE_MAX_TRIGGER_DEPTH and SQLITE_LIMIT_TRIGGER_DEPTH # settings. # proc test_on_delete_recursion {limit} { drop_all_tables execsql { BEGIN; CREATE TABLE t0(a PRIMARY KEY, b); INSERT INTO t0 VALUES('x0', NULL); } for {set i 1} {$i <= $limit} {incr i} { execsql " CREATE TABLE t$i ( a PRIMARY KEY, b REFERENCES t[expr $i-1] ON DELETE CASCADE ); INSERT INTO t$i VALUES('x$i', 'x[expr $i-1]'); " } execsql COMMIT catchsql " DELETE FROM t0; SELECT count(*) FROM t$limit; " } proc test_on_update_recursion {limit} { drop_all_tables execsql { BEGIN; CREATE TABLE t0(a PRIMARY KEY); INSERT INTO t0 VALUES('xxx'); } for {set i 1} {$i <= $limit} {incr i} { set j [expr $i-1] execsql " CREATE TABLE t$i (a PRIMARY KEY REFERENCES t$j ON UPDATE CASCADE); INSERT INTO t$i VALUES('xxx'); " } execsql COMMIT catchsql " UPDATE t0 SET a = 'yyy'; SELECT NOT (a='yyy') FROM t$limit; " } do_test e_fkey-3.1.1 { test_on_delete_recursion $SQLITE_MAX_TRIGGER_DEPTH } {0 0} do_test e_fkey-3.1.2 { test_on_delete_recursion [expr $SQLITE_MAX_TRIGGER_DEPTH+1] } {1 {too many levels of trigger recursion}} do_test e_fkey-3.1.3 { sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 5 test_on_delete_recursion 5 } {0 0} do_test e_fkey-3.1.4 { test_on_delete_recursion 6 } {1 {too many levels of trigger recursion}} do_test e_fkey-3.1.5 { sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 1000000 } {5} do_test e_fkey-3.2.1 { test_on_update_recursion $SQLITE_MAX_TRIGGER_DEPTH } {0 0} do_test e_fkey-3.2.2 { test_on_update_recursion [expr $SQLITE_MAX_TRIGGER_DEPTH+1] } {1 {too many levels of trigger recursion}} do_test e_fkey-3.2.3 { sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 5 test_on_update_recursion 5 } {0 0} do_test e_fkey-3.2.4 { test_on_update_recursion 6 } {1 {too many levels of trigger recursion}} do_test e_fkey-3.2.5 { sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 1000000 } {5} #------------------------------------------------------------------------- # /* EV: R-51769-32730 */ # # The setting of the recursive_triggers pragma does not affect foreign # key actions. # foreach recursive_triggers_setting [list 0 1 ON OFF] { drop_all_tables execsql "PRAGMA recursive_triggers = $recursive_triggers_setting" do_test e_fkey-4.$recursive_triggers_setting.1 { execsql { CREATE TABLE t1(a PRIMARY KEY, b REFERENCES t1 ON DELETE CASCADE); INSERT INTO t1 VALUES(1, NULL); INSERT INTO t1 VALUES(2, 1); INSERT INTO t1 VALUES(3, 2); INSERT INTO t1 VALUES(4, 3); INSERT INTO t1 VALUES(5, 4); SELECT count(*) FROM t1; } } {5} do_test e_fkey-4.$recursive_triggers_setting.2 { execsql { SELECT count(*) FROM t1 WHERE a = 1 } } {1} do_test e_fkey-4.$recursive_triggers_setting.3 { execsql { DELETE FROM t1 WHERE a = 1; SELECT count(*) FROM t1; } } {0} } finish_test |
Changes to test/expr.test.
︙ | ︙ | |||
161 162 163 164 165 166 167 168 169 170 171 172 173 174 | test_expr expr-1.108 {i1=0} {1%0} {{}} test_expr expr-1.109 {i1=0} {1/0} {{}} if {[working_64bit_int]} { test_expr expr-1.110 {i1=0} {-9223372036854775807/-1} 9223372036854775807 } ifcapable floatingpoint { test_expr expr-2.1 {r1=1.23, r2=2.34} {r1+r2} 3.57 test_expr expr-2.2 {r1=1.23, r2=2.34} {r1-r2} -1.11 test_expr expr-2.3 {r1=1.23, r2=2.34} {r1*r2} 2.8782 } set tcl_precision 15 ifcapable floatingpoint { | > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | test_expr expr-1.108 {i1=0} {1%0} {{}} 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 ifcapable floatingpoint { test_expr expr-2.1 {r1=1.23, r2=2.34} {r1+r2} 3.57 test_expr expr-2.2 {r1=1.23, r2=2.34} {r1-r2} -1.11 test_expr expr-2.3 {r1=1.23, r2=2.34} {r1*r2} 2.8782 } set tcl_precision 15 ifcapable floatingpoint { |
︙ | ︙ |
Changes to test/fkey1.test.
︙ | ︙ | |||
42 43 44 45 46 47 48 | y TEXT ); } } {} do_test fkey1-1.2 { execsql { CREATE TABLE t3( | | | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | y TEXT ); } } {} do_test fkey1-1.2 { execsql { CREATE TABLE t3( a INTEGER REFERENCES t2, b INTEGER REFERENCES t1, FOREIGN KEY (a,b) REFERENCES t2(x,y) ); } } {} do_test fkey1-2.1 { |
︙ | ︙ | |||
76 77 78 79 80 81 82 | CREATE TABLE t5(a PRIMARY KEY, b, c); CREATE TABLE t6( d REFERENCES t5, e REFERENCES t5(c) ); PRAGMA foreign_key_list(t6); } | | | | | | | | 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | CREATE TABLE t5(a PRIMARY KEY, b, c); CREATE TABLE t6( d REFERENCES t5, e REFERENCES t5(c) ); PRAGMA foreign_key_list(t6); } } [concat \ {0 0 t5 e c {NO ACTION} {NO ACTION} NONE} \ {1 0 t5 d {} {NO ACTION} {NO ACTION} NONE} \ ] do_test fkey1-3.2 { execsql { CREATE TABLE t7(d, e, f, FOREIGN KEY (d, e) REFERENCES t5(a, b) ); PRAGMA foreign_key_list(t7); } } [concat \ {0 0 t5 d a {NO ACTION} {NO ACTION} NONE} \ {0 1 t5 e b {NO ACTION} {NO ACTION} NONE} \ ] do_test fkey1-3.3 { execsql { CREATE TABLE t8(d, e, f, FOREIGN KEY (d, e) REFERENCES t5 ON DELETE CASCADE ON UPDATE SET NULL ); PRAGMA foreign_key_list(t8); |
︙ | ︙ |
Added test/fkey2.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 | # 2009 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. # # This file implements tests for foreign keys. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {!foreignkey||!trigger} { finish_test return } #------------------------------------------------------------------------- # Test structure: # # fkey2-1.*: Simple tests to check that immediate and deferred foreign key # constraints work when not inside a transaction. # # fkey2-2.*: Tests to verify that deferred foreign keys work inside # explicit transactions (i.e that processing really is deferred). # # fkey2-3.*: Tests that a statement transaction is rolled back if an # immediate foreign key constraint is violated. # # fkey2-4.*: Test that FK actions may recurse even when recursive triggers # are disabled. # # fkey2-5.*: Check that if foreign-keys are enabled, it is not possible # to write to an FK column using the incremental blob API. # # fkey2-6.*: Test that FK processing is automatically disabled when # running VACUUM. # # fkey2-7.*: Test using an IPK as the key in the child (referencing) table. # # fkey2-8.*: Test that enabling/disabling foreign key support while a # transaction is active is not possible. # # fkey2-9.*: Test SET DEFAULT actions. # # fkey2-10.*: Test errors. # # fkey2-11.*: Test CASCADE actions. # # fkey2-12.*: Test RESTRICT actions. # # fkey2-13.*: Test that FK processing is performed when a row is REPLACED by # an UPDATE or INSERT statement. # # fkey2-14.*: Test the ALTER TABLE and DROP TABLE commands. # # fkey2-15.*: Test that if there are no (known) outstanding foreign key # constraint violations in the database, inserting into a parent # table or deleting from a child table does not cause SQLite # to check if this has repaired an outstanding violation. # # fkey2-16.*: Test that rows that refer to themselves may be inserted, # updated and deleted. # # fkey2-17.*: Test that the "count_changes" pragma does not interfere with # FK constraint processing. # # fkey2-18.*: Test that the authorization callback is invoked when processing # FK constraints. # # fkey2-genfkey.*: Tests that were used with the shell tool .genfkey # command. Recycled to test the built-in implementation. # execsql { PRAGMA foreign_keys = on } set FkeySimpleSchema { PRAGMA foreign_keys = on; CREATE TABLE t1(a PRIMARY KEY, b); CREATE TABLE t2(c REFERENCES t1(a) /D/ , d); CREATE TABLE t3(a PRIMARY KEY, b); CREATE TABLE t4(c REFERENCES t3 /D/, d); CREATE TABLE t7(a, b INTEGER PRIMARY KEY); CREATE TABLE t8(c REFERENCES t7 /D/, d); CREATE TABLE t9(a REFERENCES nosuchtable, b); CREATE TABLE t10(a REFERENCES t9(c) /D/, b); } set FkeySimpleTests { 1.1 "INSERT INTO t2 VALUES(1, 3)" {1 {foreign key constraint failed}} 1.2 "INSERT INTO t1 VALUES(1, 2)" {0 {}} 1.3 "INSERT INTO t2 VALUES(1, 3)" {0 {}} 1.4 "INSERT INTO t2 VALUES(2, 4)" {1 {foreign key constraint failed}} 1.5 "INSERT INTO t2 VALUES(NULL, 4)" {0 {}} 1.6 "UPDATE t2 SET c=2 WHERE d=4" {1 {foreign key constraint failed}} 1.7 "UPDATE t2 SET c=1 WHERE d=4" {0 {}} 1.9 "UPDATE t2 SET c=1 WHERE d=4" {0 {}} 1.10 "UPDATE t2 SET c=NULL WHERE d=4" {0 {}} 1.11 "DELETE FROM t1 WHERE a=1" {1 {foreign key constraint failed}} 1.12 "UPDATE t1 SET a = 2" {1 {foreign key constraint failed}} 1.13 "UPDATE t1 SET a = 1" {0 {}} 2.1 "INSERT INTO t4 VALUES(1, 3)" {1 {foreign key constraint failed}} 2.2 "INSERT INTO t3 VALUES(1, 2)" {0 {}} 2.3 "INSERT INTO t4 VALUES(1, 3)" {0 {}} 4.1 "INSERT INTO t8 VALUES(1, 3)" {1 {foreign key constraint failed}} 4.2 "INSERT INTO t7 VALUES(2, 1)" {0 {}} 4.3 "INSERT INTO t8 VALUES(1, 3)" {0 {}} 4.4 "INSERT INTO t8 VALUES(2, 4)" {1 {foreign key constraint failed}} 4.5 "INSERT INTO t8 VALUES(NULL, 4)" {0 {}} 4.6 "UPDATE t8 SET c=2 WHERE d=4" {1 {foreign key constraint failed}} 4.7 "UPDATE t8 SET c=1 WHERE d=4" {0 {}} 4.9 "UPDATE t8 SET c=1 WHERE d=4" {0 {}} 4.10 "UPDATE t8 SET c=NULL WHERE d=4" {0 {}} 4.11 "DELETE FROM t7 WHERE b=1" {1 {foreign key constraint failed}} 4.12 "UPDATE t7 SET b = 2" {1 {foreign key constraint failed}} 4.13 "UPDATE t7 SET b = 1" {0 {}} 4.14 "INSERT INTO t8 VALUES('a', 'b')" {1 {foreign key constraint failed}} 4.15 "UPDATE t7 SET b = 5" {1 {foreign key constraint failed}} 4.16 "UPDATE t7 SET rowid = 5" {1 {foreign key constraint failed}} 4.17 "UPDATE t7 SET a = 10" {0 {}} 5.1 "INSERT INTO t9 VALUES(1, 3)" {1 {no such table: main.nosuchtable}} 5.2 "INSERT INTO t10 VALUES(1, 3)" {1 {foreign key mismatch}} } do_test fkey2-1.1.0 { execsql [string map {/D/ {}} $FkeySimpleSchema] } {} foreach {tn zSql res} $FkeySimpleTests { do_test fkey2-1.1.$tn { catchsql $zSql } $res } drop_all_tables do_test fkey2-1.2.0 { execsql [string map {/D/ {DEFERRABLE INITIALLY DEFERRED}} $FkeySimpleSchema] } {} foreach {tn zSql res} $FkeySimpleTests { do_test fkey2-1.2.$tn { catchsql $zSql } $res } drop_all_tables do_test fkey2-1.3.0 { execsql [string map {/D/ {}} $FkeySimpleSchema] execsql { PRAGMA count_changes = 1 } } {} foreach {tn zSql res} $FkeySimpleTests { if {$res == "0 {}"} { set res {0 1} } do_test fkey2-1.3.$tn { catchsql $zSql } $res } execsql { PRAGMA count_changes = 0 } drop_all_tables do_test fkey2-1.4.0 { execsql [string map {/D/ {}} $FkeySimpleSchema] execsql { PRAGMA count_changes = 1 } } {} foreach {tn zSql res} $FkeySimpleTests { if {$res == "0 {}"} { set res {0 1} } execsql BEGIN do_test fkey2-1.4.$tn { catchsql $zSql } $res execsql COMMIT } execsql { PRAGMA count_changes = 0 } drop_all_tables # Special test: When the parent key is an IPK, make sure the affinity of # the IPK is not applied to the child key value before it is inserted # into the child table. do_test fkey2-1.5.1 { execsql { CREATE TABLE i(i INTEGER PRIMARY KEY); CREATE TABLE j(j REFERENCES i); INSERT INTO i VALUES(35); INSERT INTO j VALUES('35.0'); SELECT j, typeof(j) FROM j; } } {35.0 text} do_test fkey2-1.5.2 { catchsql { DELETE FROM i } } {1 {foreign key constraint failed}} # Same test using a regular primary key with integer affinity. drop_all_tables do_test fkey2-1.6.1 { execsql { CREATE TABLE i(i INT UNIQUE); CREATE TABLE j(j REFERENCES i(i)); INSERT INTO i VALUES('35.0'); INSERT INTO j VALUES('35.0'); SELECT j, typeof(j) FROM j; SELECT i, typeof(i) FROM i; } } {35.0 text 35 integer} do_test fkey2-1.6.2 { catchsql { DELETE FROM i } } {1 {foreign key constraint failed}} # Use a collation sequence on the parent key. drop_all_tables do_test fkey2-1.7.1 { execsql { CREATE TABLE i(i TEXT COLLATE nocase PRIMARY KEY); CREATE TABLE j(j TEXT COLLATE binary REFERENCES i(i)); INSERT INTO i VALUES('SQLite'); INSERT INTO j VALUES('sqlite'); } catchsql { DELETE FROM i } } {1 {foreign key constraint failed}} # Use the parent key collation even if it is default and the child key # has an explicit value. drop_all_tables do_test fkey2-1.7.2 { execsql { CREATE TABLE i(i TEXT PRIMARY KEY); -- Colseq is "BINARY" CREATE TABLE j(j TEXT COLLATE nocase REFERENCES i(i)); INSERT INTO i VALUES('SQLite'); } catchsql { INSERT INTO j VALUES('sqlite') } } {1 {foreign key constraint failed}} do_test fkey2-1.7.3 { execsql { INSERT INTO i VALUES('sqlite'); INSERT INTO j VALUES('sqlite'); DELETE FROM i WHERE i = 'SQLite'; } catchsql { DELETE FROM i WHERE i = 'sqlite' } } {1 {foreign key constraint failed}} #------------------------------------------------------------------------- # This section (test cases fkey2-2.*) contains tests to check that the # deferred foreign key constraint logic works. # proc fkey2-2-test {tn nocommit sql {res {}}} { if {$res eq "FKV"} { set expected {1 {foreign key constraint failed}} } else { set expected [list 0 $res] } do_test fkey2-2.$tn [list catchsql $sql] $expected if {$nocommit} { do_test fkey2-2.${tn}c { catchsql COMMIT } {1 {foreign key constraint failed}} } } fkey2-2-test 1 0 { CREATE TABLE node( nodeid PRIMARY KEY, parent REFERENCES node DEFERRABLE INITIALLY DEFERRED ); CREATE TABLE leaf( cellid PRIMARY KEY, parent REFERENCES node DEFERRABLE INITIALLY DEFERRED ); } fkey2-2-test 1 0 "INSERT INTO node VALUES(1, 0)" FKV fkey2-2-test 2 0 "BEGIN" fkey2-2-test 3 1 "INSERT INTO node VALUES(1, 0)" fkey2-2-test 4 0 "UPDATE node SET parent = NULL" fkey2-2-test 5 0 "COMMIT" fkey2-2-test 6 0 "SELECT * FROM node" {1 {}} fkey2-2-test 7 0 "BEGIN" fkey2-2-test 8 1 "INSERT INTO leaf VALUES('a', 2)" fkey2-2-test 9 1 "INSERT INTO node VALUES(2, 0)" fkey2-2-test 10 0 "UPDATE node SET parent = 1 WHERE nodeid = 2" fkey2-2-test 11 0 "COMMIT" fkey2-2-test 12 0 "SELECT * FROM node" {1 {} 2 1} fkey2-2-test 13 0 "SELECT * FROM leaf" {a 2} fkey2-2-test 14 0 "BEGIN" fkey2-2-test 15 1 "DELETE FROM node WHERE nodeid = 2" fkey2-2-test 16 0 "INSERT INTO node VALUES(2, NULL)" fkey2-2-test 17 0 "COMMIT" fkey2-2-test 18 0 "SELECT * FROM node" {1 {} 2 {}} fkey2-2-test 19 0 "SELECT * FROM leaf" {a 2} fkey2-2-test 20 0 "BEGIN" fkey2-2-test 21 0 "INSERT INTO leaf VALUES('b', 1)" fkey2-2-test 22 0 "SAVEPOINT save" fkey2-2-test 23 0 "DELETE FROM node WHERE nodeid = 1" fkey2-2-test 24 0 "ROLLBACK TO save" fkey2-2-test 25 0 "COMMIT" fkey2-2-test 26 0 "SELECT * FROM node" {1 {} 2 {}} fkey2-2-test 27 0 "SELECT * FROM leaf" {a 2 b 1} fkey2-2-test 28 0 "BEGIN" fkey2-2-test 29 0 "INSERT INTO leaf VALUES('c', 1)" fkey2-2-test 30 0 "SAVEPOINT save" fkey2-2-test 31 0 "DELETE FROM node WHERE nodeid = 1" fkey2-2-test 32 1 "RELEASE save" fkey2-2-test 33 1 "DELETE FROM leaf WHERE cellid = 'b'" fkey2-2-test 34 0 "DELETE FROM leaf WHERE cellid = 'c'" fkey2-2-test 35 0 "COMMIT" fkey2-2-test 36 0 "SELECT * FROM node" {2 {}} fkey2-2-test 37 0 "SELECT * FROM leaf" {a 2} fkey2-2-test 38 0 "SAVEPOINT outer" fkey2-2-test 39 1 "INSERT INTO leaf VALUES('d', 3)" fkey2-2-test 40 1 "RELEASE outer" FKV fkey2-2-test 41 1 "INSERT INTO leaf VALUES('e', 3)" fkey2-2-test 42 0 "INSERT INTO node VALUES(3, 2)" fkey2-2-test 43 0 "RELEASE outer" fkey2-2-test 44 0 "SAVEPOINT outer" fkey2-2-test 45 1 "DELETE FROM node WHERE nodeid=3" fkey2-2-test 47 0 "INSERT INTO node VALUES(3, 2)" fkey2-2-test 48 0 "ROLLBACK TO outer" fkey2-2-test 49 0 "RELEASE outer" fkey2-2-test 50 0 "SAVEPOINT outer" fkey2-2-test 51 1 "INSERT INTO leaf VALUES('f', 4)" fkey2-2-test 52 1 "SAVEPOINT inner" fkey2-2-test 53 1 "INSERT INTO leaf VALUES('g', 4)" fkey2-2-test 54 1 "RELEASE outer" FKV fkey2-2-test 55 1 "ROLLBACK TO inner" fkey2-2-test 56 0 "COMMIT" FKV fkey2-2-test 57 0 "INSERT INTO node VALUES(4, NULL)" fkey2-2-test 58 0 "RELEASE outer" fkey2-2-test 59 0 "SELECT * FROM node" {2 {} 3 2 4 {}} fkey2-2-test 60 0 "SELECT * FROM leaf" {a 2 d 3 e 3 f 4} # The following set of tests check that if a statement that affects # multiple rows violates some foreign key constraints, then strikes a # constraint that causes the statement-transaction to be rolled back, # the deferred constraint counter is correctly reset to the value it # had before the statement-transaction was opened. # fkey2-2-test 61 0 "BEGIN" fkey2-2-test 62 0 "DELETE FROM leaf" fkey2-2-test 63 0 "DELETE FROM node" fkey2-2-test 64 1 "INSERT INTO leaf VALUES('a', 1)" fkey2-2-test 65 1 "INSERT INTO leaf VALUES('b', 2)" fkey2-2-test 66 1 "INSERT INTO leaf VALUES('c', 1)" do_test fkey2-2-test-67 { catchsql "INSERT INTO node SELECT parent, 3 FROM leaf" } {1 {column nodeid is not unique}} fkey2-2-test 68 0 "COMMIT" FKV fkey2-2-test 69 1 "INSERT INTO node VALUES(1, NULL)" fkey2-2-test 70 0 "INSERT INTO node VALUES(2, NULL)" fkey2-2-test 71 0 "COMMIT" fkey2-2-test 72 0 "BEGIN" fkey2-2-test 73 1 "DELETE FROM node" fkey2-2-test 74 0 "INSERT INTO node(nodeid) SELECT DISTINCT parent FROM leaf" fkey2-2-test 75 0 "COMMIT" #------------------------------------------------------------------------- # Test cases fkey2-3.* test that a program that executes foreign key # actions (CASCADE, SET DEFAULT, SET NULL etc.) or tests FK constraints # opens a statement transaction if required. # # fkey2-3.1.*: Test UPDATE statements. # fkey2-3.2.*: Test DELETE statements. # drop_all_tables do_test fkey2-3.1.1 { execsql { CREATE TABLE ab(a PRIMARY KEY, b); CREATE TABLE cd( c PRIMARY KEY REFERENCES ab ON UPDATE CASCADE ON DELETE CASCADE, d ); CREATE TABLE ef( e REFERENCES cd ON UPDATE CASCADE, f, CHECK (e!=5) ); } } {} do_test fkey2-3.1.2 { execsql { 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 {constraint failed}} 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 {constraint failed}} 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; catchsql { DELETE FROM ab } } {1 {foreign key constraint failed}} do_test fkey2-3.2.2 { execsql COMMIT execsql { SELECT * FROM ab; SELECT * FROM cd; SELECT * FROM ef } } {1 b 1 d 1 e} #------------------------------------------------------------------------- # Test cases fkey2-4.* test that recursive foreign key actions # (i.e. CASCADE) are allowed even if recursive triggers are disabled. # drop_all_tables do_test fkey2-4.1 { execsql { CREATE TABLE t1( node PRIMARY KEY, parent REFERENCES t1 ON DELETE CASCADE ); CREATE TABLE t2(node PRIMARY KEY, parent); CREATE TRIGGER t2t AFTER DELETE ON t2 BEGIN DELETE FROM t2 WHERE parent = old.node; END; INSERT INTO t1 VALUES(1, NULL); INSERT INTO t1 VALUES(2, 1); INSERT INTO t1 VALUES(3, 1); INSERT INTO t1 VALUES(4, 2); INSERT INTO t1 VALUES(5, 2); INSERT INTO t1 VALUES(6, 3); INSERT INTO t1 VALUES(7, 3); INSERT INTO t2 SELECT * FROM t1; } } {} do_test fkey2-4.2 { execsql { PRAGMA recursive_triggers = off } execsql { BEGIN; DELETE FROM t1 WHERE node = 1; SELECT node FROM t1; } } {} do_test fkey2-4.3 { execsql { DELETE FROM t2 WHERE node = 1; SELECT node FROM t2; ROLLBACK; } } {4 5 6 7} do_test fkey2-4.4 { execsql { PRAGMA recursive_triggers = on } execsql { BEGIN; DELETE FROM t1 WHERE node = 1; SELECT node FROM t1; } } {} do_test fkey2-4.3 { execsql { DELETE FROM t2 WHERE node = 1; SELECT node FROM t2; ROLLBACK; } } {} #------------------------------------------------------------------------- # Test cases fkey2-5.* verify that the incremental blob API may not # write to a foreign key column while foreign-keys are enabled. # drop_all_tables ifcapable incrblob { do_test fkey2-5.1 { execsql { CREATE TABLE t1(a PRIMARY KEY, b); CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1(a)); INSERT INTO t1 VALUES('hello', 'world'); INSERT INTO t2 VALUES('key', 'hello'); } } {} do_test fkey2-5.2 { set rc [catch { set fd [db incrblob t2 b 1] } msg] list $rc $msg } {1 {cannot open foreign key column for writing}} do_test fkey2-5.3 { set rc [catch { set fd [db incrblob -readonly t2 b 1] } msg] close $fd set rc } {0} do_test fkey2-5.4 { execsql { PRAGMA foreign_keys = off } set rc [catch { set fd [db incrblob t2 b 1] } msg] close $fd set rc } {0} do_test fkey2-5.5 { execsql { PRAGMA foreign_keys = on } } {} } drop_all_tables ifcapable vacuum { do_test fkey2-6.1 { execsql { CREATE TABLE t1(a REFERENCES t2(c), b); CREATE TABLE t2(c UNIQUE, b); INSERT INTO t2 VALUES(1, 2); INSERT INTO t1 VALUES(1, 2); VACUUM; } } {} } #------------------------------------------------------------------------- # Test that it is possible to use an INTEGER PRIMARY KEY as the child key # of a foreign constraint. # drop_all_tables do_test fkey2-7.1 { execsql { CREATE TABLE t1(a PRIMARY KEY, b); CREATE TABLE t2(c INTEGER PRIMARY KEY REFERENCES t1, b); } } {} do_test fkey2-7.2 { catchsql { INSERT INTO t2 VALUES(1, 'A'); } } {1 {foreign key constraint failed}} do_test fkey2-7.3 { execsql { INSERT INTO t1 VALUES(1, 2); INSERT INTO t1 VALUES(2, 3); INSERT INTO t2 VALUES(1, 'A'); } } {} do_test fkey2-7.4 { execsql { UPDATE t2 SET c = 2 } } {} do_test fkey2-7.5 { catchsql { UPDATE t2 SET c = 3 } } {1 {foreign key constraint failed}} do_test fkey2-7.6 { catchsql { DELETE FROM t1 WHERE a = 2 } } {1 {foreign key constraint failed}} do_test fkey2-7.7 { execsql { DELETE FROM t1 WHERE a = 1 } } {} do_test fkey2-7.8 { catchsql { UPDATE t1 SET a = 3 } } {1 {foreign key constraint failed}} do_test fkey2-7.9 { catchsql { UPDATE t2 SET rowid = 3 } } {1 {foreign key constraint failed}} #------------------------------------------------------------------------- # Test that it is not possible to enable/disable FK support while a # transaction is open. # drop_all_tables proc fkey2-8-test {tn zSql value} { do_test fkey-2.8.$tn.1 [list execsql $zSql] {} do_test fkey-2.8.$tn.2 { execsql "PRAGMA foreign_keys" } $value } fkey2-8-test 1 { PRAGMA foreign_keys = 0 } 0 fkey2-8-test 2 { PRAGMA foreign_keys = 1 } 1 fkey2-8-test 3 { BEGIN } 1 fkey2-8-test 4 { PRAGMA foreign_keys = 0 } 1 fkey2-8-test 5 { COMMIT } 1 fkey2-8-test 6 { PRAGMA foreign_keys = 0 } 0 fkey2-8-test 7 { BEGIN } 0 fkey2-8-test 8 { PRAGMA foreign_keys = 1 } 0 fkey2-8-test 9 { COMMIT } 0 fkey2-8-test 10 { PRAGMA foreign_keys = 1 } 1 fkey2-8-test 11 { PRAGMA foreign_keys = off } 0 fkey2-8-test 12 { PRAGMA foreign_keys = on } 1 fkey2-8-test 13 { PRAGMA foreign_keys = no } 0 fkey2-8-test 14 { PRAGMA foreign_keys = yes } 1 fkey2-8-test 15 { PRAGMA foreign_keys = false } 0 fkey2-8-test 16 { PRAGMA foreign_keys = true } 1 #------------------------------------------------------------------------- # The following tests, fkey2-9.*, test SET DEFAULT actions. # drop_all_tables do_test fkey2-9.1.1 { execsql { CREATE TABLE t1(a INTEGER PRIMARY KEY, b); CREATE TABLE t2( c INTEGER PRIMARY KEY, d INTEGER DEFAULT 1 REFERENCES t1 ON DELETE SET DEFAULT ); DELETE FROM t1; } } {} do_test fkey2-9.1.2 { execsql { INSERT INTO t1 VALUES(1, 'one'); INSERT INTO t1 VALUES(2, 'two'); INSERT INTO t2 VALUES(1, 2); SELECT * FROM t2; DELETE FROM t1 WHERE a = 2; SELECT * FROM t2; } } {1 2 1 1} do_test fkey2-9.1.3 { execsql { INSERT INTO t1 VALUES(2, 'two'); UPDATE t2 SET d = 2; DELETE FROM t1 WHERE a = 1; SELECT * FROM t2; } } {1 2} do_test fkey2-9.1.4 { execsql { SELECT * FROM t1 } } {2 two} do_test fkey2-9.1.5 { catchsql { DELETE FROM t1 } } {1 {foreign key constraint failed}} do_test fkey2-9.2.1 { execsql { CREATE TABLE pp(a, b, c, PRIMARY KEY(b, c)); CREATE TABLE cc(d DEFAULT 3, e DEFAULT 1, f DEFAULT 2, FOREIGN KEY(f, d) REFERENCES pp ON UPDATE SET DEFAULT ON DELETE SET NULL ); INSERT INTO pp VALUES(1, 2, 3); INSERT INTO pp VALUES(4, 5, 6); INSERT INTO pp VALUES(7, 8, 9); } } {} do_test fkey2-9.2.2 { execsql { INSERT INTO cc VALUES(6, 'A', 5); INSERT INTO cc VALUES(6, 'B', 5); INSERT INTO cc VALUES(9, 'A', 8); INSERT INTO cc VALUES(9, 'B', 8); UPDATE pp SET b = 1 WHERE a = 7; SELECT * FROM cc; } } {6 A 5 6 B 5 3 A 2 3 B 2} do_test fkey2-9.2.3 { execsql { DELETE FROM pp WHERE a = 4; SELECT * FROM cc; } } {{} A {} {} B {} 3 A 2 3 B 2} #------------------------------------------------------------------------- # The following tests, fkey2-10.*, test "foreign key mismatch" and # other errors. # set tn 0 foreach zSql [list { CREATE TABLE p(a PRIMARY KEY, b); CREATE TABLE c(x REFERENCES p(c)); } { CREATE TABLE c(x REFERENCES v(y)); CREATE VIEW v AS SELECT x AS y FROM c; } { CREATE TABLE p(a, b, PRIMARY KEY(a, b)); CREATE TABLE c(x REFERENCES p); } { CREATE TABLE p(a COLLATE binary, b); CREATE UNIQUE INDEX i ON p(a COLLATE nocase); CREATE TABLE c(x REFERENCES p(a)); }] { drop_all_tables do_test fkey2-10.1.[incr tn] { execsql $zSql catchsql { INSERT INTO c DEFAULT VALUES } } {1 {foreign key mismatch}} } # "rowid" cannot be used as part of a child or parent key definition # unless it happens to be the name of an explicitly declared column. # do_test fkey2-10.2.1 { drop_all_tables catchsql { CREATE TABLE t1(a PRIMARY KEY, b); CREATE TABLE t2(c, d, FOREIGN KEY(rowid) REFERENCES t1(a)); } } {1 {unknown column "rowid" in foreign key definition}} do_test fkey2-10.2.2 { drop_all_tables catchsql { CREATE TABLE t1(a PRIMARY KEY, b); CREATE TABLE t2(rowid, d, FOREIGN KEY(rowid) REFERENCES t1(a)); } } {0 {}} do_test fkey2-10.2.1 { drop_all_tables catchsql { CREATE TABLE t1(a, b); CREATE TABLE t2(c, d, FOREIGN KEY(c) REFERENCES t1(rowid)); INSERT INTO t1(rowid, a, b) VALUES(1, 1, 1); INSERT INTO t2 VALUES(1, 1); } } {1 {foreign key mismatch}} do_test fkey2-10.2.2 { drop_all_tables catchsql { CREATE TABLE t1(rowid PRIMARY KEY, b); CREATE TABLE t2(c, d, FOREIGN KEY(c) REFERENCES t1(rowid)); INSERT INTO t1(rowid, b) VALUES(1, 1); INSERT INTO t2 VALUES(1, 1); } } {0 {}} #------------------------------------------------------------------------- # The following tests, fkey2-11.*, test CASCADE actions. # drop_all_tables do_test fkey2-11.1.1 { execsql { CREATE TABLE t1(a INTEGER PRIMARY KEY, b); CREATE TABLE t2(c, d, FOREIGN KEY(c) REFERENCES t1(a) ON UPDATE CASCADE); INSERT INTO t1 VALUES(10, 100); INSERT INTO t2 VALUES(10, 100); UPDATE t1 SET a = 15; SELECT * FROM t2; } } {15 100} #------------------------------------------------------------------------- # The following tests, fkey2-12.*, test RESTRICT actions. # drop_all_tables do_test fkey2-12.1.1 { execsql { CREATE TABLE t1(a, b PRIMARY KEY); CREATE TABLE t2( x REFERENCES t1 ON UPDATE RESTRICT DEFERRABLE INITIALLY DEFERRED ); INSERT INTO t1 VALUES(1, 'one'); INSERT INTO t1 VALUES(2, 'two'); INSERT INTO t1 VALUES(3, 'three'); } } {} do_test fkey2-12.1.2 { execsql "BEGIN" execsql "INSERT INTO t2 VALUES('two')" } {} do_test fkey2-12.1.3 { execsql "UPDATE t1 SET b = 'four' WHERE b = 'one'" } {} do_test fkey2-12.1.4 { catchsql "UPDATE t1 SET b = 'five' WHERE b = 'two'" } {1 {foreign key constraint failed}} do_test fkey2-12.1.5 { execsql "DELETE FROM t1 WHERE b = 'two'" } {} do_test fkey2-12.1.6 { catchsql "COMMIT" } {1 {foreign key constraint failed}} do_test fkey2-12.1.7 { execsql { INSERT INTO t1 VALUES(2, 'two'); COMMIT; } } {} drop_all_tables do_test fkey2-12.2.1 { execsql { CREATE TABLE t1(x COLLATE NOCASE PRIMARY KEY); CREATE TRIGGER tt1 AFTER DELETE ON t1 WHEN EXISTS ( SELECT 1 FROM t2 WHERE old.x = y ) BEGIN INSERT INTO t1 VALUES(old.x); END; CREATE TABLE t2(y REFERENCES t1); INSERT INTO t1 VALUES('A'); INSERT INTO t1 VALUES('B'); INSERT INTO t2 VALUES('a'); INSERT INTO t2 VALUES('b'); SELECT * FROM t1; SELECT * FROM t2; } } {A B a b} do_test fkey2-12.2.2 { execsql { DELETE FROM t1 } execsql { SELECT * FROM t1; SELECT * FROM t2; } } {A B a b} do_test fkey2-12.2.3 { execsql { DROP TABLE t2; CREATE TABLE t2(y REFERENCES t1 ON DELETE RESTRICT); INSERT INTO t2 VALUES('a'); INSERT INTO t2 VALUES('b'); } catchsql { DELETE FROM t1 } } {1 {foreign key constraint failed}} do_test fkey2-12.2.4 { execsql { SELECT * FROM t1; SELECT * FROM t2; } } {A B a b} drop_all_tables do_test fkey2-12.3.1 { execsql { CREATE TABLE up( c00, c01, c02, c03, c04, c05, c06, c07, c08, c09, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31, c32, c33, c34, c35, c36, c37, c38, c39, PRIMARY KEY(c34, c35) ); CREATE TABLE down( c00, c01, c02, c03, c04, c05, c06, c07, c08, c09, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31, c32, c33, c34, c35, c36, c37, c38, c39, FOREIGN KEY(c39, c38) REFERENCES up ON UPDATE CASCADE ); } } {} do_test fkey2-12.3.2 { execsql { INSERT INTO up(c34, c35) VALUES('yes', 'no'); INSERT INTO down(c39, c38) VALUES('yes', 'no'); UPDATE up SET c34 = 'possibly'; SELECT c38, c39 FROM down; DELETE FROM down; } } {no possibly} do_test fkey2-12.3.3 { catchsql { INSERT INTO down(c39, c38) VALUES('yes', 'no') } } {1 {foreign key constraint failed}} do_test fkey2-12.3.4 { execsql { INSERT INTO up(c34, c35) VALUES('yes', 'no'); INSERT INTO down(c39, c38) VALUES('yes', 'no'); } catchsql { DELETE FROM up WHERE c34 = 'yes' } } {1 {foreign key constraint failed}} do_test fkey2-12.3.5 { execsql { DELETE FROM up WHERE c34 = 'possibly'; SELECT c34, c35 FROM up; SELECT c39, c38 FROM down; } } {yes no yes no} #------------------------------------------------------------------------- # The following tests, fkey2-13.*, test that FK processing is performed # when rows are REPLACEd. # drop_all_tables do_test fkey2-13.1.1 { execsql { CREATE TABLE pp(a UNIQUE, b, c, PRIMARY KEY(b, c)); CREATE TABLE cc(d, e, f UNIQUE, FOREIGN KEY(d, e) REFERENCES pp); INSERT INTO pp VALUES(1, 2, 3); INSERT INTO cc VALUES(2, 3, 1); } } {} foreach {tn stmt} { 1 "REPLACE INTO pp VALUES(1, 4, 5)" 2 "REPLACE INTO pp(rowid, a, b, c) VALUES(1, 2, 3, 4)" } { do_test fkey2-13.1.$tn.1 { catchsql $stmt } {1 {foreign key constraint failed}} do_test fkey2-13.1.$tn.2 { execsql { SELECT * FROM pp; SELECT * FROM cc; } } {1 2 3 2 3 1} do_test fkey2-13.1.$tn.3 { execsql BEGIN; catchsql $stmt } {1 {foreign key constraint failed}} do_test fkey2-13.1.$tn.4 { execsql { COMMIT; SELECT * FROM pp; SELECT * FROM cc; } } {1 2 3 2 3 1} } do_test fkey2-13.1.3 { execsql { REPLACE INTO pp(rowid, a, b, c) VALUES(1, 2, 2, 3); SELECT rowid, * FROM pp; SELECT * FROM cc; } } {1 2 2 3 2 3 1} do_test fkey2-13.1.4 { execsql { REPLACE INTO pp(rowid, a, b, c) VALUES(2, 2, 2, 3); SELECT rowid, * FROM pp; SELECT * FROM cc; } } {2 2 2 3 2 3 1} #------------------------------------------------------------------------- # The following tests, fkey2-14.*, test that the "DROP TABLE" and "ALTER # TABLE" commands work as expected wrt foreign key constraints. # # fkey2-14.1*: ALTER TABLE ADD COLUMN # fkey2-14.2*: ALTER TABLE RENAME TABLE # fkey2-14.3*: DROP TABLE # 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 { catchsql { ALTER TABLE t2 ADD COLUMN e REFERENCES t1 DEFAULT NULL} } {0 {}} do_test fkey2-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 fkey2-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 fkey2-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_parent($zCreate, $zOld, $zNew)} } 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")}} # 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); CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2); 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)} \ {CREATE TABLE t2(a PRIMARY KEY, b REFERENCES t1, c REFERENCES t2)} \ {CREATE TABLE t3(a REFERENCES t1, b REFERENCES t2, c REFERENCES t1)} \ ] do_test fkey2-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")} \ {CREATE TABLE t2(a PRIMARY KEY, b REFERENCES "t4", c REFERENCES t2)} \ {CREATE TABLE t3(a REFERENCES "t4", b REFERENCES t2, c REFERENCES "t4")} \ ] do_test fkey2-14.2.2.3 { catchsql { INSERT INTO t3 VALUES(1, 2, 3) } } {1 {foreign key constraint failed}} do_test fkey2-14.2.2.4 { execsql { INSERT INTO t4 VALUES(1, NULL) } } {} do_test fkey2-14.2.2.5 { catchsql { UPDATE t4 SET b = 5 } } {1 {foreign key constraint failed}} do_test fkey2-14.2.2.6 { catchsql { UPDATE t4 SET b = 1 } } {0 {}} do_test fkey2-14.2.2.7 { execsql { INSERT INTO t3 VALUES(1, NULL, 1) } } {} } do_test fkey-2.14.3.1 { drop_all_tables execsql { CREATE TABLE t1(a, b REFERENCES nosuchtable); DROP TABLE t1; } } {} do_test fkey-2.14.3.2 { execsql { CREATE TABLE t1(a PRIMARY KEY, b); INSERT INTO t1 VALUES('a', 1); CREATE TABLE t2(x REFERENCES t1); INSERT INTO t2 VALUES('a'); } } {} do_test fkey-2.14.3.3 { catchsql { DROP TABLE t1 } } {1 {foreign key constraint failed}} do_test fkey-2.14.3.4 { execsql { DELETE FROM t2; DROP TABLE t1; } } {} do_test fkey-2.14.3.4 { catchsql { INSERT INTO t2 VALUES('x') } } {1 {no such table: main.t1}} do_test fkey-2.14.3.5 { execsql { CREATE TABLE t1(x PRIMARY KEY); INSERT INTO t1 VALUES('x'); } execsql { INSERT INTO t2 VALUES('x') } } {} do_test fkey-2.14.3.6 { catchsql { DROP TABLE t1 } } {1 {foreign key constraint failed}} do_test fkey-2.14.3.7 { execsql { DROP TABLE t2; DROP TABLE t1; } } {} do_test fkey-2.14.3.8 { execsql { CREATE TABLE pp(x, y, PRIMARY KEY(x, y)); CREATE TABLE cc(a, b, FOREIGN KEY(a, b) REFERENCES pp(x, z)); } catchsql { INSERT INTO cc VALUES(1, 2) } } {1 {foreign key mismatch}} do_test fkey-2.14.3.9 { execsql { DROP TABLE cc } } {} do_test fkey-2.14.3.10 { execsql { CREATE TABLE cc(a, b, FOREIGN KEY(a, b) REFERENCES pp DEFERRABLE INITIALLY DEFERRED ); } execsql { INSERT INTO pp VALUES('a', 'b'); INSERT INTO cc VALUES('a', 'b'); BEGIN; DROP TABLE pp; CREATE TABLE pp(a, b, c, PRIMARY KEY(b, c)); INSERT INTO pp VALUES(1, 'a', 'b'); COMMIT; } } {} do_test fkey-2.14.3.11 { execsql { BEGIN; DROP TABLE cc; DROP TABLE pp; COMMIT; } } {} do_test fkey-2.14.3.12 { execsql { CREATE TABLE b1(a, b); CREATE TABLE b2(a, b REFERENCES b1); DROP TABLE b1; } } {} do_test fkey-2.14.3.13 { execsql { CREATE TABLE b3(a, b REFERENCES b2 DEFERRABLE INITIALLY DEFERRED); DROP TABLE b2; } } {} # Test that nothing goes wrong when dropping a table that refers to a view. # Or dropping a view that an existing FK (incorrectly) refers to. Or either # of the above scenarios with a virtual table. drop_all_tables do_test fkey-2.14.4.1 { execsql { CREATE TABLE t1(x REFERENCES v); CREATE VIEW v AS SELECT * FROM t1; } } {} do_test fkey-2.14.4.2 { execsql { DROP VIEW v; } } {} ifcapable vtab { register_echo_module db do_test fkey-2.14.4.3 { execsql { CREATE VIRTUAL TABLE v USING echo(t1) } } {} do_test fkey-2.14.4.2 { execsql { DROP TABLE v; } } {} } #------------------------------------------------------------------------- # The following tests, fkey2-15.*, test that unnecessary FK related scans # and lookups are avoided when the constraint counters are zero. # drop_all_tables proc execsqlS {zSql} { set ::sqlite_search_count 0 set ::sqlite_found_count 0 set res [uplevel [list execsql $zSql]] concat [expr $::sqlite_found_count + $::sqlite_search_count] $res } do_test fkey2-15.1.1 { execsql { CREATE TABLE pp(a PRIMARY KEY, b); CREATE TABLE cc(x, y REFERENCES pp DEFERRABLE INITIALLY DEFERRED); INSERT INTO pp VALUES(1, 'one'); INSERT INTO pp VALUES(2, 'two'); INSERT INTO cc VALUES('neung', 1); INSERT INTO cc VALUES('song', 2); } } {} do_test fkey2-15.1.2 { execsqlS { INSERT INTO pp VALUES(3, 'three') } } {0} do_test fkey2-15.1.3 { execsql { BEGIN; INSERT INTO cc VALUES('see', 4); -- Violates deferred constraint } execsqlS { INSERT INTO pp VALUES(5, 'five') } } {2} do_test fkey2-15.1.4 { execsql { DELETE FROM cc WHERE x = 'see' } execsqlS { INSERT INTO pp VALUES(6, 'six') } } {0} do_test fkey2-15.1.5 { execsql COMMIT } {} do_test fkey2-15.1.6 { execsql BEGIN execsqlS { DELETE FROM cc WHERE x = 'neung'; ROLLBACK; } } {1} do_test fkey2-15.1.7 { execsql { BEGIN; DELETE FROM pp WHERE a = 2; } execsqlS { DELETE FROM cc WHERE x = 'neung'; ROLLBACK; } } {2} #------------------------------------------------------------------------- # This next block of tests, fkey2-16.*, test that rows that refer to # themselves may be inserted and deleted. # foreach {tn zSchema} { 1 { CREATE TABLE self(a INTEGER PRIMARY KEY, b REFERENCES self(a)) } 2 { CREATE TABLE self(a PRIMARY KEY, b REFERENCES self(a)) } 3 { CREATE TABLE self(a UNIQUE, b INTEGER PRIMARY KEY REFERENCES self(a)) } } { drop_all_tables do_test fkey2-16.1.$tn.1 { execsql $zSchema execsql { INSERT INTO self VALUES(13, 13) } } {} do_test fkey2-16.1.$tn.2 { execsql { UPDATE self SET a = 14, b = 14 } } {} do_test fkey2-16.1.$tn.3 { catchsql { UPDATE self SET b = 15 } } {1 {foreign key constraint failed}} do_test fkey2-16.1.$tn.4 { catchsql { UPDATE self SET a = 15 } } {1 {foreign key constraint failed}} do_test fkey2-16.1.$tn.5 { catchsql { UPDATE self SET a = 15, b = 16 } } {1 {foreign key constraint failed}} do_test fkey2-16.1.$tn.6 { catchsql { UPDATE self SET a = 17, b = 17 } } {0 {}} do_test fkey2-16.1.$tn.7 { execsql { DELETE FROM self } } {} do_test fkey2-16.1.$tn.8 { catchsql { INSERT INTO self VALUES(20, 21) } } {1 {foreign key constraint failed}} } #------------------------------------------------------------------------- # This next block of tests, fkey2-17.*, tests that if "PRAGMA count_changes" # is turned on statements that violate immediate FK constraints return # SQLITE_CONSTRAINT immediately, not after returning a number of rows. # Whereas statements that violate deferred FK constraints return the number # of rows before failing. # # Also test that rows modified by FK actions are not counted in either the # returned row count or the values returned by sqlite3_changes(). Like # trigger related changes, they are included in sqlite3_total_changes() though. # drop_all_tables do_test fkey2-17.1.1 { execsql { PRAGMA count_changes = 1 } execsql { CREATE TABLE one(a, b, c, UNIQUE(b, c)); CREATE TABLE two(d, e, f, FOREIGN KEY(e, f) REFERENCES one(b, c)); INSERT INTO one VALUES(1, 2, 3); } } {1} do_test fkey2-17.1.2 { set STMT [sqlite3_prepare_v2 db "INSERT INTO two VALUES(4, 5, 6)" -1 dummy] sqlite3_step $STMT } {SQLITE_CONSTRAINT} do_test fkey2-17.1.3 { sqlite3_step $STMT } {SQLITE_MISUSE} do_test fkey2-17.1.4 { sqlite3_finalize $STMT } {SQLITE_CONSTRAINT} do_test fkey2-17.1.5 { execsql { INSERT INTO one VALUES(2, 3, 4); INSERT INTO one VALUES(3, 4, 5); INSERT INTO two VALUES(1, 2, 3); INSERT INTO two VALUES(2, 3, 4); INSERT INTO two VALUES(3, 4, 5); } } {1 1 1 1 1} do_test fkey2-17.1.6 { catchsql { BEGIN; INSERT INTO one VALUES(0, 0, 0); UPDATE two SET e=e+1, f=f+1; } } {1 {foreign key constraint failed}} do_test fkey2-17.1.7 { execsql { SELECT * FROM one } } {1 2 3 2 3 4 3 4 5 0 0 0} do_test fkey2-17.1.8 { execsql { SELECT * FROM two } } {1 2 3 2 3 4 3 4 5} do_test fkey2-17.1.9 { execsql COMMIT } {} do_test fkey2-17.1.10 { execsql { CREATE TABLE three( g, h, i, FOREIGN KEY(h, i) REFERENCES one(b, c) DEFERRABLE INITIALLY DEFERRED ); } } {} do_test fkey2-17.1.11 { set STMT [sqlite3_prepare_v2 db "INSERT INTO three VALUES(7, 8, 9)" -1 dummy] sqlite3_step $STMT } {SQLITE_ROW} do_test fkey2-17.1.12 { sqlite3_column_text $STMT 0 } {1} do_test fkey2-17.1.13 { sqlite3_step $STMT } {SQLITE_CONSTRAINT} do_test fkey2-17.1.14 { sqlite3_finalize $STMT } {SQLITE_CONSTRAINT} drop_all_tables do_test fkey2-17.2.1 { execsql { CREATE TABLE high("a'b!" PRIMARY KEY, b); CREATE TABLE low( c, "d&6" REFERENCES high ON UPDATE CASCADE ON DELETE CASCADE ); } } {} do_test fkey2-17.2.2 { execsql { INSERT INTO high VALUES('a', 'b'); INSERT INTO low VALUES('b', 'a'); } db changes } {1} set nTotal [db total_changes] do_test fkey2-17.2.3 { execsql { UPDATE high SET "a'b!" = 'c' } } {1} do_test fkey2-17.2.4 { db changes } {1} do_test fkey2-17.2.5 { expr [db total_changes] - $nTotal } {2} do_test fkey2-17.2.6 { execsql { SELECT * FROM high ; SELECT * FROM low } } {c b b c} do_test fkey2-17.2.7 { execsql { DELETE FROM high } } {1} do_test fkey2-17.2.8 { db changes } {1} do_test fkey2-17.2.9 { expr [db total_changes] - $nTotal } {4} do_test fkey2-17.2.10 { execsql { SELECT * FROM high ; SELECT * FROM low } } {} execsql { PRAGMA count_changes = 0 } #------------------------------------------------------------------------- # Test that the authorization callback works. # ifcapable auth { do_test fkey2-18.1 { execsql { CREATE TABLE long(a, b PRIMARY KEY, c); CREATE TABLE short(d, e, f REFERENCES long); CREATE TABLE mid(g, h, i REFERENCES long DEFERRABLE INITIALLY DEFERRED); } } {} proc auth {args} {eval lappend ::authargs $args ; return SQLITE_OK} db auth auth # An insert on the parent table must read the child key of any deferred # foreign key constraints. But not the child key of immediate constraints. set authargs {} do_test fkey2-18.2 { execsql { INSERT INTO long VALUES(1, 2, 3) } set authargs } {SQLITE_INSERT long {} main {} SQLITE_READ mid i main {}} # An insert on the child table of an immediate constraint must read the # parent key columns (to see if it is a violation or not). set authargs {} do_test fkey2-18.3 { execsql { INSERT INTO short VALUES(1, 3, 2) } set authargs } {SQLITE_INSERT short {} main {} SQLITE_READ long b main {}} # As must an insert on the child table of a deferred constraint. set authargs {} do_test fkey2-18.4 { execsql { INSERT INTO mid VALUES(1, 3, 2) } set authargs } {SQLITE_INSERT mid {} main {} SQLITE_READ long b main {}} do_test fkey2-18.5 { execsql { CREATE TABLE nought(a, b PRIMARY KEY, c); CREATE TABLE cross(d, e, f, FOREIGN KEY(e) REFERENCES nought(b) ON UPDATE CASCADE ); } execsql { INSERT INTO nought VALUES(2, 1, 2) } execsql { INSERT INTO cross VALUES(0, 1, 0) } set authargs [list] execsql { UPDATE nought SET b = 5 } set authargs } {SQLITE_UPDATE nought b main {} SQLITE_READ cross e main {} SQLITE_READ cross e main {} SQLITE_READ nought b main {} SQLITE_READ nought b main {} SQLITE_READ nought b main {} SQLITE_UPDATE cross e main {} SQLITE_READ nought b main {} SQLITE_READ cross e main {} SQLITE_READ nought b main {} SQLITE_READ nought b main {}} do_test fkey2-18.6 { execsql {SELECT * FROM cross} } {0 5 0} do_test fkey2-18.7 { execsql { CREATE TABLE one(a INTEGER PRIMARY KEY, b); CREATE TABLE two(b, c REFERENCES one); INSERT INTO one VALUES(101, 102); } set authargs [list] execsql { INSERT INTO two VALUES(100, 101); } set authargs } {SQLITE_INSERT two {} main {} SQLITE_READ one a main {}} # Return SQLITE_IGNORE to requests to read from the parent table. This # causes inserts of non-NULL keys into the child table to fail. # rename auth {} proc auth {args} { if {[lindex $args 1] == "long"} {return SQLITE_IGNORE} return SQLITE_OK } do_test fkey2-18.8 { catchsql { INSERT INTO short VALUES(1, 3, 2) } } {1 {foreign key constraint failed}} do_test fkey2-18.9 { execsql { INSERT INTO short VALUES(1, 3, NULL) } } {} do_test fkey2-18.10 { execsql { SELECT * FROM short } } {1 3 2 1 3 {}} do_test fkey2-18.11 { catchsql { UPDATE short SET f = 2 WHERE f IS NULL } } {1 {foreign key constraint failed}} db auth {} unset authargs } #------------------------------------------------------------------------- # The following block of tests, those prefixed with "fkey2-genfkey.", are # the same tests that were used to test the ".genfkey" command provided # by the shell tool. So these tests show that the built-in foreign key # implementation is more or less compatible with the triggers generated # by genfkey. # drop_all_tables do_test fkey2-genfkey.1.1 { execsql { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, UNIQUE(b, c)); CREATE TABLE t2(e REFERENCES t1, f); CREATE TABLE t3(g, h, i, FOREIGN KEY (h, i) REFERENCES t1(b, c)); } } {} do_test fkey2-genfkey.1.2 { catchsql { INSERT INTO t2 VALUES(1, 2) } } {1 {foreign key constraint failed}} do_test fkey2-genfkey.1.3 { execsql { INSERT INTO t1 VALUES(1, 2, 3); INSERT INTO t2 VALUES(1, 2); } } {} do_test fkey2-genfkey.1.4 { execsql { INSERT INTO t2 VALUES(NULL, 3) } } {} do_test fkey2-genfkey.1.5 { catchsql { UPDATE t2 SET e = 5 WHERE e IS NULL } } {1 {foreign key constraint failed}} do_test fkey2-genfkey.1.6 { execsql { UPDATE t2 SET e = 1 WHERE e IS NULL } } {} do_test fkey2-genfkey.1.7 { execsql { UPDATE t2 SET e = NULL WHERE f = 3 } } {} do_test fkey2-genfkey.1.8 { catchsql { UPDATE t1 SET a = 10 } } {1 {foreign key constraint failed}} do_test fkey2-genfkey.1.9 { catchsql { UPDATE t1 SET a = NULL } } {1 {datatype mismatch}} do_test fkey2-genfkey.1.10 { catchsql { DELETE FROM t1 } } {1 {foreign key constraint failed}} do_test fkey2-genfkey.1.11 { execsql { UPDATE t2 SET e = NULL } } {} do_test fkey2-genfkey.1.12 { execsql { UPDATE t1 SET a = 10; DELETE FROM t1; DELETE FROM t2; } } {} do_test fkey2-genfkey.1.13 { execsql { INSERT INTO t3 VALUES(1, NULL, NULL); INSERT INTO t3 VALUES(1, 2, NULL); INSERT INTO t3 VALUES(1, NULL, 3); } } {} do_test fkey2-genfkey.1.14 { catchsql { INSERT INTO t3 VALUES(3, 1, 4) } } {1 {foreign key constraint failed}} do_test fkey2-genfkey.1.15 { execsql { INSERT INTO t1 VALUES(1, 1, 4); INSERT INTO t3 VALUES(3, 1, 4); } } {} do_test fkey2-genfkey.1.16 { catchsql { DELETE FROM t1 } } {1 {foreign key constraint failed}} do_test fkey2-genfkey.1.17 { catchsql { UPDATE t1 SET b = 10} } {1 {foreign key constraint failed}} do_test fkey2-genfkey.1.18 { execsql { UPDATE t1 SET a = 10} } {} do_test fkey2-genfkey.1.19 { catchsql { UPDATE t3 SET h = 'hello' WHERE i = 3} } {1 {foreign key constraint failed}} drop_all_tables do_test fkey2-genfkey.2.1 { execsql { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, UNIQUE(b, c)); CREATE TABLE t2(e REFERENCES t1 ON UPDATE CASCADE ON DELETE CASCADE, f); CREATE TABLE t3(g, h, i, FOREIGN KEY (h, i) REFERENCES t1(b, c) ON UPDATE CASCADE ON DELETE CASCADE ); } } {} do_test fkey2-genfkey.2.2 { execsql { INSERT INTO t1 VALUES(1, 2, 3); INSERT INTO t1 VALUES(4, 5, 6); INSERT INTO t2 VALUES(1, 'one'); INSERT INTO t2 VALUES(4, 'four'); } } {} do_test fkey2-genfkey.2.3 { execsql { UPDATE t1 SET a = 2 WHERE a = 1; SELECT * FROM t2; } } {2 one 4 four} do_test fkey2-genfkey.2.4 { execsql { DELETE FROM t1 WHERE a = 4; SELECT * FROM t2; } } {2 one} do_test fkey2-genfkey.2.5 { execsql { INSERT INTO t3 VALUES('hello', 2, 3); UPDATE t1 SET c = 2; SELECT * FROM t3; } } {hello 2 2} do_test fkey2-genfkey.2.6 { execsql { DELETE FROM t1; SELECT * FROM t3; } } {} drop_all_tables do_test fkey2-genfkey.3.1 { execsql { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, UNIQUE(c, b)); CREATE TABLE t2(e REFERENCES t1 ON UPDATE SET NULL ON DELETE SET NULL, f); CREATE TABLE t3(g, h, i, FOREIGN KEY (h, i) REFERENCES t1(b, c) ON UPDATE SET NULL ON DELETE SET NULL ); } } {} do_test fkey2-genfkey.3.2 { execsql { INSERT INTO t1 VALUES(1, 2, 3); INSERT INTO t1 VALUES(4, 5, 6); INSERT INTO t2 VALUES(1, 'one'); INSERT INTO t2 VALUES(4, 'four'); } } {} do_test fkey2-genfkey.3.3 { execsql { UPDATE t1 SET a = 2 WHERE a = 1; SELECT * FROM t2; } } {{} one 4 four} do_test fkey2-genfkey.3.4 { execsql { DELETE FROM t1 WHERE a = 4; SELECT * FROM t2; } } {{} one {} four} do_test fkey2-genfkey.3.5 { execsql { INSERT INTO t3 VALUES('hello', 2, 3); UPDATE t1 SET c = 2; SELECT * FROM t3; } } {hello {} {}} do_test fkey2-genfkey.3.6 { execsql { UPDATE t3 SET h = 2, i = 2; DELETE FROM t1; SELECT * FROM t3; } } {hello {} {}} finish_test |
Added test/fkey3.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 | # 2009 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. # # This file implements tests for foreign keys. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {!foreignkey||!trigger} { finish_test return } # Create a table and some data to work with. # do_test fkey3-1.1 { execsql { PRAGMA foreign_keys=ON; CREATE TABLE t1(x INTEGER PRIMARY KEY); INSERT INTO t1 VALUES(100); INSERT INTO t1 VALUES(101); CREATE TABLE t2(y INTEGER REFERENCES t1 (x)); INSERT INTO t2 VALUES(100); INSERT INTO t2 VALUES(101); SELECT 1, x FROM t1; SELECT 2, y FROM t2; } } {1 100 1 101 2 100 2 101} do_test fkey3-1.2 { catchsql { DELETE FROM t1 WHERE x=100; } } {1 {foreign key constraint failed}} do_test fkey3-1.3 { catchsql { DROP TABLE t1; } } {1 {foreign key constraint failed}} do_test fkey3-1.4 { execsql { DROP TABLE t2; } } {} do_test fkey3-1.5 { execsql { DROP TABLE t1; } } {} do_test fkey3-2.1 { execsql { PRAGMA foreign_keys=ON; CREATE TABLE t1(x INTEGER PRIMARY KEY); INSERT INTO t1 VALUES(100); INSERT INTO t1 VALUES(101); CREATE TABLE t2(y INTEGER PRIMARY KEY REFERENCES t1 (x) ON UPDATE SET NULL); } execsql { INSERT INTO t2 VALUES(100); INSERT INTO t2 VALUES(101); SELECT 1, x FROM t1; SELECT 2, y FROM t2; } } {1 100 1 101 2 100 2 101} finish_test |
Added test/fkey_malloc.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 | # 2009 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. # #*********************************************************************** # # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !foreignkey||!trigger { finish_test return } source $testdir/malloc_common.tcl do_malloc_test fkey_malloc-1 -sqlprep { PRAGMA foreign_keys = 1; CREATE TABLE t1(a PRIMARY KEY, b UNIQUE); CREATE TABLE t2(x REFERENCES t1 ON UPDATE CASCADE ON DELETE CASCADE); } -sqlbody { INSERT INTO t1 VALUES('aaa', 1); INSERT INTO t2 VALUES('aaa'); UPDATE t1 SET a = 'bbb'; DELETE FROM t1; } do_malloc_test fkey_malloc-2 -sqlprep { PRAGMA foreign_keys = 1; CREATE TABLE t1(a, b, UNIQUE(a, b)); } -sqlbody { CREATE TABLE t2(x, y, FOREIGN KEY(x, y) REFERENCES t1(a, b) DEFERRABLE INITIALLY DEFERRED ); BEGIN; INSERT INTO t2 VALUES('a', 'b'); INSERT INTO t1 VALUES('a', 'b'); UPDATE t1 SET a = 'c'; DELETE FROM t2; INSERT INTO t2 VALUES('d', 'b'); UPDATE t2 SET x = 'c'; COMMIT; } do_malloc_test fkey_malloc-3 -sqlprep { PRAGMA foreign_keys = 1; CREATE TABLE t1(x INTEGER PRIMARY KEY); CREATE TABLE t2(y DEFAULT 14 REFERENCES t1(x) ON UPDATE SET DEFAULT); CREATE TABLE t3(y REFERENCES t1 ON UPDATE SET NULL); INSERT INTO t1 VALUES(13); INSERT INTO t2 VALUES(13); INSERT INTO t3 VALUES(13); } -sqlbody { UPDATE t1 SET x = 14; } proc catch_fk_error {zSql} { set rc [catch {db eval $zSql} msg] if {$rc==0} { return $msg } if {[string match {*foreign key*} $msg]} { return "" } if {$msg eq "out of memory"} { error 1 } error $msg } do_malloc_test fkey_malloc-4 -sqlprep { PRAGMA foreign_keys = 1; CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE); CREATE TABLE t2(z REFERENCES t1(x), a REFERENCES t1(y)); CREATE TABLE t3(x); CREATE TABLE t4(z REFERENCES t3); CREATE TABLE t5(x, y); CREATE TABLE t6(z REFERENCES t5(x)); CREATE INDEX i51 ON t5(x); CREATE INDEX i52 ON t5(y, x); INSERT INTO t1 VALUES(1, 2); } -tclbody { catch_fk_error {INSERT INTO t2 VALUES(1, 3)} catch_fk_error {INSERT INTO t4 VALUES(2)} catch_fk_error {INSERT INTO t6 VALUES(2)} } do_malloc_test fkey_malloc-5 -sqlprep { PRAGMA foreign_keys = 1; CREATE TABLE t1(x, y, PRIMARY KEY(x, y)); CREATE TABLE t2(a, b, FOREIGN KEY(a, b) REFERENCES t1 ON UPDATE CASCADE); INSERT INTO t1 VALUES(1, 2); INSERT INTO t2 VALUES(1, 2); } -sqlbody { UPDATE t1 SET x = 5; } do_malloc_test fkey_malloc-6 -sqlprep { PRAGMA foreign_keys = 1; CREATE TABLE t1( x PRIMARY KEY, y REFERENCES t1 ON DELETE RESTRICT ON UPDATE SET DEFAULT ); INSERT INTO t1 VALUES('abc', 'abc'); INSERT INTO t1 VALUES('def', 'def'); } -sqlbody { INSERT INTO t1 VALUES('ghi', 'ghi'); DELETE FROM t1 WHERE rowid>1; UPDATE t1 SET x='jkl', y='jkl'; } do_malloc_test fkey_malloc-7 -sqlprep { PRAGMA foreign_keys = 1; CREATE TABLE x(a, b, PRIMARY KEY(a, b)); CREATE TABLE y(c, d, FOREIGN KEY(d, c) REFERENCES x DEFERRABLE INITIALLY DEFERRED ); CREATE TABLE z(e, f, FOREIGN KEY(e, f) REFERENCES x); } -sqlbody { DROP TABLE y; DROP TABLE x; } finish_test |
Changes to test/fts3expr.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2006 September 9 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #************************************************************************* # This file implements regression tests for SQLite library. The # focus of this script is testing the FTS3 module. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2006 September 9 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #************************************************************************* # This file implements regression tests for SQLite library. The # focus of this script is testing the FTS3 module. # # $Id: fts3expr.test,v 1.9 2009/07/28 16:44:26 danielk1977 Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts3 { |
︙ | ︙ | |||
118 119 120 121 122 123 124 | do_test fts3expr-1.11 { test_fts3expr {one two*} } {AND {PHRASE 3 0 one} {PHRASE 3 0 two+}} do_test fts3expr-1.14 { test_fts3expr {a:one two} } {AND {PHRASE 0 0 one} {PHRASE 3 0 two}} | | > > > | 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | do_test fts3expr-1.11 { test_fts3expr {one two*} } {AND {PHRASE 3 0 one} {PHRASE 3 0 two+}} do_test fts3expr-1.14 { test_fts3expr {a:one two} } {AND {PHRASE 0 0 one} {PHRASE 3 0 two}} do_test fts3expr-1.15.1 { test_fts3expr {one b:two} } {AND {PHRASE 3 0 one} {PHRASE 1 0 two}} do_test fts3expr-1.15.2 { test_fts3expr {one B:two} } {AND {PHRASE 3 0 one} {PHRASE 1 0 two}} do_test fts3expr-1.16 { test_fts3expr {one AND two AND three AND four AND five} } [list AND \ [list AND \ [list AND \ [list AND {PHRASE 3 0 one} {PHRASE 3 0 two}] \ |
︙ | ︙ | |||
459 460 461 462 463 464 465 | 11 "one two OR four five NOT three" {3 7 11 15 19 23 24 25 26 27 31} 12 "(one two OR four five) NOT three" {3 11 19 24 25 26 27} 13 "((((((one two OR four five)))))) NOT three" {3 11 19 24 25 26 27} } { | | > > > > > > > > > > > > > > > > | 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 | 11 "one two OR four five NOT three" {3 7 11 15 19 23 24 25 26 27 31} 12 "(one two OR four five) NOT three" {3 11 19 24 25 26 27} 13 "((((((one two OR four five)))))) NOT three" {3 11 19 24 25 26 27} } { do_test fts3expr-6.1.$id { execsql { SELECT rowid FROM t1 WHERE t1 MATCH $expr ORDER BY rowid } } $res } set sqlite_fts3_enable_parentheses 0 foreach {id expr res} { 1 "one -two three" {5 13 21 29} 2 "-two one three" {5 13 21 29} 3 "one three -two" {5 13 21 29} 4 "-one -two three" {4 12 20 28} 5 "three -one -two" {4 12 20 28} 6 "-one three -two" {4 12 20 28} } { do_test fts3expr-6.2.$id { execsql { SELECT rowid FROM t1 WHERE t1 MATCH $expr ORDER BY rowid } } $res } set sqlite_fts3_enable_parentheses 1 do_test fts3expr-7.1 { execsql { CREATE VIRTUAL TABLE test USING fts3 (keyword); INSERT INTO test VALUES ('abc'); SELECT * FROM test WHERE keyword MATCH '""'; } } {} set sqlite_fts3_enable_parentheses 0 finish_test |
Changes to test/func.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2001 September 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing built-in functions. # | < | 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 built-in functions. # set testdir [file dirname $argv0] source $testdir/tester.tcl # Create a table to work with. # do_test func-0.0 { |
︙ | ︙ | |||
1153 1154 1155 1156 1157 1158 1159 1160 | do_test func-27.2 { catchsql {SELECT coalesce(1)} } {1 {wrong number of arguments to function coalesce()}} do_test func-27.3 { catchsql {SELECT coalesce(1,2)} } {0 1} finish_test | > > > > > > > > > > > > | 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 | do_test func-27.2 { catchsql {SELECT coalesce(1)} } {1 {wrong number of arguments to function coalesce()}} do_test func-27.3 { catchsql {SELECT coalesce(1,2)} } {0 1} # Ticket 2d401a94287b5 # Unknown function in a DEFAULT expression causes a segfault. # do_test func-28.1 { db eval { CREATE TABLE t28(x, y DEFAULT(nosuchfunc(1))); } catchsql { INSERT INTO t28(x) VALUES(1); } } {1 {unknown function: nosuchfunc()}} finish_test |
Changes to test/icu.test.
︙ | ︙ | |||
22 23 24 25 26 27 28 | # Create a table to work with. # execsql {CREATE TABLE test1(i1 int, i2 int, r1 real, r2 real, t1 text, t2 text)} execsql {INSERT INTO test1 VALUES(1,2,1.1,2.2,'hello','world')} proc test_expr {name settings expr result} { do_test $name [format { | | | | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | # Create a table to work with. # execsql {CREATE TABLE test1(i1 int, i2 int, r1 real, r2 real, t1 text, t2 text)} execsql {INSERT INTO test1 VALUES(1,2,1.1,2.2,'hello','world')} proc test_expr {name settings expr result} { do_test $name [format { lindex [db eval { BEGIN; UPDATE test1 SET %s; SELECT %s FROM test1; ROLLBACK; }] 0 } $settings $expr] $result } # Tests of the REGEXP operator. # test_expr icu-1.1 {i1='hello'} {i1 REGEXP 'hello'} 1 test_expr icu-1.2 {i1='hello'} {i1 REGEXP '.ello'} 1 |
︙ | ︙ |
Changes to test/incrblob.test.
︙ | ︙ | |||
305 306 307 308 309 310 311 | do_test incrblob-4.7 { set rc [catch { set ::blob [db incrblob blobs i 2] } msg ] list $rc $msg } {1 {cannot open value of type null}} | | > > > > > > > > > > > > > > > > | 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 | do_test incrblob-4.7 { set rc [catch { set ::blob [db incrblob blobs i 2] } msg ] list $rc $msg } {1 {cannot open value of type null}} do_test incrblob-4.8.1 { execsql { INSERT INTO blobs(k, v, i) VALUES(X'010203040506070809', 'hello', 'world'); } set rc [catch { set ::blob [db incrblob blobs k 3] } msg ] list $rc $msg } {1 {cannot open indexed column for writing}} do_test incrblob-4.8.2 { execsql { CREATE TABLE t3(a INTEGER PRIMARY KEY, b); INSERT INTO t3 VALUES(1, 2); } set rc [catch { set ::blob [db incrblob -readonly t3 a 1] } msg ] list $rc $msg } {1 {cannot open value of type null}} do_test incrblob-4.8.3 { set rc [catch { set ::blob [db incrblob -readonly t3 rowid 1] } msg ] list $rc $msg } {1 {no such column: "rowid"}} do_test incrblob-4.9.1 { set rc [catch { set ::blob [db incrblob -readonly blobs k 3] } msg] } {0} do_test incrblob-4.9.2 { |
︙ | ︙ |
Changes to test/incrblob2.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # May you share freely, never taking more than you give. # #*********************************************************************** # # Test that it is possible to have two open blob handles on a single # blob object. # | | | 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. # #*********************************************************************** # # Test that it is possible to have two open blob handles on a single # blob object. # # $Id: incrblob2.test,v 1.11 2009/06/29 06:00:37 danielk1977 Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {!autovacuum || !pragma || !incrblob} { finish_test |
︙ | ︙ | |||
270 271 272 273 274 275 276 | do_test incrblob2-5.4 { close $blob execsql BEGIN db2 catchsql { INSERT INTO t1 VALUES(4, 'pqrst') } db2 } {0 {}} do_test incrblob2-5.5 { | | | | > > | > > > > > > > | 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 | do_test incrblob2-5.4 { close $blob execsql BEGIN db2 catchsql { INSERT INTO t1 VALUES(4, 'pqrst') } db2 } {0 {}} do_test incrblob2-5.5 { set rc [catch { db incrblob -readonly t1 data 1 } msg] list $rc $msg } {1 {database table is locked: t1}} do_test incrblob2-5.6 { execsql { PRAGMA read_uncommitted=1 } set blob [db incrblob -readonly t1 data 4] read $blob } {pqrst} do_test incrblob2-5.7 { catchsql { INSERT INTO t1 VALUES(3, 'klmno') } db2 } {0 {}} do_test incrblob2-5.8 { close $blob } {} db2 close db close sqlite3_enable_shared_cache $::enable_shared_cache } #-------------------------------------------------------------------------- |
︙ | ︙ |
Changes to test/incrvacuum2.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2007 May 04 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you 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 incremental vacuum feature. # | | < < < < < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | # 2007 May 04 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you 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 incremental vacuum feature. # # $Id: incrvacuum2.test,v 1.6 2009/07/25 13:42:50 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} { finish_test return } # Create a database in incremental vacuum mode that has many # pages on the freelist. # do_test incrvacuum2-1.1 { execsql { PRAGMA page_size=1024; |
︙ | ︙ |
Added test/init.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 | # 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 effects of a failure in # sqlite3_initialize(). # # set testdir [file dirname $argv0] source $testdir/tester.tcl db close foreach {t failed rc started} { 1.1 {} SQLITE_OK {mutex mem pcache} 1.2 {mutex} SQLITE_ERROR {} 1.3 {mem} SQLITE_ERROR {mutex} 1.4 {pcache} SQLITE_ERROR {mutex mem} } { do_test init-$t.1 { eval init_wrapper_install $failed sqlite3_initialize } $rc do_test init-$t.2 { init_wrapper_query } $started do_test init-$t.3 { sqlite3_shutdown init_wrapper_query } {} do_test init-$t.4 { sqlite3_initialize } $rc do_test init-$t.5 { init_wrapper_query } $started do_test init-$t.6 { init_wrapper_clear sqlite3_initialize } SQLITE_OK do_test init-$t.7 { init_wrapper_query } {mutex mem pcache} do_test init-$t.8 { init_wrapper_uninstall } {} } source $testdir/malloc_common.tcl if {$MEMDEBUG} { do_malloc_test init-2 -tclprep { db close init_wrapper_install } -tclbody { set rc [sqlite3_initialize] if {[string match "SQLITE*NOMEM" $rc]} {error "out of memory"} } -cleanup { set zRepeat "transient" if {$::iRepeat} {set zRepeat "persistent"} do_test init-2.$zRepeat.$::n.x { init_wrapper_clear sqlite3_initialize } SQLITE_OK init_wrapper_uninstall } } autoinstall_test_functions finish_test |
Added test/intarray.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 | # 2009 November 10 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests for the "intarray" object implemented # in test_intarray.c. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !vtab { return } do_test intarray-1.0 { db eval { CREATE TABLE t1(a INTEGER PRIMARY KEY, b); } for {set i 1} {$i<=999} {incr i} { set b [format {x%03d} $i] db eval {INSERT INTO t1(a,b) VALUES($i,$b)} } db eval { CREATE TABLE t2(x INTEGER PRIMARY KEY, y); INSERT INTO t2 SELECT * FROM t1; SELECT b FROM t1 WHERE a IN (12,34,56,78) ORDER BY a } } {x012 x034 x056 x078} do_test intarray-1.1 { set ia1 [sqlite3_intarray_create db ia1] set ia2 [sqlite3_intarray_create db ia2] set ia3 [sqlite3_intarray_create db ia3] set ia4 [sqlite3_intarray_create db ia4] db eval { SELECT type, name FROM sqlite_temp_master ORDER BY name } } {table ia1 table ia2 table ia3 table ia4} do_test intarray-1.2 { db eval { SELECT b FROM t1 WHERE a IN ia3 ORDER BY a } } {} do_test intarray-1.3 { sqlite3_intarray_bind $ia3 45 123 678 db eval { SELECT b FROM t1 WHERE a IN ia3 ORDER BY a } } {x045 x123 x678} do_test intarray-1.4 { db eval { SELECT count(b) FROM t1 WHERE a NOT IN ia3 ORDER BY a } } {996} #explain {SELECT b FROM t1 WHERE a NOT IN ia3} do_test intarray-1.5 { set cmd sqlite3_intarray_bind lappend cmd $ia1 for {set i 1} {$i<=999} {incr i} { lappend cmd $i lappend cmd [expr {$i+1000}] lappend cmd [expr {$i+2000}] } eval $cmd db eval { REPLACE INTO t1 SELECT * FROM t2; DELETE FROM t1 WHERE a NOT IN ia1; SELECT count(*) FROM t1; } } {999} do_test intarray-1.6 { db eval { DELETE FROM t1 WHERE a IN ia1; SELECT count(*) FROM t1; } } {0} do_test intarray-2.1 { db eval { CREATE TEMP TABLE t3(p,q); INSERT INTO t3 SELECT * FROM t2; SELECT count(*) FROM t3 WHERE p IN ia1; } } {999} do_test intarray-2.2 { set ia5 [sqlite3_intarray_create db ia5] db eval { SELECT count(*) FROM t3 WHERE p IN ia1; } } {999} finish_test |
Changes to test/io.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # # The focus of this file is testing some specific characteristics of the # IO traffic generated by SQLite (making sure SQLite is not writing out # more database pages than it has to, stuff like that). # | < | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # #*********************************************************************** # # The focus of this file is testing some specific characteristics of the # IO traffic generated by SQLite (making sure SQLite is not writing out # more database pages than it has to, stuff like that). # set testdir [file dirname $argv0] source $testdir/tester.tcl db close sqlite3_simulate_device sqlite3 db test.db -vfs devsym |
︙ | ︙ | |||
421 422 423 424 425 426 427 428 | # 1) The directory in which the journal file is created, (unix only) # 2) The journal file (to sync the page data), # 3) The database file. # # Normally, when the SAFE_APPEND flag is not set, there is another fsync() # on the journal file between steps (2) and (3) above. # if {$::tcl_platform(platform)=="unix"} { | > | < | | > > | 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 | # 1) The directory in which the journal file is created, (unix only) # 2) The journal file (to sync the page data), # 3) The database file. # # Normally, when the SAFE_APPEND flag is not set, there is another fsync() # on the journal file between steps (2) and (3) above. # set expected_sync_count 2 if {$::tcl_platform(platform)=="unix"} { ifcapable dirsync { incr expected_sync_count } } do_test io-4.1 { execsql { DELETE FROM abc } nSync execsql { INSERT INTO abc VALUES('a', 'b') } nSync } $expected_sync_count |
︙ | ︙ |
Changes to test/join.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. # # This file implements tests for joins, including outer joins. # | | | 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. # # This file implements tests for joins, including outer joins. # # $Id: join.test,v 1.27 2009/07/01 16:12:08 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl do_test join-1.1 { execsql { CREATE TABLE t1(a,b,c); |
︙ | ︙ | |||
305 306 307 308 309 310 311 | } {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 { | < | < | | 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 | } {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 { |
︙ | ︙ | |||
573 574 575 576 577 578 579 580 581 | do_test join-10.3 { execsql { SELECT * FROM t23 LEFT JOIN (SELECT * FROM t24); } } {1 2 3 {} {} {}} } ;# ifcapable subquery finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_test join-10.3 { execsql { SELECT * FROM t23 LEFT JOIN (SELECT * FROM t24); } } {1 2 3 {} {} {}} } ;# ifcapable subquery #------------------------------------------------------------------------- # The following tests are to ensure that bug b73fb0bd64 is fixed. # do_test join-11.1 { drop_all_tables execsql { CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT); CREATE TABLE t2(a INTEGER PRIMARY KEY, b TEXT); INSERT INTO t1 VALUES(1,'abc'); INSERT INTO t1 VALUES(2,'def'); INSERT INTO t2 VALUES(1,'abc'); INSERT INTO t2 VALUES(2,'def'); SELECT * FROM t1 NATURAL JOIN t2; } } {1 abc 2 def} do_test join-11.2 { execsql { SELECT a FROM t1 JOIN t1 USING (a)} } {1 2} do_test join-11.3 { execsql { SELECT a FROM t1 JOIN t1 AS t2 USING (a)} } {1 2} do_test join-11.3 { execsql { SELECT * FROM t1 NATURAL JOIN t1 AS t2} } {1 abc 2 def} do_test join-11.4 { execsql { SELECT * FROM t1 NATURAL JOIN t1 } } {1 abc 2 def} do_test join-11.5 { drop_all_tables execsql { CREATE TABLE t1(a COLLATE nocase, b); CREATE TABLE t2(a, b); INSERT INTO t1 VALUES('ONE', 1); INSERT INTO t1 VALUES('two', 2); INSERT INTO t2 VALUES('one', 1); INSERT INTO t2 VALUES('two', 2); } } {} do_test join-11.6 { execsql { SELECT * FROM t1 NATURAL JOIN t2 } } {ONE 1 two 2} do_test join-11.7 { execsql { SELECT * FROM t2 NATURAL JOIN t1 } } {two 2} do_test join-11.8 { drop_all_tables execsql { CREATE TABLE t1(a, b TEXT); CREATE TABLE t2(b INTEGER, a); INSERT INTO t1 VALUES('one', '1.0'); INSERT INTO t1 VALUES('two', '2'); INSERT INTO t2 VALUES(1, 'one'); INSERT INTO t2 VALUES(2, 'two'); } } {} do_test join-11.9 { execsql { SELECT * FROM t1 NATURAL JOIN t2 } } {one 1.0 two 2} do_test join-11.10 { execsql { SELECT * FROM t2 NATURAL JOIN t1 } } {1 one 2 two} finish_test |
Added test/lock7.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 | # 2009 August 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. # #*********************************************************************** # # Check that reading the database schema from within an active transaction # does not establish a SHARED lock on the database file if one is not # already held (or, more accurately, that the SHARED lock is released after # reading the database schema). # set testdir [file dirname $argv0] source $testdir/tester.tcl do_test lock7-1.1 { execsql { CREATE TABLE t1(a, b) } db close sqlite3 db1 test.db sqlite3 db2 test.db db1 eval {BEGIN} db2 eval {BEGIN} } {} do_test lock7-1.2 { execsql { PRAGMA lock_status } db1 } {main unlocked temp closed} do_test lock7-1.3 { execsql { PRAGMA lock_status } db2 } {main unlocked temp closed} do_test lock7-1.4 { catchsql { INSERT INTO t1 VALUES(1, 1) } db1 } {0 {}} do_test lock7-1.5 { catchsql { INSERT INTO t1 VALUES(2, 2) } db2 } {1 {database is locked}} do_test lock7-1.6 { execsql { PRAGMA lock_status } db1 } {main reserved temp closed} do_test lock7-1.7 { execsql { PRAGMA lock_status } db2 } {main unlocked temp closed} do_test lock7-1.8 { execsql { COMMIT } db1 } {} db1 close db2 close finish_test |
Changes to test/malloc.test.
︙ | ︙ | |||
861 862 863 864 865 866 867 868 869 870 871 872 873 874 | do_test malloc-36.$zRepeat.${::n}.unlocked { execsql {INSERT INTO t1 VALUES(3, 4)} db2 } {} db2 close } catch { db2 close } } # Ensure that no file descriptors were leaked. do_test malloc-99.X { catch {db close} set sqlite_open_file_count } {0} | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_test malloc-36.$zRepeat.${::n}.unlocked { execsql {INSERT INTO t1 VALUES(3, 4)} db2 } {} db2 close } catch { db2 close } } ifcapable stat2 { do_malloc_test 38 -tclprep { add_test_collate db 0 0 1 execsql { ANALYZE; CREATE TABLE t4(x COLLATE test_collate); CREATE INDEX t4x ON t4(x); INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 0, 'aaa'); INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 1, 'aaa'); INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 2, 'aaa'); INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 3, 'aaa'); INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 4, 'aaa'); INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 5, 'aaa'); INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 6, 'aaa'); INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 7, 'aaa'); INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 8, 'aaa'); INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 9, 'aaa'); } db close sqlite3 db test.db sqlite3_db_config_lookaside db 0 0 0 add_test_collate db 0 0 1 } -sqlbody { SELECT * FROM t4 AS t41, t4 AS t42 WHERE t41.x>'ddd' AND t42.x>'ccc' } } # Ensure that no file descriptors were leaked. do_test malloc-99.X { catch {db close} set sqlite_open_file_count } {0} |
︙ | ︙ |
Changes to test/mallocI.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2008 August 01 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # This test script checks malloc failures in various obscure operations. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2008 August 01 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # This test script checks malloc failures in various obscure operations. # # $Id: mallocI.test,v 1.3 2009/08/10 04:26:39 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/malloc_common.tcl # Malloc failures in a view. # |
︙ | ︙ | |||
35 36 37 38 39 40 41 42 43 | # Malloc failure while creating a table from a SELECT statement. # do_malloc_test mallocI-3 -sqlprep { CREATE TABLE t1(a,b,c); } -sqlbody { CREATE TABLE t2 AS SELECT b,c FROM t1; } finish_test | > > > > > > > > > > > > > > > > > > > > | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | # Malloc failure while creating a table from a SELECT statement. # do_malloc_test mallocI-3 -sqlprep { CREATE TABLE t1(a,b,c); } -sqlbody { CREATE TABLE t2 AS SELECT b,c FROM t1; } # This tests that a malloc failure that occurs while passing the schema # does not result in a SHARED lock being left on the database file. # do_malloc_test mallocI-4 -tclprep { sqlite3 db2 test.db db2 eval { CREATE TABLE t1(a, b, c); CREATE TABLE t2(a, b, c); } } -sqlbody { SELECT * FROM t1 } -cleanup { do_test mallocI-4.$::n.2 { # If this INSERT is possible then [db] does not hold a shared lock # on the database file. catchsql { INSERT INTO t1 VALUES(1, 2, 3) } db2 } {0 {}} } catch { db2 close } finish_test |
Changes to test/memsubsys1.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2008 June 18 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # This file contains tests of the memory allocation subsystem # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2008 June 18 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # This file contains tests of the memory allocation subsystem # # $Id: memsubsys1.test,v 1.17 2009/07/18 14:36:24 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl sqlite3_reset_auto_extension # This procedure constructs a new database in test.db. It fills # this database with many small records (enough to force multiple |
︙ | ︙ |
Changes to test/misc2.test.
︙ | ︙ | |||
14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # left out of other test files. # # $Id: misc2.test,v 1.28 2007/09/12 17:01:45 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {trigger} { # Test for ticket #360 # do_test misc2-1.1 { catchsql { CREATE TABLE FOO(bar integer); CREATE TRIGGER foo_insert BEFORE INSERT ON foo BEGIN | > > > > > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | # left out of other test files. # # $Id: misc2.test,v 1.28 2007/09/12 17:01:45 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # The tests in this file were written before SQLite supported recursive # trigger invocation, and some tests depend on that to pass. So disable # recursive triggers for this file. catchsql { pragma recursive_triggers = off } ifcapable {trigger} { # Test for ticket #360 # do_test misc2-1.1 { catchsql { CREATE TABLE FOO(bar integer); CREATE TRIGGER foo_insert BEFORE INSERT ON foo BEGIN |
︙ | ︙ | |||
354 355 356 357 358 359 360 361 362 363 364 365 366 367 | execsql {SELECT * FROM t1} } {1 2 3 4 5 6 7 8 9 10} } db close file delete -force test.db sqlite3 db test.db # Ticket #453. If the SQL ended with "-", the tokenizer was calling that # an incomplete token, which caused problem. The solution was to just call # it a minus sign. # do_test misc2-8.1 { catchsql {-} | > | 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 | execsql {SELECT * FROM t1} } {1 2 3 4 5 6 7 8 9 10} } db close file delete -force test.db sqlite3 db test.db catchsql { pragma recursive_triggers = off } # Ticket #453. If the SQL ended with "-", the tokenizer was calling that # an incomplete token, which caused problem. The solution was to just call # it a minus sign. # do_test misc2-8.1 { catchsql {-} |
︙ | ︙ |
Changes to test/misc7.test.
1 2 3 4 5 6 7 8 9 10 11 12 | # 2006 September 4 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # 2006 September 4 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. # # $Id: misc7.test,v 1.29 2009/07/16 18:21:18 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl do_test misc7-1-misuse { c_misuse_test } {} |
︙ | ︙ | |||
362 363 364 365 366 367 368 | do_test misc7-16.X { execsql { SELECT count(*) FROM t3; } } {32} | < < < < < < < < < < | 362 363 364 365 366 367 368 369 370 371 372 373 374 375 | do_test misc7-16.X { execsql { SELECT count(*) FROM t3; } } {32} #---------------------------------------------------------------------- # Test the situation where a hot-journal is discovered but write-access # to it is denied. This should return SQLITE_BUSY. # # These tests do not work on windows due to restrictions in the # windows file system. # |
︙ | ︙ |
Changes to test/nan.test.
︙ | ︙ | |||
309 310 311 312 313 314 315 | } {-9.88131291682493e-324 real} do_test nan-4.20 { db eval {DELETE FROM t1} set big [string repeat 9 10000].0e-9000 db eval "INSERT INTO t1 VALUES($big)" db eval {SELECT x, typeof(x) FROM t1} | | | 309 310 311 312 313 314 315 316 317 318 319 320 | } {-9.88131291682493e-324 real} do_test nan-4.20 { db eval {DELETE FROM t1} set big [string repeat 9 10000].0e-9000 db eval "INSERT INTO t1 VALUES($big)" db eval {SELECT x, typeof(x) FROM t1} } {inf real} finish_test |
Changes to test/notnull.test.
︙ | ︙ | |||
497 498 499 500 501 502 503 504 505 | catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); UPDATE t1 SET e=null, a=b, b=a; SELECT * FROM t1 ORDER BY a; } } {1 {t1.e may not be NULL}} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); UPDATE t1 SET e=null, a=b, b=a; SELECT * FROM t1 ORDER BY a; } } {1 {t1.e may not be NULL}} # Test that bug 29ab7be99f is fixed. # do_test notnull-5.1 { execsql { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a, b NOT NULL); CREATE TABLE t2(c, d); INSERT INTO t2 VALUES(3, 4); INSERT INTO t2 VALUES(5, NULL); } } {} do_test notnull-5.2 { catchsql { INSERT INTO t1 VALUES(1, 2); INSERT INTO t1 SELECT * FROM t2; } } {1 {t1.b may not be NULL}} do_test notnull-5.3 { execsql { SELECT * FROM t1 } } {1 2} do_test notnull-5.4 { catchsql { DELETE FROM t1; BEGIN; INSERT INTO t1 VALUES(1, 2); INSERT INTO t1 SELECT * FROM t2; COMMIT; } } {1 {t1.b may not be NULL}} do_test notnull-5.5 { execsql { SELECT * FROM t1 } } {1 2} finish_test |
Deleted test/pager.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/pager2.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Deleted test/pager3.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to test/pcache2.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2008 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 is focused on testing the pcache module. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2008 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 is focused on testing the pcache module. # # $Id: pcache2.test,v 1.5 2009/07/18 14:36:24 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Set up a pcache memory pool so that we can easily track how many # pages are being used for cache. |
︙ | ︙ | |||
41 42 43 44 45 46 47 48 49 50 51 52 53 54 | } {2} do_test pcache2-1.3 { file delete -force test2.db test2.db-journal sqlite3 db2 test2.db db2 eval {PRAGMA cache_size=50} lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 1 } {4} # Make lots of changes on the first connection. Verify that the # page cache usage does not grow to consume the page space set aside # for the second connection. # do_test pcache2-1.4 { db eval { | > | 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | } {2} do_test pcache2-1.3 { file delete -force test2.db test2.db-journal sqlite3 db2 test2.db db2 eval {PRAGMA cache_size=50} lindex [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] 1 } {4} # Make lots of changes on the first connection. Verify that the # page cache usage does not grow to consume the page space set aside # for the second connection. # do_test pcache2-1.4 { db eval { |
︙ | ︙ |
Changes to test/permutations.test.
1 2 3 4 5 6 7 8 9 10 11 | # 2008 June 21 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # 2008 June 21 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # $Id: permutations.test,v 1.51 2009/07/01 18:09:02 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Argument processing. # #puts "PERM-DEBUG: argv=$argv" |
︙ | ︙ | |||
479 480 481 482 483 484 485 | Run tests using the allocator in mem3.c. } -exclude { autovacuum.test delete3.test manydb.test bigrow.test incrblob2.test memdb.test bitvec.test index2.test memsubsys1.test capi3c.test ioerr.test memsubsys2.test capi3.test join3.test pagesize.test | | > > > > > > > > | 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 | Run tests using the allocator in mem3.c. } -exclude { autovacuum.test delete3.test manydb.test bigrow.test incrblob2.test memdb.test bitvec.test index2.test memsubsys1.test capi3c.test ioerr.test memsubsys2.test capi3.test join3.test pagesize.test collate5.test limit.test backup_ioerr.test backup_malloc.test } -initialize { catch {db close} sqlite3_reset_auto_extension sqlite3_shutdown sqlite3_config_heap 25000000 0 sqlite3_config_lookaside 0 0 ifcapable mem5 { # If both memsys3 and memsys5 are enabled in the build, the call to # [sqlite3_config_heap] will initialize the system to use memsys5. # The following overrides this preference and installs the memsys3 # allocator. sqlite3_install_memsys3 } install_malloc_faultsim 1 sqlite3_initialize autoinstall_test_functions } -shutdown { catch {db close} sqlite3_shutdown sqlite3_config_heap 0 0 |
︙ | ︙ |
Changes to test/pragma.test.
︙ | ︙ | |||
529 530 531 532 533 534 535 | db nullvalue {} ifcapable {foreignkey} { do_test pragma-6.3.1 { execsql { CREATE TABLE t3(a int references t2(b), b UNIQUE); pragma foreign_key_list(t3); } | | | 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 | db nullvalue {} ifcapable {foreignkey} { do_test pragma-6.3.1 { execsql { CREATE TABLE t3(a int references t2(b), b UNIQUE); pragma foreign_key_list(t3); } } {0 0 t2 a b {NO ACTION} {NO ACTION} NONE} do_test pragma-6.3.2 { execsql { pragma foreign_key_list; } } {} do_test pragma-6.3.3 { execsql { |
︙ | ︙ |
Changes to test/quick.test.
︙ | ︙ | |||
54 55 56 57 58 59 60 61 62 63 64 65 66 67 | crash3.test crash4.test crash5.test crash6.test crash7.test delete3.test fts3.test fuzz.test fuzz3.test fuzz_malloc.test in2.test loadext.test memleak.test misc7.test | > | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | crash3.test crash4.test crash5.test crash6.test crash7.test delete3.test fts3.test fkey_malloc.test fuzz.test fuzz3.test fuzz_malloc.test in2.test loadext.test memleak.test misc7.test |
︙ | ︙ |
Changes to test/savepoint.test.
1 2 3 4 5 6 7 8 9 10 11 | # 2008 December 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. # #*********************************************************************** # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # 2008 December 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. # #*********************************************************************** # # $Id: savepoint.test,v 1.13 2009/07/18 08:30:45 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl #---------------------------------------------------------------------- # The following tests - savepoint-1.* - test that the SAVEPOINT, RELEASE |
︙ | ︙ | |||
265 266 267 268 269 270 271 | execsql COMMIT } {} #------------------------------------------------------------------------ # Test some logic errors to do with the savepoint feature. # | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | 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 | execsql COMMIT } {} #------------------------------------------------------------------------ # Test some logic errors to do with the savepoint feature. # ifcapable incrblob { do_test savepoint-5.1.1 { execsql { CREATE TABLE blobs(x); INSERT INTO blobs VALUES('a twentyeight character blob'); } set fd [db incrblob blobs x 1] puts -nonewline $fd "hello" catchsql {SAVEPOINT abc} } {1 {cannot open savepoint - SQL statements in progress}} do_test savepoint-5.1.2 { close $fd catchsql {SAVEPOINT abc} } {0 {}} do_test savepoint-5.2 { execsql {RELEASE abc} catchsql {RELEASE abc} } {1 {no such savepoint: abc}} do_test savepoint-5.3.1 { execsql {SAVEPOINT abc} catchsql {ROLLBACK TO def} } {1 {no such savepoint: def}} do_test savepoint-5.3.2 { execsql {SAVEPOINT def} set fd [db incrblob -readonly blobs x 1] catchsql {ROLLBACK TO def} } {1 {cannot rollback savepoint - SQL statements in progress}} do_test savepoint-5.3.3 { catchsql {RELEASE def} } {0 {}} do_test savepoint-5.3.4 { close $fd execsql {savepoint def} set fd [db incrblob blobs x 1] catchsql {release def} } {1 {cannot release savepoint - SQL statements in progress}} do_test savepoint-5.3.5 { close $fd execsql {release abc} } {} do_test savepoint-5.4.1 { execsql { SAVEPOINT main; INSERT INTO blobs VALUES('another blob'); } } {} do_test savepoint-5.4.2 { sqlite3 db2 test.db execsql { BEGIN ; SELECT * FROM blobs } db2 catchsql { RELEASE main } } {1 {database is locked}} do_test savepoint-5.4.3 { db2 close catchsql { RELEASE main } } {0 {}} do_test savepoint-5.4.4 { execsql { SELECT x FROM blobs WHERE rowid = 2 } } {{another blob}} } #------------------------------------------------------------------------- # The following tests, savepoint-6.*, test an incr-vacuum inside of a # couple of nested savepoints. # ifcapable {autovacuum && pragma} { db close |
︙ | ︙ |
Changes to test/schema.test.
︙ | ︙ | |||
359 360 361 362 363 364 365 366 367 | # The schema cookie now has the same value as it did when SQL statement # $::STMT was prepared. So unless it has been expired, it would be # possible to run the "CREATE TABLE t4" statement and create a # duplicate table. list [sqlite3_step $::STMT] [sqlite3_finalize $::STMT] } {SQLITE_ERROR SQLITE_SCHEMA} finish_test | > > > > > > > > > > > > > > > > > > > > | 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 | # The schema cookie now has the same value as it did when SQL statement # $::STMT was prepared. So unless it has been expired, it would be # possible to run the "CREATE TABLE t4" statement and create a # duplicate table. list [sqlite3_step $::STMT] [sqlite3_finalize $::STMT] } {SQLITE_ERROR SQLITE_SCHEMA} do_test schema-13.1 { set S [sqlite3_prepare_v2 db "SELECT * FROM sqlite_master" -1 dummy] db function hello hello db function hello {} db auth auth proc auth {args} { if {[lindex $args 0] == "SQLITE_READ"} {return SQLITE_DENY} return SQLITE_OK } sqlite3_step $S } {SQLITE_SCHEMA} do_test schema-13.2 { sqlite3_step $S } {SQLITE_SCHEMA} do_test schema-13.3 { sqlite3_finalize $S } {SQLITE_SCHEMA} finish_test |
Changes to test/selectC.test.
︙ | ︙ | |||
147 148 149 150 151 152 153 | FROM t1 ORDER BY x DESC } } {CCC AAA AAA} # The following query used to leak memory. Verify that has been fixed. # | > | | | | | | | | | | | | > | 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | FROM t1 ORDER BY x DESC } } {CCC AAA AAA} # The following query used to leak memory. Verify that has been fixed. # ifcapable trigger { do_test selectC-2.1 { catchsql { CREATE TABLE t21a(a,b); INSERT INTO t21a VALUES(1,2); CREATE TABLE t21b(n); CREATE TRIGGER r21 AFTER INSERT ON t21b BEGIN SELECT a FROM t21a WHERE a>new.x UNION ALL SELECT b FROM t21a WHERE b>new.x ORDER BY 1 LIMIT 2; END; INSERT INTO t21b VALUES(6); } } {1 {no such column: new.x}} } finish_test |
Added test/sharedlock.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 | # 2009 July 2 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # $Id: sharedlock.test,v 1.1 2009/07/02 17:21:58 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl db close ifcapable !shared_cache { finish_test return } set ::enable_shared_cache [sqlite3_enable_shared_cache 1] sqlite3 db test.db sqlite3 db2 test.db do_test sharedlock-1.1 { execsql { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 'one'); INSERT INTO t1 VALUES(2, 'two'); } } {} do_test sharedlock-1.2 { set res [list] db eval { SELECT * FROM t1 ORDER BY rowid } { lappend res $a $b if {$a == 1} { catch { db eval "INSERT INTO t1 VALUES(3, 'three')" } } # This should fail. Connection [db] has a read-lock on t1, which should # prevent connection [db2] from obtaining the write-lock it needs to # modify t1. At one point there was a bug causing the previous INSERT # to drop the read-lock belonging to [db]. if {$a == 2} { catch { db2 eval "INSERT INTO t1 VALUES(4, 'four')" } } } set res } {1 one 2 two 3 three} db close db2 close sqlite3_enable_shared_cache $::enable_shared_cache finish_test |
Changes to test/speed3.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 testing that the overflow-page related # enhancements added after version 3.3.17 speed things up. # | | | 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 script is testing that the overflow-page related # enhancements added after version 3.3.17 speed things up. # # $Id: speed3.test,v 1.6 2009/07/09 02:48:24 shane Exp $ # #--------------------------------------------------------------------- # Test plan: # # If auto-vacuum is enabled for the database, the following cases # should show performance improvement with respect to 3.3.17. |
︙ | ︙ | |||
101 102 103 104 105 106 107 | db_leave db # puts "1: [array get stats1]" # puts "2: [array get stats2]" puts "Incrvacuum: Read $stats1(read), wrote $stats1(write)" puts "Normal : Read $stats2(read), wrote $stats2(write)" } | < < < < < < < < < < < < | 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | db_leave db # puts "1: [array get stats1]" # puts "2: [array get stats2]" puts "Incrvacuum: Read $stats1(read), wrote $stats1(write)" puts "Normal : Read $stats2(read), wrote $stats2(write)" } proc reset_db {} { db close sqlite3 db test.db db eval { PRAGMA main.cache_size = 200000; PRAGMA main.auto_vacuum = 'incremental'; ATTACH 'test2.db' AS 'aux'; |
︙ | ︙ | |||
162 163 164 165 166 167 168 | PRAGMA aux.auto_vacuum; } } {2 0} # Delete all content in a table, one row at a time. # #io_log db | < < | 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | PRAGMA aux.auto_vacuum; } } {2 0} # Delete all content in a table, one row at a time. # #io_log db reset_db speed_trial speed3-1.incrvacuum $::NROW row {DELETE FROM main.t1 WHERE 1} speed_trial speed3-1.normal $::NROW row {DELETE FROM aux.t1 WHERE 1} io_log db # Select the "C" column (located at the far end of the overflow # chain) from each table row. # #db eval {PRAGMA incremental_vacuum(500000)} populate_t1 db reset_db speed_trial speed3-2.incrvacuum $::NROW row {SELECT c FROM main.t1} speed_trial speed3-2.normal $::NROW row {SELECT c FROM aux.t1} io_log db finish_test |
Changes to test/tableapi.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 sqlite_exec_printf() and # sqlite_get_table_printf() APIs. # | | > > > > > < < | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the sqlite_exec_printf() and # sqlite_get_table_printf() APIs. # # $Id: tableapi.test,v 1.21 2009/07/17 14:37:25 shane Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !gettable { finish_test return } ifcapable memdebug { source $testdir/malloc_common.tcl } do_test tableapi-1.0 { set ::dbx [sqlite3_open test.db] catch {sqlite_exec_printf $::dbx {DROP TABLE xyz} {}} sqlite3_exec_printf $::dbx {CREATE TABLE %s(a int, b text)} xyz } {0 {}} do_test tableapi-1.1 { sqlite3_exec_printf $::dbx { INSERT INTO xyz VALUES(1,'%q') } {Hi Y'all} } {0 {}} do_test tableapi-1.2 { sqlite3_exec_printf $::dbx {SELECT * FROM xyz} {} } {0 {a b 1 {Hi Y'all}}} do_test tableapi-2.1 { sqlite3_get_table_printf $::dbx { BEGIN TRANSACTION; SELECT * FROM xyz WHERE b='%q' } {Hi Y'all} } {0 1 2 a b 1 {Hi Y'all}} do_test tableapi-2.2 { |
︙ | ︙ | |||
110 111 112 113 114 115 116 | } } {0 3 2 a b 52 NULL 50 (50) 42 (42)} do_test tableapi-2.7 { sqlite3_get_table_printf $::dbx { SELECT * FROM xyz WHERE a>1000 } {} } {0 0 0} | < < < | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | } } {0 3 2 a b 52 NULL 50 (50) 42 (42)} do_test tableapi-2.7 { sqlite3_get_table_printf $::dbx { SELECT * FROM xyz WHERE a>1000 } {} } {0 0 0} # Repeat all tests with the empty_result_callbacks pragma turned on # do_test tableapi-3.1 { sqlite3_get_table_printf $::dbx { ROLLBACK; PRAGMA empty_result_callbacks = ON; |
︙ | ︙ |
Changes to test/tclsqlite.test.
︙ | ︙ | |||
565 566 567 568 569 570 571 572 573 574 575 576 577 578 | } {1} do_test tcl-11.2 { db exists {SELECT 0 FROM t4 WHERE x==6} } {1} do_test tcl-11.3 { db exists {SELECT 1 FROM t4 WHERE x==8} } {0} do_test tcl-12.1 { unset -nocomplain a b c version set version [db version] scan $version "%d.%d.%d" a b c expr $a*1000000 + $b*1000 + $c } [sqlite3_libversion_number] | > > > | 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 | } {1} do_test tcl-11.2 { db exists {SELECT 0 FROM t4 WHERE x==6} } {1} do_test tcl-11.3 { db exists {SELECT 1 FROM t4 WHERE x==8} } {0} do_test tcl-11.3.1 { tcl_objproc db exists {SELECT 1 FROM t4 WHERE x==8} } {0} do_test tcl-12.1 { unset -nocomplain a b c version set version [db version] scan $version "%d.%d.%d" a b c expr $a*1000000 + $b*1000 + $c } [sqlite3_libversion_number] |
︙ | ︙ |
Changes to test/tester.tcl.
︙ | ︙ | |||
953 954 955 956 957 958 959 960 961 962 963 964 965 | set t [open $to w] fconfigure $t -translation binary puts -nonewline $t [read $f [file size $from]] close $t close $f } } # If the library is compiled with the SQLITE_DEFAULT_AUTOVACUUM macro set # to non-zero, then set the global variable $AUTOVACUUM to 1. set AUTOVACUUM $sqlite_options(default_autovacuum) source $testdir/thread_common.tcl | > > > > > > > > > > > > > > | 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 | set t [open $to w] fconfigure $t -translation binary puts -nonewline $t [read $f [file size $from]] close $t close $f } } # Drop all tables in database [db] proc drop_all_tables {{db db}} { set pk [$db one "PRAGMA foreign_keys"] $db eval "PRAGMA foreign_keys = OFF" foreach {t type} [$db eval { SELECT name, type FROM sqlite_master WHERE type IN('table', 'view') AND name NOT like 'sqlite_%' }] { $db eval "DROP $type $t" } $db eval " PRAGMA foreign_keys = $pk " } # If the library is compiled with the SQLITE_DEFAULT_AUTOVACUUM macro set # to non-zero, then set the global variable $AUTOVACUUM to 1. set AUTOVACUUM $sqlite_options(default_autovacuum) source $testdir/thread_common.tcl |
Changes to test/thread2.test.
︙ | ︙ | |||
188 189 190 191 192 193 194 | do_test thread2-3.20 { thread_create A test.db thread_compile A {SELECT a FROM t1 LIMIT 3} thread_step A set STMT [thread_stmt_get A] set DB [thread_db_get A] | < < < > | > | < < < | > | | 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 | do_test thread2-3.20 { thread_create A test.db thread_compile A {SELECT a FROM t1 LIMIT 3} thread_step A set STMT [thread_stmt_get A] set DB [thread_db_get A] sqlite3_step $STMT } SQLITE_ROW do_test thread2-3.22 { sqlite3_column_int $STMT 0 } 2 do_test thread2-3.23 { # The unlock fails here. But because we never check the return # code from sqlite3OsUnlock (because we cannot do anything about it # if it fails) we do not realize that an error has occurred. breakpoint sqlite3_finalize $STMT } SQLITE_OK do_test thread2-3.25 { thread_db_put A $DB thread_halt A } {} do_test thread2-3.30 { thread_create A test.db thread_compile A {BEGIN} thread_step A thread_finalize A thread_compile A {SELECT a FROM t1 LIMIT 1} thread_step A thread_finalize A set DB [thread_db_get A] set STMT [sqlite3_prepare $DB {INSERT INTO t1 VALUES(99,'error')} -1 TAIL] sqlite3_step $STMT } SQLITE_ERROR do_test thread2-3.32 { sqlite3_finalize $STMT } SQLITE_MISUSE do_test thread2-3.33 { thread_db_put A $DB thread_halt A } {} # VERY important to set the override flag back to its true value. # set threadsOverrideEachOthersLocks $orig_threadOverride # Also important to halt the worker threads, which are using spin # locks and eating away CPU cycles. |
︙ | ︙ |
Added test/tkt-2ea2425d34.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 | # 2009 September 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. # # This file implements tests to verify that ticket [2ea2425d34be] has been # fixed. # set testdir [file dirname $argv0] source $testdir/tester.tcl do_test tkt-2ea24-1.1 { db eval { PRAGMA encoding=UTF16; CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(1,'abc'); INSERT INTO t1 VALUES(2,'def'); INSERT INTO t1 VALUES(3,'ghi'); SELECT a FROM t1 WHERE length(b)<10 AND b<>'def' ORDER BY a; } } {1 3} finish_test |
Added test/tkt-3fe897352e.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 | # 2009 October 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 to verify that ticket [3fe897352e8d8] has been # fixed. # set testdir [file dirname $argv0] source $testdir/tester.tcl do_test tkt-3fe89-1.1 { db close sqlite3 db :memory: db eval { PRAGMA encoding=UTF8; CREATE TABLE t1(x); INSERT INTO t1 VALUES(hex_to_utf16be('D800')); SELECT hex(x) FROM t1; } } {EDA080} do_test tkt-3fe89-1.2 { db eval { DELETE FROM t1; INSERT INTO t1 VALUES(hex_to_utf16le('00D8')); SELECT hex(x) FROM t1; } } {EDA080} do_test tkt-3fe89-1.3 { db eval { DELETE FROM t1; INSERT INTO t1 VALUES(hex_to_utf16be('DFFF')); SELECT hex(x) FROM t1; } } {EDBFBF} do_test tkt-3fe89-1.4 { db eval { DELETE FROM t1; INSERT INTO t1 VALUES(hex_to_utf16le('FFDF')); SELECT hex(x) FROM t1; } } {EDBFBF} finish_test |
Added test/tkt-4a03edc4c8.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 | # 2009 September 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 to verify that # ticket [4a03edc4c8c028c93e9269f64fc5e97f632c1166] has been fixed. # set testdir [file dirname $argv0] source $testdir/tester.tcl do_test tkt-4a03ed-1.1 { db eval { CREATE TABLE t1( a INTEGER PRIMARY KEY ON CONFLICT REPLACE, b UNIQUE ON CONFLICT FAIL ); INSERT INTO t1 VALUES(1, 1); INSERT INTO t1 VALUES(2, 2); } catchsql { BEGIN; INSERT INTO t1 VALUES(1, 2); COMMIT; } } {1 {column b is not unique}} do_test tkt-4a03ed-1.2 { db eval { PRAGMA integrity_check; } } {ok} do_test tkt-4a03ed-1.3 { db eval { SELECT * FROM t1 ORDER BY a; } } {1 1 2 2} finish_test |
Added test/tkt-5ee23731f.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 | # 2009 October 13 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests to verify that ticket [5ee23731f15] has been # fixed. # set testdir [file dirname $argv0] source $testdir/tester.tcl do_test tkt-5ee237-1.1 { db close file delete -force test.db sqlite3 db test.db db eval { CREATE TABLE t1(x UNIQUE); INSERT INTO t1 VALUES(1); INSERT INTO t1 VALUES(2); INSERT INTO t1 SELECT x+2 FROM t1; INSERT INTO t1 SELECT x+4 FROM t1; INSERT INTO t1 SELECT x+8 FROM t1; } db close sqlite3 db test.db -readonly 1 set rc [catch { db eval {SELECT rowid, x FROM t1 ORDER BY x} { db eval {UPDATE t1 SET x=x+1 WHERE rowid=:rowid} } } msg] lappend rc $msg } {1 {attempt to write a readonly database}} finish_test |
Added test/tkt-94c04eaadb.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 | # 2009 October 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. # set testdir [file dirname $argv0] source $testdir/tester.tcl if {[info commands sqlite3async_initialize] eq ""} { # The async logic is not built into this system finish_test return } # Create a database. do_test tkt-94c94-1.1 { execsql { CREATE TABLE t1(a, b) } } {} # Grow the file to larger than 4096MB (2^32 bytes) db close if {[catch {fake_big_file 4096 [pwd]/test.db} msg]} { puts "**** Unable to create a file larger than 4096 MB. *****" finish_test return } # Switch to async mode. sqlite3async_initialize "" 1 sqlite3 db test.db sqlite3 db2 test.db # Read from and write to the db just past the 4096MB mark. # do_test tkt-94c94-2.1 { execsql { CREATE TABLE t2(x, y) } db } {} do_test tkt-94c94-2.2 { breakpoint execsql { INSERT INTO t2 VALUES(1, 2) } db2 } {} do_test tkt-94c94-2.3 { execsql { SELECT * FROM t2 } db } {1 2} do_test tkt-94c94-2.4 { sqlite3async_control halt idle sqlite3async_start sqlite3async_wait } {} do_test tkt-94c94-2.5 { execsql { SELECT * FROM t2 } db } {1 2} do_test tkt-94c94-2.6 { sqlite3async_start sqlite3async_wait } {} db close db2 close sqlite3async_start sqlite3async_wait sqlite3async_shutdown finish_test |
Added test/tkt-d82e3f3721.txt.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | # 2009 September 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. # # This file implements tests to verify that ticket [d82e3f3721] has been # fixed. # set testdir [file dirname $argv0] source $testdir/tester.tcl do_test tkt-d82e3-1.1 { db eval { CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b); INSERT INTO t1 VALUES(null,'abc'); INSERT INTO t1 VALUES(null,'def'); DELETE FROM t1; INSERT INTO t1 VALUES(null,'ghi'); SELECT * FROM t1; } } {3 ghi} do_test tkt-d82e3-1.2 { db eval { CREATE TEMP TABLE t2(a INTEGER PRIMARY KEY AUTOINCREMENT, b); INSERT INTO t2 VALUES(null,'jkl'); INSERT INTO t2 VALUES(null,'mno'); DELETE FROM t2; INSERT INTO t2 VALUES(null,'pqr'); SELECT * FROM t2; } } {3 pqr} do_test tkt-d82e3-1.3 { db eval { SELECT 'main', * FROM main.sqlite_sequence UNION ALL SELECT 'temp', * FROM temp.sqlite_sequence ORDER BY 2 } } {main t1 3 temp t2 3} do_test tkt-d82e3-1.4 { db eval { VACUUM; SELECT 'main', * FROM main.sqlite_sequence UNION ALL SELECT 'temp', * FROM temp.sqlite_sequence ORDER BY 2 } } {main t1 3 temp t2 3} sqlite3 db2 test.db do_test tkt-d82e3-2.1 { db eval { CREATE TEMP TABLE t3(x); INSERT INTO t3 VALUES(1); } db2 eval { CREATE TABLE t3(y,z); INSERT INTO t3 VALUES(8,9); } db eval { SELECT * FROM temp.t3 JOIN main.t3; } } {1 8 9} do_test tkt-d82e3-2.2 { db eval { VACUUM; SELECT * FROM temp.t3 JOIN main.t3; } } {1 8 9} finish_test |
Added test/tkt-f777251dc7a.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 | # 2009 October 16 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests to verify that ticket [f777251dc7a] has been # fixed. # set testdir [file dirname $argv0] source $testdir/tester.tcl do_test tkt-f7772-1.1 { execsql { CREATE TEMP TABLE t1(x UNIQUE); INSERT INTO t1 VALUES(1); CREATE TABLE t2(x, y); INSERT INTO t2 VALUES(1, 2); CREATE TEMP TABLE t3(w, z); } } {} proc force_rollback {} { catch {db eval {INSERT OR ROLLBACK INTO t1 VALUES(1)}} } db function force_rollback force_rollback do_test tkt-f7772-1.2 { catchsql { BEGIN IMMEDIATE; SELECT x, force_rollback(), EXISTS(SELECT 1 FROM t3 WHERE w=x) FROM t2; } } {1 {callback requested query abort}} do_test tkt-f7772-1.3 { sqlite3_get_autocommit db } {1} do_test tkt-f7772-2.1 { execsql { DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t2; DROP TABLE IF EXISTS t3; CREATE TEMP TABLE t1(x UNIQUE); INSERT INTO t1 VALUES(1); CREATE TABLE t2(x, y); INSERT INTO t2 VALUES(1, 2); } } {} do_test tkt-f7772-2.2 { execsql { BEGIN IMMEDIATE; CREATE TEMP TABLE t3(w, z); } catchsql { SELECT x, force_rollback(), EXISTS(SELECT 1 FROM t3 WHERE w=x) FROM t2 } } {1 {callback requested query abort}} do_test tkt-f7772-2.3 { sqlite3_get_autocommit db } {1} do_test tkt-f7772-3.1 { execsql { DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t2; DROP TABLE IF EXISTS t3; CREATE TEMP TABLE t1(x); CREATE TABLE t2(x); CREATE TABLE t3(x); INSERT INTO t1 VALUES(1); INSERT INTO t1 VALUES(2); INSERT INTO t2 VALUES(1); INSERT INTO t2 VALUES(2); } } {} proc ins {} { db eval {INSERT INTO t3 VALUES('hello')} } db function ins ins do_test tkt-f7772-3.2 { execsql { SELECT ins() AS x FROM t2 UNION ALL SELECT ins() AS x FROM t1 } } {{} {} {} {}} do_test tkt-f7772-3.3 { execsql { SELECT * FROM t3 } } {hello hello hello hello} finish_test |
Changes to test/tkt3201.test.
︙ | ︙ | |||
65 66 67 68 69 70 71 72 73 74 | } execsql { SELECT a, b, c, d FROM t1, t3 } } {1 one 2 two} do_test tkt3201-7 { execsql { SELECT a, b, c, d FROM t1, t3 WHERE a < c } } {1 one 2 two} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | } execsql { SELECT a, b, c, d FROM t1, t3 } } {1 one 2 two} do_test tkt3201-7 { execsql { SELECT a, b, c, d FROM t1, t3 WHERE a < c } } {1 one 2 two} # Ticket [efc02f977919] # ifcapable trigger { do_test tkt3201-4.0 { db eval { CREATE TABLE t4(x); CREATE TABLE t4_log(x); CREATE TRIGGER r4_1 AFTER INSERT ON t4 WHEN new.x=1 BEGIN INSERT INTO t4_log(x) VALUES(new.x); END; CREATE TRIGGER r4_2 AFTER INSERT ON t4 WHEN new.x=2 BEGIN INSERT INTO t4_log(x) VALUES(new.x); END; CREATE TRIGGER r4_3 AFTER INSERT ON t4 WHEN new.x=3 BEGIN INSERT INTO t4_log(x) VALUES(new.x); END; CREATE TRIGGER r4_4 AFTER INSERT ON t4 WHEN new.x=4 BEGIN INSERT INTO t4_log(x) VALUES(new.x); END; INSERT INTO t4 VALUES(1); INSERT INTO t4 VALUES(2); INSERT INTO t4 VALUES(3); INSERT INTO t4 VALUES(4); SELECT * FROM t4_log; } } {1 2 3 4} } finish_test |
Changes to test/tkt3731.test.
︙ | ︙ | |||
13 14 15 16 17 18 19 20 21 22 23 24 25 26 | set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {!trigger} { finish_test return } do_test tkt3731-1.1 { execsql { CREATE TABLE t1(a PRIMARY KEY, b); CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN INSERT INTO t1 VALUES(new.a || '+', new.b || '+'); END; | > > > > > | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {!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 # recursive triggers for this file. catchsql { pragma recursive_triggers = off } do_test tkt3731-1.1 { execsql { CREATE TABLE t1(a PRIMARY KEY, b); CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN INSERT INTO t1 VALUES(new.a || '+', new.b || '+'); END; |
︙ | ︙ |
Added test/tkt3810.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 | # 2009 August 1 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # Tests to make sure #3810 is fixed. # # $Id: tkt3810.test,v 1.4 2009/08/06 17:43:31 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {!trigger} { finish_test return } # Create a table using the first database connection. # do_test tkt3810-1.1 { execsql { CREATE TABLE t1(x); INSERT INTO t1 VALUES(123); SELECT * FROM t1; CREATE TABLE t2(y); CREATE TABLE t3(z); } } 123 # Create a second connection to the same database. Make sure the # schema of the database has been parsed by the second connection. # do_test tkt3810-2 { sqlite3 db2 test.db execsql { SELECT * FROM t1; } db2 } 123 # DROP the table using the second connection. The table no longer exists # but the first connection does not yet know this. Then try to create a TEMP # trigger in the first connection that references the table that was dropped. # do_test tkt3810-3 { execsql {DROP TABLE t1} db2 execsql { CREATE TEMP TRIGGER r1 AFTER INSERT ON t1 BEGIN INSERT INTO t2 VALUES(new.rowid); END; } catchsql { SELECT * FROM t3; } } {0 {}} # Trigger still exists in the sqlite_temp_master table, but now it is # an orphan. # do_test tkt3810-4 { execsql {SELECT name FROM sqlite_temp_master ORDER BY name} } {r1} # Because it is an orphan, it cannot be dropped. # do_test tkt3810-5 { catchsql {DROP TRIGGER r1} } {1 {no such trigger: r1}} # Create a table t1 then drop the table in order to drop the orphaned # trigger. # do_test tkt3810-6 { execsql {CREATE TABLE t1(x)} db2 execsql {DROP TABLE t1} execsql { SELECT name FROM sqlite_temp_master; } } {} db2 close finish_test |
Changes to test/tkt3832.test.
︙ | ︙ | |||
14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # A segfault when using a BEFORE trigger on an INSERT and inserting # a NULL into the INTEGER PRIMARY KEY. # # $Id: tkt3832.test,v 1.1 2009/05/01 02:08:04 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl do_test tkt3832-1.1 { db eval { CREATE TABLE t1(a INT, b INTEGER PRIMARY KEY); CREATE TABLE log(x); CREATE TRIGGER t1r1 BEFORE INSERT ON t1 BEGIN | > > > > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | # A segfault when using a BEFORE trigger on an INSERT and inserting # a NULL into the INTEGER PRIMARY KEY. # # $Id: tkt3832.test,v 1.1 2009/05/01 02:08:04 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {!trigger} { finish_test return } do_test tkt3832-1.1 { db eval { CREATE TABLE t1(a INT, b INTEGER PRIMARY KEY); CREATE TABLE log(x); CREATE TRIGGER t1r1 BEFORE INSERT ON t1 BEGIN |
︙ | ︙ |
Changes to test/tkt3838.test.
︙ | ︙ | |||
16 17 18 19 20 21 22 23 24 25 26 27 28 29 | # Verify that this has been fixed. # # $Id: tkt3838.test,v 1.1 2009/05/05 12:54:50 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl do_test tkt3838-1.1 { db eval { PRAGMA encoding=UTF16; CREATE TABLE t1(x); INSERT INTO t1 VALUES(1); ALTER TABLE t1 ADD COLUMN b INTEGER DEFAULT '999'; | > > > > | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | # Verify that this has been fixed. # # $Id: tkt3838.test,v 1.1 2009/05/05 12:54:50 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !altertable { finish_test return } do_test tkt3838-1.1 { db eval { PRAGMA encoding=UTF16; CREATE TABLE t1(x); INSERT INTO t1 VALUES(1); ALTER TABLE t1 ADD COLUMN b INTEGER DEFAULT '999'; |
︙ | ︙ |
Changes to test/tkt3929.test.
︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # # Tests to verify ticket #3929 is fixed. # # $Id: tkt3929.test,v 1.1 2009/06/23 11:53:09 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl do_test tkt3929-1.0 { execsql { PRAGMA page_size = 1024; CREATE TABLE t1(a, b); CREATE INDEX i1 ON t1(a, b); CREATE TRIGGER t1_t1 AFTER INSERT ON t1 BEGIN | > > > > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | # # Tests to verify ticket #3929 is fixed. # # $Id: tkt3929.test,v 1.1 2009/06/23 11:53:09 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {!trigger} { finish_test return } do_test tkt3929-1.0 { execsql { PRAGMA page_size = 1024; CREATE TABLE t1(a, b); CREATE INDEX i1 ON t1(a, b); CREATE TRIGGER t1_t1 AFTER INSERT ON t1 BEGIN |
︙ | ︙ |
Added test/tkt3935.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 | # 2009 July 1 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests to verify that ticket #3935 has been fixed. # # $Id: tkt3935.test,v 1.2 2009/07/01 16:12:08 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl do_test tkt3935.1 { execsql { CREATE TABLE t1(a, b); CREATE TABLE t2(c, d); } } {} do_test tkt3935.2 { execsql { SELECT j1.b FROM ( SELECT * FROM t1 INNER JOIN t2 ON a=c ) AS j1 } } {} 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 |
Added test/tkt3992.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 | # 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. # #*********************************************************************** # # $Id: tkt3992.test,v 1.1 2009/07/27 10:05:06 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl do_test tkt3992-1.1 { execsql { CREATE TABLE parameters1( mountcnt INT NOT NULL CHECK (typeof(mountcnt) == 'integer'), version REAL NOT NULL ); INSERT INTO parameters1(mountcnt, version) VALUES(1, 1.0); CREATE TABLE parameters2( mountcnt INT NOT NULL CHECK (typeof(mountcnt) == 'integer'), version REAL CHECK (typeof(version) == 'real') ); INSERT INTO parameters2(mountcnt, version) VALUES(1, 1.0); } } {} do_test tkt3992-1.2 { execsql { UPDATE parameters1 SET mountcnt = mountcnt + 1; SELECT * FROM parameters1; } } {2 1.0} do_test tkt3992-1.3 { execsql { UPDATE parameters2 SET mountcnt = mountcnt + 1; SELECT * FROM parameters2; } } {2 1.0} ifcapable altertable { do_test tkt3992-2.1 { execsql { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 2); ALTER TABLE t1 ADD COLUMN c DEFAULT 3; SELECT * FROM t1; } } {1 2 3} do_test tkt3992-2.2 { execsql { UPDATE t1 SET a = 'one'; SELECT * FROM t1; } } {one 2 3} } ifcapable trigger { db function tcl eval do_test tkt3992-2.3 { execsql { CREATE TABLE t2(a REAL, b REAL, c REAL); INSERT INTO t2 VALUES(1, 2, 3); CREATE TRIGGER tr2 BEFORE UPDATE ON t2 BEGIN SELECT tcl('set res', typeof(new.c)); END; UPDATE t2 SET a = 'I'; } set res } {real} } finish_test |
Added test/tkt3997.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 | # 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. # #*********************************************************************** # # Tests to make sure #3997 is fixed. # # $Id: tkt3997.test,v 1.1 2009/07/28 13:30:31 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl proc reverse {lhs rhs} { return [string compare $rhs $lhs] } proc usual {lhs rhs} { return [string compare $lhs $rhs] } db collate reverse reverse db collate usual usual do_test tkt3997-1.1 { execsql { create table mytext(name BLOB); INSERT INTO mytext VALUES('abc'); INSERT INTO mytext VALUES('acd'); INSERT INTO mytext VALUES('afe'); } } {} do_test tkt3997-1.2 { execsql { SELECT name FROM mytext ORDER BY name COLLATE reverse } } {afe acd abc} do_test tkt3997-1.3 { execsql { SELECT name FROM (SELECT name FROM mytext) ORDER BY name COLLATE reverse } } {afe acd abc} do_test tkt3997-2.1 { execsql { CREATE TABLE mytext2(name COLLATE reverse); INSERT INTO mytext2 SELECT name FROM mytext; } } {} do_test tkt3997-2.2 { execsql { SELECT name FROM (SELECT name FROM mytext2) ORDER BY name } } {afe acd abc} do_test tkt3997-2.3 { execsql { SELECT name FROM (SELECT name FROM mytext2) ORDER BY name COLLATE usual } } {abc acd afe} finish_test |
Added test/tkt4018.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 | # 2009 August 20 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests to verify that ticket #4018 has been # fixed. # set testdir [file dirname $argv0] source $testdir/tester.tcl proc testsql {sql} { set fd [open tf_main.tcl w] puts $fd [subst -nocommands { sqlite3_test_control_pending_byte 0x0010000 sqlite3 db test.db set rc [catch { db eval {$sql} } msg] puts -nonewline "[set rc] {[set msg]}" flush stdout exit }] close $fd set fd [open "| [info nameofexec] ./tf_main.tcl" r] set res [read $fd] close $fd return $res } do_test tkt4018-1.1 { execsql { CREATE TABLE t1(a, b); BEGIN; SELECT * FROM t1; } } {} # The database is locked by connection [db]. Open and close a second # connection to test.db 10000 times. If file-descriptors are not being # reused, then the process will quickly exceed its maximum number of # file descriptors (1024 by default on linux). do_test tkt4018-1.2 { for {set i 0} {$i < 10000} {incr i} { sqlite3 db2 test.db db2 close } } {} # Now check that connection [db] is still holding a SHARED lock by # having a second process try to write the db. do_test tkt4018-1.3 { testsql {INSERT INTO t1 VALUES(3, 4)} } {1 {database is locked}} # Sanity checking. Have [db] release the lock and then retry the # INSERT from the previous test case. do_test tkt4018-1.4 { db eval COMMIT testsql {INSERT INTO t1 VALUES(3, 4)} } {0 {}} # Check that reusing a file descriptor cannot change a read-only # connection into a read-write connection. do_test tkt4018-2.1 { sqlite3 db2 test.db execsql {INSERT INTO t1 VALUES(1, 2)} db2 } {} do_test tkt4018-2.2 { execsql { BEGIN; SELECT * FROM t1 ORDER BY a; } } {1 2 3 4} do_test tkt4018-2.3 { db2 close sqlite3 db2 test.db -readonly 1 execsql COMMIT catchsql {INSERT INTO t1 VALUES(5, 6)} db2 } {1 {attempt to write a readonly database}} db2 close finish_test |
Changes to test/trigger1.test.
︙ | ︙ | |||
59 60 61 62 63 64 65 | catchsql { CREATE TRIGGER trig UPDATE ON t1 FOR EACH STATEMENT BEGIN SELECT * FROM sqlite_master; END; } } {1 {near "STATEMENT": syntax error}} execsql { | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 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 | catchsql { CREATE TRIGGER trig UPDATE ON t1 FOR EACH STATEMENT BEGIN SELECT * FROM sqlite_master; END; } } {1 {near "STATEMENT": syntax error}} execsql { CREATE TRIGGER tr1 INSERT ON t1 BEGIN INSERT INTO t1 values(1); END; } do_test trigger1-1.2.0 { catchsql { CREATE TRIGGER IF NOT EXISTS tr1 DELETE ON t1 BEGIN SELECT * FROM sqlite_master; END } } {0 {}} do_test trigger1-1.2.1 { catchsql { CREATE TRIGGER tr1 DELETE ON t1 BEGIN SELECT * FROM sqlite_master; END } } {1 {trigger tr1 already exists}} do_test trigger1-1.2.2 { catchsql { CREATE TRIGGER "tr1" DELETE ON t1 BEGIN SELECT * FROM sqlite_master; END } } {1 {trigger "tr1" already exists}} do_test trigger1-1.2.3 { catchsql { CREATE TRIGGER [tr1] DELETE ON t1 BEGIN SELECT * FROM sqlite_master; END } } {1 {trigger [tr1] already exists}} do_test trigger1-1.3 { catchsql { BEGIN; CREATE TRIGGER tr2 INSERT ON t1 BEGIN SELECT * from sqlite_master; END; ROLLBACK; CREATE TRIGGER tr2 INSERT ON t1 BEGIN SELECT * from sqlite_master; END; } } {0 {}} do_test trigger1-1.4 { catchsql { DROP TRIGGER IF EXISTS tr1; CREATE TRIGGER tr1 DELETE ON t1 BEGIN SELECT * FROM sqlite_master; END } } {0 {}} do_test trigger1-1.5 { execsql { BEGIN; DROP TRIGGER tr2; ROLLBACK; DROP TRIGGER tr2; } } {} do_test trigger1-1.6.1 { catchsql { DROP TRIGGER IF EXISTS biggles; } } {0 {}} do_test trigger1-1.6.2 { catchsql { DROP TRIGGER biggles; } } {1 {no such trigger: biggles}} do_test trigger1-1.7 { catchsql { DROP TABLE t1; DROP TRIGGER tr1; } } {1 {no such trigger: tr1}} ifcapable tempdb { execsql { CREATE TEMP TABLE temp_table(a); } do_test trigger1-1.8 { execsql { CREATE TRIGGER temp_trig UPDATE ON temp_table BEGIN SELECT * from sqlite_master; END; SELECT count(*) FROM sqlite_master WHERE name = 'temp_trig'; } } {0} } do_test trigger1-1.9 { catchsql { CREATE TRIGGER tr1 AFTER UPDATE ON sqlite_master BEGIN |
︙ | ︙ | |||
399 400 401 402 403 404 405 | } do_test trigger1-6.1 { execsql {SELECT type, name FROM sqlite_master} } [concat $view_v1 {table t2}] do_test trigger1-6.2 { execsql { CREATE TRIGGER t2 BEFORE DELETE ON t2 BEGIN | | | | 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 | } do_test trigger1-6.1 { execsql {SELECT type, name FROM sqlite_master} } [concat $view_v1 {table t2}] do_test trigger1-6.2 { execsql { CREATE TRIGGER t2 BEFORE DELETE ON t2 BEGIN SELECT RAISE(ABORT,'deletes are not permitted'); END; SELECT type, name FROM sqlite_master; } } [concat $view_v1 {table t2 trigger t2}] do_test trigger1-6.3 { catchsql {DELETE FROM t2} } {1 {deletes are not permitted}} do_test trigger1-6.4 { execsql {SELECT * FROM t2} } {3 4 7 8} do_test trigger1-6.5 { db close sqlite3 db test.db execsql {SELECT type, name FROM sqlite_master} |
︙ | ︙ | |||
635 636 637 638 639 640 641 642 | } catchsql { UPDATE tA SET a = 'abc' } } {1 {datatype mismatch}} do_test trigger1-15.2 { catchsql { INSERT INTO tA VALUES('abc', 2, 3) } } {1 {datatype mismatch}} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } catchsql { UPDATE tA SET a = 'abc' } } {1 {datatype mismatch}} do_test trigger1-15.2 { catchsql { INSERT INTO tA VALUES('abc', 2, 3) } } {1 {datatype mismatch}} # Ticket #3947: Do not allow qualified table names on INSERT, UPDATE, and # DELETE statements within triggers. Actually, this has never been allowed # by the grammar. But the error message is confusing: one simply gets a # "syntax error". That has now been changed to give a full error message. # do_test trigger1-16.1 { db eval { CREATE TABLE t16(a,b,c); CREATE INDEX t16a ON t16(a); CREATE INDEX t16b ON t16(b); } catchsql { CREATE TRIGGER main.t16err1 AFTER INSERT ON tA BEGIN INSERT INTO main.t16 VALUES(1,2,3); END; } } {1 {qualified table names are not allowed on INSERT, UPDATE, and DELETE statements within triggers}} do_test trigger1-16.2 { catchsql { CREATE TRIGGER main.t16err2 AFTER INSERT ON tA BEGIN UPDATE main.t16 SET rowid=rowid+1; END; } } {1 {qualified table names are not allowed on INSERT, UPDATE, and DELETE statements within triggers}} do_test trigger1-16.3 { catchsql { CREATE TRIGGER main.t16err3 AFTER INSERT ON tA BEGIN DELETE FROM main.t16; END; } } {1 {qualified table names are not allowed on INSERT, UPDATE, and DELETE statements within triggers}} do_test trigger1-16.4 { catchsql { CREATE TRIGGER main.t16err4 AFTER INSERT ON tA BEGIN UPDATE t16 NOT INDEXED SET rowid=rowid+1; END; } } {1 {the NOT INDEXED clause is not allowed on UPDATE or DELETE statements within triggers}} do_test trigger1-16.5 { catchsql { CREATE TRIGGER main.t16err5 AFTER INSERT ON tA BEGIN UPDATE t16 INDEXED BY t16a SET rowid=rowid+1 WHERE a=1; END; } } {1 {the INDEXED BY clause is not allowed on UPDATE or DELETE statements within triggers}} do_test trigger1-16.6 { catchsql { CREATE TRIGGER main.t16err6 AFTER INSERT ON tA BEGIN DELETE FROM t16 NOT INDEXED WHERE a=123; END; } } {1 {the NOT INDEXED clause is not allowed on UPDATE or DELETE statements within triggers}} do_test trigger1-16.7 { catchsql { CREATE TRIGGER main.t16err7 AFTER INSERT ON tA BEGIN DELETE FROM t16 INDEXED BY t16a WHERE a=123; END; } } {1 {the INDEXED BY clause is not allowed on UPDATE or DELETE statements within triggers}} finish_test |
Changes to test/trigger2.test.
︙ | ︙ | |||
49 50 51 52 53 54 55 56 57 58 59 60 61 62 | set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {!trigger} { finish_test return } # 1. ifcapable subquery { set ii 0 set tbl_definitions [list \ {CREATE TABLE tbl (a, b);} \ {CREATE TABLE tbl (a INTEGER PRIMARY KEY, b);} \ | > > > > > | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | 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 # recursive triggers for this file. catchsql { pragma recursive_triggers = off } # 1. ifcapable subquery { set ii 0 set tbl_definitions [list \ {CREATE TABLE tbl (a, b);} \ {CREATE TABLE tbl (a INTEGER PRIMARY KEY, b);} \ |
︙ | ︙ |
Changes to test/trigger3.test.
︙ | ︙ | |||
13 14 15 16 17 18 19 20 21 | set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {!trigger} { finish_test return } # Test that we can cause ROLLBACK, FAIL and ABORT correctly | > > > > > < < | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 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 | 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 # recursive triggers for this file. catchsql { pragma recursive_triggers = off } # Test that we can cause ROLLBACK, FAIL and ABORT correctly # catchsql { CREATE TABLE tbl(a, b ,c) } execsql { CREATE TRIGGER before_tbl_insert BEFORE INSERT ON tbl BEGIN SELECT CASE WHEN (new.a = 4) THEN RAISE(IGNORE) END; END; CREATE TRIGGER after_tbl_insert AFTER INSERT ON tbl BEGIN SELECT CASE WHEN (new.a = 1) THEN RAISE(ABORT, 'Trigger abort') WHEN (new.a = 2) THEN RAISE(FAIL, 'Trigger fail') WHEN (new.a = 3) THEN RAISE(ROLLBACK, 'Trigger rollback') END; END; } # ABORT do_test trigger3-1.1 { catchsql { BEGIN; INSERT INTO tbl VALUES (5, 5, 6); INSERT INTO tbl VALUES (1, 5, 6); } } {1 {Trigger abort}} do_test trigger3-1.2 { execsql { SELECT * FROM tbl; ROLLBACK; } } {5 5 6} do_test trigger3-1.3 { execsql {SELECT * FROM tbl} } {} # FAIL do_test trigger3-2.1 { catchsql { BEGIN; INSERT INTO tbl VALUES (5, 5, 6); INSERT INTO tbl VALUES (2, 5, 6); } } {1 {Trigger fail}} do_test trigger3-2.2 { execsql { SELECT * FROM tbl; ROLLBACK; } } {5 5 6 2 5 6} # ROLLBACK do_test trigger3-3.1 { catchsql { BEGIN; INSERT INTO tbl VALUES (5, 5, 6); INSERT INTO tbl VALUES (3, 5, 6); } } {1 {Trigger rollback}} do_test trigger3-3.2 { execsql { SELECT * FROM tbl; } } {} # Verify that a ROLLBACK trigger works like a FAIL trigger if # we are not within a transaction. Ticket #3035. # do_test trigger3-3.3 { catchsql {COMMIT} catchsql { INSERT INTO tbl VALUES (3, 9, 10); } } {1 {Trigger rollback}} do_test trigger3-3.4 { execsql {SELECT * FROM tbl} } {} # IGNORE do_test trigger3-4.1 { catchsql { BEGIN; INSERT INTO tbl VALUES (5, 5, 6); INSERT INTO tbl VALUES (4, 5, 6); } } {0 {}} do_test trigger3-4.2 { execsql { SELECT * FROM tbl; ROLLBACK; } } {5 5 6} # Check that we can also do RAISE(IGNORE) for UPDATE and DELETE execsql {DROP TABLE tbl;} execsql {CREATE TABLE tbl (a, b, c);} execsql {INSERT INTO tbl VALUES(1, 2, 3);} execsql {INSERT INTO tbl VALUES(4, 5, 6);} execsql { CREATE TRIGGER before_tbl_update BEFORE UPDATE ON tbl BEGIN SELECT CASE WHEN (old.a = 1) THEN RAISE(IGNORE) END; END; CREATE TRIGGER before_tbl_delete BEFORE DELETE ON tbl BEGIN SELECT CASE WHEN (old.a = 1) THEN RAISE(IGNORE) END; END; } do_test trigger3-5.1 { execsql { UPDATE tbl SET c = 10; SELECT * FROM tbl; } } {1 2 3 4 5 10} do_test trigger3-5.2 { execsql { DELETE FROM tbl; SELECT * FROM tbl; } } {1 2 3} # Check that RAISE(IGNORE) works correctly for nested triggers: execsql {CREATE TABLE tbl2(a, b, c)} execsql { CREATE TRIGGER after_tbl2_insert AFTER INSERT ON tbl2 BEGIN UPDATE tbl SET c = 10; INSERT INTO tbl2 VALUES (new.a, new.b, new.c); END; } do_test trigger3-6 { execsql { INSERT INTO tbl2 VALUES (1, 2, 3); SELECT * FROM tbl2; SELECT * FROM tbl; } } {1 2 3 1 2 3 1 2 3} # Check that things also work for view-triggers ifcapable view { execsql {CREATE VIEW tbl_view AS SELECT * FROM tbl} execsql { CREATE TRIGGER tbl_view_insert INSTEAD OF INSERT ON tbl_view BEGIN SELECT CASE WHEN (new.a = 1) THEN RAISE(ROLLBACK, 'View rollback') WHEN (new.a = 2) THEN RAISE(IGNORE) WHEN (new.a = 3) THEN RAISE(ABORT, 'View abort') END; END; } do_test trigger3-7.1 { catchsql { INSERT INTO tbl_view VALUES(1, 2, 3); } } {1 {View rollback}} do_test trigger3-7.2 { catchsql { INSERT INTO tbl_view VALUES(2, 2, 3); } } {0 {}} do_test trigger3-7.3 { catchsql { INSERT INTO tbl_view VALUES(3, 2, 3); } } {1 {View abort}} } ;# ifcapable view integrity_check trigger3-8.1 catchsql { DROP TABLE tbl; } catchsql { DROP TABLE tbl2; } catchsql { DROP VIEW tbl_view; } finish_test |
Changes to test/trigger8.test.
︙ | ︙ | |||
28 29 30 31 32 33 34 35 36 37 38 39 40 41 | # heap, use 1000. # set nStatement 10000 if {$tcl_platform(platform) == "symbian"} { set nStatement 1000 } do_test trigger8-1.1 { execsql { CREATE TABLE t1(x); CREATE TABLE t2(y); } set sql "CREATE TRIGGER r${nStatement} AFTER INSERT ON t1 BEGIN\n" for {set i 0} {$i<$nStatement} {incr i} { | > | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | # heap, use 1000. # set nStatement 10000 if {$tcl_platform(platform) == "symbian"} { set nStatement 1000 } set nStatement 5 do_test trigger8-1.1 { execsql { CREATE TABLE t1(x); CREATE TABLE t2(y); } set sql "CREATE TRIGGER r${nStatement} AFTER INSERT ON t1 BEGIN\n" for {set i 0} {$i<$nStatement} {incr i} { |
︙ | ︙ |
Changes to test/trigger9.test.
︙ | ︙ | |||
71 72 73 74 75 76 77 | END; DELETE FROM t1; SELECT * FROM t2; } } {1 2 3} do_test trigger9-1.3.2 { has_rowdata {DELETE FROM t1} | | | | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | END; DELETE FROM t1; SELECT * FROM t2; } } {1 2 3} do_test trigger9-1.3.2 { has_rowdata {DELETE FROM t1} } 0 do_test trigger9-1.3.3 { execsql { ROLLBACK } } {} do_test trigger9-1.4.1 { execsql { BEGIN; CREATE TRIGGER trig1 BEFORE DELETE ON t1 WHEN old.x='1' BEGIN INSERT INTO t2 VALUES(old.rowid); END; DELETE FROM t1; SELECT * FROM t2; } } {1} do_test trigger9-1.4.2 { has_rowdata {DELETE FROM t1} } 0 do_test trigger9-1.4.3 { execsql { ROLLBACK } } {} do_test trigger9-1.5.1 { execsql { BEGIN; CREATE TRIGGER trig1 BEFORE UPDATE ON t1 BEGIN INSERT INTO t2 VALUES(old.rowid); |
︙ | ︙ | |||
116 117 118 119 120 121 122 | END; UPDATE t1 SET y = ''; SELECT * FROM t2; } } {1 2 3} do_test trigger9-1.6.2 { has_rowdata {UPDATE t1 SET y = ''} | | | | 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 | END; UPDATE t1 SET y = ''; SELECT * FROM t2; } } {1 2 3} do_test trigger9-1.6.2 { has_rowdata {UPDATE t1 SET y = ''} } 0 do_test trigger9-1.6.3 { execsql { ROLLBACK } } {} do_test trigger9-1.7.1 { execsql { BEGIN; CREATE TRIGGER trig1 BEFORE UPDATE ON t1 WHEN old.x>='2' BEGIN INSERT INTO t2 VALUES(old.x); END; UPDATE t1 SET y = ''; SELECT * FROM t2; } } {2 3} do_test trigger9-1.7.2 { has_rowdata {UPDATE t1 SET y = ''} } 0 do_test trigger9-1.7.3 { execsql { ROLLBACK } } {} do_test trigger9-3.1 { execsql { CREATE TABLE t3(a, b); INSERT INTO t3 VALUES(1, 'one'); INSERT INTO t3 VALUES(2, 'two'); |
︙ | ︙ |
Changes to test/triggerA.test.
︙ | ︙ | |||
75 76 77 78 79 80 81 | } } {1 10 2 3 4 5 6 7 8 9 five four three} do_test triggerA-1.6 { db eval { CREATE VIEW v5 AS SELECT x, b FROM t1, t2 WHERE y=c; SELECT * FROM v5; } | | | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | } } {1 10 2 3 4 5 6 7 8 9 five four three} do_test triggerA-1.6 { db eval { CREATE VIEW v5 AS SELECT x, b FROM t1, t2 WHERE y=c; SELECT * FROM v5; } } {10 1003 9 904 8 805 7 705 6 603 5 504 4 404 3 305 2 203 1 103} # Create INSTEAD OF triggers on the views. Run UPDATE and DELETE statements # using those triggers. Verify correct operation. # do_test triggerA-2.1 { db eval { CREATE TABLE result2(a,b); |
︙ | ︙ |
Added test/triggerC.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 | # 2009 August 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. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {!trigger} { finish_test return } #------------------------------------------------------------------------- # Test organization: # # triggerC-1.*: Haphazardly designed trigger related tests that were useful # during an upgrade of the triggers sub-system. # # triggerC-2.*: # # triggerC-3.*: # # triggerC-4.*: # # triggerC-5.*: Test that when recursive triggers are enabled DELETE # triggers are fired when rows are deleted as part of OR # REPLACE conflict resolution. And that they are not fired # if recursive triggers are not enabled. # # triggerC-6.*: Test that the recursive_triggers pragma returns correct # results when invoked without an argument. # # Enable recursive triggers for this file. # execsql { PRAGMA recursive_triggers = on } #sqlite3_db_config_lookaside db 0 0 0 #------------------------------------------------------------------------- # This block of tests, triggerC-1.*, are not aimed at any specific # property of the triggers sub-system. They were created to debug # specific problems while modifying SQLite to support recursive # triggers. They are left here in case they can help debug the # same problems again. # do_test triggerC-1.1 { execsql { CREATE TABLE t1(a, b, c); CREATE TABLE log(t, a1, b1, c1, a2, b2, c2); CREATE TRIGGER trig1 BEFORE INSERT ON t1 BEGIN INSERT INTO log VALUES('before', NULL, NULL, NULL, new.a, new.b, new.c); END; CREATE TRIGGER trig2 AFTER INSERT ON t1 BEGIN INSERT INTO log VALUES('after', NULL, NULL, NULL, new.a, new.b, new.c); END; CREATE TRIGGER trig3 BEFORE UPDATE ON t1 BEGIN INSERT INTO log VALUES('before', old.a,old.b,old.c, new.a,new.b,new.c); END; CREATE TRIGGER trig4 AFTER UPDATE ON t1 BEGIN INSERT INTO log VALUES('after', old.a,old.b,old.c, new.a,new.b,new.c); END; CREATE TRIGGER trig5 BEFORE DELETE ON t1 BEGIN INSERT INTO log VALUES('before', old.a,old.b,old.c, NULL,NULL,NULL); END; CREATE TRIGGER trig6 AFTER DELETE ON t1 BEGIN INSERT INTO log VALUES('after', old.a,old.b,old.c, NULL,NULL,NULL); END; } } {} do_test triggerC-1.2 { execsql { INSERT INTO t1 VALUES('A', 'B', 'C'); SELECT * FROM log; } } {before {} {} {} A B C after {} {} {} A B C} do_test triggerC-1.3 { execsql { SELECT * FROM t1 } } {A B C} do_test triggerC-1.4 { execsql { DELETE FROM log; UPDATE t1 SET a = 'a'; SELECT * FROM log; } } {before A B C a B C after A B C a B C} do_test triggerC-1.5 { execsql { SELECT * FROM t1 } } {a B C} do_test triggerC-1.6 { execsql { DELETE FROM log; DELETE FROM t1; SELECT * FROM log; } } {before a B C {} {} {} after a B C {} {} {}} do_test triggerC-1.7 { execsql { SELECT * FROM t1 } } {} do_test triggerC-1.8 { execsql { CREATE TABLE t4(a, b); CREATE TRIGGER t4t AFTER DELETE ON t4 BEGIN SELECT RAISE(ABORT, 'delete is not supported'); END; } } {} do_test triggerC-1.9 { execsql { INSERT INTO t4 VALUES(1, 2) } catchsql { DELETE FROM t4 } } {1 {delete is not supported}} do_test triggerC-1.10 { execsql { SELECT * FROM t4 } } {1 2} do_test triggerC-1.11 { execsql { CREATE TABLE t5 (a primary key, b, c); INSERT INTO t5 values (1, 2, 3); CREATE TRIGGER au_tbl AFTER UPDATE ON t5 BEGIN UPDATE OR IGNORE t5 SET a = new.a, c = 10; END; } } {} do_test triggerC-1.12 { catchsql { UPDATE OR REPLACE t5 SET a = 4 WHERE a = 1 } } {1 {too many levels of trigger recursion}} do_test triggerC-1.13 { execsql { CREATE TABLE t6(a INTEGER PRIMARY KEY, b); INSERT INTO t6 VALUES(1, 2); create trigger r1 after update on t6 for each row begin SELECT 1; end; UPDATE t6 SET a=a; } } {} do_test triggerC-1.14 { execsql { DROP TABLE t1; CREATE TABLE cnt(n); INSERT INTO cnt VALUES(0); CREATE TABLE t1(a INTEGER PRIMARY KEY, b UNIQUE, c, d, e); CREATE INDEX t1cd ON t1(c,d); CREATE TRIGGER t1r1 AFTER UPDATE ON t1 BEGIN UPDATE cnt SET n=n+1; END; INSERT INTO t1 VALUES(1,2,3,4,5); INSERT INTO t1 VALUES(6,7,8,9,10); INSERT INTO t1 VALUES(11,12,13,14,15); } } {} do_test triggerC-1.15 { catchsql { UPDATE OR ROLLBACK t1 SET a=100 } } {1 {PRIMARY KEY must be unique}} #------------------------------------------------------------------------- # This block of tests, triggerC-2.*, tests that recursive trigger # programs (triggers that fire themselves) work. More specifically, # this block focuses on recursive INSERT triggers. # do_test triggerC-2.1.0 { execsql { CREATE TABLE t2(a PRIMARY KEY); } } {} foreach {n tdefn rc} { 1 { CREATE TRIGGER t2_trig AFTER INSERT ON t2 WHEN (new.a>0) BEGIN INSERT INTO t2 VALUES(new.a - 1); END; } {0 {10 9 8 7 6 5 4 3 2 1 0}} 2 { CREATE TRIGGER t2_trig AFTER INSERT ON t2 BEGIN SELECT CASE WHEN new.a==2 THEN RAISE(IGNORE) ELSE NULL END; INSERT INTO t2 VALUES(new.a - 1); END; } {0 {10 9 8 7 6 5 4 3 2}} 3 { CREATE TRIGGER t2_trig BEFORE INSERT ON t2 WHEN (new.a>0) BEGIN INSERT INTO t2 VALUES(new.a - 1); END; } {0 {0 1 2 3 4 5 6 7 8 9 10}} 4 { CREATE TRIGGER t2_trig BEFORE INSERT ON t2 BEGIN SELECT CASE WHEN new.a==2 THEN RAISE(IGNORE) ELSE NULL END; INSERT INTO t2 VALUES(new.a - 1); END; } {0 {3 4 5 6 7 8 9 10}} 5 { CREATE TRIGGER t2_trig BEFORE INSERT ON t2 BEGIN INSERT INTO t2 VALUES(new.a - 1); END; } {1 {too many levels of trigger recursion}} 6 { CREATE TRIGGER t2_trig AFTER INSERT ON t2 WHEN (new.a>0) BEGIN INSERT OR IGNORE INTO t2 VALUES(new.a); END; } {0 10} 7 { CREATE TRIGGER t2_trig BEFORE INSERT ON t2 WHEN (new.a>0) BEGIN INSERT OR IGNORE INTO t2 VALUES(new.a); END; } {1 {too many levels of trigger recursion}} } { do_test triggerC-2.1.$n { catchsql { DROP TRIGGER t2_trig } execsql { DELETE FROM t2 } execsql $tdefn catchsql { INSERT INTO t2 VALUES(10); SELECT * FROM t2; } } $rc } do_test triggerC-2.2 { execsql { CREATE TABLE t22(x); CREATE TRIGGER t22a AFTER INSERT ON t22 BEGIN INSERT INTO t22 SELECT x + (SELECT max(x) FROM t22) FROM t22; END; CREATE TRIGGER t22b BEFORE INSERT ON t22 BEGIN SELECT CASE WHEN (SELECT count(*) FROM t22) >= 100 THEN RAISE(IGNORE) ELSE NULL END; END; INSERT INTO t22 VALUES(1); SELECT count(*) FROM t22; } } {100} do_test triggerC-2.3 { execsql { CREATE TABLE t23(x PRIMARY KEY); CREATE TRIGGER t23a AFTER INSERT ON t23 BEGIN INSERT INTO t23 VALUES(new.x + 1); END; CREATE TRIGGER t23b BEFORE INSERT ON t23 BEGIN SELECT CASE WHEN new.x>500 THEN RAISE(IGNORE) ELSE NULL END; END; INSERT INTO t23 VALUES(1); SELECT count(*) FROM t23; } } {500} #----------------------------------------------------------------------- # This block of tests, triggerC-3.*, test that SQLite throws an exception # when it detects excessive recursion. # do_test triggerC-3.1.1 { execsql { CREATE TABLE t3(a, b); CREATE TRIGGER t3i AFTER INSERT ON t3 BEGIN DELETE FROM t3 WHERE rowid = new.rowid; END; CREATE TRIGGER t3d AFTER DELETE ON t3 BEGIN INSERT INTO t3 VALUES(old.a, old.b); END; } } {} do_test triggerC-3.1.2 { catchsql { INSERT INTO t3 VALUES(0,0) } } {1 {too many levels of trigger recursion}} do_test triggerC-3.1.3 { execsql { SELECT * FROM t3 } } {} do_test triggerC-3.2.1 { execsql { CREATE TABLE t3b(x); CREATE TRIGGER t3bi AFTER INSERT ON t3b WHEN new.x<2000 BEGIN INSERT INTO t3b VALUES(new.x+1); END; } catchsql { INSERT INTO t3b VALUES(1); } } {1 {too many levels of trigger recursion}} do_test triggerC-3.2.2 { db eval {SELECT * FROM t3b} } {} do_test triggerC-3.3.1 { catchsql { INSERT INTO t3b VALUES(1001); } } {0 {}} do_test triggerC-3.3.2 { db eval {SELECT count(*), max(x), min(x) FROM t3b} } {1000 2000 1001} do_test triggerC-3.4.1 { catchsql { DELETE FROM t3b; INSERT INTO t3b VALUES(999); } } {1 {too many levels of trigger recursion}} do_test triggerC-3.4.2 { db eval {SELECT count(*), max(x), min(x) FROM t3b} } {0 {} {}} do_test triggerC-3.5.1 { sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 100 catchsql { INSERT INTO t3b VALUES(1901); } } {0 {}} do_test triggerC-3.5.2 { db eval {SELECT count(*), max(x), min(x) FROM t3b} } {100 2000 1901} do_test triggerC-3.5.3 { catchsql { DELETE FROM t3b; INSERT INTO t3b VALUES(1900); } } {1 {too many levels of trigger recursion}} do_test triggerC-3.5.4 { db eval {SELECT count(*), max(x), min(x) FROM t3b} } {0 {} {}} do_test triggerC-3.6.1 { sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 1 catchsql { INSERT INTO t3b VALUES(2000); } } {0 {}} do_test triggerC-3.6.2 { db eval {SELECT count(*), max(x), min(x) FROM t3b} } {1 2000 2000} do_test triggerC-3.6.3 { catchsql { DELETE FROM t3b; INSERT INTO t3b VALUES(1999); } } {1 {too many levels of trigger recursion}} do_test triggerC-3.6.4 { db eval {SELECT count(*), max(x), min(x) FROM t3b} } {0 {} {}} sqlite3_limit db SQLITE_LIMIT_TRIGGER_DEPTH 1000 #----------------------------------------------------------------------- # This next block of tests, triggerC-4.*, checks that affinity # transformations and constraint processing is performed at the correct # times relative to BEFORE and AFTER triggers. # # For an INSERT statement, for each row to be inserted: # # 1. Apply affinities to non-rowid values to be inserted. # 2. Fire BEFORE triggers. # 3. Process constraints. # 4. Insert new record. # 5. Fire AFTER triggers. # # If the value of the rowid field is to be automatically assigned, it is # set to -1 in the new.* record. Even if it is explicitly set to NULL # by the INSERT statement. # # For an UPDATE statement, for each row to be deleted: # # 1. Apply affinities to non-rowid values to be inserted. # 2. Fire BEFORE triggers. # 3. Process constraints. # 4. Insert new record. # 5. Fire AFTER triggers. # # For a DELETE statement, for each row to be deleted: # # 1. Fire BEFORE triggers. # 2. Remove database record. # 3. Fire AFTER triggers. # # When a numeric value that as an exact integer representation is stored # in a column with REAL affinity, it is actually stored as an integer. # These tests check that the typeof() such values is always 'real', # not 'integer'. # # triggerC-4.1.*: Check that affinity transformations are made before # triggers are invoked. # do_test triggerC-4.1.1 { catchsql { DROP TABLE log } catchsql { DROP TABLE t4 } execsql { CREATE TABLE log(t); CREATE TABLE t4(a TEXT,b INTEGER,c REAL); CREATE TRIGGER t4bi BEFORE INSERT ON t4 BEGIN INSERT INTO log VALUES(new.rowid || ' ' || typeof(new.rowid) || ' ' || new.a || ' ' || typeof(new.a) || ' ' || new.b || ' ' || typeof(new.b) || ' ' || new.c || ' ' || typeof(new.c) ); END; CREATE TRIGGER t4ai AFTER INSERT ON t4 BEGIN INSERT INTO log VALUES(new.rowid || ' ' || typeof(new.rowid) || ' ' || new.a || ' ' || typeof(new.a) || ' ' || new.b || ' ' || typeof(new.b) || ' ' || new.c || ' ' || typeof(new.c) ); END; CREATE TRIGGER t4bd BEFORE DELETE ON t4 BEGIN INSERT INTO log VALUES(old.rowid || ' ' || typeof(old.rowid) || ' ' || old.a || ' ' || typeof(old.a) || ' ' || old.b || ' ' || typeof(old.b) || ' ' || old.c || ' ' || typeof(old.c) ); END; CREATE TRIGGER t4ad AFTER DELETE ON t4 BEGIN INSERT INTO log VALUES(old.rowid || ' ' || typeof(old.rowid) || ' ' || old.a || ' ' || typeof(old.a) || ' ' || old.b || ' ' || typeof(old.b) || ' ' || old.c || ' ' || typeof(old.c) ); END; CREATE TRIGGER t4bu BEFORE UPDATE ON t4 BEGIN INSERT INTO log VALUES(old.rowid || ' ' || typeof(old.rowid) || ' ' || old.a || ' ' || typeof(old.a) || ' ' || old.b || ' ' || typeof(old.b) || ' ' || old.c || ' ' || typeof(old.c) ); INSERT INTO log VALUES(new.rowid || ' ' || typeof(new.rowid) || ' ' || new.a || ' ' || typeof(new.a) || ' ' || new.b || ' ' || typeof(new.b) || ' ' || new.c || ' ' || typeof(new.c) ); END; CREATE TRIGGER t4au AFTER UPDATE ON t4 BEGIN INSERT INTO log VALUES(old.rowid || ' ' || typeof(old.rowid) || ' ' || old.a || ' ' || typeof(old.a) || ' ' || old.b || ' ' || typeof(old.b) || ' ' || old.c || ' ' || typeof(old.c) ); INSERT INTO log VALUES(new.rowid || ' ' || typeof(new.rowid) || ' ' || new.a || ' ' || typeof(new.a) || ' ' || new.b || ' ' || typeof(new.b) || ' ' || new.c || ' ' || typeof(new.c) ); END; } } {} foreach {n insert log} { 2 { INSERT INTO t4 VALUES('1', '1', '1'); DELETE FROM t4; } { -1 integer 1 text 1 integer 1.0 real 1 integer 1 text 1 integer 1.0 real 1 integer 1 text 1 integer 1.0 real 1 integer 1 text 1 integer 1.0 real } 3 { INSERT INTO t4(rowid,a,b,c) VALUES(45, 45, 45, 45); DELETE FROM t4; } { 45 integer 45 text 45 integer 45.0 real 45 integer 45 text 45 integer 45.0 real 45 integer 45 text 45 integer 45.0 real 45 integer 45 text 45 integer 45.0 real } 4 { INSERT INTO t4(rowid,a,b,c) VALUES(-42.0, -42.0, -42.0, -42.0); DELETE FROM t4; } { -42 integer -42.0 text -42 integer -42.0 real -42 integer -42.0 text -42 integer -42.0 real -42 integer -42.0 text -42 integer -42.0 real -42 integer -42.0 text -42 integer -42.0 real } 5 { INSERT INTO t4(rowid,a,b,c) VALUES(NULL, -42.4, -42.4, -42.4); DELETE FROM t4; } { -1 integer -42.4 text -42.4 real -42.4 real 1 integer -42.4 text -42.4 real -42.4 real 1 integer -42.4 text -42.4 real -42.4 real 1 integer -42.4 text -42.4 real -42.4 real } 6 { INSERT INTO t4 VALUES(7, 7, 7); UPDATE t4 SET a=8, b=8, c=8; } { -1 integer 7 text 7 integer 7.0 real 1 integer 7 text 7 integer 7.0 real 1 integer 7 text 7 integer 7.0 real 1 integer 8 text 8 integer 8.0 real 1 integer 7 text 7 integer 7.0 real 1 integer 8 text 8 integer 8.0 real } 7 { UPDATE t4 SET rowid=2; } { 1 integer 8 text 8 integer 8.0 real 2 integer 8 text 8 integer 8.0 real 1 integer 8 text 8 integer 8.0 real 2 integer 8 text 8 integer 8.0 real } 8 { UPDATE t4 SET a='9', b='9', c='9'; } { 2 integer 8 text 8 integer 8.0 real 2 integer 9 text 9 integer 9.0 real 2 integer 8 text 8 integer 8.0 real 2 integer 9 text 9 integer 9.0 real } 9 { UPDATE t4 SET a='9.1', b='9.1', c='9.1'; } { 2 integer 9 text 9 integer 9.0 real 2 integer 9.1 text 9.1 real 9.1 real 2 integer 9 text 9 integer 9.0 real 2 integer 9.1 text 9.1 real 9.1 real } } { do_test triggerC-4.1.$n { eval concat [execsql " DELETE FROM log; $insert ; SELECT * FROM log; "] } [join $log " "] } #------------------------------------------------------------------------- # This block of tests, triggerC-5.*, test that DELETE triggers are fired # if a row is deleted as a result of OR REPLACE conflict resolution. # do_test triggerC-5.1.0 { execsql { DROP TABLE IF EXISTS t5; CREATE TABLE t5(a INTEGER PRIMARY KEY, b); CREATE UNIQUE INDEX t5i ON t5(b); INSERT INTO t5 VALUES(1, 'a'); INSERT INTO t5 VALUES(2, 'b'); INSERT INTO t5 VALUES(3, 'c'); CREATE TABLE t5g(a, b, c); CREATE TRIGGER t5t BEFORE DELETE ON t5 BEGIN INSERT INTO t5g VALUES(old.a, old.b, (SELECT count(*) FROM t5)); END; } } {} foreach {n dml t5g t5} { 1 "DELETE FROM t5 WHERE a=2" {2 b 3} {1 a 3 c} 2 "INSERT OR REPLACE INTO t5 VALUES(2, 'd')" {2 b 3} {1 a 2 d 3 c} 3 "UPDATE OR REPLACE t5 SET a = 2 WHERE a = 3" {2 b 3} {1 a 2 c} 4 "INSERT OR REPLACE INTO t5 VALUES(4, 'b')" {2 b 3} {1 a 3 c 4 b} 5 "UPDATE OR REPLACE t5 SET b = 'b' WHERE b = 'c'" {2 b 3} {1 a 3 b} 6 "INSERT OR REPLACE INTO t5 VALUES(2, 'c')" {2 b 3 3 c 2} {1 a 2 c} 7 "UPDATE OR REPLACE t5 SET a=1, b='b' WHERE a = 3" {1 a 3 2 b 2} {1 b} } { do_test triggerC-5.1.$n { execsql " BEGIN; $dml ; SELECT * FROM t5g; SELECT * FROM t5; ROLLBACK; " } [concat $t5g $t5] } do_test triggerC-5.2.0 { execsql { DROP TRIGGER t5t; CREATE TRIGGER t5t AFTER DELETE ON t5 BEGIN INSERT INTO t5g VALUES(old.a, old.b, (SELECT count(*) FROM t5)); END; } } {} foreach {n dml t5g t5} { 1 "DELETE FROM t5 WHERE a=2" {2 b 2} {1 a 3 c} 2 "INSERT OR REPLACE INTO t5 VALUES(2, 'd')" {2 b 2} {1 a 2 d 3 c} 3 "UPDATE OR REPLACE t5 SET a = 2 WHERE a = 3" {2 b 2} {1 a 2 c} 4 "INSERT OR REPLACE INTO t5 VALUES(4, 'b')" {2 b 2} {1 a 3 c 4 b} 5 "UPDATE OR REPLACE t5 SET b = 'b' WHERE b = 'c'" {2 b 2} {1 a 3 b} 6 "INSERT OR REPLACE INTO t5 VALUES(2, 'c')" {2 b 2 3 c 1} {1 a 2 c} 7 "UPDATE OR REPLACE t5 SET a=1, b='b' WHERE a = 3" {1 a 2 2 b 1} {1 b} } { do_test triggerC-5.2.$n { execsql " BEGIN; $dml ; SELECT * FROM t5g; SELECT * FROM t5; ROLLBACK; " } [concat $t5g $t5] } do_test triggerC-5.3.0 { execsql { PRAGMA recursive_triggers = off } } {} foreach {n dml t5g t5} { 1 "DELETE FROM t5 WHERE a=2" {2 b 2} {1 a 3 c} 2 "INSERT OR REPLACE INTO t5 VALUES(2, 'd')" {} {1 a 2 d 3 c} 3 "UPDATE OR REPLACE t5 SET a = 2 WHERE a = 3" {} {1 a 2 c} 4 "INSERT OR REPLACE INTO t5 VALUES(4, 'b')" {} {1 a 3 c 4 b} 5 "UPDATE OR REPLACE t5 SET b = 'b' WHERE b = 'c'" {} {1 a 3 b} 6 "INSERT OR REPLACE INTO t5 VALUES(2, 'c')" {} {1 a 2 c} 7 "UPDATE OR REPLACE t5 SET a=1, b='b' WHERE a = 3" {} {1 b} } { do_test triggerC-5.3.$n { execsql " BEGIN; $dml ; SELECT * FROM t5g; SELECT * FROM t5; ROLLBACK; " } [concat $t5g $t5] } do_test triggerC-5.3.8 { execsql { PRAGMA recursive_triggers = on } } {} #------------------------------------------------------------------------- # This block of tests, triggerC-6.*, tests that "PRAGMA recursive_triggers" # statements return the current value of the recursive triggers flag. # do_test triggerC-6.1 { execsql { PRAGMA recursive_triggers } } {1} do_test triggerC-6.2 { execsql { PRAGMA recursive_triggers = off; PRAGMA recursive_triggers; } } {0} do_test triggerC-6.3 { execsql { PRAGMA recursive_triggers = on; PRAGMA recursive_triggers; } } {1} #------------------------------------------------------------------------- # Test some of the "undefined behaviour" associated with triggers. The # undefined behaviour occurs when a row being updated or deleted is # manipulated by a BEFORE trigger. # do_test triggerC-7.1 { execsql { CREATE TABLE t8(x); CREATE TABLE t7(a, b); INSERT INTO t7 VALUES(1, 2); INSERT INTO t7 VALUES(3, 4); INSERT INTO t7 VALUES(5, 6); CREATE TRIGGER t7t BEFORE UPDATE ON t7 BEGIN DELETE FROM t7 WHERE a = 1; END; CREATE TRIGGER t7ta AFTER UPDATE ON t7 BEGIN INSERT INTO t8 VALUES('after fired ' || old.rowid || '->' || new.rowid); END; } } {} do_test triggerC-7.2 { execsql { BEGIN; UPDATE t7 SET b=7 WHERE a = 5; SELECT * FROM t7; SELECT * FROM t8; ROLLBACK; } } {3 4 5 7 {after fired 3->3}} do_test triggerC-7.3 { execsql { BEGIN; UPDATE t7 SET b=7 WHERE a = 1; SELECT * FROM t7; SELECT * FROM t8; ROLLBACK; } } {3 4 5 6} do_test triggerC-7.4 { execsql { DROP TRIGGER t7t; CREATE TRIGGER t7t BEFORE UPDATE ON t7 WHEN (old.rowid!=1 OR new.rowid!=8) BEGIN UPDATE t7 set rowid = 8 WHERE rowid=1; END; } } {} do_test triggerC-7.5 { execsql { BEGIN; UPDATE t7 SET b=7 WHERE a = 5; SELECT rowid, * FROM t7; SELECT * FROM t8; ROLLBACK; } } {2 3 4 3 5 7 8 1 2 {after fired 1->8} {after fired 3->3}} do_test triggerC-7.6 { execsql { BEGIN; UPDATE t7 SET b=7 WHERE a = 1; SELECT rowid, * FROM t7; SELECT * FROM t8; ROLLBACK; } } {2 3 4 3 5 6 8 1 2 {after fired 1->8}} do_test triggerC-7.7 { execsql { DROP TRIGGER t7t; DROP TRIGGER t7ta; CREATE TRIGGER t7t BEFORE DELETE ON t7 BEGIN UPDATE t7 set rowid = 8 WHERE rowid=1; END; CREATE TRIGGER t7ta AFTER DELETE ON t7 BEGIN INSERT INTO t8 VALUES('after fired ' || old.rowid); END; } } {} do_test triggerC-7.8 { execsql { BEGIN; DELETE FROM t7 WHERE a = 3; SELECT rowid, * FROM t7; SELECT * FROM t8; ROLLBACK; } } {3 5 6 8 1 2 {after fired 2}} do_test triggerC-7.9 { execsql { BEGIN; DELETE FROM t7 WHERE a = 1; SELECT rowid, * FROM t7; SELECT * FROM t8; ROLLBACK; } } {2 3 4 3 5 6 8 1 2} # Ticket [e25d9ea771febc9c311928c1c01c3163dcb26643] # do_test triggerC-9.1 { execsql { CREATE TABLE t9(a,b); CREATE INDEX t9b ON t9(b); INSERT INTO t9 VALUES(1,0); INSERT INTO t9 VALUES(2,1); INSERT INTO t9 VALUES(3,2); INSERT INTO t9 SELECT a+3, a+2 FROM t9; INSERT INTO t9 SELECT a+6, a+5 FROM t9; SELECT a FROM t9 ORDER BY a; } } {1 2 3 4 5 6 7 8 9 10 11 12} do_test triggerC-9.2 { execsql { CREATE TRIGGER t9r1 AFTER DELETE ON t9 BEGIN DELETE FROM t9 WHERE b=old.a; END; DELETE FROM t9 WHERE b=4; SELECT a FROM t9 ORDER BY a; } } {1 2 3 4} finish_test |
Changes to test/types.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. Specfically # it tests that the different storage classes (integer, real, text etc.) # all work correctly. # | | | 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. Specfically # it tests that the different storage classes (integer, real, text etc.) # all work correctly. # # $Id: types.test,v 1.20 2009/06/29 06:00:37 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Tests in this file are organized roughly as follows: # # types-1.*.*: Test that values are stored using the expected storage |
︙ | ︙ | |||
132 133 134 135 136 137 138 139 140 141 142 143 144 145 | } # Open the table with root-page $rootpage at the btree # level. Return a list that is the length of each record # in the table, in the tables default scanning order. proc record_sizes {rootpage} { set bt [btree_open test.db 10 0] set c [btree_cursor $bt $rootpage 0] btree_first $c while 1 { lappend res [btree_payload_size $c] if {[btree_next $c]} break } btree_close_cursor $c | > | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | } # Open the table with root-page $rootpage at the btree # level. Return a list that is the length of each record # in the table, in the tables default scanning order. proc record_sizes {rootpage} { set bt [btree_open test.db 10 0] btree_begin_transaction $bt set c [btree_cursor $bt $rootpage 0] btree_first $c while 1 { lappend res [btree_payload_size $c] if {[btree_next $c]} break } btree_close_cursor $c |
︙ | ︙ |
Changes to test/vtab1.test.
︙ | ︙ | |||
1150 1151 1152 1153 1154 1155 1156 | set echo_module_fail($method,t2) "the $method method has failed" catchsql { INSERT INTO echo_t2 VALUES(7, 8, 9) } } "1 {echo-vtab-error: the $method method has failed}" unset echo_module_fail($method,t2) incr tn } | > | | | | | | > | 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 | set echo_module_fail($method,t2) "the $method method has failed" catchsql { INSERT INTO echo_t2 VALUES(7, 8, 9) } } "1 {echo-vtab-error: the $method method has failed}" unset echo_module_fail($method,t2) incr tn } ifcapable altertable { do_test vtab1-16.$tn { set echo_module_fail(xRename,t2) "the xRename method has failed" catchsql { ALTER TABLE echo_t2 RENAME TO another_name } } "1 {echo-vtab-error: the xRename method has failed}" unset echo_module_fail(xRename,t2) incr tn } unset -nocomplain echo_module_begin_fail finish_test |
Changes to test/vtab5.test.
︙ | ︙ | |||
130 131 132 133 134 135 136 | catchsql { CREATE INDEX echo_strings_i ON echo_strings(str); } } {1 {virtual tables may not be indexed}} # Test that it is impossible to add a column to a virtual table. # | > | | | | | > | 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | catchsql { CREATE INDEX echo_strings_i ON echo_strings(str); } } {1 {virtual tables may not be indexed}} # Test that it is impossible to add a column to a virtual table. # ifcapable altertable { do_test vtab5.4.2 { catchsql { ALTER TABLE echo_strings ADD COLUMN col2; } } {1 {virtual tables may not be altered}} } # Test that it is impossible to rename a virtual table. # UPDATE: It is now possible. # # do_test vtab5.4.3 { # catchsql { # ALTER TABLE echo_strings RENAME TO echo_strings2; |
︙ | ︙ |
Changes to test/vtab6.test.
︙ | ︙ | |||
10 11 12 13 14 15 16 | #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests for joins, including outer joins involving # virtual tables. The test cases in this file are copied from the file # join.test, and some of the comments still reflect that. # | | | 10 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 joins, including outer joins involving # virtual tables. The test cases in this file are copied from the file # join.test, and some of the comments still reflect that. # # $Id: vtab6.test,v 1.5 2009/07/01 16:12:08 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !vtab { finish_test return |
︙ | ︙ | |||
261 262 263 264 265 266 267 | } {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 { | < | < | | 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 | } {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 { |
︙ | ︙ | |||
490 491 492 493 494 495 496 497 498 499 500 501 502 503 | } } {1 2 3} do_test vtab6-11.2.0 { execsql { CREATE INDEX ab_i ON ab_r(b); } } {} unset ::echo_module_cost do_test vtab6-11.2.1 { execsql { | > | 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 | } } {1 2 3} do_test vtab6-11.2.0 { execsql { CREATE INDEX ab_i ON ab_r(b); CREATE INDEX bc_i ON bc_r(b); } } {} unset ::echo_module_cost do_test vtab6-11.2.1 { execsql { |
︙ | ︙ | |||
558 559 560 561 562 563 564 | set ::echo_module_ignore_usable 1 db cache flush do_test vtab6-11.4.1 { catchsql { SELECT a, b, c FROM ab NATURAL JOIN bc; } | | | 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 | set ::echo_module_ignore_usable 1 db cache flush do_test vtab6-11.4.1 { catchsql { SELECT a, b, c FROM ab NATURAL JOIN bc; } } {1 {table bc: xBestIndex returned an invalid plan}} do_test vtab6-11.4.2 { catchsql { SELECT a, b, c FROM bc NATURAL JOIN ab; } } {1 {table ab: xBestIndex returned an invalid plan}} unset ::echo_module_ignore_usable finish_test |
Changes to test/vtab_alter.test.
︙ | ︙ | |||
13 14 15 16 17 18 19 | # command on virtual tables. # # $Id: vtab_alter.test,v 1.3 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 27 | # command on virtual tables. # # $Id: vtab_alter.test,v 1.3 2007/12/13 21:54:11 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !vtab||!altertable { finish_test return } # Register the echo module. # # This test uses a special feature of the echo module. If the name |
︙ | ︙ |
Changes to test/vtab_shared.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2007 April 16 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file tests interactions between the virtual table and # shared-schema functionality. # | | | < < < < < < < < < < < | | > > | > > > | > > > > | | > > | | > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > | > > | > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 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 | # 2007 April 16 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file tests interactions between the virtual table and # shared-schema functionality. # # $Id: vtab_shared.test,v 1.3 2009/07/24 17:58:53 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !vtab||!shared_cache { finish_test return } db close sqlite3_enable_shared_cache 1 sqlite3 db test.db sqlite3 db2 test.db do_test vtab_shared-1.1 { register_echo_module [sqlite3_connection_pointer db] execsql { CREATE TABLE t0(a, b, c); INSERT INTO t0 VALUES(1, 2, 3); CREATE VIRTUAL TABLE t1 USING echo(t0); } } {} do_test vtab_shared-1.2 { execsql { SELECT * FROM t1 } db } {1 2 3} # Fails because the 'echo' module has not been registered with connection db2 do_test vtab_shared-1.3 { catchsql { SELECT * FROM t1 } db2 } {1 {no such module: echo}} do_test vtab_shared-1.4 { execsql { SELECT * FROM t0 } db2 } {1 2 3} do_test vtab_shared-1.5 { register_echo_module [sqlite3_connection_pointer db2] execsql { SELECT * FROM t1 } db } {1 2 3} # Works after the module is registered with db2 do_test vtab_shared-1.6 { execsql { SELECT * FROM t1 } db2 } {1 2 3} # Set a write-lock on table t0 using connection [db]. Then try to read from # virtual table t1 using [db2]. That this returns an SQLITE_LOCKED error # shows that the correct sqlite3_vtab is being used. # do_test vtab_shared-1.8.1 { execsql { BEGIN; INSERT INTO t1 VALUES(4, 5, 6); SELECT * FROM t1; } } {1 2 3 4 5 6} do_test vtab_shared-1.8.2 { catchsql { SELECT * FROM t1 } db2 } {1 {database table is locked}} do_test vtab_shared-1.8.3 { catchsql { SELECT * FROM t0 } db2 } {1 {database table is locked: t0}} do_test vtab_shared-1.8.4 { execsql { SELECT * FROM t0 } db } {1 2 3 4 5 6} do_test vtab_shared-1.8.5 { execsql { COMMIT } db execsql { SELECT * FROM t1 } db2 } {1 2 3 4 5 6} # While a SELECT is active on virtual table t1 via connection [db], close # [db2]. This causes the schema to be reset internally. Verify that this # does not cause a problem. # foreach {iTest dbSelect dbClose} { 1 db db2 2 db db2 3 db2 db } { do_test vtab_shared-1.9.$iTest { set res [list] $dbSelect eval { SELECT * FROM t1 } { if {$a == 1} {$dbClose close} lappend res $a $b $c } sqlite3 $dbClose test.db register_echo_module [sqlite3_connection_pointer $dbClose] set res } {1 2 3 4 5 6} } # Ensure that it is not possible for one connection to DROP a virtual # table while a second connection is reading from the database. # do_test vtab_shared-1.10 { db eval { SELECT * FROM t1 } { set error [catchsql { DROP TABLE t1 } db2] break } set error } {1 {database table is locked: sqlite_master}} do_test vtab_shared-1.11 { breakpoint execsql { CREATE VIRTUAL TABLE t2 USING echo(t0); CREATE VIRTUAL TABLE t3 USING echo(t0); } execsql { SELECT * FROM t3 } db2 } {1 2 3 4 5 6} do_test vtab_shared-1.12.1 { db close execsql { SELECT * FROM t1 UNION ALL SELECT * FROM t2 UNION ALL SELECT * FROM t3 } db2 } {1 2 3 4 5 6 1 2 3 4 5 6 1 2 3 4 5 6} do_test vtab_shared-1.12.2 { sqlite3 db test.db register_echo_module [sqlite3_connection_pointer db] execsql { SELECT * FROM t1 UNION ALL SELECT * FROM t2 UNION ALL SELECT * FROM t3 } db } {1 2 3 4 5 6 1 2 3 4 5 6 1 2 3 4 5 6} # Try a rename or two. # ifcapable altertable { do_test vtab_shared-1.13.1 { execsql { ALTER TABLE t1 RENAME TO t4 } execsql { SELECT * FROM t4 } db } {1 2 3 4 5 6} do_test vtab_shared-1.13.2 { execsql { SELECT * FROM t4 } db2 } {1 2 3 4 5 6} do_test vtab_shared-1.13.3 { execsql { ALTER TABLE t2 RENAME TO t5 } execsql { SELECT * FROM t4 } db2 } {1 2 3 4 5 6} } # Try an UPDATE/INSERT/DELETE on a shared vtab as the first statement after a # schema is loaded. do_test vtab_shared_1.14.1 { db2 close sqlite3 db2 test.db register_echo_module [sqlite3_connection_pointer db2] execsql { SELECT * FROM t3 } } {1 2 3 4 5 6} do_test vtab_shared_1.14.2 { execsql { UPDATE t3 SET c = 'six' WHERE c = 6; SELECT * FROM t3; } db2 } {1 2 3 4 5 six} do_test vtab_shared_1.14.3 { db2 close sqlite3 db2 test.db register_echo_module [sqlite3_connection_pointer db2] execsql { SELECT * FROM t3 } } {1 2 3 4 5 six} do_test vtab_shared_1.14.4 { execsql { DELETE FROM t3 WHERE c = 'six'; SELECT * FROM t3; } db2 } {1 2 3} do_test vtab_shared_1.14.5 { db2 close sqlite3 db2 test.db register_echo_module [sqlite3_connection_pointer db2] execsql { SELECT * FROM t3 } } {1 2 3} do_test vtab_shared_1.14.6 { execsql { INSERT INTO t3 VALUES(4, 5, 6); SELECT * FROM t3; } db2 } {1 2 3 4 5 6} do_test vtab_shared_1.15.1 { db2 close sqlite3 db2 test.db register_echo_module [sqlite3_connection_pointer db2] execsql { UPDATE t3 SET c = 'six' WHERE c = 6; SELECT * FROM t3; } db2 } {1 2 3 4 5 six} do_test vtab_shared_1.15.2 { db2 close sqlite3 db2 test.db register_echo_module [sqlite3_connection_pointer db2] execsql { DELETE FROM t3 WHERE c = 'six'; SELECT * FROM t3; } db2 } {1 2 3} do_test vtab_shared_1.15.3 { db2 close sqlite3 db2 test.db register_echo_module [sqlite3_connection_pointer db2] execsql { INSERT INTO t3 VALUES(4, 5, 6); SELECT * FROM t3; } } {1 2 3 4 5 6} db close db2 close sqlite3_enable_shared_cache 0 finish_test |
Changes to test/where7.test.
︙ | ︙ | |||
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | } {2 4 5 scan 0 sort 0} do_test where7-1.9 { count_steps { SELECT a FROM t1 WHERE (b=3 OR c>=10 OR c=4) } } {2 4 5 scan 0 sort 0} do_test where7-1.10 { count_steps { SELECT a FROM t1 WHERE (b=3 OR c>=10 OR c=4 OR b>10) } } {2 4 5 scan 0 sort 0} do_test where7-1.11 { count_steps { SELECT a FROM t1 WHERE (d=5 AND b=3) OR c==100 ORDER BY a; } } {2 5 scan 0 sort 1} do_test where7-1.12 { count_steps { | > > | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | } {2 4 5 scan 0 sort 0} do_test where7-1.9 { count_steps { SELECT a FROM t1 WHERE (b=3 OR c>=10 OR c=4) } } {2 4 5 scan 0 sort 0} do_test where7-1.10 { breakpoint count_steps { SELECT a FROM t1 WHERE (b=3 OR c>=10 OR c=4 OR b>10) } } {2 4 5 scan 0 sort 0} breakpoint do_test where7-1.11 { count_steps { SELECT a FROM t1 WHERE (d=5 AND b=3) OR c==100 ORDER BY a; } } {2 5 scan 0 sort 1} do_test where7-1.12 { count_steps { |
︙ | ︙ | |||
5408 5409 5410 5411 5412 5413 5414 | OR ((a BETWEEN 31 AND 33) AND a!=32) OR (d>=94.0 AND d<95.0 AND d NOT NULL) OR 1000000<b OR (f GLOB '?pqrs*' AND f GLOB 'opqr*') OR (g='rqponml' AND f GLOB 'lmnop*') OR (f GLOB '?ijkl*' AND f GLOB 'hijk*') } | | | | 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 | OR ((a BETWEEN 31 AND 33) AND a!=32) OR (d>=94.0 AND d<95.0 AND d NOT NULL) OR 1000000<b OR (f GLOB '?pqrs*' AND f GLOB 'opqr*') OR (g='rqponml' AND f GLOB 'lmnop*') OR (f GLOB '?ijkl*' AND f GLOB 'hijk*') } } {7 14 18 31 33 37 40 51 53 59 66 85 92 94 98 100 scan 0 sort 0} do_test where7-2.235.2 { count_steps_sort { SELECT a FROM t3 WHERE ((a BETWEEN 98 AND 100) AND a!=99) OR ((a BETWEEN 51 AND 53) AND a!=52) OR a=18 OR ((a BETWEEN 31 AND 33) AND a!=32) OR (d>=94.0 AND d<95.0 AND d NOT NULL) OR 1000000<b OR (f GLOB '?pqrs*' AND f GLOB 'opqr*') OR (g='rqponml' AND f GLOB 'lmnop*') OR (f GLOB '?ijkl*' AND f GLOB 'hijk*') } } {7 14 18 31 33 37 40 51 53 59 66 85 92 94 98 100 scan 0 sort 0} do_test where7-2.236.1 { count_steps_sort { SELECT a FROM t2 WHERE b=1001 OR b=168 OR (f GLOB '?ijkl*' AND f GLOB 'hijk*') OR (d>=89.0 AND d<90.0 AND d NOT NULL) |
︙ | ︙ | |||
6850 6851 6852 6853 6854 6855 6856 | OR ((a BETWEEN 37 AND 39) AND a!=38) OR ((a BETWEEN 56 AND 58) AND a!=57) OR ((a BETWEEN 18 AND 20) AND a!=19) OR (d>=45.0 AND d<46.0 AND d NOT NULL) OR (f GLOB '?ghij*' AND f GLOB 'fghi*') OR ((a BETWEEN 53 AND 55) AND a!=54) } | | | 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 | OR ((a BETWEEN 37 AND 39) AND a!=38) OR ((a BETWEEN 56 AND 58) AND a!=57) OR ((a BETWEEN 18 AND 20) AND a!=19) OR (d>=45.0 AND d<46.0 AND d NOT NULL) OR (f GLOB '?ghij*' AND f GLOB 'fghi*') OR ((a BETWEEN 53 AND 55) AND a!=54) } } {5 7 18 20 23 25 31 33 37 39 45 53 54 55 56 57 58 59 72 74 83 85 95 scan 0 sort 0} do_test where7-2.297.2 { count_steps_sort { SELECT a FROM t3 WHERE a=95 OR ((a BETWEEN 72 AND 74) AND a!=73) OR ((a BETWEEN 23 AND 25) AND a!=24) OR b=594 |
︙ | ︙ | |||
8948 8949 8950 8951 8952 8953 8954 | OR ((a BETWEEN 32 AND 34) AND a!=33) OR (f GLOB '?cdef*' AND f GLOB 'bcde*') OR b=300 OR ((a BETWEEN 24 AND 26) AND a!=25) OR (d>=21.0 AND d<22.0 AND d NOT NULL) OR ((a BETWEEN 93 AND 95) AND a!=94) } | | | 8950 8951 8952 8953 8954 8955 8956 8957 8958 8959 8960 8961 8962 8963 8964 | OR ((a BETWEEN 32 AND 34) AND a!=33) OR (f GLOB '?cdef*' AND f GLOB 'bcde*') OR b=300 OR ((a BETWEEN 24 AND 26) AND a!=25) OR (d>=21.0 AND d<22.0 AND d NOT NULL) OR ((a BETWEEN 93 AND 95) AND a!=94) } } {1 11 13 21 22 24 26 27 32 34 39 41 53 61 74 76 79 93 95 scan 0 sort 0} do_test where7-2.385.2 { count_steps_sort { SELECT a FROM t3 WHERE (d>=61.0 AND d<62.0 AND d NOT NULL) OR ((a BETWEEN 11 AND 13) AND a!=12) OR ((a BETWEEN 74 AND 76) AND a!=75) OR ((a BETWEEN 39 AND 41) AND a!=40) |
︙ | ︙ |
Changes to test/where8.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 # is testing of where.c. More specifically, the focus is the optimization # of WHERE clauses that feature the OR operator. # | | | 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 # is testing of where.c. More specifically, the focus is the optimization # of WHERE clauses that feature the OR operator. # # $Id: where8.test,v 1.9 2009/07/31 06:14:52 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Test organization: # # where8-1.*: Tests to demonstrate simple cases work with a single table |
︙ | ︙ | |||
283 284 285 286 287 288 289 | do_test where8-3.15 { execsql_status { SELECT c FROM t1, t2 WHERE a BETWEEN 1 AND 2 OR a = ( SELECT sum(e IS NULL) FROM t2 AS inner WHERE t2.d>inner.d ) } | | | 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | do_test where8-3.15 { execsql_status { SELECT c FROM t1, t2 WHERE a BETWEEN 1 AND 2 OR a = ( SELECT sum(e IS NULL) FROM t2 AS inner WHERE t2.d>inner.d ) } } {I II I II I II I II I II I II III I II III I II III I II III I II III 9 0} #----------------------------------------------------------------------- # The following tests - where8-4.* - verify that adding or removing # indexes does not change the results returned by various queries. # do_test where8-4.1 { execsql { |
︙ | ︙ | |||
649 650 651 652 653 654 655 | list } {} do_test where8-4.$A.$B.2 { lsort $R } [lsort $results($B)] } incr A } | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | list } {} do_test where8-4.$A.$B.2 { lsort $R } [lsort $results($B)] } incr A } catch {unset results} catch {unset A} catch {unset B} # At one point the following tests provoked an invalid write error (writing # to memory that had already been freed). It was not possible to demonstrate # that this bug could cause a query to return bad data. # do_test where8-5.1 { db close sqlite3 db test.db sqlite3_db_config_lookaside db 0 0 0 execsql { CREATE TABLE tA( a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p ); } execsql { SELECT * FROM tA WHERE a=1 AND b=2 AND c=3 AND d=4 AND e=5 AND f=6 AND g=7 AND h=8 AND i=1 AND j=2 AND k=3 AND l=4 AND m=5 AND n=6 AND o=7 AND (p = 1 OR p = 2 OR p = 3) } } {} do_test where8-5.2 { execsql { SELECT * FROM tA WHERE a=1 AND b=2 AND c=3 AND d=4 AND e=5 AND f=6 AND g=7 AND h=8 AND i=1 AND j=2 AND k=3 AND l=4 AND m=5 AND (p = 1 OR p = 2 OR p = 3) AND n=6 AND o=7 } } {} do_test where8-5.3 { execsql { INSERT INTO tA VALUES(1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8); CREATE UNIQUE INDEX tAI ON tA(p); CREATE TABLE tB(x); INSERT INTO tB VALUES('x'); } execsql { SELECT a, x FROM tA LEFT JOIN tB ON ( a=1 AND b=2 AND c=3 AND d=4 AND e=5 AND f=6 AND g=7 AND h=8 AND i=1 AND j=2 AND k=3 AND l=4 AND m=5 AND n=6 AND o=7 AND (p = 1 OR p = 2 OR p = 3) ) } } {1 {}} finish_test |
Added test/whereB.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 | # 2009 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 regression tests for SQLite library. The # focus of this file is testing WHERE clause conditions with # subtle affinity issues. # set testdir [file dirname $argv0] source $testdir/tester.tcl # For this set of tests: # # * t1.y holds an integer value with affinity NONE # * t2.b holds a text value with affinity TEXT # # These values are not equal and because neither affinity is NUMERIC # no type conversion occurs. # do_test whereB-1.1 { db eval { CREATE TABLE t1(x,y); -- affinity of t1.y is NONE INSERT INTO t1 VALUES(1,99); CREATE TABLE t2(a, b TEXT); -- affinity of t2.b is TEXT CREATE INDEX t2b ON t2(b); INSERT INTO t2 VALUES(2,99); SELECT x, a, y=b FROM t1, t2 ORDER BY +x, +a; } } {1 2 0} do_test whereB-1.2 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE y=b; } } {} do_test whereB-1.3 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE b=y; } } {} do_test whereB-1.4 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE +y=+b; } } {} do_test whereB-1.100 { db eval { DROP INDEX t2b; SELECT x, a, y=b FROM t1, t2 WHERE y=b; } } {} do_test whereB-1.101 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE b=y; } } {} do_test whereB-1.102 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE +y=+b; } } {} # For this set of tests: # # * t1.y holds a text value with affinity TEXT # * t2.b holds an integer value with affinity NONE # # These values are not equal and because neither affinity is NUMERIC # no type conversion occurs. # do_test whereB-2.1 { db eval { DROP TABLE t1; DROP TABLE t2; CREATE TABLE t1(x, y TEXT); -- affinity of t1.y is TEXT INSERT INTO t1 VALUES(1,99); CREATE TABLE t2(a, b BLOB); -- affinity of t2.b is NONE CREATE INDEX t2b ON t2(b); INSERT INTO t2 VALUES(2,99); SELECT x, a, y=b FROM t1, t2 ORDER BY +x, +a; } } {1 2 0} do_test whereB-2.2 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE y=b; } } {} do_test whereB-2.3 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE b=y; } } {} do_test whereB-2.4 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE +y=+b; } } {} do_test whereB-2.100 { db eval { DROP INDEX t2b; SELECT x, a, y=b FROM t1, t2 WHERE y=b; } } {} do_test whereB-2.101 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE b=y; } } {} do_test whereB-2.102 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE +y=+b; } } {} # For this set of tests: # # * t1.y holds a text value with affinity NONE # * t2.b holds an integer value with affinity NONE # # These values are not equal and because neither affinity is NUMERIC # no type conversion occurs. # do_test whereB-3.1 { db eval { DROP TABLE t1; DROP TABLE t2; CREATE TABLE t1(x, y BLOB); -- affinity of t1.y is NONE INSERT INTO t1 VALUES(1,99); CREATE TABLE t2(a, b BLOB); -- affinity of t2.b is NONE CREATE INDEX t2b ON t2(b); INSERT INTO t2 VALUES(2,'99'); SELECT x, a, y=b FROM t1, t2; } } {1 2 0} do_test whereB-3.2 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE y=b; } } {} do_test whereB-3.3 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE b=y; } } {} do_test whereB-3.4 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE +y=+b; } } {} do_test whereB-3.100 { db eval { DROP INDEX t2b; SELECT x, a, y=b FROM t1, t2 WHERE y=b; } } {} do_test whereB-3.101 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE b=y; } } {} do_test whereB-3.102 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE +y=+b; } } {} # For this set of tests: # # * t1.y holds a text value with affinity NONE # * t2.b holds an integer value with affinity NUMERIC # # Because t2.b has a numeric affinity, type conversion should occur # and the two fields should be equal. # do_test whereB-4.1 { db eval { DROP TABLE t1; DROP TABLE t2; CREATE TABLE t1(x, y BLOB); -- affinity of t1.y is NONE INSERT INTO t1 VALUES(1,'99'); CREATE TABLE t2(a, b NUMERIC); -- affinity of t2.b is NUMERIC CREATE INDEX t2b ON t2(b); INSERT INTO t2 VALUES(2,99); SELECT x, a, y=b FROM t1, t2; } } {1 2 1} do_test whereB-4.2 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE y=b; } } {1 2 1} do_test whereB-4.3 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE b=y; } } {1 2 1} do_test whereB-4.4 { # In this case the unary "+" operator removes the column affinity so # the columns compare false db eval { SELECT x, a, y=b FROM t1, t2 WHERE +y=+b; } } {} do_test whereB-4.100 { db eval { DROP INDEX t2b; SELECT x, a, y=b FROM t1, t2 WHERE y=b; } } {1 2 1} do_test whereB-4.101 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE b=y; } } {1 2 1} do_test whereB-4.102 { # In this case the unary "+" operator removes the column affinity so # the columns compare false db eval { SELECT x, a, y=b FROM t1, t2 WHERE +y=+b; } } {} # For this set of tests: # # * t1.y holds a text value with affinity NONE # * t2.b holds an integer value with affinity INTEGER # # Because t2.b has a numeric affinity, type conversion should occur # and the two fields should be equal. # do_test whereB-5.1 { db eval { DROP TABLE t1; DROP TABLE t2; CREATE TABLE t1(x, y BLOB); -- affinity of t1.y is NONE INSERT INTO t1 VALUES(1,'99'); CREATE TABLE t2(a, b INT); -- affinity of t2.b is INTEGER CREATE INDEX t2b ON t2(b); INSERT INTO t2 VALUES(2,99); SELECT x, a, y=b FROM t1, t2; } } {1 2 1} do_test whereB-5.2 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE y=b; } } {1 2 1} do_test whereB-5.3 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE b=y; } } {1 2 1} do_test whereB-5.4 { # In this case the unary "+" operator removes the column affinity so # the columns compare false db eval { SELECT x, a, y=b FROM t1, t2 WHERE +y=+b; } } {} do_test whereB-5.100 { db eval { DROP INDEX t2b; SELECT x, a, y=b FROM t1, t2 WHERE y=b; } } {1 2 1} do_test whereB-5.101 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE b=y; } } {1 2 1} do_test whereB-5.102 { # In this case the unary "+" operator removes the column affinity so # the columns compare false db eval { SELECT x, a, y=b FROM t1, t2 WHERE +y=+b; } } {} # For this set of tests: # # * t1.y holds a text value with affinity NONE # * t2.b holds an integer value with affinity REAL # # Because t2.b has a numeric affinity, type conversion should occur # and the two fields should be equal. # do_test whereB-6.1 { db eval { DROP TABLE t1; DROP TABLE t2; CREATE TABLE t1(x, y BLOB); -- affinity of t1.y is NONE INSERT INTO t1 VALUES(1,'99'); CREATE TABLE t2(a, b REAL); -- affinity of t2.b is REAL CREATE INDEX t2b ON t2(b); INSERT INTO t2 VALUES(2,99.0); SELECT x, a, y=b FROM t1, t2; } } {1 2 1} do_test whereB-6.2 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE y=b; } } {1 2 1} do_test whereB-6.3 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE b=y; } } {1 2 1} do_test whereB-6.4 { # In this case the unary "+" operator removes the column affinity so # the columns compare false db eval { SELECT x, a, y=b FROM t1, t2 WHERE +y=+b; } } {} do_test whereB-6.100 { db eval { DROP INDEX t2b; SELECT x, a, y=b FROM t1, t2 WHERE y=b; } } {1 2 1} do_test whereB-6.101 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE b=y; } } {1 2 1} do_test whereB-6.102 { # In this case the unary "+" operator removes the column affinity so # the columns compare false db eval { SELECT x, a, y=b FROM t1, t2 WHERE +y=+b; } } {} # For this set of tests: # # * t1.y holds an integer value with affinity NUMERIC # * t2.b holds a text value with affinity NONE # # Because t1.y has a numeric affinity, type conversion should occur # and the two fields should be equal. # do_test whereB-7.1 { db eval { DROP TABLE t1; DROP TABLE t2; CREATE TABLE t1(x, y NUMERIC); -- affinity of t1.y is NUMERIC INSERT INTO t1 VALUES(1,99); CREATE TABLE t2(a, b BLOB); -- affinity of t2.b is NONE CREATE INDEX t2b ON t2(b); INSERT INTO t2 VALUES(2,'99'); SELECT x, a, y=b FROM t1, t2; } } {1 2 1} do_test whereB-7.2 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE y=b; } } {1 2 1} do_test whereB-7.3 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE b=y; } } {1 2 1} do_test whereB-7.4 { # In this case the unary "+" operator removes the column affinity so # the columns compare false db eval { SELECT x, a, y=b FROM t1, t2 WHERE +y=+b; } } {} do_test whereB-7.100 { db eval { DROP INDEX t2b; SELECT x, a, y=b FROM t1, t2 WHERE y=b; } } {1 2 1} do_test whereB-7.101 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE b=y; } } {1 2 1} do_test whereB-7.102 { # In this case the unary "+" operator removes the column affinity so # the columns compare false db eval { SELECT x, a, y=b FROM t1, t2 WHERE +y=+b; } } {} # For this set of tests: # # * t1.y holds an integer value with affinity INTEGER # * t2.b holds a text value with affinity NONE # # Because t1.y has a numeric affinity, type conversion should occur # and the two fields should be equal. # do_test whereB-8.1 { db eval { DROP TABLE t1; DROP TABLE t2; CREATE TABLE t1(x, y INT); -- affinity of t1.y is INTEGER INSERT INTO t1 VALUES(1,99); CREATE TABLE t2(a, b BLOB); -- affinity of t2.b is NONE CREATE INDEX t2b ON t2(b); INSERT INTO t2 VALUES(2,'99'); SELECT x, a, y=b FROM t1, t2; } } {1 2 1} do_test whereB-8.2 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE y=b; } } {1 2 1} do_test whereB-8.3 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE b=y; } } {1 2 1} do_test whereB-8.4 { # In this case the unary "+" operator removes the column affinity so # the columns compare false db eval { SELECT x, a, y=b FROM t1, t2 WHERE +y=+b; } } {} do_test whereB-8.100 { db eval { DROP INDEX t2b; SELECT x, a, y=b FROM t1, t2 WHERE y=b; } } {1 2 1} do_test whereB-8.101 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE b=y; } } {1 2 1} do_test whereB-8.102 { # In this case the unary "+" operator removes the column affinity so # the columns compare false db eval { SELECT x, a, y=b FROM t1, t2 WHERE +y=+b; } } {} # For this set of tests: # # * t1.y holds an integer value with affinity REAL # * t2.b holds a text value with affinity NONE # # Because t1.y has a numeric affinity, type conversion should occur # and the two fields should be equal. # do_test whereB-9.1 { db eval { DROP TABLE t1; DROP TABLE t2; CREATE TABLE t1(x, y REAL); -- affinity of t1.y is REAL INSERT INTO t1 VALUES(1,99.0); CREATE TABLE t2(a, b BLOB); -- affinity of t2.b is NONE CREATE INDEX t2b ON t2(b); INSERT INTO t2 VALUES(2,'99'); SELECT x, a, y=b FROM t1, t2; } } {1 2 1} do_test whereB-9.2 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE y=b; } } {1 2 1} do_test whereB-9.3 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE b=y; } } {1 2 1} do_test whereB-9.4 { # In this case the unary "+" operator removes the column affinity so # the columns compare false db eval { SELECT x, a, y=b FROM t1, t2 WHERE +y=+b; } } {} do_test whereB-9.100 { db eval { DROP INDEX t2b; SELECT x, a, y=b FROM t1, t2 WHERE y=b; } } {1 2 1} do_test whereB-9.101 { db eval { SELECT x, a, y=b FROM t1, t2 WHERE b=y; } } {1 2 1} do_test whereB-9.102 { # In this case the unary "+" operator removes the column affinity so # the columns compare false db eval { SELECT x, a, y=b FROM t1, t2 WHERE +y=+b; } } {} finish_test |
Changes to test/zeroblob.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing of the zero-filled blob functionality # including the sqlite3_bind_zeroblob(), sqlite3_result_zeroblob(), # and the built-in zeroblob() SQL function. # | | | 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 zero-filled blob functionality # including the sqlite3_bind_zeroblob(), sqlite3_result_zeroblob(), # and the built-in zeroblob() SQL function. # # $Id: zeroblob.test,v 1.14 2009/07/14 02:33:02 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !incrblob { finish_test return |
︙ | ︙ | |||
222 223 224 225 226 227 228 229 230 | # do_test zeroblob-8.1 { llength [execsql { SELECT 'hello' AS a, zeroblob(10) as b from t1 ORDER BY a, b; }] } {8} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | # do_test zeroblob-8.1 { llength [execsql { SELECT 'hello' AS a, zeroblob(10) as b from t1 ORDER BY a, b; }] } {8} # Ticket #3965 # zeroblobs on either size of an IN operator # do_test zeroblob-9.1 { db eval {SELECT x'0000' IN (x'000000')} } {0} do_test zeroblob-9.2 { db eval {SELECT x'0000' IN (x'0000')} } {1} do_test zeroblob-9.3 { db eval {SELECT zeroblob(2) IN (x'000000')} } {0} do_test zeroblob-9.4 { db eval {SELECT zeroblob(2) IN (x'0000')} } {1} do_test zeroblob-9.5 { db eval {SELECT x'0000' IN (zeroblob(3))} } {0} do_test zeroblob-9.6 { db eval {SELECT x'0000' IN (zeroblob(2))} } {1} do_test zeroblob-9.7 { db eval {SELECT zeroblob(2) IN (zeroblob(3))} } {0} do_test zeroblob-9.8 { db eval {SELECT zeroblob(2) IN (zeroblob(2))} } {1} finish_test |
Changes to tool/genfkey.test.
︙ | ︙ | |||
287 288 289 290 291 292 293 294 | } {1 {constraint failed}} do_test genfkey-5.5 { catchsql { INSERT INTO "t.3" VALUES(1); INSERT INTO t13 VALUES(1); } } {0 {}} | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } {1 {constraint failed}} do_test genfkey-5.5 { catchsql { INSERT INTO "t.3" VALUES(1); INSERT INTO t13 VALUES(1); } } {0 {}} # Test also column names that require quoting. do_test genfkey-6.1 { execsql { DROP TABLE "t.3"; DROP TABLE t13; CREATE TABLE p( "a.1 first", "b.2 second", UNIQUE("a.1 first", "b.2 second") ); CREATE TABLE c( "c.1 I", "d.2 II", FOREIGN KEY("c.1 I", "d.2 II") REFERENCES p("a.1 first", "b.2 second") ON UPDATE CASCADE ON DELETE CASCADE ); } } {} do_test genfkey-6.2 { set rc [catch {exec ./sqlite3 test.db .genfkey} msg] } {0} do_test genfkey-6.3 { execsql $msg execsql { INSERT INTO p VALUES('A', 'B'); INSERT INTO p VALUES('C', 'D'); INSERT INTO c VALUES('A', 'B'); INSERT INTO c VALUES('C', 'D'); UPDATE p SET "a.1 first" = 'X' WHERE rowid = 1; DELETE FROM p WHERE rowid = 2; } execsql { SELECT * FROM c } } {X B} do_test genfkey-6.4 { execsql { DROP TABLE p; DROP TABLE c; CREATE TABLE parent("a.1", PRIMARY KEY("a.1")); CREATE TABLE child("b.2", FOREIGN KEY("b.2") REFERENCES parent("a.1")); } set rc [catch {exec ./sqlite3 test.db .genfkey} msg] } {0} do_test genfkey-6.5 { execsql $msg execsql { INSERT INTO parent VALUES(1); INSERT INTO child VALUES(1); } catchsql { UPDATE parent SET "a.1"=0 } } {1 {constraint failed}} do_test genfkey-6.6 { catchsql { UPDATE child SET "b.2"=7 } } {1 {constraint failed}} do_test genfkey-6.7 { execsql { SELECT * FROM parent; SELECT * FROM child; } } {1 1} |
Changes to tool/lemon.c.
︙ | ︙ | |||
365 366 367 368 369 370 371 372 373 374 375 376 377 378 | rc = ap1->sp->index - ap2->sp->index; if( rc==0 ){ rc = (int)ap1->type - (int)ap2->type; } if( rc==0 && ap1->type==REDUCE ){ rc = ap1->x.rp->index - ap2->x.rp->index; } return rc; } /* Sort parser actions */ static struct action *Action_sort( struct action *ap ){ | > > > | 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 | rc = ap1->sp->index - ap2->sp->index; if( rc==0 ){ rc = (int)ap1->type - (int)ap2->type; } if( rc==0 && ap1->type==REDUCE ){ rc = ap1->x.rp->index - ap2->x.rp->index; } if( rc==0 ){ rc = ap2 - ap1; } return rc; } /* Sort parser actions */ static struct action *Action_sort( struct action *ap ){ |
︙ | ︙ | |||
513 514 515 516 517 518 519 | /* Scan the existing action table looking for an offset where we can ** insert the current transaction set. Fall out of the loop when that ** offset is found. In the worst case, we fall out of the loop when ** i reaches p->nAction, which means we append the new transaction set. ** ** i is the index in p->aAction[] where p->mnLookahead is inserted. */ | < < < < < < < < < < < | | < | > > > > > > > > > > > > > > > > > > > | 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 | /* Scan the existing action table looking for an offset where we can ** insert the current transaction set. Fall out of the loop when that ** offset is found. In the worst case, we fall out of the loop when ** i reaches p->nAction, which means we append the new transaction set. ** ** i is the index in p->aAction[] where p->mnLookahead is inserted. */ for(i=p->nAction-1; i>=0; i--){ /* First look for an existing action table entry that can be reused */ if( p->aAction[i].lookahead==p->mnLookahead ){ if( p->aAction[i].action!=p->mnAction ) continue; for(j=0; j<p->nLookahead; j++){ k = p->aLookahead[j].lookahead - p->mnLookahead + i; if( k<0 || k>=p->nAction ) break; if( p->aLookahead[j].lookahead!=p->aAction[k].lookahead ) break; if( p->aLookahead[j].action!=p->aAction[k].action ) break; } if( j<p->nLookahead ) continue; n = 0; for(j=0; j<p->nAction; j++){ if( p->aAction[j].lookahead<0 ) continue; if( p->aAction[j].lookahead==j+p->mnLookahead-i ) n++; } if( n==p->nLookahead ){ break; /* Same as a prior transaction set */ } } } if( i<0 ){ /* If no reusable entry is found, look for an empty slot */ for(i=0; i<p->nAction; i++){ if( p->aAction[i].lookahead<0 ){ for(j=0; j<p->nLookahead; j++){ k = p->aLookahead[j].lookahead - p->mnLookahead + i; if( k<0 ) break; if( p->aAction[k].lookahead>=0 ) break; } if( j<p->nLookahead ) continue; for(j=0; j<p->nAction; j++){ if( p->aAction[j].lookahead==j+p->mnLookahead-i ) break; } if( j==p->nAction ){ break; /* Fits in empty slots */ } } } } /* Insert transaction set at index i. */ for(j=0; j<p->nLookahead; j++){ k = p->aLookahead[j].lookahead - p->mnLookahead + i; p->aAction[k] = p->aLookahead[j]; if( k>=p->nAction ) p->nAction = k+1; } |
︙ | ︙ | |||
1574 1575 1576 1577 1578 1579 1580 | char *ptr, *head; if( a==0 ){ head = b; }else if( b==0 ){ head = a; }else{ | | | | 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 | char *ptr, *head; if( a==0 ){ head = b; }else if( b==0 ){ head = a; }else{ if( (*cmp)(a,b)<=0 ){ ptr = a; a = NEXT(a); }else{ ptr = b; b = NEXT(b); } head = ptr; while( a && b ){ if( (*cmp)(a,b)<=0 ){ NEXT(ptr) = a; ptr = a; a = NEXT(a); }else{ NEXT(ptr) = b; ptr = b; b = NEXT(b); |
︙ | ︙ | |||
1635 1636 1637 1638 1639 1640 1641 | for(i=0; i<LISTSIZE-1 && set[i]!=0; i++){ ep = merge(ep,set[i],cmp,offset); set[i] = 0; } set[i] = ep; } ep = 0; | | | 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 | for(i=0; i<LISTSIZE-1 && set[i]!=0; i++){ ep = merge(ep,set[i],cmp,offset); set[i] = 0; } 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; |
︙ | ︙ | |||
3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 | ** of the following structure. An array of these structures is used ** to order the creation of entries in the yy_action[] table. */ struct axset { struct state *stp; /* A pointer to a state */ int isTkn; /* True to use tokens. False for non-terminals */ int nAction; /* Number of actions */ }; /* ** Compare to axset structures for sorting purposes */ static int axset_compare(const void *a, const void *b){ struct axset *p1 = (struct axset*)a; struct axset *p2 = (struct axset*)b; | > > | > > > > > | 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 | ** of the following structure. An array of these structures is used ** to order the creation of entries in the yy_action[] table. */ struct axset { struct state *stp; /* A pointer to a state */ int isTkn; /* True to use tokens. False for non-terminals */ int nAction; /* Number of actions */ int iOrder; /* Original order of action sets */ }; /* ** Compare to axset structures for sorting purposes */ static int axset_compare(const void *a, const void *b){ struct axset *p1 = (struct axset*)a; struct axset *p2 = (struct axset*)b; int c; c = p2->nAction - p1->nAction; if( c==0 ){ c = p2->iOrder - p1->iOrder; } assert( c!=0 || p1==p2 ); return c; } /* ** Write text on "out" that describes the rule "rp". */ static void writeRuleText(FILE *out, struct rule *rp){ int j; |
︙ | ︙ | |||
3554 3555 3556 3557 3558 3559 3560 | FILE *out, *in; char line[LINESIZE]; int lineno; struct state *stp; struct action *ap; struct rule *rp; struct acttab *pActtab; | | | 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 | FILE *out, *in; char line[LINESIZE]; int lineno; struct state *stp; struct action *ap; struct rule *rp; struct acttab *pActtab; int i, j, k, n; char *name; int mnTknOfst, mxTknOfst; int mnNtOfst, mxNtOfst; struct axset *ax; in = tplt_open(lemp); if( in==0 ) return; |
︙ | ︙ | |||
3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 | mxTknOfst = mnTknOfst = 0; mxNtOfst = mnNtOfst = 0; /* Compute the action table. In order to try to keep the size of the ** action table to a minimum, the heuristic of placing the largest action ** sets first is used. */ qsort(ax, lemp->nstate*2, sizeof(ax[0]), axset_compare); pActtab = acttab_alloc(); for(i=0; i<lemp->nstate*2 && ax[i].nAction>0; i++){ stp = ax[i].stp; if( ax[i].isTkn ){ for(ap=stp->ap; ap; ap=ap->next){ int action; | > | 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 | mxTknOfst = mnTknOfst = 0; mxNtOfst = mnNtOfst = 0; /* Compute the action table. In order to try to keep the size of the ** action table to a minimum, the heuristic of placing the largest action ** sets first is used. */ for(i=0; i<lemp->nstate*2; i++) ax[i].iOrder = i; qsort(ax, lemp->nstate*2, sizeof(ax[0]), axset_compare); pActtab = acttab_alloc(); for(i=0; i<lemp->nstate*2 && ax[i].nAction>0; i++){ stp = ax[i].stp; if( ax[i].isTkn ){ for(ap=stp->ap; ap; ap=ap->next){ int action; |
︙ | ︙ | |||
3712 3713 3714 3715 3716 3717 3718 | if( stp->iNtOfst<mnNtOfst ) mnNtOfst = stp->iNtOfst; if( stp->iNtOfst>mxNtOfst ) mxNtOfst = stp->iNtOfst; } } free(ax); /* Output the yy_action table */ | < > > | 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 | if( stp->iNtOfst<mnNtOfst ) mnNtOfst = stp->iNtOfst; if( stp->iNtOfst>mxNtOfst ) mxNtOfst = stp->iNtOfst; } } free(ax); /* Output the yy_action table */ n = acttab_size(pActtab); fprintf(out,"#define YY_ACTTAB_COUNT (%d)\n", n); lineno++; fprintf(out,"static const YYACTIONTYPE yy_action[] = {\n"); lineno++; for(i=j=0; i<n; i++){ int action = acttab_yyaction(pActtab, i); if( action<0 ) action = lemp->nstate + lemp->nrule + 2; if( j==0 ) fprintf(out," /* %5d */ ", i); fprintf(out, " %4d,", action); if( j==9 || i==n-1 ){ fprintf(out, "\n"); lineno++; |
︙ | ︙ | |||
3748 3749 3750 3751 3752 3753 3754 | } fprintf(out, "};\n"); lineno++; /* Output the yy_shift_ofst[] table */ fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++; n = lemp->nstate; while( n>0 && lemp->sorted[n-1]->iTknOfst==NO_OFFSET ) n--; | > > | | 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 | } fprintf(out, "};\n"); lineno++; /* Output the yy_shift_ofst[] table */ fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++; n = lemp->nstate; 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++; fprintf(out, "#define YY_SHIFT_MAX (%d)\n", mxTknOfst); lineno++; fprintf(out, "static const %s yy_shift_ofst[] = {\n", minimum_size_type(mnTknOfst-1, mxTknOfst)); lineno++; for(i=j=0; i<n; i++){ int ofst; stp = lemp->sorted[i]; ofst = stp->iTknOfst; if( ofst==NO_OFFSET ) ofst = mnTknOfst - 1; |
︙ | ︙ | |||
3771 3772 3773 3774 3775 3776 3777 | } fprintf(out, "};\n"); lineno++; /* Output the yy_reduce_ofst[] table */ fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++; n = lemp->nstate; while( n>0 && lemp->sorted[n-1]->iNtOfst==NO_OFFSET ) n--; | > > | | 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 | } fprintf(out, "};\n"); lineno++; /* Output the yy_reduce_ofst[] table */ fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++; n = lemp->nstate; while( n>0 && lemp->sorted[n-1]->iNtOfst==NO_OFFSET ) n--; fprintf(out, "#define YY_REDUCE_COUNT (%d)\n", n-1); lineno++; fprintf(out, "#define YY_REDUCE_MIN (%d)\n", mnNtOfst); lineno++; fprintf(out, "#define YY_REDUCE_MAX (%d)\n", mxNtOfst); lineno++; fprintf(out, "static const %s yy_reduce_ofst[] = {\n", minimum_size_type(mnNtOfst-1, mxNtOfst)); lineno++; for(i=j=0; i<n; i++){ int ofst; stp = lemp->sorted[i]; ofst = stp->iNtOfst; if( ofst==NO_OFFSET ) ofst = mnNtOfst - 1; |
︙ | ︙ | |||
4093 4094 4095 4096 4097 4098 4099 | const struct state *pA = *(const struct state**)a; const struct state *pB = *(const struct state**)b; int n; n = pB->nNtAct - pA->nNtAct; if( n==0 ){ n = pB->nTknAct - pA->nTknAct; | > > | > > | 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 | const struct state *pA = *(const struct state**)a; const struct state *pB = *(const struct state**)b; int n; n = pB->nNtAct - pA->nNtAct; if( n==0 ){ n = pB->nTknAct - pA->nTknAct; if( n==0 ){ n = pB->statenum - pA->statenum; } } assert( n!=0 ); return n; } /* ** Renumber and resort states so that states with fewer choices ** occur at the end. Except, keep state 0 as the first state. |
︙ | ︙ | |||
4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 | ** We find experimentally that leaving the symbols in their original ** order (the order they appeared in the grammar file) gives the ** smallest parser tables in SQLite. */ int Symbolcmpp(struct symbol **a, struct symbol **b){ int i1 = (**a).index + 10000000*((**a).name[0]>'Z'); int i2 = (**b).index + 10000000*((**b).name[0]>'Z'); return i1-i2; } /* There is one instance of the following structure for each ** associative array of type "x2". */ struct s_x2 { | > | 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 | ** We find experimentally that leaving the symbols in their original ** order (the order they appeared in the grammar file) gives the ** smallest parser tables in SQLite. */ int Symbolcmpp(struct symbol **a, struct symbol **b){ int i1 = (**a).index + 10000000*((**a).name[0]>'Z'); int i2 = (**b).index + 10000000*((**b).name[0]>'Z'); assert( i1!=i2 || strcmp((**a).name,(**b).name)==0 ); return i1-i2; } /* There is one instance of the following structure for each ** associative array of type "x2". */ struct s_x2 { |
︙ | ︙ |
Changes to tool/lempar.c.
︙ | ︙ | |||
121 122 123 124 125 126 127 | ** yy_shift_ofst[] For each state, the offset into yy_action for ** shifting terminals. ** yy_reduce_ofst[] For each state, the offset into yy_action for ** shifting non-terminals after a reduce. ** yy_default[] Default action for each state. */ %% | < | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | ** yy_shift_ofst[] For each state, the offset into yy_action for ** shifting terminals. ** yy_reduce_ofst[] For each state, the offset into yy_action for ** shifting non-terminals after a reduce. ** yy_default[] Default action for each state. */ %% /* The next table maps tokens into fallback tokens. If a construct ** like the following: ** ** %fallback ID X Y Z. ** ** appears in the grammar, then ID becomes a fallback token for X, Y, |
︙ | ︙ | |||
382 383 384 385 386 387 388 | static int yy_find_shift_action( yyParser *pParser, /* The parser */ YYCODETYPE iLookAhead /* The look-ahead token */ ){ int i; int stateno = pParser->yystack[pParser->yyidx].stateno; | > | | > > > > > > > | > | 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 | static int yy_find_shift_action( yyParser *pParser, /* The parser */ YYCODETYPE iLookAhead /* The look-ahead token */ ){ int i; int stateno = pParser->yystack[pParser->yyidx].stateno; if( stateno>YY_SHIFT_COUNT || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){ return yy_default[stateno]; } assert( iLookAhead!=YYNOCODE ); i += iLookAhead; if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ if( iLookAhead>0 ){ #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 return yy_find_shift_action(pParser, iFallback); } #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 yy_lookahead[j]==YYWILDCARD ){ #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]); } #endif /* NDEBUG */ return yy_action[j]; |
︙ | ︙ | |||
437 438 439 440 441 442 443 | */ static int yy_find_reduce_action( int stateno, /* Current state number */ YYCODETYPE iLookAhead /* The look-ahead token */ ){ int i; #ifdef YYERRORSYMBOL | | | | | | 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 | */ static int yy_find_reduce_action( int stateno, /* Current state number */ YYCODETYPE iLookAhead /* The look-ahead token */ ){ int i; #ifdef YYERRORSYMBOL if( stateno>YY_REDUCE_COUNT ){ return yy_default[stateno]; } #else assert( stateno<=YY_REDUCE_COUNT ); #endif i = yy_reduce_ofst[stateno]; assert( i!=YY_REDUCE_USE_DFLT ); assert( iLookAhead!=YYNOCODE ); i += iLookAhead; #ifdef YYERRORSYMBOL if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ return yy_default[stateno]; } #else assert( i>=0 && i<YY_ACTTAB_COUNT ); assert( yy_lookahead[i]==iLookAhead ); #endif return yy_action[i]; } /* ** The following routine is called if the stack overflows. |
︙ | ︙ |
Changes to tool/mkkeywordhash.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 | ** A header comment placed at the beginning of generated code. */ static const char zHdr[] = "/***** This file contains automatically generated code ******\n" "**\n" "** The code in this file has been automatically generated by\n" "**\n" | | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ** A header comment placed at the beginning of generated code. */ static const char zHdr[] = "/***** This file contains automatically generated code ******\n" "**\n" "** The code in this file has been automatically generated by\n" "**\n" "** sqlite/tool/mkkeywordhash.c\n" "**\n" "** The code in this file implements a function that determines whether\n" "** or not a given identifier is really an SQL keyword. The same thing\n" "** might be implemented more directly using a hand-written hash table.\n" "** But by using this automatically generated code, the size of the code\n" "** is substantially reduced. This is important for embedded applications\n" "** on platforms with limited memory.\n" |
︙ | ︙ | |||
140 141 142 143 144 145 146 147 148 149 150 151 152 153 | #endif /* ** These are the keywords */ static Keyword aKeywordTable[] = { { "ABORT", "TK_ABORT", CONFLICT|TRIGGER }, { "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 }, | > | 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | #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 }, |
︙ | ︙ | |||
214 215 216 217 218 219 220 221 222 223 224 225 226 227 | { "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 }, { "NOT", "TK_NOT", ALWAYS }, { "NOTNULL", "TK_NOTNULL", ALWAYS }, { "NULL", "TK_NULL", ALWAYS }, { "OF", "TK_OF", ALWAYS }, { "OFFSET", "TK_OFFSET", ALWAYS }, { "ON", "TK_ON", ALWAYS }, { "OR", "TK_OR", ALWAYS }, | > | 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | { "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 }, { "NOT", "TK_NOT", ALWAYS }, { "NOTNULL", "TK_NOTNULL", ALWAYS }, { "NULL", "TK_NULL", ALWAYS }, { "OF", "TK_OF", ALWAYS }, { "OFFSET", "TK_OFFSET", ALWAYS }, { "ON", "TK_ON", ALWAYS }, { "OR", "TK_OR", ALWAYS }, |
︙ | ︙ | |||
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 | static int keywordCompare1(const void *a, const void *b){ const Keyword *pA = (Keyword*)a; const Keyword *pB = (Keyword*)b; int n = pA->len - pB->len; if( n==0 ){ n = strcmp(pA->zName, pB->zName); } return n; } static int keywordCompare2(const void *a, const void *b){ const Keyword *pA = (Keyword*)a; const Keyword *pB = (Keyword*)b; int n = pB->longestSuffix - pA->longestSuffix; if( n==0 ){ n = strcmp(pA->zName, pB->zName); } return n; } static int keywordCompare3(const void *a, const void *b){ const Keyword *pA = (Keyword*)a; const Keyword *pB = (Keyword*)b; int n = pA->offset - pB->offset; return n; } /* ** Return a KeywordTable entry with the given id */ static Keyword *findById(int id){ | > > > > | 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 | static int keywordCompare1(const void *a, const void *b){ const Keyword *pA = (Keyword*)a; const Keyword *pB = (Keyword*)b; int n = pA->len - pB->len; if( n==0 ){ n = strcmp(pA->zName, pB->zName); } assert( n!=0 ); return n; } static int keywordCompare2(const void *a, const void *b){ const Keyword *pA = (Keyword*)a; const Keyword *pB = (Keyword*)b; int n = pB->longestSuffix - pA->longestSuffix; if( n==0 ){ n = strcmp(pA->zName, pB->zName); } assert( n!=0 ); return n; } static int keywordCompare3(const void *a, const void *b){ const Keyword *pA = (Keyword*)a; const Keyword *pB = (Keyword*)b; int n = pA->offset - pB->offset; if( n==0 ) n = pB->id - pA->id; assert( n!=0 ); return n; } /* ** Return a KeywordTable entry with the given id */ static Keyword *findById(int id){ |
︙ | ︙ |
Changes to tool/mksqlite3c.tcl.
︙ | ︙ | |||
18 19 20 21 22 23 24 | # this script: # # tclsh mksqlite3c.tcl # # The amalgamated SQLite code will be written into sqlite3.c # | | | | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | # this script: # # tclsh mksqlite3c.tcl # # The amalgamated SQLite code will be written into sqlite3.c # # Begin by reading the "sqlite3.h" header file. Extract the version number # from in this file. The versioon number is needed to generate the header # comment of the amalgamation. # if {[lsearch $argv --nostatic]>=0} { set addstatic 0 } else { set addstatic 1 } set in [open tsrc/sqlite3.h] |
︙ | ︙ | |||
56 57 58 59 60 61 62 | ** possible if the files were compiled separately. Performance improvements ** of 5% are more are commonly seen when SQLite is compiled as a single ** translation unit. ** ** This file is all you need to compile SQLite. To use SQLite in other ** programs, you need this file and the "sqlite3.h" header file that defines ** the programming interface to the SQLite library. (If you do not have | | > | | | | < < < | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | ** possible if the files were compiled separately. Performance improvements ** of 5% are more are commonly seen when SQLite is compiled as a single ** translation unit. ** ** This file is all you need to compile SQLite. To use SQLite in other ** programs, you need this file and the "sqlite3.h" header file that defines ** the programming interface to the SQLite library. (If you do not have ** the "sqlite3.h" header file at hand, you will find a copy embedded within ** the text of this file. Search for "Begin file sqlite3.h" to find the start ** of the embedded sqlite3.h header file.) Additional code files may be needed ** if you want a wrapper to interface SQLite with your choice of programming ** language. The code for the "sqlite3" command-line shell is also in a ** separate file. This file contains only code for the core SQLite library. */ #define SQLITE_CORE 1 #define SQLITE_AMALGAMATION 1}] if {$addstatic} { puts $out \ {#ifndef SQLITE_PRIVATE # define SQLITE_PRIVATE static |
︙ | ︙ | |||
162 163 164 165 166 167 168 169 170 171 172 173 174 175 | puts $out $line } } elseif {[regexp {^#ifdef __cplusplus} $line]} { puts $out "#if 0" } elseif {[regexp {^#line} $line]} { # Skip #line directives. } elseif {$addstatic && ![regexp {^(static|typedef)} $line]} { if {[regexp $declpattern $line all funcname]} { # Add the SQLITE_PRIVATE or SQLITE_API keyword before functions. # so that linkage can be modified at compile-time. if {[regexp {^sqlite3_} $funcname]} { puts $out "SQLITE_API $line" } else { puts $out "SQLITE_PRIVATE $line" | > | 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | puts $out $line } } elseif {[regexp {^#ifdef __cplusplus} $line]} { puts $out "#if 0" } elseif {[regexp {^#line} $line]} { # Skip #line directives. } elseif {$addstatic && ![regexp {^(static|typedef)} $line]} { regsub {^SQLITE_API } $line {} line if {[regexp $declpattern $line all funcname]} { # Add the SQLITE_PRIVATE or SQLITE_API keyword before functions. # so that linkage can be modified at compile-time. if {[regexp {^sqlite3_} $funcname]} { puts $out "SQLITE_API $line" } else { puts $out "SQLITE_PRIVATE $line" |
︙ | ︙ | |||
264 265 266 267 268 269 270 271 272 273 274 275 276 277 | analyze.c attach.c auth.c build.c callback.c delete.c func.c insert.c legacy.c loadext.c pragma.c prepare.c select.c table.c | > | 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 | analyze.c attach.c auth.c build.c callback.c delete.c func.c fkey.c insert.c legacy.c loadext.c pragma.c prepare.c select.c table.c |
︙ | ︙ |
Added tool/mksqlite3h.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 | #!/usr/bin/tclsh # # This script constructs the "sqlite3.h" header file from the following # sources: # # 1) The src/sqlite.h.in source file. This is the template for sqlite3.h. # 2) The VERSION file containing the current SQLite version number. # 3) The manifest file from the fossil SCM. This gives use the date. # 4) The manifest.uuid file from the fossil SCM. This gives the SHA1 hash. # # Run this script by specifying the root directory of the source tree # on the command-line. # # This script performs processing on src/sqlite.h.in. It: # # 1) Adds SQLITE_EXTERN in front of the declaration of global variables, # 2) Adds SQLITE_API in front of the declaration of API functions, # 3) Replaces the string --VERS-- with the current library version, # formatted as a string (e.g. "3.6.17"), and # 4) Replaces the string --VERSION-NUMBER-- with current library version, # formatted as an integer (e.g. "3006017"). # 5) Replaces the string --SOURCE-ID-- with the date and time and sha1 # hash of the fossil-scm manifest for the source tree. # # This script outputs to stdout. # # Example usage: # # tclsh mksqlite3h.tcl ../sqlite >sqlite3.h # # Get the source tree root directory from the command-line # set TOP [lindex $argv 0] # 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 .]] # Get the fossil-scm version number from $TOP/manifest.uuid. # set in [open $TOP/manifest.uuid] set zUuid [string trim [read $in]] close $in # Get the fossil-scm check-in date from the "D" card of $TOP/manifest. # set in [open $TOP/manifest] set zDate {} while {![eof $in]} { set line [gets $in] if {[regexp {^D (2.*[0-9])} $line all date]} { set zDate [string map {T { }} $date] break } } close $in # Set up patterns for recognizing API declarations. # 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]+\(} # Process the src/sqlite.h.in file. # set in [open $TOP/src/sqlite.h.in] while {![eof $in]} { set line [gets $in] regsub -- --VERS-- $line $zVersion line regsub -- --VERSION-NUMBER-- $line $nVersion line regsub -- --SOURCE-ID-- $line "$zDate $zUuid" line if {[regexp {define SQLITE_EXTERN extern} $line]} { puts $line puts [gets $in] puts "" puts "#ifndef SQLITE_API" puts "# define SQLITE_API" puts "#endif" set line "" } if {([regexp $varpattern $line] && ![regexp {^ *typedef} $line]) || ([regexp $declpattern $line]) } { set line "SQLITE_API $line" } puts $line } close $in |
Added tool/shell1.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 | # 2009 Nov 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. # #*********************************************************************** # # The focus of this file is testing the CLI shell tool. # # $Id: shell1.test,v 1.7 2009/07/17 16:54:48 shaneh Exp $ # # 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. # package require sqlite3 set CLI "./sqlite" proc do_test {name cmd expected} { puts -nonewline "$name ..." set res [uplevel $cmd] if {$res eq $expected} { puts Ok } else { puts Error puts " Got: $res" puts " Expected: $expected" exit } } proc execsql {sql} { uplevel [list db eval $sql] } proc catchsql {sql} { set rc [catch {uplevel [list db eval $sql]} msg] list $rc $msg } proc catchcmd {db cmd} { global CLI set out [open cmds.txt w] puts $out $cmd close $out set line "exec $CLI $db < cmds.txt" set rc [catch { eval $line } msg] list $rc $msg } file delete -force test.db test.db.journal sqlite3 db test.db #---------------------------------------------------------------------------- # Test cases shell1-1.*: Basic command line option handling. # # invalid option do_test shell1-1.1.1 { set res [catchcmd "-bad test.db" ""] set rc [lindex $res 0] list $rc \ [regexp {Error: unknown option: -bad} $res] } {1 1} # error on extra options do_test shell1-1.1.2 { set res [catchcmd "-bad test.db \"select 3\" \"select 4\"" ""] set rc [lindex $res 0] list $rc \ [regexp {Error: too many options: "select 4"} $res] } {1 1} # error on extra options do_test shell1-1.3.2 { set res [catchcmd "-bad FOO test.db BAD" ".quit"] set rc [lindex $res 0] list $rc \ [regexp {Error: too many options: "BAD"} $res] } {1 1} # -help do_test shell1-1.2.1 { set res [catchcmd "-help test.db" ""] set rc [lindex $res 0] list $rc \ [regexp {Usage} $res] \ [regexp {\-init} $res] \ [regexp {\-version} $res] } {1 1 1 1} # -init filename read/process named file do_test shell1-1.3.1 { catchcmd "-init FOO test.db" "" } {0 {}} do_test shell1-1.3.2 { set res [catchcmd "-init FOO test.db .quit BAD" ""] set rc [lindex $res 0] list $rc \ [regexp {Error: too many options: "BAD"} $res] } {1 1} # -echo print commands before execution do_test shell1-1.4.1 { catchcmd "-echo test.db" "" } {0 {}} # -[no]header turn headers on or off do_test shell1-1.5.1 { catchcmd "-header test.db" "" } {0 {}} do_test shell1-1.5.2 { catchcmd "-noheader test.db" "" } {0 {}} # -bail stop after hitting an error do_test shell1-1.6.1 { catchcmd "-bail test.db" "" } {0 {}} # -interactive force interactive I/O do_test shell1-1.7.1 { set res [catchcmd "-interactive test.db" ".quit"] set rc [lindex $res 0] list $rc \ [regexp {SQLite version} $res] \ [regexp {Enter SQL statements} $res] } {0 1 1} # -batch force batch I/O do_test shell1-1.8.1 { catchcmd "-batch test.db" "" } {0 {}} # -column set output mode to 'column' do_test shell1-1.9.1 { catchcmd "-column test.db" "" } {0 {}} # -csv set output mode to 'csv' do_test shell1-1.10.1 { catchcmd "-csv test.db" "" } {0 {}} # -html set output mode to HTML do_test shell1-1.11.1 { catchcmd "-html test.db" "" } {0 {}} # -line set output mode to 'line' do_test shell1-1.12.1 { catchcmd "-line test.db" "" } {0 {}} # -list set output mode to 'list' do_test shell1-1.13.1 { catchcmd "-list test.db" "" } {0 {}} # -separator 'x' set output field separator (|) do_test shell1-1.14.1 { catchcmd "-separator 'x' test.db" "" } {0 {}} do_test shell1-1.14.2 { catchcmd "-separator x test.db" "" } {0 {}} do_test shell1-1.14.3 { set res [catchcmd "-separator" ""] set rc [lindex $res 0] list $rc \ [regexp {Error: missing argument for option: -separator} $res] } {1 1} # -nullvalue 'text' set text string for NULL values do_test shell1-1.15.1 { catchcmd "-nullvalue 'x' test.db" "" } {0 {}} do_test shell1-1.15.2 { catchcmd "-nullvalue x test.db" "" } {0 {}} do_test shell1-1.15.3 { set res [catchcmd "-nullvalue" ""] set rc [lindex $res 0] list $rc \ [regexp {Error: missing argument for option: -nullvalue} $res] } {1 1} # -version show SQLite version do_test shell1-1.16.1 { catchcmd "-version test.db" "" } {0 3.6.20} #---------------------------------------------------------------------------- # Test cases shell1-2.*: Basic "dot" command token parsing. # # check first token handling do_test shell1-2.1.1 { catchcmd " test.db" ".foo" } {1 {Error: unknown command or invalid arguments: "foo". Enter ".help" for help}} do_test shell1-2.1.2 { catchcmd " test.db" ".\"foo OFF\"" } {1 {Error: unknown command or invalid arguments: "foo OFF". Enter ".help" for help}} do_test shell1-2.1.3 { catchcmd " test.db" ".\'foo OFF\'" } {1 {Error: unknown command or invalid arguments: "foo OFF". Enter ".help" for help}} # unbalanced quotes do_test shell1-2.2.1 { catchcmd " test.db" ".\"foo OFF" } {1 {Error: unknown command or invalid arguments: "foo OFF". Enter ".help" for help}} do_test shell1-2.2.2 { catchcmd " test.db" ".\'foo OFF" } {1 {Error: unknown command or invalid arguments: "foo OFF". Enter ".help" for help}} do_test shell1-2.2.3 { 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: column csv html insert line list tabs tcl}} do_test shell1-2.2.6 { catchcmd " test.db" ".mode \'insert FOO" } {1 {Error: mode should be one of: column csv html insert line list 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" } {0 {}} do_test shell1-2.3.3 { catchcmd " test.db" ".explain \"1 2 3\"" } {0 {}} do_test shell1-2.3.4 { catchcmd " test.db" ".explain \"OFF\"" } {0 {}} do_test shell1-2.3.5 { catchcmd " test.db" ".\'explain\' \'OFF\'" } {0 {}} do_test shell1-2.3.6 { catchcmd " test.db" ".explain \'OFF\'" } {0 {}} 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: column csv html insert line list 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 {Error: unknown command or invalid arguments: "backup". Enter ".help" for help}} do_test shell1-3.1.2 { # catchcmd " test.db" ".backup FOO" #TBD!!! this asserts currently } {} do_test shell1-3.1.3 { catchcmd " test.db" ".backup FOO BAR" } {1 {Error: unknown database FOO}} do_test shell1-3.1.4 { # too many arguments catchcmd " test.db" ".backup FOO BAR BAD" } {1 {Error: unknown command or invalid arguments: "backup". Enter ".help" for help}} # .bail ON|OFF Stop after hitting an error. Default OFF do_test shell1-3.2.1 { catchcmd " test.db" ".bail" } {1 {Error: unknown command or invalid arguments: "bail". Enter ".help" for help}} do_test shell1-3.2.2 { catchcmd " test.db" ".bail ON" } {0 {}} do_test shell1-3.2.3 { catchcmd " test.db" ".bail OFF" } {0 {}} do_test shell1-3.2.4 { # too many arguments catchcmd " test.db" ".bail OFF BAD" } {1 {Error: unknown command or invalid arguments: "bail". Enter ".help" for help}} # .databases List names and files of attached databases do_test shell1-3.3.1 { set res [catchcmd " test.db" ".databases"] regexp {0.*main.*test\.db} $res } {1} do_test shell1-3.3.2 { # too many arguments catchcmd " test.db" ".databases BAD" } {1 {Error: unknown command or invalid arguments: "databases". Enter ".help" for help}} # .dump ?TABLE? ... Dump the database in an SQL text format # If TABLE specified, only dump tables matching # LIKE pattern TABLE. do_test shell1-3.4.1 { set res [catchcmd " test.db" ".dump"] list [regexp {BEGIN TRANSACTION;} $res] \ [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 {Error: unknown command or invalid arguments: "dump". Enter ".help" for help}} # .echo ON|OFF Turn command echo on or off do_test shell1-3.5.1 { catchcmd " test.db" ".echo" } {1 {Error: unknown command or invalid arguments: "echo". Enter ".help" for help}} do_test shell1-3.5.2 { catchcmd " test.db" ".echo ON" } {0 {}} do_test shell1-3.5.3 { catchcmd " test.db" ".echo OFF" } {0 {}} do_test shell1-3.5.4 { # too many arguments catchcmd " test.db" ".echo OFF BAD" } {1 {Error: unknown command or invalid arguments: "echo". Enter ".help" for help}} # .exit Exit this program do_test shell1-3.6.1 { catchcmd " test.db" ".exit" } {0 {}} do_test shell1-3.6.2 { # too many arguments catchcmd " test.db" ".exit BAD" } {1 {Error: unknown command or invalid arguments: "exit". Enter ".help" for help}} # .explain ON|OFF Turn output mode suitable for EXPLAIN on or off. do_test shell1-3.7.1 { catchcmd " test.db" ".explain" # explain is the exception to the booleans. without an option, it turns it on. } {0 {}} do_test shell1-3.7.2 { catchcmd " test.db" ".explain ON" } {0 {}} do_test shell1-3.7.3 { catchcmd " test.db" ".explain OFF" } {0 {}} do_test shell1-3.7.4 { # too many arguments catchcmd " test.db" ".explain OFF BAD" } {1 {Error: unknown command or invalid arguments: "explain". Enter ".help" for help}} # .genfkey ?OPTIONS? Options are: # --no-drop: Do not drop old fkey triggers. # --ignore-errors: Ignore tables with fkey errors # --exec: Execute generated SQL immediately # See file tool/genfkey.README in the source # distribution for further information. do_test shell1-3.8.1 { catchcmd " test.db" ".genfkey" } {0 {}} do_test shell1-3.8.2 { catchcmd " test.db" ".genfkey FOO" } {1 {unknown option: FOO}} # .header(s) ON|OFF Turn display of headers on or off do_test shell1-3.9.1 { catchcmd " test.db" ".header" } {1 {Error: unknown command or invalid arguments: "header". Enter ".help" for help}} do_test shell1-3.9.2 { catchcmd " test.db" ".header ON" } {0 {}} do_test shell1-3.9.3 { catchcmd " test.db" ".header OFF" } {0 {}} do_test shell1-3.9.4 { # too many arguments catchcmd " test.db" ".header OFF BAD" } {1 {Error: unknown command or invalid arguments: "header". Enter ".help" for help}} do_test shell1-3.9.5 { catchcmd " test.db" ".headers" } {1 {Error: unknown command or invalid arguments: "headers". Enter ".help" for help}} do_test shell1-3.9.6 { catchcmd " test.db" ".headers ON" } {0 {}} do_test shell1-3.9.7 { catchcmd " test.db" ".headers OFF" } {0 {}} do_test shell1-3.9.8 { # too many arguments catchcmd " test.db" ".headers OFF BAD" } {1 {Error: unknown command or invalid arguments: "headers". Enter ".help" for help}} # .help Show this message do_test shell1-3.10.1 { set res [catchcmd " test.db" ".help"] # look for a few of the possible help commands list [regexp {.help} $res] \ [regexp {.quit} $res] \ [regexp {.show} $res] } {1 1 1} do_test shell1-3.10.2 { # we allow .help to take extra args (it is help after all) set res [catchcmd " test.db" ".help BAD"] # look for a few of the possible help commands list [regexp {.help} $res] \ [regexp {.quit} $res] \ [regexp {.show} $res] } {1 1 1} # .import FILE TABLE Import data from FILE into TABLE do_test shell1-3.11.1 { catchcmd " test.db" ".import" } {1 {Error: unknown command or invalid arguments: "import". Enter ".help" for help}} do_test shell1-3.11.2 { catchcmd " test.db" ".import FOO" } {1 {Error: unknown command or invalid arguments: "import". Enter ".help" for help}} 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 {Error: unknown command or invalid arguments: "import". Enter ".help" for help}} # .indices ?TABLE? Show names of all indices # If TABLE specified, only show indices for tables # matching LIKE pattern TABLE. do_test shell1-3.12.1 { catchcmd " test.db" ".indices" } {0 {}} do_test shell1-3.12.2 { catchcmd " test.db" ".indices FOO" } {0 {}} do_test shell1-3.12.3 { # too many arguments catchcmd " test.db" ".indices FOO BAD" } {1 {Error: unknown command or invalid arguments: "indices". Enter ".help" for help}} # .mode MODE ?TABLE? Set output mode where MODE is one of: # 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 .separator string # tabs Tab-separated values # tcl TCL list elements do_test shell1-3.13.1 { catchcmd " test.db" ".mode" } {1 {Error: unknown command or invalid arguments: "mode". Enter ".help" for help}} do_test shell1-3.13.2 { catchcmd " test.db" ".mode FOO" } {1 {Error: mode should be one of: column csv html insert line list 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 { catchcmd " test.db" ".mode html" } {0 {}} do_test shell1-3.13.6 { catchcmd " test.db" ".mode insert" } {0 {}} do_test shell1-3.13.7 { catchcmd " test.db" ".mode line" } {0 {}} do_test shell1-3.13.8 { catchcmd " test.db" ".mode list" } {0 {}} do_test shell1-3.13.9 { catchcmd " test.db" ".mode tabs" } {0 {}} do_test shell1-3.13.10 { catchcmd " test.db" ".mode tcl" } {0 {}} do_test shell1-3.13.11 { # too many arguments catchcmd " test.db" ".mode tcl BAD" } {1 {Error: invalid arguments: "BAD". Enter ".help" for help}} # 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: column csv html insert line list tabs tcl}} do_test shell1-3.13.13 { catchcmd " test.db" ".mode li" } {1 {Error: mode should be one of: column csv html insert line list tabs tcl}} do_test shell1-3.13.14 { catchcmd " test.db" ".mode lin" } {1 {Error: mode should be one of: column csv html insert line list tabs tcl}} # .nullvalue STRING Print STRING in place of NULL values do_test shell1-3.14.1 { catchcmd " test.db" ".nullvalue" } {1 {Error: unknown command or invalid arguments: "nullvalue". Enter ".help" for help}} do_test shell1-3.14.2 { catchcmd " test.db" ".nullvalue FOO" } {0 {}} do_test shell1-3.14.3 { # too many arguments catchcmd " test.db" ".nullvalue FOO BAD" } {1 {Error: unknown command or invalid arguments: "nullvalue". Enter ".help" for help}} # .output FILENAME Send output to FILENAME do_test shell1-3.15.1 { catchcmd " test.db" ".output" } {1 {Error: unknown command or invalid arguments: "output". Enter ".help" for help}} do_test shell1-3.15.2 { catchcmd " test.db" ".output FOO" } {0 {}} do_test shell1-3.15.3 { # too many arguments catchcmd " test.db" ".output FOO BAD" } {1 {Error: unknown command or invalid arguments: "output". Enter ".help" for help}} # .output stdout Send output to the screen do_test shell1-3.16.1 { catchcmd " test.db" ".output stdout" } {0 {}} do_test shell1-3.16.2 { # too many arguments catchcmd " test.db" ".output stdout BAD" } {1 {Error: unknown command or invalid arguments: "output". Enter ".help" for help}} # .prompt MAIN CONTINUE Replace the standard prompts do_test shell1-3.17.1 { catchcmd " test.db" ".prompt" } {1 {Error: unknown command or invalid arguments: "prompt". Enter ".help" for help}} do_test shell1-3.17.2 { catchcmd " test.db" ".prompt FOO" } {0 {}} do_test shell1-3.17.3 { catchcmd " test.db" ".prompt FOO BAR" } {0 {}} do_test shell1-3.17.4 { # too many arguments catchcmd " test.db" ".prompt FOO BAR BAD" } {1 {Error: unknown command or invalid arguments: "prompt". Enter ".help" for help}} # .quit Exit this program do_test shell1-3.18.1 { catchcmd " test.db" ".quit" } {0 {}} do_test shell1-3.18.2 { # too many arguments catchcmd " test.db" ".quit BAD" } {1 {Error: unknown command or invalid arguments: "quit". Enter ".help" for help}} # .read FILENAME Execute SQL in FILENAME do_test shell1-3.19.1 { catchcmd " test.db" ".read" } {1 {Error: unknown command or invalid arguments: "read". Enter ".help" for help}} do_test shell1-3.19.2 { file delete -force FOO catchcmd " test.db" ".read FOO" } {1 {Error: cannot open "FOO"}} do_test shell1-3.19.3 { # too many arguments catchcmd " test.db" ".read FOO BAD" } {1 {Error: unknown command or invalid arguments: "read". Enter ".help" for help}} # .restore ?DB? FILE Restore content of DB (default "main") from FILE do_test shell1-3.20.1 { catchcmd " test.db" ".restore" } {1 {Error: unknown command or invalid arguments: "restore". Enter ".help" for help}} do_test shell1-3.20.2 { # catchcmd " test.db" ".restore FOO" #TBD!!! this asserts currently } {} do_test shell1-3.20.3 { catchcmd " test.db" ".restore FOO BAR" } {1 {Error: unknown database FOO}} do_test shell1-3.20.4 { # too many arguments catchcmd " test.db" ".restore FOO BAR BAD" } {1 {Error: unknown command or invalid arguments: "restore". Enter ".help" for help}} # .schema ?TABLE? Show the CREATE statements # If TABLE specified, only show tables matching # LIKE pattern TABLE. do_test shell1-3.21.1 { catchcmd " test.db" ".schema" } {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 {Error: unknown command or invalid arguments: "schema". Enter ".help" for help}} # .separator STRING Change separator used by output mode and .import do_test shell1-3.22.1 { catchcmd " test.db" ".separator" } {1 {Error: unknown command or invalid arguments: "separator". Enter ".help" for help}} do_test shell1-3.22.2 { catchcmd " test.db" ".separator FOO" } {0 {}} do_test shell1-3.22.3 { # too many arguments catchcmd " test.db" ".separator FOO BAD" } {1 {Error: unknown command or invalid arguments: "separator". Enter ".help" for help}} # .show Show the current values for various settings do_test shell1-3.23.1 { set res [catchcmd " test.db" ".show"] list [regexp {echo:} $res] \ [regexp {explain:} $res] \ [regexp {headers:} $res] \ [regexp {mode:} $res] \ [regexp {nullvalue:} $res] \ [regexp {output:} $res] \ [regexp {separator:} $res] \ [regexp {width:} $res] } {1 1 1 1 1 1 1 1} do_test shell1-3.23.2 { # too many arguments catchcmd " test.db" ".show BAD" } {1 {Error: unknown command or invalid arguments: "show". Enter ".help" for help}} # .tables ?TABLE? List names of tables # If TABLE specified, only list tables matching # LIKE pattern TABLE. do_test shell1-3.24.1 { catchcmd " test.db" ".tables" } {0 {}} do_test shell1-3.24.2 { catchcmd " test.db" ".tables FOO" } {0 {}} do_test shell1-3.24.3 { # too many arguments catchcmd " test.db" ".tables FOO BAD" } {1 {Error: unknown command or invalid arguments: "tables". Enter ".help" for help}} # .timeout MS Try opening locked tables for MS milliseconds do_test shell1-3.25.1 { catchcmd " test.db" ".timeout" } {1 {Error: unknown command or invalid arguments: "timeout". Enter ".help" for help}} do_test shell1-3.25.2 { catchcmd " test.db" ".timeout zzz" # this should be treated the same as a '0' timeout } {0 {}} do_test shell1-3.25.3 { catchcmd " test.db" ".timeout 1" } {0 {}} do_test shell1-3.25.4 { # too many arguments catchcmd " test.db" ".timeout 1 BAD" } {1 {Error: unknown command or invalid arguments: "timeout". Enter ".help" for help}} # .width NUM NUM ... Set column widths for "column" mode do_test shell1-3.26.1 { catchcmd " test.db" ".width" } {1 {Error: unknown command or invalid arguments: "width". Enter ".help" for help}} do_test shell1-3.26.2 { catchcmd " test.db" ".width xxx" # this should be treated the same as a '0' width for col 1 } {0 {}} do_test shell1-3.26.3 { catchcmd " test.db" ".width xxx yyy" # 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 {}} # .timer ON|OFF Turn the CPU timer measurement on or off do_test shell1-3.27.1 { catchcmd " test.db" ".timer" } {1 {Error: unknown command or invalid arguments: "timer". Enter ".help" for help}} do_test shell1-3.27.2 { catchcmd " test.db" ".timer ON" } {0 {}} do_test shell1-3.27.3 { catchcmd " test.db" ".timer OFF" } {0 {}} do_test shell1-3.27.4 { # too many arguments catchcmd " test.db" ".timer OFF BAD" } {1 {Error: unknown command or invalid arguments: "timer". Enter ".help" for help}} # |
Added tool/shell2.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 | # 2009 Nov 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. # #*********************************************************************** # # The focus of this file is testing the CLI shell tool. # # $Id: shell2.test,v 1.7 2009/07/17 16:54:48 shaneh Exp $ # # Test plan: # # shell2-1.*: Misc. test of various tickets and reported errors. # package require sqlite3 set CLI "./sqlite" proc do_test {name cmd expected} { puts -nonewline "$name ..." set res [uplevel $cmd] if {$res eq $expected} { puts Ok } else { puts Error puts " Got: $res" puts " Expected: $expected" exit } } proc execsql {sql} { uplevel [list db eval $sql] } proc catchsql {sql} { set rc [catch {uplevel [list db eval $sql]} msg] list $rc $msg } proc catchcmd {db cmd} { global CLI set out [open cmds.txt w] puts $out $cmd close $out set line "exec $CLI $db < cmds.txt" set rc [catch { eval $line } msg] list $rc $msg } file delete -force test.db test.db.journal sqlite3 db test.db #---------------------------------------------------------------------------- # shell2-1.*: Misc. test of various tickets and reported errors. # # Batch mode not creating databases. # Reported on mailing list by Ken Zalewski. # Ticket [aeff892c57]. do_test shell2-1.1.1 { file delete -force foo.db set rc [ catchcmd "-batch foo.db" "CREATE TABLE t1(a);" ] 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 \ [regexp {Error: too many options: "select 4"} $msg] } {1 1} |
Changes to tool/vdbe-compress.tcl.
︙ | ︙ | |||
91 92 93 94 95 96 97 98 99 100 101 102 103 104 | } if {[regexp "^\175" $line]} { append afterUnion $line\n set vlist {} } elseif {[llength $vlist]>0} { append line " " foreach v $vlist { regsub -all "(\[^a-zA-Z0-9>.\])${v}(\\W)" $line "\\1u.$sname.$v\\2" line } append afterUnion [string trimright $line]\n } elseif {$line=="" && [eof stdin]} { # no-op } else { append afterUnion $line\n | > | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | } if {[regexp "^\175" $line]} { append afterUnion $line\n set vlist {} } elseif {[llength $vlist]>0} { append line " " foreach v $vlist { regsub -all "(\[^a-zA-Z0-9>.\])${v}(\\W)" $line "\\1u.$sname.$v\\2" line regsub -all "(\[^a-zA-Z0-9>.\])${v}(\\W)" $line "\\1u.$sname.$v\\2" line } append afterUnion [string trimright $line]\n } elseif {$line=="" && [eof stdin]} { # no-op } else { append afterUnion $line\n |
︙ | ︙ |