Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Difference From version-3.7.15 To version-3.7.16
2013-03-18
| ||
17:18 | Clarifications to the documentation for the sqlite3_aggregate_context() API. Also, shorten an over-length source line in sqlite.h.in. (check-in: 4fe2db1d86 user: drh tags: trunk) | |
16:24 | Adjust the MSVC makefile so that it correctly handles the sessions extension being included in the amalgamation. Import the test case changes that appeared in 3.7.16 final. (check-in: 9bac09a99a user: drh tags: sessions) | |
11:39 | Version 3.7.16 (check-in: 66d5f2b767 user: drh tags: trunk, release, version-3.7.16) | |
2013-03-13
| ||
07:02 | Enhance tests for ticket [4dd95f6943]. (check-in: 0b452734fa user: dan tags: trunk) | |
2012-12-19
| ||
17:10 | Backport to the 3.7.15 branch the fix to the segfault problem of ticket [a7b7803e8d1e869] which involved the use of "AS" named result columns as logical terms of the WHERE clause. Also, change the version number to 3.7.15.1. (check-in: bae528f486 user: drh tags: branch-3.7.15) | |
2012-12-12
| ||
14:30 | Allow the error message from "PRAGMA integrity_check" to be longer than 20,000 bytes. (check-in: 120c82d56e user: drh tags: trunk) | |
13:36 | Version 3.7.15 (check-in: cd0b37c526 user: dan tags: trunk, release, version-3.7.15) | |
2012-12-11
| ||
19:40 | Update requirements marks and test cases for multi-VALUE INSERT and to fix typos in requirements text. (check-in: 81d9ee0f0d user: drh tags: trunk) | |
Changes to Makefile.in.
︙ | ︙ | |||
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 | $(TOP)/src/test_autoext.c \ $(TOP)/src/test_async.c \ $(TOP)/src/test_backup.c \ $(TOP)/src/test_btree.c \ $(TOP)/src/test_config.c \ $(TOP)/src/test_demovfs.c \ $(TOP)/src/test_devsym.c \ $(TOP)/src/test_func.c \ $(TOP)/src/test_fuzzer.c \ $(TOP)/src/test_hexio.c \ $(TOP)/src/test_init.c \ $(TOP)/src/test_intarray.c \ $(TOP)/src/test_journal.c \ $(TOP)/src/test_malloc.c \ $(TOP)/src/test_multiplex.c \ $(TOP)/src/test_mutex.c \ $(TOP)/src/test_onefile.c \ $(TOP)/src/test_osinst.c \ $(TOP)/src/test_pcache.c \ $(TOP)/src/test_quota.c \ $(TOP)/src/test_rtree.c \ $(TOP)/src/test_schema.c \ $(TOP)/src/test_server.c \ $(TOP)/src/test_superlock.c \ $(TOP)/src/test_syscall.c \ $(TOP)/src/test_stat.c \ $(TOP)/src/test_tclvar.c \ | > > | 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 | $(TOP)/src/test_autoext.c \ $(TOP)/src/test_async.c \ $(TOP)/src/test_backup.c \ $(TOP)/src/test_btree.c \ $(TOP)/src/test_config.c \ $(TOP)/src/test_demovfs.c \ $(TOP)/src/test_devsym.c \ $(TOP)/src/test_fs.c \ $(TOP)/src/test_func.c \ $(TOP)/src/test_fuzzer.c \ $(TOP)/src/test_hexio.c \ $(TOP)/src/test_init.c \ $(TOP)/src/test_intarray.c \ $(TOP)/src/test_journal.c \ $(TOP)/src/test_malloc.c \ $(TOP)/src/test_multiplex.c \ $(TOP)/src/test_mutex.c \ $(TOP)/src/test_onefile.c \ $(TOP)/src/test_osinst.c \ $(TOP)/src/test_pcache.c \ $(TOP)/src/test_quota.c \ $(TOP)/src/test_regexp.c \ $(TOP)/src/test_rtree.c \ $(TOP)/src/test_schema.c \ $(TOP)/src/test_server.c \ $(TOP)/src/test_superlock.c \ $(TOP)/src/test_syscall.c \ $(TOP)/src/test_stat.c \ $(TOP)/src/test_tclvar.c \ |
︙ | ︙ |
Changes to Makefile.msc.
︙ | ︙ | |||
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 | $(TOP)\src\test_autoext.c \ $(TOP)\src\test_async.c \ $(TOP)\src\test_backup.c \ $(TOP)\src\test_btree.c \ $(TOP)\src\test_config.c \ $(TOP)\src\test_demovfs.c \ $(TOP)\src\test_devsym.c \ $(TOP)\src\test_func.c \ $(TOP)\src\test_fuzzer.c \ $(TOP)\src\test_hexio.c \ $(TOP)\src\test_init.c \ $(TOP)\src\test_intarray.c \ $(TOP)\src\test_journal.c \ $(TOP)\src\test_malloc.c \ $(TOP)\src\test_multiplex.c \ $(TOP)\src\test_mutex.c \ $(TOP)\src\test_onefile.c \ $(TOP)\src\test_osinst.c \ $(TOP)\src\test_pcache.c \ $(TOP)\src\test_quota.c \ $(TOP)\src\test_rtree.c \ $(TOP)\src\test_schema.c \ $(TOP)\src\test_server.c \ $(TOP)\src\test_superlock.c \ $(TOP)\src\test_syscall.c \ $(TOP)\src\test_stat.c \ $(TOP)\src\test_tclvar.c \ | > > | 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 | $(TOP)\src\test_autoext.c \ $(TOP)\src\test_async.c \ $(TOP)\src\test_backup.c \ $(TOP)\src\test_btree.c \ $(TOP)\src\test_config.c \ $(TOP)\src\test_demovfs.c \ $(TOP)\src\test_devsym.c \ $(TOP)\src\test_fs.c \ $(TOP)\src\test_func.c \ $(TOP)\src\test_fuzzer.c \ $(TOP)\src\test_hexio.c \ $(TOP)\src\test_init.c \ $(TOP)\src\test_intarray.c \ $(TOP)\src\test_journal.c \ $(TOP)\src\test_malloc.c \ $(TOP)\src\test_multiplex.c \ $(TOP)\src\test_mutex.c \ $(TOP)\src\test_onefile.c \ $(TOP)\src\test_osinst.c \ $(TOP)\src\test_pcache.c \ $(TOP)\src\test_quota.c \ $(TOP)\src\test_regexp.c \ $(TOP)\src\test_rtree.c \ $(TOP)\src\test_schema.c \ $(TOP)\src\test_server.c \ $(TOP)\src\test_superlock.c \ $(TOP)\src\test_syscall.c \ $(TOP)\src\test_stat.c \ $(TOP)\src\test_tclvar.c \ |
︙ | ︙ |
Changes to VERSION.
|
| | | 1 | 3.7.16 |
Changes to configure.
1 2 | #! /bin/sh # Guess values for system-dependent variables and create Makefiles. | | | 1 2 3 4 5 6 7 8 9 10 | #! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.62 for sqlite 3.7.16. # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## --------------------- ## ## M4sh Initialization. ## |
︙ | ︙ | |||
739 740 741 742 743 744 745 | MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='sqlite' PACKAGE_TARNAME='sqlite' | | | | 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 | MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='sqlite' PACKAGE_TARNAME='sqlite' PACKAGE_VERSION='3.7.16' PACKAGE_STRING='sqlite 3.7.16' PACKAGE_BUGREPORT='' # Factoring default headers for most tests. ac_includes_default="\ #include <stdio.h> #ifdef HAVE_SYS_TYPES_H # include <sys/types.h> |
︙ | ︙ | |||
1480 1481 1482 1483 1484 1485 1486 | # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF | | | 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 | # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures sqlite 3.7.16 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. |
︙ | ︙ | |||
1545 1546 1547 1548 1549 1550 1551 | --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in | | | 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 | --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of sqlite 3.7.16:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] |
︙ | ︙ | |||
1661 1662 1663 1664 1665 1666 1667 | cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF | | | | 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 | cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF sqlite configure 3.7.16 generated by GNU Autoconf 2.62 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by sqlite $as_me 3.7.16, which was generated by GNU Autoconf 2.62. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { |
︙ | ︙ | |||
3729 3730 3731 3732 3733 3734 3735 | { $as_echo "$as_me:$LINENO: checking the name lister ($NM) interface" >&5 $as_echo_n "checking the name lister ($NM) interface... " >&6; } if test "${lt_cv_nm_interface+set}" = set; then $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext | | | | | 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 | { $as_echo "$as_me:$LINENO: checking the name lister ($NM) interface" >&5 $as_echo_n "checking the name lister ($NM) interface... " >&6; } if test "${lt_cv_nm_interface+set}" = set; then $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:3736: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 (eval echo "\"\$as_me:3739: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 (eval echo "\"\$as_me:3742: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest* fi { $as_echo "$as_me:$LINENO: result: $lt_cv_nm_interface" >&5 |
︙ | ︙ | |||
4957 4958 4959 4960 4961 4962 4963 | ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. | | | 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 | ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '#line 4964 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in |
︙ | ︙ | |||
6826 6827 6828 6829 6830 6831 6832 | # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` | | | | 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 | # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:6833: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:6837: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_rtti_exceptions=yes |
︙ | ︙ | |||
7165 7166 7167 7168 7169 7170 7171 | # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` | | | | 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 | # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:7172: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:7176: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works=yes |
︙ | ︙ | |||
7270 7271 7272 7273 7274 7275 7276 | # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` | | | | 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285 7286 7287 7288 | # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:7277: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:7281: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then |
︙ | ︙ | |||
7325 7326 7327 7328 7329 7330 7331 | # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` | | | | 7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339 7340 7341 7342 7343 | # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:7332: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:7336: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then |
︙ | ︙ | |||
10138 10139 10140 10141 10142 10143 10144 | else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF | | | 10138 10139 10140 10141 10142 10143 10144 10145 10146 10147 10148 10149 10150 10151 10152 | else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line 10145 "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include <dlfcn.h> #endif #include <stdio.h> |
︙ | ︙ | |||
10234 10235 10236 10237 10238 10239 10240 | else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF | | | 10234 10235 10236 10237 10238 10239 10240 10241 10242 10243 10244 10245 10246 10247 10248 | else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line 10241 "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include <dlfcn.h> #endif #include <stdio.h> |
︙ | ︙ | |||
12904 12905 12906 12907 12908 12909 12910 |
| < | 12904 12905 12906 12907 12908 12909 12910 12911 12912 12913 12914 12915 12916 12917 | fi fi if test "${use_tcl}" = "no" ; then HAVE_TCL="" else HAVE_TCL=1 fi |
︙ | ︙ | |||
14029 14030 14031 14032 14033 14034 14035 | exec 6>&1 # Save the log message, to keep $[0] and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" | | | 14028 14029 14030 14031 14032 14033 14034 14035 14036 14037 14038 14039 14040 14041 14042 | exec 6>&1 # Save the log message, to keep $[0] and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by sqlite $as_me 3.7.16, 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 $@ |
︙ | ︙ | |||
14082 14083 14084 14085 14086 14087 14088 | $config_commands Report bugs to <bug-autoconf@gnu.org>." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_version="\\ | | | 14081 14082 14083 14084 14085 14086 14087 14088 14089 14090 14091 14092 14093 14094 14095 | $config_commands Report bugs to <bug-autoconf@gnu.org>." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_version="\\ sqlite config.status 3.7.16 configured by $0, generated by GNU Autoconf 2.62, with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" Copyright (C) 2008 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." |
︙ | ︙ |
Changes to ext/rtree/rtree.c.
︙ | ︙ | |||
3045 3046 3047 3048 3049 3050 3051 | ** This ensures that each node is stored on a single database page. If the ** database page-size is so large that more than RTREE_MAXCELLS entries ** would fit in a single node, use a smaller node-size. */ static int getNodeSize( sqlite3 *db, /* Database handle */ Rtree *pRtree, /* Rtree handle */ | | > > > > > > | 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 | ** This ensures that each node is stored on a single database page. If the ** database page-size is so large that more than RTREE_MAXCELLS entries ** would fit in a single node, use a smaller node-size. */ static int getNodeSize( sqlite3 *db, /* Database handle */ Rtree *pRtree, /* Rtree handle */ int isCreate, /* True for xCreate, false for xConnect */ char **pzErr /* OUT: Error message, if any */ ){ int rc; char *zSql; if( isCreate ){ int iPageSize = 0; zSql = sqlite3_mprintf("PRAGMA %Q.page_size", pRtree->zDb); rc = getIntFromStmt(db, zSql, &iPageSize); if( rc==SQLITE_OK ){ pRtree->iNodeSize = iPageSize-64; if( (4+pRtree->nBytesPerCell*RTREE_MAXCELLS)<pRtree->iNodeSize ){ pRtree->iNodeSize = 4+pRtree->nBytesPerCell*RTREE_MAXCELLS; } }else{ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); } }else{ zSql = sqlite3_mprintf( "SELECT length(data) FROM '%q'.'%q_node' WHERE nodeno = 1", pRtree->zDb, pRtree->zName ); rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize); if( rc!=SQLITE_OK ){ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); } } sqlite3_free(zSql); return rc; } /* |
︙ | ︙ | |||
3128 3129 3130 3131 3132 3133 3134 | pRtree->nDim = (argc-4)/2; pRtree->nBytesPerCell = 8 + pRtree->nDim*4*2; pRtree->eCoordType = eCoordType; memcpy(pRtree->zDb, argv[1], nDb); memcpy(pRtree->zName, argv[2], nName); /* Figure out the node size to use. */ | | | 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 | pRtree->nDim = (argc-4)/2; pRtree->nBytesPerCell = 8 + pRtree->nDim*4*2; pRtree->eCoordType = eCoordType; memcpy(pRtree->zDb, argv[1], nDb); memcpy(pRtree->zName, argv[2], nName); /* Figure out the node size to use. */ rc = getNodeSize(db, pRtree, isCreate, pzErr); /* Create/Connect to the underlying relational database schema. If ** that is successful, call sqlite3_declare_vtab() to configure ** the r-tree table schema. */ if( rc==SQLITE_OK ){ if( (rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate)) ){ |
︙ | ︙ |
Changes to main.mk.
︙ | ︙ | |||
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 | $(TOP)/src/test_autoext.c \ $(TOP)/src/test_async.c \ $(TOP)/src/test_backup.c \ $(TOP)/src/test_btree.c \ $(TOP)/src/test_config.c \ $(TOP)/src/test_demovfs.c \ $(TOP)/src/test_devsym.c \ $(TOP)/src/test_func.c \ $(TOP)/src/test_fuzzer.c \ $(TOP)/src/test_hexio.c \ $(TOP)/src/test_init.c \ $(TOP)/src/test_intarray.c \ $(TOP)/src/test_journal.c \ $(TOP)/src/test_malloc.c \ $(TOP)/src/test_multiplex.c \ $(TOP)/src/test_mutex.c \ $(TOP)/src/test_onefile.c \ $(TOP)/src/test_osinst.c \ $(TOP)/src/test_pcache.c \ $(TOP)/src/test_quota.c \ $(TOP)/src/test_rtree.c \ $(TOP)/src/test_schema.c \ $(TOP)/src/test_server.c \ $(TOP)/src/test_stat.c \ $(TOP)/src/test_sqllog.c \ $(TOP)/src/test_superlock.c \ $(TOP)/src/test_syscall.c \ | > > | 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 | $(TOP)/src/test_autoext.c \ $(TOP)/src/test_async.c \ $(TOP)/src/test_backup.c \ $(TOP)/src/test_btree.c \ $(TOP)/src/test_config.c \ $(TOP)/src/test_demovfs.c \ $(TOP)/src/test_devsym.c \ $(TOP)/src/test_fs.c \ $(TOP)/src/test_func.c \ $(TOP)/src/test_fuzzer.c \ $(TOP)/src/test_hexio.c \ $(TOP)/src/test_init.c \ $(TOP)/src/test_intarray.c \ $(TOP)/src/test_journal.c \ $(TOP)/src/test_malloc.c \ $(TOP)/src/test_multiplex.c \ $(TOP)/src/test_mutex.c \ $(TOP)/src/test_onefile.c \ $(TOP)/src/test_osinst.c \ $(TOP)/src/test_pcache.c \ $(TOP)/src/test_quota.c \ $(TOP)/src/test_regexp.c \ $(TOP)/src/test_rtree.c \ $(TOP)/src/test_schema.c \ $(TOP)/src/test_server.c \ $(TOP)/src/test_stat.c \ $(TOP)/src/test_sqllog.c \ $(TOP)/src/test_superlock.c \ $(TOP)/src/test_syscall.c \ |
︙ | ︙ |
Changes to src/analyze.c.
︙ | ︙ | |||
469 470 471 472 473 474 475 | if( v==0 || NEVER(pTab==0) ){ return; } if( pTab->tnum==0 ){ /* Do not gather statistics on views or virtual tables */ return; } | | | 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 | if( v==0 || NEVER(pTab==0) ){ return; } if( pTab->tnum==0 ){ /* Do not gather statistics on views or virtual tables */ return; } if( sqlite3_strnicmp(pTab->zName, "sqlite_", 7)==0 ){ /* Do not gather statistics on system tables */ return; } assert( sqlite3BtreeHoldsAllMutexes(db) ); iDb = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iDb>=0 ); assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); |
︙ | ︙ | |||
879 880 881 882 883 884 885 | v = v*10 + c - '0'; z++; } if( i==0 ) pTable->nRowEst = v; if( pIndex==0 ) break; pIndex->aiRowEst[i] = v; if( *z==' ' ) z++; | | | 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 | v = v*10 + c - '0'; z++; } if( i==0 ) pTable->nRowEst = v; if( pIndex==0 ) break; pIndex->aiRowEst[i] = v; if( *z==' ' ) z++; if( strcmp(z, "unordered")==0 ){ pIndex->bUnordered = 1; break; } } return 0; } |
︙ | ︙ |
Changes to src/backup.c.
︙ | ︙ | |||
208 209 210 211 212 213 214 | } /* ** Parameter zSrcData points to a buffer containing the data for ** page iSrcPg from the source database. Copy this data into the ** destination database. */ | | > > > > > | 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | } /* ** Parameter zSrcData points to a buffer containing the data for ** page iSrcPg from the source database. Copy this data into the ** destination database. */ static int backupOnePage( sqlite3_backup *p, /* Backup handle */ Pgno iSrcPg, /* Source database page to backup */ const u8 *zSrcData, /* Source database page data */ int bUpdate /* True for an update, false otherwise */ ){ Pager * const pDestPager = sqlite3BtreePager(p->pDest); const int nSrcPgsz = sqlite3BtreeGetPageSize(p->pSrc); int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest); const int nCopy = MIN(nSrcPgsz, nDestPgsz); const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz; #ifdef SQLITE_HAS_CODEC /* Use BtreeGetReserveNoMutex() for the source b-tree, as although it is |
︙ | ︙ | |||
281 282 283 284 285 286 287 288 289 290 291 292 293 294 | ** and the pager code use this trick (clearing the first byte ** of the page 'extra' space to invalidate the Btree layers ** cached parse of the page). MemPage.isInit is marked ** "MUST BE FIRST" for this purpose. */ memcpy(zOut, zIn, nCopy); ((u8 *)sqlite3PagerGetExtra(pDestPg))[0] = 0; } sqlite3PagerUnref(pDestPg); } return rc; } | > > > | 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 | ** and the pager code use this trick (clearing the first byte ** of the page 'extra' space to invalidate the Btree layers ** cached parse of the page). MemPage.isInit is marked ** "MUST BE FIRST" for this purpose. */ memcpy(zOut, zIn, nCopy); ((u8 *)sqlite3PagerGetExtra(pDestPg))[0] = 0; if( iOff==0 && bUpdate==0 ){ sqlite3Put4byte(&zOut[28], sqlite3BtreeLastPage(p->pSrc)); } } sqlite3PagerUnref(pDestPg); } return rc; } |
︙ | ︙ | |||
387 388 389 390 391 392 393 | assert( nSrcPage>=0 ); for(ii=0; (nPage<0 || ii<nPage) && p->iNext<=(Pgno)nSrcPage && !rc; ii++){ const Pgno iSrcPg = p->iNext; /* Source page number */ if( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ){ DbPage *pSrcPg; /* Source page object */ rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg); if( rc==SQLITE_OK ){ | | | 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 | assert( nSrcPage>=0 ); for(ii=0; (nPage<0 || ii<nPage) && p->iNext<=(Pgno)nSrcPage && !rc; ii++){ const Pgno iSrcPg = p->iNext; /* Source page number */ if( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ){ DbPage *pSrcPg; /* Source page object */ rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg); if( rc==SQLITE_OK ){ rc = backupOnePage(p, iSrcPg, sqlite3PagerGetData(pSrcPg), 0); sqlite3PagerUnref(pSrcPg); } } p->iNext++; } if( rc==SQLITE_OK ){ p->nPagecount = nSrcPage; |
︙ | ︙ | |||
450 451 452 453 454 455 456 | if( nDestTruncate==(int)PENDING_BYTE_PAGE(p->pDest->pBt) ){ nDestTruncate--; } }else{ nDestTruncate = nSrcPage * (pgszSrc/pgszDest); } assert( nDestTruncate>0 ); | < > > | > > > > > > > > > > > > | > | 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 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 | if( nDestTruncate==(int)PENDING_BYTE_PAGE(p->pDest->pBt) ){ nDestTruncate--; } }else{ nDestTruncate = nSrcPage * (pgszSrc/pgszDest); } assert( nDestTruncate>0 ); if( pgszSrc<pgszDest ){ /* If the source page-size is smaller than the destination page-size, ** two extra things may need to happen: ** ** * The destination may need to be truncated, and ** ** * Data stored on the pages immediately following the ** pending-byte page in the source database may need to be ** copied into the destination database. */ const i64 iSize = (i64)pgszSrc * (i64)nSrcPage; sqlite3_file * const pFile = sqlite3PagerFile(pDestPager); Pgno iPg; int nDstPage; i64 iOff; i64 iEnd; assert( pFile ); assert( nDestTruncate==0 || (i64)nDestTruncate*(i64)pgszDest >= iSize || ( nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1) && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest )); /* This block ensures that all data required to recreate the original ** database has been stored in the journal for pDestPager and the ** journal synced to disk. So at this point we may safely modify ** the database file in any way, knowing that if a power failure ** occurs, the original database will be reconstructed from the ** journal file. */ sqlite3PagerPagecount(pDestPager, &nDstPage); for(iPg=nDestTruncate; rc==SQLITE_OK && iPg<=(Pgno)nDstPage; iPg++){ if( iPg!=PENDING_BYTE_PAGE(p->pDest->pBt) ){ DbPage *pPg; rc = sqlite3PagerGet(pDestPager, iPg, &pPg); if( rc==SQLITE_OK ){ rc = sqlite3PagerWrite(pPg); sqlite3PagerUnref(pPg); } } } if( rc==SQLITE_OK ){ rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1); } /* Write the extra pages and truncate the database file as required */ iEnd = MIN(PENDING_BYTE + pgszDest, iSize); for( iOff=PENDING_BYTE+pgszSrc; rc==SQLITE_OK && iOff<iEnd; iOff+=pgszSrc |
︙ | ︙ | |||
507 508 509 510 511 512 513 514 515 516 517 518 519 520 | } /* Sync the database file to disk. */ if( rc==SQLITE_OK ){ rc = sqlite3PagerSync(pDestPager); } }else{ rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0); } /* Finish committing the transaction to the destination database. */ if( SQLITE_OK==rc && SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(p->pDest, 0)) ){ | > | 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 | } /* Sync the database file to disk. */ if( rc==SQLITE_OK ){ rc = sqlite3PagerSync(pDestPager); } }else{ sqlite3PagerTruncateImage(pDestPager, nDestTruncate); rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0); } /* Finish committing the transaction to the destination database. */ if( SQLITE_OK==rc && SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(p->pDest, 0)) ){ |
︙ | ︙ | |||
635 636 637 638 639 640 641 | /* The backup process p has already copied page iPage. But now it ** has been modified by a transaction on the source pager. Copy ** the new data into the backup. */ int rc; assert( p->pDestDb ); sqlite3_mutex_enter(p->pDestDb->mutex); | | | 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 | /* The backup process p has already copied page iPage. But now it ** has been modified by a transaction on the source pager. Copy ** the new data into the backup. */ int rc; assert( p->pDestDb ); sqlite3_mutex_enter(p->pDestDb->mutex); rc = backupOnePage(p, iPage, aData, 1); sqlite3_mutex_leave(p->pDestDb->mutex); assert( rc!=SQLITE_BUSY && rc!=SQLITE_LOCKED ); if( rc!=SQLITE_OK ){ p->rc = rc; } } } |
︙ | ︙ |
Changes to src/btree.c.
︙ | ︙ | |||
39 40 41 42 43 44 45 46 47 48 49 50 51 52 | ** This routine is used to extract the "offset to cell content area" value ** from the header of a btree page. If the page size is 65536 and the page ** is empty, the offset should be 65536, but the 2-byte value stores zero. ** This routine makes the necessary adjustment to 65536. */ #define get2byteNotZero(X) (((((int)get2byte(X))-1)&0xffff)+1) #ifndef SQLITE_OMIT_SHARED_CACHE /* ** A list of BtShared objects that are eligible for participation ** in shared cache. This variable has file scope during normal builds, ** but the test harness needs to access it so we make it global for ** test builds. ** | > > > > > > > > > > > > > > > > > > > | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | ** This routine is used to extract the "offset to cell content area" value ** from the header of a btree page. If the page size is 65536 and the page ** is empty, the offset should be 65536, but the 2-byte value stores zero. ** This routine makes the necessary adjustment to 65536. */ #define get2byteNotZero(X) (((((int)get2byte(X))-1)&0xffff)+1) /* ** Values passed as the 5th argument to allocateBtreePage() */ #define BTALLOC_ANY 0 /* Allocate any page */ #define BTALLOC_EXACT 1 /* Allocate exact page if possible */ #define BTALLOC_LE 2 /* Allocate any page <= the parameter */ /* ** Macro IfNotOmitAV(x) returns (x) if SQLITE_OMIT_AUTOVACUUM is not ** defined, or 0 if it is. For example: ** ** bIncrVacuum = IfNotOmitAV(pBtShared->incrVacuum); */ #ifndef SQLITE_OMIT_AUTOVACUUM #define IfNotOmitAV(expr) (expr) #else #define IfNotOmitAV(expr) 0 #endif #ifndef SQLITE_OMIT_SHARED_CACHE /* ** A list of BtShared objects that are eligible for participation ** in shared cache. This variable has file scope during normal builds, ** but the test harness needs to access it so we make it global for ** test builds. ** |
︙ | ︙ | |||
2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 | /* If the btree is already in a write-transaction, or it ** is already in a read-transaction and a read-transaction ** is requested, this is a no-op. */ if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){ goto trans_begun; } /* Write transactions are not possible on a read-only database */ if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){ rc = SQLITE_READONLY; goto trans_begun; } | > | 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 | /* If the btree is already in a write-transaction, or it ** is already in a read-transaction and a read-transaction ** is requested, this is a no-op. */ if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){ goto trans_begun; } assert( IfNotOmitAV(pBt->bDoTruncate)==0 ); /* Write transactions are not possible on a read-only database */ if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){ rc = SQLITE_READONLY; goto trans_begun; } |
︙ | ︙ | |||
2907 2908 2909 2910 2911 2912 2913 | return rc; } /* Forward declaration required by incrVacuumStep(). */ static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8); /* | | | | > | | | > > | | | < < < < | | | 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 | 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. Or, if an error ** occurs, return some other error code. ** ** 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. ** ** Parameter nFin is the number of pages that this database would contain ** were this function called until it returns SQLITE_DONE. ** ** If the bCommit parameter is non-zero, this function assumes that the ** caller will keep calling incrVacuumStep() until it returns SQLITE_DONE ** or an error. bCommit is passed true for an auto-vacuum-on-commmit ** operation, or false for an incremental vacuum. */ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){ Pgno nFreeList; /* Number of pages still on the free-list */ int rc; assert( sqlite3_mutex_held(pBt->mutex) ); assert( iLastPg>nFin ); if( !PTRMAP_ISPAGE(pBt, iLastPg) && iLastPg!=PENDING_BYTE_PAGE(pBt) ){ |
︙ | ︙ | |||
2949 2950 2951 2952 2953 2954 2955 | return rc; } if( eType==PTRMAP_ROOTPAGE ){ return SQLITE_CORRUPT_BKPT; } if( eType==PTRMAP_FREEPAGE ){ | | | | > > | | > > > > | | < < | < | > | | | | < < > | | | < > | > > > > > > | | > > > > > | > | | < < | | > > > > > > > | | | | | > > > | 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 | return rc; } if( eType==PTRMAP_ROOTPAGE ){ return SQLITE_CORRUPT_BKPT; } if( eType==PTRMAP_FREEPAGE ){ if( bCommit==0 ){ /* Remove the page from the files free-list. This is not required ** if bCommit is non-zero. In that case, the free-list will be ** truncated to zero after this function returns, so it doesn't ** matter if it still contains some garbage entries. */ Pgno iFreePg; MemPage *pFreePg; rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iLastPg, BTALLOC_EXACT); if( rc!=SQLITE_OK ){ return rc; } assert( iFreePg==iLastPg ); releasePage(pFreePg); } } else { Pgno iFreePg; /* Index of free page to move pLastPg to */ MemPage *pLastPg; u8 eMode = BTALLOC_ANY; /* Mode parameter for allocateBtreePage() */ Pgno iNear = 0; /* nearby parameter for allocateBtreePage() */ rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0); if( rc!=SQLITE_OK ){ return rc; } /* If bCommit is zero, this loop runs exactly once and page pLastPg ** is swapped with the first free page pulled off the free list. ** ** On the other hand, if bCommit is greater than zero, then keep ** looping until a free-page located within the first nFin pages ** of the file is found. */ if( bCommit==0 ){ eMode = BTALLOC_LE; iNear = nFin; } do { MemPage *pFreePg; rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iNear, eMode); if( rc!=SQLITE_OK ){ releasePage(pLastPg); return rc; } releasePage(pFreePg); }while( bCommit && iFreePg>nFin ); assert( iFreePg<iLastPg ); rc = relocatePage(pBt, pLastPg, eType, iPtrPage, iFreePg, bCommit); releasePage(pLastPg); if( rc!=SQLITE_OK ){ return rc; } } } if( bCommit==0 ){ do { iLastPg--; }while( iLastPg==PENDING_BYTE_PAGE(pBt) || PTRMAP_ISPAGE(pBt, iLastPg) ); pBt->bDoTruncate = 1; pBt->nPage = iLastPg; } return SQLITE_OK; } /* ** The database opened by the first argument is an auto-vacuum database ** nOrig pages in size containing nFree free pages. Return the expected ** size of the database in pages following an auto-vacuum operation. */ static Pgno finalDbSize(BtShared *pBt, Pgno nOrig, Pgno nFree){ int nEntry; /* Number of entries on one ptrmap page */ Pgno nPtrmap; /* Number of PtrMap pages to be freed */ Pgno nFin; /* Return value */ 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--; } return nFin; } /* ** A write-transaction must be opened before calling this function. ** It performs a single unit of work towards an incremental vacuum. ** ** If the incremental vacuum is finished after this function has run, ** SQLITE_DONE is returned. If it is not finished, but no error occurred, ** SQLITE_OK is returned. Otherwise an SQLite error code. */ int sqlite3BtreeIncrVacuum(Btree *p){ int rc; BtShared *pBt = p->pBt; sqlite3BtreeEnter(p); assert( pBt->inTransaction==TRANS_WRITE && p->inTrans==TRANS_WRITE ); if( !pBt->autoVacuum ){ rc = SQLITE_DONE; }else{ Pgno nOrig = btreePagecount(pBt); Pgno nFree = get4byte(&pBt->pPage1->aData[36]); Pgno nFin = finalDbSize(pBt, nOrig, nFree); if( nOrig<nFin ){ rc = SQLITE_CORRUPT_BKPT; }else if( nFree>0 ){ invalidateAllOverflowCache(pBt); rc = incrVacuumStep(pBt, nFin, nOrig, 0); if( rc==SQLITE_OK ){ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); put4byte(&pBt->pPage1->aData[28], pBt->nPage); } }else{ rc = SQLITE_DONE; } } sqlite3BtreeLeave(p); return rc; } /* |
︙ | ︙ | |||
3073 3074 3075 3076 3077 3078 3079 | 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 */ | < < < | < < < < < < < | | | 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 | assert( sqlite3_mutex_held(pBt->mutex) ); invalidateAllOverflowCache(pBt); assert(pBt->autoVacuum); if( !pBt->incrVacuum ){ Pgno nFin; /* Number of pages in database after autovacuuming */ Pgno nFree; /* Number of pages on the freelist initially */ Pgno iFree; /* The next page to be freed */ Pgno nOrig; /* Database size before freeing */ nOrig = btreePagecount(pBt); if( PTRMAP_ISPAGE(pBt, nOrig) || nOrig==PENDING_BYTE_PAGE(pBt) ){ /* It is not possible to create a database for which the final page ** is either a pointer-map page or the pending-byte page. If one ** is encountered, this indicates corruption. */ return SQLITE_CORRUPT_BKPT; } nFree = get4byte(&pBt->pPage1->aData[36]); nFin = finalDbSize(pBt, nOrig, nFree); if( nFin>nOrig ) return SQLITE_CORRUPT_BKPT; for(iFree=nOrig; iFree>nFin && rc==SQLITE_OK; iFree--){ rc = incrVacuumStep(pBt, nFin, iFree, 1); } if( (rc==SQLITE_DONE || rc==SQLITE_OK) && nFree>0 ){ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); put4byte(&pBt->pPage1->aData[32], 0); put4byte(&pBt->pPage1->aData[36], 0); put4byte(&pBt->pPage1->aData[28], nFin); pBt->bDoTruncate = 1; pBt->nPage = nFin; } if( rc!=SQLITE_OK ){ sqlite3PagerRollback(pPager); } } |
︙ | ︙ | |||
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 | if( pBt->autoVacuum ){ rc = autoVacuumCommit(pBt); if( rc!=SQLITE_OK ){ sqlite3BtreeLeave(p); return rc; } } #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; | > > > > > > | 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 | if( pBt->autoVacuum ){ rc = autoVacuumCommit(pBt); if( rc!=SQLITE_OK ){ sqlite3BtreeLeave(p); return rc; } } if( pBt->bDoTruncate ){ sqlite3PagerTruncateImage(pBt->pPager, pBt->nPage); } #endif rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zMaster, 0); sqlite3BtreeLeave(p); } return rc; } /* ** This function is called from both BtreeCommitPhaseTwo() and BtreeRollback() ** at the conclusion of a transaction. */ static void btreeEndTransaction(Btree *p){ BtShared *pBt = p->pBt; assert( sqlite3BtreeHoldsMutex(p) ); #ifndef SQLITE_OMIT_AUTOVACUUM pBt->bDoTruncate = 0; #endif 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; |
︙ | ︙ | |||
4849 4850 4851 4852 4853 4854 4855 | ** been referenced and the calling routine is responsible for calling ** sqlite3PagerUnref() on the new page when it is done. ** ** SQLITE_OK is returned on success. Any other return value indicates ** an error. *ppPage and *pPgno are undefined in the event of an error. ** Do not invoke sqlite3PagerUnref() on *ppPage if an error is returned. ** | | | | | > > | | | | | > | > | | | | | | | | | > > | | > | 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 | ** been referenced and the calling routine is responsible for calling ** sqlite3PagerUnref() on the new page when it is done. ** ** SQLITE_OK is returned on success. Any other return value indicates ** an error. *ppPage and *pPgno are undefined in the event of an error. ** Do not invoke sqlite3PagerUnref() on *ppPage if an error is returned. ** ** If the "nearby" parameter is not 0, then an effort is made to ** locate a page close to the page number "nearby". This can be used in an ** attempt to keep related pages close to each other in the database file, ** which in turn can make database access faster. ** ** If the eMode parameter is BTALLOC_EXACT and the nearby page exists ** anywhere on the free-list, then it is guaranteed to be returned. If ** eMode is BTALLOC_LT then the page returned will be less than or equal ** to nearby if any such page exists. If eMode is BTALLOC_ANY then there ** are no restrictions on which page is returned. */ static int allocateBtreePage( BtShared *pBt, /* The btree */ MemPage **ppPage, /* Store pointer to the allocated page here */ Pgno *pPgno, /* Store the page number here */ Pgno nearby, /* Search for a page near this one */ u8 eMode /* BTALLOC_EXACT, BTALLOC_LT, or BTALLOC_ANY */ ){ MemPage *pPage1; int rc; u32 n; /* Number of pages on the freelist */ u32 k; /* Number of leaves on the trunk of the freelist */ MemPage *pTrunk = 0; MemPage *pPrevTrunk = 0; Pgno mxPage; /* Total size of the database file */ assert( sqlite3_mutex_held(pBt->mutex) ); assert( eMode==BTALLOC_ANY || (nearby>0 && IfNotOmitAV(pBt->autoVacuum)) ); pPage1 = pBt->pPage1; mxPage = btreePagecount(pBt); 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' */ /* If eMode==BTALLOC_EXACT and a query of the pointer-map ** shows that the page 'nearby' is somewhere on the free-list, then ** the entire-list will be searched for that page. */ #ifndef SQLITE_OMIT_AUTOVACUUM if( eMode==BTALLOC_EXACT ){ if( nearby<=mxPage ){ u8 eType; assert( nearby>0 ); assert( pBt->autoVacuum ); rc = ptrmapGet(pBt, nearby, &eType, 0); if( rc ) return rc; if( eType==PTRMAP_FREEPAGE ){ searchList = 1; } } }else if( eMode==BTALLOC_LE ){ searchList = 1; } #endif /* Decrement the free-list count by 1. Set iTrunk to the index of the ** first free-list trunk page. iPrevTrunk is initially 1. */ rc = sqlite3PagerWrite(pPage1->pDbPage); if( rc ) return rc; put4byte(&pPage1->aData[36], n-1); /* The code within this loop is run only once if the 'searchList' variable ** is not true. Otherwise, it runs once for each trunk-page on the ** free-list until the page 'nearby' is located (eMode==BTALLOC_EXACT) ** or until a page less than 'nearby' is located (eMode==BTALLOC_LT) */ do { pPrevTrunk = pTrunk; if( pPrevTrunk ){ iTrunk = get4byte(&pPrevTrunk->aData[0]); }else{ iTrunk = get4byte(&pPage1->aData[32]); |
︙ | ︙ | |||
4955 4956 4957 4958 4959 4960 4961 | pTrunk = 0; TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1)); }else if( k>(u32)(pBt->usableSize/4 - 2) ){ /* Value of k is out of range. Database corruption */ rc = SQLITE_CORRUPT_BKPT; goto end_allocate_page; #ifndef SQLITE_OMIT_AUTOVACUUM | | > > | | 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 | pTrunk = 0; TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1)); }else if( k>(u32)(pBt->usableSize/4 - 2) ){ /* Value of k is out of range. Database corruption */ rc = SQLITE_CORRUPT_BKPT; goto end_allocate_page; #ifndef SQLITE_OMIT_AUTOVACUUM }else if( searchList && (nearby==iTrunk || (iTrunk<nearby && eMode==BTALLOC_LE)) ){ /* The list is being searched and this trunk page is the page ** to allocate, regardless of whether it has leaves. */ *pPgno = iTrunk; *ppPage = pTrunk; searchList = 0; rc = sqlite3PagerWrite(pTrunk->pDbPage); if( rc ){ goto end_allocate_page; } if( k==0 ){ |
︙ | ︙ | |||
5022 5023 5024 5025 5026 5027 5028 | }else if( k>0 ){ /* Extract a leaf from the trunk */ u32 closest; Pgno iPage; unsigned char *aData = pTrunk->aData; if( nearby>0 ){ u32 i; | < > > > > > > > > > > | | | | | | > | > > | 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 | }else if( k>0 ){ /* Extract a leaf from the trunk */ u32 closest; Pgno iPage; unsigned char *aData = pTrunk->aData; if( nearby>0 ){ u32 i; closest = 0; if( eMode==BTALLOC_LE ){ for(i=0; i<k; i++){ iPage = get4byte(&aData[8+i*4]); if( iPage<=nearby ){ closest = i; break; } } }else{ int dist; dist = sqlite3AbsInt32(get4byte(&aData[8]) - nearby); for(i=1; i<k; i++){ int d2 = sqlite3AbsInt32(get4byte(&aData[8+i*4]) - nearby); if( d2<dist ){ closest = i; dist = d2; } } } }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 || (iPage<nearby && eMode==BTALLOC_LE)) ){ 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)); rc = sqlite3PagerWrite(pTrunk->pDbPage); if( rc ) goto end_allocate_page; |
︙ | ︙ | |||
5070 5071 5072 5073 5074 5075 5076 | searchList = 0; } } releasePage(pPrevTrunk); pPrevTrunk = 0; }while( searchList ); }else{ | | > > > > > > > > > > > > > > > > > > | | | | 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 | searchList = 0; } } releasePage(pPrevTrunk); pPrevTrunk = 0; }while( searchList ); }else{ /* There are no pages on the freelist, so append a new page to the ** database image. ** ** Normally, new pages allocated by this block can be requested from the ** pager layer with the 'no-content' flag set. This prevents the pager ** from trying to read the pages content from disk. However, if the ** current transaction has already run one or more incremental-vacuum ** steps, then the page we are about to allocate may contain content ** that is required in the event of a rollback. In this case, do ** not set the no-content flag. This causes the pager to load and journal ** the current page content before overwriting it. ** ** Note that the pager will not actually attempt to load or journal ** content for any page that really does lie past the end of the database ** file on disk. So the effects of disabling the no-content optimization ** here are confined to those pages that lie between the end of the ** database image and the end of the database file. */ int bNoContent = (0==IfNotOmitAV(pBt->bDoTruncate)); rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); if( rc ) return rc; pBt->nPage++; if( pBt->nPage==PENDING_BYTE_PAGE(pBt) ) pBt->nPage++; #ifndef SQLITE_OMIT_AUTOVACUUM if( pBt->autoVacuum && PTRMAP_ISPAGE(pBt, pBt->nPage) ){ /* If *pPgno refers to a pointer-map page, allocate two new pages ** at the end of the file instead of one. The first allocated page ** becomes a new pointer-map page, the second is used by the caller. */ MemPage *pPg = 0; TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage)); assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) ); rc = btreeGetPage(pBt, pBt->nPage, &pPg, bNoContent); if( rc==SQLITE_OK ){ rc = sqlite3PagerWrite(pPg->pDbPage); releasePage(pPg); } if( rc ) return rc; pBt->nPage++; if( pBt->nPage==PENDING_BYTE_PAGE(pBt) ){ pBt->nPage++; } } #endif put4byte(28 + (u8*)pBt->pPage1->aData, pBt->nPage); *pPgno = pBt->nPage; assert( *pPgno!=PENDING_BYTE_PAGE(pBt) ); rc = btreeGetPage(pBt, *pPgno, ppPage, bNoContent); if( rc ) return rc; rc = sqlite3PagerWrite((*ppPage)->pDbPage); if( rc!=SQLITE_OK ){ releasePage(*ppPage); } TRACE(("ALLOCATE: %d from end of file\n", *pPgno)); } |
︙ | ︙ | |||
7115 7116 7117 7118 7119 7120 7121 | } assert( pgnoRoot>=3 ); /* Allocate a page. The page that currently resides at pgnoRoot will ** be moved to the allocated page (unless the allocated page happens ** to reside at pgnoRoot). */ | | | 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 | } assert( pgnoRoot>=3 ); /* Allocate a page. The page that currently resides at pgnoRoot will ** be moved to the allocated page (unless the allocated page happens ** to reside at pgnoRoot). */ rc = allocateBtreePage(pBt, &pPageMove, &pgnoMove, pgnoRoot, BTALLOC_EXACT); if( rc!=SQLITE_OK ){ return rc; } 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 |
︙ | ︙ | |||
8022 8023 8024 8025 8026 8027 8028 | if( !sCheck.aPgRef ){ *pnErr = 1; sqlite3BtreeLeave(p); return 0; } i = PENDING_BYTE_PAGE(pBt); if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i); | | | 8099 8100 8101 8102 8103 8104 8105 8106 8107 8108 8109 8110 8111 8112 8113 | if( !sCheck.aPgRef ){ *pnErr = 1; sqlite3BtreeLeave(p); return 0; } i = PENDING_BYTE_PAGE(pBt); if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i); sqlite3StrAccumInit(&sCheck.errMsg, zErr, sizeof(zErr), SQLITE_MAX_LENGTH); sCheck.errMsg.useMalloc = 2; /* Check the integrity of the freelist */ checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]), get4byte(&pBt->pPage1->aData[36]), "Main freelist: "); |
︙ | ︙ |
Changes to src/btreeInt.h.
︙ | ︙ | |||
407 408 409 410 411 412 413 414 415 416 417 418 419 420 | sqlite3 *db; /* Database connection currently using this Btree */ BtCursor *pCursor; /* A list of all open cursors */ MemPage *pPage1; /* First page of the database */ u8 openFlags; /* Flags to sqlite3BtreeOpen() */ #ifndef SQLITE_OMIT_AUTOVACUUM u8 autoVacuum; /* True if auto-vacuum is enabled */ u8 incrVacuum; /* True if incr-vacuum is enabled */ #endif u8 inTransaction; /* Transaction state */ u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */ u16 btsFlags; /* Boolean parameters. See BTS_* macros below */ u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */ u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */ u16 maxLeaf; /* Maximum local payload in a LEAFDATA table */ | > | 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 | sqlite3 *db; /* Database connection currently using this Btree */ BtCursor *pCursor; /* A list of all open cursors */ MemPage *pPage1; /* First page of the database */ u8 openFlags; /* Flags to sqlite3BtreeOpen() */ #ifndef SQLITE_OMIT_AUTOVACUUM u8 autoVacuum; /* True if auto-vacuum is enabled */ u8 incrVacuum; /* True if incr-vacuum is enabled */ u8 bDoTruncate; /* True to truncate db on commit */ #endif u8 inTransaction; /* Transaction state */ u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */ u16 btsFlags; /* Boolean parameters. See BTS_* macros below */ u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */ u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */ u16 maxLeaf; /* Maximum local payload in a LEAFDATA table */ |
︙ | ︙ |
Changes to src/build.c.
︙ | ︙ | |||
2443 2444 2445 2446 2447 2448 2449 | sqlite3VdbeJumpHere(v, addr1); addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); if( pIndex->onError!=OE_None ){ int j2 = sqlite3VdbeCurrentAddr(v) + 3; sqlite3VdbeAddOp2(v, OP_Goto, 0, j2); addr2 = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp3(v, OP_SorterCompare, iSorter, j2, regRecord); | | | | 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 | sqlite3VdbeJumpHere(v, addr1); addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); if( pIndex->onError!=OE_None ){ int j2 = sqlite3VdbeCurrentAddr(v) + 3; sqlite3VdbeAddOp2(v, OP_Goto, 0, j2); addr2 = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp3(v, OP_SorterCompare, iSorter, j2, regRecord); sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_UNIQUE, OE_Abort, "indexed columns are not unique", P4_STATIC ); }else{ addr2 = sqlite3VdbeCurrentAddr(v); } sqlite3VdbeAddOp2(v, OP_SorterData, iSorter, regRecord); sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 1); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); |
︙ | ︙ | |||
2470 2471 2472 2473 2474 2475 2476 | ** (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); | | | | 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 | ** (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, SQLITE_CONSTRAINT_UNIQUE, "indexed columns are not unique", P4_STATIC); } sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 0); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); #endif sqlite3ReleaseTempReg(pParse, regRecord); sqlite3VdbeAddOp2(v, OP_SorterNext, iSorter, addr2); sqlite3VdbeJumpHere(v, addr1); |
︙ | ︙ | |||
2590 2591 2592 2593 2594 2595 2596 | iDb = sqlite3SchemaToIndex(db, pTab->pSchema); } pDb = &db->aDb[iDb]; assert( pTab!=0 ); assert( pParse->nErr==0 ); if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 | | | 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 | iDb = sqlite3SchemaToIndex(db, pTab->pSchema); } pDb = &db->aDb[iDb]; assert( pTab!=0 ); assert( pParse->nErr==0 ); if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 && sqlite3StrNICmp(&pTab->zName[7],"altertab_",9)!=0 ){ sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName); goto exit_create_index; } #ifndef SQLITE_OMIT_VIEW if( pTab->pSelect ){ sqlite3ErrorMsg(pParse, "views may not be indexed"); goto exit_create_index; |
︙ | ︙ | |||
3688 3689 3690 3691 3692 3693 3694 | } /* ** 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. */ | | > > > > > > > | | 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 | } /* ** 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, /* Parsing context */ int errCode, /* extended error code */ int onError, /* Constraint type */ char *p4, /* Error message */ int p4type /* P4_STATIC or P4_TRANSIENT */ ){ Vdbe *v = sqlite3GetVdbe(pParse); assert( (errCode&0xff)==SQLITE_CONSTRAINT ); if( onError==OE_Abort ){ sqlite3MayAbort(pParse); } sqlite3VdbeAddOp4(v, OP_Halt, errCode, 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/delete.c.
︙ | ︙ | |||
89 90 91 92 93 94 95 | void sqlite3MaterializeView( Parse *pParse, /* Parsing context */ Table *pView, /* View definition */ Expr *pWhere, /* Optional WHERE clause to be added */ int iCur /* Cursor number for ephemerial table */ ){ SelectDest dest; | | > | < < < | | | > | | | | | | < < | > | | | | | | 89 90 91 92 93 94 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 | void sqlite3MaterializeView( Parse *pParse, /* Parsing context */ Table *pView, /* View definition */ Expr *pWhere, /* Optional WHERE clause to be added */ int iCur /* Cursor number for ephemerial table */ ){ SelectDest dest; Select *pSel; SrcList *pFrom; sqlite3 *db = pParse->db; int iDb = sqlite3SchemaToIndex(db, pView->pSchema); pWhere = sqlite3ExprDup(db, pWhere, 0); pFrom = sqlite3SrcListAppend(db, 0, 0, 0); if( pFrom ){ assert( pFrom->nSrc==1 ); pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName); pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName); assert( pFrom->a[0].pOn==0 ); assert( pFrom->a[0].pUsing==0 ); } pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, 0, 0, 0); if( pSel ) pSel->selFlags |= SF_Materialize; sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur); sqlite3Select(pParse, pSel, &dest); sqlite3SelectDelete(db, pSel); } #endif /* !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) */ #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) /* ** Generate an expression tree to implement the WHERE, ORDER BY, ** and LIMIT/OFFSET portion of DELETE and UPDATE statements. |
︙ | ︙ |
Changes to src/expr.c.
︙ | ︙ | |||
634 635 636 637 638 639 640 | }else{ /* Wildcards like ":aaa", "$aaa" or "@aaa". Reuse the same variable ** number as the prior appearance of the same name, or if the name ** has never appeared before, reuse the same variable number */ ynVar i; for(i=0; i<pParse->nzVar; i++){ | | | 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 | }else{ /* Wildcards like ":aaa", "$aaa" or "@aaa". Reuse the same variable ** number as the prior appearance of the same name, or if the name ** has never appeared before, reuse the same variable number */ ynVar i; for(i=0; i<pParse->nzVar; i++){ if( pParse->azVar[i] && strcmp(pParse->azVar[i],z)==0 ){ pExpr->iColumn = x = (ynVar)i+1; break; } } if( x==0 ) x = pExpr->iColumn = (ynVar)(++pParse->nVar); } if( x>0 ){ |
︙ | ︙ | |||
1452 1453 1454 1455 1456 1457 1458 | ** all members of the RHS set, skipping duplicates. ** ** A cursor is opened on the b-tree object that the RHS of the IN operator ** and pX->iTable is set to the index of that cursor. ** ** The returned value of this function indicates the b-tree type, as follows: ** | | > | | | | 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 | ** all members of the RHS set, skipping duplicates. ** ** A cursor is opened on the b-tree object that the RHS of the IN operator ** and pX->iTable is set to the index of that cursor. ** ** The returned value of this function indicates the b-tree type, as follows: ** ** IN_INDEX_ROWID - The cursor was opened on a database table. ** IN_INDEX_INDEX_ASC - The cursor was opened on an ascending index. ** IN_INDEX_INDEX_DESC - The cursor was opened on a descending index. ** IN_INDEX_EPH - The cursor was opened on a specially created and ** populated epheremal table. ** ** An existing b-tree might be used if the RHS expression pX is a simple ** subquery such as: ** ** SELECT <column> FROM <table> ** ** If the RHS of the IN operator is a list or a more complex subquery, then |
︙ | ︙ | |||
1578 1579 1580 1581 1582 1583 1584 | pKey = (char *)sqlite3IndexKeyinfo(pParse, pIdx); iAddr = sqlite3CodeOnce(pParse); sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb, pKey,P4_KEYINFO_HANDOFF); VdbeComment((v, "%s", pIdx->zName)); | > | | 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 | pKey = (char *)sqlite3IndexKeyinfo(pParse, pIdx); iAddr = sqlite3CodeOnce(pParse); sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb, pKey,P4_KEYINFO_HANDOFF); VdbeComment((v, "%s", pIdx->zName)); assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 ); eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0]; sqlite3VdbeJumpHere(v, iAddr); if( prNotFound && !pTab->aCol[iCol].notNull ){ *prNotFound = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound); } } |
︙ | ︙ | |||
2931 2932 2933 2934 2935 2936 2937 | 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{ | | > | 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 | 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, SQLITE_CONSTRAINT_TRIGGER, pExpr->affinity, pExpr->u.zToken, 0); } break; } #endif } sqlite3ReleaseTempReg(pParse, regFree1); |
︙ | ︙ | |||
3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 | }else{ sqlite3ExplainPush(pOut); for(i=0; i<pList->nExpr; i++){ sqlite3ExplainPrintf(pOut, "item[%d] = ", i); sqlite3ExplainPush(pOut); sqlite3ExplainExpr(pOut, pList->a[i].pExpr); sqlite3ExplainPop(pOut); if( i<pList->nExpr-1 ){ sqlite3ExplainNL(pOut); } } sqlite3ExplainPop(pOut); } } | > > > > > > | 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 | }else{ sqlite3ExplainPush(pOut); for(i=0; i<pList->nExpr; i++){ sqlite3ExplainPrintf(pOut, "item[%d] = ", i); sqlite3ExplainPush(pOut); sqlite3ExplainExpr(pOut, pList->a[i].pExpr); sqlite3ExplainPop(pOut); if( pList->a[i].zName ){ sqlite3ExplainPrintf(pOut, " AS %s", pList->a[i].zName); } if( pList->a[i].bSpanIsTab ){ sqlite3ExplainPrintf(pOut, " (%s)", pList->a[i].zSpan); } if( i<pList->nExpr-1 ){ sqlite3ExplainNL(pOut); } } sqlite3ExplainPop(pOut); } } |
︙ | ︙ |
Changes to src/fkey.c.
︙ | ︙ | |||
17 18 19 20 21 22 23 | #ifndef SQLITE_OMIT_TRIGGER /* ** Deferred and Immediate FKs ** -------------------------- ** ** Foreign keys in SQLite come in two flavours: deferred and immediate. | | > | | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #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_FOREIGNKEY 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 |
︙ | ︙ | |||
82 83 84 85 86 87 88 | ** 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 | | > | 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | ** 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_FOREIGNKEY ** 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 |
︙ | ︙ | |||
138 139 140 141 142 143 144 | ** 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, | | | 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | ** 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 for 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. |
︙ | ︙ | |||
174 175 176 177 178 179 180 | ** 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. */ | | | 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | ** 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. */ int sqlite3FkLocateIndex( 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 */ |
︙ | ︙ | |||
271 272 273 274 275 276 277 | if( i==nCol ) break; /* pIdx is usable */ } } } if( !pIdx ){ if( !pParse->disableTriggers ){ | | > > | 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | if( i==nCol ) break; /* pIdx is usable */ } } } if( !pIdx ){ if( !pParse->disableTriggers ){ sqlite3ErrorMsg(pParse, "foreign key mismatch - \"%w\" referencing \"%w\"", pFKey->pFrom->zName, pFKey->zTo); } sqlite3DbFree(pParse->db, aiCol); return 1; } *ppIdx = pIdx; return 0; |
︙ | ︙ | |||
420 421 422 423 424 425 426 | 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 ); | | | | 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 | 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, SQLITE_CONSTRAINT_FOREIGNKEY, 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); } |
︙ | ︙ | |||
661 662 663 664 665 666 667 | 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); | | | | 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 | 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, SQLITE_CONSTRAINT_FOREIGNKEY, OE_Abort, "foreign key constraint failed", P4_STATIC ); if( iSkip ){ sqlite3VdbeResolveLabel(v, iSkip); } } } |
︙ | ︙ | |||
732 733 734 735 736 737 738 | ** 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); } | | | 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 | ** 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 || sqlite3FkLocateIndex(pParse, pTo, pFKey, &pIdx, &aiFree) ){ assert( isIgnoreErrors==0 || (regOld!=0 && regNew==0) ); if( !isIgnoreErrors || db->mallocFailed ) return; if( pTo==0 ){ /* If isIgnoreErrors is true, then a table is being dropped. In this ** case SQLite runs a "DELETE FROM xxx" on the table being dropped ** before actually dropping it in order to check FK constraints. ** If the parent table of an FK constraint on the current table is |
︙ | ︙ | |||
812 813 814 815 816 817 818 | 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; } | | | 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 | 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( sqlite3FkLocateIndex(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 |
︙ | ︙ | |||
867 868 869 870 871 872 873 | 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; | | | 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 | FKey *p; int i; for(p=pTab->pFKey; p; p=p->pNextFrom){ for(i=0; i<p->nCol; i++) mask |= COLUMN_MASK(p->aCol[i].iFrom); } for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){ Index *pIdx = 0; sqlite3FkLocateIndex(pParse, pTab, p, &pIdx, 0); if( pIdx ){ for(i=0; i<pIdx->nColumn; i++) mask |= COLUMN_MASK(pIdx->aiColumn[i]); } } } return mask; } |
︙ | ︙ | |||
993 994 995 996 997 998 999 | 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 */ | | | 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 | 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( sqlite3FkLocateIndex(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 */ |
︙ | ︙ |
Changes to src/func.c.
︙ | ︙ | |||
957 958 959 960 961 962 963 964 965 966 967 968 969 970 | default: { assert( sqlite3_value_type(argv[0])==SQLITE_NULL ); sqlite3_result_text(context, "NULL", 4, SQLITE_STATIC); break; } } } /* ** The hex() function. Interpret the argument as a blob. Return ** a hexadecimal rendering as text. */ static void hexFunc( sqlite3_context *context, | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | default: { assert( sqlite3_value_type(argv[0])==SQLITE_NULL ); sqlite3_result_text(context, "NULL", 4, SQLITE_STATIC); break; } } } /* ** The unicode() function. Return the integer unicode code-point value ** for the first character of the input string. */ static void unicodeFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const unsigned char *z = sqlite3_value_text(argv[0]); (void)argc; if( z && z[0] ) sqlite3_result_int(context, sqlite3Utf8Read(&z)); } /* ** The char() function takes zero or more arguments, each of which is ** an integer. It constructs a string where each character of the string ** is the unicode character for the corresponding integer argument. */ static void charFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ unsigned char *z, *zOut; int i; zOut = z = sqlite3_malloc( argc*4 ); if( z==0 ){ sqlite3_result_error_nomem(context); return; } for(i=0; i<argc; i++){ sqlite3_int64 x; unsigned c; x = sqlite3_value_int64(argv[i]); if( x<0 || x>0x10ffff ) x = 0xfffd; c = (unsigned)(x & 0x1fffff); if( c<0x00080 ){ *zOut++ = (u8)(c&0xFF); }else if( c<0x00800 ){ *zOut++ = 0xC0 + (u8)((c>>6)&0x1F); *zOut++ = 0x80 + (u8)(c & 0x3F); }else if( c<0x10000 ){ *zOut++ = 0xE0 + (u8)((c>>12)&0x0F); *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); *zOut++ = 0x80 + (u8)(c & 0x3F); }else{ *zOut++ = 0xF0 + (u8)((c>>18) & 0x07); *zOut++ = 0x80 + (u8)((c>>12) & 0x3F); *zOut++ = 0x80 + (u8)((c>>6) & 0x3F); *zOut++ = 0x80 + (u8)(c & 0x3F); } \ } sqlite3_result_text(context, (char*)z, (int)(zOut-z), sqlite3_free); } /* ** The hex() function. Interpret the argument as a blob. Return ** a hexadecimal rendering as text. */ static void hexFunc( sqlite3_context *context, |
︙ | ︙ | |||
1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 | FUNCTION(max, 0, 1, 1, 0 ), AGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize ), FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF), FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH), FUNCTION(instr, 2, 0, 0, instrFunc ), FUNCTION(substr, 2, 0, 0, substrFunc ), FUNCTION(substr, 3, 0, 0, substrFunc ), FUNCTION(abs, 1, 0, 0, absFunc ), #ifndef SQLITE_OMIT_FLOATING_POINT FUNCTION(round, 1, 0, 0, roundFunc ), FUNCTION(round, 2, 0, 0, roundFunc ), #endif FUNCTION(upper, 1, 0, 0, upperFunc ), FUNCTION(lower, 1, 0, 0, lowerFunc ), | > > | 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 | FUNCTION(max, 0, 1, 1, 0 ), AGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize ), FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF), FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH), FUNCTION(instr, 2, 0, 0, instrFunc ), FUNCTION(substr, 2, 0, 0, substrFunc ), FUNCTION(substr, 3, 0, 0, substrFunc ), FUNCTION(unicode, 1, 0, 0, unicodeFunc ), FUNCTION(char, -1, 0, 0, charFunc ), FUNCTION(abs, 1, 0, 0, absFunc ), #ifndef SQLITE_OMIT_FLOATING_POINT FUNCTION(round, 1, 0, 0, roundFunc ), FUNCTION(round, 2, 0, 0, roundFunc ), #endif FUNCTION(upper, 1, 0, 0, upperFunc ), FUNCTION(lower, 1, 0, 0, lowerFunc ), |
︙ | ︙ |
Changes to src/insert.c.
︙ | ︙ | |||
1241 1242 1243 1244 1245 1246 1247 | switch( onError ){ case OE_Abort: sqlite3MayAbort(pParse); case OE_Rollback: case OE_Fail: { char *zMsg; sqlite3VdbeAddOp3(v, OP_HaltIfNull, | | | 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 | switch( onError ){ case OE_Abort: sqlite3MayAbort(pParse); case OE_Rollback: case OE_Fail: { char *zMsg; sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL, onError, regData+i); zMsg = sqlite3MPrintf(db, "%s.%s may not be NULL", pTab->zName, pTab->aCol[i].zName); sqlite3VdbeChangeP4(v, -1, zMsg, P4_DYNAMIC); break; } case OE_Ignore: { sqlite3VdbeAddOp2(v, OP_IsNull, regData+i, ignoreDest); |
︙ | ︙ | |||
1281 1282 1283 1284 1285 1286 1287 | char *zConsName = pCheck->a[i].zName; if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-15569-63625 */ if( zConsName ){ zConsName = sqlite3MPrintf(db, "constraint %s failed", zConsName); }else{ zConsName = 0; } | | > | 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 | char *zConsName = pCheck->a[i].zName; if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-15569-63625 */ if( zConsName ){ zConsName = sqlite3MPrintf(db, "constraint %s failed", zConsName); }else{ zConsName = 0; } sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_CHECK, onError, zConsName, P4_DYNAMIC); } sqlite3VdbeResolveLabel(v, allOk); } } #endif /* !defined(SQLITE_OMIT_CHECK) */ /* If we have an INTEGER PRIMARY KEY, make sure the primary key |
︙ | ︙ | |||
1312 1313 1314 1315 1316 1317 1318 | default: { onError = OE_Abort; /* Fall thru into the next case */ } case OE_Rollback: case OE_Abort: case OE_Fail: { | | | | 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 | default: { onError = OE_Abort; /* Fall thru into the next case */ } case OE_Rollback: case OE_Abort: case OE_Fail: { sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_PRIMARYKEY, 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 table. This will fire ** the triggers and remove both the table and index b-tree entries. |
︙ | ︙ | |||
1440 1441 1442 1443 1444 1445 1446 | sqlite3StrAccumAppend(&errMsg, zSep, -1); zSep = ", "; sqlite3StrAccumAppend(&errMsg, zCol, -1); } sqlite3StrAccumAppend(&errMsg, pIdx->nColumn>1 ? " are not unique" : " is not unique", -1); zErr = sqlite3StrAccumFinish(&errMsg); | | > | 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 | 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, SQLITE_CONSTRAINT_UNIQUE, onError, zErr, 0); sqlite3DbFree(errMsg.db, zErr); break; } case OE_Ignore: { assert( seenReplace==0 ); sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); break; |
︙ | ︙ | |||
1848 1849 1850 1851 1852 1853 1854 | 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); | | | | 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 | 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, SQLITE_CONSTRAINT_PRIMARYKEY, 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 ); |
︙ | ︙ |
Changes to src/journal.c.
︙ | ︙ | |||
54 55 56 57 58 59 60 61 62 63 64 65 66 67 | sqlite3_file *pReal = (sqlite3_file *)&p[1]; rc = sqlite3OsOpen(p->pVfs, p->zJournal, pReal, p->flags, 0); if( rc==SQLITE_OK ){ p->pReal = pReal; if( p->iSize>0 ){ assert(p->iSize<=p->nBuf); rc = sqlite3OsWrite(p->pReal, p->zBuf, p->iSize, 0); } } } return rc; } /* | > > > > > > > > | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | sqlite3_file *pReal = (sqlite3_file *)&p[1]; rc = sqlite3OsOpen(p->pVfs, p->zJournal, pReal, p->flags, 0); if( rc==SQLITE_OK ){ p->pReal = pReal; if( p->iSize>0 ){ assert(p->iSize<=p->nBuf); rc = sqlite3OsWrite(p->pReal, p->zBuf, p->iSize, 0); } if( rc!=SQLITE_OK ){ /* If an error occurred while writing to the file, close it before ** returning. This way, SQLite uses the in-memory journal data to ** roll back changes made to the internal page-cache before this ** function was called. */ sqlite3OsClose(pReal); p->pReal = 0; } } } return rc; } /* |
︙ | ︙ |
Changes to src/loadext.c.
︙ | ︙ | |||
374 375 376 377 378 379 380 381 382 383 384 385 386 387 | 0, 0, 0, #endif sqlite3_blob_reopen, sqlite3_vtab_config, sqlite3_vtab_on_conflict, }; /* ** Attempt to load an SQLite extension library contained in the file ** zFile. The entry point is zProc. zProc may be 0 in which case a ** default entry point name (sqlite3_extension_init) is used. Use ** of the default name is recommended. | > > > > > > > > > > > > > | 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 | 0, 0, 0, #endif sqlite3_blob_reopen, sqlite3_vtab_config, sqlite3_vtab_on_conflict, sqlite3_close_v2, sqlite3_db_filename, sqlite3_db_readonly, sqlite3_db_release_memory, sqlite3_errstr, sqlite3_stmt_busy, sqlite3_stmt_readonly, sqlite3_stricmp, sqlite3_uri_boolean, sqlite3_uri_int64, sqlite3_uri_parameter, sqlite3_vsnprintf, sqlite3_wal_checkpoint_v2 }; /* ** Attempt to load an SQLite extension library contained in the file ** zFile. The entry point is zProc. zProc may be 0 in which case a ** default entry point name (sqlite3_extension_init) is used. Use ** of the default name is recommended. |
︙ | ︙ |
Changes to src/main.c.
︙ | ︙ | |||
998 999 1000 1001 1002 1003 1004 | sqlite3BtreeRollback(p, tripCode); db->aDb[i].inTrans = 0; } } sqlite3VtabRollback(db); sqlite3EndBenignMalloc(); | | | 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 | sqlite3BtreeRollback(p, tripCode); db->aDb[i].inTrans = 0; } } sqlite3VtabRollback(db); sqlite3EndBenignMalloc(); if( (db->flags&SQLITE_InternChanges)!=0 && db->init.busy==0 ){ sqlite3ExpirePreparedStatements(db); sqlite3ResetAllSchemasOfConnection(db); } /* Any deferred constraint violations have now been resolved. */ db->nDeferredCons = 0; |
︙ | ︙ |
Changes to src/os_unix.c.
︙ | ︙ | |||
408 409 410 411 412 413 414 | { "pwrite64", (sqlite3_syscall_ptr)pwrite64, 0 }, #else { "pwrite64", (sqlite3_syscall_ptr)0, 0 }, #endif #define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\ aSyscall[13].pCurrent) | < < < < | 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 | { "pwrite64", (sqlite3_syscall_ptr)pwrite64, 0 }, #else { "pwrite64", (sqlite3_syscall_ptr)0, 0 }, #endif #define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\ aSyscall[13].pCurrent) { "fchmod", (sqlite3_syscall_ptr)fchmod, 0 }, #define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent) #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE { "fallocate", (sqlite3_syscall_ptr)posix_fallocate, 0 }, #else { "fallocate", (sqlite3_syscall_ptr)0, 0 }, #endif |
︙ | ︙ | |||
437 438 439 440 441 442 443 | { "rmdir", (sqlite3_syscall_ptr)rmdir, 0 }, #define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent) { "fchown", (sqlite3_syscall_ptr)posixFchown, 0 }, #define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent) | < < < | 433 434 435 436 437 438 439 440 441 442 443 444 445 446 | { "rmdir", (sqlite3_syscall_ptr)rmdir, 0 }, #define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent) { "fchown", (sqlite3_syscall_ptr)posixFchown, 0 }, #define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent) }; /* End of the overrideable system calls */ /* ** This is the xSetSystemCall() method of sqlite3_vfs for all of the ** "unix" VFSes. Return SQLITE_OK opon successfully updating the ** system call pointer, or SQLITE_NOTFOUND if there is no configurable ** system call named zName. |
︙ | ︙ | |||
544 545 546 547 548 549 550 | ** In that way, if a database file is -rw-rw-rw or -rw-rw-r-, and a ** transaction crashes and leaves behind hot journals, then any ** process that is able to write to the database will also be able to ** recover the hot journals. */ static int robust_open(const char *z, int f, mode_t m){ int fd; | < < < | < < < < > | > > > > > | | > | > | 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 | ** In that way, if a database file is -rw-rw-rw or -rw-rw-r-, and a ** transaction crashes and leaves behind hot journals, then any ** process that is able to write to the database will also be able to ** recover the hot journals. */ static int robust_open(const char *z, int f, mode_t m){ int fd; mode_t m2 = m ? m : SQLITE_DEFAULT_FILE_PERMISSIONS; do{ #if defined(O_CLOEXEC) fd = osOpen(z,f|O_CLOEXEC,m2); #else fd = osOpen(z,f,m2); #endif }while( fd<0 && errno==EINTR ); if( fd>=0 ){ if( m!=0 ){ struct stat statbuf; if( osFstat(fd, &statbuf)==0 && statbuf.st_size==0 && (statbuf.st_mode&0777)!=m ){ osFchmod(fd, m); } } #if defined(FD_CLOEXEC) && (!defined(O_CLOEXEC) || O_CLOEXEC==0) osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC); #endif } return fd; } /* ** Helper functions to obtain and relinquish the global mutex. The ** global mutex is used to protect the unixInodeInfo and ** vxworksFileId objects used by this file, all of which may be |
︙ | ︙ | |||
4757 4758 4759 4760 4761 4762 4763 | pNew->pVfs = pVfs; pNew->zPath = zFilename; pNew->ctrlFlags = (u8)ctrlFlags; if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0), "psow", SQLITE_POWERSAFE_OVERWRITE) ){ pNew->ctrlFlags |= UNIXFILE_PSOW; } | | | 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 | pNew->pVfs = pVfs; pNew->zPath = zFilename; pNew->ctrlFlags = (u8)ctrlFlags; if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0), "psow", SQLITE_POWERSAFE_OVERWRITE) ){ pNew->ctrlFlags |= UNIXFILE_PSOW; } if( strcmp(pVfs->zName,"unix-excl")==0 ){ pNew->ctrlFlags |= UNIXFILE_EXCL; } #if OS_VXWORKS pNew->pId = vxworksFindFileId(zFilename); if( pNew->pId==0 ){ ctrlFlags |= UNIXFILE_NOLOCK; |
︙ | ︙ | |||
6990 6991 6992 6993 6994 6995 6996 | UNIXVFS("unix-proxy", proxyIoFinder ), #endif }; unsigned int i; /* Loop counter */ /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ | | | 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 | UNIXVFS("unix-proxy", proxyIoFinder ), #endif }; unsigned int i; /* Loop counter */ /* Double-check that the aSyscall[] array has been constructed ** correctly. See ticket [bb3a86e890c8e96ab] */ assert( ArraySize(aSyscall)==21 ); /* Register all VFSes defined in the aVfs[] array */ for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){ sqlite3_vfs_register(&aVfs[i], i==0); } return SQLITE_OK; } |
︙ | ︙ |
Changes to src/os_win.c.
︙ | ︙ | |||
984 985 986 987 988 989 990 | } /* ** This function outputs the specified (ANSI) string to the Win32 debugger ** (if available). */ | | | 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 | } /* ** This function outputs the specified (ANSI) string to the Win32 debugger ** (if available). */ void sqlite3_win32_write_debug(const char *zBuf, int nBuf){ char zDbgBuf[SQLITE_WIN32_DBG_BUF_SIZE]; int nMin = MIN(nBuf, (SQLITE_WIN32_DBG_BUF_SIZE - 1)); /* may be negative. */ if( nMin<-1 ) nMin = -1; /* all negative values become -1. */ assert( nMin==-1 || nMin==0 || nMin<SQLITE_WIN32_DBG_BUF_SIZE ); #if defined(SQLITE_WIN32_HAS_ANSI) if( nMin>0 ){ memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE); |
︙ | ︙ | |||
1617 1618 1619 1620 1621 1622 1623 1624 | } } #if SQLITE_OS_WINCE /************************************************************************* ** This section contains code for WinCE only. */ /* | > | | | 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 | } } #if SQLITE_OS_WINCE /************************************************************************* ** This section contains code for WinCE only. */ #if !defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API /* ** The MSVC CRT on Windows CE may not have a localtime() function. So ** create a substitute. */ #include <time.h> struct tm *__cdecl localtime(const time_t *t) { static struct tm y; FILETIME uTm, lTm; SYSTEMTIME pTm; |
︙ | ︙ | |||
1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 | 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; } #define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)] /* ** Acquire a lock on the handle h */ static void winceMutexAcquire(HANDLE h){ | > | 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 | 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; } #endif #define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)] /* ** Acquire a lock on the handle h */ static void winceMutexAcquire(HANDLE h){ |
︙ | ︙ | |||
1664 1665 1666 1667 1668 1669 1670 | */ #define winceMutexRelease(h) ReleaseMutex(h) /* ** Create the mutex and shared memory used for locking in the file ** descriptor pFile */ | | > > | > | | > | | | | | > | > > > > > > | | | | 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 | */ #define winceMutexRelease(h) ReleaseMutex(h) /* ** Create the mutex and shared memory used for locking in the file ** descriptor pFile */ static int winceCreateLock(const char *zFilename, winFile *pFile){ LPWSTR zTok; LPWSTR zName; DWORD lastErrno; BOOL bLogged = FALSE; BOOL bInit = TRUE; zName = utf8ToUnicode(zFilename); if( zName==0 ){ /* out of memory */ return SQLITE_IOERR_NOMEM; } /* Initialize the local lockdata */ memset(&pFile->local, 0, sizeof(pFile->local)); /* Replace the backslashes from the filename and lowercase it ** to derive a mutex name. */ zTok = osCharLowerW(zName); for (;*zTok;zTok++){ if (*zTok == '\\') *zTok = '_'; } /* Create/open the named mutex */ pFile->hMutex = osCreateMutexW(NULL, FALSE, zName); if (!pFile->hMutex){ pFile->lastErrno = osGetLastError(); winLogError(SQLITE_IOERR, pFile->lastErrno, "winceCreateLock1", zFilename); sqlite3_free(zName); return SQLITE_IOERR; } /* Acquire the mutex before continuing */ winceMutexAcquire(pFile->hMutex); /* Since the names of named mutexes, semaphores, file mappings etc are ** case-sensitive, take advantage of that by uppercasing the mutex name ** and using that as the shared filemapping name. */ osCharUpperW(zName); pFile->hShared = osCreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(winceLock), zName); /* Set a flag that indicates we're the first to create the memory so it ** must be zero-initialized */ lastErrno = osGetLastError(); if (lastErrno == ERROR_ALREADY_EXISTS){ bInit = FALSE; } sqlite3_free(zName); /* If we succeeded in making the shared memory handle, map it. */ if( pFile->hShared ){ pFile->shared = (winceLock*)osMapViewOfFile(pFile->hShared, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock)); /* If mapping failed, close the shared memory handle and erase it */ if( !pFile->shared ){ pFile->lastErrno = osGetLastError(); winLogError(SQLITE_IOERR, pFile->lastErrno, "winceCreateLock2", zFilename); bLogged = TRUE; osCloseHandle(pFile->hShared); pFile->hShared = NULL; } } /* If shared memory could not be created, then close the mutex and fail */ if( pFile->hShared==NULL ){ if( !bLogged ){ pFile->lastErrno = lastErrno; winLogError(SQLITE_IOERR, pFile->lastErrno, "winceCreateLock3", zFilename); bLogged = TRUE; } winceMutexRelease(pFile->hMutex); osCloseHandle(pFile->hMutex); pFile->hMutex = NULL; return SQLITE_IOERR; } /* Initialize the shared memory if we're supposed to */ if( bInit ){ memset(pFile->shared, 0, sizeof(winceLock)); } winceMutexRelease(pFile->hMutex); return SQLITE_OK; } /* ** Destroy the part of winFile that deals with wince locks */ static void winceDestroyLock(winFile *pFile){ if (pFile->hMutex){ |
︙ | ︙ | |||
1821 1822 1823 1824 1825 1826 1827 | pFile->shared->nReaders ++; } bReturn = TRUE; } } /* Want a pending lock? */ | | > | > | 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 | 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; } } |
︙ | ︙ | |||
1874 1875 1876 1877 1878 1879 1880 | pFile->local.bExclusive = FALSE; pFile->shared->bExclusive = FALSE; bReturn = TRUE; } /* Did we just have a reader lock? */ else if (pFile->local.nReaders){ | | > | > | > | 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 | 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; } } |
︙ | ︙ | |||
2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 | winFile *pFile = (winFile*)id; assert( id!=0 ); #ifndef SQLITE_OMIT_WAL assert( pFile->pShm==0 ); #endif OSTRACE(("CLOSE %d\n", pFile->h)); do{ rc = osCloseHandle(pFile->h); /* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */ }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (sqlite3_win32_sleep(100), 1) ); #if SQLITE_OS_WINCE #define WINCE_DELETION_ATTEMPTS 3 winceDestroyLock(pFile); | > | 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 | winFile *pFile = (winFile*)id; assert( id!=0 ); #ifndef SQLITE_OMIT_WAL assert( pFile->pShm==0 ); #endif OSTRACE(("CLOSE %d\n", pFile->h)); assert( pFile->h!=NULL && pFile->h!=INVALID_HANDLE_VALUE ); do{ rc = osCloseHandle(pFile->h); /* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */ }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (sqlite3_win32_sleep(100), 1) ); #if SQLITE_OS_WINCE #define WINCE_DELETION_ATTEMPTS 3 winceDestroyLock(pFile); |
︙ | ︙ | |||
2751 2752 2753 2754 2755 2756 2757 | win32IoerrRetryDelay = a[1]; }else{ a[1] = win32IoerrRetryDelay; } return SQLITE_OK; } case SQLITE_FCNTL_TEMPFILENAME: { | | | 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 | win32IoerrRetryDelay = a[1]; }else{ a[1] = win32IoerrRetryDelay; } return SQLITE_OK; } case SQLITE_FCNTL_TEMPFILENAME: { char *zTFile = sqlite3MallocZero( pFile->pVfs->mxPathname ); if( zTFile ){ getTempname(pFile->pVfs->mxPathname, zTFile); *(char**)pArg = zTFile; } return SQLITE_OK; } } |
︙ | ︙ | |||
2975 2976 2977 2978 2979 2980 2981 | (int)osGetCurrentProcessId(), i, bRc ? "ok" : "failed")); bRc = osCloseHandle(p->aRegion[i].hMap); OSTRACE(("SHM-PURGE pid-%d close region=%d %s\n", (int)osGetCurrentProcessId(), i, bRc ? "ok" : "failed")); } | | | 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 | (int)osGetCurrentProcessId(), i, bRc ? "ok" : "failed")); bRc = osCloseHandle(p->aRegion[i].hMap); OSTRACE(("SHM-PURGE pid-%d close region=%d %s\n", (int)osGetCurrentProcessId(), i, bRc ? "ok" : "failed")); } if( p->hFile.h!=NULL && p->hFile.h!=INVALID_HANDLE_VALUE ){ SimulateIOErrorBenign(1); winClose((sqlite3_file *)&p->hFile); SimulateIOErrorBenign(0); } if( deleteFlag ){ SimulateIOErrorBenign(1); sqlite3BeginBenignMalloc(); |
︙ | ︙ | |||
3055 3056 3057 3058 3059 3060 3061 | rc = SQLITE_IOERR_NOMEM; goto shm_open_err; } rc = winOpen(pDbFd->pVfs, pShmNode->zFilename, /* Name of the file (UTF-8) */ (sqlite3_file*)&pShmNode->hFile, /* File handle here */ | | | 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 | rc = SQLITE_IOERR_NOMEM; goto shm_open_err; } rc = winOpen(pDbFd->pVfs, pShmNode->zFilename, /* Name of the file (UTF-8) */ (sqlite3_file*)&pShmNode->hFile, /* File handle here */ SQLITE_OPEN_WAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0); if( SQLITE_OK!=rc ){ goto shm_open_err; } /* Check to see if another process is holding the dead-man switch. ** If not, truncate the file to zero length. |
︙ | ︙ | |||
3670 3671 3672 3673 3674 3675 3676 | /* Assert that the upper layer has set one of the "file-type" flags. */ assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL ); | | | > < < > | 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 | /* Assert that the upper layer has set one of the "file-type" flags. */ assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL ); assert( pFile!=0 ); memset(pFile, 0, sizeof(winFile)); pFile->h = INVALID_HANDLE_VALUE; #if SQLITE_OS_WINRT if( !sqlite3_temp_directory ){ sqlite3_log(SQLITE_ERROR, "sqlite3_temp_directory variable should be set for WinRT"); } #endif /* If the second argument to this function is NULL, generate a ** temporary file name to use */ if( !zUtf8Name ){ assert(isDelete && !isOpenJournal); memset(zTmpname, 0, MAX_PATH+2); rc = getTempname(MAX_PATH+2, zTmpname); if( rc!=SQLITE_OK ){ return rc; } zUtf8Name = zTmpname; } |
︙ | ︙ | |||
3809 3810 3811 3812 3813 3814 3815 | if( h==INVALID_HANDLE_VALUE ){ pFile->lastErrno = lastErrno; winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name); sqlite3_free(zConverted); if( isReadWrite && !isExclusive ){ return winOpen(pVfs, zName, id, | | > > < < < < < < < < < < < < < | | > > > > > > > > > | 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 | if( h==INVALID_HANDLE_VALUE ){ pFile->lastErrno = lastErrno; winLogError(SQLITE_CANTOPEN, pFile->lastErrno, "winOpen", zUtf8Name); sqlite3_free(zConverted); if( isReadWrite && !isExclusive ){ return winOpen(pVfs, zName, id, ((flags|SQLITE_OPEN_READONLY) & ~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), pOutFlags); }else{ return SQLITE_CANTOPEN_BKPT; } } if( pOutFlags ){ if( isReadWrite ){ *pOutFlags = SQLITE_OPEN_READWRITE; }else{ *pOutFlags = SQLITE_OPEN_READONLY; } } #if SQLITE_OS_WINCE if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB && (rc = winceCreateLock(zName, pFile))!=SQLITE_OK ){ osCloseHandle(h); sqlite3_free(zConverted); return rc; } if( isTemp ){ pFile->zDeleteOnClose = zConverted; }else #endif { sqlite3_free(zConverted); } pFile->pMethod = &winIoMethod; pFile->pVfs = pVfs; pFile->h = h; if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){ pFile->ctrlFlags |= WINFILE_PSOW; } pFile->lastErrno = NO_ERROR; pFile->zPath = zName; OpenCounter(+1); return rc; } /* ** Delete the named file. |
︙ | ︙ | |||
3896 3897 3898 3899 3900 3901 3902 | WIN32_FILE_ATTRIBUTE_DATA sAttrData; memset(&sAttrData, 0, sizeof(sAttrData)); if ( osGetFileAttributesExW(zConverted, GetFileExInfoStandard, &sAttrData) ){ attr = sAttrData.dwFileAttributes; }else{ lastErrno = osGetLastError(); | | > | > | 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 | WIN32_FILE_ATTRIBUTE_DATA sAttrData; memset(&sAttrData, 0, sizeof(sAttrData)); if ( osGetFileAttributesExW(zConverted, GetFileExInfoStandard, &sAttrData) ){ attr = sAttrData.dwFileAttributes; }else{ lastErrno = osGetLastError(); if( lastErrno==ERROR_FILE_NOT_FOUND || lastErrno==ERROR_PATH_NOT_FOUND ){ rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */ }else{ rc = SQLITE_ERROR; } break; } #else attr = osGetFileAttributesW(zConverted); #endif if ( attr==INVALID_FILE_ATTRIBUTES ){ lastErrno = osGetLastError(); if( lastErrno==ERROR_FILE_NOT_FOUND || lastErrno==ERROR_PATH_NOT_FOUND ){ rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */ }else{ rc = SQLITE_ERROR; } break; } if ( attr&FILE_ATTRIBUTE_DIRECTORY ){ |
︙ | ︙ | |||
3935 3936 3937 3938 3939 3940 3941 | } #ifdef SQLITE_WIN32_HAS_ANSI else{ do { attr = osGetFileAttributesA(zConverted); if ( attr==INVALID_FILE_ATTRIBUTES ){ lastErrno = osGetLastError(); | | > | 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 | } #ifdef SQLITE_WIN32_HAS_ANSI else{ do { attr = osGetFileAttributesA(zConverted); if ( attr==INVALID_FILE_ATTRIBUTES ){ lastErrno = osGetLastError(); if( lastErrno==ERROR_FILE_NOT_FOUND || lastErrno==ERROR_PATH_NOT_FOUND ){ rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */ }else{ rc = SQLITE_ERROR; } break; } if ( attr&FILE_ATTRIBUTE_DIRECTORY ){ |
︙ | ︙ | |||
4103 4104 4105 4106 4107 4108 4109 | ** NOTE: We are dealing with a relative path name and the data ** directory has been set. Therefore, use it as the basis ** for converting the relative path name to an absolute ** one by prepending the data directory and a slash. */ char zOut[MAX_PATH+1]; memset(zOut, 0, MAX_PATH+1); | | > < < < < < | | 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 | ** NOTE: We are dealing with a relative path name and the data ** directory has been set. Therefore, use it as the basis ** for converting the relative path name to an absolute ** one by prepending the data directory and a slash. */ char zOut[MAX_PATH+1]; memset(zOut, 0, MAX_PATH+1); cygwin_conv_path(CCP_POSIX_TO_WIN_A|CCP_RELATIVE, zRelative, zOut, MAX_PATH+1); sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s\\%s", sqlite3_data_directory, zOut); }else{ cygwin_conv_path(CCP_POSIX_TO_WIN_A, zRelative, zFull, nFull); } return SQLITE_OK; #endif #if (SQLITE_OS_WINCE || SQLITE_OS_WINRT) && !defined(__CYGWIN__) SimulateIOError( return SQLITE_ERROR ); /* WinCE has no concept of a relative pathname, or so I am told. */ |
︙ | ︙ | |||
4270 4271 4272 4273 4274 4275 4276 | sqlite3_free(zConverted); return (void*)h; } static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){ UNUSED_PARAMETER(pVfs); getLastErrorMsg(osGetLastError(), nBuf, zBufOut); } | | | | 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 | sqlite3_free(zConverted); return (void*)h; } static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){ UNUSED_PARAMETER(pVfs); getLastErrorMsg(osGetLastError(), nBuf, zBufOut); } static void (*winDlSym(sqlite3_vfs *pVfs,void *pH,const char *zSym))(void){ UNUSED_PARAMETER(pVfs); return (void(*)(void))osGetProcAddressA((HANDLE)pH, zSym); } static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){ UNUSED_PARAMETER(pVfs); osFreeLibrary((HANDLE)pHandle); } #else /* if SQLITE_OMIT_LOAD_EXTENSION is defined: */ #define winDlOpen 0 |
︙ | ︙ | |||
4370 4371 4372 4373 4374 4375 4376 | FILETIME ft; static const sqlite3_int64 winFiletimeEpoch = 23058135*(sqlite3_int64)8640000; #ifdef SQLITE_TEST static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000; #endif /* 2^32 - to avoid use of LL and warnings in gcc */ static const sqlite3_int64 max32BitValue = | | > | 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 | FILETIME ft; static const sqlite3_int64 winFiletimeEpoch = 23058135*(sqlite3_int64)8640000; #ifdef SQLITE_TEST static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000; #endif /* 2^32 - to avoid use of LL and warnings in gcc */ static const sqlite3_int64 max32BitValue = (sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 + (sqlite3_int64)294967296; #if SQLITE_OS_WINCE SYSTEMTIME time; osGetSystemTime(&time); /* if SystemTimeToFileTime() fails, it returns zero. */ if (!osSystemTimeToFileTime(&time,&ft)){ return SQLITE_ERROR; |
︙ | ︙ |
Changes to src/pager.c.
︙ | ︙ | |||
1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 | if( rc2==SQLITE_FULL || rc2==SQLITE_IOERR ){ pPager->errCode = rc; pPager->eState = PAGER_ERROR; } return rc; } /* ** This routine ends a transaction. A transaction is usually ended by ** either a COMMIT or a ROLLBACK operation. This routine may be called ** after rollback of a hot-journal, or if an error occurs while opening ** the journal file or writing the very first journal-header of a ** database transaction. ** | > > | 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 | if( rc2==SQLITE_FULL || rc2==SQLITE_IOERR ){ pPager->errCode = rc; pPager->eState = PAGER_ERROR; } return rc; } static int pager_truncate(Pager *pPager, Pgno nPage); /* ** This routine ends a transaction. A transaction is usually ended by ** either a COMMIT or a ROLLBACK operation. This routine may be called ** after rollback of a hot-journal, or if an error occurs while opening ** the journal file or writing the very first journal-header of a ** database transaction. ** |
︙ | ︙ | |||
1887 1888 1889 1890 1891 1892 1893 | ** database then the IO error code is returned to the user. If the ** operation to finalize the journal file fails, then the code still ** tries to unlock the database file if not in exclusive mode. If the ** unlock operation fails as well, then the first error code related ** to the first error encountered (the journal finalization one) is ** returned. */ | | | 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 | ** database then the IO error code is returned to the user. If the ** operation to finalize the journal file fails, then the code still ** tries to unlock the database file if not in exclusive mode. If the ** unlock operation fails as well, then the first error code related ** to the first error encountered (the journal finalization one) is ** returned. */ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){ int rc = SQLITE_OK; /* Error code from journal finalization operation */ int rc2 = SQLITE_OK; /* Error code from db file unlock operation */ /* Do nothing if the pager does not have an open write transaction ** or at least a RESERVED lock. This function may be called when there ** is no write-transaction active but a RESERVED or greater lock is ** held under two circumstances: |
︙ | ︙ | |||
1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 | if( pagerUseWal(pPager) ){ /* Drop the WAL write-lock, if any. Also, if the connection was in ** locking_mode=exclusive mode but is no longer, drop the EXCLUSIVE ** lock held on the database file. */ rc2 = sqlite3WalEndWriteTransaction(pPager->pWal); assert( rc2==SQLITE_OK ); } if( !pPager->exclusiveMode && (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0)) ){ rc2 = pagerUnlockDb(pPager, SHARED_LOCK); pPager->changeCountDone = 0; } pPager->eState = PAGER_READER; | > > > > > > > > > > | 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 | if( pagerUseWal(pPager) ){ /* Drop the WAL write-lock, if any. Also, if the connection was in ** locking_mode=exclusive mode but is no longer, drop the EXCLUSIVE ** lock held on the database file. */ rc2 = sqlite3WalEndWriteTransaction(pPager->pWal); assert( rc2==SQLITE_OK ); }else if( rc==SQLITE_OK && bCommit && pPager->dbFileSize>pPager->dbSize ){ /* This branch is taken when committing a transaction in rollback-journal ** mode if the database file on disk is larger than the database image. ** At this point the journal has been finalized and the transaction ** successfully committed, but the EXCLUSIVE lock is still held on the ** file. So it is safe to truncate the database file to its minimum ** required size. */ assert( pPager->eLock==EXCLUSIVE_LOCK ); rc = pager_truncate(pPager, pPager->dbSize); } if( !pPager->exclusiveMode && (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0)) ){ rc2 = pagerUnlockDb(pPager, SHARED_LOCK); pPager->changeCountDone = 0; } pPager->eState = PAGER_READER; |
︙ | ︙ | |||
2012 2013 2014 2015 2016 2017 2018 | assert( assert_pager_state(pPager) ); if( pPager->eState>=PAGER_WRITER_LOCKED ){ sqlite3BeginBenignMalloc(); sqlite3PagerRollback(pPager); sqlite3EndBenignMalloc(); }else if( !pPager->exclusiveMode ){ assert( pPager->eState==PAGER_READER ); | | | 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 | assert( assert_pager_state(pPager) ); if( pPager->eState>=PAGER_WRITER_LOCKED ){ sqlite3BeginBenignMalloc(); sqlite3PagerRollback(pPager); sqlite3EndBenignMalloc(); }else if( !pPager->exclusiveMode ){ assert( pPager->eState==PAGER_READER ); pager_end_transaction(pPager, 0, 0); } } pager_unlock(pPager); } /* ** Parameter aData must point to a buffer of pPager->pageSize bytes |
︙ | ︙ | |||
2787 2788 2789 2790 2791 2792 2793 | } if( rc==SQLITE_OK && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN) ){ rc = sqlite3PagerSync(pPager); } if( rc==SQLITE_OK ){ | | | 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 | } if( rc==SQLITE_OK && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN) ){ rc = sqlite3PagerSync(pPager); } if( rc==SQLITE_OK ){ rc = pager_end_transaction(pPager, zMaster[0]!='\0', 0); testcase( rc!=SQLITE_OK ); } if( rc==SQLITE_OK && zMaster[0] && res ){ /* If there was a master journal and this routine will return success, ** see if it is possible to delete the master journal. */ rc = pager_delmaster(pPager, zMaster); |
︙ | ︙ | |||
3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 | #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->dbSize>=nPage ); assert( pPager->eState>=PAGER_WRITER_CACHEMOD ); pPager->dbSize = nPage; | > > > > > > | > > > > > > > > | 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 | #endif /* ** Truncate the in-memory database file image to nPage pages. This ** function does not actually modify the database file on disk. It ** just sets the internal state of the pager object so that the ** truncation will be done when the current transaction is committed. ** ** This function is only called right before committing a transaction. ** Once this function has been called, the transaction must either be ** rolled back or committed. It is not safe to call this function and ** then continue writing to the database. */ void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){ assert( pPager->dbSize>=nPage ); assert( pPager->eState>=PAGER_WRITER_CACHEMOD ); pPager->dbSize = nPage; /* At one point the code here called assertTruncateConstraint() to ** ensure that all pages being truncated away by this operation are, ** if one or more savepoints are open, present in the savepoint ** journal so that they can be restored if the savepoint is rolled ** back. This is no longer necessary as this function is now only ** called right before committing a transaction. So although the ** Pager object may still have open savepoints (Pager.nSavepoint!=0), ** they cannot be rolled back. So the assertTruncateConstraint() call ** is no longer correct. */ } /* ** This function is called before attempting a hot-journal rollback. It ** syncs the journal file to disk, then sets pPager->journalHdr to the ** size of the journal file so that the pager_playback() routine knows |
︙ | ︙ | |||
4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 | if( pPager->eLock<=SHARED_LOCK ){ rc = hasHotJournal(pPager, &bHotJournal); } if( rc!=SQLITE_OK ){ goto failed; } if( bHotJournal ){ /* Get an EXCLUSIVE lock on the database file. At this point it is ** important that a RESERVED lock is not obtained on the way to the ** EXCLUSIVE lock. If it were, another process might open the ** database file, detect the RESERVED lock, and conclude that the ** database is safe to read while this process is still rolling the ** hot-journal back. ** | > > > > > | 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 | if( pPager->eLock<=SHARED_LOCK ){ rc = hasHotJournal(pPager, &bHotJournal); } if( rc!=SQLITE_OK ){ goto failed; } if( bHotJournal ){ if( pPager->readOnly ){ rc = SQLITE_READONLY_ROLLBACK; goto failed; } /* Get an EXCLUSIVE lock on the database file. At this point it is ** important that a RESERVED lock is not obtained on the way to the ** EXCLUSIVE lock. If it were, another process might open the ** database file, detect the RESERVED lock, and conclude that the ** database is safe to read while this process is still rolling the ** hot-journal back. ** |
︙ | ︙ | |||
5881 5882 5883 5884 5885 5886 5887 | } } #else rc = pager_incr_changecounter(pPager, 0); #endif if( rc!=SQLITE_OK ) goto commit_phase_one_exit; | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 | } } #else rc = pager_incr_changecounter(pPager, 0); #endif if( rc!=SQLITE_OK ) goto commit_phase_one_exit; /* Write the master journal name into the journal file. If a master ** journal file name has already been written to the journal file, ** or if zMaster is NULL (no master journal), then this call is a no-op. */ rc = writeMasterJournal(pPager, zMaster); if( rc!=SQLITE_OK ) goto commit_phase_one_exit; |
︙ | ︙ | |||
5938 5939 5940 5941 5942 5943 5944 | rc = pager_write_pagelist(pPager,sqlite3PcacheDirtyList(pPager->pPCache)); if( rc!=SQLITE_OK ){ assert( rc!=SQLITE_IOERR_BLOCKED ); goto commit_phase_one_exit; } sqlite3PcacheCleanAll(pPager->pPCache); | | | | | > > > | | 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 | rc = pager_write_pagelist(pPager,sqlite3PcacheDirtyList(pPager->pPCache)); if( rc!=SQLITE_OK ){ assert( rc!=SQLITE_IOERR_BLOCKED ); goto commit_phase_one_exit; } sqlite3PcacheCleanAll(pPager->pPCache); /* If the file on disk is smaller than the database image, use ** pager_truncate to grow the file here. This can happen if the database ** image was extended as part of the current transaction and then the ** last page in the db image moved to the free-list. In this case the ** last page is never written out to disk, leaving the database file ** undersized. Fix this now if it is the case. */ if( pPager->dbSize>pPager->dbFileSize ){ Pgno nNew = pPager->dbSize - (pPager->dbSize==PAGER_MJ_PGNO(pPager)); assert( pPager->eState==PAGER_WRITER_DBMOD ); rc = pager_truncate(pPager, nNew); if( rc!=SQLITE_OK ) goto commit_phase_one_exit; } /* Finally, sync the database file. */ |
︙ | ︙ | |||
6015 6016 6017 6018 6019 6020 6021 | ){ assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) || !pPager->journalOff ); pPager->eState = PAGER_READER; return SQLITE_OK; } PAGERTRACE(("COMMIT %d\n", PAGERID(pPager))); | | | 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 | ){ assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) || !pPager->journalOff ); pPager->eState = PAGER_READER; return SQLITE_OK; } PAGERTRACE(("COMMIT %d\n", PAGERID(pPager))); rc = pager_end_transaction(pPager, pPager->setMaster, 1); return pager_error(pPager, rc); } /* ** If a write transaction is open, then all changes made within the ** transaction are reverted and the current write-transaction is closed. ** The pager falls back to PAGER_READER state if successful, or PAGER_ERROR |
︙ | ︙ | |||
6060 6061 6062 6063 6064 6065 6066 | assert( assert_pager_state(pPager) ); if( pPager->eState==PAGER_ERROR ) return pPager->errCode; if( pPager->eState<=PAGER_READER ) return SQLITE_OK; if( pagerUseWal(pPager) ){ int rc2; rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, -1); | | | | 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 | assert( assert_pager_state(pPager) ); if( pPager->eState==PAGER_ERROR ) return pPager->errCode; if( pPager->eState<=PAGER_READER ) return SQLITE_OK; if( pagerUseWal(pPager) ){ int rc2; rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, -1); rc2 = pager_end_transaction(pPager, pPager->setMaster, 0); if( rc==SQLITE_OK ) rc = rc2; }else if( !isOpen(pPager->jfd) || pPager->eState==PAGER_WRITER_LOCKED ){ int eState = pPager->eState; rc = pager_end_transaction(pPager, 0, 0); if( !MEMDB && eState>PAGER_WRITER_LOCKED ){ /* This can happen using journal_mode=off. Move the pager to the error ** state to indicate that the contents of the cache may not be trusted. ** Any active readers will get SQLITE_ABORT. */ pPager->errCode = SQLITE_ABORT; pPager->eState = PAGER_ERROR; |
︙ | ︙ | |||
6462 6463 6464 6465 6466 6467 6468 | ** ** If the isCommit flag is set, there is no need to remember that ** the journal needs to be sync()ed before database page pPg->pgno ** can be written to. The caller has already promised not to write to it. */ if( (pPg->flags&PGHDR_NEED_SYNC) && !isCommit ){ needSyncPgno = pPg->pgno; | > | | 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 | ** ** If the isCommit flag is set, there is no need to remember that ** the journal needs to be sync()ed before database page pPg->pgno ** can be written to. The caller has already promised not to write to it. */ if( (pPg->flags&PGHDR_NEED_SYNC) && !isCommit ){ needSyncPgno = pPg->pgno; assert( pPager->journalMode==PAGER_JOURNALMODE_OFF || pageInJournal(pPg) || pPg->pgno>pPager->dbOrigSize ); assert( pPg->flags&PGHDR_DIRTY ); } /* If the cache contains a page with page-number pgno, remove it ** from its hash chain. Also, if the PGHDR_NEED_SYNC flag was set for ** page pgno before the 'move' operation, it needs to be retained ** for the page moved there. |
︙ | ︙ |
Changes to src/parse.y.
︙ | ︙ | |||
431 432 433 434 435 436 437 | groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L). { A = sqlite3SelectNew(pParse,W,X,Y,P,Q,Z,D,L.pLimit,L.pOffset); } // The "distinct" nonterminal is true (1) if the DISTINCT keyword is // present and false (0) if it is not. // | | | | 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 | groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L). { A = sqlite3SelectNew(pParse,W,X,Y,P,Q,Z,D,L.pLimit,L.pOffset); } // The "distinct" nonterminal is true (1) if the DISTINCT keyword is // present and false (0) if it is not. // %type distinct {u16} distinct(A) ::= DISTINCT. {A = SF_Distinct;} distinct(A) ::= ALL. {A = 0;} distinct(A) ::= . {A = 0;} // selcollist is a list of expressions that are to become the return // values of the SELECT statement. The "*" in statements like // "SELECT * FROM ..." is encoded as a special expression with an // opcode of TK_ALL. |
︙ | ︙ | |||
495 496 497 498 499 500 501 | // in a SELECT statement. "stl_prefix" is a prefix of this list. // stl_prefix(A) ::= seltablist(X) joinop(Y). { A = X; if( ALWAYS(A && A->nSrc>0) ) A->a[A->nSrc-1].jointype = (u8)Y; } stl_prefix(A) ::= . {A = 0;} | | > > > > > > > > > > > | < < < < < < < < < < < < | 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 | // in a SELECT statement. "stl_prefix" is a prefix of this list. // stl_prefix(A) ::= seltablist(X) joinop(Y). { A = X; if( ALWAYS(A && A->nSrc>0) ) A->a[A->nSrc-1].jointype = (u8)Y; } stl_prefix(A) ::= . {A = 0;} seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) indexed_opt(I) on_opt(N) using_opt(U). { A = sqlite3SrcListAppendFromTerm(pParse,X,&Y,&D,&Z,0,N,U); sqlite3SrcListIndexedBy(pParse, A, &I); } %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 if( F->nSrc==1 ){ A = sqlite3SrcListAppendFromTerm(pParse,X,0,0,&Z,0,N,U); if( A ){ struct SrcList_item *pNew = &A->a[A->nSrc-1]; struct SrcList_item *pOld = F->a; pNew->zName = pOld->zName; pNew->zDatabase = pOld->zDatabase; pOld->zName = pOld->zDatabase = 0; } sqlite3SrcListDelete(pParse->db, F); }else{ Select *pSubquery; sqlite3SrcListShiftJoinType(F); pSubquery = sqlite3SelectNew(pParse,0,F,0,0,0,0,SF_NestedFrom,0,0); A = sqlite3SrcListAppendFromTerm(pParse,X,0,0,&Z,pSubquery,N,U); } } %endif SQLITE_OMIT_SUBQUERY %type dbnm {Token} dbnm(A) ::= . {A.z=0; A.n=0;} dbnm(A) ::= DOT nm(X). {A = X;} %type fullname {SrcList*} |
︙ | ︙ | |||
649 650 651 652 653 654 655 | where_opt(A) ::= . {A = 0;} where_opt(A) ::= WHERE expr(X). {A = X.pExpr;} ////////////////////////// The UPDATE command //////////////////////////////// // %ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT | | > | > | 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 | where_opt(A) ::= . {A = 0;} where_opt(A) ::= WHERE expr(X). {A = X.pExpr;} ////////////////////////// The UPDATE command //////////////////////////////// // %ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT cmd ::= UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y) where_opt(W) orderby_opt(O) limit_opt(L). { sqlite3SrcListIndexedBy(pParse, X, &I); sqlite3ExprListCheckLength(pParse,Y,"set list"); W = sqlite3LimitWhere(pParse, X, W, O, L.pLimit, L.pOffset, "UPDATE"); sqlite3Update(pParse,X,Y,W,R); } %endif %ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT cmd ::= UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y) where_opt(W). { sqlite3SrcListIndexedBy(pParse, X, &I); sqlite3ExprListCheckLength(pParse,Y,"set list"); sqlite3Update(pParse,X,Y,W,R); } %endif %type setlist {ExprList*} |
︙ | ︙ |
Changes to src/pragma.c.
︙ | ︙ | |||
180 181 182 183 184 185 186 187 188 189 190 191 192 193 | #ifndef SQLITE_OMIT_AUTOMATIC_INDEX { "automatic_index", SQLITE_AutoIndex }, #endif #ifdef SQLITE_DEBUG { "sql_trace", SQLITE_SqlTrace }, { "vdbe_listing", SQLITE_VdbeListing }, { "vdbe_trace", SQLITE_VdbeTrace }, #endif #ifndef SQLITE_OMIT_CHECK { "ignore_check_constraints", SQLITE_IgnoreChecks }, #endif /* The following is VERY experimental */ { "writable_schema", SQLITE_WriteSchema|SQLITE_RecoveryMode }, | > > > | 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | #ifndef SQLITE_OMIT_AUTOMATIC_INDEX { "automatic_index", SQLITE_AutoIndex }, #endif #ifdef SQLITE_DEBUG { "sql_trace", SQLITE_SqlTrace }, { "vdbe_listing", SQLITE_VdbeListing }, { "vdbe_trace", SQLITE_VdbeTrace }, { "vdbe_addoptrace", SQLITE_VdbeAddopTrace}, { "vdbe_debug", SQLITE_SqlTrace | SQLITE_VdbeListing | SQLITE_VdbeTrace }, #endif #ifndef SQLITE_OMIT_CHECK { "ignore_check_constraints", SQLITE_IgnoreChecks }, #endif /* The following is VERY experimental */ { "writable_schema", SQLITE_WriteSchema|SQLITE_RecoveryMode }, |
︙ | ︙ | |||
944 945 946 947 948 949 950 | ** dflt_value: The default value for the column, if any. */ if( sqlite3StrICmp(zLeft, "table_info")==0 && zRight ){ Table *pTab; if( sqlite3ReadSchema(pParse) ) goto pragma_out; pTab = sqlite3FindTable(db, zRight, zDb); if( pTab ){ | | > > > | 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 | ** dflt_value: The default value for the column, if any. */ if( sqlite3StrICmp(zLeft, "table_info")==0 && zRight ){ Table *pTab; if( sqlite3ReadSchema(pParse) ) goto pragma_out; pTab = sqlite3FindTable(db, zRight, zDb); if( pTab ){ int i, k; int nHidden = 0; Column *pCol; Index *pPk; for(pPk=pTab->pIndex; pPk && pPk->autoIndex!=2; pPk=pPk->pNext){} sqlite3VdbeSetNumCols(v, 6); pParse->nMem = 6; sqlite3CodeVerifySchema(pParse, iDb); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cid", SQLITE_STATIC); sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC); sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "type", SQLITE_STATIC); sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "notnull", SQLITE_STATIC); sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "dflt_value", SQLITE_STATIC); sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "pk", SQLITE_STATIC); sqlite3ViewGetColumnNames(pParse, pTab); |
︙ | ︙ | |||
971 972 973 974 975 976 977 | pCol->zType ? pCol->zType : "", 0); sqlite3VdbeAddOp2(v, OP_Integer, (pCol->notNull ? 1 : 0), 4); if( pCol->zDflt ){ sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, (char*)pCol->zDflt, 0); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, 5); } | > > > > > > > | < > | 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 | pCol->zType ? pCol->zType : "", 0); sqlite3VdbeAddOp2(v, OP_Integer, (pCol->notNull ? 1 : 0), 4); if( pCol->zDflt ){ sqlite3VdbeAddOp4(v, OP_String8, 0, 5, 0, (char*)pCol->zDflt, 0); }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, 5); } if( (pCol->colFlags & COLFLAG_PRIMKEY)==0 ){ k = 0; }else if( pPk==0 ){ k = 1; }else{ for(k=1; ALWAYS(k<=pTab->nCol) && pPk->aiColumn[k-1]!=i; k++){} } sqlite3VdbeAddOp2(v, OP_Integer, k, 6); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6); } } }else if( sqlite3StrICmp(zLeft, "index_info")==0 && zRight ){ Index *pIdx; Table *pTab; if( sqlite3ReadSchema(pParse) ) goto pragma_out; pIdx = sqlite3FindIndex(db, zRight, zDb); if( pIdx ){ int i; pTab = pIdx->pTable; sqlite3VdbeSetNumCols(v, 3); pParse->nMem = 3; sqlite3CodeVerifySchema(pParse, iDb); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seqno", SQLITE_STATIC); sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "cid", SQLITE_STATIC); sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "name", SQLITE_STATIC); for(i=0; i<pIdx->nColumn; i++){ int cnum = pIdx->aiColumn[i]; sqlite3VdbeAddOp2(v, OP_Integer, i, 1); sqlite3VdbeAddOp2(v, OP_Integer, cnum, 2); |
︙ | ︙ | |||
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 | if( pTab ){ v = sqlite3GetVdbe(pParse); pIdx = pTab->pIndex; if( pIdx ){ int i = 0; sqlite3VdbeSetNumCols(v, 3); pParse->nMem = 3; sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC); sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC); sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", SQLITE_STATIC); while(pIdx){ sqlite3VdbeAddOp2(v, OP_Integer, i, 1); sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0); sqlite3VdbeAddOp2(v, OP_Integer, pIdx->onError!=OE_None, 3); | > | 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 | if( pTab ){ v = sqlite3GetVdbe(pParse); pIdx = pTab->pIndex; if( pIdx ){ int i = 0; sqlite3VdbeSetNumCols(v, 3); pParse->nMem = 3; sqlite3CodeVerifySchema(pParse, iDb); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "seq", SQLITE_STATIC); sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "name", SQLITE_STATIC); sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "unique", SQLITE_STATIC); while(pIdx){ sqlite3VdbeAddOp2(v, OP_Integer, i, 1); sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0); sqlite3VdbeAddOp2(v, OP_Integer, pIdx->onError!=OE_None, 3); |
︙ | ︙ | |||
1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 | if( pTab ){ v = sqlite3GetVdbe(pParse); pFK = pTab->pFKey; if( pFK ){ int i = 0; sqlite3VdbeSetNumCols(v, 8); pParse->nMem = 8; sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "id", SQLITE_STATIC); sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "seq", SQLITE_STATIC); sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "table", SQLITE_STATIC); sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "from", SQLITE_STATIC); sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "to", SQLITE_STATIC); sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "on_update", SQLITE_STATIC); sqlite3VdbeSetColName(v, 6, COLNAME_NAME, "on_delete", SQLITE_STATIC); | > | 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 | if( pTab ){ v = sqlite3GetVdbe(pParse); pFK = pTab->pFKey; if( pFK ){ int i = 0; sqlite3VdbeSetNumCols(v, 8); pParse->nMem = 8; sqlite3CodeVerifySchema(pParse, iDb); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "id", SQLITE_STATIC); sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "seq", SQLITE_STATIC); sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "table", SQLITE_STATIC); sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "from", SQLITE_STATIC); sqlite3VdbeSetColName(v, 4, COLNAME_NAME, "to", SQLITE_STATIC); sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "on_update", SQLITE_STATIC); sqlite3VdbeSetColName(v, 6, COLNAME_NAME, "on_delete", SQLITE_STATIC); |
︙ | ︙ | |||
1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 | pFK = pFK->pNextFrom; } } } }else #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ #ifndef NDEBUG if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){ if( zRight ){ if( sqlite3GetBoolean(zRight, 0) ){ sqlite3ParserTrace(stderr, "parser: "); }else{ sqlite3ParserTrace(0, 0); | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | pFK = pFK->pNextFrom; } } } }else #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ #ifndef SQLITE_OMIT_FOREIGN_KEY #ifndef SQLITE_OMIT_TRIGGER if( sqlite3StrICmp(zLeft, "foreign_key_check")==0 ){ FKey *pFK; /* A foreign key constraint */ Table *pTab; /* Child table contain "REFERENCES" keyword */ Table *pParent; /* Parent table that child points to */ Index *pIdx; /* Index in the parent table */ int i; /* Loop counter: Foreign key number for pTab */ int j; /* Loop counter: Field of the foreign key */ HashElem *k; /* Loop counter: Next table in schema */ int x; /* result variable */ int regResult; /* 3 registers to hold a result row */ int regKey; /* Register to hold key for checking the FK */ int regRow; /* Registers to hold a row from pTab */ int addrTop; /* Top of a loop checking foreign keys */ int addrOk; /* Jump here if the key is OK */ int *aiCols; /* child to parent column mapping */ if( sqlite3ReadSchema(pParse) ) goto pragma_out; regResult = pParse->nMem+1; pParse->nMem += 4; regKey = ++pParse->nMem; regRow = ++pParse->nMem; v = sqlite3GetVdbe(pParse); sqlite3VdbeSetNumCols(v, 4); sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "table", SQLITE_STATIC); sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "rowid", SQLITE_STATIC); sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "parent", SQLITE_STATIC); sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "fkid", SQLITE_STATIC); sqlite3CodeVerifySchema(pParse, iDb); k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash); while( k ){ if( zRight ){ pTab = sqlite3LocateTable(pParse, 0, zRight, zDb); k = 0; }else{ pTab = (Table*)sqliteHashData(k); k = sqliteHashNext(k); } if( pTab==0 || pTab->pFKey==0 ) continue; sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow; sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead); sqlite3VdbeAddOp4(v, OP_String8, 0, regResult, 0, pTab->zName, P4_TRANSIENT); for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){ pParent = sqlite3LocateTable(pParse, 0, pFK->zTo, zDb); if( pParent==0 ) break; pIdx = 0; sqlite3TableLock(pParse, iDb, pParent->tnum, 0, pParent->zName); x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, 0); if( x==0 ){ if( pIdx==0 ){ sqlite3OpenTable(pParse, i, iDb, pParent, OP_OpenRead); }else{ KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); sqlite3VdbeAddOp3(v, OP_OpenRead, i, pIdx->tnum, iDb); sqlite3VdbeChangeP4(v, -1, (char*)pKey, P4_KEYINFO_HANDOFF); } }else{ k = 0; break; } } if( pFK ) break; if( pParse->nTab<i ) pParse->nTab = i; addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, 0); for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){ pParent = sqlite3LocateTable(pParse, 0, pFK->zTo, zDb); assert( pParent!=0 ); pIdx = 0; aiCols = 0; x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, &aiCols); assert( x==0 ); addrOk = sqlite3VdbeMakeLabel(v); if( pIdx==0 ){ int iKey = pFK->aCol[0].iFrom; assert( iKey>=0 && iKey<pTab->nCol ); if( iKey!=pTab->iPKey ){ sqlite3VdbeAddOp3(v, OP_Column, 0, iKey, regRow); sqlite3ColumnDefault(v, pTab, iKey, regRow); sqlite3VdbeAddOp2(v, OP_IsNull, regRow, addrOk); sqlite3VdbeAddOp2(v, OP_MustBeInt, regRow, sqlite3VdbeCurrentAddr(v)+3); }else{ sqlite3VdbeAddOp2(v, OP_Rowid, 0, regRow); } sqlite3VdbeAddOp3(v, OP_NotExists, i, 0, regRow); sqlite3VdbeAddOp2(v, OP_Goto, 0, addrOk); sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2); }else{ for(j=0; j<pFK->nCol; j++){ sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, aiCols ? aiCols[j] : pFK->aCol[0].iFrom, regRow+j); sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); } sqlite3VdbeAddOp3(v, OP_MakeRecord, regRow, pFK->nCol, regKey); sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v,pIdx), P4_TRANSIENT); sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0); } sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1); sqlite3VdbeAddOp4(v, OP_String8, 0, regResult+2, 0, pFK->zTo, P4_TRANSIENT); sqlite3VdbeAddOp2(v, OP_Integer, i-1, regResult+3); sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 4); sqlite3VdbeResolveLabel(v, addrOk); sqlite3DbFree(db, aiCols); } sqlite3VdbeAddOp2(v, OP_Next, 0, addrTop+1); sqlite3VdbeJumpHere(v, addrTop); } }else #endif /* !defined(SQLITE_OMIT_TRIGGER) */ #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ #ifndef NDEBUG if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){ if( zRight ){ if( sqlite3GetBoolean(zRight, 0) ){ sqlite3ParserTrace(stderr, "parser: "); }else{ sqlite3ParserTrace(0, 0); |
︙ | ︙ | |||
1607 1608 1609 1610 1611 1612 1613 | sqlite3_key(db, zKey, i/2); }else{ sqlite3_rekey(db, zKey, i/2); } }else #endif #if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD) | | | 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 | sqlite3_key(db, zKey, i/2); }else{ sqlite3_rekey(db, zKey, i/2); } }else #endif #if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD) if( sqlite3StrICmp(zLeft, "activate_extensions")==0 && zRight ){ #ifdef SQLITE_HAS_CODEC if( sqlite3StrNICmp(zRight, "see-", 4)==0 ){ sqlite3_activate_see(&zRight[4]); } #endif #ifdef SQLITE_ENABLE_CEROD if( sqlite3StrNICmp(zRight, "cerod-", 6)==0 ){ |
︙ | ︙ |
Changes to src/prepare.c.
︙ | ︙ | |||
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 | /* If opening a non-empty database, check the text encoding. For the ** main database, set sqlite3.enc to the encoding of the main database. ** For an attached db, it is an error if the encoding is not the same ** as sqlite3.enc. */ if( meta[BTREE_TEXT_ENCODING-1] ){ /* text encoding */ if( iDb==0 ){ u8 encoding; /* If opening the main database, set ENC(db). */ encoding = (u8)meta[BTREE_TEXT_ENCODING-1] & 3; if( encoding==0 ) encoding = SQLITE_UTF8; ENC(db) = encoding; }else{ /* If opening an attached database, the encoding much match ENC(db) */ if( meta[BTREE_TEXT_ENCODING-1]!=ENC(db) ){ sqlite3SetString(pzErrMsg, db, "attached databases must use the same" " text encoding as main database"); rc = SQLITE_ERROR; goto initone_error_out; | > > > > | 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 | /* If opening a non-empty database, check the text encoding. For the ** main database, set sqlite3.enc to the encoding of the main database. ** For an attached db, it is an error if the encoding is not the same ** as sqlite3.enc. */ if( meta[BTREE_TEXT_ENCODING-1] ){ /* text encoding */ if( iDb==0 ){ #ifndef SQLITE_OMIT_UTF16 u8 encoding; /* If opening the main database, set ENC(db). */ encoding = (u8)meta[BTREE_TEXT_ENCODING-1] & 3; if( encoding==0 ) encoding = SQLITE_UTF8; ENC(db) = encoding; #else ENC(db) = SQLITE_UTF8; #endif }else{ /* If opening an attached database, the encoding much match ENC(db) */ if( meta[BTREE_TEXT_ENCODING-1]!=ENC(db) ){ sqlite3SetString(pzErrMsg, db, "attached databases must use the same" " text encoding as main database"); rc = SQLITE_ERROR; goto initone_error_out; |
︙ | ︙ |
Changes to src/resolve.c.
︙ | ︙ | |||
146 147 148 149 150 151 152 153 154 155 156 157 158 159 | for(k=0; k<pUsing->nId; k++){ if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ) return 1; } } return 0; } /* ** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up ** that name in the set of source tables in pSrcList and make the pExpr ** expression node refer back to that source column. The following changes ** are made to pExpr: ** | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | for(k=0; k<pUsing->nId; k++){ if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ) return 1; } } return 0; } /* ** Subqueries stores the original database, table and column names for their ** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN". ** Check to see if the zSpan given to this routine matches the zDb, zTab, ** and zCol. If any of zDb, zTab, and zCol are NULL then those fields will ** match anything. */ int sqlite3MatchSpanName( const char *zSpan, const char *zCol, const char *zTab, const char *zDb ){ int n; for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){} if( zDb && (sqlite3StrNICmp(zSpan, zDb, n)!=0 || zDb[n]!=0) ){ return 0; } zSpan += n+1; for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){} if( zTab && (sqlite3StrNICmp(zSpan, zTab, n)!=0 || zTab[n]!=0) ){ return 0; } zSpan += n+1; if( zCol && sqlite3StrICmp(zSpan, zCol)!=0 ){ return 0; } return 1; } /* ** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up ** that name in the set of source tables in pSrcList and make the pExpr ** expression node refer back to that source column. The following changes ** are made to pExpr: ** |
︙ | ︙ | |||
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | 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; pExpr->pTab = 0; ExprSetIrreducible(pExpr); /* Start at the inner-most context and move outward until a match is found */ while( pNC && cnt==0 ){ ExprList *pEList; SrcList *pSrcList = pNC->pSrcList; if( pSrcList ){ for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){ Table *pTab; | > > > > > > > > > > > > > > < < < | > | > | > > | > | < > > | | | | | > > > > > < < < < < < > > > > | > | 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 | 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; pExpr->pTab = 0; ExprSetIrreducible(pExpr); /* Translate the schema name in zDb into a pointer to the corresponding ** schema. If not found, pSchema will remain NULL and nothing will match ** resulting in an appropriate error message toward the end of this routine */ if( zDb ){ for(i=0; i<db->nDb; i++){ assert( db->aDb[i].zName ); if( sqlite3StrICmp(db->aDb[i].zName,zDb)==0 ){ pSchema = db->aDb[i].pSchema; break; } } } /* Start at the inner-most context and move outward until a match is found */ while( pNC && cnt==0 ){ ExprList *pEList; SrcList *pSrcList = pNC->pSrcList; if( pSrcList ){ for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){ Table *pTab; Column *pCol; pTab = pItem->pTab; assert( pTab!=0 && pTab->zName!=0 ); assert( pTab->nCol>0 ); if( pItem->pSelect && (pItem->pSelect->selFlags & SF_NestedFrom)!=0 ){ int hit = 0; pEList = pItem->pSelect->pEList; for(j=0; j<pEList->nExpr; j++){ if( sqlite3MatchSpanName(pEList->a[j].zSpan, zCol, zTab, zDb) ){ cnt++; cntTab = 2; pMatch = pItem; pExpr->iColumn = j; hit = 1; } } if( hit || zTab==0 ) continue; } if( zDb && pTab->pSchema!=pSchema ){ continue; } if( zTab ){ const char *zTabName = pItem->zAlias ? pItem->zAlias : pTab->zName; assert( zTabName!=0 ); if( sqlite3StrICmp(zTabName, zTab)!=0 ){ continue; } } if( 0==(cntTab++) ){ pMatch = pItem; } for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){ if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ /* If there has been exactly one prior match and this match ** is for the right-hand table of a NATURAL JOIN or is in a ** USING clause, then skip this match. */ if( cnt==1 ){ if( pItem->jointype & JT_NATURAL ) continue; if( nameInUsingClause(pItem->pUsing, zCol) ) continue; } cnt++; pMatch = pItem; /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j; break; } } } if( pMatch ){ pExpr->iTable = pMatch->iCursor; pExpr->pTab = pMatch->pTab; pSchema = pExpr->pTab->pSchema; } } /* if( pSrcList ) */ #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; |
︙ | ︙ | |||
593 594 595 596 597 598 599 | } } #endif if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){ sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId); pNC->nErr++; is_agg = 0; | | | 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 | } } #endif if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){ sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId); pNC->nErr++; is_agg = 0; }else if( no_such_func && pParse->db->init.busy==0 ){ sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId); pNC->nErr++; }else if( wrong_num_args ){ sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()", nId, zId); pNC->nErr++; } |
︙ | ︙ | |||
1029 1030 1031 1032 1033 1034 1035 | memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; if( sqlite3ResolveExprNames(&sNC, p->pLimit) || sqlite3ResolveExprNames(&sNC, p->pOffset) ){ return WRC_Abort; } | < < < < < < < < < < < < < < < < < | 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 | memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; if( sqlite3ResolveExprNames(&sNC, p->pLimit) || sqlite3ResolveExprNames(&sNC, p->pOffset) ){ return WRC_Abort; } /* Recursively resolve names in all subqueries */ for(i=0; i<p->pSrc->nSrc; i++){ struct SrcList_item *pItem = &p->pSrc->a[i]; if( pItem->pSelect ){ NameContext *pNC; /* Used to iterate name contexts */ int nRef = 0; /* Refcount for pOuterNC and outer contexts */ |
︙ | ︙ | |||
1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 | if( pParse->nErr || db->mallocFailed ) return WRC_Abort; for(pNC=pOuterNC; pNC; pNC=pNC->pNext) nRef -= pNC->nRef; assert( pItem->isCorrelated==0 && nRef<=0 ); pItem->isCorrelated = (nRef!=0); } } /* If there are no aggregate functions in the result-set, and no GROUP BY ** expression, do not allow aggregates in any of the other expressions. */ assert( (p->selFlags & SF_Aggregate)==0 ); pGroupBy = p->pGroupBy; if( pGroupBy || (sNC.ncFlags & NC_HasAgg)!=0 ){ | > > > > > > > > > > > > > > > > > | 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 | if( pParse->nErr || db->mallocFailed ) return WRC_Abort; for(pNC=pOuterNC; pNC; pNC=pNC->pNext) nRef -= pNC->nRef; assert( pItem->isCorrelated==0 && nRef<=0 ); pItem->isCorrelated = (nRef!=0); } } /* Set up the local name-context to pass to sqlite3ResolveExprNames() to ** resolve the result-set expression list. */ sNC.ncFlags = NC_AllowAgg; sNC.pSrcList = p->pSrc; sNC.pNext = pOuterNC; /* Resolve names in the result set. */ pEList = p->pEList; assert( pEList!=0 ); for(i=0; i<pEList->nExpr; i++){ Expr *pX = pEList->a[i].pExpr; if( sqlite3ResolveExprNames(&sNC, pX) ){ return WRC_Abort; } } /* If there are no aggregate functions in the result-set, and no GROUP BY ** expression, do not allow aggregates in any of the other expressions. */ assert( (p->selFlags & SF_Aggregate)==0 ); pGroupBy = p->pGroupBy; if( pGroupBy || (sNC.ncFlags & NC_HasAgg)!=0 ){ |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
51 52 53 54 55 56 57 | Parse *pParse, /* Parsing context */ ExprList *pEList, /* which columns to include in the result */ SrcList *pSrc, /* the FROM clause -- which tables to scan */ Expr *pWhere, /* the WHERE clause */ ExprList *pGroupBy, /* the GROUP BY clause */ Expr *pHaving, /* the HAVING clause */ ExprList *pOrderBy, /* the ORDER BY clause */ | | | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | Parse *pParse, /* Parsing context */ ExprList *pEList, /* which columns to include in the result */ SrcList *pSrc, /* the FROM clause -- which tables to scan */ Expr *pWhere, /* the WHERE clause */ ExprList *pGroupBy, /* the GROUP BY clause */ Expr *pHaving, /* the HAVING clause */ ExprList *pOrderBy, /* the ORDER BY clause */ u16 selFlags, /* Flag parameters, such as SF_Distinct */ Expr *pLimit, /* LIMIT value. NULL means not used */ Expr *pOffset /* OFFSET value. NULL means no offset */ ){ Select *pNew; Select standin; sqlite3 *db = pParse->db; pNew = sqlite3DbMallocZero(db, sizeof(*pNew) ); |
︙ | ︙ | |||
75 76 77 78 79 80 81 | pNew->pEList = pEList; if( pSrc==0 ) pSrc = sqlite3DbMallocZero(db, sizeof(*pSrc)); pNew->pSrc = pSrc; pNew->pWhere = pWhere; pNew->pGroupBy = pGroupBy; pNew->pHaving = pHaving; pNew->pOrderBy = pOrderBy; | | | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | pNew->pEList = pEList; if( pSrc==0 ) pSrc = sqlite3DbMallocZero(db, sizeof(*pSrc)); pNew->pSrc = pSrc; pNew->pWhere = pWhere; pNew->pGroupBy = pGroupBy; pNew->pHaving = pHaving; pNew->pOrderBy = pOrderBy; pNew->selFlags = selFlags; pNew->op = TK_SELECT; pNew->pLimit = pLimit; pNew->pOffset = pOffset; assert( pOffset==0 || pLimit!=0 ); pNew->addrOpenEphm[0] = -1; pNew->addrOpenEphm[1] = -1; pNew->addrOpenEphm[2] = -1; |
︙ | ︙ | |||
1332 1333 1334 1335 1336 1337 1338 | *pnCol = nCol; *paCol = aCol; for(i=0, pCol=aCol; i<nCol; i++, pCol++){ /* Get an appropriate name for the column */ p = sqlite3ExprSkipCollate(pEList->a[i].pExpr); | < < | 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 | *pnCol = nCol; *paCol = aCol; for(i=0, pCol=aCol; i<nCol; i++, pCol++){ /* Get an appropriate name for the column */ p = sqlite3ExprSkipCollate(pEList->a[i].pExpr); if( (zName = pEList->a[i].zName)!=0 ){ /* If the column contains an "AS <name>" phrase, use <name> as the name */ zName = sqlite3DbStrDup(db, zName); }else{ Expr *pColExpr = p; /* The expression that is the result column name */ Table *pTab; /* Table associated with this expression */ while( pColExpr->op==TK_DOT ){ |
︙ | ︙ | |||
1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 | /* Make sure the column name is unique. If the name is not unique, ** append a integer to the name so that it becomes unique. */ nName = sqlite3Strlen30(zName); for(j=cnt=0; j<i; j++){ if( sqlite3StrICmp(aCol[j].zName, zName)==0 ){ char *zNewName; zName[nName] = 0; zNewName = sqlite3MPrintf(db, "%s:%d", zName, ++cnt); sqlite3DbFree(db, zName); zName = zNewName; j = -1; if( zName==0 ) break; } | > > > | 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 | /* Make sure the column name is unique. If the name is not unique, ** append a integer to the name so that it becomes unique. */ nName = sqlite3Strlen30(zName); for(j=cnt=0; j<i; j++){ if( sqlite3StrICmp(aCol[j].zName, zName)==0 ){ char *zNewName; int k; for(k=nName-1; k>1 && sqlite3Isdigit(zName[k]); k--){} if( zName[k]==':' ) nName = k; zName[nName] = 0; zNewName = sqlite3MPrintf(db, "%s:%d", zName, ++cnt); sqlite3DbFree(db, zName); zName = zNewName; j = -1; if( zName==0 ) break; } |
︙ | ︙ | |||
1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 | /* Generate code for the left and right SELECT statements. */ switch( p->op ){ case TK_ALL: { int addr = 0; int nLimit; assert( !pPrior->pLimit ); pPrior->pLimit = p->pLimit; pPrior->pOffset = p->pOffset; explainSetInteger(iSub1, pParse->iNextSelectId); rc = sqlite3Select(pParse, pPrior, &dest); p->pLimit = 0; p->pOffset = 0; if( rc ){ | > > | 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 | /* Generate code for the left and right SELECT statements. */ switch( p->op ){ case TK_ALL: { int addr = 0; int nLimit; assert( !pPrior->pLimit ); pPrior->iLimit = p->iLimit; pPrior->iOffset = p->iOffset; pPrior->pLimit = p->pLimit; pPrior->pOffset = p->pOffset; explainSetInteger(iSub1, pParse->iNextSelectId); rc = sqlite3Select(pParse, pPrior, &dest); p->pLimit = 0; p->pOffset = 0; if( rc ){ |
︙ | ︙ | |||
2359 2360 2361 2362 2363 2364 2365 | ** operator is UNION, EXCEPT, or INTERSECT (but not UNION ALL). */ if( op==TK_ALL ){ regPrev = 0; }else{ int nExpr = p->pEList->nExpr; assert( nOrderBy>=nExpr || db->mallocFailed ); | | > | 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 | ** operator is UNION, EXCEPT, or INTERSECT (but not UNION ALL). */ if( op==TK_ALL ){ regPrev = 0; }else{ int nExpr = p->pEList->nExpr; assert( nOrderBy>=nExpr || db->mallocFailed ); regPrev = pParse->nMem+1; pParse->nMem += nExpr+1; sqlite3VdbeAddOp2(v, OP_Integer, 0, regPrev); pKeyDup = sqlite3DbMallocZero(db, sizeof(*pKeyDup) + nExpr*(sizeof(CollSeq*)+1) ); if( pKeyDup ){ pKeyDup->aSortOrder = (u8*)&pKeyDup->aColl[nExpr]; pKeyDup->nField = (u16)nExpr; pKeyDup->enc = ENC(db); |
︙ | ︙ | |||
2541 2542 2543 2544 2545 2546 2547 | sqlite3VdbeResolveLabel(v, labelCmpr); sqlite3VdbeAddOp4(v, OP_Permutation, 0, 0, 0, (char*)aPermute, P4_INTARRAY); sqlite3VdbeAddOp4(v, OP_Compare, destA.iSdst, destB.iSdst, nOrderBy, (char*)pKeyMerge, P4_KEYINFO_HANDOFF); sqlite3VdbeChangeP5(v, OPFLAG_PERMUTE); sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB); | < < < < < < | 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 | sqlite3VdbeResolveLabel(v, labelCmpr); sqlite3VdbeAddOp4(v, OP_Permutation, 0, 0, 0, (char*)aPermute, P4_INTARRAY); sqlite3VdbeAddOp4(v, OP_Compare, destA.iSdst, destB.iSdst, nOrderBy, (char*)pKeyMerge, P4_KEYINFO_HANDOFF); sqlite3VdbeChangeP5(v, OPFLAG_PERMUTE); sqlite3VdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB); /* Jump to the this point in order to terminate the query. */ sqlite3VdbeResolveLabel(v, labelEnd); /* Set the number of output columns */ if( pDest->eDest==SRT_Output ){ |
︙ | ︙ | |||
2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 | ** ** We call this the "compound-subquery flattening". */ for(pSub=pSub->pPrior; pSub; pSub=pSub->pPrior){ Select *pNew; ExprList *pOrderBy = p->pOrderBy; Expr *pLimit = p->pLimit; Select *pPrior = p->pPrior; p->pOrderBy = 0; p->pSrc = 0; p->pPrior = 0; p->pLimit = 0; pNew = sqlite3SelectDup(db, p, 0); p->pLimit = pLimit; p->pOrderBy = pOrderBy; p->pSrc = pSrc; p->op = TK_ALL; p->pRightmost = 0; if( pNew==0 ){ pNew = pPrior; | > > > | 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 | ** ** We call this the "compound-subquery flattening". */ for(pSub=pSub->pPrior; pSub; pSub=pSub->pPrior){ Select *pNew; ExprList *pOrderBy = p->pOrderBy; Expr *pLimit = p->pLimit; Expr *pOffset = p->pOffset; Select *pPrior = p->pPrior; p->pOrderBy = 0; p->pSrc = 0; p->pPrior = 0; p->pLimit = 0; p->pOffset = 0; pNew = sqlite3SelectDup(db, p, 0); p->pOffset = pOffset; p->pLimit = pLimit; p->pOrderBy = pOrderBy; p->pSrc = pSrc; p->op = TK_ALL; p->pRightmost = 0; if( pNew==0 ){ pNew = pPrior; |
︙ | ︙ | |||
3156 3157 3158 3159 3160 3161 3162 | sqlite3SelectDelete(db, pSub1); return 1; } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ /* | > | < < < > > | | | > > > > | > > > > | | < < | < < < | | | | > | | > | > > > > | | 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 | sqlite3SelectDelete(db, pSub1); return 1; } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ /* ** Based on the contents of the AggInfo structure indicated by the first ** argument, this function checks if the following are true: ** ** * the query contains just a single aggregate function, ** * the aggregate function is either min() or max(), and ** * the argument to the aggregate function is a column value. ** ** If all of the above are true, then WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX ** is returned as appropriate. Also, *ppMinMax is set to point to the ** list of arguments passed to the aggregate before returning. ** ** Or, if the conditions above are not met, *ppMinMax is set to 0 and ** WHERE_ORDERBY_NORMAL is returned. */ static u8 minMaxQuery(AggInfo *pAggInfo, ExprList **ppMinMax){ int eRet = WHERE_ORDERBY_NORMAL; /* Return value */ *ppMinMax = 0; if( pAggInfo->nFunc==1 ){ Expr *pExpr = pAggInfo->aFunc[0].pExpr; /* Aggregate function */ ExprList *pEList = pExpr->x.pList; /* Arguments to agg function */ assert( pExpr->op==TK_AGG_FUNCTION ); if( pEList && pEList->nExpr==1 && pEList->a[0].pExpr->op==TK_AGG_COLUMN ){ const char *zFunc = pExpr->u.zToken; if( sqlite3StrICmp(zFunc, "min")==0 ){ eRet = WHERE_ORDERBY_MIN; *ppMinMax = pEList; }else if( sqlite3StrICmp(zFunc, "max")==0 ){ eRet = WHERE_ORDERBY_MAX; *ppMinMax = pEList; } } } assert( *ppMinMax==0 || (*ppMinMax)->nExpr==1 ); return eRet; } /* ** The select statement passed as the first argument is an aggregate query. ** The second argment is the associated aggregate-info object. This ** function tests if the SELECT is of the form: ** |
︙ | ︙ | |||
3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 | static int selectExpander(Walker *pWalker, Select *p){ Parse *pParse = pWalker->pParse; int i, j, k; SrcList *pTabList; ExprList *pEList; struct SrcList_item *pFrom; sqlite3 *db = pParse->db; if( db->mallocFailed ){ return WRC_Abort; } | > > > | < | 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 | static int selectExpander(Walker *pWalker, Select *p){ Parse *pParse = pWalker->pParse; int i, j, k; SrcList *pTabList; ExprList *pEList; struct SrcList_item *pFrom; sqlite3 *db = pParse->db; Expr *pE, *pRight, *pExpr; u16 selFlags = p->selFlags; p->selFlags |= SF_Expanded; if( db->mallocFailed ){ return WRC_Abort; } if( NEVER(p->pSrc==0) || (selFlags & SF_Expanded)!=0 ){ return WRC_Prune; } pTabList = p->pSrc; pEList = p->pEList; /* Make sure cursor numbers have been assigned to all entries in ** the FROM clause of the SELECT statement. */ sqlite3SrcListAssignCursors(pParse, pTabList); |
︙ | ︙ | |||
3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 | pTab->tabFlags |= TF_Ephemeral; #endif }else{ /* An ordinary table or view name in the FROM clause */ assert( pFrom->pTab==0 ); pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom); if( pTab==0 ) return WRC_Abort; pTab->nRef++; #if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE) if( pTab->pSelect || IsVirtual(pTab) ){ /* We reach here if the named table is a really a view */ if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort; assert( pFrom->pSelect==0 ); pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0); | > > > > > > | 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 | pTab->tabFlags |= TF_Ephemeral; #endif }else{ /* An ordinary table or view name in the FROM clause */ assert( pFrom->pTab==0 ); pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom); if( pTab==0 ) return WRC_Abort; if( pTab->nRef==0xffff ){ sqlite3ErrorMsg(pParse, "too many references to \"%s\": max 65535", pTab->zName); pFrom->pTab = 0; return WRC_Abort; } pTab->nRef++; #if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE) if( pTab->pSelect || IsVirtual(pTab) ){ /* We reach here if the named table is a really a view */ if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort; assert( pFrom->pSelect==0 ); pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0); |
︙ | ︙ | |||
3363 3364 3365 3366 3367 3368 3369 | ** The following code just has to locate the TK_ALL expressions and expand ** each one to the list of all columns in all tables. ** ** The first loop just checks to see if there are any "*" operators ** that need expanding. */ for(k=0; k<pEList->nExpr; k++){ | | > > > > > > > | > | | | < < > > > > > | | | | > > < > > > > > > > > | 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 | ** The following code just has to locate the TK_ALL expressions and expand ** each one to the list of all columns in all tables. ** ** The first loop just checks to see if there are any "*" operators ** that need expanding. */ for(k=0; k<pEList->nExpr; k++){ pE = pEList->a[k].pExpr; if( pE->op==TK_ALL ) break; assert( pE->op!=TK_DOT || pE->pRight!=0 ); assert( pE->op!=TK_DOT || (pE->pLeft!=0 && pE->pLeft->op==TK_ID) ); if( pE->op==TK_DOT && pE->pRight->op==TK_ALL ) break; } if( k<pEList->nExpr ){ /* ** If we get here it means the result set contains one or more "*" ** operators that need to be expanded. Loop through each expression ** in the result set and expand them one by one. */ struct ExprList_item *a = pEList->a; ExprList *pNew = 0; int flags = pParse->db->flags; int longNames = (flags & SQLITE_FullColNames)!=0 && (flags & SQLITE_ShortColNames)==0; /* When processing FROM-clause subqueries, it is always the case ** that full_column_names=OFF and short_column_names=ON. The ** sqlite3ResultSetOfSelect() routine makes it so. */ assert( (p->selFlags & SF_NestedFrom)==0 || ((flags & SQLITE_FullColNames)==0 && (flags & SQLITE_ShortColNames)!=0) ); for(k=0; k<pEList->nExpr; k++){ pE = a[k].pExpr; pRight = pE->pRight; assert( pE->op!=TK_DOT || pRight!=0 ); if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pRight->op!=TK_ALL) ){ /* This particular expression does not need to be expanded. */ pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr); if( pNew ){ pNew->a[pNew->nExpr-1].zName = a[k].zName; pNew->a[pNew->nExpr-1].zSpan = a[k].zSpan; a[k].zName = 0; a[k].zSpan = 0; } a[k].pExpr = 0; }else{ /* This expression is a "*" or a "TABLE.*" and needs to be ** expanded. */ int tableSeen = 0; /* Set to 1 when TABLE matches */ char *zTName = 0; /* text of name of TABLE */ if( pE->op==TK_DOT ){ assert( pE->pLeft!=0 ); assert( !ExprHasProperty(pE->pLeft, EP_IntValue) ); zTName = pE->pLeft->u.zToken; } for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){ Table *pTab = pFrom->pTab; Select *pSub = pFrom->pSelect; char *zTabName = pFrom->zAlias; const char *zSchemaName = 0; int iDb; if( zTabName==0 ){ zTabName = pTab->zName; } if( db->mallocFailed ) break; if( pSub==0 || (pSub->selFlags & SF_NestedFrom)==0 ){ pSub = 0; if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){ continue; } iDb = sqlite3SchemaToIndex(db, pTab->pSchema); zSchemaName = iDb>=0 ? db->aDb[iDb].zName : "*"; } for(j=0; j<pTab->nCol; j++){ char *zName = pTab->aCol[j].zName; char *zColname; /* The computed column name */ char *zToFree; /* Malloced string that needs to be freed */ Token sColname; /* Computed column name as a token */ assert( zName ); if( zTName && pSub && sqlite3MatchSpanName(pSub->pEList->a[j].zSpan, 0, zTName, 0)==0 ){ continue; } /* If a column is marked as 'hidden' (currently only possible ** for virtual tables), do not include it in the expanded ** result-set list. */ if( IsHiddenColumn(&pTab->aCol[j]) ){ assert(IsVirtual(pTab)); continue; } tableSeen = 1; if( i>0 && zTName==0 ){ if( (pFrom->jointype & JT_NATURAL)!=0 && tableAndColumnIndex(pTabList, i, zName, 0, 0) ){ /* In a NATURAL join, omit the join columns from the ** table to the right of the join */ |
︙ | ︙ | |||
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 | pRight = sqlite3Expr(db, TK_ID, zName); zColname = zName; zToFree = 0; if( longNames || pTabList->nSrc>1 ){ Expr *pLeft; pLeft = sqlite3Expr(db, TK_ID, zTabName); pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0); if( longNames ){ zColname = sqlite3MPrintf(db, "%s.%s", zTabName, zName); zToFree = zColname; } }else{ pExpr = pRight; } pNew = sqlite3ExprListAppend(pParse, pNew, pExpr); sColname.z = zColname; sColname.n = sqlite3Strlen30(zColname); sqlite3ExprListSetName(pParse, pNew, &sColname, 0); sqlite3DbFree(db, zToFree); } } if( !tableSeen ){ if( zTName ){ sqlite3ErrorMsg(pParse, "no such table: %s", zTName); }else{ | > > > > > > > > > > > > > > > > | 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 | pRight = sqlite3Expr(db, TK_ID, zName); zColname = zName; zToFree = 0; if( longNames || pTabList->nSrc>1 ){ Expr *pLeft; pLeft = sqlite3Expr(db, TK_ID, zTabName); pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0); if( zSchemaName ){ pLeft = sqlite3Expr(db, TK_ID, zSchemaName); pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pExpr, 0); } if( longNames ){ zColname = sqlite3MPrintf(db, "%s.%s", zTabName, zName); zToFree = zColname; } }else{ pExpr = pRight; } pNew = sqlite3ExprListAppend(pParse, pNew, pExpr); sColname.z = zColname; sColname.n = sqlite3Strlen30(zColname); sqlite3ExprListSetName(pParse, pNew, &sColname, 0); if( pNew && (p->selFlags & SF_NestedFrom)!=0 ){ struct ExprList_item *pX = &pNew->a[pNew->nExpr-1]; if( pSub ){ pX->zSpan = sqlite3DbStrDup(db, pSub->pEList->a[j].zSpan); testcase( pX->zSpan==0 ); }else{ pX->zSpan = sqlite3MPrintf(db, "%s.%s.%s", zSchemaName, zTabName, zColname); testcase( pX->zSpan==0 ); } pX->bSpanIsTab = 1; } sqlite3DbFree(db, zToFree); } } if( !tableSeen ){ if( zTName ){ sqlite3ErrorMsg(pParse, "no such table: %s", zTName); }else{ |
︙ | ︙ | |||
3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 | Parse *pParse, /* The parser context */ Select *p, /* The SELECT statement being coded. */ NameContext *pOuterNC /* Name context for container */ ){ sqlite3 *db; if( NEVER(p==0) ) return; db = pParse->db; if( p->selFlags & SF_HasTypeInfo ) return; sqlite3SelectExpand(pParse, p); if( pParse->nErr || db->mallocFailed ) return; sqlite3ResolveSelectNames(pParse, p, pOuterNC); if( pParse->nErr || db->mallocFailed ) return; sqlite3SelectAddTypeInfo(pParse, p); } | > | 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 | Parse *pParse, /* The parser context */ Select *p, /* The SELECT statement being coded. */ NameContext *pOuterNC /* Name context for container */ ){ sqlite3 *db; if( NEVER(p==0) ) return; db = pParse->db; if( db->mallocFailed ) return; if( p->selFlags & SF_HasTypeInfo ) return; sqlite3SelectExpand(pParse, p); if( pParse->nErr || db->mallocFailed ) return; sqlite3ResolveSelectNames(pParse, p, pOuterNC); if( pParse->nErr || db->mallocFailed ) return; sqlite3SelectAddTypeInfo(pParse, p); } |
︙ | ︙ | |||
4523 4524 4525 4526 4527 4528 4529 | ** ** + The optimizer code in where.c (the thing that decides which ** index or indices to use) should place a different priority on ** satisfying the 'ORDER BY' clause than it does in other cases. ** Refer to code and comments in where.c for details. */ ExprList *pMinMax = 0; | > > > > > | > > > < < | | 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 | ** ** + The optimizer code in where.c (the thing that decides which ** index or indices to use) should place a different priority on ** satisfying the 'ORDER BY' clause than it does in other cases. ** Refer to code and comments in where.c for details. */ ExprList *pMinMax = 0; u8 flag = WHERE_ORDERBY_NORMAL; assert( p->pGroupBy==0 ); assert( flag==0 ); if( p->pHaving==0 ){ flag = minMaxQuery(&sAggInfo, &pMinMax); } assert( flag==0 || (pMinMax!=0 && pMinMax->nExpr==1) ); if( flag ){ pMinMax = sqlite3ExprListDup(db, pMinMax, 0); pDel = pMinMax; if( pMinMax && !db->mallocFailed ){ pMinMax->a[0].sortOrder = flag!=WHERE_ORDERBY_MIN ?1:0; pMinMax->a[0].pExpr->op = TK_COLUMN; } } |
︙ | ︙ | |||
4683 4684 4685 4686 4687 4688 4689 | } } void sqlite3ExplainSelect(Vdbe *pVdbe, Select *p){ if( p==0 ){ sqlite3ExplainPrintf(pVdbe, "(null-select)"); return; } | | > > > | 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 | } } void sqlite3ExplainSelect(Vdbe *pVdbe, Select *p){ if( p==0 ){ sqlite3ExplainPrintf(pVdbe, "(null-select)"); return; } while( p->pPrior ){ p->pPrior->pNext = p; p = p->pPrior; } sqlite3ExplainPush(pVdbe); while( p ){ explainOneSelect(pVdbe, p); p = p->pNext; if( p==0 ) break; sqlite3ExplainNL(pVdbe); sqlite3ExplainPrintf(pVdbe, "%s\n", selectOpName(p->op)); |
︙ | ︙ |
Changes to src/shell.c.
︙ | ︙ | |||
86 87 88 89 90 91 92 | static int enableTimer = 0; /* ctype macros that work with signed characters */ #define IsSpace(X) isspace((unsigned char)X) #define IsDigit(X) isdigit((unsigned char)X) #define ToLower(X) (char)tolower((unsigned char)X) | | > | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | static int enableTimer = 0; /* ctype macros that work with signed characters */ #define IsSpace(X) isspace((unsigned char)X) #define IsDigit(X) isdigit((unsigned char)X) #define ToLower(X) (char)tolower((unsigned char)X) #if !defined(_WIN32) && !defined(WIN32) && !defined(_WRS_KERNEL) \ && !defined(__minux) #include <sys/time.h> #include <sys/resource.h> /* Saved resource information for the beginning of an operation */ static struct rusage sBegin; /* |
︙ | ︙ | |||
1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 | fprintf(stderr,"Error: unable to open database \"%s\": %s\n", p->zDbFilename, sqlite3_errmsg(db)); exit(1); } #ifndef SQLITE_OMIT_LOAD_EXTENSION sqlite3_enable_load_extension(p->db, 1); #endif } } /* ** Do C-language style dequoting. ** ** \t -> tab | > > > > > > > > > > > > | 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 | 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 #ifdef SQLITE_ENABLE_REGEXP { extern int sqlite3_add_regexp_func(sqlite3*); sqlite3_add_regexp_func(db); } #endif #ifdef SQLITE_ENABLE_SPELLFIX { extern int sqlite3_spellfix1_register(sqlite3*); sqlite3_spellfix1_register(db); } #endif } } /* ** Do C-language style dequoting. ** ** \t -> tab |
︙ | ︙ | |||
1521 1522 1523 1524 1525 1526 1527 | z[j] = 0; } /* ** Interpret zArg as a boolean value. Return either 0 or 1. */ static int booleanValue(char *zArg){ | < | | | > > | | < < > > | | 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 | z[j] = 0; } /* ** Interpret zArg as a boolean value. Return either 0 or 1. */ static int booleanValue(char *zArg){ int i; for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){} if( i>0 && zArg[i]==0 ) return atoi(zArg); if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){ return 1; } if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){ return 0; } fprintf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n", zArg); return 0; } /* ** Close an output file, assuming it is not stderr or stdout */ static void output_file_close(FILE *f){ if( f && f!=stdout && f!=stderr ) fclose(f); |
︙ | ︙ | |||
1619 1620 1621 1622 1623 1624 1625 | } /* Process the input line. */ if( nArg==0 ) return 0; /* no tokens, no error */ n = strlen30(azArg[0]); c = azArg[0][0]; | | | | > > | | > > > | | > > > > > | > > | > > > | > > > > > > > > > > > | 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 | } /* 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 ){ const char *zDestFile = 0; const char *zDb = 0; const char *zKey = 0; sqlite3 *pDest; sqlite3_backup *pBackup; int j; for(j=1; j<nArg; j++){ const char *z = azArg[j]; if( z[0]=='-' ){ while( z[0]=='-' ) z++; if( strcmp(z,"key")==0 && j<nArg-1 ){ zKey = azArg[++j]; }else { fprintf(stderr, "unknown option: %s\n", azArg[j]); return 1; } }else if( zDestFile==0 ){ zDestFile = azArg[j]; }else if( zDb==0 ){ zDb = zDestFile; zDestFile = azArg[j]; }else{ fprintf(stderr, "too many arguments to .backup\n"); return 1; } } if( zDestFile==0 ){ fprintf(stderr, "missing FILENAME argument on .backup\n"); return 1; } if( zDb==0 ) zDb = "main"; rc = sqlite3_open(zDestFile, &pDest); if( rc!=SQLITE_OK ){ fprintf(stderr, "Error: cannot open \"%s\"\n", zDestFile); sqlite3_close(pDest); return 1; } #ifdef SQLITE_HAS_CODEC sqlite3_key(pDest, zKey, (int)strlen(zKey)); #else (void)zKey; #endif 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; } |
︙ | ︙ | |||
1738 1739 1740 1741 1742 1743 1744 | fprintf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n"); }else if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 && nArg<3 ){ p->echoOn = booleanValue(azArg[1]); }else | | > | 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 | fprintf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "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 ){ if( nArg>1 && (rc = atoi(azArg[1]))!=0 ) exit(rc); 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) { |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
279 280 281 282 283 284 285 | ** host languages that are garbage collected, and where the order in which ** destructors are called is arbitrary. ** ** Applications should [sqlite3_finalize | finalize] all [prepared statements], ** [sqlite3_blob_close | close] all [BLOB handles], and ** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated ** with the [sqlite3] object prior to attempting to close the object. ^If | | | 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 | ** host languages that are garbage collected, and where the order in which ** destructors are called is arbitrary. ** ** Applications should [sqlite3_finalize | finalize] all [prepared statements], ** [sqlite3_blob_close | close] all [BLOB handles], and ** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated ** with the [sqlite3] object prior to attempting to close the object. ^If ** sqlite3_close_v2() is called on a [database connection] that still has ** outstanding [prepared statements], [BLOB handles], and/or ** [sqlite3_backup] objects then it returns SQLITE_OK but the deallocation ** of resources is deferred until all [prepared statements], [BLOB handles], ** and [sqlite3_backup] objects are also destroyed. ** ** ^If an [sqlite3] object is destroyed while a transaction is open, ** the transaction is automatically rolled back. |
︙ | ︙ | |||
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 | #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8)) #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) #define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8)) /* ** CAPI3REF: Flags For File Open Operations ** ** These bit values are intended for use in the ** 3rd parameter to the [sqlite3_open_v2()] interface and ** in the 4th parameter to the [sqlite3_vfs.xOpen] method. | > > > > > > > > > > | 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 | #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8)) #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) #define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8)) #define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8)) #define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8)) #define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8)) #define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8)) #define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8)) #define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3<<8)) #define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4<<8)) #define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5<<8)) #define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6<<8)) #define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7<<8)) #define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8)) #define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8)) /* ** CAPI3REF: Flags For File Open Operations ** ** These bit values are intended for use in the ** 3rd parameter to the [sqlite3_open_v2()] interface and ** in the 4th parameter to the [sqlite3_vfs.xOpen] method. |
︙ | ︙ |
Changes to src/sqlite3ext.h.
︙ | ︙ | |||
232 233 234 235 236 237 238 239 240 241 242 243 244 245 | int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*); int (*wal_autocheckpoint)(sqlite3*,int); int (*wal_checkpoint)(sqlite3*,const char*); void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*); int (*blob_reopen)(sqlite3_blob*,sqlite3_int64); int (*vtab_config)(sqlite3*,int op,...); int (*vtab_on_conflict)(sqlite3*); }; /* ** The following macros redefine the API routines so that they are ** redirected throught the global sqlite3_api structure. ** ** This header file is also used by the loadext.c source file | > > > > > > > > > > > > > > | 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 | int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*); int (*wal_autocheckpoint)(sqlite3*,int); int (*wal_checkpoint)(sqlite3*,const char*); void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*); int (*blob_reopen)(sqlite3_blob*,sqlite3_int64); int (*vtab_config)(sqlite3*,int op,...); int (*vtab_on_conflict)(sqlite3*); /* Version 3.7.16 and later */ int (*close_v2)(sqlite3*); const char *(*db_filename)(sqlite3*,const char*); int (*db_readonly)(sqlite3*,const char*); int (*db_release_memory)(sqlite3*); const char *(*errstr)(int); int (*stmt_busy)(sqlite3_stmt*); int (*stmt_readonly)(sqlite3_stmt*); int (*stricmp)(const char*,const char*); int (*uri_boolean)(const char*,const char*,int); sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64); const char *(*uri_parameter)(const char*,const char*); char *(*vsnprintf)(int,char*,const char*,va_list); int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*); }; /* ** The following macros redefine the API routines so that they are ** redirected throught the global sqlite3_api structure. ** ** This header file is also used by the loadext.c source file |
︙ | ︙ | |||
435 436 437 438 439 440 441 442 443 444 445 446 447 | #define sqlite3_unlock_notify sqlite3_api->unlock_notify #define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint #define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint #define sqlite3_wal_hook sqlite3_api->wal_hook #define sqlite3_blob_reopen sqlite3_api->blob_reopen #define sqlite3_vtab_config sqlite3_api->vtab_config #define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict #endif /* SQLITE_CORE */ #define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api = 0; #define SQLITE_EXTENSION_INIT2(v) sqlite3_api = v; #endif /* _SQLITE3EXT_H_ */ | > > > > > > > > > > > > > > | 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 | #define sqlite3_unlock_notify sqlite3_api->unlock_notify #define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint #define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint #define sqlite3_wal_hook sqlite3_api->wal_hook #define sqlite3_blob_reopen sqlite3_api->blob_reopen #define sqlite3_vtab_config sqlite3_api->vtab_config #define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict /* Version 3.7.16 and later */ #define sqlite3_close_v2 sqlite3_api->close_v2 #define sqlite3_db_filename sqlite3_api->db_filename #define sqlite3_db_readonly sqlite3_api->db_readonly #define sqlite3_db_release_memory sqlite3_api->db_release_memory #define sqlite3_errstr sqlite3_api->errstr #define sqlite3_stmt_busy sqlite3_api->stmt_busy #define sqlite3_stmt_readonly sqlite3_api->stmt_readonly #define sqlite3_stricmp sqlite3_api->stricmp #define sqlite3_uri_boolean sqlite3_api->uri_boolean #define sqlite3_uri_int64 sqlite3_api->uri_int64 #define sqlite3_uri_parameter sqlite3_api->uri_parameter #define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf #define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2 #endif /* SQLITE_CORE */ #define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api = 0; #define SQLITE_EXTENSION_INIT2(v) sqlite3_api = v; #endif /* _SQLITE3EXT_H_ */ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
62 63 64 65 66 67 68 69 70 71 72 73 74 75 | #endif /* Needed for various definitions... */ #ifndef _GNU_SOURCE # define _GNU_SOURCE #endif /* ** Include standard header files as necessary */ #ifdef HAVE_STDINT_H #include <stdint.h> #endif #ifdef HAVE_INTTYPES_H | > > > > | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | #endif /* Needed for various definitions... */ #ifndef _GNU_SOURCE # define _GNU_SOURCE #endif #if defined(__OpenBSD__) && !defined(_BSD_SOURCE) # define _BSD_SOURCE #endif /* ** Include standard header files as necessary */ #ifdef HAVE_STDINT_H #include <stdint.h> #endif #ifdef HAVE_INTTYPES_H |
︙ | ︙ | |||
196 197 198 199 200 201 202 | ** Later we learn that _XOPEN_SOURCE is poorly or incorrectly ** implemented on some systems. So we avoid defining it at all ** if it is already defined or if it is unneeded because we are ** not doing a threadsafe build. Ticket #2681. ** ** See also ticket #2741. */ | | > | 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | ** Later we learn that _XOPEN_SOURCE is poorly or incorrectly ** implemented on some systems. So we avoid defining it at all ** if it is already defined or if it is unneeded because we are ** not doing a threadsafe build. Ticket #2681. ** ** See also ticket #2741. */ #if !defined(_XOPEN_SOURCE) && !defined(__DARWIN__) \ && !defined(__APPLE__) && SQLITE_THREADSAFE # define _XOPEN_SOURCE 500 /* Needed to enable pthread recursive mutexes */ #endif /* ** The TCL headers are only needed when compiling the TCL bindings. */ #if defined(SQLITE_TCL) || defined(TCLSH) |
︙ | ︙ | |||
571 572 573 574 575 576 577 578 579 580 581 582 583 584 | /* ** A convenience macro that returns the number of elements in ** an array. */ #define ArraySize(X) ((int)(sizeof(X)/sizeof(X[0]))) /* ** The following value as a destructor means to use sqlite3DbFree(). ** The sqlite3DbFree() routine requires two parameters instead of the ** one parameter that destructors normally want. So we have to introduce ** this magic value that the code knows to handle differently. Any ** pointer will work here as long as it is distinct from SQLITE_STATIC ** and SQLITE_TRANSIENT. | > > > > > | 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 | /* ** A convenience macro that returns the number of elements in ** an array. */ #define ArraySize(X) ((int)(sizeof(X)/sizeof(X[0]))) /* ** Determine if the argument is a power of two */ #define IsPowerOfTwo(X) (((X)&((X)-1))==0) /* ** The following value as a destructor means to use sqlite3DbFree(). ** The sqlite3DbFree() routine requires two parameters instead of the ** one parameter that destructors normally want. So we have to introduce ** this magic value that the code knows to handle differently. Any ** pointer will work here as long as it is distinct from SQLITE_STATIC ** and SQLITE_TRANSIENT. |
︙ | ︙ | |||
940 941 942 943 944 945 946 | /* DELETE, or UPDATE and return */ /* the count using a callback. */ #define SQLITE_NullCallback 0x00000020 /* Invoke the callback once if the */ /* result set is empty */ #define SQLITE_SqlTrace 0x00000040 /* Debug print SQL as it executes */ #define SQLITE_VdbeListing 0x00000080 /* Debug listings of VDBE programs */ #define SQLITE_WriteSchema 0x00000100 /* OK to update SQLITE_MASTER */ | | | 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 | /* DELETE, or UPDATE and return */ /* the count using a callback. */ #define SQLITE_NullCallback 0x00000020 /* Invoke the callback once if the */ /* result set is empty */ #define SQLITE_SqlTrace 0x00000040 /* Debug print SQL as it executes */ #define SQLITE_VdbeListing 0x00000080 /* Debug listings of VDBE programs */ #define SQLITE_WriteSchema 0x00000100 /* OK to update SQLITE_MASTER */ #define SQLITE_VdbeAddopTrace 0x00000200 /* Trace sqlite3VdbeAddOp() calls */ #define SQLITE_IgnoreChecks 0x00000400 /* Do not enforce check constraints */ #define SQLITE_ReadUncommitted 0x0000800 /* For shared-cache mode */ #define SQLITE_LegacyFileFmt 0x00001000 /* Create new databases in format 1 */ #define SQLITE_FullFSync 0x00002000 /* Use full fsync on the backend */ #define SQLITE_CkptFullFSync 0x00004000 /* Use full fsync for checkpoint */ #define SQLITE_RecoveryMode 0x00008000 /* Ignore schema errors */ #define SQLITE_ReverseOrder 0x00010000 /* Reverse unordered SELECTs */ |
︙ | ︙ | |||
969 970 971 972 973 974 975 976 977 978 979 980 981 982 | #define SQLITE_GroupByOrder 0x0004 /* GROUPBY cover of ORDERBY */ #define SQLITE_FactorOutConst 0x0008 /* Constant factoring */ #define SQLITE_IdxRealAsInt 0x0010 /* Store REAL as INT in indices */ #define SQLITE_DistinctOpt 0x0020 /* DISTINCT using indexes */ #define SQLITE_CoverIdxScan 0x0040 /* Covering index scans */ #define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */ #define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */ #define SQLITE_AllOpts 0xffff /* All optimizations */ /* ** Macros for testing whether or not optimizations are enabled or disabled. */ #ifndef SQLITE_OMIT_BUILTIN_TEST #define OptimizationDisabled(db, mask) (((db)->dbOptFlags&(mask))!=0) | > | 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 | #define SQLITE_GroupByOrder 0x0004 /* GROUPBY cover of ORDERBY */ #define SQLITE_FactorOutConst 0x0008 /* Constant factoring */ #define SQLITE_IdxRealAsInt 0x0010 /* Store REAL as INT in indices */ #define SQLITE_DistinctOpt 0x0020 /* DISTINCT using indexes */ #define SQLITE_CoverIdxScan 0x0040 /* Covering index scans */ #define SQLITE_OrderByIdxJoin 0x0080 /* ORDER BY of joins via index */ #define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */ #define SQLITE_Transitive 0x0200 /* Transitive constraints */ #define SQLITE_AllOpts 0xffff /* All optimizations */ /* ** Macros for testing whether or not optimizations are enabled or disabled. */ #ifndef SQLITE_OMIT_BUILTIN_TEST #define OptimizationDisabled(db, mask) (((db)->dbOptFlags&(mask))!=0) |
︙ | ︙ | |||
1480 1481 1482 1483 1484 1485 1486 | ** must be unique and what to do if they are not. When Index.onError=OE_None, ** it means this is not a unique index. Otherwise it is a unique index ** and the value of Index.onError indicate the which conflict resolution ** algorithm to employ whenever an attempt is made to insert a non-unique ** element. */ struct Index { | | | | | | | | | | < | > | | | | 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 | ** must be unique and what to do if they are not. When Index.onError=OE_None, ** it means this is not a unique index. Otherwise it is a unique index ** and the value of Index.onError indicate the which conflict resolution ** algorithm to employ whenever an attempt is made to insert a non-unique ** element. */ struct Index { char *zName; /* Name of this index */ int *aiColumn; /* Which columns are used by this index. 1st is 0 */ tRowcnt *aiRowEst; /* From ANALYZE: Est. rows selected by each column */ Table *pTable; /* The SQL table being indexed */ char *zColAff; /* String defining the affinity of each column */ Index *pNext; /* The next index associated with the same table */ Schema *pSchema; /* Schema containing this index */ u8 *aSortOrder; /* for each column: True==DESC, False==ASC */ char **azColl; /* Array of collation sequence names for index */ int tnum; /* DB Page containing root of this index */ u16 nColumn; /* Number of columns in table used by this index */ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ unsigned autoIndex:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */ unsigned bUnordered:1; /* Use this index for == or IN queries only */ #ifdef SQLITE_ENABLE_STAT3 int nSample; /* Number of elements in aSample[] */ tRowcnt avgEq; /* Average nEq value for key values not in aSample */ IndexSample *aSample; /* Samples of the left-most key */ #endif }; |
︙ | ︙ | |||
1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 | /* ** A list of expressions. Each expression may optionally have a ** name. An expr/name combination can be used in several ways, such ** as the list of "expr AS ID" fields following a "SELECT" or in the ** list of "ID = expr" items in an UPDATE. A list of expressions can ** also be used as the argument to a function, in which case the a.zName ** field is not used. */ struct ExprList { int nExpr; /* Number of expressions on the list */ int iECursor; /* VDBE Cursor associated with this ExprList */ struct ExprList_item { /* For each expression in the list */ | > > > > > > > > | | | | | > | | | 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 | /* ** A list of expressions. Each expression may optionally have a ** name. An expr/name combination can be used in several ways, such ** as the list of "expr AS ID" fields following a "SELECT" or in the ** list of "ID = expr" items in an UPDATE. A list of expressions can ** also be used as the argument to a function, in which case the a.zName ** field is not used. ** ** By default the Expr.zSpan field holds a human-readable description of ** the expression that is used in the generation of error messages and ** column labels. In this case, Expr.zSpan is typically the text of a ** column expression as it exists in a SELECT statement. However, if ** the bSpanIsTab flag is set, then zSpan is overloaded to mean the name ** of the result column in the form: DATABASE.TABLE.COLUMN. This later ** form is used for name resolution with nested FROM clauses. */ struct ExprList { int nExpr; /* Number of expressions on the list */ int iECursor; /* VDBE Cursor associated with this ExprList */ struct ExprList_item { /* For each expression in the list */ Expr *pExpr; /* The list of expressions */ char *zName; /* Token associated with this expression */ char *zSpan; /* Original text of the expression */ u8 sortOrder; /* 1 for DESC or 0 for ASC */ unsigned done :1; /* A flag to indicate when processing is finished */ unsigned bSpanIsTab :1; /* zSpan holds DB.TABLE.COLUMN */ u16 iOrderByCol; /* For ORDER BY, column number in result set */ u16 iAlias; /* Index into Parse.aAlias[] for zName */ } *a; /* Alloc a power of two greater or equal to nExpr */ }; /* ** An instance of this structure is used by the parser to record both ** the parse tree for an expression and the span of input text for an ** expression. |
︙ | ︙ | |||
1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 | int p1, p2; /* Operands of the opcode used to ends the loop */ union { /* Information that depends on plan.wsFlags */ struct { int nIn; /* Number of entries in aInLoop[] */ struct InLoop { int iCur; /* The VDBE cursor used by this IN operator */ int addrInTop; /* Top of the IN loop */ } *aInLoop; /* Information about each nested IN operator */ } in; /* Used when plan.wsFlags&WHERE_IN_ABLE */ Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */ } u; double rOptCost; /* "Optimal" cost for this level */ /* The following field is really not part of the current level. But | > | 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 | int p1, p2; /* Operands of the opcode used to ends the loop */ union { /* Information that depends on plan.wsFlags */ struct { int nIn; /* Number of entries in aInLoop[] */ struct InLoop { int iCur; /* The VDBE cursor used by this IN operator */ int addrInTop; /* Top of the IN loop */ u8 eEndLoopOp; /* IN Loop terminator. OP_Next or OP_Prev */ } *aInLoop; /* Information about each nested IN operator */ } in; /* Used when plan.wsFlags&WHERE_IN_ABLE */ Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */ } u; double rOptCost; /* "Optimal" cost for this level */ /* The following field is really not part of the current level. But |
︙ | ︙ | |||
2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 | #define SF_Aggregate 0x0004 /* Contains aggregate functions */ #define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */ #define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */ #define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */ #define SF_UseSorter 0x0040 /* Sort using a sorter */ #define SF_Values 0x0080 /* Synthesized from VALUES clause */ #define SF_Materialize 0x0100 /* Force materialization of views */ /* ** The results of a select can be distributed in several ways. The ** "SRT" prefix means "SELECT Result Type". */ #define SRT_Union 1 /* Store result as keys in an index */ | > | 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 | #define SF_Aggregate 0x0004 /* Contains aggregate functions */ #define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */ #define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */ #define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */ #define SF_UseSorter 0x0040 /* Sort using a sorter */ #define SF_Values 0x0080 /* Synthesized from VALUES clause */ #define SF_Materialize 0x0100 /* Force materialization of views */ #define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */ /* ** The results of a select can be distributed in several ways. The ** "SRT" prefix means "SELECT Result Type". */ #define SRT_Union 1 /* Store result as keys in an index */ |
︙ | ︙ | |||
2810 2811 2812 2813 2814 2815 2816 | 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*, | | | | 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 | 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*,u16,Expr*,Expr*); void sqlite3SelectDelete(sqlite3*, Select*); Table *sqlite3SrcListLookup(Parse*, SrcList*); int sqlite3IsReadOnly(Parse*, Table*, int); void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int); #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,Expr*,char*); #endif void sqlite3DeleteFrom(Parse*, SrcList*, Expr*); void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int); WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int); void sqlite3WhereEnd(WhereInfo*); int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8); void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); |
︙ | ︙ | |||
2884 2885 2886 2887 2888 2889 2890 | 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*); | | | 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 | 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, 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,u8); |
︙ | ︙ | |||
2997 2998 2999 3000 3001 3002 3003 | ** x = sqlite3GetVarint32( A, &B ); ** x = sqlite3PutVarint32( A, B ); ** ** x = getVarint32( A, B ); ** x = putVarint32( A, B ); ** */ | | > | > > | 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 | ** x = sqlite3GetVarint32( A, &B ); ** x = sqlite3PutVarint32( A, B ); ** ** x = getVarint32( A, B ); ** x = putVarint32( A, B ); ** */ #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); |
︙ | ︙ | |||
3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 | void sqlite3AlterFunctions(void); 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(Parse*, u8, CollSeq *, const char*); | > | 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 | void sqlite3AlterFunctions(void); 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 sqlite3MatchSpanName(const char*, const char*, const char*, const char*); 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(Parse*, u8, CollSeq *, const char*); |
︙ | ︙ | |||
3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 | #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(sqlite3 *, Table*); #else #define sqlite3FkDelete(a,b) #endif /* ** Available fault injectors. Should be numbered beginning with 0. */ #define SQLITE_FAULTINJECTOR_MALLOC 0 | > > | 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 | #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(sqlite3 *, Table*); int sqlite3FkLocateIndex(Parse*,Table*,FKey*,Index**,int**); #else #define sqlite3FkDelete(a,b) #define sqlite3FkLocateIndex(a,b,c,d,e) #endif /* ** Available fault injectors. Should be numbered beginning with 0. */ #define SQLITE_FAULTINJECTOR_MALLOC 0 |
︙ | ︙ | |||
3231 3232 3233 3234 3235 3236 3237 | #else #define sqlite3BeginBenignMalloc() #define sqlite3EndBenignMalloc() #endif #define IN_INDEX_ROWID 1 #define IN_INDEX_EPH 2 | | > | 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 | #else #define sqlite3BeginBenignMalloc() #define sqlite3EndBenignMalloc() #endif #define IN_INDEX_ROWID 1 #define IN_INDEX_EPH 2 #define IN_INDEX_INDEX_ASC 3 #define IN_INDEX_INDEX_DESC 4 int sqlite3FindInIndex(Parse *, Expr *, int*); #ifdef SQLITE_ENABLE_ATOMIC_WRITE int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int); int sqlite3JournalSize(sqlite3_vfs *); int sqlite3JournalCreate(sqlite3_file *); int sqlite3JournalExists(sqlite3_file *p); |
︙ | ︙ |
Changes to src/tclsqlite.c.
︙ | ︙ | |||
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 | 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*); extern int Sqlitetestvfs_Init(Tcl_Interp *); extern int Sqlitetestrtree_Init(Tcl_Interp*); extern int Sqlitequota_Init(Tcl_Interp*); extern int Sqlitemultiplex_Init(Tcl_Interp*); extern int SqliteSuperlock_Init(Tcl_Interp*); extern int SqlitetestSyscall_Init(Tcl_Interp*); extern int Sqlitetestfuzzer_Init(Tcl_Interp*); extern int Sqlitetestwholenumber_Init(Tcl_Interp*); #if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) extern int Sqlitetestfts3_Init(Tcl_Interp *interp); #endif #ifdef SQLITE_ENABLE_ZIPVFS extern int Zipvfs_Init(Tcl_Interp*); | > > | 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 | 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 Sqlitetestfs_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*); extern int Sqlitetestvfs_Init(Tcl_Interp *); extern int Sqlitetestrtree_Init(Tcl_Interp*); extern int Sqlitequota_Init(Tcl_Interp*); extern int Sqlitemultiplex_Init(Tcl_Interp*); extern int SqliteSuperlock_Init(Tcl_Interp*); extern int SqlitetestSyscall_Init(Tcl_Interp*); extern int Sqlitetestfuzzer_Init(Tcl_Interp*); extern int Sqlitetestwholenumber_Init(Tcl_Interp*); extern int Sqlitetestregexp_Init(Tcl_Interp*); #if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) extern int Sqlitetestfts3_Init(Tcl_Interp *interp); #endif #ifdef SQLITE_ENABLE_ZIPVFS extern int Zipvfs_Init(Tcl_Interp*); |
︙ | ︙ | |||
3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 | 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); Sqlitetestvfs_Init(interp); Sqlitetestrtree_Init(interp); Sqlitequota_Init(interp); Sqlitemultiplex_Init(interp); SqliteSuperlock_Init(interp); SqlitetestSyscall_Init(interp); Sqlitetestfuzzer_Init(interp); Sqlitetestwholenumber_Init(interp); #if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) Sqlitetestfts3_Init(interp); #endif Tcl_CreateObjCommand( interp, "load_testfixture_extensions", init_all_cmd, 0, 0 | > > | 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 | 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); Sqlitetestfs_Init(interp); SqlitetestThread_Init(interp); SqlitetestOnefile_Init(interp); SqlitetestOsinst_Init(interp); Sqlitetestbackup_Init(interp); Sqlitetestintarray_Init(interp); Sqlitetestvfs_Init(interp); Sqlitetestrtree_Init(interp); Sqlitequota_Init(interp); Sqlitemultiplex_Init(interp); SqliteSuperlock_Init(interp); SqlitetestSyscall_Init(interp); Sqlitetestfuzzer_Init(interp); Sqlitetestwholenumber_Init(interp); Sqlitetestregexp_Init(interp); #if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4) Sqlitetestfts3_Init(interp); #endif Tcl_CreateObjCommand( interp, "load_testfixture_extensions", init_all_cmd, 0, 0 |
︙ | ︙ |
Changes to src/test1.c.
︙ | ︙ | |||
134 135 136 137 138 139 140 141 142 143 144 145 146 147 | case SQLITE_FULL: zName = "SQLITE_FULL"; break; case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break; case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break; case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break; case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break; case SQLITE_TOOBIG: zName = "SQLITE_TOOBIG"; break; case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT"; break; case SQLITE_MISMATCH: zName = "SQLITE_MISMATCH"; break; case SQLITE_MISUSE: zName = "SQLITE_MISUSE"; break; case SQLITE_NOLFS: zName = "SQLITE_NOLFS"; break; case SQLITE_AUTH: zName = "SQLITE_AUTH"; break; case SQLITE_FORMAT: zName = "SQLITE_FORMAT"; break; case SQLITE_RANGE: zName = "SQLITE_RANGE"; break; case SQLITE_NOTADB: zName = "SQLITE_NOTADB"; break; | > > > > > > > > > > > > | 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 | case SQLITE_FULL: zName = "SQLITE_FULL"; break; case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break; case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break; case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break; case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break; case SQLITE_TOOBIG: zName = "SQLITE_TOOBIG"; break; case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT"; break; case SQLITE_CONSTRAINT_UNIQUE: zName = "SQLITE_CONSTRAINT_UNIQUE"; break; case SQLITE_CONSTRAINT_TRIGGER: zName = "SQLITE_CONSTRAINT_TRIGGER";break; case SQLITE_CONSTRAINT_FOREIGNKEY: zName = "SQLITE_CONSTRAINT_FOREIGNKEY"; break; case SQLITE_CONSTRAINT_CHECK: zName = "SQLITE_CONSTRAINT_CHECK"; break; case SQLITE_CONSTRAINT_PRIMARYKEY: zName = "SQLITE_CONSTRAINT_PRIMARYKEY"; break; case SQLITE_CONSTRAINT_NOTNULL: zName = "SQLITE_CONSTRAINT_NOTNULL";break; case SQLITE_CONSTRAINT_COMMITHOOK: zName = "SQLITE_CONSTRAINT_COMMITHOOK"; break; case SQLITE_CONSTRAINT_VTAB: zName = "SQLITE_CONSTRAINT_VTAB"; break; case SQLITE_CONSTRAINT_FUNCTION: zName = "SQLITE_CONSTRAINT_FUNCTION";break; case SQLITE_MISMATCH: zName = "SQLITE_MISMATCH"; break; case SQLITE_MISUSE: zName = "SQLITE_MISUSE"; break; case SQLITE_NOLFS: zName = "SQLITE_NOLFS"; break; case SQLITE_AUTH: zName = "SQLITE_AUTH"; break; case SQLITE_FORMAT: zName = "SQLITE_FORMAT"; break; case SQLITE_RANGE: zName = "SQLITE_RANGE"; break; case SQLITE_NOTADB: zName = "SQLITE_NOTADB"; break; |
︙ | ︙ | |||
162 163 164 165 166 167 168 169 170 171 172 173 174 175 | case SQLITE_IOERR_ACCESS: zName = "SQLITE_IOERR_ACCESS"; break; case SQLITE_IOERR_CHECKRESERVEDLOCK: zName = "SQLITE_IOERR_CHECKRESERVEDLOCK"; break; case SQLITE_IOERR_LOCK: zName = "SQLITE_IOERR_LOCK"; break; case SQLITE_CORRUPT_VTAB: zName = "SQLITE_CORRUPT_VTAB"; break; case SQLITE_READONLY_RECOVERY: zName = "SQLITE_READONLY_RECOVERY"; break; case SQLITE_READONLY_CANTLOCK: zName = "SQLITE_READONLY_CANTLOCK"; break; default: zName = "SQLITE_Unknown"; break; } return zName; } #define t1ErrorName sqlite3TestErrorName /* | > | 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | case SQLITE_IOERR_ACCESS: zName = "SQLITE_IOERR_ACCESS"; break; case SQLITE_IOERR_CHECKRESERVEDLOCK: zName = "SQLITE_IOERR_CHECKRESERVEDLOCK"; break; case SQLITE_IOERR_LOCK: zName = "SQLITE_IOERR_LOCK"; break; case SQLITE_CORRUPT_VTAB: zName = "SQLITE_CORRUPT_VTAB"; break; case SQLITE_READONLY_RECOVERY: zName = "SQLITE_READONLY_RECOVERY"; break; case SQLITE_READONLY_CANTLOCK: zName = "SQLITE_READONLY_CANTLOCK"; break; case SQLITE_READONLY_ROLLBACK: zName = "SQLITE_READONLY_ROLLBACK"; break; default: zName = "SQLITE_Unknown"; break; } return zName; } #define t1ErrorName sqlite3TestErrorName /* |
︙ | ︙ | |||
6232 6233 6234 6235 6236 6237 6238 | extern int sqlite3_pager_writej_count; #if SQLITE_OS_WIN extern int sqlite3_os_type; #endif #ifdef SQLITE_DEBUG extern int sqlite3WhereTrace; extern int sqlite3OSTrace; | < | 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 | extern int sqlite3_pager_writej_count; #if SQLITE_OS_WIN extern int sqlite3_os_type; #endif #ifdef SQLITE_DEBUG extern int sqlite3WhereTrace; extern int sqlite3OSTrace; extern int sqlite3WalTrace; #endif #ifdef SQLITE_TEST extern char sqlite3_query_plan[]; static char *query_plan = sqlite3_query_plan; #ifdef SQLITE_ENABLE_FTS3 extern int sqlite3_fts3_enable_parentheses; |
︙ | ︙ | |||
6295 6296 6297 6298 6299 6300 6301 | (char*)&sqlite3_os_type, TCL_LINK_INT); #endif #ifdef SQLITE_TEST Tcl_LinkVar(interp, "sqlite_query_plan", (char*)&query_plan, TCL_LINK_STRING|TCL_LINK_READ_ONLY); #endif #ifdef SQLITE_DEBUG | < < | 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 | (char*)&sqlite3_os_type, TCL_LINK_INT); #endif #ifdef SQLITE_TEST Tcl_LinkVar(interp, "sqlite_query_plan", (char*)&query_plan, TCL_LINK_STRING|TCL_LINK_READ_ONLY); #endif #ifdef SQLITE_DEBUG Tcl_LinkVar(interp, "sqlite_where_trace", (char*)&sqlite3WhereTrace, TCL_LINK_INT); Tcl_LinkVar(interp, "sqlite_os_trace", (char*)&sqlite3OSTrace, TCL_LINK_INT); #ifndef SQLITE_OMIT_WAL Tcl_LinkVar(interp, "sqlite_wal_trace", (char*)&sqlite3WalTrace, TCL_LINK_INT); |
︙ | ︙ |
Changes to src/test8.c.
︙ | ︙ | |||
1385 1386 1387 1388 1389 1390 1391 | if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; | | | 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 | if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; sqlite3_spellfix1_register(db); return TCL_OK; } #endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */ /* ** Register commands with the TCL interpreter. |
︙ | ︙ |
Added src/test_fs.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 | /* ** 2013 Jan 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. ** ************************************************************************* ** 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 FS virtual table is created as follows: ** ** CREATE VIRTUAL TABLE tbl USING fs(idx); ** ** where idx is the name of a table in the db with 2 columns. The virtual ** table also has two columns - file path and file contents. ** ** The first column of table idx must be an IPK, and the second contains file ** paths. For example: ** ** CREATE TABLE idx(id INTEGER PRIMARY KEY, path TEXT); ** INSERT INTO idx VALUES(4, '/etc/passwd'); ** ** Adding the row to the idx table automatically creates a row in the ** virtual table with rowid=4, path=/etc/passwd and a text field that ** contains data read from file /etc/passwd on disk. */ #include "sqliteInt.h" #include "tcl.h" #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #if SQLITE_OS_UNIX # include <unistd.h> #endif #if SQLITE_OS_WIN # include <io.h> #endif #ifndef SQLITE_OMIT_VIRTUALTABLE typedef struct fs_vtab fs_vtab; typedef struct fs_cursor fs_cursor; /* ** A fs virtual-table object */ struct fs_vtab { sqlite3_vtab base; sqlite3 *db; char *zDb; /* Name of db containing zTbl */ char *zTbl; /* Name of docid->file map table */ }; /* A fs cursor object */ struct fs_cursor { sqlite3_vtab_cursor base; sqlite3_stmt *pStmt; char *zBuf; int nBuf; int nAlloc; }; /* ** This function is the implementation of both the xConnect and xCreate ** methods of the fs virtual table. ** ** The argv[] array contains the following: ** ** argv[0] -> module name ("fs") ** argv[1] -> database name ** argv[2] -> table name ** argv[...] -> other module argument fields. */ static int fsConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ fs_vtab *pVtab; int nByte; const char *zTbl; const char *zDb = argv[1]; if( argc!=4 ){ *pzErr = sqlite3_mprintf("wrong number of arguments"); return SQLITE_ERROR; } zTbl = argv[3]; nByte = sizeof(fs_vtab) + strlen(zTbl) + 1 + strlen(zDb) + 1; pVtab = (fs_vtab *)sqlite3MallocZero( nByte ); if( !pVtab ) return SQLITE_NOMEM; pVtab->zTbl = (char *)&pVtab[1]; pVtab->zDb = &pVtab->zTbl[strlen(zTbl)+1]; pVtab->db = db; memcpy(pVtab->zTbl, zTbl, strlen(zTbl)); memcpy(pVtab->zDb, zDb, strlen(zDb)); *ppVtab = &pVtab->base; sqlite3_declare_vtab(db, "CREATE TABLE xyz(path TEXT, data TEXT)"); return SQLITE_OK; } /* Note that for this virtual table, the xCreate and xConnect ** methods are identical. */ static int fsDisconnect(sqlite3_vtab *pVtab){ sqlite3_free(pVtab); return SQLITE_OK; } /* The xDisconnect and xDestroy methods are also the same */ /* ** Open a new fs cursor. */ static int fsOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ fs_cursor *pCur; pCur = sqlite3MallocZero(sizeof(fs_cursor)); *ppCursor = &pCur->base; return SQLITE_OK; } /* ** Close a fs cursor. */ static int fsClose(sqlite3_vtab_cursor *cur){ fs_cursor *pCur = (fs_cursor *)cur; sqlite3_finalize(pCur->pStmt); sqlite3_free(pCur->zBuf); sqlite3_free(pCur); return SQLITE_OK; } static int fsNext(sqlite3_vtab_cursor *cur){ fs_cursor *pCur = (fs_cursor *)cur; int rc; rc = sqlite3_step(pCur->pStmt); if( rc==SQLITE_ROW || rc==SQLITE_DONE ) rc = SQLITE_OK; return rc; } static int fsFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ int rc; fs_cursor *pCur = (fs_cursor *)pVtabCursor; fs_vtab *p = (fs_vtab *)(pVtabCursor->pVtab); assert( (idxNum==0 && argc==0) || (idxNum==1 && argc==1) ); if( idxNum==1 ){ char *zStmt = sqlite3_mprintf( "SELECT * FROM %Q.%Q WHERE rowid=?", p->zDb, p->zTbl); if( !zStmt ) return SQLITE_NOMEM; rc = sqlite3_prepare_v2(p->db, zStmt, -1, &pCur->pStmt, 0); sqlite3_free(zStmt); if( rc==SQLITE_OK ){ sqlite3_bind_value(pCur->pStmt, 1, argv[0]); } }else{ char *zStmt = sqlite3_mprintf("SELECT * FROM %Q.%Q", p->zDb, p->zTbl); if( !zStmt ) return SQLITE_NOMEM; rc = sqlite3_prepare_v2(p->db, zStmt, -1, &pCur->pStmt, 0); sqlite3_free(zStmt); } if( rc==SQLITE_OK ){ rc = fsNext(pVtabCursor); } return rc; } static int fsColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ fs_cursor *pCur = (fs_cursor*)cur; assert( i==0 || i==1 ); if( i==0 ){ sqlite3_result_value(ctx, sqlite3_column_value(pCur->pStmt, 0)); }else{ const char *zFile = (const char *)sqlite3_column_text(pCur->pStmt, 1); struct stat sbuf; int fd; fd = open(zFile, O_RDONLY); if( fd<0 ) return SQLITE_IOERR; fstat(fd, &sbuf); if( sbuf.st_size>=pCur->nAlloc ){ int nNew = sbuf.st_size*2; char *zNew; if( nNew<1024 ) nNew = 1024; zNew = sqlite3Realloc(pCur->zBuf, nNew); if( zNew==0 ){ close(fd); return SQLITE_NOMEM; } pCur->zBuf = zNew; pCur->nAlloc = nNew; } read(fd, pCur->zBuf, sbuf.st_size); close(fd); pCur->nBuf = sbuf.st_size; pCur->zBuf[pCur->nBuf] = '\0'; sqlite3_result_text(ctx, pCur->zBuf, -1, SQLITE_TRANSIENT); } return SQLITE_OK; } static int fsRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ fs_cursor *pCur = (fs_cursor*)cur; *pRowid = sqlite3_column_int64(pCur->pStmt, 0); return SQLITE_OK; } static int fsEof(sqlite3_vtab_cursor *cur){ fs_cursor *pCur = (fs_cursor*)cur; return (sqlite3_data_count(pCur->pStmt)==0); } static int fsBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ int ii; for(ii=0; ii<pIdxInfo->nConstraint; ii++){ struct sqlite3_index_constraint const *pCons = &pIdxInfo->aConstraint[ii]; if( pCons->iColumn<0 && pCons->usable && pCons->op==SQLITE_INDEX_CONSTRAINT_EQ ){ struct sqlite3_index_constraint_usage *pUsage; pUsage = &pIdxInfo->aConstraintUsage[ii]; pUsage->omit = 0; pUsage->argvIndex = 1; pIdxInfo->idxNum = 1; pIdxInfo->estimatedCost = 1.0; break; } } return SQLITE_OK; } /* ** A virtual table module that provides read-only access to a ** Tcl global variable namespace. */ static sqlite3_module fsModule = { 0, /* iVersion */ fsConnect, fsConnect, fsBestIndex, fsDisconnect, fsDisconnect, fsOpen, /* xOpen - open a cursor */ fsClose, /* xClose - close a cursor */ fsFilter, /* xFilter - configure scan constraints */ fsNext, /* xNext - advance a cursor */ fsEof, /* xEof - check for end of scan */ fsColumn, /* xColumn - read data */ fsRowid, /* xRowid - read data */ 0, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ }; /* ** Decode a pointer to an sqlite3 object. */ extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); /* ** Register the echo virtual table module. */ static int register_fs_module( ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3 *db; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3_create_module(db, "fs", &fsModule, (void *)interp); #endif return TCL_OK; } #endif /* ** Register commands with the TCL interpreter. */ int Sqlitetestfs_Init(Tcl_Interp *interp){ #ifndef SQLITE_OMIT_VIRTUALTABLE static struct { char *zName; Tcl_ObjCmdProc *xProc; void *clientData; } aObjCmd[] = { { "register_fs_module", register_fs_module, 0 }, }; int i; for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, aObjCmd[i].clientData, 0); } #endif return TCL_OK; } |
Changes to src/test_quota.c.
︙ | ︙ | |||
1291 1292 1293 1294 1295 1296 1297 | } quotaEnter(); pGroup = quotaGroupFind(zFull); if( pGroup ){ for(pFile=pGroup->pFiles; pFile && rc==SQLITE_OK; pFile=pNextFile){ pNextFile = pFile->pNext; | | | 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 | } quotaEnter(); pGroup = quotaGroupFind(zFull); if( pGroup ){ for(pFile=pGroup->pFiles; pFile && rc==SQLITE_OK; pFile=pNextFile){ pNextFile = pFile->pNext; diff = strncmp(zFull, pFile->zFilename, nFull); if( diff==0 && ((c = pFile->zFilename[nFull])==0 || c=='/' || c=='\\') ){ if( pFile->nRef ){ pFile->deleteOnClose = 1; }else{ rc = gQuota.pOrigVfs->xDelete(gQuota.pOrigVfs, pFile->zFilename, 0); quotaRemoveFile(pFile); quotaGroupDeref(pGroup); |
︙ | ︙ |
Added src/test_regexp.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 | /* ** 2012-11-13 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** The code in this file implements a compact but reasonably ** efficient regular-expression matcher for posix extended regular ** expressions against UTF8 text. The following syntax is supported: ** ** X* zero or more occurrences of X ** X+ one or more occurrences of X ** X? zero or one occurrences of X ** X{p,q} between p and q occurrences of X ** (X) match X ** X|Y X or Y ** ^X X occurring at the beginning of the string ** X$ X occurring at the end of the string ** . Match any single character ** \c Character c where c is one of \{}()[]|*+?. ** \c C-language escapes for c in afnrtv. ex: \t or \n ** \uXXXX Where XXXX is exactly 4 hex digits, unicode value XXXX ** \xXX Where XX is exactly 2 hex digits, unicode value XX ** [abc] Any single character from the set abc ** [^abc] Any single character not in the set abc ** [a-z] Any single character in the range a-z ** [^a-z] Any single character not in the range a-z ** \b Word boundary ** \w Word character. [A-Za-z0-9_] ** \W Non-word character ** \d Digit ** \D Non-digit ** \s Whitespace character ** \S Non-whitespace character ** ** A nondeterministic finite automaton (NFA) is used for matching, so the ** performance is bounded by O(N*M) where N is the size of the regular ** expression and M is the size of the input string. The matcher never ** exhibits exponential behavior. Note that the X{p,q} operator expands ** to p copies of X following by q-p copies of X? and that the size of the ** regular expression in the O(N*M) performance bound is computed after ** this expansion. */ #include <string.h> #include <stdlib.h> #include "sqlite3.h" /* The end-of-input character */ #define RE_EOF 0 /* End of input */ /* The NFA is implemented as sequence of opcodes taken from the following ** set. Each opcode has a single integer argument. */ #define RE_OP_MATCH 1 /* Match the one character in the argument */ #define RE_OP_ANY 2 /* Match any one character. (Implements ".") */ #define RE_OP_ANYSTAR 3 /* Special optimized version of .* */ #define RE_OP_FORK 4 /* Continue to both next and opcode at iArg */ #define RE_OP_GOTO 5 /* Jump to opcode at iArg */ #define RE_OP_ACCEPT 6 /* Halt and indicate a successful match */ #define RE_OP_CC_INC 7 /* Beginning of a [...] character class */ #define RE_OP_CC_EXC 8 /* Beginning of a [^...] character class */ #define RE_OP_CC_VALUE 9 /* Single value in a character class */ #define RE_OP_CC_RANGE 10 /* Range of values in a character class */ #define RE_OP_WORD 11 /* Perl word character [A-Za-z0-9_] */ #define RE_OP_NOTWORD 12 /* Not a perl word character */ #define RE_OP_DIGIT 13 /* digit: [0-9] */ #define RE_OP_NOTDIGIT 14 /* Not a digit */ #define RE_OP_SPACE 15 /* space: [ \t\n\r\v\f] */ #define RE_OP_NOTSPACE 16 /* Not a digit */ #define RE_OP_BOUNDARY 17 /* Boundary between word and non-word */ /* Each opcode is a "state" in the NFA */ typedef unsigned short ReStateNumber; /* Because this is an NFA and not a DFA, multiple states can be active at ** once. An instance of the following object records all active states in ** the NFA. The implementation is optimized for the common case where the ** number of actives states is small. */ typedef struct ReStateSet { unsigned nState; /* Number of current states */ ReStateNumber *aState; /* Current states */ } ReStateSet; /* An input string read one character at a time. */ typedef struct ReInput ReInput; struct ReInput { const unsigned char *z; /* All text */ int i; /* Next byte to read */ int mx; /* EOF when i>=mx */ }; /* A compiled NFA (or an NFA that is in the process of being compiled) is ** an instance of the following object. */ typedef struct ReCompiled ReCompiled; struct ReCompiled { ReInput sIn; /* Regular expression text */ const char *zErr; /* Error message to return */ char *aOp; /* Operators for the virtual machine */ int *aArg; /* Arguments to each operator */ unsigned (*xNextChar)(ReInput*); /* Next character function */ unsigned char zInit[12]; /* Initial text to match */ int nInit; /* Number of characters in zInit */ unsigned nState; /* Number of entries in aOp[] and aArg[] */ unsigned nAlloc; /* Slots allocated for aOp[] and aArg[] */ }; /* Add a state to the given state set if it is not already there */ static void re_add_state(ReStateSet *pSet, int newState){ unsigned i; for(i=0; i<pSet->nState; i++) if( pSet->aState[i]==newState ) return; pSet->aState[pSet->nState++] = newState; } /* Extract the next unicode character from *pzIn and return it. Advance ** *pzIn to the first byte past the end of the character returned. To ** be clear: this routine converts utf8 to unicode. This routine is ** optimized for the common case where the next character is a single byte. */ static unsigned re_next_char(ReInput *p){ unsigned c; if( p->i>=p->mx ) return 0; c = p->z[p->i++]; if( c>=0x80 ){ if( (c&0xe0)==0xc0 && p->i<p->mx && (p->z[p->i]&0xc0)==0x80 ){ c = (c&0x1f)<<6 | (p->z[p->i++]&0x3f); if( c<0x80 ) c = 0xfffd; }else if( (c&0xf0)==0xe0 && p->i+1<p->mx && (p->z[p->i]&0xc0)==0x80 && (p->z[p->i+1]&0xc0)==0x80 ){ c = (c&0x0f)<<12 | ((p->z[p->i]&0x3f)<<6) | (p->z[p->i+1]&0x3f); p->i += 2; if( c<=0x3ff || (c>=0xd800 && c<=0xdfff) ) c = 0xfffd; }else if( (c&0xf8)==0xf0 && p->i+3<p->mx && (p->z[p->i]&0xc0)==0x80 && (p->z[p->i+1]&0xc0)==0x80 && (p->z[p->i+2]&0xc0)==0x80 ){ c = (c&0x07)<<18 | ((p->z[p->i]&0x3f)<<12) | ((p->z[p->i+1]&0x3f)<<6) | (p->z[p->i+2]&0x3f); p->i += 3; if( c<=0xffff || c>0x10ffff ) c = 0xfffd; }else{ c = 0xfffd; } } return c; } static unsigned re_next_char_nocase(ReInput *p){ unsigned c = re_next_char(p); if( c>='A' && c<='Z' ) c += 'a' - 'A'; return c; } /* Return true if c is a perl "word" character: [A-Za-z0-9_] */ static int re_word_char(int c){ return (c>='0' && c<='9') || (c>='a' && c<='z') || (c>='A' && c<='Z') || c=='_'; } /* Return true if c is a "digit" character: [0-9] */ static int re_digit_char(int c){ return (c>='0' && c<='9'); } /* Return true if c is a perl "space" character: [ \t\r\n\v\f] */ static int re_space_char(int c){ return c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f'; } /* Run a compiled regular expression on the zero-terminated input ** string zIn[]. Return true on a match and false if there is no match. */ int re_match(ReCompiled *pRe, const unsigned char *zIn, int nIn){ ReStateSet aStateSet[2], *pThis, *pNext; ReStateNumber aSpace[100]; ReStateNumber *pToFree; unsigned int i = 0; unsigned int iSwap = 0; int c = RE_EOF+1; int cPrev = 0; int rc = 0; ReInput in; in.z = zIn; in.i = 0; in.mx = nIn>=0 ? nIn : strlen((char const*)zIn); /* Look for the initial prefix match, if there is one. */ if( pRe->nInit ){ unsigned char x = pRe->zInit[0]; while( in.i+pRe->nInit<=in.mx && (zIn[in.i]!=x || strncmp((const char*)zIn+in.i, (const char*)pRe->zInit, pRe->nInit)!=0) ){ in.i++; } if( in.i+pRe->nInit>in.mx ) return 0; } if( pRe->nState<=(sizeof(aSpace)/(sizeof(aSpace[0])*2)) ){ pToFree = 0; aStateSet[0].aState = aSpace; }else{ pToFree = sqlite3_malloc( sizeof(ReStateNumber)*2*pRe->nState ); if( pToFree==0 ) return -1; aStateSet[0].aState = pToFree; } aStateSet[1].aState = &aStateSet[0].aState[pRe->nState]; pNext = &aStateSet[1]; pNext->nState = 0; re_add_state(pNext, 0); while( c!=RE_EOF && pNext->nState>0 ){ cPrev = c; c = pRe->xNextChar(&in); pThis = pNext; pNext = &aStateSet[iSwap]; iSwap = 1 - iSwap; pNext->nState = 0; for(i=0; i<pThis->nState; i++){ int x = pThis->aState[i]; switch( pRe->aOp[x] ){ case RE_OP_MATCH: { if( pRe->aArg[x]==c ) re_add_state(pNext, x+1); break; } case RE_OP_ANY: { re_add_state(pNext, x+1); break; } case RE_OP_WORD: { if( re_word_char(c) ) re_add_state(pNext, x+1); break; } case RE_OP_NOTWORD: { if( !re_word_char(c) ) re_add_state(pNext, x+1); break; } case RE_OP_DIGIT: { if( re_digit_char(c) ) re_add_state(pNext, x+1); break; } case RE_OP_NOTDIGIT: { if( !re_digit_char(c) ) re_add_state(pNext, x+1); break; } case RE_OP_SPACE: { if( re_space_char(c) ) re_add_state(pNext, x+1); break; } case RE_OP_NOTSPACE: { if( !re_space_char(c) ) re_add_state(pNext, x+1); break; } case RE_OP_BOUNDARY: { if( re_word_char(c)!=re_word_char(cPrev) ) re_add_state(pThis, x+1); break; } case RE_OP_ANYSTAR: { re_add_state(pNext, x); re_add_state(pThis, x+1); break; } case RE_OP_FORK: { re_add_state(pThis, x+pRe->aArg[x]); re_add_state(pThis, x+1); break; } case RE_OP_GOTO: { re_add_state(pThis, x+pRe->aArg[x]); break; } case RE_OP_ACCEPT: { rc = 1; goto re_match_end; } case RE_OP_CC_INC: case RE_OP_CC_EXC: { int j = 1; int n = pRe->aArg[x]; int hit = 0; for(j=1; j>0 && j<n; j++){ if( pRe->aOp[x+j]==RE_OP_CC_VALUE ){ if( pRe->aArg[x+j]==c ){ hit = 1; j = -1; } }else{ if( pRe->aArg[x+j]<=c && pRe->aArg[x+j+1]>=c ){ hit = 1; j = -1; }else{ j++; } } } if( pRe->aOp[x]==RE_OP_CC_EXC ) hit = !hit; if( hit ) re_add_state(pNext, x+n); break; } } } } for(i=0; i<pNext->nState; i++){ if( pRe->aOp[pNext->aState[i]]==RE_OP_ACCEPT ){ rc = 1; break; } } re_match_end: sqlite3_free(pToFree); return rc; } /* Resize the opcode and argument arrays for an RE under construction. */ static int re_resize(ReCompiled *p, int N){ char *aOp; int *aArg; aOp = sqlite3_realloc(p->aOp, N*sizeof(p->aOp[0])); if( aOp==0 ) return 1; p->aOp = aOp; aArg = sqlite3_realloc(p->aArg, N*sizeof(p->aArg[0])); if( aArg==0 ) return 1; p->aArg = aArg; p->nAlloc = N; return 0; } /* Insert a new opcode and argument into an RE under construction. The ** insertion point is just prior to existing opcode iBefore. */ static int re_insert(ReCompiled *p, int iBefore, int op, int arg){ int i; if( p->nAlloc<=p->nState && re_resize(p, p->nAlloc*2) ) return 0; for(i=p->nState; i>iBefore; i--){ p->aOp[i] = p->aOp[i-1]; p->aArg[i] = p->aArg[i-1]; } p->nState++; p->aOp[iBefore] = op; p->aArg[iBefore] = arg; return iBefore; } /* Append a new opcode and argument to the end of the RE under construction. */ static int re_append(ReCompiled *p, int op, int arg){ return re_insert(p, p->nState, op, arg); } /* Make a copy of N opcodes starting at iStart onto the end of the RE ** under construction. */ static void re_copy(ReCompiled *p, int iStart, int N){ if( p->nState+N>=p->nAlloc && re_resize(p, p->nAlloc*2+N) ) return; memcpy(&p->aOp[p->nState], &p->aOp[iStart], N*sizeof(p->aOp[0])); memcpy(&p->aArg[p->nState], &p->aArg[iStart], N*sizeof(p->aArg[0])); p->nState += N; } /* Return true if c is a hexadecimal digit character: [0-9a-fA-F] ** If c is a hex digit, also set *pV = (*pV)*16 + valueof(c). If ** c is not a hex digit *pV is unchanged. */ static int re_hex(int c, int *pV){ if( c>='0' && c<='9' ){ c -= '0'; }else if( c>='a' && c<='f' ){ c -= 'a' - 10; }else if( c>='A' && c<='F' ){ c -= 'A' - 10; }else{ return 0; } *pV = (*pV)*16 + (c & 0xff); return 1; } /* A backslash character has been seen, read the next character and ** return its interpretation. */ static unsigned re_esc_char(ReCompiled *p){ static const char zEsc[] = "afnrtv\\()*.+?[$^{|}]"; static const char zTrans[] = "\a\f\n\r\t\v"; int i, v = 0; char c; if( p->sIn.i>=p->sIn.mx ) return 0; c = p->sIn.z[p->sIn.i]; if( c=='u' && p->sIn.i+4<p->sIn.mx ){ const unsigned char *zIn = p->sIn.z + p->sIn.i; if( re_hex(zIn[1],&v) && re_hex(zIn[2],&v) && re_hex(zIn[3],&v) && re_hex(zIn[4],&v) ){ p->sIn.i += 5; return v; } } if( c=='x' && p->sIn.i+2<p->sIn.mx ){ const unsigned char *zIn = p->sIn.z + p->sIn.i; if( re_hex(zIn[1],&v) && re_hex(zIn[2],&v) ){ p->sIn.i += 3; return v; } } for(i=0; zEsc[i] && zEsc[i]!=c; i++){} if( zEsc[i] ){ if( i<6 ) c = zTrans[i]; p->sIn.i++; }else{ p->zErr = "unknown \\ escape"; } return c; } /* Forward declaration */ static const char *re_subcompile_string(ReCompiled*); /* Peek at the next byte of input */ static unsigned char rePeek(ReCompiled *p){ return p->sIn.i<p->sIn.mx ? p->sIn.z[p->sIn.i] : 0; } /* Compile RE text into a sequence of opcodes. Continue up to the ** first unmatched ")" character, then return. If an error is found, ** return a pointer to the error message string. */ static const char *re_subcompile_re(ReCompiled *p){ const char *zErr; int iStart, iEnd, iGoto; iStart = p->nState; zErr = re_subcompile_string(p); if( zErr ) return zErr; while( rePeek(p)=='|' ){ iEnd = p->nState; re_insert(p, iStart, RE_OP_FORK, iEnd + 2 - iStart); iGoto = re_append(p, RE_OP_GOTO, 0); p->sIn.i++; zErr = re_subcompile_string(p); if( zErr ) return zErr; p->aArg[iGoto] = p->nState - iGoto; } return 0; } /* Compile an element of regular expression text (anything that can be ** an operand to the "|" operator). Return NULL on success or a pointer ** to the error message if there is a problem. */ static const char *re_subcompile_string(ReCompiled *p){ int iPrev = -1; int iStart; unsigned c; const char *zErr; while( (c = p->xNextChar(&p->sIn))!=0 ){ iStart = p->nState; switch( c ){ case '|': case '$': case ')': { p->sIn.i--; return 0; } case '(': { zErr = re_subcompile_re(p); if( zErr ) return zErr; if( rePeek(p)!=')' ) return "unmatched '('"; p->sIn.i++; break; } case '.': { if( rePeek(p)=='*' ){ re_append(p, RE_OP_ANYSTAR, 0); p->sIn.i++; }else{ re_append(p, RE_OP_ANY, 0); } break; } case '*': { if( iPrev<0 ) return "'*' without operand"; re_insert(p, iPrev, RE_OP_GOTO, p->nState - iPrev + 1); re_append(p, RE_OP_FORK, iPrev - p->nState + 1); break; } case '+': { if( iPrev<0 ) return "'+' without operand"; re_append(p, RE_OP_FORK, iPrev - p->nState); break; } case '?': { if( iPrev<0 ) return "'?' without operand"; re_insert(p, iPrev, RE_OP_FORK, p->nState - iPrev+1); break; } case '{': { int m = 0, n = 0; int sz, j; if( iPrev<0 ) return "'{m,n}' without operand"; while( (c=rePeek(p))>='0' && c<='9' ){ m = m*10 + c - '0'; p->sIn.i++; } n = m; if( c==',' ){ p->sIn.i++; n = 0; while( (c=rePeek(p))>='0' && c<='9' ){ n = n*10 + c-'0'; p->sIn.i++; } } if( c!='}' ) return "unmatched '{'"; if( n>0 && n<m ) return "n less than m in '{m,n}'"; p->sIn.i++; sz = p->nState - iPrev; if( m==0 ){ if( n==0 ) return "both m and n are zero in '{m,n}'"; re_insert(p, iPrev, RE_OP_FORK, sz+1); n--; }else{ for(j=1; j<m; j++) re_copy(p, iPrev, sz); } for(j=m; j<n; j++){ re_append(p, RE_OP_FORK, sz+1); re_copy(p, iPrev, sz); } if( n==0 && m>0 ){ re_append(p, RE_OP_FORK, -sz); } break; } case '[': { int iFirst = p->nState; if( rePeek(p)=='^' ){ re_append(p, RE_OP_CC_EXC, 0); p->sIn.i++; }else{ re_append(p, RE_OP_CC_INC, 0); } while( (c = p->xNextChar(&p->sIn))!=0 ){ if( c=='[' && rePeek(p)==':' ){ return "POSIX character classes not supported"; } if( c=='\\' ) c = re_esc_char(p); if( rePeek(p)=='-' ){ re_append(p, RE_OP_CC_RANGE, c); p->sIn.i++; c = p->xNextChar(&p->sIn); if( c=='\\' ) c = re_esc_char(p); re_append(p, RE_OP_CC_RANGE, c); }else{ re_append(p, RE_OP_CC_VALUE, c); } if( rePeek(p)==']' ){ p->sIn.i++; break; } } if( c==0 ) return "unclosed '['"; p->aArg[iFirst] = p->nState - iFirst; break; } case '\\': { int specialOp = 0; switch( rePeek(p) ){ case 'b': specialOp = RE_OP_BOUNDARY; break; case 'd': specialOp = RE_OP_DIGIT; break; case 'D': specialOp = RE_OP_NOTDIGIT; break; case 's': specialOp = RE_OP_SPACE; break; case 'S': specialOp = RE_OP_NOTSPACE; break; case 'w': specialOp = RE_OP_WORD; break; case 'W': specialOp = RE_OP_NOTWORD; break; } if( specialOp ){ p->sIn.i++; re_append(p, specialOp, 0); }else{ c = re_esc_char(p); re_append(p, RE_OP_MATCH, c); } break; } default: { re_append(p, RE_OP_MATCH, c); break; } } iPrev = iStart; } return 0; } /* Free and reclaim all the memory used by a previously compiled ** regular expression. Applications should invoke this routine once ** for every call to re_compile() to avoid memory leaks. */ void re_free(ReCompiled *pRe){ if( pRe ){ sqlite3_free(pRe->aOp); sqlite3_free(pRe->aArg); sqlite3_free(pRe); } } /* ** Compile a textual regular expression in zIn[] into a compiled regular ** expression suitable for us by re_match() and return a pointer to the ** compiled regular expression in *ppRe. Return NULL on success or an ** error message if something goes wrong. */ const char *re_compile(ReCompiled **ppRe, const char *zIn, int noCase){ ReCompiled *pRe; const char *zErr; int i, j; *ppRe = 0; pRe = sqlite3_malloc( sizeof(*pRe) ); if( pRe==0 ){ return "out of memory"; } memset(pRe, 0, sizeof(*pRe)); pRe->xNextChar = noCase ? re_next_char_nocase : re_next_char; if( re_resize(pRe, 30) ){ re_free(pRe); return "out of memory"; } if( zIn[0]=='^' ){ zIn++; }else{ re_append(pRe, RE_OP_ANYSTAR, 0); } pRe->sIn.z = (unsigned char*)zIn; pRe->sIn.i = 0; pRe->sIn.mx = strlen(zIn); zErr = re_subcompile_re(pRe); if( zErr ){ re_free(pRe); return zErr; } if( rePeek(pRe)=='$' && pRe->sIn.i+1>=pRe->sIn.mx ){ re_append(pRe, RE_OP_MATCH, RE_EOF); re_append(pRe, RE_OP_ACCEPT, 0); *ppRe = pRe; }else if( pRe->sIn.i>=pRe->sIn.mx ){ re_append(pRe, RE_OP_ACCEPT, 0); *ppRe = pRe; }else{ re_free(pRe); return "unrecognized character"; } /* The following is a performance optimization. If the regex begins with ** ".*" (if the input regex lacks an initial "^") and afterwards there are ** one or more matching characters, enter those matching characters into ** zInit[]. The re_match() routine can then search ahead in the input ** string looking for the initial match without having to run the whole ** regex engine over the string. Do not worry able trying to match ** unicode characters beyond plane 0 - those are very rare and this is ** just an optimization. */ if( pRe->aOp[0]==RE_OP_ANYSTAR ){ for(j=0, i=1; j<sizeof(pRe->zInit)-2 && pRe->aOp[i]==RE_OP_MATCH; i++){ unsigned x = pRe->aArg[i]; if( x<=127 ){ pRe->zInit[j++] = x; }else if( x<=0xfff ){ pRe->zInit[j++] = 0xc0 | (x>>6); pRe->zInit[j++] = 0x80 | (x&0x3f); }else if( x<=0xffff ){ pRe->zInit[j++] = 0xd0 | (x>>12); pRe->zInit[j++] = 0x80 | ((x>>6)&0x3f); pRe->zInit[j++] = 0x80 | (x&0x3f); }else{ break; } } if( j>0 && pRe->zInit[j-1]==0 ) j--; pRe->nInit = j; } return pRe->zErr; } /* ** Implementation of the regexp() SQL function. This function implements ** the build-in REGEXP operator. The first argument to the function is the ** pattern and the second argument is the string. So, the SQL statements: ** ** A REGEXP B ** ** is implemented as regexp(B,A). */ static void re_sql_func( sqlite3_context *context, int argc, sqlite3_value **argv ){ ReCompiled *pRe; /* Compiled regular expression */ const char *zPattern; /* The regular expression */ const unsigned char *zStr;/* String being searched */ const char *zErr; /* Compile error message */ pRe = sqlite3_get_auxdata(context, 0); if( pRe==0 ){ zPattern = (const char*)sqlite3_value_text(argv[0]); if( zPattern==0 ) return; zErr = re_compile(&pRe, zPattern, 0); if( zErr ){ re_free(pRe); sqlite3_result_error(context, zErr, -1); return; } if( pRe==0 ){ sqlite3_result_error_nomem(context); return; } sqlite3_set_auxdata(context, 0, pRe, (void(*)(void*))re_free); } zStr = (const unsigned char*)sqlite3_value_text(argv[1]); if( zStr!=0 ){ sqlite3_result_int(context, re_match(pRe, zStr, -1)); } } /* ** Invoke this routine in order to install the REGEXP function in an ** SQLite database connection. ** ** Use: ** ** sqlite3_auto_extension(sqlite3_add_regexp_func); ** ** to cause this extension to be automatically loaded into each new ** database connection. */ int sqlite3_add_regexp_func(sqlite3 *db){ return sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, 0, re_sql_func, 0, 0); } /***************************** Test Code ***********************************/ #ifdef SQLITE_TEST #include <tcl.h> extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); /* Implementation of the TCL command: ** ** sqlite3_add_regexp_func $DB */ static int tclSqlite3AddRegexpFunc( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; sqlite3_add_regexp_func(db); return TCL_OK; } /* Register the sqlite3_add_regexp_func TCL command with the TCL interpreter. */ int Sqlitetestregexp_Init(Tcl_Interp *interp){ Tcl_CreateObjCommand(interp, "sqlite3_add_regexp_func", tclSqlite3AddRegexpFunc, 0, 0); return TCL_OK; } #endif /* SQLITE_TEST */ /**************************** End Of Test Code *******************************/ |
Changes to src/test_spellfix.c.
︙ | ︙ | |||
17 18 19 20 21 22 23 24 25 26 27 28 29 30 | #if SQLITE_CORE # include "sqliteInt.h" #else # include <string.h> # include <stdio.h> # include <stdlib.h> # include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #endif /* !SQLITE_CORE */ #include <ctype.h> /* ** Character classes for ASCII characters: ** | > > > > > | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #if SQLITE_CORE # include "sqliteInt.h" #else # include <string.h> # include <stdio.h> # include <stdlib.h> # include "sqlite3ext.h" # include <assert.h> # define ALWAYS(X) 1 # define NEVER(X) 0 typedef unsigned char u8; typedef unsigned short u16; SQLITE_EXTENSION_INIT1 #endif /* !SQLITE_CORE */ #include <ctype.h> /* ** Character classes for ASCII characters: ** |
︙ | ︙ | |||
735 736 737 738 739 740 741 | } } if( len>N ) len = N; return len; } /* | | | | | | 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 | } } if( len>N ) len = N; return len; } /* ** Return TRUE (non-zero) if the To side of the given cost matches ** the given string. */ static int matchTo(EditDist3Cost *p, const char *z, int n){ if( p->nTo>n ) return 0; if( strncmp(p->a+p->nFrom, z, p->nTo)!=0 ) return 0; return 1; } /* ** Return TRUE (non-zero) if the From side of the given cost matches ** the given string. */ static int matchFrom(EditDist3Cost *p, const char *z, int n){ assert( p->nFrom<=n ); if( strncmp(p->a, z, p->nFrom)!=0 ) return 0; return 1; } /* ** Return TRUE (non-zero) of the next FROM character and the next TO ** character are the same. */ |
︙ | ︙ | |||
1943 1944 1945 1946 1947 1948 1949 | spellfix1DbExec(&rc, db, "CREATE INDEX IF NOT EXISTS \"%w\".\"%w_index_%llx\" " "ON \"%w_vocab\"(langid,k2);", zDbName, zModule, r, zTableName ); } for(i=3; rc==SQLITE_OK && i<argc; i++){ | | | 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 | spellfix1DbExec(&rc, db, "CREATE INDEX IF NOT EXISTS \"%w\".\"%w_index_%llx\" " "ON \"%w_vocab\"(langid,k2);", zDbName, zModule, r, zTableName ); } for(i=3; rc==SQLITE_OK && i<argc; i++){ if( strncmp(argv[i],"edit_cost_table=",16)==0 && pNew->zCostTable==0 ){ pNew->zCostTable = spellfix1Dequote(&argv[i][16]); if( pNew->zCostTable==0 ) rc = SQLITE_NOMEM; continue; } *pzErr = sqlite3_mprintf("bad argument to spellfix1(): \"%s\"", argv[i]); rc = SQLITE_ERROR; } |
︙ | ︙ | |||
2664 2665 2666 2667 2668 2669 2670 | ** cause zWord to be NULL, so we look at the "command" column to see ** what special actions to take */ const char *zCmd = (const char*)sqlite3_value_text(argv[SPELLFIX_COL_COMMAND+2]); if( zCmd==0 ){ pVTab->zErrMsg = sqlite3_mprintf("%s.word may not be NULL", p->zTableName); | | > > > > > > > > > > > > | 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 | ** cause zWord to be NULL, so we look at the "command" column to see ** what special actions to take */ const char *zCmd = (const char*)sqlite3_value_text(argv[SPELLFIX_COL_COMMAND+2]); if( zCmd==0 ){ pVTab->zErrMsg = sqlite3_mprintf("%s.word may not be NULL", p->zTableName); return SQLITE_CONSTRAINT_NOTNULL; } if( strcmp(zCmd,"reset")==0 ){ /* Reset the edit cost table (if there is one). */ editDist3ConfigDelete(p->pConfig3); p->pConfig3 = 0; return SQLITE_OK; } if( strncmp(zCmd,"edit_cost_table=",16)==0 ){ editDist3ConfigDelete(p->pConfig3); p->pConfig3 = 0; sqlite3_free(p->zCostTable); p->zCostTable = spellfix1Dequote(zCmd+16); if( p->zCostTable==0 ) return SQLITE_NOMEM; if( p->zCostTable[0]==0 || sqlite3_stricmp(p->zCostTable,"null")==0 ){ sqlite3_free(p->zCostTable); p->zCostTable = 0; } return SQLITE_OK; } pVTab->zErrMsg = sqlite3_mprintf("unknown value for %s.command: \"%w\"", p->zTableName, zCmd); return SQLITE_ERROR; } if( iRank<1 ) iRank = 1; if( zSoundslike ){ |
︙ | ︙ | |||
2805 2806 2807 2808 2809 2810 2811 | return rc; } #if SQLITE_CORE || defined(SQLITE_TEST) /* ** Register the spellfix1 virtual table and its associated functions. */ | | | | 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 | return rc; } #if SQLITE_CORE || defined(SQLITE_TEST) /* ** Register the spellfix1 virtual table and its associated functions. */ int sqlite3_spellfix1_register(sqlite3 *db){ return spellfix1Register(db); } #endif #if !SQLITE_CORE /* ** Extension load function. */ int sqlite3_spellfix1_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ SQLITE_EXTENSION_INIT2(pApi); return spellfix1Register(db); } #endif /* !SQLITE_CORE */ |
Changes to src/test_vfs.c.
︙ | ︙ | |||
261 262 263 264 265 266 267 | static void tvfsExecTcl( Testvfs *p, const char *zMethod, Tcl_Obj *arg1, Tcl_Obj *arg2, | | > > | | 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 | static void tvfsExecTcl( Testvfs *p, const char *zMethod, Tcl_Obj *arg1, Tcl_Obj *arg2, Tcl_Obj *arg3, Tcl_Obj *arg4 ){ int rc; /* Return code from Tcl_EvalObj() */ Tcl_Obj *pEval; assert( p->pScript ); assert( zMethod ); assert( p ); assert( arg2==0 || arg1!=0 ); assert( arg3==0 || arg2!=0 ); pEval = Tcl_DuplicateObj(p->pScript); Tcl_IncrRefCount(p->pScript); Tcl_ListObjAppendElement(p->interp, pEval, Tcl_NewStringObj(zMethod, -1)); if( arg1 ) Tcl_ListObjAppendElement(p->interp, pEval, arg1); if( arg2 ) Tcl_ListObjAppendElement(p->interp, pEval, arg2); if( arg3 ) Tcl_ListObjAppendElement(p->interp, pEval, arg3); if( arg4 ) Tcl_ListObjAppendElement(p->interp, pEval, arg4); rc = Tcl_EvalObjEx(p->interp, pEval, TCL_EVAL_GLOBAL); if( rc!=TCL_OK ){ Tcl_BackgroundError(p->interp); Tcl_ResetResult(p->interp); } } /* ** Close an tvfs-file. */ static int tvfsClose(sqlite3_file *pFile){ int rc; TestvfsFile *pTestfile = (TestvfsFile *)pFile; TestvfsFd *pFd = pTestfile->pFd; Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_CLOSE_MASK ){ tvfsExecTcl(p, "xClose", Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0, 0 ); } if( pFd->pShmId ){ Tcl_DecrRefCount(pFd->pShmId); pFd->pShmId = 0; } |
︙ | ︙ | |||
329 330 331 332 333 334 335 | sqlite_int64 iOfst ){ int rc = SQLITE_OK; TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_READ_MASK ){ tvfsExecTcl(p, "xRead", | | | 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 | sqlite_int64 iOfst ){ int rc = SQLITE_OK; TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_READ_MASK ){ tvfsExecTcl(p, "xRead", Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0, 0 ); tvfsResultCode(p, &rc); } if( rc==SQLITE_OK && p->mask&TESTVFS_READ_MASK && tvfsInjectIoerr(p) ){ rc = SQLITE_IOERR; } if( rc==SQLITE_OK ){ |
︙ | ︙ | |||
358 359 360 361 362 363 364 | int rc = SQLITE_OK; TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_WRITE_MASK ){ tvfsExecTcl(p, "xWrite", Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, | | | 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 | int rc = SQLITE_OK; TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_WRITE_MASK ){ tvfsExecTcl(p, "xWrite", Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, Tcl_NewWideIntObj(iOfst), Tcl_NewIntObj(iAmt) ); tvfsResultCode(p, &rc); } if( rc==SQLITE_OK && tvfsInjectFullerr(p) ){ rc = SQLITE_FULL; } |
︙ | ︙ | |||
386 387 388 389 390 391 392 | static int tvfsTruncate(sqlite3_file *pFile, sqlite_int64 size){ int rc = SQLITE_OK; TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_TRUNCATE_MASK ){ tvfsExecTcl(p, "xTruncate", | | | 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 | static int tvfsTruncate(sqlite3_file *pFile, sqlite_int64 size){ int rc = SQLITE_OK; TestvfsFd *pFd = tvfsGetFd(pFile); Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_TRUNCATE_MASK ){ tvfsExecTcl(p, "xTruncate", Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0, 0 ); tvfsResultCode(p, &rc); } if( rc==SQLITE_OK ){ rc = sqlite3OsTruncate(pFd->pReal, size); } |
︙ | ︙ | |||
427 428 429 430 431 432 433 | break; default: assert(0); } tvfsExecTcl(p, "xSync", Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, | | | 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 | break; default: assert(0); } tvfsExecTcl(p, "xSync", Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, Tcl_NewStringObj(zFlags, -1), 0 ); tvfsResultCode(p, &rc); } if( rc==SQLITE_OK && tvfsInjectFullerr(p) ) rc = SQLITE_FULL; if( rc==SQLITE_OK ){ |
︙ | ︙ | |||
574 575 576 577 578 579 580 | while( *z ){ Tcl_ListObjAppendElement(0, pArg, Tcl_NewStringObj(z, -1)); z += strlen(z) + 1; Tcl_ListObjAppendElement(0, pArg, Tcl_NewStringObj(z, -1)); z += strlen(z) + 1; } } | | | 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 | while( *z ){ Tcl_ListObjAppendElement(0, pArg, Tcl_NewStringObj(z, -1)); z += strlen(z) + 1; Tcl_ListObjAppendElement(0, pArg, Tcl_NewStringObj(z, -1)); z += strlen(z) + 1; } } tvfsExecTcl(p, "xOpen", Tcl_NewStringObj(pFd->zFilename, -1), pArg, 0, 0); Tcl_DecrRefCount(pArg); if( tvfsResultCode(p, &rc) ){ if( rc!=SQLITE_OK ) return rc; }else{ pId = Tcl_GetObjResult(p->interp); } } |
︙ | ︙ | |||
631 632 633 634 635 636 637 | */ static int tvfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ int rc = SQLITE_OK; Testvfs *p = (Testvfs *)pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_DELETE_MASK ){ tvfsExecTcl(p, "xDelete", | | | 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 | */ static int tvfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ int rc = SQLITE_OK; Testvfs *p = (Testvfs *)pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_DELETE_MASK ){ tvfsExecTcl(p, "xDelete", Tcl_NewStringObj(zPath, -1), Tcl_NewIntObj(dirSync), 0, 0 ); tvfsResultCode(p, &rc); } if( rc==SQLITE_OK ){ rc = sqlite3OsDelete(PARENTVFS(pVfs), zPath, dirSync); } return rc; |
︙ | ︙ | |||
659 660 661 662 663 664 665 | if( p->pScript && p->mask&TESTVFS_ACCESS_MASK ){ int rc; char *zArg = 0; if( flags==SQLITE_ACCESS_EXISTS ) zArg = "SQLITE_ACCESS_EXISTS"; if( flags==SQLITE_ACCESS_READWRITE ) zArg = "SQLITE_ACCESS_READWRITE"; if( flags==SQLITE_ACCESS_READ ) zArg = "SQLITE_ACCESS_READ"; tvfsExecTcl(p, "xAccess", | | | 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 | if( p->pScript && p->mask&TESTVFS_ACCESS_MASK ){ int rc; char *zArg = 0; if( flags==SQLITE_ACCESS_EXISTS ) zArg = "SQLITE_ACCESS_EXISTS"; if( flags==SQLITE_ACCESS_READWRITE ) zArg = "SQLITE_ACCESS_READWRITE"; if( flags==SQLITE_ACCESS_READ ) zArg = "SQLITE_ACCESS_READ"; tvfsExecTcl(p, "xAccess", Tcl_NewStringObj(zPath, -1), Tcl_NewStringObj(zArg, -1), 0, 0 ); if( tvfsResultCode(p, &rc) ){ if( rc!=SQLITE_OK ) return rc; }else{ Tcl_Interp *interp = p->interp; if( TCL_OK==Tcl_GetBooleanFromObj(0, Tcl_GetObjResult(interp), pResOut) ){ return SQLITE_OK; |
︙ | ︙ | |||
687 688 689 690 691 692 693 | const char *zPath, int nOut, char *zOut ){ Testvfs *p = (Testvfs *)pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_FULLPATHNAME_MASK ){ int rc; | | | 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 | const char *zPath, int nOut, char *zOut ){ Testvfs *p = (Testvfs *)pVfs->pAppData; if( p->pScript && p->mask&TESTVFS_FULLPATHNAME_MASK ){ int rc; tvfsExecTcl(p, "xFullPathname", Tcl_NewStringObj(zPath, -1), 0, 0, 0); if( tvfsResultCode(p, &rc) ){ if( rc!=SQLITE_OK ) return rc; } } return sqlite3OsFullPathname(PARENTVFS(pVfs), zPath, nOut, zOut); } |
︙ | ︙ | |||
767 768 769 770 771 772 773 | /* Evaluate the Tcl script: ** ** SCRIPT xShmOpen FILENAME */ Tcl_ResetResult(p->interp); if( p->pScript && p->mask&TESTVFS_SHMOPEN_MASK ){ | | | 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 | /* Evaluate the Tcl script: ** ** SCRIPT xShmOpen FILENAME */ Tcl_ResetResult(p->interp); if( p->pScript && p->mask&TESTVFS_SHMOPEN_MASK ){ tvfsExecTcl(p, "xShmOpen", Tcl_NewStringObj(pFd->zFilename, -1), 0, 0, 0); if( tvfsResultCode(p, &rc) ){ if( rc!=SQLITE_OK ) return rc; } } assert( rc==SQLITE_OK ); if( p->mask&TESTVFS_SHMOPEN_MASK && tvfsInjectIoerr(p) ){ |
︙ | ︙ | |||
837 838 839 840 841 842 843 | if( p->pScript && p->mask&TESTVFS_SHMMAP_MASK ){ Tcl_Obj *pArg = Tcl_NewObj(); Tcl_IncrRefCount(pArg); Tcl_ListObjAppendElement(p->interp, pArg, Tcl_NewIntObj(iPage)); Tcl_ListObjAppendElement(p->interp, pArg, Tcl_NewIntObj(pgsz)); Tcl_ListObjAppendElement(p->interp, pArg, Tcl_NewIntObj(isWrite)); tvfsExecTcl(p, "xShmMap", | | | 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 | if( p->pScript && p->mask&TESTVFS_SHMMAP_MASK ){ Tcl_Obj *pArg = Tcl_NewObj(); Tcl_IncrRefCount(pArg); Tcl_ListObjAppendElement(p->interp, pArg, Tcl_NewIntObj(iPage)); Tcl_ListObjAppendElement(p->interp, pArg, Tcl_NewIntObj(pgsz)); Tcl_ListObjAppendElement(p->interp, pArg, Tcl_NewIntObj(isWrite)); tvfsExecTcl(p, "xShmMap", Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, pArg, 0 ); tvfsResultCode(p, &rc); Tcl_DecrRefCount(pArg); } if( rc==SQLITE_OK && p->mask&TESTVFS_SHMMAP_MASK && tvfsInjectIoerr(p) ){ rc = SQLITE_IOERR; } |
︙ | ︙ | |||
887 888 889 890 891 892 893 | if( flags & SQLITE_SHM_SHARED ){ strcpy(&zLock[nLock], " shared"); }else{ strcpy(&zLock[nLock], " exclusive"); } tvfsExecTcl(p, "xShmLock", Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, | | | 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 | if( flags & SQLITE_SHM_SHARED ){ strcpy(&zLock[nLock], " shared"); }else{ strcpy(&zLock[nLock], " exclusive"); } tvfsExecTcl(p, "xShmLock", Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, Tcl_NewStringObj(zLock, -1), 0 ); tvfsResultCode(p, &rc); } if( rc==SQLITE_OK && p->mask&TESTVFS_SHMLOCK_MASK && tvfsInjectIoerr(p) ){ rc = SQLITE_IOERR; } |
︙ | ︙ | |||
933 934 935 936 937 938 939 | if( p->isFullshm ){ sqlite3OsShmBarrier(pFd->pReal); return; } if( p->pScript && p->mask&TESTVFS_SHMBARRIER_MASK ){ tvfsExecTcl(p, "xShmBarrier", | | | 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 | if( p->isFullshm ){ sqlite3OsShmBarrier(pFd->pReal); return; } if( p->pScript && p->mask&TESTVFS_SHMBARRIER_MASK ){ tvfsExecTcl(p, "xShmBarrier", Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0, 0 ); } } static int tvfsShmUnmap( sqlite3_file *pFile, int deleteFlag |
︙ | ︙ | |||
957 958 959 960 961 962 963 | } if( !pBuffer ) return SQLITE_OK; assert( pFd->pShmId && pFd->pShm ); if( p->pScript && p->mask&TESTVFS_SHMCLOSE_MASK ){ tvfsExecTcl(p, "xShmUnmap", | | | 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 | } if( !pBuffer ) return SQLITE_OK; assert( pFd->pShmId && pFd->pShm ); if( p->pScript && p->mask&TESTVFS_SHMCLOSE_MASK ){ tvfsExecTcl(p, "xShmUnmap", Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0, 0 ); tvfsResultCode(p, &rc); } for(ppFd=&pBuffer->pFile; *ppFd!=pFd; ppFd=&((*ppFd)->pNext)); assert( (*ppFd)==pFd ); *ppFd = pFd->pNext; |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
865 866 867 868 869 870 871 | sqlite3_log(pOp->p1, "constraint failed at %d in [%s]", pc, p->zSql); } rc = sqlite3VdbeHalt(p); assert( rc==SQLITE_BUSY || rc==SQLITE_OK || rc==SQLITE_ERROR ); if( rc==SQLITE_BUSY ){ p->rc = rc = SQLITE_BUSY; }else{ | | | 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 | sqlite3_log(pOp->p1, "constraint failed at %d in [%s]", pc, p->zSql); } 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&0xff)==SQLITE_CONSTRAINT ); assert( rc==SQLITE_OK || db->nDeferredCons>0 ); rc = p->rc ? SQLITE_ERROR : SQLITE_DONE; } goto vdbe_return; } /* Opcode: Integer P1 P2 * * * |
︙ | ︙ | |||
6059 6060 6061 6062 6063 6064 6065 | rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid); db->vtabOnConflict = vtabOnConflict; importVtabErrMsg(p, pVtab); if( rc==SQLITE_OK && pOp->p1 ){ assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) ); db->lastRowid = lastRowid = rowid; } | | | 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 | rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid); db->vtabOnConflict = vtabOnConflict; importVtabErrMsg(p, pVtab); if( rc==SQLITE_OK && pOp->p1 ){ assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) ); db->lastRowid = lastRowid = rowid; } if( (rc&0xff)==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){ if( pOp->p5==OE_Ignore ){ rc = SQLITE_OK; }else{ p->errorAction = ((pOp->p5==OE_Replace) ? OE_Abort : pOp->p5); } }else{ p->nChange++; |
︙ | ︙ |
Changes to src/vdbeInt.h.
︙ | ︙ | |||
119 120 121 122 123 124 125 | VdbeFrame *pParent; /* Parent of this frame, or NULL if parent is main */ Op *aOp; /* Program instructions for parent frame */ Mem *aMem; /* Array of memory cells for parent frame */ u8 *aOnceFlag; /* Array of OP_Once flags for parent frame */ VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */ void *token; /* Copy of SubProgram.token */ i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */ | | | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | VdbeFrame *pParent; /* Parent of this frame, or NULL if parent is main */ Op *aOp; /* Program instructions for parent frame */ Mem *aMem; /* Array of memory cells for parent frame */ u8 *aOnceFlag; /* Array of OP_Once flags for parent frame */ VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */ void *token; /* Copy of SubProgram.token */ i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */ int nCursor; /* Number of entries in apCsr */ int pc; /* Program Counter in parent (calling) frame */ int nOp; /* Size of aOp array */ int nMem; /* Number of entries in aMem */ int nOnceFlag; /* Number of entries in aOnceFlag */ int nChildMem; /* Number of memory cells for child frame */ int nChildCsr; /* Number of cursors for child frame */ int nChange; /* Statement changes (Vdbe.nChanges) */ |
︙ | ︙ | |||
305 306 307 308 309 310 311 | Mem *pResultSet; /* Pointer to an array of results */ int nMem; /* Number of memory locations currently allocated */ int nOp; /* Number of instructions in the program */ int nOpAlloc; /* Number of slots allocated for aOp[] */ int nLabel; /* Number of labels used */ int *aLabel; /* Space to hold the labels */ u16 nResColumn; /* Number of columns in one row of the result set */ | | | 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | Mem *pResultSet; /* Pointer to an array of results */ int nMem; /* Number of memory locations currently allocated */ int nOp; /* Number of instructions in the program */ int nOpAlloc; /* Number of slots allocated for aOp[] */ int nLabel; /* Number of labels used */ int *aLabel; /* Space to hold the labels */ u16 nResColumn; /* Number of columns in one row of the result set */ int nCursor; /* Number of slots in apCsr[] */ u32 magic; /* Magic number for sanity checking */ char *zErrMsg; /* Error message written here */ Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */ VdbeCursor **apCsr; /* One element of this array for each open cursor */ Mem *aVar; /* Values for the OP_Variable opcode. */ char **azVar; /* Name of variables */ ynVar nVar; /* Number of entries in aVar[] */ |
︙ | ︙ |
Changes to src/vdbeapi.c.
︙ | ︙ | |||
1194 1195 1196 1197 1198 1199 1200 | int i; if( p==0 ){ return 0; } if( zName ){ for(i=0; i<p->nzVar; i++){ const char *z = p->azVar[i]; | | | 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 | int i; if( p==0 ){ return 0; } if( zName ){ for(i=0; i<p->nzVar; i++){ const char *z = p->azVar[i]; if( z && strncmp(z,zName,nName)==0 && z[nName]==0 ){ return i+1; } } } return 0; } int sqlite3_bind_parameter_index(sqlite3_stmt *pStmt, const char *zName){ |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
13 14 15 16 17 18 19 | ** 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" | < < < < < < < < < < < < | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ** 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" /* ** Create a new virtual database engine. */ Vdbe *sqlite3VdbeCreate(sqlite3 *db){ Vdbe *p; p = sqlite3DbMallocZero(db, sizeof(Vdbe) ); if( p==0 ) return 0; |
︙ | ︙ | |||
154 155 156 157 158 159 160 | pOp->p1 = p1; pOp->p2 = p2; pOp->p3 = p3; pOp->p4.p = 0; pOp->p4type = P4_NOTUSED; #ifdef SQLITE_DEBUG pOp->zComment = 0; | > | > | 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | pOp->p1 = p1; pOp->p2 = p2; pOp->p3 = p3; pOp->p4.p = 0; pOp->p4type = P4_NOTUSED; #ifdef SQLITE_DEBUG pOp->zComment = 0; if( p->db->flags & SQLITE_VdbeAddopTrace ){ sqlite3VdbePrintOp(0, i, &p->aOp[i]); } #endif #ifdef VDBE_PROFILE pOp->cycles = 0; pOp->cnt = 0; #endif return i; } |
︙ | ︙ | |||
373 374 375 376 377 378 379 | 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) | | | 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 | 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&0xff)==SQLITE_CONSTRAINT && pOp->p2==OE_Abort)) ){ hasAbort = 1; break; } } sqlite3DbFree(v->db, sIter.apSub); |
︙ | ︙ | |||
508 509 510 511 512 513 514 | } pOut->p3 = pIn->p3; pOut->p4type = P4_NOTUSED; pOut->p4.p = 0; pOut->p5 = 0; #ifdef SQLITE_DEBUG pOut->zComment = 0; | | | 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 | } pOut->p3 = pIn->p3; pOut->p4type = P4_NOTUSED; pOut->p4.p = 0; pOut->p5 = 0; #ifdef SQLITE_DEBUG pOut->zComment = 0; if( p->db->flags & SQLITE_VdbeAddopTrace ){ sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]); } #endif } p->nOp += nOp; } return addr; |
︙ | ︙ | |||
1534 1535 1536 1537 1538 1539 1540 | if( nByte ){ p->pFree = sqlite3DbMallocZero(db, nByte); } zCsr = p->pFree; zEnd = &zCsr[nByte]; }while( nByte && !db->mallocFailed ); | | | 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 | if( nByte ){ p->pFree = sqlite3DbMallocZero(db, nByte); } zCsr = p->pFree; zEnd = &zCsr[nByte]; }while( nByte && !db->mallocFailed ); p->nCursor = nCursor; p->nOnceFlag = nOnce; if( p->aVar ){ p->nVar = (ynVar)nVar; for(n=0; n<nVar; n++){ p->aVar[n].flags = MEM_Null; p->aVar[n].db = db; } |
︙ | ︙ | |||
1776 1777 1778 1779 1780 1781 1782 | return rc; } /* If there are any write-transactions at all, invoke the commit hook */ if( needXcommit && db->xCommitCallback ){ rc = db->xCommitCallback(db->pCommitArg); if( rc ){ | | | 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 | return rc; } /* If there are any write-transactions at all, invoke the commit hook */ if( needXcommit && db->xCommitCallback ){ rc = db->xCommitCallback(db->pCommitArg); if( rc ){ return SQLITE_CONSTRAINT_COMMITHOOK; } } /* The simple case - no more than one database file (not counting the ** TEMP database) has a transaction active. There is no need for the ** master-journal. ** |
︙ | ︙ | |||
2068 2069 2070 2071 2072 2073 2074 | /* ** 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 | | | | | 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 | /* ** 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_FOREIGNKEY ** 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_FOREIGNKEY; p->errorAction = OE_Abort; sqlite3SetString(&p->zErrMsg, db, "foreign key constraint failed"); return SQLITE_ERROR; } return SQLITE_OK; } #endif |
︙ | ︙ | |||
2190 2191 2192 2193 2194 2195 2196 | if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){ rc = sqlite3VdbeCheckFk(p, 1); if( rc!=SQLITE_OK ){ if( NEVER(p->readOnly) ){ sqlite3VdbeLeave(p); return SQLITE_ERROR; } | | | 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 | if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){ rc = sqlite3VdbeCheckFk(p, 1); if( rc!=SQLITE_OK ){ if( NEVER(p->readOnly) ){ sqlite3VdbeLeave(p); return SQLITE_ERROR; } rc = SQLITE_CONSTRAINT_FOREIGNKEY; }else{ /* The auto-commit flag is true, the vdbe program was successful ** or hit an 'OR FAIL' constraint and there are no deferred foreign ** key constraints to hold up the transaction. This means a commit ** is required. */ rc = vdbeCommit(db, p); } |
︙ | ︙ | |||
2233 2234 2235 2236 2237 2238 2239 | ** do so. If this operation returns an error, and the current statement ** error code is SQLITE_OK or SQLITE_CONSTRAINT, then promote the ** current statement error code. */ if( eStatementOp ){ rc = sqlite3VdbeCloseStatement(p, eStatementOp); if( rc ){ | | | 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 | ** do so. If this operation returns an error, and the current statement ** error code is SQLITE_OK or SQLITE_CONSTRAINT, then promote the ** current statement error code. */ if( eStatementOp ){ rc = sqlite3VdbeCloseStatement(p, eStatementOp); if( rc ){ if( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT ){ p->rc = rc; sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = 0; } sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK); sqlite3CloseSavepoints(db); db->autoCommit = 1; |
︙ | ︙ | |||
2474 2475 2476 2477 2478 2479 2480 | for(i=p->nzVar-1; i>=0; i--) sqlite3DbFree(db, p->azVar[i]); vdbeFreeOpArray(db, p->aOp, p->nOp); sqlite3DbFree(db, p->aLabel); sqlite3DbFree(db, p->aColName); sqlite3DbFree(db, p->zSql); sqlite3DbFree(db, p->pFree); #if defined(SQLITE_ENABLE_TREE_EXPLAIN) | | | 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 | for(i=p->nzVar-1; i>=0; i--) sqlite3DbFree(db, p->azVar[i]); vdbeFreeOpArray(db, p->aOp, p->nOp); sqlite3DbFree(db, p->aLabel); sqlite3DbFree(db, p->aColName); sqlite3DbFree(db, p->zSql); sqlite3DbFree(db, p->pFree); #if defined(SQLITE_ENABLE_TREE_EXPLAIN) sqlite3DbFree(db, p->zExplain); sqlite3DbFree(db, p->pExplain); #endif } /* ** Delete an entire VDBE. */ |
︙ | ︙ |
Changes to src/vdbemem.c.
︙ | ︙ | |||
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | ** routine is a no-op. ** ** SQLITE_OK is returned if the conversion is successful (or not required). ** SQLITE_NOMEM may be returned if a malloc() fails during conversion ** between formats. */ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ int rc; assert( (pMem->flags&MEM_RowSet)==0 ); assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE || desiredEnc==SQLITE_UTF16BE ); if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){ return SQLITE_OK; } assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); | > > | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | ** routine is a no-op. ** ** SQLITE_OK is returned if the conversion is successful (or not required). ** SQLITE_NOMEM may be returned if a malloc() fails during conversion ** between formats. */ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ #ifndef SQLITE_OMIT_UTF16 int rc; #endif assert( (pMem->flags&MEM_RowSet)==0 ); assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE || desiredEnc==SQLITE_UTF16BE ); if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){ return SQLITE_OK; } assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
94 95 96 97 98 99 100 | typedef struct WhereTerm WhereTerm; struct WhereTerm { Expr *pExpr; /* Pointer to the subexpression that is this term */ int iParent; /* Disable pWC->a[iParent] when this term disabled */ int leftCursor; /* Cursor number of X in "X <op> <expr>" */ union { int leftColumn; /* Column number of X in "X <op> <expr>" */ | | | | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | typedef struct WhereTerm WhereTerm; struct WhereTerm { Expr *pExpr; /* Pointer to the subexpression that is this term */ int iParent; /* Disable pWC->a[iParent] when this term disabled */ int leftCursor; /* Cursor number of X in "X <op> <expr>" */ union { int leftColumn; /* Column number of X in "X <op> <expr>" */ WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */ WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */ } u; u16 eOperator; /* A WO_xx value describing <op> */ u8 wtFlags; /* TERM_xxx bit flags. See below */ u8 nChild; /* Number of children that must disable us */ WhereClause *pWC; /* The clause this term is part of */ Bitmask prereqRight; /* Bitmask of tables used by pExpr->pRight */ Bitmask prereqAll; /* Bitmask of tables referenced by pExpr */ |
︙ | ︙ | |||
136 137 138 139 140 141 142 | ** There are separate WhereClause objects for the whole clause and for ** the subclauses "(b AND c)" and "(d AND e)". The pOuter field of the ** subclauses points to the WhereClause object for the whole clause. */ struct WhereClause { Parse *pParse; /* The parser context */ WhereMaskSet *pMaskSet; /* Mapping of table cursor numbers to bitmasks */ | < | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | ** There are separate WhereClause objects for the whole clause and for ** the subclauses "(b AND c)" and "(d AND e)". The pOuter field of the ** subclauses points to the WhereClause object for the whole clause. */ struct WhereClause { Parse *pParse; /* The parser context */ WhereMaskSet *pMaskSet; /* Mapping of table cursor numbers to bitmasks */ WhereClause *pOuter; /* Outer conjunction */ u8 op; /* Split operator. TK_AND or TK_OR */ u16 wctrlFlags; /* Might include WHERE_AND_ONLY */ int nTerm; /* Number of terms */ int nSlot; /* Number of entries in a[] */ WhereTerm *a; /* Each a[] describes a term of the WHERE cluase */ #if defined(SQLITE_SMALL_STACK) |
︙ | ︙ | |||
223 224 225 226 227 228 229 230 231 232 233 234 235 236 | #define WO_LE (WO_EQ<<(TK_LE-TK_EQ)) #define WO_GT (WO_EQ<<(TK_GT-TK_EQ)) #define WO_GE (WO_EQ<<(TK_GE-TK_EQ)) #define WO_MATCH 0x040 #define WO_ISNULL 0x080 #define WO_OR 0x100 /* Two or more OR-connected terms */ #define WO_AND 0x200 /* Two or more AND-connected terms */ #define WO_NOOP 0x800 /* This term does not restrict search space */ #define WO_ALL 0xfff /* Mask of all possible WO_* values */ #define WO_SINGLE 0x0ff /* Mask of all non-compound WO_* values */ /* ** Value for wsFlags returned by bestIndex() and stored in | > | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | #define WO_LE (WO_EQ<<(TK_LE-TK_EQ)) #define WO_GT (WO_EQ<<(TK_GT-TK_EQ)) #define WO_GE (WO_EQ<<(TK_GE-TK_EQ)) #define WO_MATCH 0x040 #define WO_ISNULL 0x080 #define WO_OR 0x100 /* Two or more OR-connected terms */ #define WO_AND 0x200 /* Two or more AND-connected terms */ #define WO_EQUIV 0x400 /* Of the form A==B, both columns */ #define WO_NOOP 0x800 /* This term does not restrict search space */ #define WO_ALL 0xfff /* Mask of all possible WO_* values */ #define WO_SINGLE 0x0ff /* Mask of all non-compound WO_* values */ /* ** Value for wsFlags returned by bestIndex() and stored in |
︙ | ︙ | |||
249 250 251 252 253 254 255 | #define WHERE_ROWID_RANGE 0x00002000 /* rowid<EXPR and/or rowid>EXPR */ #define WHERE_COLUMN_EQ 0x00010000 /* x=EXPR or x IN (...) or x IS NULL */ #define WHERE_COLUMN_RANGE 0x00020000 /* x<EXPR and/or x>EXPR */ #define WHERE_COLUMN_IN 0x00040000 /* x IN (...) */ #define WHERE_COLUMN_NULL 0x00080000 /* x IS NULL */ #define WHERE_INDEXED 0x000f0000 /* Anything that uses an index */ #define WHERE_NOT_FULLSCAN 0x100f3000 /* Does not do a full table scan */ | | | 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 | #define WHERE_ROWID_RANGE 0x00002000 /* rowid<EXPR and/or rowid>EXPR */ #define WHERE_COLUMN_EQ 0x00010000 /* x=EXPR or x IN (...) or x IS NULL */ #define WHERE_COLUMN_RANGE 0x00020000 /* x<EXPR and/or x>EXPR */ #define WHERE_COLUMN_IN 0x00040000 /* x IN (...) */ #define WHERE_COLUMN_NULL 0x00080000 /* x IS NULL */ #define WHERE_INDEXED 0x000f0000 /* Anything that uses an index */ #define WHERE_NOT_FULLSCAN 0x100f3000 /* Does not do a full table scan */ #define WHERE_IN_ABLE 0x080f1000 /* Able to support an IN operator */ #define WHERE_TOP_LIMIT 0x00100000 /* x<EXPR or x<=EXPR constraint */ #define WHERE_BTM_LIMIT 0x00200000 /* x>EXPR or x>=EXPR constraint */ #define WHERE_BOTH_LIMIT 0x00300000 /* Both x>EXPR and x<EXPR */ #define WHERE_IDX_ONLY 0x00400000 /* Use index only - omit table */ #define WHERE_ORDERED 0x00800000 /* Output will appear in correct order */ #define WHERE_REVERSE 0x01000000 /* Scan in reverse order */ #define WHERE_UNIQUE 0x02000000 /* Selects no more than one row */ |
︙ | ︙ | |||
312 313 314 315 316 317 318 | ){ pWC->pParse = pParse; pWC->pMaskSet = pMaskSet; pWC->pOuter = 0; pWC->nTerm = 0; pWC->nSlot = ArraySize(pWC->aStatic); pWC->a = pWC->aStatic; | < | 312 313 314 315 316 317 318 319 320 321 322 323 324 325 | ){ pWC->pParse = pParse; pWC->pMaskSet = pMaskSet; pWC->pOuter = 0; pWC->nTerm = 0; pWC->nSlot = ArraySize(pWC->aStatic); pWC->a = pWC->aStatic; pWC->wctrlFlags = wctrlFlags; } /* Forward reference */ static void whereClauseClear(WhereClause*); /* |
︙ | ︙ | |||
399 400 401 402 403 404 405 | memcpy(pWC->a, pOld, sizeof(pWC->a[0])*pWC->nTerm); if( pOld!=pWC->aStatic ){ sqlite3DbFree(db, pOld); } pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]); } pTerm = &pWC->a[idx = pWC->nTerm++]; | | | 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 | memcpy(pWC->a, pOld, sizeof(pWC->a[0])*pWC->nTerm); if( pOld!=pWC->aStatic ){ sqlite3DbFree(db, pOld); } pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]); } pTerm = &pWC->a[idx = pWC->nTerm++]; pTerm->pExpr = sqlite3ExprSkipCollate(p); pTerm->wtFlags = wtFlags; pTerm->pWC = pWC; pTerm->iParent = -1; return idx; } /* |
︙ | ︙ | |||
625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 | } /* ** Search for a term in the WHERE clause that is of the form "X <op> <expr>" ** where X is a reference to the iColumn of table iCur and <op> is one of ** the WO_xx operator codes specified by the op parameter. ** Return a pointer to the term. Return 0 if not found. */ static WhereTerm *findTerm( WhereClause *pWC, /* The WHERE clause to be searched */ int iCur, /* Cursor number of LHS */ int iColumn, /* Column number of LHS */ Bitmask notReady, /* RHS must not overlap with this mask */ u32 op, /* Mask of WO_xx values describing operator */ Index *pIdx /* Must be compatible with this index, if not NULL */ ){ | > > > > > > > > > > > > > > > > > | > > > > > > > > > | | > > | | | < | > > | | | < | | | > | < | | > > | | | | | | | | | | | | | > | > > | > > > | | > > > > > > > | > > > > > > > > > > > > > > | | 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 | } /* ** Search for a term in the WHERE clause that is of the form "X <op> <expr>" ** where X is a reference to the iColumn of table iCur and <op> is one of ** the WO_xx operator codes specified by the op parameter. ** Return a pointer to the term. Return 0 if not found. ** ** The term returned might by Y=<expr> if there is another constraint in ** the WHERE clause that specifies that X=Y. Any such constraints will be ** identified by the WO_EQUIV bit in the pTerm->eOperator field. The ** aEquiv[] array holds X and all its equivalents, with each SQL variable ** taking up two slots in aEquiv[]. The first slot is for the cursor number ** and the second is for the column number. There are 22 slots in aEquiv[] ** so that means we can look for X plus up to 10 other equivalent values. ** Hence a search for X will return <expr> if X=A1 and A1=A2 and A2=A3 ** and ... and A9=A10 and A10=<expr>. ** ** If there are multiple terms in the WHERE clause of the form "X <op> <expr>" ** then try for the one with no dependencies on <expr> - in other words where ** <expr> is a constant expression of some kind. Only return entries of ** the form "X <op> Y" where Y is a column in another table if no terms of ** the form "X <op> <const-expr>" exist. If no terms with a constant RHS ** exist, try to return a term that does not use WO_EQUIV. */ static WhereTerm *findTerm( WhereClause *pWC, /* The WHERE clause to be searched */ int iCur, /* Cursor number of LHS */ int iColumn, /* Column number of LHS */ Bitmask notReady, /* RHS must not overlap with this mask */ u32 op, /* Mask of WO_xx values describing operator */ Index *pIdx /* Must be compatible with this index, if not NULL */ ){ WhereTerm *pTerm; /* Term being examined as possible result */ WhereTerm *pResult = 0; /* The answer to return */ WhereClause *pWCOrig = pWC; /* Original pWC value */ int j, k; /* Loop counters */ Expr *pX; /* Pointer to an expression */ Parse *pParse; /* Parsing context */ int iOrigCol = iColumn; /* Original value of iColumn */ int nEquiv = 2; /* Number of entires in aEquiv[] */ int iEquiv = 2; /* Number of entries of aEquiv[] processed so far */ int aEquiv[22]; /* iCur,iColumn and up to 10 other equivalents */ assert( iCur>=0 ); aEquiv[0] = iCur; aEquiv[1] = iColumn; for(;;){ for(pWC=pWCOrig; pWC; pWC=pWC->pOuter){ for(pTerm=pWC->a, k=pWC->nTerm; k; k--, pTerm++){ if( pTerm->leftCursor==iCur && pTerm->u.leftColumn==iColumn ){ if( (pTerm->prereqRight & notReady)==0 && (pTerm->eOperator & op & WO_ALL)!=0 ){ if( iOrigCol>=0 && pIdx && (pTerm->eOperator & WO_ISNULL)==0 ){ CollSeq *pColl; char idxaff; pX = pTerm->pExpr; pParse = pWC->pParse; idxaff = pIdx->pTable->aCol[iOrigCol].affinity; if( !sqlite3IndexAffinityOk(pX, idxaff) ){ continue; } /* Figure out the collation sequence required from an index for ** it to be useful for optimising expression pX. Store this ** value in variable pColl. */ assert(pX->pLeft); pColl = sqlite3BinaryCompareCollSeq(pParse,pX->pLeft,pX->pRight); if( pColl==0 ) pColl = pParse->db->pDfltColl; for(j=0; pIdx->aiColumn[j]!=iOrigCol; j++){ if( NEVER(j>=pIdx->nColumn) ) return 0; } if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ){ continue; } } if( pTerm->prereqRight==0 ){ pResult = pTerm; goto findTerm_success; }else if( pResult==0 ){ pResult = pTerm; } } if( (pTerm->eOperator & WO_EQUIV)!=0 && nEquiv<ArraySize(aEquiv) ){ pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight); assert( pX->op==TK_COLUMN ); for(j=0; j<nEquiv; j+=2){ if( aEquiv[j]==pX->iTable && aEquiv[j+1]==pX->iColumn ) break; } if( j==nEquiv ){ aEquiv[j] = pX->iTable; aEquiv[j+1] = pX->iColumn; nEquiv += 2; } } } } } if( iEquiv>=nEquiv ) break; iCur = aEquiv[iEquiv++]; iColumn = aEquiv[iEquiv++]; } findTerm_success: return pResult; } /* Forward reference */ static void exprAnalyze(SrcList*, WhereClause*, int); /* ** Call exprAnalyze on all terms in a WHERE clause. |
︙ | ︙ | |||
858 859 860 861 862 863 864 | ** (B) x=expr1 OR expr2=x OR x=expr3 ** (C) t1.x=t2.y OR (t1.x=t2.z AND t1.y=15) ** (D) x=expr1 OR (y>11 AND y<22 AND z LIKE '*hello*') ** (E) (p.a=1 AND q.b=2 AND r.c=3) OR (p.x=4 AND q.y=5 AND r.z=6) ** ** CASE 1: ** | | | 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 | ** (B) x=expr1 OR expr2=x OR x=expr3 ** (C) t1.x=t2.y OR (t1.x=t2.z AND t1.y=15) ** (D) x=expr1 OR (y>11 AND y<22 AND z LIKE '*hello*') ** (E) (p.a=1 AND q.b=2 AND r.c=3) OR (p.x=4 AND q.y=5 AND r.z=6) ** ** CASE 1: ** ** If all subterms are of the form T.C=expr for some single column of C and ** a single table T (as shown in example B above) then create a new virtual ** term that is an equivalent IN expression. In other words, if the term ** being analyzed is: ** ** x = expr1 OR expr2 = x OR x = expr3 ** ** then create a new virtual term like this: |
︙ | ︙ | |||
946 947 948 949 950 951 952 | if( db->mallocFailed ) return; assert( pOrWc->nTerm>=2 ); /* ** Compute the set of tables that might satisfy cases 1 or 2. */ indexable = ~(Bitmask)0; | | < | 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 | if( db->mallocFailed ) return; assert( pOrWc->nTerm>=2 ); /* ** Compute the set of tables that might satisfy cases 1 or 2. */ indexable = ~(Bitmask)0; chngToIN = ~(Bitmask)0; for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0 && indexable; i--, pOrTerm++){ if( (pOrTerm->eOperator & WO_SINGLE)==0 ){ WhereAndInfo *pAndInfo; assert( (pOrTerm->wtFlags & (TERM_ANDINFO|TERM_ORINFO))==0 ); chngToIN = 0; pAndInfo = sqlite3DbMallocRaw(db, sizeof(*pAndInfo)); if( pAndInfo ){ WhereClause *pAndWC; WhereTerm *pAndTerm; int j; |
︙ | ︙ | |||
989 990 991 992 993 994 995 | Bitmask b; b = getMask(pMaskSet, pOrTerm->leftCursor); if( pOrTerm->wtFlags & TERM_VIRTUAL ){ WhereTerm *pOther = &pOrWc->a[pOrTerm->iParent]; b |= getMask(pMaskSet, pOther->leftCursor); } indexable &= b; | | | 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 | Bitmask b; b = getMask(pMaskSet, pOrTerm->leftCursor); if( pOrTerm->wtFlags & TERM_VIRTUAL ){ WhereTerm *pOther = &pOrWc->a[pOrTerm->iParent]; b |= getMask(pMaskSet, pOther->leftCursor); } indexable &= b; if( (pOrTerm->eOperator & WO_EQ)==0 ){ chngToIN = 0; }else{ chngToIN &= b; } } } |
︙ | ︙ | |||
1040 1041 1042 1043 1044 1045 1046 | ** will be recorded in iCursor and iColumn. There might not be any ** such table and column. Set okToChngToIN if an appropriate table ** and column is found but leave okToChngToIN false if not found. */ for(j=0; j<2 && !okToChngToIN; j++){ pOrTerm = pOrWc->a; for(i=pOrWc->nTerm-1; i>=0; i--, pOrTerm++){ | | | 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 | ** will be recorded in iCursor and iColumn. There might not be any ** such table and column. Set okToChngToIN if an appropriate table ** and column is found but leave okToChngToIN false if not found. */ for(j=0; j<2 && !okToChngToIN; j++){ pOrTerm = pOrWc->a; for(i=pOrWc->nTerm-1; i>=0; i--, pOrTerm++){ assert( pOrTerm->eOperator & WO_EQ ); pOrTerm->wtFlags &= ~TERM_OR_OK; if( pOrTerm->leftCursor==iCursor ){ /* This is the 2-bit case and we are on the second iteration and ** current term is from the first iteration. So skip this term. */ assert( j==1 ); continue; } |
︙ | ︙ | |||
1066 1067 1068 1069 1070 1071 1072 | iCursor = pOrTerm->leftCursor; break; } if( i<0 ){ /* No candidate table+column was found. This can only occur ** on the second iteration */ assert( j==1 ); | | | | 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 | iCursor = pOrTerm->leftCursor; break; } if( i<0 ){ /* No candidate table+column was found. This can only occur ** on the second iteration */ assert( j==1 ); assert( IsPowerOfTwo(chngToIN) ); assert( chngToIN==getMask(pMaskSet, iCursor) ); break; } testcase( j==1 ); /* We have found a candidate table and column. Check to see if that ** table and column is common to every term in the OR clause */ okToChngToIN = 1; for(; i>=0 && okToChngToIN; i--, pOrTerm++){ assert( pOrTerm->eOperator & WO_EQ ); if( pOrTerm->leftCursor!=iCursor ){ pOrTerm->wtFlags &= ~TERM_OR_OK; }else if( pOrTerm->u.leftColumn!=iColumn ){ okToChngToIN = 0; }else{ int affLeft, affRight; /* If the right-hand side is also a column, then the affinities |
︙ | ︙ | |||
1112 1113 1114 1115 1116 1117 1118 | Expr *pDup; /* A transient duplicate expression */ ExprList *pList = 0; /* The RHS of the IN operator */ Expr *pLeft = 0; /* The LHS of the IN operator */ Expr *pNew; /* The complete IN operator */ for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0; i--, pOrTerm++){ if( (pOrTerm->wtFlags & TERM_OR_OK)==0 ) continue; | | | 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 | Expr *pDup; /* A transient duplicate expression */ ExprList *pList = 0; /* The RHS of the IN operator */ Expr *pLeft = 0; /* The LHS of the IN operator */ Expr *pNew; /* The complete IN operator */ for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0; i--, pOrTerm++){ if( (pOrTerm->wtFlags & TERM_OR_OK)==0 ) continue; assert( pOrTerm->eOperator & WO_EQ ); assert( pOrTerm->leftCursor==iCursor ); assert( pOrTerm->u.leftColumn==iColumn ); pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0); pList = sqlite3ExprListAppend(pWC->pParse, pList, pDup); pLeft = pOrTerm->pExpr->pLeft; } assert( pLeft!=0 ); |
︙ | ︙ | |||
1141 1142 1143 1144 1145 1146 1147 | sqlite3ExprListDelete(db, pList); } pTerm->eOperator = WO_NOOP; /* case 1 trumps case 2 */ } } } #endif /* !SQLITE_OMIT_OR_OPTIMIZATION && !SQLITE_OMIT_SUBQUERY */ | < | 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 | sqlite3ExprListDelete(db, pList); } pTerm->eOperator = WO_NOOP; /* case 1 trumps case 2 */ } } } #endif /* !SQLITE_OMIT_OR_OPTIMIZATION && !SQLITE_OMIT_SUBQUERY */ /* ** The input to this routine is an WhereTerm structure with only the ** "pExpr" field filled in. The job of this routine is to analyze the ** subexpression and populate all the other fields of the WhereTerm ** structure. ** |
︙ | ︙ | |||
1184 1185 1186 1187 1188 1189 1190 | sqlite3 *db = pParse->db; /* Database connection */ if( db->mallocFailed ){ return; } pTerm = &pWC->a[idxTerm]; pMaskSet = pWC->pMaskSet; | | > | 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 | sqlite3 *db = pParse->db; /* Database connection */ if( db->mallocFailed ){ return; } pTerm = &pWC->a[idxTerm]; pMaskSet = pWC->pMaskSet; pExpr = pTerm->pExpr; assert( pExpr->op!=TK_AS && pExpr->op!=TK_COLLATE ); prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft); op = pExpr->op; if( op==TK_IN ){ assert( pExpr->pRight==0 ); if( ExprHasProperty(pExpr, EP_xIsSelect) ){ pTerm->prereqRight = exprSelectTableUsage(pMaskSet, pExpr->x.pSelect); }else{ |
︙ | ︙ | |||
1210 1211 1212 1213 1214 1215 1216 | extraRight = x-1; /* ON clause terms may not be used with an index ** on left table of a LEFT JOIN. Ticket #3015 */ } pTerm->prereqAll = prereqAll; pTerm->leftCursor = -1; pTerm->iParent = -1; pTerm->eOperator = 0; | | > | > > > > > > > > | | 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 | extraRight = x-1; /* ON clause terms may not be used with an index ** on left table of a LEFT JOIN. Ticket #3015 */ } pTerm->prereqAll = prereqAll; pTerm->leftCursor = -1; pTerm->iParent = -1; pTerm->eOperator = 0; if( allowedOp(op) ){ Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft); Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight); u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV; if( pLeft->op==TK_COLUMN ){ pTerm->leftCursor = pLeft->iTable; pTerm->u.leftColumn = pLeft->iColumn; pTerm->eOperator = operatorMask(op) & opMask; } if( pRight && pRight->op==TK_COLUMN ){ WhereTerm *pNew; Expr *pDup; u16 eExtraOp = 0; /* Extra bits for pNew->eOperator */ if( pTerm->leftCursor>=0 ){ int idxNew; pDup = sqlite3ExprDup(db, pExpr, 0); if( db->mallocFailed ){ sqlite3ExprDelete(db, pDup); return; } idxNew = whereClauseInsert(pWC, pDup, TERM_VIRTUAL|TERM_DYNAMIC); if( idxNew==0 ) return; pNew = &pWC->a[idxNew]; pNew->iParent = idxTerm; pTerm = &pWC->a[idxTerm]; pTerm->nChild = 1; pTerm->wtFlags |= TERM_COPIED; if( pExpr->op==TK_EQ && !ExprHasProperty(pExpr, EP_FromJoin) && OptimizationEnabled(db, SQLITE_Transitive) ){ pTerm->eOperator |= WO_EQUIV; eExtraOp = WO_EQUIV; } }else{ pDup = pExpr; pNew = pTerm; } exprCommute(pParse, pDup); pLeft = sqlite3ExprSkipCollate(pDup->pLeft); pNew->leftCursor = pLeft->iTable; pNew->u.leftColumn = pLeft->iColumn; testcase( (prereqLeft | extraRight) != prereqLeft ); pNew->prereqRight = prereqLeft | extraRight; pNew->prereqAll = prereqAll; pNew->eOperator = (operatorMask(pDup->op) + eExtraOp) & opMask; } } #ifndef SQLITE_OMIT_BETWEEN_OPTIMIZATION /* If a term is the BETWEEN operator, create two new virtual terms ** that define the range that the BETWEEN implements. For example: ** |
︙ | ︙ | |||
1705 1706 1707 1708 1709 1710 1711 | } if( pWC->wctrlFlags & WHERE_AND_ONLY ){ return; } /* Search the WHERE clause terms for a usable WO_OR term. */ for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){ | | | | 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 | } if( pWC->wctrlFlags & WHERE_AND_ONLY ){ return; } /* Search the WHERE clause terms for a usable WO_OR term. */ for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){ if( (pTerm->eOperator & WO_OR)!=0 && ((pTerm->prereqAll & ~maskSrc) & p->notReady)==0 && (pTerm->u.pOrInfo->indexable & maskSrc)!=0 ){ 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; WhereBestIdx sBOI; sBOI = *p; sBOI.pOrderBy = 0; sBOI.pDistinct = 0; sBOI.ppIdxInfo = 0; for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){ WHERETRACE(("... Multi-index OR testing for term %d of %d....\n", (pOrTerm - pOrWC->a), (pTerm - pWC->a) )); if( (pOrTerm->eOperator& WO_AND)!=0 ){ sBOI.pWC = &pOrTerm->u.pAndInfo->wc; bestIndex(&sBOI); }else if( pOrTerm->leftCursor==iCur ){ WhereClause tempWC; tempWC.pParse = pWC->pParse; tempWC.pMaskSet = pWC->pMaskSet; tempWC.pOuter = pWC; |
︙ | ︙ | |||
1787 1788 1789 1790 1791 1792 1793 | static int termCanDriveIndex( WhereTerm *pTerm, /* WHERE clause term to check */ struct SrcList_item *pSrc, /* Table we are trying to access */ Bitmask notReady /* Tables in outer loops of the join */ ){ char aff; if( pTerm->leftCursor!=pSrc->iCursor ) return 0; | | | 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 | static int termCanDriveIndex( WhereTerm *pTerm, /* WHERE clause term to check */ struct SrcList_item *pSrc, /* Table we are trying to access */ Bitmask notReady /* Tables in outer loops of the join */ ){ char aff; if( pTerm->leftCursor!=pSrc->iCursor ) return 0; if( (pTerm->eOperator & WO_EQ)==0 ) return 0; if( (pTerm->prereqRight & notReady)!=0 ) return 0; aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity; if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0; return 1; } #endif |
︙ | ︙ | |||
2049 2050 2051 2052 2053 2054 2055 | WHERETRACE(("Recomputing index info for %s...\n", pSrc->pTab->zName)); /* Count the number of possible WHERE clause constraints referring ** to this virtual table */ for(i=nTerm=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){ if( pTerm->leftCursor != pSrc->iCursor ) continue; | | | | | | 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 | WHERETRACE(("Recomputing index info for %s...\n", pSrc->pTab->zName)); /* Count the number of possible WHERE clause constraints referring ** to this virtual table */ for(i=nTerm=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){ if( pTerm->leftCursor != pSrc->iCursor ) continue; assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) ); testcase( pTerm->eOperator & WO_IN ); testcase( pTerm->eOperator & WO_ISNULL ); if( pTerm->eOperator & (WO_ISNULL) ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; nTerm++; } /* If the ORDER BY clause contains only columns in the current ** virtual table then allocate space for the aOrderBy part of ** the sqlite3_index_info structure. |
︙ | ︙ | |||
2100 2101 2102 2103 2104 2105 2106 2107 | *(int*)&pIdxInfo->nOrderBy = nOrderBy; *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint = pIdxCons; *(struct sqlite3_index_orderby**)&pIdxInfo->aOrderBy = pIdxOrderBy; *(struct sqlite3_index_constraint_usage**)&pIdxInfo->aConstraintUsage = pUsage; for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){ if( pTerm->leftCursor != pSrc->iCursor ) continue; | > | | | | > > | | | 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 | *(int*)&pIdxInfo->nOrderBy = nOrderBy; *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint = pIdxCons; *(struct sqlite3_index_orderby**)&pIdxInfo->aOrderBy = pIdxOrderBy; *(struct sqlite3_index_constraint_usage**)&pIdxInfo->aConstraintUsage = pUsage; for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){ u8 op; if( pTerm->leftCursor != pSrc->iCursor ) continue; assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) ); testcase( pTerm->eOperator & WO_IN ); testcase( pTerm->eOperator & WO_ISNULL ); if( pTerm->eOperator & (WO_ISNULL) ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; pIdxCons[j].iColumn = pTerm->u.leftColumn; pIdxCons[j].iTermOffset = i; op = (u8)pTerm->eOperator & WO_ALL; if( op==WO_IN ) op = WO_EQ; pIdxCons[j].op = op; /* The direct assignment in the previous line is possible only because ** the WO_ and SQLITE_INDEX_CONSTRAINT_ codes are identical. The ** following asserts verify this fact. */ assert( WO_EQ==SQLITE_INDEX_CONSTRAINT_EQ ); assert( WO_LT==SQLITE_INDEX_CONSTRAINT_LT ); assert( WO_LE==SQLITE_INDEX_CONSTRAINT_LE ); assert( WO_GT==SQLITE_INDEX_CONSTRAINT_GT ); assert( WO_GE==SQLITE_INDEX_CONSTRAINT_GE ); assert( WO_MATCH==SQLITE_INDEX_CONSTRAINT_MATCH ); assert( pTerm->eOperator & (WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_MATCH) ); j++; } for(i=0; i<nOrderBy; i++){ Expr *pExpr = pOrderBy->a[i].pExpr; pIdxOrderBy[i].iColumn = pExpr->iColumn; pIdxOrderBy[i].desc = pOrderBy->a[i].sortOrder; } |
︙ | ︙ | |||
2202 2203 2204 2205 2206 2207 2208 | WhereClause *pWC = p->pWC; /* The WHERE clause */ struct SrcList_item *pSrc = p->pSrc; /* The FROM clause term to search */ Table *pTab = pSrc->pTab; sqlite3_index_info *pIdxInfo; struct sqlite3_index_constraint *pIdxCons; struct sqlite3_index_constraint_usage *pUsage; WhereTerm *pTerm; | | > > | 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 | WhereClause *pWC = p->pWC; /* The WHERE clause */ struct SrcList_item *pSrc = p->pSrc; /* The FROM clause term to search */ Table *pTab = pSrc->pTab; sqlite3_index_info *pIdxInfo; struct sqlite3_index_constraint *pIdxCons; struct sqlite3_index_constraint_usage *pUsage; WhereTerm *pTerm; int i, j, k; int nOrderBy; int sortOrder; /* Sort order for IN clauses */ int bAllowIN; /* Allow IN optimizations */ double rCost; /* Make sure wsFlags is initialized to some sane value. Otherwise, if the ** malloc in allocateIndexInfo() fails and this function returns leaving ** wsFlags in an uninitialized state, the caller may behave unpredictably. */ memset(&p->cost, 0, sizeof(p->cost)); |
︙ | ︙ | |||
2238 2239 2240 2241 2242 2243 2244 | /* 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) ); | > > | > | < | < < < < < < < < < | < < < < < > > > > > > > > > > > > > > > > > > > > > > > | | | | | > > > | > > > | | | | | | | | | | | | | | | | | | | | > | | | > > | > > > > > > > | > > > > | | > > > > > > | 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 | /* 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) ); /* Try once or twice. On the first attempt, allow IN optimizations. ** If an IN optimization is accepted by the virtual table xBestIndex ** method, but the pInfo->aConstrainUsage.omit flag is not set, then ** the query will not work because it might allow duplicate rows in ** output. In that case, run the xBestIndex method a second time ** without the IN constraints. Usually this loop only runs once. ** The loop will exit using a "break" statement. */ for(bAllowIN=1; 1; bAllowIN--){ assert( bAllowIN==0 || bAllowIN==1 ); /* 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: ** ** column = expr ** ** and we are evaluating a join, then the constraint on column is ** only valid if all tables referenced in expr occur to the left ** of the table containing column. ** ** The aConstraints[] array contains entries for all constraints ** on the current table. That way we only have to compute it once ** even though we might try to pick the best index multiple times. ** For each attempt at picking an index, the order of tables in the ** join might be different so we have to recompute the usable flag ** 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]; if( (pTerm->prereqRight&p->notReady)==0 && (bAllowIN || (pTerm->eOperator & WO_IN)==0) ){ pIdxCons->usable = 1; }else{ pIdxCons->usable = 0; } } 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( !p->pOrderBy ){ pIdxInfo->nOrderBy = 0; } if( vtabBestIndex(pParse, pTab, pIdxInfo) ){ return; } sortOrder = SQLITE_SO_ASC; pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint; for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){ if( pUsage[i].argvIndex>0 ){ j = pIdxCons->iTermOffset; pTerm = &pWC->a[j]; p->cost.used |= pTerm->prereqRight; if( (pTerm->eOperator & WO_IN)!=0 ){ if( pUsage[i].omit==0 ){ /* Do not attempt to use an IN constraint if the virtual table ** says that the equivalent EQ constraint cannot be safely omitted. ** If we do attempt to use such a constraint, some rows might be ** repeated in the output. */ break; } for(k=0; k<pIdxInfo->nOrderBy; k++){ if( pIdxInfo->aOrderBy[k].iColumn==pIdxCons->iColumn ){ sortOrder = pIdxInfo->aOrderBy[k].desc; break; } } } } } if( i>=pIdxInfo->nConstraint ) break; } /* If there is an ORDER BY clause, and the selected virtual table index ** does not satisfy it, increase the cost of the scan accordingly. This ** matches the processing for non-virtual tables in bestBtreeIndex(). */ rCost = pIdxInfo->estimatedCost; if( p->pOrderBy && pIdxInfo->orderByConsumed==0 ){ rCost += estLog(rCost)*rCost; |
︙ | ︙ | |||
2314 2315 2316 2317 2318 2319 2320 | if( (SQLITE_BIG_DBL/((double)2))<rCost ){ p->cost.rCost = (SQLITE_BIG_DBL/((double)2)); }else{ p->cost.rCost = rCost; } p->cost.plan.u.pVtabIdx = pIdxInfo; if( pIdxInfo->orderByConsumed ){ | > | | 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 | if( (SQLITE_BIG_DBL/((double)2))<rCost ){ p->cost.rCost = (SQLITE_BIG_DBL/((double)2)); }else{ p->cost.rCost = rCost; } p->cost.plan.u.pVtabIdx = pIdxInfo; if( pIdxInfo->orderByConsumed ){ assert( sortOrder==0 || sortOrder==1 ); p->cost.plan.wsFlags |= WHERE_ORDERED + sortOrder*WHERE_REVERSE; p->cost.plan.nOBSat = nOrderBy; }else{ p->cost.plan.nOBSat = p->i ? p->aLevel[p->i-1].plan.nOBSat : 0; } p->cost.plan.nEq = 0; pIdxInfo->nOrderBy = nOrderBy; |
︙ | ︙ | |||
2585 2586 2587 2588 2589 2590 2591 | tRowcnt iUpper = p->aiRowEst[0]; tRowcnt a[2]; u8 aff = p->pTable->aCol[p->aiColumn[0]].affinity; if( pLower ){ Expr *pExpr = pLower->pExpr->pRight; rc = valueFromExpr(pParse, pExpr, aff, &pRangeVal); | | | | | | 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 | tRowcnt iUpper = p->aiRowEst[0]; tRowcnt a[2]; u8 aff = p->pTable->aCol[p->aiColumn[0]].affinity; if( pLower ){ Expr *pExpr = pLower->pExpr->pRight; rc = valueFromExpr(pParse, pExpr, aff, &pRangeVal); assert( (pLower->eOperator & (WO_GT|WO_GE))!=0 ); if( rc==SQLITE_OK && whereKeyStats(pParse, p, pRangeVal, 0, a)==SQLITE_OK ){ iLower = a[0]; if( (pLower->eOperator & WO_GT)!=0 ) iLower += a[1]; } sqlite3ValueFree(pRangeVal); } if( rc==SQLITE_OK && pUpper ){ Expr *pExpr = pUpper->pExpr->pRight; rc = valueFromExpr(pParse, pExpr, aff, &pRangeVal); assert( (pUpper->eOperator & (WO_LT|WO_LE))!=0 ); if( rc==SQLITE_OK && whereKeyStats(pParse, p, pRangeVal, 1, a)==SQLITE_OK ){ iUpper = a[0]; if( (pUpper->eOperator & WO_LE)!=0 ) iUpper += a[1]; } sqlite3ValueFree(pRangeVal); } if( rc==SQLITE_OK ){ if( iUpper<=iLower ){ *pRangeDiv = (double)p->aiRowEst[0]; }else{ |
︙ | ︙ | |||
2910 2911 2912 2913 2914 2915 2916 | /* If X is the column in the index and ORDER BY clause, check to see ** if there are any X= or X IS NULL constraints in the WHERE clause. */ pConstraint = findTerm(p->pWC, base, iColumn, p->notReady, WO_EQ|WO_ISNULL|WO_IN, pIdx); if( pConstraint==0 ){ isEq = 0; | | | < < < | | 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 | /* If X is the column in the index and ORDER BY clause, check to see ** if there are any X= or X IS NULL constraints in the WHERE clause. */ pConstraint = findTerm(p->pWC, base, iColumn, p->notReady, WO_EQ|WO_ISNULL|WO_IN, pIdx); if( pConstraint==0 ){ isEq = 0; }else if( (pConstraint->eOperator & WO_IN)!=0 ){ isEq = 0; }else if( (pConstraint->eOperator & WO_ISNULL)!=0 ){ uniqueNotNull = 0; isEq = 1; /* "X IS NULL" means X has only a single value */ }else if( pConstraint->prereqRight==0 ){ isEq = 1; /* Constraint "X=constant" means X has only a single value */ }else{ Expr *pRight = pConstraint->pExpr->pRight; if( pRight->op==TK_COLUMN ){ |
︙ | ︙ | |||
3218 3219 3220 3221 3222 3223 3224 | /* If the index being considered is UNIQUE, and there is an equality ** constraint for all columns in the index, then this search will find ** at most a single row. In this case set the WHERE_UNIQUE flag to ** indicate this to the caller. ** ** Otherwise, if the search may find more than one row, test to see if | | | | 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 | /* If the index being considered is UNIQUE, and there is an equality ** constraint for all columns in the index, then this search will find ** at most a single row. In this case set the WHERE_UNIQUE flag to ** indicate this to the caller. ** ** Otherwise, if the search may find more than one row, test to see if ** there is a range constraint on indexed column (pc.plan.nEq+1) that ** can be optimized using the index. */ if( pc.plan.nEq==pProbe->nColumn && pProbe->onError!=OE_None ){ testcase( pc.plan.wsFlags & WHERE_COLUMN_IN ); testcase( pc.plan.wsFlags & WHERE_COLUMN_NULL ); if( (pc.plan.wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_NULL))==0 ){ pc.plan.wsFlags |= WHERE_UNIQUE; if( p->i==0 || (p->aLevel[p->i-1].plan.wsFlags & WHERE_ALL_UNIQUE)!=0 ){ |
︙ | ︙ | |||
3265 3266 3267 3268 3269 3270 3271 | ** variable. */ if( bSort && (pSrc->jointype & JT_LEFT)==0 ){ int bRev = 2; WHERETRACE((" --> before isSortingIndex: nPriorSat=%d\n",nPriorSat)); pc.plan.nOBSat = isSortingIndex(p, pProbe, iCur, &bRev); WHERETRACE((" --> after isSortingIndex: bRev=%d nOBSat=%d\n", bRev, pc.plan.nOBSat)); | | | 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 | ** variable. */ if( bSort && (pSrc->jointype & JT_LEFT)==0 ){ int bRev = 2; WHERETRACE((" --> before isSortingIndex: nPriorSat=%d\n",nPriorSat)); pc.plan.nOBSat = isSortingIndex(p, pProbe, iCur, &bRev); WHERETRACE((" --> after isSortingIndex: bRev=%d nOBSat=%d\n", bRev, pc.plan.nOBSat)); if( nPriorSat<pc.plan.nOBSat || (pc.plan.wsFlags & WHERE_ALL_UNIQUE)!=0 ){ pc.plan.wsFlags |= WHERE_ORDERED; } if( nOrderBy==pc.plan.nOBSat ){ bSort = 0; pc.plan.wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE; } if( bRev & 1 ) pc.plan.wsFlags |= WHERE_REVERSE; |
︙ | ︙ | |||
3328 3329 3330 3331 3332 3333 3334 | ** to get a better estimate on the number of rows based on ** VALUE and how common that value is according to the histogram. */ if( pc.plan.nRow>(double)1 && pc.plan.nEq==1 && pFirstTerm!=0 && aiRowEst[1]>1 ){ assert( (pFirstTerm->eOperator & (WO_EQ|WO_ISNULL|WO_IN))!=0 ); if( pFirstTerm->eOperator & (WO_EQ|WO_ISNULL) ){ | | | > | | 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 | ** to get a better estimate on the number of rows based on ** VALUE and how common that value is according to the histogram. */ if( pc.plan.nRow>(double)1 && pc.plan.nEq==1 && pFirstTerm!=0 && aiRowEst[1]>1 ){ assert( (pFirstTerm->eOperator & (WO_EQ|WO_ISNULL|WO_IN))!=0 ); if( pFirstTerm->eOperator & (WO_EQ|WO_ISNULL) ){ testcase( pFirstTerm->eOperator & WO_EQ ); testcase( pFirstTerm->eOperator & WO_EQUIV ); testcase( pFirstTerm->eOperator & WO_ISNULL ); whereEqualScanEst(pParse, pProbe, pFirstTerm->pExpr->pRight, &pc.plan.nRow); }else if( bInEst==0 ){ assert( pFirstTerm->eOperator & WO_IN ); whereInScanEst(pParse, pProbe, pFirstTerm->pExpr->x.pList, &pc.plan.nRow); } } #endif /* SQLITE_ENABLE_STAT3 */ /* Adjust the number of output rows and downward to reflect rows |
︙ | ︙ | |||
3480 3481 3482 3483 3484 3485 3486 | ** set size by a factor of 3. Indexed range constraints reduce ** the search space by a larger factor: 4. We make indexed range ** more selective intentionally because of the subjective ** observation that indexed range constraints really are more ** selective in practice, on average. */ pc.plan.nRow /= 3; } | | | 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 | ** set size by a factor of 3. Indexed range constraints reduce ** the search space by a larger factor: 4. We make indexed range ** more selective intentionally because of the subjective ** observation that indexed range constraints really are more ** selective in practice, on average. */ pc.plan.nRow /= 3; } }else if( (pTerm->eOperator & WO_NOOP)==0 ){ /* Any other expression lowers the output row count by half */ pc.plan.nRow /= 2; } } if( pc.plan.nRow<2 ) pc.plan.nRow = 2; } |
︙ | ︙ | |||
3532 3533 3534 3535 3536 3537 3538 | assert( p->pOrderBy || (p->cost.plan.wsFlags&WHERE_ORDERED)==0 ); assert( p->cost.plan.u.pIdx==0 || (p->cost.plan.wsFlags&WHERE_ROWID_EQ)==0 ); assert( pSrc->pIndex==0 || p->cost.plan.u.pIdx==0 || p->cost.plan.u.pIdx==pSrc->pIndex ); | | | > | 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 | assert( p->pOrderBy || (p->cost.plan.wsFlags&WHERE_ORDERED)==0 ); assert( p->cost.plan.u.pIdx==0 || (p->cost.plan.wsFlags&WHERE_ROWID_EQ)==0 ); assert( pSrc->pIndex==0 || p->cost.plan.u.pIdx==0 || p->cost.plan.u.pIdx==pSrc->pIndex ); WHERETRACE((" best index is %s cost=%.1f\n", p->cost.plan.u.pIdx ? p->cost.plan.u.pIdx->zName : "ipk", p->cost.rCost)); bestOrClauseIndex(p); bestAutomaticIndex(p); p->cost.plan.wsFlags |= eqTermMask; } /* |
︙ | ︙ | |||
3558 3559 3560 3561 3562 3563 3564 | */ static void bestIndex(WhereBestIdx *p){ #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(p->pSrc->pTab) ){ sqlite3_index_info *pIdxInfo = 0; p->ppIdxInfo = &pIdxInfo; bestVirtualIndex(p); | > | | 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 | */ static void bestIndex(WhereBestIdx *p){ #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(p->pSrc->pTab) ){ sqlite3_index_info *pIdxInfo = 0; p->ppIdxInfo = &pIdxInfo; bestVirtualIndex(p); assert( pIdxInfo!=0 || p->pParse->db->mallocFailed ); if( pIdxInfo && pIdxInfo->needToFreeIdxStr ){ sqlite3_free(pIdxInfo->idxStr); } sqlite3DbFree(p->pParse->db, pIdxInfo); }else #endif { bestBtreeIndex(p); |
︙ | ︙ | |||
3664 3665 3666 3667 3668 3669 3670 | ** For a constraint of the form X=expr, the expression is evaluated and its ** result is left on the stack. For constraints of the form X IN (...) ** this routine sets up a loop that will iterate over all values of X. */ static int codeEqualityTerm( Parse *pParse, /* The parsing context */ WhereTerm *pTerm, /* The term of the WHERE clause to be coded */ | | > > > > > > > > > > > > > > > | > | 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 | ** For a constraint of the form X=expr, the expression is evaluated and its ** result is left on the stack. For constraints of the form X IN (...) ** this routine sets up a loop that will iterate over all values of X. */ static int codeEqualityTerm( Parse *pParse, /* The parsing context */ WhereTerm *pTerm, /* The term of the WHERE clause to be coded */ WhereLevel *pLevel, /* The level of the FROM clause we are working on */ int iEq, /* Index of the equality term within this level */ int iTarget /* Attempt to leave results in this register */ ){ Expr *pX = pTerm->pExpr; Vdbe *v = pParse->pVdbe; int iReg; /* Register holding results */ assert( iTarget>0 ); if( pX->op==TK_EQ ){ iReg = sqlite3ExprCodeTarget(pParse, pX->pRight, iTarget); }else if( pX->op==TK_ISNULL ){ iReg = iTarget; sqlite3VdbeAddOp2(v, OP_Null, 0, iReg); #ifndef SQLITE_OMIT_SUBQUERY }else{ int eType; int iTab; struct InLoop *pIn; u8 bRev = (pLevel->plan.wsFlags & WHERE_REVERSE)!=0; if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 && pLevel->plan.u.pIdx->aSortOrder[iEq] ){ testcase( iEq==0 ); testcase( iEq==pLevel->plan.u.pIdx->nColumn-1 ); testcase( iEq>0 && iEq+1<pLevel->plan.u.pIdx->nColumn ); testcase( bRev ); bRev = !bRev; } assert( pX->op==TK_IN ); iReg = iTarget; eType = sqlite3FindInIndex(pParse, pX, 0); if( eType==IN_INDEX_INDEX_DESC ){ testcase( bRev ); bRev = !bRev; } iTab = pX->iTable; sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0); assert( pLevel->plan.wsFlags & WHERE_IN_ABLE ); if( pLevel->u.in.nIn==0 ){ pLevel->addrNxt = sqlite3VdbeMakeLabel(v); } pLevel->u.in.nIn++; pLevel->u.in.aInLoop = sqlite3DbReallocOrFree(pParse->db, pLevel->u.in.aInLoop, sizeof(pLevel->u.in.aInLoop[0])*pLevel->u.in.nIn); pIn = pLevel->u.in.aInLoop; if( pIn ){ pIn += pLevel->u.in.nIn - 1; pIn->iCur = iTab; if( eType==IN_INDEX_ROWID ){ pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iReg); }else{ pIn->addrInTop = sqlite3VdbeAddOp3(v, OP_Column, iTab, 0, iReg); } pIn->eEndLoopOp = bRev ? OP_Prev : OP_Next; sqlite3VdbeAddOp1(v, OP_IsNull, iReg); }else{ pLevel->u.in.nIn = 0; } #endif } disableTerm(pLevel, pTerm); |
︙ | ︙ | |||
3799 3800 3801 3802 3803 3804 3805 | int k = pIdx->aiColumn[j]; pTerm = findTerm(pWC, iCur, k, notReady, pLevel->plan.wsFlags, pIdx); if( pTerm==0 ) break; /* The following true for indices with redundant columns. ** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */ testcase( (pTerm->wtFlags & TERM_CODED)!=0 ); testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */ | | | 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 | int k = pIdx->aiColumn[j]; pTerm = findTerm(pWC, iCur, k, notReady, pLevel->plan.wsFlags, pIdx); if( pTerm==0 ) break; /* The following true for indices with redundant columns. ** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */ testcase( (pTerm->wtFlags & TERM_CODED)!=0 ); testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */ r1 = codeEqualityTerm(pParse, pTerm, pLevel, j, regBase+j); if( r1!=regBase+j ){ if( nReg==1 ){ sqlite3ReleaseTempReg(pParse, regBase); regBase = r1; }else{ sqlite3VdbeAddOp2(v, OP_SCopy, r1, regBase+j); } |
︙ | ︙ | |||
4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 | #ifndef SQLITE_OMIT_VIRTUALTABLE if( (pLevel->plan.wsFlags & WHERE_VIRTUALTABLE)!=0 ){ /* Case 0: The table is a virtual-table. Use the VFilter and VNext ** to access the data. */ int iReg; /* P3 Value for OP_VFilter */ sqlite3_index_info *pVtabIdx = pLevel->plan.u.pVtabIdx; int nConstraint = pVtabIdx->nConstraint; struct sqlite3_index_constraint_usage *aUsage = pVtabIdx->aConstraintUsage; const struct sqlite3_index_constraint *aConstraint = pVtabIdx->aConstraint; sqlite3ExprCachePush(pParse); iReg = sqlite3GetTempRange(pParse, nConstraint+2); for(j=1; j<=nConstraint; j++){ for(k=0; k<nConstraint; k++){ if( aUsage[k].argvIndex==j ){ | > > > | > > > > | > | | 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 | #ifndef SQLITE_OMIT_VIRTUALTABLE if( (pLevel->plan.wsFlags & WHERE_VIRTUALTABLE)!=0 ){ /* Case 0: The table is a virtual-table. Use the VFilter and VNext ** to access the data. */ int iReg; /* P3 Value for OP_VFilter */ int addrNotFound; sqlite3_index_info *pVtabIdx = pLevel->plan.u.pVtabIdx; int nConstraint = pVtabIdx->nConstraint; struct sqlite3_index_constraint_usage *aUsage = pVtabIdx->aConstraintUsage; const struct sqlite3_index_constraint *aConstraint = pVtabIdx->aConstraint; sqlite3ExprCachePush(pParse); iReg = sqlite3GetTempRange(pParse, nConstraint+2); addrNotFound = pLevel->addrBrk; for(j=1; j<=nConstraint; j++){ for(k=0; k<nConstraint; k++){ if( aUsage[k].argvIndex==j ){ int iTarget = iReg+j+1; pTerm = &pWC->a[aConstraint[k].iTermOffset]; if( pTerm->eOperator & WO_IN ){ codeEqualityTerm(pParse, pTerm, pLevel, k, iTarget); addrNotFound = pLevel->addrNxt; }else{ sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget); } break; } } if( k==nConstraint ) break; } sqlite3VdbeAddOp2(v, OP_Integer, pVtabIdx->idxNum, iReg); sqlite3VdbeAddOp2(v, OP_Integer, j-1, iReg+1); sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg, pVtabIdx->idxStr, pVtabIdx->needToFreeIdxStr ? P4_MPRINTF : P4_STATIC); pVtabIdx->needToFreeIdxStr = 0; for(j=0; j<nConstraint; j++){ if( aUsage[j].omit ){ int iTerm = aConstraint[j].iTermOffset; disableTerm(pLevel, &pWC->a[iTerm]); } |
︙ | ︙ | |||
4107 4108 4109 4110 4111 4112 4113 | ** we reference multiple rows using a "rowid IN (...)" ** construct. */ iReleaseReg = sqlite3GetTempReg(pParse); pTerm = findTerm(pWC, iCur, -1, notReady, WO_EQ|WO_IN, 0); assert( pTerm!=0 ); assert( pTerm->pExpr!=0 ); | < | > | 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 | ** we reference multiple rows using a "rowid IN (...)" ** construct. */ iReleaseReg = sqlite3GetTempReg(pParse); pTerm = findTerm(pWC, iCur, -1, notReady, WO_EQ|WO_IN, 0); assert( pTerm!=0 ); assert( pTerm->pExpr!=0 ); assert( omitTable==0 ); testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */ iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, iReleaseReg); addrNxt = pLevel->addrNxt; sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt); sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg); sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1); sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); VdbeComment((v, "pk")); pLevel->op = OP_Noop; }else if( pLevel->plan.wsFlags & WHERE_ROWID_RANGE ){ /* Case 2: We have an inequality comparison against the ROWID field. */ int testOp = OP_Noop; |
︙ | ︙ | |||
4498 4499 4500 4501 4502 4503 4504 | int iRetInit; /* Address of regReturn init */ int untestedTerms = 0; /* Some terms not completely tested */ int ii; /* Loop counter */ Expr *pAndExpr = 0; /* An ".. AND (...)" expression */ pTerm = pLevel->plan.u.pTerm; assert( pTerm!=0 ); | | | 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 | int iRetInit; /* Address of regReturn init */ int untestedTerms = 0; /* Some terms not completely tested */ int ii; /* Loop counter */ Expr *pAndExpr = 0; /* An ".. AND (...)" expression */ pTerm = pLevel->plan.u.pTerm; assert( pTerm!=0 ); assert( pTerm->eOperator & WO_OR ); assert( (pTerm->wtFlags & TERM_ORINFO)!=0 ); pOrWc = &pTerm->u.pOrInfo->wc; pLevel->op = OP_Return; pLevel->p1 = regReturn; /* Set up a new SrcList in pOrTab containing the table being scanned ** by this loop in the a[0] slot and all notReady tables in a[1..] slots. |
︙ | ︙ | |||
4571 4572 4573 4574 4575 4576 4577 | if( pAndExpr ){ pAndExpr = sqlite3PExpr(pParse, TK_AND, 0, pAndExpr, 0); } } for(ii=0; ii<pOrWc->nTerm; ii++){ WhereTerm *pOrTerm = &pOrWc->a[ii]; | | | 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 | if( pAndExpr ){ pAndExpr = sqlite3PExpr(pParse, TK_AND, 0, pAndExpr, 0); } } for(ii=0; ii<pOrWc->nTerm; ii++){ WhereTerm *pOrTerm = &pOrWc->a[ii]; if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){ WhereInfo *pSubWInfo; /* Info for single OR-term scan */ Expr *pOrExpr = pOrTerm->pExpr; if( pAndExpr ){ pAndExpr->pLeft = pOrExpr; pOrExpr = pAndExpr; } /* Loop through table entries that match term pOrTerm. */ |
︙ | ︙ | |||
4949 4950 4951 4952 4953 4954 4955 | ** the bitmask for all FROM clause terms to the left of the N-th term ** is (X-1). An expression from the ON clause of a LEFT JOIN can use ** its Expr.iRightJoinTable value to find the bitmask of the right table ** of the join. Subtracting one from the right table bitmask gives a ** bitmask for all tables to the left of the join. Knowing the bitmask ** for all tables to the left of a left join is important. Ticket #3015. ** | < < < < < < < < < < < | 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 | ** the bitmask for all FROM clause terms to the left of the N-th term ** is (X-1). An expression from the ON clause of a LEFT JOIN can use ** its Expr.iRightJoinTable value to find the bitmask of the right table ** of the join. Subtracting one from the right table bitmask gives a ** bitmask for all tables to the left of the join. Knowing the bitmask ** for all tables to the left of a left join is important. Ticket #3015. ** ** Note that bitmasks are created for all pTabList->nSrc tables in ** pTabList, not just the first nTabList tables. nTabList is normally ** equal to pTabList->nSrc but might be shortened to 1 if the ** WHERE_ONETABLE_ONLY flag is set. */ for(ii=0; ii<pTabList->nSrc; ii++){ createMask(pMaskSet, pTabList->a[ii].iCursor); } #ifndef NDEBUG { Bitmask toTheLeft = 0; for(ii=0; ii<pTabList->nSrc; ii++){ Bitmask m = getMask(pMaskSet, pTabList->a[ii].iCursor); assert( (m-1)==toTheLeft ); |
︙ | ︙ | |||
5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 | for(sWBI.i=iFrom=0, pLevel=pWInfo->a; sWBI.i<nTabList; sWBI.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 */ int nUnconstrained; /* Number tables without INDEXED BY */ Bitmask notIndexed; /* Mask of tables that cannot use an index */ memset(&bestPlan, 0, sizeof(bestPlan)); bestPlan.rCost = SQLITE_BIG_DBL; WHERETRACE(("*** Begin search for loop %d ***\n", sWBI.i)); | > | 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 | for(sWBI.i=iFrom=0, pLevel=pWInfo->a; sWBI.i<nTabList; sWBI.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 */ int ckOptimal; /* Do the optimal scan check */ int nUnconstrained; /* Number tables without INDEXED BY */ Bitmask notIndexed; /* Mask of tables that cannot use an index */ memset(&bestPlan, 0, sizeof(bestPlan)); bestPlan.rCost = SQLITE_BIG_DBL; WHERETRACE(("*** Begin search for loop %d ***\n", sWBI.i)); |
︙ | ︙ | |||
5060 5061 5062 5063 5064 5065 5066 | ** that do not use indices. But this nRow reduction only happens if the ** table really is the innermost join. ** ** The second loop iteration is only performed if no optimal scan ** strategies were found by the first iteration. This second iteration ** is used to search for the lowest cost scan overall. ** | | < < | | > > > > > > < < < < > > > > > > > > > > > > > > > > > > > > > > | 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 | ** that do not use indices. But this nRow reduction only happens if the ** table really is the innermost join. ** ** The second loop iteration is only performed if no optimal scan ** strategies were found by the first iteration. This second iteration ** is used to search for the lowest cost scan overall. ** ** Without the optimal scan step (the first iteration) a suboptimal ** plan might be chosen for queries like this: ** ** 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. ** 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. */ nUnconstrained = 0; notIndexed = 0; /* The optimal scan check only occurs if there are two or more tables ** available to be reordered */ if( iFrom==nTabList-1 ){ ckOptimal = 0; /* Common case of just one table in the FROM clause */ }else{ ckOptimal = -1; for(j=iFrom, sWBI.pSrc=&pTabList->a[j]; j<nTabList; j++, sWBI.pSrc++){ m = getMask(pMaskSet, sWBI.pSrc->iCursor); if( (m & sWBI.notValid)==0 ){ if( j==iFrom ) iFrom++; continue; } if( j>iFrom && (sWBI.pSrc->jointype & (JT_LEFT|JT_CROSS))!=0 ) break; if( ++ckOptimal ) break; if( (sWBI.pSrc->jointype & JT_LEFT)!=0 ) break; } } assert( ckOptimal==0 || ckOptimal==1 ); for(isOptimal=ckOptimal; isOptimal>=0 && bestJ<0; isOptimal--){ for(j=iFrom, sWBI.pSrc=&pTabList->a[j]; j<nTabList; j++, sWBI.pSrc++){ if( j>iFrom && (sWBI.pSrc->jointype & (JT_LEFT|JT_CROSS))!=0 ){ /* This break and one like it in the ckOptimal computation loop ** above prevent table reordering across LEFT and CROSS JOINs. ** The LEFT JOIN case is necessary for correctness. The prohibition ** against reordering across a CROSS JOIN is an SQLite feature that ** allows the developer to control table reordering */ break; } m = getMask(pMaskSet, sWBI.pSrc->iCursor); if( (m & sWBI.notValid)==0 ){ assert( j>iFrom ); continue; } sWBI.notReady = (isOptimal ? m : sWBI.notValid); if( sWBI.pSrc->pIndex==0 ) nUnconstrained++; WHERETRACE((" === trying table %d (%s) with isOptimal=%d ===\n", j, sWBI.pSrc->pTab->zName, isOptimal)); assert( sWBI.pSrc->pTab ); |
︙ | ︙ | |||
5117 5118 5119 5120 5121 5122 5123 | || sWBI.cost.plan.u.pIdx==sWBI.pSrc->pIndex ); if( isOptimal && (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ){ notIndexed |= m; } if( isOptimal ){ pWInfo->a[j].rOptCost = sWBI.cost.rCost; | | | | 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 | || sWBI.cost.plan.u.pIdx==sWBI.pSrc->pIndex ); if( isOptimal && (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ){ notIndexed |= m; } if( isOptimal ){ pWInfo->a[j].rOptCost = sWBI.cost.rCost; }else if( ckOptimal ){ /* If two or more tables have nearly the same outer loop cost, but ** very different inner loop (optimal) cost, we want to choose ** for the outer loop that table which benefits the least from ** being in the inner loop. The following code scales the ** outer loop cost estimate to accomplish that. */ WHERETRACE((" scaling cost from %.1f to %.1f\n", sWBI.cost.rCost, sWBI.cost.rCost/pWInfo->a[j].rOptCost)); |
︙ | ︙ | |||
5163 5164 5165 5166 5167 5168 5169 | " cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=%08x\n", j, sWBI.pSrc->pTab->zName, sWBI.cost.rCost, sWBI.cost.plan.nRow, sWBI.cost.plan.nOBSat, sWBI.cost.plan.wsFlags)); bestPlan = sWBI.cost; bestJ = j; } | | > > > > > > > > | 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 | " cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=%08x\n", j, sWBI.pSrc->pTab->zName, sWBI.cost.rCost, sWBI.cost.plan.nRow, sWBI.cost.plan.nOBSat, sWBI.cost.plan.wsFlags)); bestPlan = sWBI.cost; bestJ = j; } /* In a join like "w JOIN x LEFT JOIN y JOIN z" make sure that ** table y (and not table z) is always the next inner loop inside ** of table x. */ if( (sWBI.pSrc->jointype & JT_LEFT)!=0 ) break; } } assert( bestJ>=0 ); assert( sWBI.notValid & getMask(pMaskSet, pTabList->a[bestJ].iCursor) ); assert( bestJ==iFrom || (pTabList->a[iFrom].jointype & JT_LEFT)==0 ); testcase( bestJ>iFrom && (pTabList->a[iFrom].jointype & JT_CROSS)!=0 ); testcase( bestJ>iFrom && bestJ<nTabList-1 && (pTabList->a[bestJ+1].jointype & JT_LEFT)!=0 ); WHERETRACE(("*** Optimizer selects table %d (%s) for loop %d with:\n" " cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=0x%08x\n", bestJ, pTabList->a[bestJ].pTab->zName, pLevel-pWInfo->a, bestPlan.rCost, bestPlan.plan.nRow, bestPlan.plan.nOBSat, bestPlan.plan.wsFlags)); if( (bestPlan.plan.wsFlags & WHERE_DISTINCT)!=0 ){ assert( pWInfo->eDistinct==0 ); |
︙ | ︙ | |||
5419 5420 5421 5422 5423 5424 5425 | } if( pLevel->plan.wsFlags & WHERE_IN_ABLE && pLevel->u.in.nIn>0 ){ struct InLoop *pIn; int j; sqlite3VdbeResolveLabel(v, pLevel->addrNxt); for(j=pLevel->u.in.nIn, pIn=&pLevel->u.in.aInLoop[j-1]; j>0; j--, pIn--){ sqlite3VdbeJumpHere(v, pIn->addrInTop+1); | | | 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 | } if( pLevel->plan.wsFlags & WHERE_IN_ABLE && pLevel->u.in.nIn>0 ){ struct InLoop *pIn; int j; sqlite3VdbeResolveLabel(v, pLevel->addrNxt); for(j=pLevel->u.in.nIn, pIn=&pLevel->u.in.aInLoop[j-1]; j>0; j--, pIn--){ sqlite3VdbeJumpHere(v, pIn->addrInTop+1); sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop); sqlite3VdbeJumpHere(v, pIn->addrInTop-1); } sqlite3DbFree(db, pLevel->u.in.aInLoop); } sqlite3VdbeResolveLabel(v, pLevel->addrBrk); if( pLevel->iLeftJoin ){ int addr; |
︙ | ︙ |
Changes to test/auth.test.
︙ | ︙ | |||
2258 2259 2260 2261 2262 2263 2264 | } set authargs } [list \ SQLITE_UPDATE v1 x main {} \ SQLITE_SELECT {} {} {} v1 \ SQLITE_READ t2 a main v1 \ SQLITE_READ t2 b main v1 \ | > > | | 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 | } set authargs } [list \ SQLITE_UPDATE v1 x main {} \ SQLITE_SELECT {} {} {} v1 \ SQLITE_READ t2 a main v1 \ SQLITE_READ t2 b main v1 \ SQLITE_READ v1 x main v1 \ SQLITE_READ v1 x main v1 \ SQLITE_SELECT {} {} {} v1 \ 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 { |
︙ | ︙ | |||
2284 2285 2286 2287 2288 2289 2290 | } set authargs } [list \ SQLITE_DELETE v1 {} main {} \ SQLITE_SELECT {} {} {} v1 \ SQLITE_READ t2 a main v1 \ SQLITE_READ t2 b main v1 \ | > > | | 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 | } set authargs } [list \ SQLITE_DELETE v1 {} main {} \ SQLITE_SELECT {} {} {} v1 \ SQLITE_READ t2 a main v1 \ SQLITE_READ t2 b main v1 \ SQLITE_READ v1 x main v1 \ SQLITE_READ v1 x main v1 \ SQLITE_SELECT {} {} {} v1 \ SQLITE_READ v1 x main v1 \ SQLITE_INSERT v1chng {} main r3 \ SQLITE_READ v1 x main r3 \ ] } ;# ifcapable view && trigger |
︙ | ︙ |
Changes to test/auth2.test.
︙ | ︙ | |||
127 128 129 130 131 132 133 | do_test auth2-2.3 { set ::authargs {} db eval { SELECT a, b FROM v2; } set ::authargs } {SQLITE_SELECT {} {} {} {} | < < > > < < < < > > > > | 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 | do_test auth2-2.3 { set ::authargs {} db eval { SELECT a, b FROM v2; } set ::authargs } {SQLITE_SELECT {} {} {} {} SQLITE_READ t2 x main v2 SQLITE_READ t2 y main v2 SQLITE_READ t2 y main v2 SQLITE_READ t2 z main v2 SQLITE_READ v2 a main {} SQLITE_READ v2 b main {} SQLITE_SELECT {} {} {} v2 } do_test auth2-2.4 { db2 eval { CREATE TABLE t3(p,q,r); } set ::authargs {} db eval { SELECT b, a FROM v2; } set ::authargs } {SQLITE_SELECT {} {} {} {} SQLITE_READ t2 x main v2 SQLITE_READ t2 y main v2 SQLITE_READ t2 y main v2 SQLITE_READ t2 z main v2 SQLITE_READ v2 b main {} SQLITE_READ v2 a main {} SQLITE_SELECT {} {} {} v2 SQLITE_SELECT {} {} {} {} SQLITE_READ t2 x main v2 SQLITE_READ t2 y main v2 SQLITE_READ t2 y main v2 SQLITE_READ t2 z main v2 SQLITE_READ v2 b main {} SQLITE_READ v2 a main {} SQLITE_SELECT {} {} {} v2 } db2 close finish_test |
Changes to test/autoindex1.test.
︙ | ︙ | |||
253 254 255 256 257 258 259 260 261 | CREATE TABLE t5(a, b, c); EXPLAIN QUERY PLAN SELECT a FROM t5 WHERE b=10 ORDER BY c; } { 0 0 0 {SCAN TABLE t5 (~100000 rows)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | CREATE TABLE t5(a, b, c); EXPLAIN QUERY PLAN SELECT a FROM t5 WHERE b=10 ORDER BY c; } { 0 0 0 {SCAN TABLE t5 (~100000 rows)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } # The following checks a performance issue reported on the sqlite-dev # mailing list on 2013-01-10 # do_execsql_test autoindex1-800 { CREATE TABLE accounts( _id INTEGER PRIMARY KEY AUTOINCREMENT, account_name TEXT, account_type TEXT, data_set TEXT ); CREATE TABLE data( _id INTEGER PRIMARY KEY AUTOINCREMENT, package_id INTEGER REFERENCES package(_id), mimetype_id INTEGER REFERENCES mimetype(_id) NOT NULL, raw_contact_id INTEGER REFERENCES raw_contacts(_id) NOT NULL, is_read_only INTEGER NOT NULL DEFAULT 0, is_primary INTEGER NOT NULL DEFAULT 0, is_super_primary INTEGER NOT NULL DEFAULT 0, data_version INTEGER NOT NULL DEFAULT 0, data1 TEXT, data2 TEXT, data3 TEXT, data4 TEXT, data5 TEXT, data6 TEXT, data7 TEXT, data8 TEXT, data9 TEXT, data10 TEXT, data11 TEXT, data12 TEXT, data13 TEXT, data14 TEXT, data15 TEXT, data_sync1 TEXT, data_sync2 TEXT, data_sync3 TEXT, data_sync4 TEXT ); CREATE TABLE mimetypes( _id INTEGER PRIMARY KEY AUTOINCREMENT, mimetype TEXT NOT NULL ); CREATE TABLE raw_contacts( _id INTEGER PRIMARY KEY AUTOINCREMENT, account_id INTEGER REFERENCES accounts(_id), sourceid TEXT, raw_contact_is_read_only INTEGER NOT NULL DEFAULT 0, version INTEGER NOT NULL DEFAULT 1, dirty INTEGER NOT NULL DEFAULT 0, deleted INTEGER NOT NULL DEFAULT 0, contact_id INTEGER REFERENCES contacts(_id), aggregation_mode INTEGER NOT NULL DEFAULT 0, aggregation_needed INTEGER NOT NULL DEFAULT 1, custom_ringtone TEXT, send_to_voicemail INTEGER NOT NULL DEFAULT 0, times_contacted INTEGER NOT NULL DEFAULT 0, last_time_contacted INTEGER, starred INTEGER NOT NULL DEFAULT 0, display_name TEXT, display_name_alt TEXT, display_name_source INTEGER NOT NULL DEFAULT 0, phonetic_name TEXT, phonetic_name_style TEXT, sort_key TEXT, sort_key_alt TEXT, name_verified INTEGER NOT NULL DEFAULT 0, sync1 TEXT, sync2 TEXT, sync3 TEXT, sync4 TEXT, sync_uid TEXT, sync_version INTEGER NOT NULL DEFAULT 1, has_calendar_event INTEGER NOT NULL DEFAULT 0, modified_time INTEGER, is_restricted INTEGER DEFAULT 0, yp_source TEXT, method_selected INTEGER DEFAULT 0, custom_vibration_type INTEGER DEFAULT 0, custom_ringtone_path TEXT, message_notification TEXT, message_notification_path TEXT ); CREATE INDEX data_mimetype_data1_index ON data (mimetype_id,data1); CREATE INDEX data_raw_contact_id ON data (raw_contact_id); CREATE UNIQUE INDEX mime_type ON mimetypes (mimetype); CREATE INDEX raw_contact_sort_key1_index ON raw_contacts (sort_key); CREATE INDEX raw_contact_sort_key2_index ON raw_contacts (sort_key_alt); CREATE INDEX raw_contacts_contact_id_index ON raw_contacts (contact_id); CREATE INDEX raw_contacts_source_id_account_id_index ON raw_contacts (sourceid, account_id); ANALYZE sqlite_master; INSERT INTO sqlite_stat1 VALUES('raw_contacts','raw_contact_sort_key2_index','1600 4'); INSERT INTO sqlite_stat1 VALUES('raw_contacts','raw_contact_sort_key1_index','1600 4'); INSERT INTO sqlite_stat1 VALUES('raw_contacts','raw_contacts_source_id_account_id_index', '1600 1600 1600'); INSERT INTO sqlite_stat1 VALUES('raw_contacts','raw_contacts_contact_id_index','1600 1'); INSERT INTO sqlite_stat1 VALUES('mimetypes','mime_type','12 1'); INSERT INTO sqlite_stat1 VALUES('data','data_mimetype_data1_index','9819 2455 3'); INSERT INTO sqlite_stat1 VALUES('data','data_raw_contact_id','9819 7'); INSERT INTO sqlite_stat1 VALUES('accounts',NULL,'1'); DROP TABLE IF EXISTS sqlite_stat3; ANALYZE sqlite_master; EXPLAIN QUERY PLAN SELECT * FROM data JOIN mimetypes ON (data.mimetype_id=mimetypes._id) JOIN raw_contacts ON (data.raw_contact_id=raw_contacts._id) JOIN accounts ON (raw_contacts.account_id=accounts._id) WHERE mimetype_id=10 AND data14 IS NOT NULL; } {/SEARCH TABLE data .*SEARCH TABLE raw_contacts/} do_execsql_test autoindex1-801 { EXPLAIN QUERY PLAN SELECT * FROM data JOIN mimetypes ON (data.mimetype_id=mimetypes._id) JOIN raw_contacts ON (data.raw_contact_id=raw_contacts._id) JOIN accounts ON (raw_contacts.account_id=accounts._id) WHERE mimetypes._id=10 AND data14 IS NOT NULL; } {/SEARCH TABLE data .*SEARCH TABLE raw_contacts/} finish_test |
Changes to test/capi2.test.
︙ | ︙ | |||
231 232 233 234 235 236 237 | # Update for v3: Preparing a statement does not affect the change counter. # (Test result changes from 0 to 1). (Later:) change counter updates occur # when sqlite3_step returns, not at finalize time. do_test capi2-3.13b {db changes} {0} do_test capi2-3.14 { | | > | | 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | # Update for v3: Preparing a statement does not affect the change counter. # (Test result changes from 0 to 1). (Later:) change counter updates occur # when sqlite3_step returns, not at finalize time. do_test capi2-3.13b {db changes} {0} do_test capi2-3.14 { list [sqlite3_finalize $VM] [sqlite3_errmsg $DB] \ [sqlite3_extended_errcode $DB] } {SQLITE_CONSTRAINT {column a is not unique} SQLITE_CONSTRAINT_UNIQUE} do_test capi2-3.15 { set VM [sqlite3_prepare $DB {CREATE TABLE t2(a NOT NULL, b)} -1 TAIL] set TAIL } {} do_test capi2-3.16 { list [sqlite3_step $VM] \ [sqlite3_column_count $VM] \ |
︙ | ︙ | |||
254 255 256 257 258 259 260 | set VM [sqlite3_prepare $DB {INSERT INTO t2 VALUES(NULL,2)} -1 TAIL] list [sqlite3_step $VM] \ [sqlite3_column_count $VM] \ [get_row_values $VM] \ [get_column_names $VM] } {SQLITE_ERROR 0 {} {}} do_test capi2-3.19 { | | > | | | | 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 | set VM [sqlite3_prepare $DB {INSERT INTO t2 VALUES(NULL,2)} -1 TAIL] list [sqlite3_step $VM] \ [sqlite3_column_count $VM] \ [get_row_values $VM] \ [get_column_names $VM] } {SQLITE_ERROR 0 {} {}} do_test capi2-3.19 { list [sqlite3_finalize $VM] [sqlite3_errmsg $DB] \ [sqlite3_extended_errcode $DB] } {SQLITE_CONSTRAINT {t2.a may not be NULL} SQLITE_CONSTRAINT_NOTNULL} do_test capi2-3.20 { execsql { CREATE TABLE a1(message_id, name , UNIQUE(message_id, name) ); INSERT INTO a1 VALUES(1, 1); } } {} do_test capi2-3.21 { set VM [sqlite3_prepare $DB {INSERT INTO a1 VALUES(1, 1)} -1 TAIL] sqlite3_step $VM } {SQLITE_ERROR} do_test capi2-3.22 { sqlite3_errcode $DB } {SQLITE_ERROR} do_test capi2-3.23 { sqlite3_finalize $VM } {SQLITE_CONSTRAINT} do_test capi2-3.24 { list [sqlite3_errcode $DB] [sqlite3_extended_errcode $DB] } {SQLITE_CONSTRAINT SQLITE_CONSTRAINT_UNIQUE} # Two or more virtual machines exists at the same time. # do_test capi2-4.1 { set VM1 [sqlite3_prepare $DB {INSERT INTO t2 VALUES(1,2)} -1 TAIL] set TAIL } {} |
︙ | ︙ |
Changes to test/check.test.
︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # This file implements regression tests for SQLite library. The # focus of this file is testing CHECK constraints # # $Id: check.test,v 1.13 2009/06/05 17:09:12 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Only run these tests if the build includes support for CHECK constraints ifcapable !check { finish_test return } | > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # This file implements regression tests for SQLite library. The # focus of this file is testing CHECK constraints # # $Id: check.test,v 1.13 2009/06/05 17:09:12 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix check # Only run these tests if the build includes support for CHECK constraints ifcapable !check { finish_test return } |
︙ | ︙ | |||
408 409 410 411 412 413 414 415 416 | } {0 {}} do_test check-6.15 { execsql {SELECT * FROM t1} } {3 12.0 2 20.0} } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 | } {0 {}} do_test check-6.15 { execsql {SELECT * FROM t1} } {3 12.0 2 20.0} } #-------------------------------------------------------------------------- # If a connection opens a database that contains a CHECK constraint that # uses an unknown UDF, the schema should not be considered malformed. # Attempting to modify the table should fail (since the CHECK constraint # cannot be tested). # reset_db proc myfunc {x} {expr $x < 10} db func myfunc myfunc do_execsql_test 7.1 { CREATE TABLE t6(a CHECK (myfunc(a))) } do_execsql_test 7.2 { INSERT INTO t6 VALUES(9) } do_catchsql_test 7.3 { INSERT INTO t6 VALUES(11) } {1 {constraint failed}} do_test 7.4 { sqlite3 db2 test.db execsql { SELECT * FROM t6 } db2 } {9} do_test 7.5 { catchsql { INSERT INTO t6 VALUES(8) } db2 } {1 {unknown function: myfunc()}} do_test 7.6 { catchsql { CREATE TABLE t7(a CHECK (myfunc(a))) } db2 } {1 {no such function: myfunc}} do_test 7.7 { db2 func myfunc myfunc execsql { INSERT INTO t6 VALUES(8) } db2 } {} do_test 7.8 { db2 func myfunc myfunc catchsql { INSERT INTO t6 VALUES(12) } db2 } {1 {constraint failed}} finish_test |
Changes to test/conflict.test.
︙ | ︙ | |||
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 | catchsql { BEGIN; UPDATE t3 SET x=x+1; INSERT INTO t2 VALUES(3,3,3,3,1); SELECT * FROM t2; } } {1 {column e is not unique}} do_test conflict-9.20 { catch {execsql {COMMIT}} execsql {SELECT * FROM t3} } {5} do_test conflict-9.21 { catchsql { BEGIN; UPDATE t3 SET x=x+1; UPDATE t2 SET e=e+1 WHERE e=1; SELECT * FROM t2; } } {1 {column e is not unique}} do_test conflict-9.22 { catch {execsql {COMMIT}} execsql {SELECT * FROM t3} } {5} do_test conflict-9.23 { catchsql { INSERT INTO t2 VALUES(3,3,1,3,3); | > > | 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 | catchsql { BEGIN; UPDATE t3 SET x=x+1; INSERT INTO t2 VALUES(3,3,3,3,1); SELECT * FROM t2; } } {1 {column e is not unique}} verify_ex_errcode conflict-9.21b SQLITE_CONSTRAINT_UNIQUE do_test conflict-9.20 { catch {execsql {COMMIT}} execsql {SELECT * FROM t3} } {5} do_test conflict-9.21 { catchsql { BEGIN; UPDATE t3 SET x=x+1; UPDATE t2 SET e=e+1 WHERE e=1; SELECT * FROM t2; } } {1 {column e is not unique}} verify_ex_errcode conflict-9.21b SQLITE_CONSTRAINT_UNIQUE do_test conflict-9.22 { catch {execsql {COMMIT}} execsql {SELECT * FROM t3} } {5} do_test conflict-9.23 { catchsql { INSERT INTO t2 VALUES(3,3,1,3,3); |
︙ | ︙ | |||
777 778 779 780 781 782 783 784 785 786 787 788 789 790 | } } {1 one 2 two} do_test conflict-12.3 { catchsql { UPDATE t5 SET a=a+1 WHERE a=1; } } {1 {PRIMARY KEY must be unique}} do_test conflict-12.4 { execsql { UPDATE OR REPLACE t5 SET a=a+1 WHERE a=1; SELECT * FROM t5; } } {2 one} | > | 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 | } } {1 one 2 two} do_test conflict-12.3 { catchsql { UPDATE t5 SET a=a+1 WHERE a=1; } } {1 {PRIMARY KEY must be unique}} verify_ex_errcode conflict-12.3b SQLITE_CONSTRAINT_PRIMARYKEY do_test conflict-12.4 { execsql { UPDATE OR REPLACE t5 SET a=a+1 WHERE a=1; SELECT * FROM t5; } } {2 one} |
︙ | ︙ | |||
798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 | BEGIN; REPLACE INTO t13 VALUES(1); } catchsql { REPLACE INTO t13 VALUES(2); } } {1 {constraint failed}} do_test conflict-13.2 { execsql { REPLACE INTO t13 VALUES(3); COMMIT; SELECT * FROM t13; } } {1 3} finish_test | > | 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 | BEGIN; REPLACE INTO t13 VALUES(1); } catchsql { REPLACE INTO t13 VALUES(2); } } {1 {constraint failed}} verify_ex_errcode conflict-13.1b SQLITE_CONSTRAINT_CHECK do_test conflict-13.2 { execsql { REPLACE INTO t13 VALUES(3); COMMIT; SELECT * FROM t13; } } {1 3} finish_test |
Changes to test/descidx3.test.
︙ | ︙ | |||
128 129 130 131 132 133 134 | } {9 7 6 8 3 4 2 5} ifcapable subquery { # If the subquery capability is not compiled in to the binary, then # the IN(...) operator is not available. Hence these tests cannot be # run. do_test descidx3-4.1 { | | | | | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | } {9 7 6 8 3 4 2 5} ifcapable subquery { # If the subquery capability is not compiled in to the binary, then # the IN(...) operator is not available. Hence these tests cannot be # run. do_test descidx3-4.1 { lsort [execsql { UPDATE t1 SET a=2 WHERE i<6; SELECT i FROM t1 WHERE a IN (1,2) AND b>0 AND b<'zzz'; }] } {2 3 4 6 8} do_test descidx3-4.2 { execsql { UPDATE t1 SET a=1; SELECT i FROM t1 WHERE a IN (1,2) AND b>0 AND b<'zzz'; } } {2 4 3 8 6} do_test descidx3-4.3 { |
︙ | ︙ |
Changes to test/e_fkey.test.
︙ | ︙ | |||
623 624 625 626 627 628 629 | } } {} proc test_efkey_57 {tn isError sql} { catchsql { DROP TABLE t1 } execsql $sql do_test e_fkey-18.$tn { catchsql { INSERT INTO t2 VALUES(NULL) } | | > | 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 | } } {} proc test_efkey_57 {tn isError sql} { catchsql { DROP TABLE t1 } execsql $sql do_test e_fkey-18.$tn { catchsql { INSERT INTO t2 VALUES(NULL) } } [lindex {{0 {}} {/1 {foreign key mismatch - ".*" referencing ".*"}/}} \ $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); |
︙ | ︙ | |||
694 695 696 697 698 699 700 | INSERT INTO child1 VALUES('xxx', 1); INSERT INTO child2 VALUES('xxx', 2); INSERT INTO child3 VALUES(3, 4); } } {} do_test e_fkey-19.2 { catchsql { INSERT INTO child4 VALUES('xxx', 5) } | | | | | | 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 | INSERT INTO child1 VALUES('xxx', 1); INSERT INTO child2 VALUES('xxx', 2); INSERT INTO child3 VALUES(3, 4); } } {} do_test e_fkey-19.2 { catchsql { INSERT INTO child4 VALUES('xxx', 5) } } {1 {foreign key mismatch - "child4" referencing "parent"}} do_test e_fkey-19.3 { catchsql { INSERT INTO child5 VALUES('xxx', 6) } } {1 {foreign key mismatch - "child5" referencing "parent"}} do_test e_fkey-19.4 { catchsql { INSERT INTO child6 VALUES(2, 3) } } {1 {foreign key mismatch - "child6" referencing "parent"}} do_test e_fkey-19.5 { catchsql { INSERT INTO child7 VALUES(3) } } {1 {foreign key mismatch - "child7" referencing "parent"}} #------------------------------------------------------------------------- # 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]). # # EVIDENCE-OF: R-45488-08504 If the database schema contains foreign key |
︙ | ︙ | |||
761 762 763 764 765 766 767 | 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" | | | | | | | | 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 | 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 - \"c2\" referencing \"p2\"" 4 c3 p3 "foreign key mismatch - \"c3\" referencing \"p3\"" 5 c4 p4 "foreign key mismatch - \"c4\" referencing \"p4\"" 6 c5 p5 "foreign key mismatch - \"c5\" referencing \"p5\"" 7 c6 p6 "foreign key mismatch - \"c6\" referencing \"p6\"" 8 c7 p7 "foreign key mismatch - \"c7\" referencing \"p7\"" } { do_test e_fkey-20.$tn.1 { catchsql "INSERT INTO $tbl VALUES('a', 'b')" } [list 1 $err] do_test e_fkey-20.$tn.2 { catchsql "UPDATE $tbl SET c = ?, d = ?" } [list 1 $err] |
︙ | ︙ | |||
816 817 818 819 820 821 822 | execsql { INSERT INTO parent2 VALUES('I', 'II'); INSERT INTO child8 VALUES('I', 'II'); } } {} do_test e_fkey-21.3 { catchsql { INSERT INTO child9 VALUES('I') } | | | | | | | | 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 | execsql { INSERT INTO parent2 VALUES('I', 'II'); INSERT INTO child8 VALUES('I', 'II'); } } {} do_test e_fkey-21.3 { catchsql { INSERT INTO child9 VALUES('I') } } {1 {foreign key mismatch - "child9" referencing "parent2"}} do_test e_fkey-21.4 { catchsql { INSERT INTO child9 VALUES('II') } } {1 {foreign key mismatch - "child9" referencing "parent2"}} do_test e_fkey-21.5 { catchsql { INSERT INTO child9 VALUES(NULL) } } {1 {foreign key mismatch - "child9" referencing "parent2"}} do_test e_fkey-21.6 { catchsql { INSERT INTO child10 VALUES('I', 'II', 'III') } } {1 {foreign key mismatch - "child10" referencing "parent2"}} do_test e_fkey-21.7 { catchsql { INSERT INTO child10 VALUES(1, 2, 3) } } {1 {foreign key mismatch - "child10" referencing "parent2"}} do_test e_fkey-21.8 { catchsql { INSERT INTO child10 VALUES(NULL, NULL, NULL) } } {1 {foreign key mismatch - "child10" referencing "parent2"}} #------------------------------------------------------------------------- # 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. |
︙ | ︙ | |||
1147 1148 1149 1150 1151 1152 1153 | do_test e_fkey-28.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} | | | | 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 | do_test e_fkey-28.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 - "c" referencing "p"}} do_test e_fkey-28.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 - "c" referencing "p"}} #------------------------------------------------------------------------- # EVIDENCE-OF: R-24676-09859 # # Test the example schema in the "Composite Foreign Key Constraints" # section. |
︙ | ︙ | |||
2725 2726 2727 2728 2729 2730 2731 | SELECT * FROM c3; ROLLBACK; } } {{} 2} do_test e_fkey-60.4 { execsql { CREATE TABLE nosuchtable(x PRIMARY KEY) } catchsql { DELETE FROM p } | | | | 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 | SELECT * FROM c3; ROLLBACK; } } {{} 2} do_test e_fkey-60.4 { execsql { CREATE TABLE nosuchtable(x PRIMARY KEY) } catchsql { DELETE FROM p } } {1 {foreign key mismatch - "c2" referencing "p"}} do_test e_fkey-60.5 { execsql { DROP TABLE c1 } catchsql { DELETE FROM p } } {1 {foreign key mismatch - "c2" referencing "p"}} do_test e_fkey-60.6 { execsql { DROP TABLE c2 } execsql { DELETE FROM p } } {} #------------------------------------------------------------------------- # Test that the special behaviours of ALTER and DROP TABLE are only |
︙ | ︙ |
Changes to test/errmsg.test.
︙ | ︙ | |||
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | } do_test 2.2 { error_messages "INSERT INTO t1 VALUES('ghi', 'def')" } [list {*}{ SQLITE_ERROR {SQL logic error or missing database} SQLITE_CONSTRAINT {column b is not unique} }] do_test 2.3 { error_messages_v2 "INSERT INTO t1 VALUES('ghi', 'def')" } [list {*}{ SQLITE_CONSTRAINT {column b is not unique} SQLITE_CONSTRAINT {column b is not unique} }] #------------------------------------------------------------------------- # Test SQLITE_SCHEMA errors. And, for _v2(), test that if the schema # change invalidates the SQL statement itself the error message is returned # correctly. # do_execsql_test 3.1.1 { | > > | 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | } do_test 2.2 { error_messages "INSERT INTO t1 VALUES('ghi', 'def')" } [list {*}{ SQLITE_ERROR {SQL logic error or missing database} SQLITE_CONSTRAINT {column b is not unique} }] verify_ex_errcode 2.2b SQLITE_CONSTRAINT_UNIQUE do_test 2.3 { error_messages_v2 "INSERT INTO t1 VALUES('ghi', 'def')" } [list {*}{ SQLITE_CONSTRAINT {column b is not unique} SQLITE_CONSTRAINT {column b is not unique} }] verify_ex_errcode 2.3b SQLITE_CONSTRAINT_UNIQUE #------------------------------------------------------------------------- # Test SQLITE_SCHEMA errors. And, for _v2(), test that if the schema # change invalidates the SQL statement itself the error message is returned # correctly. # do_execsql_test 3.1.1 { |
︙ | ︙ |
Changes to test/filefmt.test.
︙ | ︙ | |||
209 210 211 212 213 214 215 216 | sql36231 { DROP TABLE t1 } } {} do_execsql_test filefmt-3.3 { SELECT * FROM sqlite_master; PRAGMA integrity_check; } {ok} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | sql36231 { DROP TABLE t1 } } {} do_execsql_test filefmt-3.3 { SELECT * FROM sqlite_master; PRAGMA integrity_check; } {ok} reset_db do_execsql_test filefmt-4.1 { PRAGMA auto_vacuum = 1; CREATE TABLE t1(x, y); CREATE TABLE t2(x, y); INSERT INTO t1 VALUES(randomblob(100), randomblob(100)); INSERT INTO t1 VALUES(randomblob(100), randomblob(100)); INSERT INTO t1 VALUES(randomblob(100), randomblob(100)); INSERT INTO t1 VALUES(randomblob(100), randomblob(100)); INSERT INTO t1 VALUES(randomblob(100), randomblob(100)); INSERT INTO t1 VALUES(randomblob(100), randomblob(100)); INSERT INTO t2 SELECT randomblob(100), randomblob(100) FROM t1; INSERT INTO t2 SELECT randomblob(100), randomblob(100) FROM t1; INSERT INTO t2 SELECT randomblob(100), randomblob(100) FROM t1; INSERT INTO t2 SELECT randomblob(100), randomblob(100) FROM t1; } do_test filefmt-4.2 { sql36231 { INSERT INTO t2 SELECT * FROM t1 } } {} do_test filefmt-4.3 { forcedelete bak.db db backup bak.db } {} do_test filefmt-4.4 { sqlite3 db2 bak.db db2 eval { PRAGMA integrity_check } } {ok} db2 close finish_test |
Changes to test/fkey2.test.
︙ | ︙ | |||
135 136 137 138 139 140 141 | 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}} | | > | > > > > > > > > > > > > > > > > > > | 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 | 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 - "t10" referencing "t9"}} } do_test fkey2-1.1.0 { execsql [string map {/D/ {}} $FkeySimpleSchema] } {} foreach {tn zSql res} $FkeySimpleTests { do_test fkey2-1.1.$tn.1 { catchsql $zSql } $res do_test fkey2-1.1.$tn.2 { execsql {PRAGMA foreign_key_check(t1)} } {} do_test fkey2-1.1.$tn.3 { execsql {PRAGMA foreign_key_check(t2)} } {} do_test fkey2-1.1.$tn.4 { execsql {PRAGMA foreign_key_check(t3)} } {} do_test fkey2-1.1.$tn.5 { execsql {PRAGMA foreign_key_check(t4)} } {} do_test fkey2-1.1.$tn.6 { execsql {PRAGMA foreign_key_check(t7)} } {} do_test fkey2-1.1.$tn.7 { execsql {PRAGMA foreign_key_check(t8)} } {} } 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 do_test fkey2-1.2.$tn.2 { execsql {PRAGMA foreign_key_check(t1)} } {} do_test fkey2-1.2.$tn.3 { execsql {PRAGMA foreign_key_check(t2)} } {} do_test fkey2-1.2.$tn.4 { execsql {PRAGMA foreign_key_check(t3)} } {} do_test fkey2-1.2.$tn.5 { execsql {PRAGMA foreign_key_check(t4)} } {} do_test fkey2-1.2.$tn.6 { execsql {PRAGMA foreign_key_check(t7)} } {} do_test fkey2-1.2.$tn.7 { execsql {PRAGMA foreign_key_check(t8)} } {} } 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 do_test fkey2-1.3.$tn.2 { execsql {PRAGMA foreign_key_check(t1)} } {} do_test fkey2-1.3.$tn.3 { execsql {PRAGMA foreign_key_check(t2)} } {} do_test fkey2-1.3.$tn.4 { execsql {PRAGMA foreign_key_check(t3)} } {} do_test fkey2-1.3.$tn.5 { execsql {PRAGMA foreign_key_check(t4)} } {} do_test fkey2-1.3.$tn.6 { execsql {PRAGMA foreign_key_check(t7)} } {} do_test fkey2-1.3.$tn.7 { execsql {PRAGMA foreign_key_check(t8)} } {} } execsql { PRAGMA count_changes = 0 } drop_all_tables do_test fkey2-1.4.0 { execsql [string map {/D/ {}} $FkeySimpleSchema] execsql { PRAGMA count_changes = 1 } |
︙ | ︙ | |||
677 678 679 680 681 682 683 | 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 } | | | 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 | 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 - "c" referencing "."}/} } # "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 |
︙ | ︙ | |||
705 706 707 708 709 710 711 | 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); } | | | 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 | 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 - "t2" referencing "t1"}} 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); |
︙ | ︙ | |||
1219 1220 1221 1222 1223 1224 1225 | } {} 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) } | | | 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 | } {} 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 - "cc" referencing "pp"}} 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 |
︙ | ︙ | |||
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 | 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} ifcapable autoreset { do_test fkey2-17.1.3 { sqlite3_step $STMT } {SQLITE_CONSTRAINT} } else { 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); | > > > | 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 | 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} verify_ex_errcode fkey2-17.1.2b SQLITE_CONSTRAINT_FOREIGNKEY ifcapable autoreset { do_test fkey2-17.1.3 { sqlite3_step $STMT } {SQLITE_CONSTRAINT} verify_ex_errcode fkey2-17.1.3b SQLITE_CONSTRAINT_FOREIGNKEY } else { do_test fkey2-17.1.3 { sqlite3_step $STMT } {SQLITE_MISUSE} } do_test fkey2-17.1.4 { sqlite3_finalize $STMT } {SQLITE_CONSTRAINT} verify_ex_errcode fkey2-17.1.4b SQLITE_CONSTRAINT_FOREIGNKEY 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); |
︙ | ︙ | |||
1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 | } {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, | > > | 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 | } {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} verify_ex_errcode fkey2-17.1.13b SQLITE_CONSTRAINT_FOREIGNKEY do_test fkey2-17.1.14 { sqlite3_finalize $STMT } {SQLITE_CONSTRAINT} verify_ex_errcode fkey2-17.1.14b SQLITE_CONSTRAINT_FOREIGNKEY drop_all_tables do_test fkey2-17.2.1 { execsql { CREATE TABLE high("a'b!" PRIMARY KEY, b); CREATE TABLE low( c, |
︙ | ︙ | |||
1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 | } } {} do_test fkey2-19.2 { set S [sqlite3_prepare_v2 db "DELETE FROM main WHERE id = ?" -1 dummy] sqlite3_bind_int $S 1 2 sqlite3_step $S } {SQLITE_CONSTRAINT} do_test fkey2-19.3 { sqlite3_reset $S } {SQLITE_CONSTRAINT} do_test fkey2-19.4 { sqlite3_bind_int $S 1 1 sqlite3_step $S } {SQLITE_DONE} do_test fkey2-19.4 { sqlite3_finalize $S } {SQLITE_OK} | > > | 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 | } } {} do_test fkey2-19.2 { set S [sqlite3_prepare_v2 db "DELETE FROM main WHERE id = ?" -1 dummy] sqlite3_bind_int $S 1 2 sqlite3_step $S } {SQLITE_CONSTRAINT} verify_ex_errcode fkey2-19.2b SQLITE_CONSTRAINT_FOREIGNKEY do_test fkey2-19.3 { sqlite3_reset $S } {SQLITE_CONSTRAINT} verify_ex_errcode fkey2-19.3b SQLITE_CONSTRAINT_FOREIGNKEY do_test fkey2-19.4 { sqlite3_bind_int $S 1 1 sqlite3_step $S } {SQLITE_DONE} do_test fkey2-19.4 { sqlite3_finalize $S } {SQLITE_OK} |
︙ | ︙ |
Changes to test/fkey4.test.
︙ | ︙ | |||
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | do_test fkey4-1.2 { set ::DB [sqlite3_connection_pointer db] set ::SQL {INSERT INTO t2 VALUES(2,4)} set ::STMT1 [sqlite3_prepare_v2 $::DB $::SQL -1 TAIL] sqlite3_step $::STMT1 } {SQLITE_CONSTRAINT} do_test fkey4-1.3 { set ::STMT2 [sqlite3_prepare_v2 $::DB $::SQL -1 TAIL] sqlite3_step $::STMT2 } {SQLITE_CONSTRAINT} do_test fkey4-1.4 { db eval {SELECT * FROM t2} } {1 3} sqlite3_finalize $::STMT1 sqlite3_finalize $::STMT2 finish_test | > > | 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | do_test fkey4-1.2 { set ::DB [sqlite3_connection_pointer db] set ::SQL {INSERT INTO t2 VALUES(2,4)} set ::STMT1 [sqlite3_prepare_v2 $::DB $::SQL -1 TAIL] sqlite3_step $::STMT1 } {SQLITE_CONSTRAINT} verify_ex_errcode fkey4-1.2b SQLITE_CONSTRAINT_FOREIGNKEY do_test fkey4-1.3 { set ::STMT2 [sqlite3_prepare_v2 $::DB $::SQL -1 TAIL] sqlite3_step $::STMT2 } {SQLITE_CONSTRAINT} verify_ex_errcode fkey4-1.3b SQLITE_CONSTRAINT_FOREIGNKEY do_test fkey4-1.4 { db eval {SELECT * FROM t2} } {1 3} sqlite3_finalize $::STMT1 sqlite3_finalize $::STMT2 finish_test |
Added test/fkey5.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 | # 2012 December 17 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file tests the PRAGMA foreign_key_check command. # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {!foreignkey} { finish_test return } do_test fkey5-1.1 { db eval { CREATE TABLE p1(a INTEGER PRIMARY KEY); INSERT INTO p1 VALUES(88),(89); CREATE TABLE p2(a INT PRIMARY KEY); INSERT INTO p2 VALUES(77),(78); CREATE TABLE p3(a TEXT PRIMARY KEY); INSERT INTO p3 VALUES(66),(67),('alpha'),('BRAVO'); CREATE TABLE p4(a TEXT PRIMARY KEY COLLATE nocase); INSERT INTO p4 VALUES('alpha'),('BRAVO'),('55'),('Delta'),('ECHO'); CREATE TABLE p5(a INTEGER PRIMARY KEY, b, c, UNIQUE(b,c)); INSERT INTO p5 VALUES(1,'Alpha','abc'),(2,'beta','def'); CREATE TABLE p6(a INTEGER PRIMARY KEY, b TEXT COLLATE nocase, c TEXT COLLATE rtrim, UNIQUE(b,c)); INSERT INTO p6 VALUES(1,'Alpha','abc '),(2,'bETA','def '); CREATE TABLE c1(x INTEGER PRIMARY KEY references p1); CREATE TABLE c2(x INTEGER PRIMARY KEY references p2); CREATE TABLE c3(x INTEGER PRIMARY KEY references p3); CREATE TABLE c4(x INTEGER PRIMARY KEY references p4); CREATE TABLE c5(x INT references p1); CREATE TABLE c6(x INT references p2); CREATE TABLE c7(x INT references p3); CREATE TABLE c8(x INT references p4); CREATE TABLE c9(x TEXT UNIQUE references p1); CREATE TABLE c10(x TEXT UNIQUE references p2); CREATE TABLE c11(x TEXT UNIQUE references p3); CREATE TABLE c12(x TEXT UNIQUE references p4); CREATE TABLE c13(x TEXT COLLATE nocase references p3); CREATE TABLE c14(x TEXT COLLATE nocase references p4); CREATE TABLE c15(x, y, FOREIGN KEY(x,y) REFERENCES p5(b,c)); CREATE TABLE c16(x, y, FOREIGN KEY(x,y) REFERENCES p5(c,b)); CREATE TABLE c17(x, y, FOREIGN KEY(x,y) REFERENCES p6(b,c)); CREATE TABLE c18(x, y, FOREIGN KEY(x,y) REFERENCES p6(c,b)); CREATE TABLE c19(x TEXT COLLATE nocase, y TEXT COLLATE rtrim, FOREIGN KEY(x,y) REFERENCES p5(b,c)); CREATE TABLE c20(x TEXT COLLATE nocase, y TEXT COLLATE rtrim, FOREIGN KEY(x,y) REFERENCES p5(c,b)); CREATE TABLE c21(x TEXT COLLATE nocase, y TEXT COLLATE rtrim, FOREIGN KEY(x,y) REFERENCES p6(b,c)); CREATE TABLE c22(x TEXT COLLATE nocase, y TEXT COLLATE rtrim, FOREIGN KEY(x,y) REFERENCES p6(c,b)); PRAGMA foreign_key_check; } } {} do_test fkey5-1.2 { db eval { INSERT INTO c1 VALUES(90),(87),(88); PRAGMA foreign_key_check; } } {c1 87 p1 0 c1 90 p1 0} do_test fkey5-1.3 { db eval { PRAGMA foreign_key_check(c1); } } {c1 87 p1 0 c1 90 p1 0} do_test fkey5-1.4 { db eval { PRAGMA foreign_key_check(c2); } } {} do_test fkey5-2.0 { db eval { INSERT INTO c5 SELECT x FROM c1; DELETE FROM c1; PRAGMA foreign_key_check; } } {c5 1 p1 0 c5 3 p1 0} do_test fkey5-2.1 { db eval { PRAGMA foreign_key_check(c5); } } {c5 1 p1 0 c5 3 p1 0} do_test fkey5-2.2 { db eval { PRAGMA foreign_key_check(c1); } } {} do_test fkey5-3.0 { db eval { INSERT INTO c9 SELECT x FROM c5; DELETE FROM c5; PRAGMA foreign_key_check; } } {c9 1 p1 0 c9 3 p1 0} do_test fkey5-3.1 { db eval { PRAGMA foreign_key_check(c9); } } {c9 1 p1 0 c9 3 p1 0} do_test fkey5-3.2 { db eval { PRAGMA foreign_key_check(c5); } } {} do_test fkey5-4.0 { db eval { DELETE FROM c9; INSERT INTO c2 VALUES(79),(77),(76); PRAGMA foreign_key_check; } } {c2 76 p2 0 c2 79 p2 0} do_test fkey5-4.1 { db eval { PRAGMA foreign_key_check(c2); } } {c2 76 p2 0 c2 79 p2 0} do_test fkey5-4.2 { db eval { INSERT INTO c6 SELECT x FROM c2; DELETE FROM c2; PRAGMA foreign_key_check; } } {c6 1 p2 0 c6 3 p2 0} do_test fkey5-4.3 { db eval { PRAGMA foreign_key_check(c6); } } {c6 1 p2 0 c6 3 p2 0} do_test fkey5-4.4 { db eval { INSERT INTO c10 SELECT x FROM c6; DELETE FROM c6; PRAGMA foreign_key_check; } } {c10 1 p2 0 c10 3 p2 0} do_test fkey5-4.5 { db eval { PRAGMA foreign_key_check(c10); } } {c10 1 p2 0 c10 3 p2 0} do_test fkey5-5.0 { db eval { DELETE FROM c10; INSERT INTO c3 VALUES(68),(67),(65); PRAGMA foreign_key_check; } } {c3 65 p3 0 c3 68 p3 0} do_test fkey5-5.1 { db eval { PRAGMA foreign_key_check(c3); } } {c3 65 p3 0 c3 68 p3 0} do_test fkey5-5.2 { db eval { INSERT INTO c7 SELECT x FROM c3; INSERT INTO c7 VALUES('Alpha'),('alpha'),('foxtrot'); DELETE FROM c3; PRAGMA foreign_key_check; } } {c7 1 p3 0 c7 3 p3 0 c7 4 p3 0 c7 6 p3 0} do_test fkey5-5.3 { db eval { PRAGMA foreign_key_check(c7); } } {c7 1 p3 0 c7 3 p3 0 c7 4 p3 0 c7 6 p3 0} do_test fkey5-5.4 { db eval { INSERT INTO c11 SELECT x FROM c7; DELETE FROM c7; PRAGMA foreign_key_check; } } {c11 1 p3 0 c11 3 p3 0 c11 4 p3 0 c11 6 p3 0} do_test fkey5-5.5 { db eval { PRAGMA foreign_key_check(c11); } } {c11 1 p3 0 c11 3 p3 0 c11 4 p3 0 c11 6 p3 0} do_test fkey5-6.0 { db eval { DELETE FROM c11; INSERT INTO c4 VALUES(54),(55),(56); PRAGMA foreign_key_check; } } {c4 54 p4 0 c4 56 p4 0} do_test fkey5-6.1 { db eval { PRAGMA foreign_key_check(c4); } } {c4 54 p4 0 c4 56 p4 0} do_test fkey5-6.2 { db eval { INSERT INTO c8 SELECT x FROM c4; INSERT INTO c8 VALUES('Alpha'),('ALPHA'),('foxtrot'); DELETE FROM c4; PRAGMA foreign_key_check; } } {c8 1 p4 0 c8 3 p4 0 c8 6 p4 0} do_test fkey5-6.3 { db eval { PRAGMA foreign_key_check(c8); } } {c8 1 p4 0 c8 3 p4 0 c8 6 p4 0} do_test fkey5-6.4 { db eval { INSERT INTO c12 SELECT x FROM c8; DELETE FROM c8; PRAGMA foreign_key_check; } } {c12 1 p4 0 c12 3 p4 0 c12 6 p4 0} do_test fkey5-6.5 { db eval { PRAGMA foreign_key_check(c12); } } {c12 1 p4 0 c12 3 p4 0 c12 6 p4 0} do_test fkey5-7.1 { db eval { INSERT OR IGNORE INTO c13 SELECT * FROM c12; INSERT OR IGNORE INTO C14 SELECT * FROM c12; DELETE FROM c12; PRAGMA foreign_key_check; } } {c14 1 p4 0 c14 3 p4 0 c14 6 p4 0 c13 1 p3 0 c13 2 p3 0 c13 3 p3 0 c13 4 p3 0 c13 5 p3 0 c13 6 p3 0} do_test fkey5-7.2 { db eval { PRAGMA foreign_key_check(c14); } } {c14 1 p4 0 c14 3 p4 0 c14 6 p4 0} do_test fkey5-7.3 { db eval { PRAGMA foreign_key_check(c13); } } {c13 1 p3 0 c13 2 p3 0 c13 3 p3 0 c13 4 p3 0 c13 5 p3 0 c13 6 p3 0} do_test fkey5-8.0 { db eval { DELETE FROM c13; DELETE FROM c14; INSERT INTO c19 VALUES('alpha','abc'); PRAGMA foreign_key_check(c19); } } {c19 1 p5 0} do_test fkey5-8.1 { db eval { DELETE FROM c19; INSERT INTO c19 VALUES('Alpha','abc'); PRAGMA foreign_key_check(c19); } } {} do_test fkey5-8.2 { db eval { INSERT INTO c20 VALUES('Alpha','abc'); PRAGMA foreign_key_check(c20); } } {c20 1 p5 0} do_test fkey5-8.3 { db eval { DELETE FROM c20; INSERT INTO c20 VALUES('abc','Alpha'); PRAGMA foreign_key_check(c20); } } {} do_test fkey5-8.4 { db eval { INSERT INTO c21 VALUES('alpha','abc '); PRAGMA foreign_key_check(c21); } } {} do_test fkey5-8.5 { db eval { DELETE FROM c21; INSERT INTO c19 VALUES('Alpha','abc'); PRAGMA foreign_key_check(c21); } } {} do_test fkey5-8.6 { db eval { INSERT INTO c22 VALUES('Alpha','abc'); PRAGMA foreign_key_check(c22); } } {c22 1 p6 0} do_test fkey5-8.7 { db eval { DELETE FROM c22; INSERT INTO c22 VALUES('abc ','ALPHA'); PRAGMA foreign_key_check(c22); } } {} finish_test |
Changes to test/fkey_malloc.test.
︙ | ︙ | |||
25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 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, | > | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 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; PRAGMA foreign_key_check; } 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, |
︙ | ︙ | |||
124 125 126 127 128 129 130 | CREATE TABLE z(e, f, FOREIGN KEY(e, f) REFERENCES x); } -sqlbody { DROP TABLE y; DROP TABLE x; } finish_test | < < | 125 126 127 128 129 130 131 | CREATE TABLE z(e, f, FOREIGN KEY(e, f) REFERENCES x); } -sqlbody { DROP TABLE y; DROP TABLE x; } finish_test |
Changes to test/fts3ai.test.
︙ | ︙ | |||
14 15 16 17 18 19 20 21 22 23 24 25 26 27 | source $testdir/tester.tcl # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts3 { finish_test return } # Return the UTF-16 representation of the supplied UTF-8 string $str. # If $nt is true, append two 0x00 bytes as a nul terminator. # NOTE(shess) Copied from capi3.test. proc utf16 {str {nt 1}} { set r [encoding convertto unicode $str] if {$nt} { | > > > > > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | source $testdir/tester.tcl # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts3 { finish_test return } ifcapable !utf16 { finish_test return } # Return the UTF-16 representation of the supplied UTF-8 string $str. # If $nt is true, append two 0x00 bytes as a nul terminator. # NOTE(shess) Copied from capi3.test. proc utf16 {str {nt 1}} { set r [encoding convertto unicode $str] if {$nt} { |
︙ | ︙ |
Changes to test/fts4content.test.
︙ | ︙ | |||
42 43 44 45 46 47 48 49 50 51 52 53 54 55 | # 7.* - Test that if content=xxx is specified and table xxx does not # exist, the FTS table can still be used for INSERT and some # SELECT statements. # # 8.* - Test that if the content=xxx and prefix options are used together, # the 'rebuild' command still works. # do_execsql_test 1.1.1 { CREATE TABLE t1(a, b, c); INSERT INTO t1 VALUES('w x', 'x y', 'y z'); CREATE VIRTUAL TABLE ft1 USING fts4(content=t1); } | > > | 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | # 7.* - Test that if content=xxx is specified and table xxx does not # exist, the FTS table can still be used for INSERT and some # SELECT statements. # # 8.* - Test that if the content=xxx and prefix options are used together, # the 'rebuild' command still works. # # 9.* - Test using content=xxx where xxx is a virtual table. # do_execsql_test 1.1.1 { CREATE TABLE t1(a, b, c); INSERT INTO t1 VALUES('w x', 'x y', 'y z'); CREATE VIRTUAL TABLE ft1 USING fts4(content=t1); } |
︙ | ︙ | |||
517 518 519 520 521 522 523 524 525 | } do_execsql_test 8.2 { SELECT * FROM ft10 WHERE a MATCH 'ab*'; } do_execsql_test 8.3 { INSERT INTO ft10(ft10) VALUES('rebuild'); } do_execsql_test 8.4 { SELECT rowid FROM ft10 WHERE a MATCH 'ab*'; } {1 2 3} do_execsql_test 8.5 { SELECT rowid FROM ft10 WHERE b MATCH 'abav*'; } {3} do_execsql_test 8.6 { SELECT rowid FROM ft10 WHERE ft10 MATCH 'abas*'; } {1} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } do_execsql_test 8.2 { SELECT * FROM ft10 WHERE a MATCH 'ab*'; } do_execsql_test 8.3 { INSERT INTO ft10(ft10) VALUES('rebuild'); } do_execsql_test 8.4 { SELECT rowid FROM ft10 WHERE a MATCH 'ab*'; } {1 2 3} do_execsql_test 8.5 { SELECT rowid FROM ft10 WHERE b MATCH 'abav*'; } {3} do_execsql_test 8.6 { SELECT rowid FROM ft10 WHERE ft10 MATCH 'abas*'; } {1} #------------------------------------------------------------------------- # Test cases 9.* # reset_db register_echo_module [sqlite3_connection_pointer db] do_execsql_test 9.1 { CREATE TABLE tbl1(a, b); INSERT INTO tbl1 VALUES('a b', 'c d'); INSERT INTO tbl1 VALUES('e f', 'a b'); CREATE VIRTUAL TABLE e1 USING echo(tbl1); CREATE VIRTUAL TABLE ft1 USING fts4(content=e1); INSERT INTO ft1(ft1) VALUES('rebuild'); } do_execsql_test 9.2 { SELECT rowid, * FROM ft1 WHERE ft1 MATCH 'e' } {2 {e f} {a b}} do_execsql_test 9.3 { SELECT rowid, * FROM ft1 WHERE ft1 MATCH 'a' } {1 {a b} {c d} 2 {e f} {a b}} do_execsql_test 9.4 { DELETE FROM ft1 WHERE docid=1; } do_execsql_test 9.5 { SELECT rowid, * FROM ft1 WHERE ft1 MATCH 'a' } {2 {e f} {a b}} do_execsql_test 9.6 { INSERT INTO ft1(ft1) VALUES('rebuild'); SELECT rowid, * FROM ft1 WHERE ft1 MATCH 'a' } {1 {a b} {c d} 2 {e f} {a b}} #------------------------------------------------------------------------- # Test cases 10.* # reset_db register_fs_module [sqlite3_connection_pointer db] proc write_file {path text} { set fd [open $path w] puts -nonewline $fd $text close $fd } write_file t1.txt {a b c d e f g h i j k l m n o p q r s t u v w x y z} write_file t2.txt {a b c d e f g h i j k l m a b c d e f g h i j k l m} write_file t3.txt {n o p q r s t u v w x y z n o p q r s t u v w x y z} do_execsql_test 10.1 { CREATE TABLE idx(id INTEGER PRIMARY KEY, path TEXT); INSERT INTO idx VALUES (1, 't1.txt'); INSERT INTO idx VALUES (2, 't2.txt'); INSERT INTO idx VALUES (3, 't3.txt'); CREATE VIRTUAL TABLE vt USING fs(idx); SELECT * FROM vt; } { 1 {a b c d e f g h i j k l m n o p q r s t u v w x y z} 2 {a b c d e f g h i j k l m a b c d e f g h i j k l m} 3 {n o p q r s t u v w x y z n o p q r s t u v w x y z} } do_execsql_test 10.2 { SELECT * FROM vt WHERE rowid = 2; } { 2 {a b c d e f g h i j k l m a b c d e f g h i j k l m} } do_execsql_test 10.3 { CREATE VIRTUAL TABLE ft USING fts4(content=vt); INSERT INTO ft(ft) VALUES('rebuild'); } do_execsql_test 10.4 { SELECT snippet(ft, '[', ']', '...', -1, 5) FROM ft WHERE ft MATCH 'e' } { {...c d [e] f g...} {...c d [e] f g...} } do_execsql_test 10.5 { SELECT snippet(ft, '[', ']', '...', -1, 5) FROM ft WHERE ft MATCH 't' } { {...r s [t] u v...} {...r s [t] u v...} } do_execsql_test 10.6 { DELETE FROM ft WHERE docid=2 } do_execsql_test 10.7 { SELECT snippet(ft, '[', ']', '...', -1, 5) FROM ft WHERE ft MATCH 'e' } { {...c d [e] f g...} } finish_test |
Changes to test/fts4unicode.test.
︙ | ︙ | |||
40 41 42 43 44 45 46 | append sql "'" } append sql ")" uplevel [list do_execsql_test $tn $sql [list [list {*}$res]]] } do_unicode_token_test 1.0 {a B c D} {0 a a 1 b B 2 c c 3 d D} | | | | | | | > > > | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | append sql "'" } append sql ")" uplevel [list do_execsql_test $tn $sql [list [list {*}$res]]] } do_unicode_token_test 1.0 {a B c D} {0 a a 1 b B 2 c c 3 d D} do_unicode_token_test 1.1 {Ä Ö Ü} {0 ä Ä 1 ö Ö 2 ü Ü} do_unicode_token_test 1.2 {xÄx xÖx xÜx} {0 xäx xÄx 1 xöx xÖx 2 xüx xÜx} # 0x00DF is a small "sharp s". 0x1E9E is a capital sharp s. do_unicode_token_test 1.3 "\uDF" "0 \uDF \uDF" do_unicode_token_test 1.4 "\u1E9E" "0 ß \u1E9E" do_unicode_token_test 1.5 "\u1E9E" "0 \uDF \u1E9E" do_unicode_token_test 1.6 "The quick brown fox" { 0 the The 1 quick quick 2 brown brown 3 fox fox } do_unicode_token_test 1.7 "The\u00bfquick\u224ebrown\u2263fox" { 0 the The 1 quick quick 2 brown brown 3 fox fox } do_unicode_token_test2 1.8 {a B c D} {0 a a 1 b B 2 c c 3 d D} do_unicode_token_test2 1.9 {Ä Ö Ü} {0 a Ä 1 o Ö 2 u Ü} do_unicode_token_test2 1.10 {xÄx xÖx xÜx} {0 xax xÄx 1 xox xÖx 2 xux xÜx} # Check that diacritics are removed if remove_diacritics=1 is specified. # And that they do not break tokens. do_unicode_token_test2 1.11 "xx\u0301xx" "0 xxxx xx\u301xx" # Title-case mappings work do_unicode_token_test 1.12 "\u01c5" "0 \u01c6 \u01c5" #------------------------------------------------------------------------- # set docs [list { Enhance the INSERT syntax to allow multiple rows to be inserted via the VALUES clause. } { |
︙ | ︙ | |||
379 380 381 382 383 384 385 | do_isspace_test 6.$T.19 $T {8196 8197 8198 8199} do_isspace_test 6.$T.19 $T {8200 8201 8202 8239} do_isspace_test 6.$T.19 $T {8287 12288} } finish_test | < < | 382 383 384 385 386 387 388 | do_isspace_test 6.$T.19 $T {8196 8197 8198 8199} do_isspace_test 6.$T.19 $T {8200 8201 8202 8239} do_isspace_test 6.$T.19 $T {8287 12288} } finish_test |
Changes to test/func.test.
︙ | ︙ | |||
1285 1286 1287 1288 1289 1290 1291 | db eval {SELECT sum(length(x)) FROM t29} } {1000009} do_test func-29.6 { set x [lindex [sqlite3_db_status db CACHE_MISS 1] 1] if {$x<5} {set x 1} set x } {1} | | > > > > > > > > > > > > > > > | 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 | db eval {SELECT sum(length(x)) FROM t29} } {1000009} do_test func-29.6 { set x [lindex [sqlite3_db_status db CACHE_MISS 1] 1] if {$x<5} {set x 1} set x } {1} do_execsql_test func-30.1 {SELECT unicode('$');} 36 do_execsql_test func-30.2 [subst {SELECT unicode('\u00A2');}] 162 do_execsql_test func-30.3 [subst {SELECT unicode('\u20AC');}] 8364 do_execsql_test func-30.4 {SELECT char(36,162,8364);} [subst {$\u00A2\u20AC}] for {set i 1} {$i<0xd800} {incr i 13} { do_execsql_test func-30.5.$i {SELECT unicode(char($i))} $i } for {set i 57344} {$i<=0xfffd} {incr i 17} { if {$i==0xfeff} continue do_execsql_test func-30.5.$i {SELECT unicode(char($i))} $i } for {set i 65536} {$i<=0x10ffff} {incr i 139} { do_execsql_test func-30.5.$i {SELECT unicode(char($i))} $i } finish_test |
Changes to test/hook.test.
︙ | ︙ | |||
70 71 72 73 74 75 76 77 78 79 80 81 82 83 | set ::commit_cnt [execsql {SELECT * FROM t2}] return 1 } catchsql { INSERT INTO t2 VALUES(6,7); } } {1 {constraint failed}} do_test hook-3.7 { set ::commit_cnt } {1 2 2 3 3 4 4 5 5 6 6 7} do_test hook-3.8 { execsql {SELECT * FROM t2} } {1 2 2 3 3 4 4 5 5 6} | > | 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | set ::commit_cnt [execsql {SELECT * FROM t2}] return 1 } catchsql { INSERT INTO t2 VALUES(6,7); } } {1 {constraint failed}} verify_ex_errcode hook-3.6b SQLITE_CONSTRAINT_COMMITHOOK do_test hook-3.7 { set ::commit_cnt } {1 2 2 3 3 4 4 5 5 6 6 7} do_test hook-3.8 { execsql {SELECT * FROM t2} } {1 2 2 3 3 4 4 5 5 6} |
︙ | ︙ |
Added test/incrvacuum3.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 | # 2013 Feb 25 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for the SQLite library, focusing # on the incremental vacuum feature. # # The tests in this file were added at the same time as optimizations # were made to: # # * Truncate the database after a rollback mode commit, and # # * Avoid moving pages to locations from which they may need to be moved # a second time if an incremental-vacuum proccess is allowed to vacuum # the entire database. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix incrvacuum3 # If this build of the library does not support auto-vacuum, omit this # whole file. ifcapable {!autovacuum || !pragma} { finish_test return } proc check_on_disk {} { # Copy the wal and journal files for database "test.db" to "test2.db". forcedelete test2.db test2.db-journal test2.db-wal if {[file exists test.db-journal]} { forcecopy test.db-journal test2.db-journal } if {[file exists test.db-wal]} { forcecopy test.db-wal test2.db-wal } # Now copy the database file itself. Do this using open/read/puts # instead of the [file copy] command in order to avoid attempting # to read the 512 bytes begining at offset $sqlite_pending_byte. # set sz [file size test.db] set fd [open test.db] set fd2 [open test2.db w] fconfigure $fd -encoding binary -translation binary fconfigure $fd2 -encoding binary -translation binary if {$sz>$::sqlite_pending_byte} { puts -nonewline $fd2 [read $fd $::sqlite_pending_byte] seek $fd [expr $::sqlite_pending_byte+512] seek $fd2 [expr $::sqlite_pending_byte+512] } puts -nonewline $fd2 [read $fd] close $fd2 close $fd # Open "test2.db" and check it is Ok. sqlite3 dbcheck test2.db set ret [dbcheck eval { PRAGMA integrity_check }] dbcheck close set ret } # Run these tests once in rollback journal mode, and once in wal mode. # foreach {T jrnl_mode} { 1 delete 2 wal } { catch { db close } forcedelete test.db test.db-journal test.db-wal sqlite3 db test.db db eval { PRAGMA cache_size = 5; PRAGMA page_size = 1024; PRAGMA auto_vacuum = 2; } db eval "PRAGMA journal_mode = $jrnl_mode" foreach {tn sql} { 1 { CREATE TABLE t1(x UNIQUE); INSERT INTO t1 VALUES(randomblob(400)); INSERT INTO t1 VALUES(randomblob(400)); INSERT INTO t1 SELECT randomblob(400) FROM t1; -- 4 INSERT INTO t1 SELECT randomblob(400) FROM t1; -- 8 INSERT INTO t1 SELECT randomblob(400) FROM t1; -- 16 INSERT INTO t1 SELECT randomblob(400) FROM t1; -- 32 INSERT INTO t1 SELECT randomblob(400) FROM t1; -- 64 INSERT INTO t1 SELECT randomblob(400) FROM t1; -- 128 INSERT INTO t1 SELECT randomblob(400) FROM t1; -- 256 } 2 { DELETE FROM t1 WHERE rowid%8; } 3 { BEGIN; PRAGMA incremental_vacuum = 100; INSERT INTO t1 SELECT randomblob(400) FROM t1; -- 64 INSERT INTO t1 SELECT randomblob(400) FROM t1; -- 128 INSERT INTO t1 SELECT randomblob(400) FROM t1; -- 256 ROLLBACK; } 4 { BEGIN; SAVEPOINT one; PRAGMA incremental_vacuum = 100; SAVEPOINT two; INSERT INTO t1 SELECT randomblob(400) FROM t1; -- 64 INSERT INTO t1 SELECT randomblob(400) FROM t1; -- 128 INSERT INTO t1 SELECT randomblob(400) FROM t1; -- 256 } 5 { ROLLBACK to two } 6 { ROLLBACK to one } 7 { INSERT INTO t1 SELECT randomblob(400) FROM t1; -- 64 PRAGMA incremental_vacuum = 1000; INSERT INTO t1 SELECT randomblob(400) FROM t1; -- 128 INSERT INTO t1 SELECT randomblob(400) FROM t1; -- 256 ROLLBACK; } 8 { BEGIN; INSERT INTO t1 SELECT randomblob(400) FROM t1; -- 64 PRAGMA incremental_vacuum = 1000; INSERT INTO t1 SELECT randomblob(400) FROM t1; -- 128 COMMIT; } } { do_execsql_test $T.1.$tn.1 $sql do_execsql_test $T.1.$tn.2 {PRAGMA integrity_check} ok do_test $T.1.$tn.3 { check_on_disk } ok } do_execsql_test $T.1.x.1 { PRAGMA freelist_count } 0 do_execsql_test $T.1.x.2 { SELECT count(*) FROM t1 } 128 } finish_test |
Changes to test/incrvacuum_ioerr.test.
︙ | ︙ | |||
135 136 137 138 139 140 141 | set ::rc 1 for {set iTest 1} {$::rc && $iTest<2000} {incr iTest} { # Figure out how big the database is and how many free pages it # has before running incremental-vacuum. # | < > > | | | 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 | set ::rc 1 for {set iTest 1} {$::rc && $iTest<2000} {incr iTest} { # Figure out how big the database is and how many free pages it # has before running incremental-vacuum. # set nFree [execsql {pragma freelist_count} db1] set nPage [execsql {pragma page_count} db1] puts "nFree=$nFree nPage=$nPage" # Now run incremental-vacuum to vacuum 5 pages from the db file. # The iTest'th I/O call is set to fail. # set ::sqlite_io_error_pending $iTest set ::sqlite_io_error_persist 1 do_test incrvacuum-ioerr-4.$iTest.1 { set ::rc [catch {execsql {pragma incremental_vacuum(5)} db1} msg] expr {$::rc==0 || $msg eq "disk I/O error"} } {1} set ::sqlite_io_error_pending 0 set ::sqlite_io_error_persist 0 set ::sqlite_io_error_hit 0 set ::sqlite_io_error_hardhit 0 set nFree2 [execsql {pragma freelist_count} db1] set nPage2 [execsql {pragma page_count} db1] do_test incrvacuum-ioerr-4.$iTest.2 { set shrink [expr {$nPage-$nPage2}] expr {$shrink==0 || $shrink==5 || ($nFree<5 && $shrink==$nFree)} } {1} do_test incrvacuum-ioerr-4.$iTest.3 { expr {$nPage - $nPage2} } [expr {$nFree - $nFree2}] } |
︙ | ︙ |
Changes to test/index5.test.
︙ | ︙ | |||
32 33 34 35 36 37 38 | } } {1024} db close testvfs tvfs tvfs filter xWrite tvfs script write_cb | | < | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | } } {1024} db close testvfs tvfs tvfs filter xWrite tvfs script write_cb proc write_cb {xCall file handle iOfst args} { if {[file tail $file]=="test.db"} { lappend ::write_list [expr $iOfst/1024] } } do_test 1.2 { sqlite3 db test.db -vfs tvfs set ::write_list [list] execsql { CREATE INDEX i1 ON t1(x) } } {} |
︙ | ︙ | |||
61 62 63 64 65 66 67 68 | } elseif {$iNext==($iPrev-1)} { incr nBackward } else { incr nNoncont } set iPrev $iNext } | > > | < | 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | } elseif {$iNext==($iPrev-1)} { incr nBackward } else { incr nNoncont } set iPrev $iNext } puts -nonewline \ " (forward=$nForward, back=$nBackward, noncontiguous=$nNoncont)" expr {$nForward > 2*($nBackward + $nNoncont)} } {1} db close tvfs delete finish_test |
Added test/ioerr6.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 | # 2012 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. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/malloc_common.tcl set ::testprefix ioerr6 ifcapable !atomicwrite { puts "skipping tests - not compiled with SQLITE_ENABLE_ATOMIC_WRITE..." finish_test return } if {[permutation]=="inmemory_journal"} { # These tests will not work with in-memory journals (as persistent VFS # errors commencing after a transaction has started to write to the db # cannot be recovered from). finish_test return } faultsim_save_and_close do_test 1.1 { testvfs shmfault -default true shmfault devchar atomic sqlite3 db test.db execsql { CREATE TABLE t1(a, b); CREATE INDEX i1 ON t1(a, b); INSERT INTO t1 VALUES(1, 2); INSERT INTO t1 VALUES(2, 4); INSERT INTO t1 VALUES(3, 6); INSERT INTO t1 VALUES(4, 8); } # Cause the first call to xWrite() to fail with SQLITE_FULL. shmfault full 2 1 catchsql { INSERT INTO t1 VALUES(5, 10) } } {1 {database or disk is full}} do_test 1.2 { execsql { PRAGMA integrity_check } } {ok} db close shmfault delete do_faultsim_test 2 -faults full* -prep { shmfault devchar atomic faultsim_restore sqlite3 db test.db } -body { db eval { CREATE TABLE t1(x PRIMARY KEY); INSERT INTO t1 VALUES('abc'); } } -test { set res [db one { PRAGMA integrity_check }] if {$res != "ok"} { error "integrity check: $res" } } do_faultsim_test 3 -faults full* -prep { shmfault devchar atomic faultsim_restore sqlite3 db test.db } -body { db eval { CREATE TABLE t1(x); CREATE TABLE t2(x); } } -test { db eval { CREATE TABLE t3(x) } if {[db one { PRAGMA integrity_check }] != "ok"} { error "integrity check failed" } } finish_test |
Changes to test/limit.test.
︙ | ︙ | |||
464 465 466 467 468 469 470 471 472 | } {1 {no such column: x}} do_test limit-12.4 { catchsql { SELECT * FROM t1 LIMIT 1 OFFSET x } } {1 {no such column: x}} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } {1 {no such column: x}} do_test limit-12.4 { catchsql { SELECT * FROM t1 LIMIT 1 OFFSET x } } {1 {no such column: x}} # Ticket [db4d96798da8b] # LIMIT does not work with nested views containing UNION ALL # do_test limit-13.1 { db eval { CREATE TABLE t13(x); INSERT INTO t13 VALUES(1),(2); CREATE VIEW v13a AS SELECT x AS y FROM t13; CREATE VIEW v13b AS SELECT y AS z FROM v13a UNION ALL SELECT y+10 FROM v13a; CREATE VIEW v13c AS SELECT z FROM v13b UNION ALL SELECT z+20 FROM v13b; } } {} do_test limit-13.2 { db eval {SELECT z FROM v13c LIMIT 1} } {1} do_test limit-13.3 { db eval {SELECT z FROM v13c LIMIT 2} } {1 2} do_test limit-13.4 { db eval {SELECT z FROM v13c LIMIT 3} } {1 2 11} do_test limit-13.5 { db eval {SELECT z FROM v13c LIMIT 4} } {1 2 11 12} do_test limit-13.6 { db eval {SELECT z FROM v13c LIMIT 5} } {1 2 11 12 21} do_test limit-13.7 { db eval {SELECT z FROM v13c LIMIT 6} } {1 2 11 12 21 22} do_test limit-13.8 { db eval {SELECT z FROM v13c LIMIT 7} } {1 2 11 12 21 22 31} do_test limit-13.9 { db eval {SELECT z FROM v13c LIMIT 8} } {1 2 11 12 21 22 31 32} do_test limit-13.10 { db eval {SELECT z FROM v13c LIMIT 9} } {1 2 11 12 21 22 31 32} do_test limit-13.11 { db eval {SELECT z FROM v13c LIMIT 1 OFFSET 1} } {2} do_test limit-13.12 { db eval {SELECT z FROM v13c LIMIT 2 OFFSET 1} } {2 11} do_test limit-13.13 { db eval {SELECT z FROM v13c LIMIT 3 OFFSET 1} } {2 11 12} do_test limit-13.14 { db eval {SELECT z FROM v13c LIMIT 4 OFFSET 1} } {2 11 12 21} do_test limit-13.15 { db eval {SELECT z FROM v13c LIMIT 5 OFFSET 1} } {2 11 12 21 22} do_test limit-13.16 { db eval {SELECT z FROM v13c LIMIT 6 OFFSET 1} } {2 11 12 21 22 31} do_test limit-13.17 { db eval {SELECT z FROM v13c LIMIT 7 OFFSET 1} } {2 11 12 21 22 31 32} do_test limit-13.18 { db eval {SELECT z FROM v13c LIMIT 8 OFFSET 1} } {2 11 12 21 22 31 32} do_test limit-13.21 { db eval {SELECT z FROM v13c LIMIT 1 OFFSET 2} } {11} do_test limit-13.22 { db eval {SELECT z FROM v13c LIMIT 2 OFFSET 2} } {11 12} do_test limit-13.23 { db eval {SELECT z FROM v13c LIMIT 3 OFFSET 2} } {11 12 21} do_test limit-13.24 { db eval {SELECT z FROM v13c LIMIT 4 OFFSET 2} } {11 12 21 22} do_test limit-13.25 { db eval {SELECT z FROM v13c LIMIT 5 OFFSET 2} } {11 12 21 22 31} do_test limit-13.26 { db eval {SELECT z FROM v13c LIMIT 6 OFFSET 2} } {11 12 21 22 31 32} do_test limit-13.27 { db eval {SELECT z FROM v13c LIMIT 7 OFFSET 2} } {11 12 21 22 31 32} do_test limit-13.31 { db eval {SELECT z FROM v13c LIMIT 1 OFFSET 3} } {12} do_test limit-13.32 { db eval {SELECT z FROM v13c LIMIT 2 OFFSET 3} } {12 21} do_test limit-13.33 { db eval {SELECT z FROM v13c LIMIT 3 OFFSET 3} } {12 21 22} do_test limit-13.34 { db eval {SELECT z FROM v13c LIMIT 4 OFFSET 3} } {12 21 22 31} do_test limit-13.35 { db eval {SELECT z FROM v13c LIMIT 5 OFFSET 3} } {12 21 22 31 32} do_test limit-13.36 { db eval {SELECT z FROM v13c LIMIT 6 OFFSET 3} } {12 21 22 31 32} do_test limit-13.41 { db eval {SELECT z FROM v13c LIMIT 1 OFFSET 4} } {21} do_test limit-13.42 { db eval {SELECT z FROM v13c LIMIT 2 OFFSET 4} } {21 22} do_test limit-13.43 { db eval {SELECT z FROM v13c LIMIT 3 OFFSET 4} } {21 22 31} do_test limit-13.44 { db eval {SELECT z FROM v13c LIMIT 4 OFFSET 4} } {21 22 31 32} do_test limit-13.45 { db eval {SELECT z FROM v13c LIMIT 5 OFFSET 4} } {21 22 31 32} do_test limit-13.51 { db eval {SELECT z FROM v13c LIMIT 1 OFFSET 5} } {22} do_test limit-13.52 { db eval {SELECT z FROM v13c LIMIT 2 OFFSET 5} } {22 31} do_test limit-13.53 { db eval {SELECT z FROM v13c LIMIT 3 OFFSET 5} } {22 31 32} do_test limit-13.54 { db eval {SELECT z FROM v13c LIMIT 4 OFFSET 5} } {22 31 32} do_test limit-13.61 { db eval {SELECT z FROM v13c LIMIT 1 OFFSET 6} } {31} do_test limit-13.62 { db eval {SELECT z FROM v13c LIMIT 2 OFFSET 6} } {31 32} do_test limit-13.63 { db eval {SELECT z FROM v13c LIMIT 3 OFFSET 6} } {31 32} do_test limit-13.71 { db eval {SELECT z FROM v13c LIMIT 1 OFFSET 7} } {32} do_test limit-13.72 { db eval {SELECT z FROM v13c LIMIT 2 OFFSET 7} } {32} do_test limit-13.81 { db eval {SELECT z FROM v13c LIMIT 1 OFFSET 8} } {} finish_test |
Changes to test/mallocG.test.
︙ | ︙ | |||
48 49 50 51 52 53 54 55 56 57 58 59 60 61 | WHERE x BETWEEN 'a' AND 'z' AND x BETWEEN 'c' AND 'w' AND x BETWEEN 'e' AND 'u' AND x BETWEEN 'g' AND 'r' AND x BETWEEN 'i' AND 'q' AND x BETWEEN 'i' AND 'm' } proc utf16 {utf8} { set utf16 [encoding convertto unicode $utf8] append utf16 "\x00\x00" return $utf16 } | > > > > > | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | WHERE x BETWEEN 'a' AND 'z' AND x BETWEEN 'c' AND 'w' AND x BETWEEN 'e' AND 'u' AND x BETWEEN 'g' AND 'r' AND x BETWEEN 'i' AND 'q' AND x BETWEEN 'i' AND 'm' } ifcapable !utf16 { finish_test return } proc utf16 {utf8} { set utf16 [encoding convertto unicode $utf8] append utf16 "\x00\x00" return $utf16 } |
︙ | ︙ |
Changes to test/minmax.test.
︙ | ︙ | |||
13 14 15 16 17 18 19 20 21 22 23 24 25 26 | # aggregate min() and max() functions and which are handled as # as a special case. # # $Id: minmax.test,v 1.21 2008/07/08 18:05:26 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl do_test minmax-1.0 { execsql { BEGIN; CREATE TABLE t1(x, y); INSERT INTO t1 VALUES(1,1); INSERT INTO t1 VALUES(2,2); | > | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | # aggregate min() and max() functions and which are handled as # as a special case. # # $Id: minmax.test,v 1.21 2008/07/08 18:05:26 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix minmax do_test minmax-1.0 { execsql { BEGIN; CREATE TABLE t1(x, y); INSERT INTO t1 VALUES(1,1); INSERT INTO t1 VALUES(2,2); |
︙ | ︙ | |||
532 533 534 535 536 537 538 539 540 541 542 | } {25} do_test minmax-12.17 { execsql { SELECT max(rowid) FROM t7 WHERE a=3 AND b=5 AND c=15; } } {5} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } {25} do_test minmax-12.17 { execsql { SELECT max(rowid) FROM t7 WHERE a=3 AND b=5 AND c=15; } } {5} #------------------------------------------------------------------------- reset_db proc do_test_13 {op name sql1 sql2 res} { set ::sqlite_search_count 0 uplevel [list do_execsql_test $name.1 $sql1 $res] set a $::sqlite_search_count set ::sqlite_search_count 0 uplevel [list do_execsql_test $name.2 $sql2 $res] set b $::sqlite_search_count uplevel [list do_test $name.3 [list expr "$a $op $b"] 1] } # Run a test named $name. Check that SQL statements $sql1 and $sql2 both # return the same result, but that $sql2 increments the $sqlite_search_count # variable more often (indicating that it is visiting more rows to determine # the result). # proc do_test_13_opt {name sql1 sql2 res} { uplevel [list do_test_13 < $name $sql1 $sql2 $res] } # Like [do_test_13_noopt], except this time check that the $sqlite_search_count # variable is incremented the same number of times by both SQL statements. # proc do_test_13_noopt {name sql1 sql2 res} { uplevel [list do_test_13 == $name $sql1 $sql2 $res] } do_execsql_test 13.1 { CREATE TABLE t1(a, b, c); INSERT INTO t1 VALUES('a', 1, 1); INSERT INTO t1 VALUES('b', 6, 6); INSERT INTO t1 VALUES('c', 5, 5); INSERT INTO t1 VALUES('a', 4, 4); INSERT INTO t1 VALUES('a', 5, 5); INSERT INTO t1 VALUES('c', 6, 6); INSERT INTO t1 VALUES('b', 4, 4); INSERT INTO t1 VALUES('c', 7, 7); INSERT INTO t1 VALUES('b', 2, 2); INSERT INTO t1 VALUES('b', 3, 3); INSERT INTO t1 VALUES('a', 3, 3); INSERT INTO t1 VALUES('b', 5, 5); INSERT INTO t1 VALUES('c', 4, 4); INSERT INTO t1 VALUES('c', 3, 3); INSERT INTO t1 VALUES('a', 2, 2); SELECT * FROM t1 ORDER BY a, b, c; } {a 1 1 a 2 2 a 3 3 a 4 4 a 5 5 b 2 2 b 3 3 b 4 4 b 5 5 b 6 6 c 3 3 c 4 4 c 5 5 c 6 6 c 7 7 } do_execsql_test 13.2 { CREATE INDEX i1 ON t1(a, b, c) } do_test_13_opt 13.3 { SELECT min(b) FROM t1 WHERE a='b' } { SELECT min(c) FROM t1 WHERE a='b' } {2} do_test_13_opt 13.4 { SELECT a, min(b) FROM t1 WHERE a='b' } { SELECT a, min(c) FROM t1 WHERE a='b' } {b 2} do_test_13_opt 13.4 { SELECT a||c, max(b)+4 FROM t1 WHERE a='c' } { SELECT a||c, max(c)+4 FROM t1 WHERE a='c' } {c7 11} do_test_13_noopt 13.5 { SELECT a||c, max(b+1) FROM t1 WHERE a='c' } { SELECT a||c, max(c+1) FROM t1 WHERE a='c' } {c7 8} do_test_13_noopt 13.6 { SELECT count(b) FROM t1 WHERE a='c' } { SELECT count(c) FROM t1 WHERE a='c' } {5} do_test_13_noopt 13.7 { SELECT min(b), count(b) FROM t1 WHERE a='a'; } { SELECT min(c), count(c) FROM t1 WHERE a='a'; } {1 5} finish_test |
Changes to test/misc7.test.
︙ | ︙ | |||
484 485 486 487 488 489 490 491 492 493 494 495 | # do_test misc7-21.1 { set zFile [file join [get_pwd] "[string repeat abcde 104].db"] set rc [catch {sqlite3 db2 $zFile} msg] list $rc $msg } {1 {unable to open database file}} db close forcedelete test.db finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # do_test misc7-21.1 { set zFile [file join [get_pwd] "[string repeat abcde 104].db"] set rc [catch {sqlite3 db2 $zFile} msg] list $rc $msg } {1 {unable to open database file}} # Try to do hot-journal rollback with a read-only connection. The # error code should be SQLITE_READONLY_ROLLBACK. # do_test misc7-22.1 { db close forcedelete test.db copy.db-journal sqlite3 db test.db execsql { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 2); INSERT INTO t1 VALUES(3, 4); } db close sqlite3 db test.db -readonly 1 catchsql { INSERT INTO t1 VALUES(5, 6); } } {1 {attempt to write a readonly database}} do_test misc7-22.2 { execsql { SELECT * FROM t1 } } {1 2 3 4} do_test misc7-22.3 { set fd [open test.db-journal w] puts $fd [string repeat abc 1000] close $fd catchsql { SELECT * FROM t1 } } {1 {attempt to write a readonly database}} do_test misc7-22.4 { sqlite3_extended_errcode db } SQLITE_READONLY_ROLLBACK db close forcedelete test.db finish_test |
Changes to test/notnull.test.
︙ | ︙ | |||
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | do_test notnull-1.2 { catchsql { DELETE FROM t1; INSERT INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } } {1 {t1.a may not be NULL}} do_test notnull-1.3 { catchsql { DELETE FROM t1; INSERT OR IGNORE INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } } {0 {}} do_test notnull-1.4 { catchsql { DELETE FROM t1; INSERT OR REPLACE INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } } {1 {t1.a may not be NULL}} do_test notnull-1.5 { catchsql { DELETE FROM t1; INSERT OR ABORT INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } } {1 {t1.a may not be NULL}} do_test notnull-1.6 { catchsql { DELETE FROM t1; INSERT INTO t1(a,c,d,e) VALUES(1,3,4,5); SELECT * FROM t1 order by a; } } {0 {1 5 3 4 5}} | > > > | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | do_test notnull-1.2 { catchsql { DELETE FROM t1; INSERT INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } } {1 {t1.a may not be NULL}} verify_ex_errcode notnull-1.2b SQLITE_CONSTRAINT_NOTNULL do_test notnull-1.3 { catchsql { DELETE FROM t1; INSERT OR IGNORE INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } } {0 {}} do_test notnull-1.4 { catchsql { DELETE FROM t1; INSERT OR REPLACE INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } } {1 {t1.a may not be NULL}} verify_ex_errcode notnull-1.4b SQLITE_CONSTRAINT_NOTNULL do_test notnull-1.5 { catchsql { DELETE FROM t1; INSERT OR ABORT INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } } {1 {t1.a may not be NULL}} verify_ex_errcode notnull-1.5b SQLITE_CONSTRAINT_NOTNULL do_test notnull-1.6 { catchsql { DELETE FROM t1; INSERT INTO t1(a,c,d,e) VALUES(1,3,4,5); SELECT * FROM t1 order by a; } } {0 {1 5 3 4 5}} |
︙ | ︙ | |||
100 101 102 103 104 105 106 107 108 109 110 111 112 113 | do_test notnull-1.10 { catchsql { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,null,3,4,5); SELECT * FROM t1 order by a; } } {1 {t1.b may not be NULL}} do_test notnull-1.11 { catchsql { DELETE FROM t1; INSERT OR IGNORE INTO t1(a,b,c,d,e) VALUES(1,null,3,4,5); SELECT * FROM t1 order by a; } } {0 {}} | > | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | do_test notnull-1.10 { catchsql { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,null,3,4,5); SELECT * FROM t1 order by a; } } {1 {t1.b may not be NULL}} verify_ex_errcode notnull-1.10b SQLITE_CONSTRAINT_NOTNULL do_test notnull-1.11 { catchsql { DELETE FROM t1; INSERT OR IGNORE INTO t1(a,b,c,d,e) VALUES(1,null,3,4,5); SELECT * FROM t1 order by a; } } {0 {}} |
︙ | ︙ | |||
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | do_test notnull-1.16 { catchsql { DELETE FROM t1; INSERT OR ABORT INTO t1(a,b,c,d,e) VALUES(1,2,null,4,5); SELECT * FROM t1 order by a; } } {1 {t1.c may not be NULL}} do_test notnull-1.17 { catchsql { DELETE FROM t1; INSERT OR ABORT INTO t1(a,b,c,d,e) VALUES(1,2,3,null,5); SELECT * FROM t1 order by a; } } {1 {t1.d may not be NULL}} do_test notnull-1.18 { catchsql { DELETE FROM t1; INSERT OR ABORT INTO t1(a,b,c,e) VALUES(1,2,3,5); SELECT * FROM t1 order by a; } } {0 {1 2 3 7 5}} | > > | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | do_test notnull-1.16 { catchsql { DELETE FROM t1; INSERT OR ABORT INTO t1(a,b,c,d,e) VALUES(1,2,null,4,5); SELECT * FROM t1 order by a; } } {1 {t1.c may not be NULL}} verify_ex_errcode notnull-1.16b SQLITE_CONSTRAINT_NOTNULL do_test notnull-1.17 { catchsql { DELETE FROM t1; INSERT OR ABORT INTO t1(a,b,c,d,e) VALUES(1,2,3,null,5); SELECT * FROM t1 order by a; } } {1 {t1.d may not be NULL}} verify_ex_errcode notnull-1.17b SQLITE_CONSTRAINT_NOTNULL do_test notnull-1.18 { catchsql { DELETE FROM t1; INSERT OR ABORT INTO t1(a,b,c,e) VALUES(1,2,3,5); SELECT * FROM t1 order by a; } } {0 {1 2 3 7 5}} |
︙ | ︙ | |||
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 | do_test notnull-1.20 { catchsql { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,null); SELECT * FROM t1 order by a; } } {1 {t1.e may not be NULL}} do_test notnull-1.21 { catchsql { DELETE FROM t1; INSERT OR REPLACE INTO t1(e,d,c,b,a) VALUES(1,2,3,null,5); SELECT * FROM t1 order by a; } } {0 {5 5 3 2 1}} do_test notnull-2.1 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); UPDATE t1 SET a=null; SELECT * FROM t1 ORDER BY a; } } {1 {t1.a may not be NULL}} do_test notnull-2.2 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); UPDATE OR REPLACE t1 SET a=null; SELECT * FROM t1 ORDER BY a; } } {1 {t1.a may not be NULL}} do_test notnull-2.3 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); UPDATE OR IGNORE t1 SET a=null; SELECT * FROM t1 ORDER BY a; } } {0 {1 2 3 4 5}} do_test notnull-2.4 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); UPDATE OR ABORT t1 SET a=null; SELECT * FROM t1 ORDER BY a; } } {1 {t1.a may not be NULL}} do_test notnull-2.5 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); UPDATE t1 SET b=null; SELECT * FROM t1 ORDER BY a; } } {1 {t1.b may not be NULL}} do_test notnull-2.6 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); UPDATE OR REPLACE t1 SET b=null, d=e, e=d; SELECT * FROM t1 ORDER BY a; } | > > > > > | 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 | do_test notnull-1.20 { catchsql { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,null); SELECT * FROM t1 order by a; } } {1 {t1.e may not be NULL}} verify_ex_errcode notnull-1.20b SQLITE_CONSTRAINT_NOTNULL do_test notnull-1.21 { catchsql { DELETE FROM t1; INSERT OR REPLACE INTO t1(e,d,c,b,a) VALUES(1,2,3,null,5); SELECT * FROM t1 order by a; } } {0 {5 5 3 2 1}} do_test notnull-2.1 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); UPDATE t1 SET a=null; SELECT * FROM t1 ORDER BY a; } } {1 {t1.a may not be NULL}} verify_ex_errcode notnull-2.1b SQLITE_CONSTRAINT_NOTNULL do_test notnull-2.2 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); UPDATE OR REPLACE t1 SET a=null; SELECT * FROM t1 ORDER BY a; } } {1 {t1.a may not be NULL}} verify_ex_errcode notnull-2.2b SQLITE_CONSTRAINT_NOTNULL do_test notnull-2.3 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); UPDATE OR IGNORE t1 SET a=null; SELECT * FROM t1 ORDER BY a; } } {0 {1 2 3 4 5}} do_test notnull-2.4 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); UPDATE OR ABORT t1 SET a=null; SELECT * FROM t1 ORDER BY a; } } {1 {t1.a may not be NULL}} verify_ex_errcode notnull-2.4b SQLITE_CONSTRAINT_NOTNULL do_test notnull-2.5 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); UPDATE t1 SET b=null; SELECT * FROM t1 ORDER BY a; } } {1 {t1.b may not be NULL}} verify_ex_errcode notnull-2.6b SQLITE_CONSTRAINT_NOTNULL do_test notnull-2.6 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); UPDATE OR REPLACE t1 SET b=null, d=e, e=d; SELECT * FROM t1 ORDER BY a; } |
︙ | ︙ | |||
258 259 260 261 262 263 264 265 266 267 268 269 270 271 | 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}} do_test notnull-3.0 { execsql { CREATE INDEX t1a ON t1(a); CREATE INDEX t1b ON t1(b); CREATE INDEX t1c ON t1(c); CREATE INDEX t1d ON t1(d); | > | 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 | 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}} verify_ex_errcode notnull-2.10b SQLITE_CONSTRAINT_NOTNULL do_test notnull-3.0 { execsql { CREATE INDEX t1a ON t1(a); CREATE INDEX t1b ON t1(b); CREATE INDEX t1c ON t1(c); CREATE INDEX t1d ON t1(d); |
︙ | ︙ | |||
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 | do_test notnull-3.2 { catchsql { DELETE FROM t1; INSERT INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } } {1 {t1.a may not be NULL}} do_test notnull-3.3 { catchsql { DELETE FROM t1; INSERT OR IGNORE INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } } {0 {}} do_test notnull-3.4 { catchsql { DELETE FROM t1; INSERT OR REPLACE INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } } {1 {t1.a may not be NULL}} do_test notnull-3.5 { catchsql { DELETE FROM t1; INSERT OR ABORT INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } } {1 {t1.a may not be NULL}} do_test notnull-3.6 { catchsql { DELETE FROM t1; INSERT INTO t1(a,c,d,e) VALUES(1,3,4,5); SELECT * FROM t1 order by a; } } {0 {1 5 3 4 5}} | > > > | 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 | do_test notnull-3.2 { catchsql { DELETE FROM t1; INSERT INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } } {1 {t1.a may not be NULL}} verify_ex_errcode notnull-3.2b SQLITE_CONSTRAINT_NOTNULL do_test notnull-3.3 { catchsql { DELETE FROM t1; INSERT OR IGNORE INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } } {0 {}} do_test notnull-3.4 { catchsql { DELETE FROM t1; INSERT OR REPLACE INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } } {1 {t1.a may not be NULL}} verify_ex_errcode notnull-3.4b SQLITE_CONSTRAINT_NOTNULL do_test notnull-3.5 { catchsql { DELETE FROM t1; INSERT OR ABORT INTO t1(b,c,d,e) VALUES(2,3,4,5); SELECT * FROM t1 order by a; } } {1 {t1.a may not be NULL}} verify_ex_errcode notnull-3.5b SQLITE_CONSTRAINT_NOTNULL do_test notnull-3.6 { catchsql { DELETE FROM t1; INSERT INTO t1(a,c,d,e) VALUES(1,3,4,5); SELECT * FROM t1 order by a; } } {0 {1 5 3 4 5}} |
︙ | ︙ | |||
339 340 341 342 343 344 345 346 347 348 349 350 351 352 | do_test notnull-3.10 { catchsql { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,null,3,4,5); SELECT * FROM t1 order by a; } } {1 {t1.b may not be NULL}} do_test notnull-3.11 { catchsql { DELETE FROM t1; INSERT OR IGNORE INTO t1(a,b,c,d,e) VALUES(1,null,3,4,5); SELECT * FROM t1 order by a; } } {0 {}} | > | 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 | do_test notnull-3.10 { catchsql { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,null,3,4,5); SELECT * FROM t1 order by a; } } {1 {t1.b may not be NULL}} verify_ex_errcode notnull-3.10b SQLITE_CONSTRAINT_NOTNULL do_test notnull-3.11 { catchsql { DELETE FROM t1; INSERT OR IGNORE INTO t1(a,b,c,d,e) VALUES(1,null,3,4,5); SELECT * FROM t1 order by a; } } {0 {}} |
︙ | ︙ | |||
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 | do_test notnull-3.16 { catchsql { DELETE FROM t1; INSERT OR ABORT INTO t1(a,b,c,d,e) VALUES(1,2,null,4,5); SELECT * FROM t1 order by a; } } {1 {t1.c may not be NULL}} do_test notnull-3.17 { catchsql { DELETE FROM t1; INSERT OR ABORT INTO t1(a,b,c,d,e) VALUES(1,2,3,null,5); SELECT * FROM t1 order by a; } } {1 {t1.d may not be NULL}} do_test notnull-3.18 { catchsql { DELETE FROM t1; INSERT OR ABORT INTO t1(a,b,c,e) VALUES(1,2,3,5); SELECT * FROM t1 order by a; } } {0 {1 2 3 7 5}} | > > | 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 | do_test notnull-3.16 { catchsql { DELETE FROM t1; INSERT OR ABORT INTO t1(a,b,c,d,e) VALUES(1,2,null,4,5); SELECT * FROM t1 order by a; } } {1 {t1.c may not be NULL}} verify_ex_errcode notnull-3.16b SQLITE_CONSTRAINT_NOTNULL do_test notnull-3.17 { catchsql { DELETE FROM t1; INSERT OR ABORT INTO t1(a,b,c,d,e) VALUES(1,2,3,null,5); SELECT * FROM t1 order by a; } } {1 {t1.d may not be NULL}} verify_ex_errcode notnull-3.17b SQLITE_CONSTRAINT_NOTNULL do_test notnull-3.18 { catchsql { DELETE FROM t1; INSERT OR ABORT INTO t1(a,b,c,e) VALUES(1,2,3,5); SELECT * FROM t1 order by a; } } {0 {1 2 3 7 5}} |
︙ | ︙ | |||
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 | do_test notnull-3.20 { catchsql { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,null); SELECT * FROM t1 order by a; } } {1 {t1.e may not be NULL}} do_test notnull-3.21 { catchsql { DELETE FROM t1; INSERT OR REPLACE INTO t1(e,d,c,b,a) VALUES(1,2,3,null,5); SELECT * FROM t1 order by a; } } {0 {5 5 3 2 1}} do_test notnull-4.1 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); UPDATE t1 SET a=null; SELECT * FROM t1 ORDER BY a; } } {1 {t1.a may not be NULL}} do_test notnull-4.2 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); UPDATE OR REPLACE t1 SET a=null; SELECT * FROM t1 ORDER BY a; } } {1 {t1.a may not be NULL}} do_test notnull-4.3 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); UPDATE OR IGNORE t1 SET a=null; SELECT * FROM t1 ORDER BY a; } } {0 {1 2 3 4 5}} do_test notnull-4.4 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); UPDATE OR ABORT t1 SET a=null; SELECT * FROM t1 ORDER BY a; } } {1 {t1.a may not be NULL}} do_test notnull-4.5 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); UPDATE t1 SET b=null; SELECT * FROM t1 ORDER BY a; } } {1 {t1.b may not be NULL}} do_test notnull-4.6 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); UPDATE OR REPLACE t1 SET b=null, d=e, e=d; SELECT * FROM t1 ORDER BY a; } | > > > > > | 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 | do_test notnull-3.20 { catchsql { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,null); SELECT * FROM t1 order by a; } } {1 {t1.e may not be NULL}} verify_ex_errcode notnull-3.20b SQLITE_CONSTRAINT_NOTNULL do_test notnull-3.21 { catchsql { DELETE FROM t1; INSERT OR REPLACE INTO t1(e,d,c,b,a) VALUES(1,2,3,null,5); SELECT * FROM t1 order by a; } } {0 {5 5 3 2 1}} do_test notnull-4.1 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); UPDATE t1 SET a=null; SELECT * FROM t1 ORDER BY a; } } {1 {t1.a may not be NULL}} verify_ex_errcode notnull-4.1b SQLITE_CONSTRAINT_NOTNULL do_test notnull-4.2 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); UPDATE OR REPLACE t1 SET a=null; SELECT * FROM t1 ORDER BY a; } } {1 {t1.a may not be NULL}} verify_ex_errcode notnull-4.2b SQLITE_CONSTRAINT_NOTNULL do_test notnull-4.3 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); UPDATE OR IGNORE t1 SET a=null; SELECT * FROM t1 ORDER BY a; } } {0 {1 2 3 4 5}} do_test notnull-4.4 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); UPDATE OR ABORT t1 SET a=null; SELECT * FROM t1 ORDER BY a; } } {1 {t1.a may not be NULL}} verify_ex_errcode notnull-4.4b SQLITE_CONSTRAINT_NOTNULL do_test notnull-4.5 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); UPDATE t1 SET b=null; SELECT * FROM t1 ORDER BY a; } } {1 {t1.b may not be NULL}} verify_ex_errcode notnull-4.5b SQLITE_CONSTRAINT_NOTNULL do_test notnull-4.6 { catchsql { DELETE FROM t1; INSERT INTO t1 VALUES(1,2,3,4,5); UPDATE OR REPLACE t1 SET b=null, d=e, e=d; SELECT * FROM t1 ORDER BY a; } |
︙ | ︙ | |||
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 | 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 | > > > < | 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 | 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}} verify_ex_errcode notnull-4.10b SQLITE_CONSTRAINT_NOTNULL # 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}} verify_ex_errcode notnull-5.2b SQLITE_CONSTRAINT_NOTNULL 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}} verify_ex_errcode notnull-5.4b SQLITE_CONSTRAINT_NOTNULL do_test notnull-5.5 { execsql { SELECT * FROM t1 } } {1 2} finish_test |
Added test/orderby3.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 | # 2013 January 09 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing that the optimizations that disable # ORDER BY clauses work correctly on a 3-way join. See ticket # http://www.sqlite.org/src/956e4d7f89 # set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix orderby3 # Generate test data for a join. Verify that the join gets the # correct answer. # do_execsql_test 1.0 { CREATE TABLE t1(a INTEGER PRIMARY KEY); CREATE TABLE t2(b INTEGER PRIMARY KEY, c INTEGER); CREATE TABLE t3(d INTEGER); INSERT INTO t1 VALUES(1),(2),(3); INSERT INTO t2 VALUES(3, 1); INSERT INTO t2 VALUES(4, 2); INSERT INTO t2 VALUES(5, 3); INSERT INTO t3 VALUES(4),(3),(5); } {} do_execsql_test 1.1.asc { SELECT t1.a FROM t1, t2, t3 WHERE t1.a=t2.c AND t2.b=t3.d ORDER BY t1.a; } {1 2 3} do_execsql_test 1.1.desc { SELECT t1.a FROM t1, t2, t3 WHERE t1.a=t2.c AND t2.b=t3.d ORDER BY t1.a DESC; } {3 2 1} do_execsql_test 1.123.asc { SELECT t1.a FROM t1 CROSS JOIN t2 CROSS JOIN t3 WHERE t1.a=t2.c AND t2.b=t3.d ORDER BY t1.a; } {1 2 3} do_execsql_test 1.123.desc { SELECT t1.a FROM t1 CROSS JOIN t2 CROSS JOIN t3 WHERE t1.a=t2.c AND t2.b=t3.d ORDER BY t1.a DESC; } {3 2 1} do_execsql_test 1.132.asc { SELECT t1.a FROM t1 CROSS JOIN t3 CROSS JOIN t2 WHERE t1.a=t2.c AND t2.b=t3.d ORDER BY t1.a; } {1 2 3} do_execsql_test 1.132.desc { SELECT t1.a FROM t1 CROSS JOIN t3 CROSS JOIN t2 WHERE t1.a=t2.c AND t2.b=t3.d ORDER BY t1.a DESC; } {3 2 1} do_execsql_test 1.213.asc { SELECT t1.a FROM t2 CROSS JOIN t1 CROSS JOIN t3 WHERE t1.a=t2.c AND t2.b=t3.d ORDER BY t1.a; } {1 2 3} do_execsql_test 1.213.desc { SELECT t1.a FROM t2 CROSS JOIN t1 CROSS JOIN t3 WHERE t1.a=t2.c AND t2.b=t3.d ORDER BY t1.a DESC; } {3 2 1} do_execsql_test 1.231.asc { SELECT t1.a FROM t2 CROSS JOIN t3 CROSS JOIN t1 WHERE t1.a=t2.c AND t2.b=t3.d ORDER BY t1.a; } {1 2 3} do_execsql_test 1.231.desc { SELECT t1.a FROM t2 CROSS JOIN t3 CROSS JOIN t1 WHERE t1.a=t2.c AND t2.b=t3.d ORDER BY t1.a DESC; } {3 2 1} do_execsql_test 1.312.asc { SELECT t1.a FROM t3 CROSS JOIN t1 CROSS JOIN t2 WHERE t1.a=t2.c AND t2.b=t3.d ORDER BY t1.a; } {1 2 3} do_execsql_test 1.312.desc { SELECT t1.a FROM t3 CROSS JOIN t1 CROSS JOIN t2 WHERE t1.a=t2.c AND t2.b=t3.d ORDER BY t1.a DESC; } {3 2 1} do_execsql_test 1.321.asc { SELECT t1.a FROM t3 CROSS JOIN t2 CROSS JOIN t1 WHERE t1.a=t2.c AND t2.b=t3.d ORDER BY t1.a; } {1 2 3} do_execsql_test 1.321.desc { SELECT t1.a FROM t3 CROSS JOIN t2 CROSS JOIN t1 WHERE t1.a=t2.c AND t2.b=t3.d ORDER BY t1.a DESC; } {3 2 1} finish_test |
Changes to test/pager1.test.
︙ | ︙ | |||
748 749 750 751 752 753 754 | faultsim_restore_and_reopen db close sqlite3 db test.db -readonly 1 do_catchsql_test pager1.4.5.6 { SELECT * FROM t1; SELECT * FROM t2; | | | 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 | faultsim_restore_and_reopen db close sqlite3 db test.db -readonly 1 do_catchsql_test pager1.4.5.6 { SELECT * FROM t1; SELECT * FROM t2; } {1 {attempt to write a readonly database}} db close # Snapshot the file-system just before multi-file commit. Save the name # of the master journal file in $::mj_filename. # tv script copy_on_mj_delete tv filter xDelete |
︙ | ︙ | |||
879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 | INSERT INTO t1 VALUES('IV', 'sixteen'); INSERT INTO t1 VALUES('V' , 'twentyfive'); COMMIT; } {delete} tv filter {} db close tv delete do_test pager1.4.7.2 { faultsim_restore_and_reopen catch {file attributes test.db-journal -permissions r--------} catch {file attributes test.db-journal -readonly 1} catchsql { SELECT * FROM t1 } } {1 {unable to open database file}} do_test pager1.4.7.3 { db close catch {file attributes test.db-journal -permissions rw-rw-rw-} catch {file attributes test.db-journal -readonly 0} delete_file test.db-journal file exists test.db-journal } {0} | > > > > > > > > | 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 | INSERT INTO t1 VALUES('IV', 'sixteen'); INSERT INTO t1 VALUES('V' , 'twentyfive'); COMMIT; } {delete} tv filter {} db close tv delete catch { test_syscall install fchmod test_syscall fault 1 1 } do_test pager1.4.7.2 { faultsim_restore_and_reopen catch {file attributes test.db-journal -permissions r--------} catch {file attributes test.db-journal -readonly 1} catchsql { SELECT * FROM t1 } } {1 {unable to open database file}} catch { test_syscall reset test_syscall fault 0 0 } do_test pager1.4.7.3 { db close catch {file attributes test.db-journal -permissions rw-rw-rw-} catch {file attributes test.db-journal -readonly 0} delete_file test.db-journal file exists test.db-journal } {0} |
︙ | ︙ |
Changes to test/pragma.test.
︙ | ︙ | |||
530 531 532 533 534 535 536 | do_test pragma-6.2.2 { execsql { CREATE TABLE t5( a TEXT DEFAULT CURRENT_TIMESTAMP, b DEFAULT (5+3), c TEXT, d INTEGER DEFAULT NULL, | | > > | > > > > > > | 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 | do_test pragma-6.2.2 { execsql { CREATE TABLE t5( a TEXT DEFAULT CURRENT_TIMESTAMP, b DEFAULT (5+3), c TEXT, d INTEGER DEFAULT NULL, e TEXT DEFAULT '', UNIQUE(b,c,d), PRIMARY KEY(e,b,c) ); PRAGMA table_info(t5); } } {0 a TEXT 0 CURRENT_TIMESTAMP 0 1 b {} 0 5+3 2 2 c TEXT 0 <<NULL>> 3 3 d INTEGER 0 NULL 0 4 e TEXT 0 '' 1} db nullvalue {} do_test pragma-6.2.3 { execsql { CREATE TABLE t2_3(a,b INTEGER PRIMARY KEY,c); pragma table_info(t2_3) } } {0 a {} 0 {} 0 1 b INTEGER 0 {} 1 2 c {} 0 {} 0} 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} |
︙ | ︙ | |||
1614 1615 1616 1617 1618 1619 1620 | do_test 22.4.2 { execsql { PRAGMA main.integrity_check; } } [list $mainerr] do_test 22.4.3 { execsql { PRAGMA aux.integrity_check; } } {ok} | > > > > | > > > > > | > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_test 22.4.2 { execsql { PRAGMA main.integrity_check; } } [list $mainerr] do_test 22.4.3 { execsql { PRAGMA aux.integrity_check; } } {ok} db close forcedelete test.db test.db-wal test.db-journal sqlite3 db test.db sqlite3 db2 test.db do_test 23.1 { db eval { CREATE TABLE t1(a INTEGER PRIMARY KEY,b,c,d); CREATE INDEX i1 ON t1(b,c); CREATE INDEX i2 ON t1(c,d); CREATE TABLE t2(x INTEGER REFERENCES t1); } db2 eval {SELECT name FROM sqlite_master} } {t1 i1 i2 t2} do_test 23.2 { db eval { DROP INDEX i2; CREATE INDEX i2 ON t1(c,d,b); } db2 eval {PRAGMA index_info(i2)} } {0 2 c 1 3 d 2 1 b} do_test 23.3 { db eval { CREATE INDEX i3 ON t1(d,b,c); } db2 eval {PRAGMA index_list(t1)} } {0 i3 0 1 i2 0 2 i1 0} do_test 23.4 { db eval { ALTER TABLE t1 ADD COLUMN e; } db2 eval { PRAGMA table_info(t1); } } {/4 e {} 0 {} 0/} do_test 23.5 { db eval { DROP TABLE t2; CREATE TABLE t2(x, y INTEGER REFERENCES t1); } db2 eval { PRAGMA foreign_key_list(t2); } } {0 0 t1 y {} {NO ACTION} {NO ACTION} NONE} finish_test |
Added test/regexp1.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 | # 2012 December 31 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # This file implements test for the REGEXP operator in test_regexp.c. # set testdir [file dirname $argv0] source $testdir/tester.tcl do_test regexp1-1.1 { sqlite3_add_regexp_func db db eval { CREATE TABLE t1(x INTEGER PRIMARY KEY, y TEXT); INSERT INTO t1 VALUES(1, 'For since by man came death,'); INSERT INTO t1 VALUES(2, 'by man came also the resurrection of the dead.'); INSERT INTO t1 VALUES(3, 'For as in Adam all die,'); INSERT INTO t1 VALUES(4, 'even so in Christ shall all be made alive.'); SELECT x FROM t1 WHERE y REGEXP '^For ' ORDER BY x; } } {1 3} do_execsql_test regexp1-1.2 { SELECT x FROM t1 WHERE y REGEXP 'by|in' ORDER BY x; } {1 2 3 4} do_execsql_test regexp1-1.3 { SELECT x FROM t1 WHERE y REGEXP 'by|Christ' ORDER BY x; } {1 2 4} do_execsql_test regexp1-1.4 { SELECT x FROM t1 WHERE y REGEXP 'shal+ al+' ORDER BY x; } {4} do_execsql_test regexp1-1.5 { SELECT x FROM t1 WHERE y REGEXP 'shall x*y*z*all' ORDER BY x; } {4} do_execsql_test regexp1-1.6 { SELECT x FROM t1 WHERE y REGEXP 'shallx?y? ?z?all' ORDER BY x; } {4} do_execsql_test regexp1-1.7 { SELECT x FROM t1 WHERE y REGEXP 'r{2}' ORDER BY x; } {2} do_execsql_test regexp1-1.8 { SELECT x FROM t1 WHERE y REGEXP 'r{3}' ORDER BY x; } {} do_execsql_test regexp1-1.9 { SELECT x FROM t1 WHERE y REGEXP 'r{1}' ORDER BY x; } {1 2 3 4} do_execsql_test regexp1-1.10 { SELECT x FROM t1 WHERE y REGEXP 'ur{2,10}e' ORDER BY x; } {2} do_execsql_test regexp1-1.11 { SELECT x FROM t1 WHERE y REGEXP '[Aa]dam' ORDER BY x; } {3} do_execsql_test regexp1-1.12 { SELECT x FROM t1 WHERE y REGEXP '[^Aa]dam' ORDER BY x; } {} do_execsql_test regexp1-1.13 { SELECT x FROM t1 WHERE y REGEXP '[^b-zB-Z]dam' ORDER BY x; } {3} do_execsql_test regexp1-1.14 { SELECT x FROM t1 WHERE y REGEXP 'alive' ORDER BY x; } {4} do_execsql_test regexp1-1.15 { SELECT x FROM t1 WHERE y REGEXP '^alive' ORDER BY x; } {} do_execsql_test regexp1-1.16 { SELECT x FROM t1 WHERE y REGEXP 'alive$' ORDER BY x; } {} do_execsql_test regexp1-1.17 { SELECT x FROM t1 WHERE y REGEXP 'alive.$' ORDER BY x; } {4} do_execsql_test regexp1-1.18 { SELECT x FROM t1 WHERE y REGEXP 'alive\.$' ORDER BY x; } {4} do_execsql_test regexp1-1.19 { SELECT x FROM t1 WHERE y REGEXP 'ma[nd]' ORDER BY x; } {1 2 4} do_execsql_test regexp1-1.20 { SELECT x FROM t1 WHERE y REGEXP '\bma[nd]' ORDER BY x; } {1 2 4} do_execsql_test regexp1-1.21 { SELECT x FROM t1 WHERE y REGEXP 'ma[nd]\b' ORDER BY x; } {1 2} do_execsql_test regexp1-1.22 { SELECT x FROM t1 WHERE y REGEXP 'ma\w' ORDER BY x; } {1 2 4} do_execsql_test regexp1-1.23 { SELECT x FROM t1 WHERE y REGEXP 'ma\W' ORDER BY x; } {} do_execsql_test regexp1-1.24 { SELECT x FROM t1 WHERE y REGEXP '\sma\w' ORDER BY x; } {1 2 4} do_execsql_test regexp1-1.25 { SELECT x FROM t1 WHERE y REGEXP '\Sma\w' ORDER BY x; } {} do_execsql_test regexp1-1.26 { SELECT x FROM t1 WHERE y REGEXP 'alive\S$' ORDER BY x; } {4} do_execsql_test regexp1-1.27 { SELECT x FROM t1 WHERE y REGEXP '\b(unto|us|son|given|his|name|called|' || 'wonderful|councelor|mighty|god|everlasting|father|' || 'prince|peace|alive)\b'; } {4} do_execsql_test regexp1-2.1 { SELECT 'aaaabbbbcccc' REGEXP 'ab*c', 'aaaacccc' REGEXP 'ab*c'; } {1 1} do_execsql_test regexp1-2.2 { SELECT 'aaaabbbbcccc' REGEXP 'ab+c', 'aaaacccc' REGEXP 'ab+c'; } {1 0} do_execsql_test regexp1-2.3 { SELECT 'aaaabbbbcccc' REGEXP 'ab?c', 'aaaacccc' REGEXP 'ab?c'; } {0 1} do_execsql_test regexp1-2.4 { SELECT 'aaaabbbbbbcccc' REGEXP 'ab{3,5}c', 'aaaabbbbbcccc' REGEXP 'ab{3,5}c', 'aaaabbbbcccc' REGEXP 'ab{3,5}c', 'aaaabbbcccc' REGEXP 'ab{3,5}c', 'aaaabbcccc' REGEXP 'ab{3,5}c', 'aaaabcccc' REGEXP 'ab{3,5}c' } {0 1 1 1 0 0} do_execsql_test regexp1-2.5 { SELECT 'aaaabbbbcccc' REGEXP 'a(a|b|c)+c', 'aaaabbbbcccc' REGEXP '^a(a|b|c){11}c$', 'aaaabbbbcccc' REGEXP '^a(a|b|c){10}c$', 'aaaabbbbcccc' REGEXP '^a(a|b|c){9}c$' } {1 0 1 0} do_execsql_test regexp1-2.6 { SELECT 'aaaabbbbcccc' REGEXP '^a(a|bb|c)+c$', 'aaaabbbbcccc' REGEXP '^a(a|bbb|c)+c$', 'aaaabbbbcccc' REGEXP '^a(a|bbbb|c)+c$' } {1 0 1} do_execsql_test regexp1-2.7 { SELECT 'aaaabbbbcccc' REGEXP '^a([ac]+|bb){3}c$', 'aaaabbbbcccc' REGEXP '^a([ac]+|bb){4}c$', 'aaaabbbbcccc' REGEXP '^a([ac]+|bb){5}c$' } {0 1 1} do_execsql_test regexp1-2.8 { SELECT 'abc*def+ghi.jkl[mno]pqr' REGEXP 'c.d', 'abc*def+ghi.jkl[mno]pqr' REGEXP 'c\*d', 'abc*def+ghi.jkl[mno]pqr' REGEXP 'f\+g', 'abc*def+ghi.jkl[mno]pqr' REGEXP 'i\.j', 'abc*def+ghi.jkl[mno]pqr' REGEXP 'l\[mno\]p' } {1 1 1 1 1} do_test regexp1-2.9 { set v1 "abc\ndef" db eval {SELECT $v1 REGEXP '^abc\ndef$'} } {1} do_test regexp1-2.10 { set v1 "abc\adef" db eval {SELECT $v1 REGEXP '^abc\adef$'} } {1} do_test regexp1-2.11 { set v1 "abc\tdef" db eval {SELECT $v1 REGEXP '^abc\tdef$'} } {1} do_test regexp1-2.12 { set v1 "abc\rdef" db eval {SELECT $v1 REGEXP '^abc\rdef$'} } {1} do_test regexp1-2.13 { set v1 "abc\fdef" db eval {SELECT $v1 REGEXP '^abc\fdef$'} } {1} do_test regexp1-2.14 { set v1 "abc\vdef" db eval {SELECT $v1 REGEXP '^abc\vdef$'} } {1} do_execsql_test regexp1-2.15 { SELECT 'abc\def' REGEXP '^abc\\def', 'abc(def' REGEXP '^abc\(def', 'abc)def' REGEXP '^abc\)def', 'abc*def' REGEXP '^abc\*def', 'abc.def' REGEXP '^abc\.def', 'abc+def' REGEXP '^abc\+def', 'abc?def' REGEXP '^abc\?def', 'abc[def' REGEXP '^abc\[def', 'abc$def' REGEXP '^abc\$', '^def' REGEXP '\^def', 'abc{4}x' REGEXP '^abc\{4\}x$', 'abc|def' REGEXP '^abc\|def$' } {1 1 1 1 1 1 1 1 1 1 1 1} do_execsql_test regexp1-2.20 { SELECT 'abc$¢€xyz' REGEXP '^abc\u0024\u00a2\u20acxyz$', 'abc$¢€xyz' REGEXP '^abc\u0024\u00A2\u20ACxyz$', 'abc$¢€xyz' REGEXP '^abc\x24\xa2\u20acxyz$' } {1 1 1} do_execsql_test regexp1-2.21 { SELECT 'abc$¢€xyz' REGEXP '^abc[\u0024][\u00a2][\u20ac]xyz$', 'abc$¢€xyz' REGEXP '^abc[\u0024\u00A2\u20AC]{3}xyz$', 'abc$¢€xyz' REGEXP '^abc[\x24][\xa2\u20ac]+xyz$' } {1 1 1} do_execsql_test regexp1-2.22 { SELECT 'abc$¢€xyz' REGEXP '^abc[^\u0025-X][^ -\u007f][^\u20ab]xyz$' } {1} finish_test |
Added test/selectD.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 | # 2012 December 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 name resolution in SELECT # statements that have parenthesized FROM clauses. # set testdir [file dirname $argv0] source $testdir/tester.tcl for {set i 1} {$i<=2} {incr i} { db close forcedelete test$i.db sqlite3 db test$i.db if {$i==2} { optimization_control db query-flattener off } do_test selectD-$i.0 { db eval { ATTACH ':memory:' AS aux1; CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(111,'x1'); CREATE TABLE t2(a,b); INSERT INTO t2 VALUES(222,'x2'); CREATE TEMP TABLE t3(a,b); INSERT INTO t3 VALUES(333,'x3'); CREATE TABLE main.t4(a,b); INSERT INTO main.t4 VALUES(444,'x4'); CREATE TABLE aux1.t4(a,b); INSERT INTO aux1.t4 VALUES(555,'x5'); } } {} do_test selectD-$i.1 { db eval { SELECT * FROM (t1), (t2), (t3), (t4) WHERE t4.a=t3.a+111 AND t3.a=t2.a+111 AND t2.a=t1.a+111; } } {111 x1 222 x2 333 x3 444 x4} do_test selectD-$i.2.1 { db eval { SELECT * FROM t1 JOIN (t2 JOIN (t3 JOIN t4 ON t4.a=t3.a+111) ON t3.a=t2.a+111) ON t2.a=t1.a+111; } } {111 x1 222 x2 333 x3 444 x4} do_test selectD-$i.2.2 { db eval { SELECT t3.a FROM t1 JOIN (t2 JOIN (t3 JOIN t4 ON t4.a=t3.a+111) ON t3.a=t2.a+111) ON t2.a=t1.a+111; } } {333} do_test selectD-$i.2.3 { db eval { SELECT t3.* FROM t1 JOIN (t2 JOIN (t3 JOIN t4 ON t4.a=t3.a+111) ON t3.a=t2.a+111) ON t2.a=t1.a+111; } } {333 x3} do_test selectD-$i.2.3 { db eval { SELECT t3.*, t2.* FROM t1 JOIN (t2 JOIN (t3 JOIN t4 ON t4.a=t3.a+111) ON t3.a=t2.a+111) ON t2.a=t1.a+111; } } {333 x3 222 x2} do_test selectD-$i.2.4 { db eval { SELECT * FROM t1 JOIN (t2 JOIN (main.t4 JOIN aux1.t4 ON aux1.t4.a=main.t4.a+111) ON main.t4.a=t2.a+222) ON t2.a=t1.a+111; } } {111 x1 222 x2 444 x4 555 x5} do_test selectD-$i.2.5 { db eval { SELECT * FROM t1 JOIN (t2 JOIN (main.t4 AS x JOIN aux1.t4 ON aux1.t4.a=x.a+111) ON x.a=t2.a+222) ON t2.a=t1.a+111; } } {111 x1 222 x2 444 x4 555 x5} do_test selectD-$i.2.6 { catchsql { SELECT * FROM t1 JOIN (t2 JOIN (main.t4 JOIN aux.t4 ON aux.t4.a=main.t4.a+111) ON main.t4.a=t2.a+222) ON t2.a=t1.a+111; } } {1 {no such table: aux.t4}} do_test selectD-$i.2.7 { db eval { SELECT x.a, y.b FROM t1 JOIN (t2 JOIN (main.t4 x JOIN aux1.t4 y ON y.a=x.a+111) ON x.a=t2.a+222) ON t2.a=t1.a+111; } } {444 x5} do_test selectD-$i.3 { db eval { UPDATE t2 SET a=111; UPDATE t3 SET a=111; UPDATE t4 SET a=111; SELECT * FROM t1 JOIN (t2 JOIN (t3 JOIN t4 USING(a)) USING (a)) USING (a); } } {111 x1 x2 x3 x4} do_test selectD-$i.4 { db eval { UPDATE t2 SET a=111; UPDATE t3 SET a=111; UPDATE t4 SET a=111; SELECT * FROM t1 LEFT JOIN (t2 LEFT JOIN (t3 LEFT JOIN t4 USING(a)) USING (a)) USING (a); } } {111 x1 x2 x3 x4} do_test selectD-$i.5 { db eval { UPDATE t3 SET a=222; UPDATE t4 SET a=222; SELECT * FROM (t1 LEFT JOIN t2 USING(a)) JOIN (t3 LEFT JOIN t4 USING(a)) ON t1.a=t3.a-111; } } {111 x1 x2 222 x3 x4} do_test selectD-$i.6 { db eval { UPDATE t4 SET a=333; SELECT * FROM (t1 LEFT JOIN t2 USING(a)) JOIN (t3 LEFT JOIN t4 USING(a)) ON t1.a=t3.a-111; } } {111 x1 x2 222 x3 {}} do_test selectD-$i.7 { db eval { SELECT t1.*, t2.*, t3.*, t4.b FROM (t1 LEFT JOIN t2 USING(a)) JOIN (t3 LEFT JOIN t4 USING(a)) ON t1.a=t3.a-111; } } {111 x1 111 x2 222 x3 {}} } finish_test |
Changes to test/shell1.test.
︙ | ︙ | |||
216 217 218 219 220 221 222 | 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\"" | | | 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | 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\"" } {1 {ERROR: Not a boolean value: "1 2 3". Assuming "no".}} 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 { |
︙ | ︙ | |||
249 250 251 252 253 254 255 | #---------------------------------------------------------------------------- # 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" | | | | 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 | #---------------------------------------------------------------------------- # Test cases shell1-3.*: Basic test that "dot" command can be called. # # .backup ?DB? FILE Backup DB (default "main") to FILE do_test shell1-3.1.1 { catchcmd "test.db" ".backup" } {1 {missing FILENAME argument on .backup}} do_test shell1-3.1.2 { catchcmd "test.db" ".backup FOO" } {0 {}} do_test shell1-3.1.3 { catchcmd "test.db" ".backup FOO BAR" } {1 {Error: unknown database FOO}} do_test shell1-3.1.4 { # too many arguments catchcmd "test.db" ".backup FOO BAR BAD" } {1 {too many arguments to .backup}} # .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" |
︙ | ︙ | |||
322 323 324 325 326 327 328 | 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 {}} | < < < < | 322 323 324 325 326 327 328 329 330 331 332 333 334 335 | 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 {}} # .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 { |
︙ | ︙ |
Changes to test/spellfix.test.
︙ | ︙ | |||
132 133 134 135 136 137 138 | do_test 3.2 { foreach w $vocab { execsql { INSERT INTO t3(word) VALUES($w) } } } {} | < | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | do_test 3.2 { foreach w $vocab { execsql { INSERT INTO t3(word) VALUES($w) } } } {} foreach {tn word res} { 1 kos* {kosher 3 kiosk 4 kudo 2 kiss 3 kissed 3} 2 kellj* {killjoy 5 kill 4 killed 4 killer 4 killers 4} 3 kellj {kill 4 kills 5 killjoy 7 keel 4 killed 6} } { do_execsql_test 3.2.$tn { SELECT word, matchlen FROM t3 WHERE word MATCH $word ORDER BY score, word LIMIT 5 } $res } do_execsql_test 4.0 { INSERT INTO t3(command) VALUES('edit_cost_table=NULL'); } foreach {tn word res} { 1 kosher {kosher 0 kisser 51 kissers 76 kissed 126 kisses 126} 2 kellj {keels 60 killjoy 68 kills 80 keel 120 kill 125} 3 kashar {kosher 80 kisser 91 kissers 116 kissed 166 kisses 166} } { do_execsql_test 4.1.$tn { SELECT word, distance FROM t3 WHERE word MATCH $word ORDER BY score, word LIMIT 5 } $res } do_execsql_test 5.0 { CREATE TABLE costs2(iLang, cFrom, cTo, iCost); INSERT INTO costs2 VALUES(0, 'a', 'o', 1); INSERT INTO costs2 VALUES(0, 'e', 'o', 4); INSERT INTO costs2 VALUES(0, 'i', 'o', 8); INSERT INTO costs2 VALUES(0, 'u', 'o', 16); INSERT INTO t3(command) VALUES('edit_cost_table="costs2"'); } foreach {tn word res} { 1 kasher {kosher 1} 2 kesher {kosher 4} 3 kisher {kosher 8} 4 kosher {kosher 0} 5 kusher {kosher 16} } { do_execsql_test 5.1.$tn { SELECT word, distance FROM t3 WHERE word MATCH $word ORDER BY score, word LIMIT 1 } $res } finish_test |
Changes to test/tester.tcl.
︙ | ︙ | |||
50 51 52 53 54 55 56 57 58 59 60 61 62 63 | # execsql SQL ?DB? # # Commands to run test cases: # # do_ioerr_test TESTNAME ARGS... # crashsql ARGS... # integrity_check TESTNAME ?DB? # do_test TESTNAME SCRIPT EXPECTED # do_execsql_test TESTNAME SQL EXPECTED # do_catchsql_test TESTNAME SQL EXPECTED # # Commands providing a lower level interface to the global test counters: # # set_test_counter COUNTER ?VALUE? | > | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | # execsql SQL ?DB? # # Commands to run test cases: # # do_ioerr_test TESTNAME ARGS... # crashsql ARGS... # integrity_check TESTNAME ?DB? # verify_ex_errcode TESTNAME EXPECTED ?DB? # do_test TESTNAME SCRIPT EXPECTED # do_execsql_test TESTNAME SQL EXPECTED # do_catchsql_test TESTNAME SQL EXPECTED # # Commands providing a lower level interface to the global test counters: # # set_test_counter COUNTER ?VALUE? |
︙ | ︙ | |||
964 965 966 967 968 969 970 971 972 973 974 975 976 977 | # proc integrity_check {name {db db}} { ifcapable integrityck { do_test $name [list execsql {PRAGMA integrity_check} $db] {ok} } } # Return true if the SQL statement passed as the second argument uses a # statement transaction. # proc sql_uses_stmt {db sql} { set stmt [sqlite3_prepare $db $sql -1 dummy] set uses [uses_stmt_journal $stmt] | > > > > > > | 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 | # proc integrity_check {name {db db}} { ifcapable integrityck { do_test $name [list execsql {PRAGMA integrity_check} $db] {ok} } } # Check the extended error code # proc verify_ex_errcode {name expected {db db}} { do_test $name [list sqlite3_extended_errcode $db] $expected } # Return true if the SQL statement passed as the second argument uses a # statement transaction. # proc sql_uses_stmt {db sql} { set stmt [sqlite3_prepare $db $sql -1 dummy] set uses [uses_stmt_journal $stmt] |
︙ | ︙ | |||
1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 | if {$msg=="child killed: unknown signal"} { set msg "child process exited abnormally" } } lappend r $msg } # Usage: do_ioerr_test <test number> <options...> # # This proc is used to implement test cases that check that IO errors # are correctly handled. The first argument, <test number>, is an integer # used to name the tests executed by this proc. Options are as follows: # | > > > > > > > > > > > > > > > > > > > | 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 | if {$msg=="child killed: unknown signal"} { set msg "child process exited abnormally" } } lappend r $msg } proc run_ioerr_prep {} { set ::sqlite_io_error_pending 0 catch {db close} catch {db2 close} catch {forcedelete test.db} catch {forcedelete test.db-journal} catch {forcedelete test2.db} catch {forcedelete test2.db-journal} set ::DB [sqlite3 db test.db; sqlite3_connection_pointer db] sqlite3_extended_result_codes $::DB $::ioerropts(-erc) if {[info exists ::ioerropts(-tclprep)]} { eval $::ioerropts(-tclprep) } if {[info exists ::ioerropts(-sqlprep)]} { execsql $::ioerropts(-sqlprep) } expr 0 } # Usage: do_ioerr_test <test number> <options...> # # This proc is used to implement test cases that check that IO errors # are correctly handled. The first argument, <test number>, is an integer # used to name the tests executed by this proc. Options are as follows: # |
︙ | ︙ | |||
1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 | set ::ioerropts(-ckrefcount) 0 set ::ioerropts(-restoreprng) 1 array set ::ioerropts $args # TEMPORARY: For 3.5.9, disable testing of extended result codes. There are # a couple of obscure IO errors that do not return them. set ::ioerropts(-erc) 0 set ::go 1 #reset_prng_state | > > > > > > > > > > > > > > > > > < < < < < < < < < < < | < < < < < | | < < < < < < < < < | < | | | 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 | set ::ioerropts(-ckrefcount) 0 set ::ioerropts(-restoreprng) 1 array set ::ioerropts $args # TEMPORARY: For 3.5.9, disable testing of extended result codes. There are # a couple of obscure IO errors that do not return them. set ::ioerropts(-erc) 0 # Create a single TCL script from the TCL and SQL specified # as the body of the test. set ::ioerrorbody {} if {[info exists ::ioerropts(-tclbody)]} { append ::ioerrorbody "$::ioerropts(-tclbody)\n" } if {[info exists ::ioerropts(-sqlbody)]} { append ::ioerrorbody "db eval {$::ioerropts(-sqlbody)}" } save_prng_state if {$::ioerropts(-cksum)} { run_ioerr_prep eval $::ioerrorbody set ::goodcksum [cksum] } set ::go 1 #reset_prng_state for {set n $::ioerropts(-start)} {$::go} {incr n} { set ::TN $n incr ::ioerropts(-count) -1 if {$::ioerropts(-count)<0} break # Skip this IO error if it was specified with the "-exclude" option. if {[info exists ::ioerropts(-exclude)]} { if {[lsearch $::ioerropts(-exclude) $n]!=-1} continue } if {$::ioerropts(-restoreprng)} { restore_prng_state } # Delete the files test.db and test2.db, then execute the TCL and # SQL (in that order) to prepare for the test case. do_test $testname.$n.1 { run_ioerr_prep } {0} # Read the 'checksum' of the database. if {$::ioerropts(-cksum)} { set ::checksum [cksum] } # Set the Nth IO error to fail. do_test $testname.$n.2 [subst { set ::sqlite_io_error_persist $::ioerropts(-persist) set ::sqlite_io_error_pending $n }] $n # Execute the TCL script created for the body of this test. If # at least N IO operations performed by SQLite as a result of # the script, the Nth will fail. do_test $testname.$n.3 { set ::sqlite_io_error_hit 0 set ::sqlite_io_error_hardhit 0 set r [catch $::ioerrorbody msg] set ::errseen $r set rc [sqlite3_errcode $::DB] if {$::ioerropts(-erc)} { |
︙ | ︙ | |||
1304 1305 1306 1307 1308 1309 1310 | # be the same as before the script that caused the IO error was run. # if {$::go && $::sqlite_io_error_hardhit && $::ioerropts(-cksum)} { do_test $testname.$n.6 { catch {db close} catch {db2 close} set ::DB [sqlite3 db test.db; sqlite3_connection_pointer db] | | > > > | > > > > | 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 | # be the same as before the script that caused the IO error was run. # if {$::go && $::sqlite_io_error_hardhit && $::ioerropts(-cksum)} { do_test $testname.$n.6 { catch {db close} catch {db2 close} set ::DB [sqlite3 db test.db; sqlite3_connection_pointer db] set nowcksum [cksum] set res [expr {$nowcksum==$::checksum || $nowcksum==$::goodcksum}] if {$res==0} { puts "now=$nowcksum" puts "the=$::checksum" puts "fwd=$::goodcksum" } set res } 1 } set ::sqlite_io_error_hardhit 0 set ::sqlite_io_error_pending 0 if {[info exists ::ioerropts(-cleanup)]} { catch $::ioerropts(-cleanup) } |
︙ | ︙ |
Added test/tkt-4dd95f6943.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 | # 2013 March 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. # set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix tkt-4dd95f6943 do_execsql_test 1.0 { CREATE TABLE t1(x); INSERT INTO t1 VALUES (3), (4), (2), (1), (5), (6); } foreach {tn1 idx} { 1 { CREATE INDEX i1 ON t1(x ASC) } 2 { CREATE INDEX i1 ON t1(x DESC) } } { do_execsql_test 1.$tn1.1 { DROP INDEX IF EXISTS i1; } do_execsql_test 1.$tn1.2 $idx do_execsql_test 1.$tn1.3 { SELECT x FROM t1 WHERE x IN(2, 4, 5) ORDER BY x ASC; } {2 4 5} do_execsql_test 1.$tn1.4 { SELECT x FROM t1 WHERE x IN(2, 4, 5) ORDER BY x DESC; } {5 4 2} } do_execsql_test 2.0 { CREATE TABLE t2(x, y); INSERT INTO t2 VALUES (5, 3), (5, 4), (5, 2), (5, 1), (5, 5), (5, 6); INSERT INTO t2 VALUES (1, 3), (1, 4), (1, 2), (1, 1), (1, 5), (1, 6); INSERT INTO t2 VALUES (3, 3), (3, 4), (3, 2), (3, 1), (3, 5), (3, 6); INSERT INTO t2 VALUES (2, 3), (2, 4), (2, 2), (2, 1), (2, 5), (2, 6); INSERT INTO t2 VALUES (4, 3), (4, 4), (4, 2), (4, 1), (4, 5), (4, 6); INSERT INTO t2 VALUES (6, 3), (6, 4), (6, 2), (6, 1), (6, 5), (6, 6); CREATE TABLE t3(a, b); INSERT INTO t3 VALUES (2, 2), (4, 4), (5, 5); CREATE UNIQUE INDEX t3i1 ON t3(a ASC); CREATE UNIQUE INDEX t3i2 ON t3(b DESC); } foreach {tn1 idx} { 1 { CREATE INDEX i1 ON t2(x ASC, y ASC) } 2 { CREATE INDEX i1 ON t2(x ASC, y DESC) } 3 { CREATE INDEX i1 ON t2(x DESC, y ASC) } 4 { CREATE INDEX i1 ON t2(x DESC, y DESC) } 5 { CREATE INDEX i1 ON t2(y ASC, x ASC) } 6 { CREATE INDEX i1 ON t2(y ASC, x DESC) } 7 { CREATE INDEX i1 ON t2(y DESC, x ASC) } 8 { CREATE INDEX i1 ON t2(y DESC, x DESC) } } { do_execsql_test 2.$tn1.1 { DROP INDEX IF EXISTS i1; } do_execsql_test 2.$tn1.2 $idx foreach {tn2 inexpr} { 3 "(2, 4, 5)" 4 "(SELECT a FROM t3)" 5 "(SELECT b FROM t3)" } { do_execsql_test 2.$tn1.$tn2.1 " SELECT x, y FROM t2 WHERE x = 1 AND y IN $inexpr ORDER BY x ASC, y ASC; " {1 2 1 4 1 5} do_execsql_test 2.$tn1.$tn2.2 " SELECT x, y FROM t2 WHERE x = 2 AND y IN $inexpr ORDER BY x ASC, y DESC; " {2 5 2 4 2 2} do_execsql_test 2.$tn1.$tn2.3 " SELECT x, y FROM t2 WHERE x = 3 AND y IN $inexpr ORDER BY x DESC, y ASC; " {3 2 3 4 3 5} do_execsql_test 2.$tn1.$tn2.4 " SELECT x, y FROM t2 WHERE x = 4 AND y IN $inexpr ORDER BY x DESC, y DESC; " {4 5 4 4 4 2} do_execsql_test 2.$tn1.$tn2.5 " SELECT a, x, y FROM t2, t3 WHERE a = 4 AND x = 1 AND y IN $inexpr ORDER BY a, x ASC, y ASC; " {4 1 2 4 1 4 4 1 5} do_execsql_test 2.$tn1.$tn2.6 " SELECT a, x, y FROM t2, t3 WHERE a = 2 AND x = 1 AND y IN $inexpr ORDER BY x ASC, y ASC; " {2 1 2 2 1 4 2 1 5} do_execsql_test 2.$tn1.$tn2.7 " SELECT a, x, y FROM t2, t3 WHERE a = 4 AND x = 1 AND y IN $inexpr ORDER BY a, x ASC, y DESC; " {4 1 5 4 1 4 4 1 2} do_execsql_test 2.$tn1.8 " SELECT a, x, y FROM t2, t3 WHERE a = 2 AND x = 1 AND y IN $inexpr ORDER BY x ASC, y DESC; " {2 1 5 2 1 4 2 1 2} do_execsql_test 2.$tn1.$tn2.9 " SELECT a, x, y FROM t2, t3 WHERE a = 4 AND x = 1 AND y IN $inexpr ORDER BY a, x DESC, y ASC; " {4 1 2 4 1 4 4 1 5} do_execsql_test 2.$tn1.10 " SELECT a, x, y FROM t2, t3 WHERE a = 2 AND x = 1 AND y IN $inexpr ORDER BY x DESC, y ASC; " {2 1 2 2 1 4 2 1 5} do_execsql_test 2.$tn1.$tn2.11 " SELECT a, x, y FROM t2, t3 WHERE a = 4 AND x = 1 AND y IN $inexpr ORDER BY a, x DESC, y DESC; " {4 1 5 4 1 4 4 1 2} do_execsql_test 2.$tn1.$tn2.12 " SELECT a, x, y FROM t2, t3 WHERE a = 2 AND x = 1 AND y IN $inexpr ORDER BY x DESC, y DESC; " {2 1 5 2 1 4 2 1 2} } } do_execsql_test 3.0 { CREATE TABLE t7(x); INSERT INTO t7 VALUES (1), (2), (3); CREATE INDEX i7 ON t7(x); CREATE TABLE t8(y); INSERT INTO t8 VALUES (1), (2), (3); } foreach {tn idxdir sortdir sortdata} { 1 ASC ASC {1 2 3} 2 ASC DESC {3 2 1} 3 DESC ASC {1 2 3} 4 ASC DESC {3 2 1} } { do_execsql_test 3.$tn " DROP INDEX IF EXISTS i8; CREATE UNIQUE INDEX i8 ON t8(y $idxdir); SELECT x FROM t7 WHERE x IN (SELECT y FROM t8) ORDER BY x $sortdir; " $sortdata } finish_test |
Added test/tkt-7a31705a7e6.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 | # 2013 February 26 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # This file implements regression tests for SQLite library. Specifically, # it tests that ticket [7a31705a7e6c95d514e6f20a6900f436bbc9fed8] in the # name resolver has been fixed. # set testdir [file dirname $argv0] source $testdir/tester.tcl do_execsql_test tkt-7a31705a7e6-1.1 { CREATE TABLE t1 (a INTEGER PRIMARY KEY); CREATE TABLE t2 (a INTEGER PRIMARY KEY, b INTEGER); CREATE TABLE t2x (b INTEGER PRIMARY KEY); SELECT t1.a FROM ((t1 JOIN t2 ON t1.a=t2.a) AS x JOIN t2x ON x.b=t2x.b) as y; } {} |
Added test/tkt-a7b7803e.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 | # 2012 December 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. Specifically, # it tests that ticket [a7b7803e8d1e8699cd8a460a38133b98892d2e17] has # been fixed. # set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/lock_common.tcl source $testdir/malloc_common.tcl do_test tkt-a7b7803e.1 { db eval { CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(0,'first'),(99,'fuzzy'); SELECT (t1.a==0) AS x, b FROM t1 WHERE a=0 OR x; } } {1 first} do_test tkt-a7b7803e.2 { db eval { SELECT a, (t1.b='fuzzy') AS x FROM t1 WHERE x } } {99 1} do_test tkt-a7b7803e.3 { db eval { SELECT (a=99) AS x, (t1.b='fuzzy') AS y, * FROM t1 WHERE x AND y } } {1 1 99 fuzzy} do_test tkt-a7b7803e.4 { db eval { SELECT (a=99) AS x, (t1.b='first') AS y, * FROM t1 WHERE x OR y ORDER BY a } } {0 1 0 first 1 0 99 fuzzy} do_test tkt-a7b7803e.5 { db eval { SELECT (M.a=99) AS x, M.b, (N.b='first') AS y, N.b FROM t1 M, t1 N WHERE x OR y ORDER BY M.a, N.a } } {0 first 1 first 1 fuzzy 1 first 1 fuzzy 0 fuzzy} do_test tkt-a7b7803e.6 { db eval { SELECT (M.a=99) AS x, M.b, (N.b='first') AS y, N.b FROM t1 M, t1 N WHERE x AND y ORDER BY M.a, N.a } } {1 fuzzy 1 first} do_test tkt-a7b7803e.7 { db eval { SELECT (M.a=99) AS x, M.b, (N.b='first') AS y, N.b FROM t1 M JOIN t1 N ON x AND y ORDER BY M.a, N.a } } {1 fuzzy 1 first} do_test tkt-a7b7803e.8 { db eval { SELECT (M.a=99) AS x, M.b, (N.b='first') AS y, N.b FROM t1 M JOIN t1 N ON x ORDER BY M.a, N.a } } {1 fuzzy 1 first 1 fuzzy 0 fuzzy} finish_test |
Added test/tkt-fc7bd6358f.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 | # 2013 March 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 regression tests for SQLite library. Specifically, # it tests that ticket [fc7bd6358f]: # # The following SQL yields an incorrect result (zero rows) in all # versions of SQLite between 3.6.14 and 3.7.15.2: # # CREATE TABLE t(textid TEXT); # INSERT INTO t VALUES('12'); # INSERT INTO t VALUES('34'); # CREATE TABLE i(intid INTEGER PRIMARY KEY); # INSERT INTO i VALUES(12); # INSERT INTO i VALUES(34); # # SELECT t1.textid AS a, i.intid AS b, t2.textid AS c # FROM t t1, i, t t2 # WHERE t1.textid = i.intid # AND t1.textid = t2.textid; # # The correct result should be two rows, one with 12|12|12 and the other # with 34|34|34. With this bug, no rows are returned. Bisecting shows that # this bug was introduced with check-in [dd4d67a67454] on 2009-04-23. # set testdir [file dirname $argv0] source $testdir/tester.tcl do_test tkt-fc7bd6358f.100 { db eval { CREATE TABLE t(textid TEXT); INSERT INTO t VALUES('12'); INSERT INTO t VALUES('34'); CREATE TABLE i(intid INTEGER PRIMARY KEY); INSERT INTO i VALUES(12); INSERT INTO i VALUES(34); } } {} unset -nocomplain from unset -nocomplain where unset -nocomplain a unset -nocomplain b foreach {a from} { 1 {FROM t t1, i, t t2} 2 {FROM i, t t1, t t2} 3 {FROM t t1, t t2, i} } { foreach {b where} { 1 {WHERE t1.textid=i.intid AND t1.textid=t2.textid} 2 {WHERE i.intid=t1.textid AND t1.textid=t2.textid} 3 {WHERE t1.textid=i.intid AND i.intid=t2.textid} 4 {WHERE t1.textid=i.intid AND t2.textid=i.intid} 5 {WHERE i.intid=t1.textid AND i.intid=t2.textid} 6 {WHERE i.intid=t1.textid AND t2.textid=i.intid} 7 {WHERE t1.textid=t2.textid AND i.intid=t2.textid} 8 {WHERE t1.textid=t2.textid AND t2.textid=i.intid} } { do_test tkt-fc7bd6358f.110.$a.$b.1 { db eval {PRAGMA automatic_index=ON} db eval "SELECT t1.textid, i.intid, t2.textid $from $where" } {12 12 12 34 34 34} do_test tkt-fc7bd6358f.110.$a.$b.2 { db eval {PRAGMA automatic_index=OFF} db eval "SELECT t1.textid, i.intid, t2.textid $from $where" } {12 12 12 34 34 34} } } finish_test |
Changes to test/tkt3457.test.
︙ | ︙ | |||
57 58 59 60 61 62 63 64 65 66 67 68 69 70 | fconfigure $fd -encoding binary -translation binary seek $fd 0 puts -nonewline $fd "\xd9\xd5\x05\xf9\x20\xa1\x63\xd7" close $fd execsql COMMIT } {} do_test tkt3457-1.2 { forcecopy bak.db-journal test.db-journal file attributes test.db-journal -permissions --------- catchsql { SELECT * FROM t1 } } {1 {unable to open database file}} do_test tkt3457-1.3 { | > > > > > > > > | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | fconfigure $fd -encoding binary -translation binary seek $fd 0 puts -nonewline $fd "\xd9\xd5\x05\xf9\x20\xa1\x63\xd7" close $fd execsql COMMIT } {} # Disable fchmod to make sure SQLite itself does not try to change the # permission bits on us # catch { test_syscall install fchmod test_syscall fault 1 1 } do_test tkt3457-1.2 { forcecopy bak.db-journal test.db-journal file attributes test.db-journal -permissions --------- catchsql { SELECT * FROM t1 } } {1 {unable to open database file}} do_test tkt3457-1.3 { |
︙ | ︙ | |||
79 80 81 82 83 84 85 86 87 | } {1 {unable to open database file}} do_test tkt3457-1.5 { forcecopy bak.db-journal test.db-journal file attributes test.db-journal -permissions rw-rw-rw- catchsql { SELECT * FROM t1 } } {0 {1 2 3 4 5 6}} finish_test | > > > > > > | 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | } {1 {unable to open database file}} do_test tkt3457-1.5 { forcecopy bak.db-journal test.db-journal file attributes test.db-journal -permissions rw-rw-rw- catchsql { SELECT * FROM t1 } } {0 {1 2 3 4 5 6}} # Reenable fchmod catch { test_syscall uninstall test_syscall fault 0 0 } finish_test |
Changes to test/tkt3762.test.
1 2 3 4 5 6 7 8 9 10 11 12 | # 2009 March 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. # #*********************************************************************** # # Ticket #3762: Make sure that an incremental vacuum that reduces the | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2009 March 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. # #*********************************************************************** # # Ticket #3762: Make sure that an incremental vacuum that reduces the # size of the database file such that if a pointer-map page is eliminated # it can be correctly rolled back. # # That ticket #3762 has been fixed has already been verified by the # savepoint6.test test script. But this script is simplier and a # redundant test never hurts. # # $Id: tkt3762.test,v 1.1 2009/03/31 00:50:36 drh Exp $ |
︙ | ︙ |
Added test/transitive1.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | # 2013 April 17 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #************************************************************************* # This file implements regression tests for SQLite library. The # focus of this script is testing of transitive WHERE clause constraints # set testdir [file dirname $argv0] source $testdir/tester.tcl do_execsql_test transitive1-100 { CREATE TABLE t1(a TEXT, b TEXT, c TEXT COLLATE NOCASE); INSERT INTO t1 VALUES('abc','abc','Abc'); INSERT INTO t1 VALUES('def','def','def'); INSERT INTO t1 VALUES('ghi','ghi','GHI'); CREATE INDEX t1a1 ON t1(a); CREATE INDEX t1a2 ON t1(a COLLATE nocase); SELECT * FROM t1 WHERE a=b AND c=b AND c='DEF'; } {def def def} do_execsql_test transitive1-110 { SELECT * FROM t1 WHERE a=b AND c=b AND c>='DEF' ORDER BY +a; } {def def def ghi ghi GHI} do_execsql_test transitive1-120 { SELECT * FROM t1 WHERE a=b AND c=b AND c<='DEF' ORDER BY +a; } {abc abc Abc def def def} do_execsql_test transitive1-200 { CREATE TABLE t2(a INTEGER, b INTEGER, c TEXT); INSERT INTO t2 VALUES(100,100,100); INSERT INTO t2 VALUES(20,20,20); INSERT INTO t2 VALUES(3,3,3); SELECT * FROM t2 WHERE a=b AND c=b AND c=20; } {20 20 20} do_execsql_test transitive1-210 { SELECT * FROM t2 WHERE a=b AND c=b AND c>=20 ORDER BY +a; } {3 3 3 20 20 20} do_execsql_test transitive1-220 { SELECT * FROM t2 WHERE a=b AND c=b AND c<=20 ORDER BY +a; } {20 20 20 100 100 100} finish_test |
Changes to test/trigger1.test.
︙ | ︙ | |||
419 420 421 422 423 424 425 426 427 428 429 430 431 432 | 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} | > | 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 | 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}} verify_ex_errcode trigger1-6.3b SQLITE_CONSTRAINT_TRIGGER 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} |
︙ | ︙ |
Changes to test/trigger3.test.
︙ | ︙ | |||
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | 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 { | > > > > | 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | do_test trigger3-1.1 { catchsql { BEGIN; INSERT INTO tbl VALUES (5, 5, 6); INSERT INTO tbl VALUES (1, 5, 6); } } {1 {Trigger abort}} verify_ex_errcode trigger3-1.1b SQLITE_CONSTRAINT_TRIGGER 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}} verify_ex_errcode trigger3-2.1b SQLITE_CONSTRAINT_TRIGGER 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}} verify_ex_errcode trigger3-3.1b SQLITE_CONSTRAINT_TRIGGER 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}} verify_ex_errcode trigger3-3.3b SQLITE_CONSTRAINT_TRIGGER do_test trigger3-3.4 { execsql {SELECT * FROM tbl} } {} # IGNORE do_test trigger3-4.1 { catchsql { |
︙ | ︙ | |||
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 | } 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 | > > | 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 | } do_test trigger3-7.1 { catchsql { INSERT INTO tbl_view VALUES(1, 2, 3); } } {1 {View rollback}} verify_ex_errcode trigger3-7.1b SQLITE_CONSTRAINT_TRIGGER 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}} verify_ex_errcode trigger3-7.3b SQLITE_CONSTRAINT_TRIGGER } ;# 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/triggerA.test.
︙ | ︙ | |||
186 187 188 189 190 191 192 193 194 195 196 197 198 199 | db eval { DELETE FROM result4; CREATE TRIGGER r5u INSTEAD OF UPDATE ON v5 BEGIN INSERT INTO result4(a,b,c,d) VALUES(old.x, old.b, new.x, new.b); END; UPDATE v5 SET b = b+9900000 WHERE x BETWEEN 3 AND 5; SELECT * FROM result4 ORDER BY a; } } {3 305 3 9900305 4 404 4 9900404 5 504 5 9900504} # Only run the reamining tests if memory debugging is turned on. # ifcapable !memdebug { puts "Skipping triggerA malloc tests: not compiled with -DSQLITE_MEMDEBUG..." | > > > > > > > | 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | db eval { DELETE FROM result4; CREATE TRIGGER r5u INSTEAD OF UPDATE ON v5 BEGIN INSERT INTO result4(a,b,c,d) VALUES(old.x, old.b, new.x, new.b); END; UPDATE v5 SET b = b+9900000 WHERE x BETWEEN 3 AND 5; SELECT * FROM result4 ORDER BY a; } } {3 305 3 9900305 4 404 4 9900404 5 504 5 9900504} do_test triggerA-2.11 { db eval { DELETE FROM result4; UPDATE v5 SET b = main.v5.b+9900000 WHERE main.v5.x BETWEEN 3 AND 5; SELECT * FROM result4 ORDER BY a; } } {3 305 3 9900305 4 404 4 9900404 5 504 5 9900504} # Only run the reamining tests if memory debugging is turned on. # ifcapable !memdebug { puts "Skipping triggerA malloc tests: not compiled with -DSQLITE_MEMDEBUG..." |
︙ | ︙ |
Changes to test/unique.test.
︙ | ︙ | |||
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | } } {0 {}} do_test unique-1.3 { catchsql { INSERT INTO t1(a,b,c) VALUES(1,3,4) } } {1 {column a is not unique}} do_test unique-1.4 { execsql { SELECT * FROM t1 ORDER BY a; } } {1 2 3} do_test unique-1.5 { catchsql { INSERT INTO t1(a,b,c) VALUES(3,2,4) } } {1 {column b is not unique}} do_test unique-1.6 { execsql { SELECT * FROM t1 ORDER BY a; } } {1 2 3} do_test unique-1.7 { catchsql { | > > | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | } } {0 {}} do_test unique-1.3 { catchsql { INSERT INTO t1(a,b,c) VALUES(1,3,4) } } {1 {column a is not unique}} verify_ex_errcode unique-1.3b SQLITE_CONSTRAINT_UNIQUE do_test unique-1.4 { execsql { SELECT * FROM t1 ORDER BY a; } } {1 2 3} do_test unique-1.5 { catchsql { INSERT INTO t1(a,b,c) VALUES(3,2,4) } } {1 {column b is not unique}} verify_ex_errcode unique-1.5b SQLITE_CONSTRAINT_UNIQUE do_test unique-1.6 { execsql { SELECT * FROM t1 ORDER BY a; } } {1 2 3} do_test unique-1.7 { catchsql { |
︙ | ︙ | |||
95 96 97 98 99 100 101 102 103 104 105 106 107 108 | } } {0 {1 2 3 4}} do_test unique-2.3 { catchsql { INSERT INTO t2 VALUES(1,5); } } {1 {column a is not unique}} do_test unique-2.4 { catchsql { SELECT * FROM t2 ORDER BY a } } {0 {1 2 3 4}} do_test unique-2.5 { catchsql { | > | 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | } } {0 {1 2 3 4}} do_test unique-2.3 { catchsql { INSERT INTO t2 VALUES(1,5); } } {1 {column a is not unique}} verify_ex_errcode unique-2.3b SQLITE_CONSTRAINT_UNIQUE do_test unique-2.4 { catchsql { SELECT * FROM t2 ORDER BY a } } {0 {1 2 3 4}} do_test unique-2.5 { catchsql { |
︙ | ︙ | |||
121 122 123 124 125 126 127 128 129 130 131 132 133 134 | } } {0 {1 2 1 5 3 4}} do_test unique-2.8 { catchsql { CREATE UNIQUE INDEX i2 ON t2(a); } } {1 {indexed columns are not unique}} do_test unique-2.9 { catchsql { CREATE INDEX i2 ON t2(a); } } {0 {}} integrity_check unique-2.10 | > | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | } } {0 {1 2 1 5 3 4}} do_test unique-2.8 { catchsql { CREATE UNIQUE INDEX i2 ON t2(a); } } {1 {indexed columns are not unique}} verify_ex_errcode unique-2.8b SQLITE_CONSTRAINT_UNIQUE do_test unique-2.9 { catchsql { CREATE INDEX i2 ON t2(a); } } {0 {}} integrity_check unique-2.10 |
︙ | ︙ | |||
159 160 161 162 163 164 165 166 167 168 169 170 171 172 | } {0 {1 2 3 4 1 2 3 5}} do_test unique-3.4 { catchsql { INSERT INTO t3(a,b,c,d) VALUES(1,4,3,5); SELECT * FROM t3 ORDER BY a,b,c,d; } } {1 {columns a, c, d are not unique}} integrity_check unique-3.5 # Make sure NULLs are distinct as far as the UNIQUE tests are # concerned. # do_test unique-4.1 { execsql { | > | 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | } {0 {1 2 3 4 1 2 3 5}} do_test unique-3.4 { catchsql { INSERT INTO t3(a,b,c,d) VALUES(1,4,3,5); SELECT * FROM t3 ORDER BY a,b,c,d; } } {1 {columns a, c, d are not unique}} verify_ex_errcode unique-3.4b SQLITE_CONSTRAINT_UNIQUE integrity_check unique-3.5 # Make sure NULLs are distinct as far as the UNIQUE tests are # concerned. # do_test unique-4.1 { execsql { |
︙ | ︙ | |||
213 214 215 216 217 218 219 220 221 222 223 224 225 226 | } {0 {}} do_test unique-4.9 { catchsql {CREATE UNIQUE INDEX i4b ON t4(a,b,c)} } {0 {}} do_test unique-4.10 { catchsql {CREATE UNIQUE INDEX i4c ON t4(b)} } {1 {indexed columns are not unique}} integrity_check unique-4.99 # Test the error message generation logic. In particular, make sure we # do not overflow the static buffer used to generate the error message. # do_test unique-5.1 { execsql { | > | 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | } {0 {}} do_test unique-4.9 { catchsql {CREATE UNIQUE INDEX i4b ON t4(a,b,c)} } {0 {}} do_test unique-4.10 { catchsql {CREATE UNIQUE INDEX i4c ON t4(b)} } {1 {indexed columns are not unique}} verify_ex_errcode unique-4.10b SQLITE_CONSTRAINT_UNIQUE integrity_check unique-4.99 # Test the error message generation logic. In particular, make sure we # do not overflow the static buffer used to generate the error message. # do_test unique-5.1 { execsql { |
︙ | ︙ | |||
245 246 247 248 249 250 251 252 253 | } } {1 2 3 4 5 6} do_test unique-5.2 { catchsql { INSERT INTO t5 VALUES(1,2,3,4,5,6); } } {1 {columns first_column_with_long_name, second_column_with_long_name, third_column_with_long_name, fourth_column_with_long_name, fifth_column_with_long_name, sixth_column_with_long_name are not unique}} finish_test | > > | 251 252 253 254 255 256 257 258 259 260 261 | } } {1 2 3 4 5 6} do_test unique-5.2 { catchsql { INSERT INTO t5 VALUES(1,2,3,4,5,6); } } {1 {columns first_column_with_long_name, second_column_with_long_name, third_column_with_long_name, fourth_column_with_long_name, fifth_column_with_long_name, sixth_column_with_long_name are not unique}} verify_ex_errcode unique-5.2b SQLITE_CONSTRAINT_UNIQUE finish_test |
Changes to test/view.test.
︙ | ︙ | |||
571 572 573 574 575 576 577 578 579 | execsql { DROP TABLE IF EXISTS t1; DROP VIEW IF EXISTS v1; CREATE TABLE t1(c1); CREATE VIEW v1 AS SELECT c1 FROM (SELECT t1.c1 FROM t1); } } {} 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 | execsql { DROP TABLE IF EXISTS t1; DROP VIEW IF EXISTS v1; CREATE TABLE t1(c1); CREATE VIEW v1 AS SELECT c1 FROM (SELECT t1.c1 FROM t1); } } {} # Ticket [d58ccbb3f1b]: Prevent Table.nRef overflow. db close sqlite3 db :memory: do_test view-21.1 { catchsql { CREATE TABLE t1(x); INSERT INTO t1 VALUES(5); CREATE VIEW v1 AS SELECT x*2 FROM t1; CREATE VIEW v2 AS SELECT * FROM v1 UNION SELECT * FROM v1; CREATE VIEW v4 AS SELECT * FROM v2 UNION SELECT * FROM v2; CREATE VIEW v8 AS SELECT * FROM v4 UNION SELECT * FROM v4; CREATE VIEW v16 AS SELECT * FROM v8 UNION SELECT * FROM v8; CREATE VIEW v32 AS SELECT * FROM v16 UNION SELECT * FROM v16; CREATE VIEW v64 AS SELECT * FROM v32 UNION SELECT * FROM v32; CREATE VIEW v128 AS SELECT * FROM v64 UNION SELECT * FROM v64; CREATE VIEW v256 AS SELECT * FROM v128 UNION SELECT * FROM v128; CREATE VIEW v512 AS SELECT * FROM v256 UNION SELECT * FROM v256; CREATE VIEW v1024 AS SELECT * FROM v512 UNION SELECT * FROM v512; CREATE VIEW v2048 AS SELECT * FROM v1024 UNION SELECT * FROM v1024; CREATE VIEW v4096 AS SELECT * FROM v2048 UNION SELECT * FROM v2048; CREATE VIEW v8192 AS SELECT * FROM v4096 UNION SELECT * FROM v4096; CREATE VIEW v16384 AS SELECT * FROM v8192 UNION SELECT * FROM v8192; CREATE VIEW v32768 AS SELECT * FROM v16384 UNION SELECT * FROM v16384; CREATE VIEW vx AS SELECT * FROM v32768 UNION SELECT * FROM v32768; } } {1 {too many references to "v1": max 65535}} ifcapable progress { do_test view-21.2 { db progress 1000 {expr 1} catchsql { SELECT * FROM v32768; } } {1 interrupted} } finish_test |
Changes to test/vtab1.test.
︙ | ︙ | |||
1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 | } {15 {} 16} do_test vtab1.13-3 { execsql { SELECT * FROM echo_c WHERE b IS NULL AND a = 15; } } {15 {} 16} do_test vtab1-14.1 { execsql { DELETE FROM c } set echo_module "" execsql { SELECT * FROM echo_c WHERE rowid IN (1, 2, 3) } set echo_module | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | 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 | } {15 {} 16} do_test vtab1.13-3 { execsql { SELECT * FROM echo_c WHERE b IS NULL AND a = 15; } } {15 {} 16} do_test vtab1-14.001 { execsql {SELECT rowid, * FROM echo_c WHERE +rowid IN (1,2,3)} } {1 3 G H 2 {} 15 16 3 15 {} 16} do_test vtab1-14.002 { execsql {SELECT rowid, * FROM echo_c WHERE rowid IN (1,2,3)} } {1 3 G H 2 {} 15 16 3 15 {} 16} do_test vtab1-14.003 { execsql {SELECT rowid, * FROM echo_c WHERE +rowid IN (0,1,5,2,'a',3,NULL)} } {1 3 G H 2 {} 15 16 3 15 {} 16} do_test vtab1-14.004 { execsql {SELECT rowid, * FROM echo_c WHERE rowid IN (0,1,5,'a',2,3,NULL)} } {1 3 G H 2 {} 15 16 3 15 {} 16} do_test vtab1-14.005 { execsql {SELECT rowid, * FROM echo_c WHERE rowid NOT IN (0,1,5,'a',2,3)} } {} do_test vtab1-14.006 { execsql {SELECT rowid, * FROM echo_c WHERE rowid NOT IN (0,5,'a',2,3)} } {1 3 G H} do_test vtab1-14.007 { execsql {SELECT rowid, * FROM echo_c WHERE +rowid NOT IN (0,5,'a',2,3,NULL)} } {} do_test vtab1-14.008 { execsql {SELECT rowid, * FROM echo_c WHERE rowid NOT IN (0,5,'a',2,3,NULL)} } {} do_test vtab1-14.011 { execsql {SELECT * FROM echo_c WHERE +a IN (1,3,8,'x',NULL,15,24)} } {3 G H 15 {} 16} do_test vtab1-14.012 { execsql {SELECT * FROM echo_c WHERE a IN (1,3,8,'x',NULL,15,24)} } {3 G H 15 {} 16} do_test vtab1-14.013 { execsql {SELECT * FROM echo_c WHERE a NOT IN (1,8,'x',15,24)} } {3 G H} do_test vtab1-14.014 { execsql {SELECT * FROM echo_c WHERE a NOT IN (1,8,'x',NULL,15,24)} } {} do_test vtab1-14.015 { execsql {SELECT * FROM echo_c WHERE +a NOT IN (1,8,'x',NULL,15,24)} } {} do_test vtab1-14.1 { execsql { DELETE FROM c } set echo_module "" execsql { SELECT * FROM echo_c WHERE rowid IN (1, 2, 3) } set echo_module } {/xBestIndex {SELECT rowid, . FROM 'c' WHERE rowid = .} xFilter {SELECT rowid, . FROM 'c' WHERE rowid = .} 1/} do_test vtab1-14.2 { set echo_module "" execsql { SELECT * FROM echo_c WHERE rowid = 1 } set echo_module } [list xBestIndex {SELECT rowid, * FROM 'c' WHERE rowid = ?} xFilter {SELECT rowid, * FROM 'c' WHERE rowid = ?} 1] do_test vtab1-14.3 { set echo_module "" execsql { SELECT * FROM echo_c WHERE a = 1 } set echo_module } [list xBestIndex {SELECT rowid, * FROM 'c' WHERE a = ?} xFilter {SELECT rowid, * FROM 'c' WHERE a = ?} 1] do_test vtab1-14.4 { set echo_module "" execsql { SELECT * FROM echo_c WHERE a IN (1, 2) } set echo_module } {/xBestIndex {SELECT rowid, . FROM 'c' WHERE a = .} xFilter {SELECT rowid, . FROM 'c' WHERE a = .} 1/} do_test vtab1-15.1 { execsql { CREATE TABLE t1(a, b, c); CREATE VIRTUAL TABLE echo_t1 USING echo(t1); } } {} |
︙ | ︙ |
Changes to test/where.test.
︙ | ︙ | |||
375 376 377 378 379 380 381 | } } {1 0 4 2 1 9 3 1 16 4} do_test where-5.2 { count { SELECT * FROM t1 WHERE rowid+0 IN (1,2,3,1234) order by 1; } } {1 0 4 2 1 9 3 1 16 102} | | | > > > > > > > > > > > > > > > | 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 | } } {1 0 4 2 1 9 3 1 16 4} do_test where-5.2 { count { SELECT * FROM t1 WHERE rowid+0 IN (1,2,3,1234) order by 1; } } {1 0 4 2 1 9 3 1 16 102} do_test where-5.3a { count { SELECT * FROM t1 WHERE w IN (-1,1,2,3) order by 1; } } {1 0 4 2 1 9 3 1 16 13} do_test where-5.3b { count { SELECT * FROM t1 WHERE w IN (3,-1,1,2) order by 1; } } {1 0 4 2 1 9 3 1 16 13} do_test where-5.3c { count { SELECT * FROM t1 WHERE w IN (3,2,-1,1,2) order by 1; } } {1 0 4 2 1 9 3 1 16 13} do_test where-5.3d { count { SELECT * FROM t1 WHERE w IN (-1,1,2,3) order by 1 DESC; } } {3 1 16 2 1 9 1 0 4 12} do_test where-5.4 { count { SELECT * FROM t1 WHERE w+0 IN (-1,1,2,3) order by 1; } } {1 0 4 2 1 9 3 1 16 102} do_test where-5.5 { count { |
︙ | ︙ | |||
448 449 450 451 452 453 454 455 456 457 458 459 460 461 | } } {2 1 9 8} do_test where-5.15 { count { SELECT * FROM t1 WHERE x IN (1,7) AND y IN (9,16) ORDER BY 1; } } {2 1 9 3 1 16 11} } # This procedure executes the SQL. Then it checks to see if the OP_Sort # opcode was executed. If an OP_Sort did occur, then "sort" is appended # to the result. If no OP_Sort happened, then "nosort" is appended. # # This procedure is used to check to make sure sorting is or is not | > > > > > > > > > > > > > > > > > > > > > > > > | 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 | } } {2 1 9 8} do_test where-5.15 { count { SELECT * FROM t1 WHERE x IN (1,7) AND y IN (9,16) ORDER BY 1; } } {2 1 9 3 1 16 11} do_test where-5.100 { db eval { SELECT w, x, y FROM t1 WHERE x IN (1,5) AND y IN (9,8,3025,1000,3969) ORDER BY x, y } } {2 1 9 54 5 3025 62 5 3969} do_test where-5.101 { db eval { SELECT w, x, y FROM t1 WHERE x IN (1,5) AND y IN (9,8,3025,1000,3969) ORDER BY x DESC, y DESC } } {62 5 3969 54 5 3025 2 1 9} do_test where-5.102 { db eval { SELECT w, x, y FROM t1 WHERE x IN (1,5) AND y IN (9,8,3025,1000,3969) ORDER BY x DESC, y } } {54 5 3025 62 5 3969 2 1 9} do_test where-5.103 { db eval { SELECT w, x, y FROM t1 WHERE x IN (1,5) AND y IN (9,8,3025,1000,3969) ORDER BY x, y DESC } } {2 1 9 62 5 3969 54 5 3025} } # This procedure executes the SQL. Then it checks to see if the OP_Sort # opcode was executed. If an OP_Sort did occur, then "sort" is appended # to the result. If no OP_Sort happened, then "nosort" is appended. # # This procedure is used to check to make sure sorting is or is not |
︙ | ︙ | |||
507 508 509 510 511 512 513 | } {1 100 4 2 99 9 3 98 16 nosort} do_test where-6.7 { cksort { SELECT * FROM t3 WHERE b>0 ORDER BY a LIMIT 3 } } {1 100 4 2 99 9 3 98 16 nosort} ifcapable subquery { | | | > > > > > | 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 | } {1 100 4 2 99 9 3 98 16 nosort} do_test where-6.7 { cksort { SELECT * FROM t3 WHERE b>0 ORDER BY a LIMIT 3 } } {1 100 4 2 99 9 3 98 16 nosort} ifcapable subquery { do_test where-6.8a { cksort { SELECT * FROM t3 WHERE a IN (3,5,7,1,9,4,2) ORDER BY a LIMIT 3 } } {1 100 4 2 99 9 3 98 16 nosort} do_test where-6.8b { cksort { SELECT * FROM t3 WHERE a IN (3,5,7,1,9,4,2) ORDER BY a DESC LIMIT 3 } } {9 92 100 7 94 64 5 96 36 nosort} } do_test where-6.9.1 { cksort { SELECT * FROM t3 WHERE a=1 AND c>0 ORDER BY a LIMIT 3 } } {1 100 4 nosort} do_test where-6.9.1.1 { |
︙ | ︙ |
Changes to test/where2.test.
︙ | ︙ | |||
163 164 165 166 167 168 169 | SELECT * FROM t1 WHERE z IN (SELECT 10207 UNION SELECT 10006) AND y IN (SELECT 10000 UNION SELECT 10201) AND x>0 AND x<10 ORDER BY w } } {99 6 10000 10006 100 6 10201 10207 sort t1 i1zyx} } | | > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > | 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 | SELECT * FROM t1 WHERE z IN (SELECT 10207 UNION SELECT 10006) AND y IN (SELECT 10000 UNION SELECT 10201) AND x>0 AND x<10 ORDER BY w } } {99 6 10000 10006 100 6 10201 10207 sort t1 i1zyx} } do_test where2-4.6a { queryplan { SELECT * FROM t1 WHERE x IN (1,2,3,4,5,6,7,8) AND y IN (10000,10001,10002,10003,10004,10005) ORDER BY x } } {99 6 10000 10006 nosort t1 i1xy} do_test where2-4.6b { queryplan { SELECT * FROM t1 WHERE x IN (1,2,3,4,5,6,7,8) AND y IN (10000,10001,10002,10003,10004,10005) ORDER BY x DESC } } {99 6 10000 10006 nosort t1 i1xy} do_test where2-4.6c { queryplan { SELECT * FROM t1 WHERE x IN (1,2,3,4,5,6,7,8) AND y IN (10000,10001,10002,10003,10004,10005) ORDER BY x, y } } {99 6 10000 10006 nosort t1 i1xy} do_test where2-4.6d { queryplan { SELECT * FROM t1 WHERE x IN (1,2,3,4,5,6,7,8) AND y IN (10000,10001,10002,10003,10004,10005) ORDER BY x, y DESC } } {99 6 10000 10006 sort t1 i1xy} # Duplicate entires on the RHS of an IN operator do not cause duplicate # output rows. # do_test where2-4.6x { queryplan { SELECT * FROM t1 WHERE z IN (10207,10006,10006,10207) ORDER BY w } } {99 6 10000 10006 100 6 10201 10207 sort t1 i1zyx} do_test where2-4.6y { queryplan { SELECT * FROM t1 WHERE z IN (10207,10006,10006,10207) ORDER BY w DESC } } {100 6 10201 10207 99 6 10000 10006 sort t1 i1zyx} ifcapable compound { do_test where2-4.7 { queryplan { SELECT * FROM t1 WHERE z IN ( SELECT 10207 UNION ALL SELECT 10006 UNION ALL SELECT 10006 UNION ALL SELECT 10207) ORDER BY w |
︙ | ︙ | |||
203 204 205 206 207 208 209 | do_test where2-5.1 { queryplan { SELECT * FROM t1 WHERE w=99 ORDER BY w } } {99 6 10000 10006 nosort t1 i1w} ifcapable subquery { | | | > > > > > | 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | do_test where2-5.1 { queryplan { SELECT * FROM t1 WHERE w=99 ORDER BY w } } {99 6 10000 10006 nosort t1 i1w} ifcapable subquery { do_test where2-5.2a { queryplan { SELECT * FROM t1 WHERE w IN (99) ORDER BY w } } {99 6 10000 10006 nosort t1 i1w} do_test where2-5.2b { queryplan { SELECT * FROM t1 WHERE w IN (99) ORDER BY w DESC } } {99 6 10000 10006 nosort t1 i1w} } # Verify that OR clauses get translated into IN operators. # set ::idx {} ifcapable subquery {set ::idx i1w} do_test where2-6.1.1 { |
︙ | ︙ |
Changes to test/where8.test.
︙ | ︙ | |||
285 286 287 288 289 290 291 292 293 294 295 296 297 298 | 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 ) ORDER BY c } } {I I I I I I I I I I II II II II II II II II II II III III III III III 9 1} #----------------------------------------------------------------------- # 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 { | > > > > > > > > > > > > > > | 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 | 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 ) ORDER BY c } } {I I I I I I I I I I II II II II II II II II II II III III III III III 9 1} do_test where8-3.21 { execsql_status { SELECT a, d FROM t1, (t2) WHERE (a=d OR b=e) AND a<5 ORDER BY a } } {1 1 2 2 3 3 4 2 4 4 0 0} do_test where8-3.22 { execsql_status { SELECT a, d FROM ((((((t1))), (((t2)))))) WHERE (a=d OR b=e) AND a<5 ORDER BY a } } {1 1 2 2 3 3 4 2 4 4 0 0} #----------------------------------------------------------------------- # The following tests - where8-4.* - verify that adding or removing # indexes does not change the results returned by various queries. # do_test where8-4.1 { execsql { |
︙ | ︙ |
Changes to test/where9.test.
︙ | ︙ | |||
228 229 230 231 232 233 234 | OR (b IS NULL AND c NOT NULL AND d NOT NULL) OR (b NOT NULL AND c IS NULL AND d NOT NULL) ORDER BY a } } {90 91 92 97 scan 98 sort 0} do_test where9-1.3.4 { count_steps { | | | 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | OR (b IS NULL AND c NOT NULL AND d NOT NULL) OR (b NOT NULL AND c IS NULL AND d NOT NULL) ORDER BY a } } {90 91 92 97 scan 98 sort 0} do_test where9-1.3.4 { count_steps { SELECT a FROM (t4) WHERE (b IS NULL AND c NOT NULL AND d NOT NULL) OR (b NOT NULL AND c NOT NULL AND d IS NULL) OR (b NOT NULL AND c IS NULL AND d NOT NULL) ORDER BY a } } {90 91 92 97 scan 98 sort 0} |
︙ | ︙ | |||
870 871 872 873 874 875 876 877 878 879 880 | INSERT INTO t82 VALUES(2,4); INSERT INTO t83 VALUES(5,55); SELECT * FROM t81 LEFT JOIN t82 ON y=b JOIN t83 WHERE c==p OR d==p ORDER BY +a; } } {2 3 4 5 {} {} 5 55 3 4 5 6 2 4 5 55} finish_test | > > > > > > > > > > > > > > > > | 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 | INSERT INTO t82 VALUES(2,4); INSERT INTO t83 VALUES(5,55); SELECT * FROM t81 LEFT JOIN t82 ON y=b JOIN t83 WHERE c==p OR d==p ORDER BY +a; } } {2 3 4 5 {} {} 5 55 3 4 5 6 2 4 5 55} do_test where9-8.2 { db eval { SELECT * FROM t81 LEFT JOIN (t82) ON y=b JOIN t83 WHERE c==p OR d==p ORDER BY +a; } } {2 3 4 5 {} {} 5 55 3 4 5 6 2 4 5 55} do_test where9-8.3 { db eval { SELECT * FROM (t81) LEFT JOIN (main.t82) ON y=b JOIN t83 WHERE c==p OR d==p ORDER BY +a; } } {2 3 4 5 {} {} 5 55 3 4 5 6 2 4 5 55} finish_test |
Changes to tool/build-shell.sh.
︙ | ︙ | |||
11 12 13 14 15 16 17 18 19 | make sqlite3.c gcc -o sqlite3 -g -Os -I. \ -DSQLITE_THREADSAFE=0 \ -DSQLITE_ENABLE_VFSTRACE \ -DSQLITE_ENABLE_STAT3 \ -DSQLITE_ENABLE_FTS4 \ -DSQLITE_ENABLE_RTREE \ -DHAVE_READLINE \ -DHAVE_USLEEP=1 \ | > > | > > > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | make sqlite3.c gcc -o sqlite3 -g -Os -I. \ -DSQLITE_THREADSAFE=0 \ -DSQLITE_ENABLE_VFSTRACE \ -DSQLITE_ENABLE_STAT3 \ -DSQLITE_ENABLE_FTS4 \ -DSQLITE_ENABLE_RTREE \ -DSQLITE_ENABLE_REGEXP \ -DSQLITE_ENABLE_SPELLFIX -DSQLITE_CORE=1 \ -DHAVE_READLINE \ -DHAVE_USLEEP=1 \ ../sqlite/src/shell.c \ ../sqlite/src/test_regexp.c \ ../sqlite/src/test_spellfix.c \ ../sqlite/src/test_vfstrace.c \ sqlite3.c -ldl -lreadline -lncurses |
Changes to tool/showdb.c.
︙ | ︙ | |||
467 468 469 470 471 472 473 | va_list ap; char *zMsg; va_start(ap, zFormat); zMsg = sqlite3_vmprintf(zFormat, ap); va_end(ap); if( pgno<=0 || pgno>mxPage ){ | | | | 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 | va_list ap; char *zMsg; va_start(ap, zFormat); zMsg = sqlite3_vmprintf(zFormat, ap); va_end(ap); if( pgno<=0 || pgno>mxPage ){ printf("ERROR: page %d out of range 1..%d: %s\n", pgno, mxPage, zMsg); sqlite3_free(zMsg); return; } if( zPageUse[pgno]!=0 ){ printf("ERROR: page %d used multiple times:\n", pgno); printf("ERROR: previous: %s\n", zPageUse[pgno]); printf("ERROR: current: %s\n", zMsg); sqlite3_free(zPageUse[pgno]); } zPageUse[pgno] = zMsg; } /* ** Find overflow pages of a cell and describe their usage. |
︙ | ︙ | |||
610 611 612 613 614 615 616 617 618 619 620 621 | i, pgno); } free(a); parent = pgno; pgno = iNext; } } /* ** Try to figure out how every page in the database file is being used. */ static void page_usage_report(const char *zDbName){ | > > > > > > > > > > > > > > > > | > | 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 | i, pgno); } free(a); parent = pgno; pgno = iNext; } } /* ** Determine pages used as PTRMAP pages */ static void page_usage_ptrmap(unsigned char *a){ if( a[55] ){ int usable = pagesize - a[20]; int pgno = 2; int perPage = usable/5; while( pgno<=mxPage ){ page_usage_msg(pgno, "PTRMAP page covering %d..%d", pgno+1, pgno+perPage); pgno += perPage + 1; } } } /* ** Try to figure out how every page in the database file is being used. */ static void page_usage_report(const char *zDbName){ int i, j; int rc; sqlite3 *db; sqlite3_stmt *pStmt; unsigned char *a; char zQuery[200]; /* Avoid the pathological case */ if( mxPage<1 ){ printf("empty database\n"); return; } |
︙ | ︙ | |||
644 645 646 647 648 649 650 651 652 | zPageUse = sqlite3_malloc( sizeof(zPageUse[0])*(mxPage+1) ); if( zPageUse==0 ) out_of_memory(); memset(zPageUse, 0, sizeof(zPageUse[0])*(mxPage+1)); /* Discover the usage of each page */ a = getContent(0, 100); page_usage_freelist(decodeInt32(a+32)); free(a); page_usage_btree(1, 0, 0, "sqlite_master"); | > > > | | > | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | zPageUse = sqlite3_malloc( sizeof(zPageUse[0])*(mxPage+1) ); if( zPageUse==0 ) out_of_memory(); memset(zPageUse, 0, sizeof(zPageUse[0])*(mxPage+1)); /* Discover the usage of each page */ a = getContent(0, 100); page_usage_freelist(decodeInt32(a+32)); page_usage_ptrmap(a); free(a); page_usage_btree(1, 0, 0, "sqlite_master"); sqlite3_exec(db, "PRAGMA writable_schema=ON", 0, 0, 0); for(j=0; j<2; j++){ sqlite3_snprintf(sizeof(zQuery), zQuery, "SELECT type, name, rootpage FROM SQLITE_MASTER WHERE rootpage" " ORDER BY rowid %s", j?"DESC":""); rc = sqlite3_prepare_v2(db, zQuery, -1, &pStmt, 0); if( rc==SQLITE_OK ){ while( sqlite3_step(pStmt)==SQLITE_ROW ){ int pgno = sqlite3_column_int(pStmt, 2); page_usage_btree(pgno, 0, 0, sqlite3_column_text(pStmt, 1)); } }else{ printf("ERROR: cannot query database: %s\n", sqlite3_errmsg(db)); } rc = sqlite3_finalize(pStmt); if( rc==SQLITE_OK ) break; } sqlite3_close(db); /* Print the report and free memory used */ for(i=1; i<=mxPage; i++){ printf("%5d: %s\n", i, zPageUse[i] ? zPageUse[i] : "???"); sqlite3_free(zPageUse[i]); } sqlite3_free(zPageUse); zPageUse = 0; } /* ** Try to figure out how every page in the database file is being used. */ static void ptrmap_coverage_report(const char *zDbName){ unsigned int pgno; unsigned char *aHdr; unsigned char *a; int usable; int perPage; unsigned int i; /* Avoid the pathological case */ if( mxPage<1 ){ printf("empty database\n"); return; } /* Make sure PTRMAPs are used in this database */ aHdr = getContent(0, 100); if( aHdr[55]==0 ){ printf("database does not use PTRMAP pages\n"); return; } usable = pagesize - aHdr[20]; perPage = usable/5; free(aHdr); printf("%5d: root of sqlite_master\n", 1); for(pgno=2; pgno<=mxPage; pgno += perPage+1){ printf("%5d: PTRMAP page covering %d..%d\n", pgno, pgno+1, pgno+perPage); a = getContent((pgno-1)*pagesize, usable); for(i=0; i+5<=usable && pgno+1+i/5<=mxPage; i+=5){ const char *zType = "???"; unsigned int iFrom = decodeInt32(&a[i+1]); switch( a[i] ){ case 1: zType = "b-tree root page"; break; case 2: zType = "freelist page"; break; case 3: zType = "first page of overflow"; break; case 4: zType = "later page of overflow"; break; case 5: zType = "b-tree non-root page"; break; } printf("%5d: %s, parent=%u\n", pgno+1+i/5, zType, iFrom); } free(a); } } /* ** Print a usage comment */ static void usage(const char *argv0){ fprintf(stderr, "Usage %s FILENAME ?args...?\n\n", argv0); fprintf(stderr, "args:\n" " dbheader Show database header\n" " pgidx Index of how each page is used\n" " ptrmap Show all PTRMAP page content\n" " NNN..MMM Show hex of pages NNN through MMM\n" " NNN..end Show hex of pages NNN through end of file\n" " NNNb Decode btree page NNN\n" " NNNbc Decode btree page NNN and show content\n" " NNNbm Decode btree page NNN and show a layout map\n" " NNNt Decode freelist trunk page NNN\n" " NNNtd Show leaf freelist pages on the decode\n" |
︙ | ︙ | |||
726 727 728 729 730 731 732 733 734 735 736 737 738 739 | if( strcmp(argv[i], "dbheader")==0 ){ print_db_header(); continue; } if( strcmp(argv[i], "pgidx")==0 ){ page_usage_report(argv[1]); continue; } if( !isdigit(argv[i][0]) ){ fprintf(stderr, "%s: unknown option: [%s]\n", argv[0], argv[i]); continue; } iStart = strtol(argv[i], &zLeft, 0); if( zLeft && strcmp(zLeft,"..end")==0 ){ | > > > > > > > > | 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 | if( strcmp(argv[i], "dbheader")==0 ){ print_db_header(); continue; } if( strcmp(argv[i], "pgidx")==0 ){ page_usage_report(argv[1]); continue; } if( strcmp(argv[i], "ptrmap")==0 ){ ptrmap_coverage_report(argv[1]); continue; } if( strcmp(argv[i], "help")==0 ){ usage(argv[0]); continue; } if( !isdigit(argv[i][0]) ){ fprintf(stderr, "%s: unknown option: [%s]\n", argv[0], argv[i]); continue; } iStart = strtol(argv[i], &zLeft, 0); if( zLeft && strcmp(zLeft,"..end")==0 ){ |
︙ | ︙ |
Changes to tool/showwal.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 21 22 23 24 25 26 27 | static int pagesize = 1024; /* Size of a database page */ static int fd = -1; /* File descriptor for reading the WAL file */ static int mxFrame = 0; /* Last frame */ static int perLine = 16; /* HEX elements to print per line */ typedef long long int i64; /* Datatype for 64-bit integers */ /* ** Convert the var-int format into i64. Return the number of bytes ** in the var-int. Write the var-int value into *pVal. */ static int decodeVarint(const unsigned char *z, i64 *pVal){ i64 v = 0; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | static int pagesize = 1024; /* Size of a database page */ static int fd = -1; /* File descriptor for reading the WAL file */ static int mxFrame = 0; /* Last frame */ static int perLine = 16; /* HEX elements to print per line */ typedef long long int i64; /* Datatype for 64-bit integers */ /* Information for computing the checksum */ typedef struct Cksum Cksum; struct Cksum { int bSwap; /* True to do byte swapping on 32-bit words */ unsigned s0, s1; /* Current checksum value */ }; /* ** extract a 32-bit big-endian integer */ static unsigned int getInt32(const unsigned char *a){ unsigned int x = (a[0]<<24) + (a[1]<<16) + (a[2]<<8) + a[3]; return x; } /* ** Swap bytes on a 32-bit unsigned integer */ static unsigned int swab32(unsigned int x){ return (((x)&0x000000FF)<<24) + (((x)&0x0000FF00)<<8) + (((x)&0x00FF0000)>>8) + (((x)&0xFF000000)>>24); } /* Extend the checksum. Reinitialize the checksum if bInit is true. */ static void extendCksum( Cksum *pCksum, unsigned char *aData, unsigned int nByte, int bInit ){ unsigned int *a32; if( bInit ){ int a = 0; *((char*)&a) = 1; if( a==1 ){ /* Host is little-endian */ pCksum->bSwap = getInt32(aData)!=0x377f0682; }else{ /* Host is big-endian */ pCksum->bSwap = getInt32(aData)!=0x377f0683; } pCksum->s0 = 0; pCksum->s1 = 0; } a32 = (unsigned int*)aData; while( nByte>0 ){ unsigned int x0 = a32[0]; unsigned int x1 = a32[1]; if( pCksum->bSwap ){ x0 = swab32(x0); x1 = swab32(x1); } pCksum->s0 += x0 + pCksum->s1; pCksum->s1 += x1 + pCksum->s0; nByte -= 8; a32 += 2; } } /* ** Convert the var-int format into i64. Return the number of bytes ** in the var-int. Write the var-int value into *pVal. */ static int decodeVarint(const unsigned char *z, i64 *pVal){ i64 v = 0; |
︙ | ︙ | |||
148 149 150 151 152 153 154 | print_decode_line(aData,16, 4, 1, "Checksum-1"); print_decode_line(aData,20, 4, 1, "Checksum-2"); print_byte_range(iStart+24, pagesize, aData+24, 0); free(aData); } /* | < < < < < < | < < | > > > > > | < | > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > | | | > > > | > > > > > > > > > > > | | > > > > > | > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > | 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 | print_decode_line(aData,16, 4, 1, "Checksum-1"); print_decode_line(aData,20, 4, 1, "Checksum-2"); print_byte_range(iStart+24, pagesize, aData+24, 0); free(aData); } /* ** Summarize a single frame on a single line. */ static void print_oneline_frame(int iFrame, Cksum *pCksum){ int iStart; unsigned char *aData; unsigned int s0, s1; iStart = 32 + (iFrame-1)*(pagesize+24); aData = getContent(iStart, 24); extendCksum(pCksum, aData, 8, 0); extendCksum(pCksum, getContent(iStart+24, pagesize), pagesize, 0); s0 = getInt32(aData+16); s1 = getInt32(aData+20); fprintf(stdout, "Frame %4d: %6d %6d 0x%08x,%08x 0x%08x,%08x %s\n", iFrame, getInt32(aData), getInt32(aData+4), getInt32(aData+8), getInt32(aData+12), s0, s1, (s0==pCksum->s0 && s1==pCksum->s1) ? "" : "cksum-fail" ); /* Reset the checksum so that a single frame checksum failure will not ** cause all subsequent frames to also show a failure. */ pCksum->s0 = s0; pCksum->s1 = s1; free(aData); } /* ** Decode the WAL header. */ static void print_wal_header(Cksum *pCksum){ unsigned char *aData; aData = getContent(0, 32); if( pCksum ){ extendCksum(pCksum, aData, 24, 1); printf("Checksum byte order: %s\n", pCksum->bSwap ? "swapped" : "native"); } printf("WAL Header:\n"); print_decode_line(aData, 0, 4,1,"Magic. 0x377f0682 (le) or 0x377f0683 (be)"); print_decode_line(aData, 4, 4, 0, "File format"); print_decode_line(aData, 8, 4, 0, "Database page size"); print_decode_line(aData, 12,4, 0, "Checkpoint sequence number"); print_decode_line(aData, 16,4, 1, "Salt-1"); print_decode_line(aData, 20,4, 1, "Salt-2"); print_decode_line(aData, 24,4, 1, "Checksum-1"); print_decode_line(aData, 28,4, 1, "Checksum-2"); if( pCksum ){ if( pCksum->s0!=getInt32(aData+24) ){ printf("**** cksum-1 mismatch: 0x%08x\n", pCksum->s0); } if( pCksum->s1!=getInt32(aData+28) ){ printf("**** cksum-2 mismatch: 0x%08x\n", pCksum->s1); } } free(aData); } /* ** Describe cell content. */ static int describeContent( unsigned char *a, /* Cell content */ int nLocal, /* Bytes in a[] */ char *zDesc /* Write description here */ ){ int nDesc = 0; int n, i, j; i64 x, v; const unsigned char *pData; const unsigned char *pLimit; char sep = ' '; pLimit = &a[nLocal]; n = decodeVarint(a, &x); pData = &a[x]; a += n; i = x - n; while( i>0 && pData<=pLimit ){ n = decodeVarint(a, &x); a += n; i -= n; nLocal -= n; zDesc[0] = sep; sep = ','; nDesc++; zDesc++; if( x==0 ){ sprintf(zDesc, "*"); /* NULL is a "*" */ }else if( x>=1 && x<=6 ){ v = (signed char)pData[0]; pData++; switch( x ){ case 6: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2; case 5: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2; case 4: v = (v<<8) + pData[0]; pData++; case 3: v = (v<<8) + pData[0]; pData++; case 2: v = (v<<8) + pData[0]; pData++; } sprintf(zDesc, "%lld", v); }else if( x==7 ){ sprintf(zDesc, "real"); pData += 8; }else if( x==8 ){ sprintf(zDesc, "0"); }else if( x==9 ){ sprintf(zDesc, "1"); }else if( x>=12 ){ int size = (x-12)/2; if( (x&1)==0 ){ sprintf(zDesc, "blob(%d)", size); }else{ sprintf(zDesc, "txt(%d)", size); } pData += size; } j = strlen(zDesc); zDesc += j; nDesc += j; } return nDesc; } /* ** Compute the local payload size given the total payload size and ** the page size. */ static int localPayload(i64 nPayload, char cType){ int maxLocal; int minLocal; int surplus; int nLocal; if( cType==13 ){ /* Table leaf */ maxLocal = pagesize-35; minLocal = (pagesize-12)*32/255-23; }else{ maxLocal = (pagesize-12)*64/255-23; minLocal = (pagesize-12)*32/255-23; } if( nPayload>maxLocal ){ surplus = minLocal + (nPayload-minLocal)%(pagesize-4); if( surplus<=maxLocal ){ nLocal = surplus; }else{ nLocal = minLocal; } }else{ nLocal = nPayload; } return nLocal; } /* ** Create a description for a single cell. ** ** The return value is the local cell size. */ static int describeCell( unsigned char cType, /* Page type */ unsigned char *a, /* Cell content */ int showCellContent, /* Show cell content if true */ char **pzDesc /* Store description here */ ){ int i; int nDesc = 0; int n = 0; int leftChild; i64 nPayload; i64 rowid; int nLocal; static char zDesc[1000]; i = 0; if( cType<=5 ){ leftChild = ((a[0]*256 + a[1])*256 + a[2])*256 + a[3]; a += 4; n += 4; sprintf(zDesc, "lx: %d ", leftChild); nDesc = strlen(zDesc); } if( cType!=5 ){ i = decodeVarint(a, &nPayload); a += i; n += i; sprintf(&zDesc[nDesc], "n: %lld ", nPayload); nDesc += strlen(&zDesc[nDesc]); nLocal = localPayload(nPayload, cType); }else{ nPayload = nLocal = 0; } if( cType==5 || cType==13 ){ i = decodeVarint(a, &rowid); a += i; n += i; sprintf(&zDesc[nDesc], "r: %lld ", rowid); nDesc += strlen(&zDesc[nDesc]); } if( nLocal<nPayload ){ int ovfl; unsigned char *b = &a[nLocal]; ovfl = ((b[0]*256 + b[1])*256 + b[2])*256 + b[3]; sprintf(&zDesc[nDesc], "ov: %d ", ovfl); nDesc += strlen(&zDesc[nDesc]); n += 4; } if( showCellContent && cType!=5 ){ nDesc += describeContent(a, nLocal, &zDesc[nDesc-1]); } *pzDesc = zDesc; return nLocal+n; } /* ** Decode a btree page */ static void decode_btree_page( unsigned char *a, /* Content of the btree page to be decoded */ int pgno, /* Page number */ int hdrSize, /* Size of the page1-header in bytes */ const char *zArgs /* Flags to control formatting */ ){ const char *zType = "unknown"; int nCell; int i, j; int iCellPtr; int showCellContent = 0; int showMap = 0; char *zMap = 0; switch( a[0] ){ case 2: zType = "index interior node"; break; case 5: zType = "table interior node"; break; case 10: zType = "index leaf"; break; case 13: zType = "table leaf"; break; } while( zArgs[0] ){ switch( zArgs[0] ){ case 'c': showCellContent = 1; break; case 'm': showMap = 1; break; } zArgs++; } printf("Decode of btree page %d:\n", pgno); print_decode_line(a, 0, 1, 0, zType); print_decode_line(a, 1, 2, 0, "Offset to first freeblock"); print_decode_line(a, 3, 2, 0, "Number of cells on this page"); nCell = a[3]*256 + a[4]; print_decode_line(a, 5, 2, 0, "Offset to cell content area"); print_decode_line(a, 7, 1, 0, "Fragmented byte count"); if( a[0]==2 || a[0]==5 ){ print_decode_line(a, 8, 4, 0, "Right child"); iCellPtr = 12; }else{ iCellPtr = 8; } if( nCell>0 ){ printf(" key: lx=left-child n=payload-size r=rowid\n"); } if( showMap ){ zMap = malloc(pagesize); memset(zMap, '.', pagesize); memset(zMap, '1', hdrSize); memset(&zMap[hdrSize], 'H', iCellPtr); memset(&zMap[hdrSize+iCellPtr], 'P', 2*nCell); } for(i=0; i<nCell; i++){ int cofst = iCellPtr + i*2; char *zDesc; int n; cofst = a[cofst]*256 + a[cofst+1]; n = describeCell(a[0], &a[cofst-hdrSize], showCellContent, &zDesc); if( showMap ){ char zBuf[30]; memset(&zMap[cofst], '*', n); zMap[cofst] = '['; zMap[cofst+n-1] = ']'; sprintf(zBuf, "%d", i); j = strlen(zBuf); if( j<=n-2 ) memcpy(&zMap[cofst+1], zBuf, j); } printf(" %03x: cell[%d] %s\n", cofst, i, zDesc); } if( showMap ){ for(i=0; i<pagesize; i+=64){ printf(" %03x: %.64s\n", i, &zMap[i]); } free(zMap); } } int main(int argc, char **argv){ struct stat sbuf; unsigned char zPgSz[2]; if( argc<2 ){ fprintf(stderr,"Usage: %s FILENAME ?PAGE? ...\n", argv[0]); |
︙ | ︙ | |||
294 295 296 297 298 299 300 | printf("file too small to be a WAL\n"); return 0; } mxFrame = (sbuf.st_size - 32)/(pagesize + 24); printf("Available pages: 1..%d\n", mxFrame); if( argc==2 ){ int i; | > | | > > | < > > | < | 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 | printf("file too small to be a WAL\n"); return 0; } mxFrame = (sbuf.st_size - 32)/(pagesize + 24); printf("Available pages: 1..%d\n", mxFrame); if( argc==2 ){ int i; Cksum x; print_wal_header(&x); for(i=1; i<=mxFrame; i++){ print_oneline_frame(i, &x); } }else{ int i; for(i=2; i<argc; i++){ int iStart, iEnd; char *zLeft; if( strcmp(argv[i], "header")==0 ){ print_wal_header(0); continue; } if( !isdigit(argv[i][0]) ){ fprintf(stderr, "%s: unknown option: [%s]\n", argv[0], argv[i]); continue; } iStart = strtol(argv[i], &zLeft, 0); if( zLeft && strcmp(zLeft,"..end")==0 ){ iEnd = mxFrame; }else if( zLeft && zLeft[0]=='.' && zLeft[1]=='.' ){ iEnd = strtol(&zLeft[2], 0, 0); }else if( zLeft && zLeft[0]=='b' ){ int ofst, nByte, hdrSize; unsigned char *a; if( iStart==1 ){ hdrSize = 100; ofst = hdrSize = 100; nByte = pagesize-100; }else{ hdrSize = 0; ofst = (iStart-1)*pagesize; nByte = pagesize; } ofst = 32 + hdrSize + (iStart-1)*(pagesize+24) + 24; a = getContent(ofst, nByte); decode_btree_page(a, iStart, hdrSize, zLeft+1); free(a); continue; }else{ iEnd = iStart; } if( iStart<1 || iEnd<iStart || iEnd>mxFrame ){ fprintf(stderr, "Page argument should be LOWER?..UPPER?. Range 1 to %d\n", mxFrame); |
︙ | ︙ |