Compare commits
200 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 09ff9e1664 | |||
| 3da0df9d18 | |||
| 6d235cb8d8 | |||
| 994ff6f587 | |||
| dbd4d5fc77 | |||
| fe7a5d11b6 | |||
| 5acefe7dbe | |||
| ef593f293e | |||
| 42c4bd02f4 | |||
| 459f63e7ed | |||
| a0272d8255 | |||
| cfc176973e | |||
| 77dfe91662 | |||
| b83c21e600 | |||
| e3664fb03c | |||
| e1df4e31ec | |||
| edf9a17b47 | |||
| 84fb4c22b9 | |||
| e0ac363c62 | |||
| 7015698b81 | |||
| 82e647d7c3 | |||
| 1d59d036de | |||
| 1488052d38 | |||
| 6e8a54fbd2 | |||
| 6ffb4975f7 | |||
| de97724827 | |||
| 503a686e09 | |||
| 016fff2b6e | |||
| dd1dd489d9 | |||
| 9cf37e718c | |||
| 8d0b81d764 | |||
| c9545442f9 | |||
| fbc1ddf079 | |||
| c6a67173bd | |||
| 132d93838d | |||
| f2874b0e1d | |||
| 295fc442b5 | |||
| 896f99e942 | |||
| 9138471141 | |||
| e0b605917e | |||
| 22d2730047 | |||
| b88e24fd59 | |||
| 87ade19eb9 | |||
| bc1a3c6ce2 | |||
| f38b65a85d | |||
| 51f0b6d568 | |||
| d495d8c9a3 | |||
| d5d0f6432c | |||
| 344a97b4b0 | |||
| 103a70fa62 | |||
| 00e637f0f0 | |||
| 5c5760aa81 | |||
| 4bde37027c | |||
| 5cee8a7af5 | |||
| c8ac0d1649 | |||
| 4600255a88 | |||
| c95e01da22 | |||
| 9ce59a947f | |||
| 4207a3fb9b | |||
| a4b05e2874 | |||
| 25129243b7 | |||
| 785097da6b | |||
| 7e87eae901 | |||
| a173eab75f | |||
| 433dccfb52 | |||
| d91c1a1768 | |||
| 5edf8435d3 | |||
| 3667033bfc | |||
| 2d96b934c8 | |||
| c3e552ff5c | |||
| 1b8fc65b92 | |||
| 928d9c6209 | |||
| 2bfe1df01b | |||
| 28a3bcba0a | |||
| 547180baf0 | |||
| e096205a7f | |||
| 47f2239fc1 | |||
| d2a5623866 | |||
| 173ba0998c | |||
| 7c37e2f674 | |||
| ef4c035275 | |||
| d3ac7d9b51 | |||
| 1590d10bc9 | |||
| 03c41c0bc9 | |||
| d63ce044d1 | |||
| bc46f02c5d | |||
| 25fe97ae88 | |||
| afe1dd84af | |||
| b064dc33bc | |||
| f218ee2dd4 | |||
| 28fc473ce6 | |||
| eb5bc9261c | |||
| 63db0392ae | |||
| 738fc79dcf | |||
| 806c00666f | |||
| 413c63ba81 | |||
| 58eb1c0af1 | |||
| 7fe18b4105 | |||
| 7a5bcc0f08 | |||
| 3bd5ab8638 | |||
| ea84a65e4e | |||
| 5d5cf01ee0 | |||
| 9f5ff37120 | |||
| 9fe27de651 | |||
| 29a8bf8e94 | |||
| 97a3e09f4e | |||
| be93ca3561 | |||
| ddd1fc7283 | |||
| aa5df79d32 | |||
| a8e97da9ae | |||
| e1186ab260 | |||
| e454f3d6f8 | |||
| 6578dd67fa | |||
| 26de1e9956 | |||
| 953bf725b4 | |||
| 38b384a032 | |||
| c75e09c761 | |||
| 3e3f1a5b49 | |||
| fb7773276b | |||
| d530ee64ca | |||
| b376daeb67 | |||
| 384b7fe221 | |||
| 25846af3be | |||
| 14172743a2 | |||
| 5cc3bea44a | |||
| b2bb176b70 | |||
| 83e0dba311 | |||
| b290294c46 | |||
| 0e8578fc9e | |||
| 11c6387d38 | |||
| 7ee751d241 | |||
| 0dde4739f3 | |||
| 8f25d18b21 | |||
| 832ee3d4cc | |||
| 92689d2869 | |||
| e924041846 | |||
| 985cd59c48 | |||
| 7d22a4d710 | |||
| 4b4b473a1e | |||
| 9148defa61 | |||
| 613028b34e | |||
| a7c2f3e760 | |||
| 6c5b915fcb | |||
| 6d42097622 | |||
| d03025327e | |||
| 03597ef6e2 | |||
| e40ed78c1c | |||
| b3256037ff | |||
| 92f76572e0 | |||
| 4ac391fc05 | |||
| 32055c2499 | |||
| 2d6381865d | |||
| 6949784cc4 | |||
| 39ac5de6c5 | |||
| be707b396a | |||
| b136e902ad | |||
| de7ced37fe | |||
| 04229acebc | |||
| 468ef9a87e | |||
| 261d8a51e2 | |||
| fb76f5a00c | |||
| 0ca10dfbed | |||
| 2d8e920339 | |||
| 580c8c1816 | |||
| d91eba9673 | |||
| 85d641f948 | |||
| 8e049633aa | |||
| 62a66e7034 | |||
| 953f7611da | |||
| bd13d34b08 | |||
| 7a66da1395 | |||
| 4b2f358938 | |||
| 0a8a406e9b | |||
| 4b17cf5855 | |||
| bac19cf904 | |||
| 88be0144fb | |||
| 46af59e96c | |||
| ae80ddea9f | |||
| fd4d47053d | |||
| f78baafe41 | |||
| 696b33e622 | |||
| 74358f0c77 | |||
| 48dd9deffe | |||
| f44d4b41bd | |||
| 0590552811 | |||
| e6f1e760d5 | |||
| f344a5e70e | |||
| e825831ee4 | |||
| 97305a7ccb | |||
| 9ccaefb172 | |||
| 7f5febc729 | |||
| 44c4fcb9d8 | |||
| 3de0f18476 | |||
| 8411b25c59 | |||
| 68c804b9ab | |||
| ec6b07b27b | |||
| d483dfa4b4 | |||
| 7b6be6f7bf | |||
| a359b5eea4 | |||
| 281bbe2a95 |
+3
-2
@@ -45,7 +45,7 @@ TCC += @TCL_INCLUDE_SPEC@
|
||||
|
||||
# The library that programs using TCL must link against.
|
||||
#
|
||||
LIBTCL = @TCL_LIB_SPEC@ @TCL_LIBS@
|
||||
LIBTCL = @TCL_LIB_SPEC@
|
||||
|
||||
# Compiler options needed for programs that use the readline() library.
|
||||
#
|
||||
@@ -357,6 +357,7 @@ TESTSRC = \
|
||||
$(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 \
|
||||
@@ -370,6 +371,7 @@ TESTSRC = \
|
||||
$(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 \
|
||||
@@ -935,7 +937,6 @@ clean:
|
||||
rm -rf .libs .deps
|
||||
rm -f lemon$(BEXE) lempar.c parse.* sqlite*.tar.gz
|
||||
rm -f mkkeywordhash$(BEXE) keywordhash.h
|
||||
rm -f $(PUBLISH)
|
||||
rm -f *.da *.bb *.bbg gmon.out
|
||||
rm -rf quota2a quota2b quota2c
|
||||
rm -rf tsrc .target_source
|
||||
|
||||
+4
-2
@@ -678,6 +678,7 @@ TESTSRC = \
|
||||
$(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 \
|
||||
@@ -691,6 +692,7 @@ TESTSRC = \
|
||||
$(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 \
|
||||
@@ -829,8 +831,8 @@ sqlite3.exe: $(TOP)\src\shell.c libsqlite3.lib $(LIBRESOBJS) sqlite3.h
|
||||
sqlite3.c: .target_source $(TOP)\tool\mksqlite3c.tcl
|
||||
$(TCLSH_CMD) $(TOP)\tool\mksqlite3c.tcl
|
||||
|
||||
sqlite3-all.c: sqlite3.c $(TOP)/tool/split-sqlite3c.tcl
|
||||
$(TCLSH_CMD) $(TOP)/tool/split-sqlite3c.tcl
|
||||
sqlite3-all.c: sqlite3.c $(TOP)\tool\split-sqlite3c.tcl
|
||||
$(TCLSH_CMD) $(TOP)\tool\split-sqlite3c.tcl
|
||||
|
||||
# Rule to build the amalgamation
|
||||
#
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.62 for sqlite 3.7.15.
|
||||
# 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.
|
||||
@@ -743,8 +743,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='sqlite'
|
||||
PACKAGE_TARNAME='sqlite'
|
||||
PACKAGE_VERSION='3.7.15'
|
||||
PACKAGE_STRING='sqlite 3.7.15'
|
||||
PACKAGE_VERSION='3.7.16'
|
||||
PACKAGE_STRING='sqlite 3.7.16'
|
||||
PACKAGE_BUGREPORT=''
|
||||
|
||||
# Factoring default headers for most tests.
|
||||
@@ -879,7 +879,6 @@ TARGET_EXEEXT
|
||||
TCL_VERSION
|
||||
TCL_BIN_DIR
|
||||
TCL_SRC_DIR
|
||||
TCL_LIBS
|
||||
TCL_INCLUDE_SPEC
|
||||
TCL_LIB_FILE
|
||||
TCL_LIB_FLAG
|
||||
@@ -1485,7 +1484,7 @@ 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.15 to adapt to many kinds of systems.
|
||||
\`configure' configures sqlite 3.7.16 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1550,7 +1549,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of sqlite 3.7.15:";;
|
||||
short | recursive ) echo "Configuration of sqlite 3.7.16:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1666,7 +1665,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
sqlite configure 3.7.15
|
||||
sqlite configure 3.7.16
|
||||
generated by GNU Autoconf 2.62
|
||||
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||||
@@ -1680,7 +1679,7 @@ 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.15, which was
|
||||
It was created by sqlite $as_me 3.7.16, which was
|
||||
generated by GNU Autoconf 2.62. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -3734,13 +3733,13 @@ if test "${lt_cv_nm_interface+set}" = set; then
|
||||
else
|
||||
lt_cv_nm_interface="BSD nm"
|
||||
echo "int some_variable = 0;" > conftest.$ac_ext
|
||||
(eval echo "\"\$as_me:3737: $ac_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:3736: $ac_compile\"" >&5)
|
||||
(eval "$ac_compile" 2>conftest.err)
|
||||
cat conftest.err >&5
|
||||
(eval echo "\"\$as_me:3740: $NM \\\"conftest.$ac_objext\\\"\"" >&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:3743: output\"" >&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"
|
||||
@@ -4962,7 +4961,7 @@ ia64-*-hpux*)
|
||||
;;
|
||||
*-*-irix6*)
|
||||
# Find out which ABI we are using.
|
||||
echo '#line 4965 "configure"' > conftest.$ac_ext
|
||||
echo '#line 4964 "configure"' > conftest.$ac_ext
|
||||
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
|
||||
(eval $ac_compile) 2>&5
|
||||
ac_status=$?
|
||||
@@ -6831,11 +6830,11 @@ else
|
||||
-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:6834: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:6833: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>conftest.err)
|
||||
ac_status=$?
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:6838: \$? = $ac_status" >&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.
|
||||
@@ -7170,11 +7169,11 @@ else
|
||||
-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:7173: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:7172: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>conftest.err)
|
||||
ac_status=$?
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:7177: \$? = $ac_status" >&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.
|
||||
@@ -7275,11 +7274,11 @@ else
|
||||
-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:7278: $lt_compile\"" >&5)
|
||||
(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:7282: \$? = $ac_status" >&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
|
||||
@@ -7330,11 +7329,11 @@ else
|
||||
-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:7333: $lt_compile\"" >&5)
|
||||
(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:7337: \$? = $ac_status" >&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
|
||||
@@ -10143,7 +10142,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 10146 "configure"
|
||||
#line 10145 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@@ -10239,7 +10238,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 10242 "configure"
|
||||
#line 10241 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@@ -12909,7 +12908,6 @@ $as_echo "file not found" >&6; }
|
||||
|
||||
|
||||
|
||||
|
||||
fi
|
||||
fi
|
||||
if test "${use_tcl}" = "no" ; then
|
||||
@@ -14034,7 +14032,7 @@ exec 6>&1
|
||||
# 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.15, which was
|
||||
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
|
||||
@@ -14087,7 +14085,7 @@ Report bugs to <bug-autoconf@gnu.org>."
|
||||
_ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_version="\\
|
||||
sqlite config.status 3.7.15
|
||||
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'`\\"
|
||||
|
||||
|
||||
@@ -501,7 +501,6 @@ if test "${use_tcl}" = "yes" ; then
|
||||
AC_SUBST(TCL_VERSION)
|
||||
AC_SUBST(TCL_BIN_DIR)
|
||||
AC_SUBST(TCL_SRC_DIR)
|
||||
AC_SUBST(TCL_LIBS)
|
||||
AC_SUBST(TCL_INCLUDE_SPEC)
|
||||
|
||||
AC_SUBST(TCL_LIB_FILE)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
NOTE (2012-11-29):
|
||||
|
||||
The functionality implemented by this extension has been superceded
|
||||
The functionality implemented by this extension has been superseded
|
||||
by WAL-mode. This module is no longer supported or maintained. The
|
||||
code is retained for historical reference only.
|
||||
|
||||
|
||||
@@ -1510,6 +1510,7 @@ static void asyncWriterThread(void){
|
||||
case ASYNC_DELETE:
|
||||
ASYNC_TRACE(("DELETE %s\n", p->zBuf));
|
||||
rc = pVfs->xDelete(pVfs, p->zBuf, (int)p->iOffset);
|
||||
if( rc==SQLITE_IOERR_DELETE_NOENT ) rc = SQLITE_OK;
|
||||
break;
|
||||
|
||||
case ASYNC_OPENEXCLUSIVE: {
|
||||
|
||||
@@ -75,7 +75,7 @@ int sqlite3async_initialize(const char *zParent, int isDefault);
|
||||
** On win32 platforms, this function also releases the small number of
|
||||
** critical section and event objects created by sqlite3async_initialize().
|
||||
*/
|
||||
void sqlite3async_shutdown();
|
||||
void sqlite3async_shutdown(void);
|
||||
|
||||
/*
|
||||
** This function may only be called when the asynchronous IO VFS is
|
||||
@@ -94,7 +94,7 @@ void sqlite3async_shutdown();
|
||||
** If multiple simultaneous calls are made to sqlite3async_run() from two
|
||||
** or more threads, then the calls are serialized internally.
|
||||
*/
|
||||
void sqlite3async_run();
|
||||
void sqlite3async_run(void);
|
||||
|
||||
/*
|
||||
** This function may only be called when the asynchronous IO VFS is
|
||||
|
||||
@@ -5253,7 +5253,7 @@ int sqlite3Fts3UpdateMethod(
|
||||
int rc = SQLITE_OK; /* Return Code */
|
||||
int isRemove = 0; /* True for an UPDATE or DELETE */
|
||||
u32 *aSzIns = 0; /* Sizes of inserted documents */
|
||||
u32 *aSzDel; /* Sizes of deleted documents */
|
||||
u32 *aSzDel = 0; /* Sizes of deleted documents */
|
||||
int nChng = 0; /* Net change in number of documents */
|
||||
int bInsertDone = 0;
|
||||
|
||||
|
||||
+8
-2
@@ -3049,7 +3049,8 @@ static int getIntFromStmt(sqlite3 *db, const char *zSql, int *piVal){
|
||||
static int getNodeSize(
|
||||
sqlite3 *db, /* Database handle */
|
||||
Rtree *pRtree, /* Rtree handle */
|
||||
int isCreate /* True for xCreate, false for xConnect */
|
||||
int isCreate, /* True for xCreate, false for xConnect */
|
||||
char **pzErr /* OUT: Error message, if any */
|
||||
){
|
||||
int rc;
|
||||
char *zSql;
|
||||
@@ -3062,6 +3063,8 @@ static int getNodeSize(
|
||||
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(
|
||||
@@ -3069,6 +3072,9 @@ static int getNodeSize(
|
||||
pRtree->zDb, pRtree->zName
|
||||
);
|
||||
rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize);
|
||||
if( rc!=SQLITE_OK ){
|
||||
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_free(zSql);
|
||||
@@ -3132,7 +3138,7 @@ static int rtreeInit(
|
||||
memcpy(pRtree->zName, argv[2], nName);
|
||||
|
||||
/* Figure out the node size to use. */
|
||||
rc = getNodeSize(db, pRtree, isCreate);
|
||||
rc = getNodeSize(db, pRtree, isCreate, pzErr);
|
||||
|
||||
/* Create/Connect to the underlying relational database schema. If
|
||||
** that is successful, call sqlite3_declare_vtab() to configure
|
||||
|
||||
@@ -240,6 +240,7 @@ TESTSRC = \
|
||||
$(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 \
|
||||
@@ -253,6 +254,7 @@ TESTSRC = \
|
||||
$(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 \
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
C Improvements\sto\sthe\s'tcl'\sshell\soutput\smode.\s\sEscape\sdouble\squotes,\sset\sseparator\sto\sspace\swhen\smode\sis\sset,\sand\sskip\sseparator\safter\sfinal\scolumn.
|
||||
D 2012-12-04T00:23:43.067
|
||||
C Fixes\sfor\scompiling\swith\sSQLITE_OMIT_AUTOVACUUM\sand/or\sSQLITE_OMIT_TRIGGER\sdefined.
|
||||
D 2013-03-11T11:49:03.189
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 82c41c0ed4cc94dd3cc7d498575b84c57c2c2384
|
||||
F Makefile.in 9a804abbd3cae82d196e4d33aba13239e32522a5
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
F Makefile.msc 911b8188f5d67801035a113e063c3023a617525d
|
||||
F Makefile.msc 1bed3bca025ee90441bb0c9f95f36f42b70bd839
|
||||
F Makefile.vxworks b18ad88e9a8c6a001f5cf4a389116a4f1a7ab45f
|
||||
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
|
||||
F VERSION edab4af5a4623f8198833ea481ce98ab53750a8d
|
||||
F VERSION 6d4f66eaebabc42ef8c2a4d2d0caf4ce7ee81137
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
F addopcodes.awk 17dc593f791f874d2c23a0f9360850ded0286531
|
||||
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
|
||||
@@ -15,16 +15,16 @@ F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2
|
||||
F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977
|
||||
F config.h.in 0921066a13130082764ab4ab6456f7b5bebe56de
|
||||
F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
|
||||
F configure 4907207e1627a394e8892cce8dcc8068fbe5f7cd x
|
||||
F configure.ac 6e909664785b8184db2179013cd9d574f96ca3a3
|
||||
F configure 00d3a5fda47ee7dd3e68dc9dad7eeb439cd1ffea x
|
||||
F configure.ac 81c43d151d0b0e406be056394cc9ff4cb3fd0444
|
||||
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
|
||||
F doc/lemon.html 334dbf6621b8fb8790297ec1abf3cfa4621709d1
|
||||
F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710
|
||||
F doc/vfs-shm.txt e101f27ea02a8387ce46a05be2b1a902a021d37a
|
||||
F ext/README.txt 913a7bd3f4837ab14d7e063304181787658b14e1
|
||||
F ext/async/README.txt 048f24b1b8f28eb31fb84aac28e70a6ce3de6973
|
||||
F ext/async/sqlite3async.c 733a9f21b1066f44ff07b9c0da973b1e483d1e0c
|
||||
F ext/async/sqlite3async.h a21e1252deb14a2c211f0e165c4b9122a8f1f344
|
||||
F ext/async/README.txt e12275968f6fde133a80e04387d0e839b0c51f91
|
||||
F ext/async/sqlite3async.c b5a3e30f538a9ffe81538b3063b4d5963f9bb422
|
||||
F ext/async/sqlite3async.h f489b080af7e72aec0e1ee6f1d98ab6cf2e4dcef
|
||||
F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e
|
||||
F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b
|
||||
F ext/fts1/ft_hash.h 1a35e654a235c2c662d3ca0dfc3138ad60b8b7d5
|
||||
@@ -72,7 +72,7 @@ F ext/fts3/fts3_tokenizer.h 66dec98e365854b6cd2d54f1a96bb6d428fc5a68
|
||||
F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004
|
||||
F ext/fts3/fts3_unicode.c 49e36e6ba59f79e6bd6a8bfe434570fe48d20559
|
||||
F ext/fts3/fts3_unicode2.c a863f05f758af36777dffc2facc898bc73fec896
|
||||
F ext/fts3/fts3_write.c a432433a706bd065e8bb0f8b3b33ce7cf9d7f21d
|
||||
F ext/fts3/fts3_write.c c2166f7148a4ad8bcdad99a99d647b1091744e6b
|
||||
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
|
||||
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
|
||||
F ext/fts3/tool/fts3view.c 6cfc5b67a5f0e09c0d698f9fd012c784bfaa9197
|
||||
@@ -83,7 +83,7 @@ F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9
|
||||
F ext/icu/icu.c eb9ae1d79046bd7871aa97ee6da51eb770134b5a
|
||||
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
F ext/rtree/rtree.c 47064ee2995a396bfb626337d2b43f12cc0af687
|
||||
F ext/rtree/rtree.c ebd07d0f06dc167f1424ff3940a5711a3a039982
|
||||
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
|
||||
F ext/rtree/rtree1.test e474a2b5eff231496dbd073fe67e5fbaf7f444c9
|
||||
F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba
|
||||
@@ -103,7 +103,7 @@ F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
|
||||
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F main.mk a0d170ae1a8a8683688e281194e09d47a68eaa3f
|
||||
F main.mk 404cd38114d1a94ef6ad5aa01a1c8bb46da36161
|
||||
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
|
||||
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
|
||||
F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac
|
||||
@@ -115,35 +115,35 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
|
||||
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
|
||||
F src/alter.c f8db986c03eb0bfb221523fc9bbb9d0b70de3168
|
||||
F src/analyze.c 7553068d21e32a57fc33ab6b2393fc8c1ba41410
|
||||
F src/attach.c 34c15ecd686e58f08e5bb1389e28a0b65c2c83db
|
||||
F src/analyze.c d5f895810e8ff9737c9ec7b76abc3dcff5860335
|
||||
F src/attach.c ea5247f240e2c08afd608e9beb380814b86655e1
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c cab40f2c1fe79d6eb93d3b4086c78c41ad2fa5d0
|
||||
F src/backup.c b2cac9f7993f3f9588827b824b1501d0c820fa68
|
||||
F src/bitvec.c 26675fe8e431dc555e6f2d0e11e651d172234aa1
|
||||
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
|
||||
F src/btree.c eccee944cb2221e919d7a855e5928d8643194b14
|
||||
F src/btree.c 746c4dafae8565b3be6fb9ce3bb1fa9f1e67cc59
|
||||
F src/btree.h 3ad7964d6c5b1c7bff569aab6adfa075f8bf06cd
|
||||
F src/btreeInt.h 4e5c2bd0f9b36b2a815a6d84f771a61a65830621
|
||||
F src/build.c f35dac52924a6e8e6346a90f0c195a84e28b6f21
|
||||
F src/btreeInt.h eecc84f02375b2bb7a44abbcbbe3747dde73edb2
|
||||
F src/build.c 375e5df716e03b9343c5e1211be3b24e6d6dff05
|
||||
F src/callback.c d7e46f40c3cf53c43550b7da7a1d0479910b62cc
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c 72a70dcfda75d3a1f81041ce4573e7afddcd8e4e
|
||||
F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4
|
||||
F src/delete.c 9b8d308979114991e5dc7cee958316e07186941d
|
||||
F src/expr.c 3b25a95f3d309403940ba4a3212f197b8b6251d5
|
||||
F src/delete.c aeabdabeeeaa0584127f291baa9617153d334778
|
||||
F src/expr.c a23b4aac2a455b2e76b55bef5dcfbe62b665375c
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c c82a04e7a92bb728f9ab972b76590403283be2af
|
||||
F src/func.c 1755cafdb8f2a291681f1ea55e0215518ebd6e52
|
||||
F src/fkey.c e16942bd5c8a868ac53287886464a5ed0e72b179
|
||||
F src/func.c 48987c025d69399f59a1c2a553cea5da41bf105d
|
||||
F src/global.c e59ecd2c553ad0d4bfbc84ca71231336f8993a7a
|
||||
F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4
|
||||
F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c d7ed04b1fab887d6d26cf5e36753f5d6d1246290
|
||||
F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
|
||||
F src/insert.c f7cb141e8ce257cb6b15c497f09e4e23d6055599
|
||||
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
|
||||
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
|
||||
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
|
||||
F src/loadext.c f20382fbaeec832438a1ba7797bee3d3c8a6d51d
|
||||
F src/main.c 448564ee3795b13c373bbc5c8590df8fbfe1d64c
|
||||
F src/loadext.c 1422eba4aa2b1fb5f7b3aef574752272477d21e2
|
||||
F src/main.c 8d204866d1abf5100503dcd54d3187b88f6846b7
|
||||
F src/malloc.c fe085aa851b666b7c375c1ff957643dc20a04bf6
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 437c7c4af964895d4650f29881df63535caaa1fa
|
||||
@@ -160,38 +160,38 @@ F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
|
||||
F src/os.c e1acdc09ff3ac2412945cca9766e2dcf4675f31c
|
||||
F src/os.h 027491c77d2404c0a678bb3fb06286f331eb9b57
|
||||
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
|
||||
F src/os_unix.c b75d9b0876ad3fde151843ad389b4c3dd727c662
|
||||
F src/os_win.c 6e55b48f793d0c0d0e086d3f1482a0882530eeeb
|
||||
F src/pager.c ed53fe75a269c1d67645fe079ea0f3f0ce6492d5
|
||||
F src/os_unix.c f6387eef0cf8f6b808738f4f3aa47e6132af0940
|
||||
F src/os_win.c f7da4dc0a2545c0a430080380809946ae4d676d6
|
||||
F src/pager.c 582f8da52d0bd4b43d3bdaeba0ea7702c1f23702
|
||||
F src/pager.h 1109a06578ec5574dc2c74cf8d9f69daf36fe3e0
|
||||
F src/parse.y f29df90bd3adc64b33114ab1de9fb7768fcf2099
|
||||
F src/parse.y 5d5e12772845805fdfeb889163516b84fbb9ae95
|
||||
F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
|
||||
F src/pcache.h 1b5dcc3dc8103d03e625b177023ee67764fa6b7c
|
||||
F src/pcache1.c 9fd22671c270b35131ef480bbc00392b8b5f8ab9
|
||||
F src/pragma.c 015723c48072781d2740e310ab04dc92956b76d1
|
||||
F src/prepare.c 931ad0d852a0df48f79adcba6ce79ca5f475625c
|
||||
F src/pragma.c 9f0ee3d74a7f33eeeff40a4b014fc3abf8182ce2
|
||||
F src/prepare.c 78cd7ae8cd0d8de8ef8a8b5352fc5f38693a0852
|
||||
F src/printf.c 4a9f882f1c1787a8b494a2987765acf9d97ac21f
|
||||
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
|
||||
F src/resolve.c 7b986a715ac281643309c29257bb58cfae7aa810
|
||||
F src/resolve.c 9079da7d59aed2bb14ec8315bc7f720dd85b5b65
|
||||
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
|
||||
F src/select.c 3a8baf4719f9723b4e0b43f2baa60692d0d921f8
|
||||
F src/shell.c e392dd1ccbb77cc1d75a8367a89b473c24bea019
|
||||
F src/sqlite.h.in 4e71a210f383b6d060bd3fdf81d850f0f8c4eca3
|
||||
F src/select.c e1c6f6abdf9f359f4e735cb8ae11d2f359bf52a9
|
||||
F src/shell.c 7c41bfcd9e5bf9d96b9215f79b03a5b2b44a3bca
|
||||
F src/sqlite.h.in 31045976254225e6bf046a96e87b40fa4c1d55e4
|
||||
F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0
|
||||
F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477
|
||||
F src/sqliteInt.h 68f23dcfc3fb6559c07b327ab6d8d2e63e4bb69e
|
||||
F src/sqlite3ext.h 7183ab832e23db0f934494f16928da127a571d75
|
||||
F src/sqliteInt.h 601c887f6d9c92e75551873c0a34711fff745bed
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c 515abd8e33e82aa330eeb54675185a7e1e5b6778
|
||||
F src/test1.c 936afc02766403e5debca49a1817a780e116df7e
|
||||
F src/tclsqlite.c 3213f3101e3b85f047d6e389da5a53d76d3d7540
|
||||
F src/test1.c ff3e68eedfbd858c9b89cf03e3db233cd29be1d0
|
||||
F src/test2.c 4178056dd1e7d70f954ad8a1e3edb71a2a784daf
|
||||
F src/test3.c 3c3c2407fa6ec7a19e24ae23f7cb439d0275a60d
|
||||
F src/test4.c bf9fa9bece01de08e6f5e02314e4af5c13590dfa
|
||||
F src/test5.c a6d1ac55ac054d0b2b8f37b5e655b6c92645a013
|
||||
F src/test6.c 938794c970ed6810036c8d28450ca28166524bf7
|
||||
F src/test7.c 2e0781754905c8adc3268d8f0967e7633af58843
|
||||
F src/test8.c 8bcce65e5ee027fbfd7da41d28371aabbfd369ff
|
||||
F src/test8.c 58ea1d9698f3947e4662107ef98f429e84ae20e0
|
||||
F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60
|
||||
F src/test_async.c 0612a752896fad42d55c3999a5122af10dcf22ad
|
||||
F src/test_autoext.c 30e7bd98ab6d70a62bb9ba572e4c7df347fe645e
|
||||
@@ -200,6 +200,7 @@ F src/test_btree.c 5b89601dcb42a33ba8b820a6b763cc9cb48bac16
|
||||
F src/test_config.c 09781397ccc24268cb895be0d4c21b4aad651486
|
||||
F src/test_demovfs.c 20a4975127993f4959890016ae9ce5535a880094
|
||||
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
|
||||
F src/test_fs.c 1c51e203b2c20235d8c3739f8c1fb13a7502915b
|
||||
F src/test_func.c 3a8dd37c08ab43b76d38eea2836e34a3897bf170
|
||||
F src/test_fuzzer.c 1d26aa965120420bc14807da29d4d4541bfa6148
|
||||
F src/test_hexio.c abfdecb6fa58c354623978efceb088ca18e379cd
|
||||
@@ -208,49 +209,50 @@ F src/test_intarray.c 07ddcebe4097d400ffca362770f1d883c112387a
|
||||
F src/test_intarray.h b999bb18d090b8d9d9c49d36ec37ef8f341fe169
|
||||
F src/test_journal.c f5c0a05b7b3d5930db769b5ee6c3766dc2221a64
|
||||
F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e
|
||||
F src/test_malloc.c 01cd65ae7ae93de9fbf8214d1ee6b4eba4850700
|
||||
F src/test_malloc.c 6982a357a6a6c24f281b91c89303a5c31075c392
|
||||
F src/test_multiplex.c ac0fbc1748e5b86a41a1d7a84654fae0d53a881d
|
||||
F src/test_multiplex.h 9b63b95f07acedee425fdfe49a47197c9bf5f9d8
|
||||
F src/test_mutex.c a6bd7b9cf6e19d989e31392b06ac8d189f0d573e
|
||||
F src/test_onefile.c 0396f220561f3b4eedc450cef26d40c593c69a25
|
||||
F src/test_osinst.c 90a845c8183013d80eccb1f29e8805608516edba
|
||||
F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00
|
||||
F src/test_quota.c 0e0e2e3bf6766b101ecccd8c042b66e44e9be8f5
|
||||
F src/test_quota.c 1ec82e02fd3643899e9a5de9684515e84641c91f
|
||||
F src/test_quota.h 8761e463b25e75ebc078bd67d70e39b9c817a0cb
|
||||
F src/test_regexp.c 5ff0eafd66c9a209417142fa319006f7028fbda8
|
||||
F src/test_rtree.c aba603c949766c4193f1068b91c787f57274e0d9
|
||||
F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
|
||||
F src/test_server.c 2f99eb2837dfa06a4aacf24af24c6affdf66a84f
|
||||
F src/test_spellfix.c 76dd8d3111d2f5354c374f71fa23b752bd0b029c
|
||||
F src/test_sqllog.c 7813b47021a6d4e39bb7b1b328a8893dc59885cb
|
||||
F src/test_spellfix.c 56dfa6d583ac34f61af0834d7b58d674e7e18e13
|
||||
F src/test_sqllog.c 8acb843ddb9928dea8962e31bb09f421a72ffccb
|
||||
F src/test_stat.c d1569c7a4839f13e80187e2c26b2ab4da2d03935
|
||||
F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd
|
||||
F src/test_syscall.c a992d8c80ea91fbf21fb2dd570db40e77dd7e6ae
|
||||
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
|
||||
F src/test_thread.c e286f2173563f2a1747c24bcda6b9d030bf4f4e4
|
||||
F src/test_vfs.c c6260ef238c1142c8f8bd402db02216afd182ae3
|
||||
F src/test_vfstrace.c f60e12754e65c05386aab59db8d2ae086314138d
|
||||
F src/test_vfs.c fb16b2d9938cf0c1afc5a423b55b952fcc024275
|
||||
F src/test_vfstrace.c 34b544e80ba7fb77be15395a609c669df2e660a2
|
||||
F src/test_wholenumber.c 3d2b9ed1505c40ad5c5ca2ad16ae7a289d6cc251
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/tokenize.c 1e86210d3976717a19238ea7b047fac481fe8c12
|
||||
F src/trigger.c 3f258307040173aff383eb23fb74c44fe829078c
|
||||
F src/trigger.c cd95ac64efa60e39faf9b5597443192ff27a22fa
|
||||
F src/update.c 28d2d098b43a2c70dae399896ea8a02f622410ef
|
||||
F src/utf.c 8d819e2e5104a430fc2005f018db14347c95a38f
|
||||
F src/util.c 0af2e515dc0dabacec931bca39525f6c3f1c5455
|
||||
F src/vacuum.c 2727bdd08847fcb6b2d2da6d14f018910e8645d3
|
||||
F src/vdbe.c 5b49cb1f852e4604a4fb6c47e087ddab28af193f
|
||||
F src/vdbe.c 292f8f7ced59c29c63fe17830cbe5f5a0230cdf0
|
||||
F src/vdbe.h b52887278cb173e66188da84dfab216bea61119d
|
||||
F src/vdbeInt.h 79abf9b31be406d35ca77d6999cb2d42aaf91e78
|
||||
F src/vdbeapi.c 4c2418161cf45392ba76a7ca92f9a5f06b96f89c
|
||||
F src/vdbeaux.c 2d1b3ee65860b1ea97ad9f20a02338b26caf2367
|
||||
F src/vdbeInt.h 396bb03eec560f768d1b86092b00f46c25575d3b
|
||||
F src/vdbeapi.c 9616986209cc77822aa9f7d91cf9e6880516d557
|
||||
F src/vdbeaux.c 735a6905df302a7f3c715a82bd3af06dc7d74ef2
|
||||
F src/vdbeblob.c 32f2a4899d67f69634ea4dd93e3f651936d732cb
|
||||
F src/vdbemem.c cb55e84b8e2c15704968ee05f0fae25883299b74
|
||||
F src/vdbemem.c 833005f1cbbf447289f1973dba2a0c2228c7b8ab
|
||||
F src/vdbesort.c c61ca318681c0e7267da8be3abfca8469652a7e9
|
||||
F src/vdbetrace.c 8bd5da325fc90f28464335e4cc4ad1407fe30835
|
||||
F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83
|
||||
F src/wal.c f5c7b5027d0ed0e9bc9afeb4a3a8dfea762ec7d2
|
||||
F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6
|
||||
F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b
|
||||
F src/where.c b5325975cbdd9b64f680fb88d7e727fc9368db68
|
||||
F src/where.c 8b7690cae8700b385d8a53a39387cf8054d8cc47
|
||||
F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
|
||||
@@ -279,18 +281,18 @@ F test/attach2.test e54436ed956d3d88bdee61221da59bf3935a0966
|
||||
F test/attach3.test d89ccfe4fe6e2b5e368d480fcdfe4b496c54cf4e
|
||||
F test/attach4.test 53bf502f17647c6d6c5add46dda6bac8b6f4665c
|
||||
F test/attachmalloc.test 3a4bfca9545bfe906a8d2e622de10fbac5b711b0
|
||||
F test/auth.test 304e82f31592820d3bde26ab6b75deaa123e1a6f
|
||||
F test/auth2.test 270baddc8b9c273682760cffba6739d907bd2882
|
||||
F test/auth.test 1b21145e888130d60a03db0cb829d59df8f29266
|
||||
F test/auth2.test a2a371aa6df15f8b0c8109b33d3d7f0f73e4c9aa
|
||||
F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5
|
||||
F test/autoinc.test bd30d372d00045252f6c2e41b5f41455e1975acf
|
||||
F test/autoindex1.test 058d0b331ae6840a61bbee910d8cbae27bfd5991
|
||||
F test/autoindex1.test f88146c4c889ea0afbb620e49d83b5fbf5ee4d06
|
||||
F test/autovacuum.test 9f22a7733f39c56ef6a5665d10145ac25d8cb574
|
||||
F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4
|
||||
F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85
|
||||
F test/backcompat.test ecd841f3a3bfb81518721879cc56a760670e3198
|
||||
F test/backup.test c9cdd23a495864b9edf75a9fa66f5cb7e10fcf62
|
||||
F test/backup2.test 34986ef926ea522911a51dfdb2f8e99b7b75ebcf
|
||||
F test/backup4.test 3c3639d28f3cdb4a123694a0a7c5fa7bfe304e2a
|
||||
F test/backup4.test 4d90389daeb781fe718816a4fc836ad1b06791d8
|
||||
F test/backup_ioerr.test 40d208bc9224b666ee3ed423f49bc9062a36a9d0
|
||||
F test/backup_malloc.test 7162d604ec2b4683c4b3799a48657fb8b5e2d450
|
||||
F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f
|
||||
@@ -314,16 +316,16 @@ F test/boundary4.tcl 0bb4b1a94f4fc5ae59b79b9a2b7a140c405e2983
|
||||
F test/boundary4.test 89e02fa66397b8a325d5eb102b5806f961f8ec4b
|
||||
F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0
|
||||
F test/cache.test f64136b0893c293d0b910ed057b3b711249099a7
|
||||
F test/capi2.test 835d4cee9f542ea50fa8d01f3fe6de80b0627360
|
||||
F test/capi2.test e8b18cc61090b6e5e388f54d6b125d711d1b265a
|
||||
F test/capi3.test 56ab450125ead38846cbae7e5b6a216686c3cffa
|
||||
F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4
|
||||
F test/capi3c.test 93d24621c9ff84da9da060f30431e0453db1cdb0
|
||||
F test/capi3d.test 17b57ca28be3e37e14c2ba8f787d292d84b724a1
|
||||
F test/capi3e.test f7408dda65c92b9056199fdc180f893015f83dde
|
||||
F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3
|
||||
F test/check.test 193f47ed43a8d29aca12b30cd30ceb105fbe710d
|
||||
F test/check.test 2eb93611139a7dfaed3be80067c7dc5ceb5fb287
|
||||
F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91
|
||||
F test/collate1.test e3eaa48c21e150814be1a7b852d2a8af24458d04
|
||||
F test/collate1.test fd02c4d8afc71879c4bb952586389961a21fb0ce
|
||||
F test/collate2.test 04cebe4a033be319d6ddbb3bbc69464e01700b49
|
||||
F test/collate3.test d28d2cfab2c3a3d4628ae4b2b7afc9965daa3b4c
|
||||
F test/collate4.test d37682293d3c32223dec2e6afdeaf9de18415248
|
||||
@@ -335,7 +337,7 @@ F test/collate9.test 3adcc799229545940df2f25308dd1ad65869145a
|
||||
F test/collateA.test b8218ab90d1fa5c59dcf156efabb1b2599c580d6
|
||||
F test/colmeta.test 087c42997754b8c648819832241daf724f813322
|
||||
F test/colname.test 08948a4809d22817e0e5de89c7c0a8bd90cb551b
|
||||
F test/conflict.test cabc41f7616675df71b4fddabca3bd5d9221915a
|
||||
F test/conflict.test 0b3922d2304a14a47e3ccd61bbd6824327af659b
|
||||
F test/corrupt.test 4aabd06cff3fe759e3e658bcc17b71789710665e
|
||||
F test/corrupt2.test 9c0ab4becd50e9050bc1ebb8675456a4e5587bf0
|
||||
F test/corrupt3.test 889d7cdb811800303aa722d7813fe8a4299cf726
|
||||
@@ -376,29 +378,29 @@ F test/descidx1.test 533dcbda614b0463b0ea029527fd27e5a9ab2d66
|
||||
F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d
|
||||
F test/descidx3.test fe720e8b37d59f4cef808b0bf4e1b391c2e56b6f
|
||||
F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e
|
||||
F test/distinct.test c239558222e5ae357aade535bfe61aaabcb00bbf
|
||||
F test/distinct.test 84da1414b2e6887fffd5ed571311b344c5b082ce
|
||||
F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
|
||||
F test/e_createtable.test 0a2465736199cb5e084645a8714ee04299b81721
|
||||
F test/e_delete.test 89aa84d3d1bd284a0689ede04bce10226a5aeaa5
|
||||
F test/e_droptrigger.test afd5c4d27dec607f5997a66bf7e2498a082cb235
|
||||
F test/e_dropview.test 583411e470458c5d76148542cfb5a5fa84c8f93e
|
||||
F test/e_expr.test 5489424d3d9a452ac3701cdf4b680ae31a157894
|
||||
F test/e_fkey.test a79ab1d3213c7ac64621eec28f8e8bb219775445
|
||||
F test/e_fkey.test 89a2ff734a33693b997534eff90724573948be7b
|
||||
F test/e_fts3.test 5c02288842e4f941896fd44afdef564dd5fc1459
|
||||
F test/e_insert.test c6ac239a97cb16dfbd0c16496f8cd871b4068c0c
|
||||
F test/e_insert.test d5331cc95e101af2508159fc98b6801631659ffe
|
||||
F test/e_reindex.test dfedfc32c5a282b0596c6537cbcd4217fbb1a216
|
||||
F test/e_resolve.test dcce9308fb13b934ce29591105d031d3e14fbba6
|
||||
F test/e_select.test 07e8d81268ba1ffcaf1dc4bec48956af150c42f9
|
||||
F test/e_select2.test 5c3d3da19c7b3e90ae444579db2b70098599ab92
|
||||
F test/e_update.test 161d5dc6a3ed9dd08f5264d13e20735d7a89f00c
|
||||
F test/e_uri.test 9e190ca799d9190eec6e43f2aadf1d10c06a57a3
|
||||
F test/e_uri.test bc240fbc6cbbbdff832ee05858432a25961ab36a
|
||||
F test/e_vacuum.test 331da289ae186656cf5f2eb27f577a89c0c221af
|
||||
F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea
|
||||
F test/enc2.test 796c59832e2b9a52842f382ffda8f3e989db03ad
|
||||
F test/enc3.test 90683ad0e6ea587b9d5542ca93568af9a9858c40
|
||||
F test/enc4.test c8f1ce3618508fd0909945beb8b8831feef2c020
|
||||
F test/eqp.test 46aa946dd55c90635327898275d3e533d23a9845
|
||||
F test/errmsg.test 3bb606db9d040cc6854459f8f5e5a2bcd9b7fd2a
|
||||
F test/errmsg.test 050717f1c6a5685de9c79f5f9f6b83d7c592f73a
|
||||
F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3
|
||||
F test/exclusive.test a1b324cb21834a490cd052d409d34789cfef57cb
|
||||
F test/exclusive2.test 372be98f6de44dd78734e364b7b626ea211761a6
|
||||
@@ -406,13 +408,14 @@ F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7
|
||||
F test/exists.test 8f7b27b61c2fbe5822f0a1f899c715d14e416e30
|
||||
F test/expr.test 67c9fd6f8f829e239dc8b0f4a08a73c08b09196d
|
||||
F test/fallocate.test b5d34437bd7ab01d41b1464b8117aefd4d32160e
|
||||
F test/filectrl.test f0327bd804d9c7bd048fa7a151c5eab8e27df42b
|
||||
F test/filefmt.test ffa17b5aebc3eb4b1e3be1ccb5ee906ffbd97f6e
|
||||
F test/filectrl.test 14fa712e42c4cb791e09dfd58a6a03efb47ef13a
|
||||
F test/filefmt.test dbee33e57818249cdffbbb7b13464635217beff1
|
||||
F test/fkey1.test 01c7de578e11747e720c2d9aeef27f239853c4da
|
||||
F test/fkey2.test 080969fe219b3b082b0e097ac18c6af2e5b0631f
|
||||
F test/fkey2.test 06e0b4cc9e1b3271ae2ae6feeb19755468432111
|
||||
F test/fkey3.test 5ec899d12b13bcf1e9ef40eff7fb692fdb91392e
|
||||
F test/fkey4.test c6c8f9f9be885f95c85c7bceb26f243ad906fd49
|
||||
F test/fkey_malloc.test c3a12acd053c976de09036498eef09b83afa4a80
|
||||
F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
|
||||
F test/fkey5.test 0bf64f2d19ad80433ca0b24edbf604a18b353d5f
|
||||
F test/fkey_malloc.test bb74c9cb8f8fceed03b58f8a7ef2df98520bbd51
|
||||
F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
|
||||
F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c
|
||||
F test/fts1a.test 46090311f85da51bb33bd5ce84f7948359c6d8d7
|
||||
@@ -459,7 +462,7 @@ F test/fts3ae.test ce32a13b34b0260928e4213b4481acf801533bda
|
||||
F test/fts3af.test d394978c534eabf22dd0837e718b913fd66b499c
|
||||
F test/fts3ag.test 0b7d303f61ae5d620c4efb5e825713ea34ff9441
|
||||
F test/fts3ah.test dc9f66c32c296f1bc8bcc4535126bddfeca62894
|
||||
F test/fts3ai.test d29cee6ed653e30de478066881cec8aa766531b2
|
||||
F test/fts3ai.test 24058fdc6e9e5102c1fd8459591b114b6a85d285
|
||||
F test/fts3aj.test 0ed71e1dd9b03b843a857dc3eb9b15630e0104fc
|
||||
F test/fts3ak.test bd14deafe9d1586e8e9bf032411026ac4f8c925d
|
||||
F test/fts3al.test 07d64326e79bbdbab20ee87fc3328fbf01641c9f
|
||||
@@ -498,14 +501,14 @@ F test/fts3snippet.test 8e956051221a34c7daeb504f023cb54d5fa5a8b2
|
||||
F test/fts3sort.test 95be0b19d7e41c44b29014f13ea8bddd495fd659
|
||||
F test/fts4aa.test 95f448fb02c4a976968b08d1b4ce134e720946ae
|
||||
F test/fts4check.test 66fa274cab2b615f2fb338b257713aba8fad88a8
|
||||
F test/fts4content.test 17b2360f7d1a9a7e5aa8022783f5c5731b6dfd4f
|
||||
F test/fts4content.test 6efc53b4fd03cab167e6998d2b0b7d4b7d419ee6
|
||||
F test/fts4langid.test 24a6e41063b416bbdf371ff6b4476fa41c194aa7
|
||||
F test/fts4merge.test c424309743fdd203f8e56a1f1cd7872cd66cc0ee
|
||||
F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891
|
||||
F test/fts4merge3.test aab02a09f50fe6baaddc2e159c3eabc116d45fc7
|
||||
F test/fts4unicode.test aad033abdcfa0f87ce5f56468f59fdf2a0acbcef
|
||||
F test/fts4unicode.test 25ccad45896f8e50f6a694cff738a35f798cdb40
|
||||
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
|
||||
F test/func.test 0d89043dab9a8853358d14c68e028ee0093bf066
|
||||
F test/func.test b058483c17952eff7797b837bbb61e27e6b05606
|
||||
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
|
||||
F test/func3.test 001021e5b88bd02a3b365a5c5fd8f6f49d39744a
|
||||
F test/fuzz-oss1.test 4912e528ec9cf2f42134456933659d371c9e0d74
|
||||
@@ -516,7 +519,7 @@ F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b
|
||||
F test/fuzz_malloc.test 328f70aaca63adf29b4c6f06505ed0cf57ca7c26
|
||||
F test/fuzzer1.test a2e93bb1e19513dd6bf9c63d3d7c4673c983ca19
|
||||
F test/fuzzerfault.test ff2282c81797b6a355f0748d8b54c7287c5d2b25
|
||||
F test/hook.test 5f3749de6462a6b87b4209b74adf7df5ac2df639
|
||||
F test/hook.test 45cb22b940c3cc0af616ba7430f666e245711a48
|
||||
F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4
|
||||
F test/in.test 5941096407d8c133b9eff15bd3e666624b6cbde3
|
||||
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
|
||||
@@ -531,12 +534,13 @@ F test/incrblob_err.test d2562d2771ebffd4b3af89ef64c140dd44371597
|
||||
F test/incrblobfault.test 917c0292224c64a56ef7215fd633a3a82f805be0
|
||||
F test/incrvacuum.test d2a6ddf5e429720b5fe502766af747915ccf6c32
|
||||
F test/incrvacuum2.test 379eeb8740b0ef60c372c439ad4cbea20b34bb9b
|
||||
F test/incrvacuum_ioerr.test 22f208d01c528403240e05beecc41dc98ed01637
|
||||
F test/incrvacuum3.test 2ffa9e4a23f072bd7902b9ae6471f8822a6522a7
|
||||
F test/incrvacuum_ioerr.test 6ae2f783424e47a0033304808fe27789cf93e635
|
||||
F test/index.test b5429732b3b983fa810e3ac867d7ca85dae35097
|
||||
F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6
|
||||
F test/index3.test 423a25c789fc8cc51aaf2a4370bbdde2d9e9eed7
|
||||
F test/index4.test 2983216eb8c86ee62d9ed7cb206b5cc3331c0026
|
||||
F test/index5.test edc8c64ca78bee140c21ce3836820fadf47906bb
|
||||
F test/index5.test fc07c14193c0430814e7a08b5da46888ee795c33
|
||||
F test/indexedby.test be501e381b82b2f8ab406309ba7aac46e221f4ad
|
||||
F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d
|
||||
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
|
||||
@@ -547,7 +551,7 @@ F test/insert4.test 87f6798f31d60c4e177622fcc3663367e6ecbd90
|
||||
F test/insert5.test 394f96728d1258f406fe5f5aeb0aaf29487c39a6
|
||||
F test/instr.test a34e1d46a9eefb098a7167ef0e730a4a3d82fba0
|
||||
F test/intarray.test 066b7d7ac38d25bf96f87f1b017bfc687551cdd4
|
||||
F test/interrupt.test 42e7cf98646fd9cb4a3b131a93ed3c50b9e149f1
|
||||
F test/interrupt.test dfe9a67a94b0b2d8f70545ba1a6cca10780d71cc
|
||||
F test/intpkey.test 7af30f6ae852d8d1c2b70e4bf1551946742e92d8
|
||||
F test/io.test 36d251507d72e92b965fb2f0801c2f0b56335bcf
|
||||
F test/ioerr.test 40bb2cfcab63fb6aa7424cd97812a84bc16b5fb8
|
||||
@@ -555,6 +559,7 @@ F test/ioerr2.test 9d71166f8466eda510f1af6137bdabaa82b5408d
|
||||
F test/ioerr3.test d3cec5e1a11ad6d27527d0d38573fbff14c71bdd
|
||||
F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c
|
||||
F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4
|
||||
F test/ioerr6.test cf25523b921d1a6a0e5b536cd4acb3c3d979ea52
|
||||
F test/join.test 8d63cc4d230a7affafa4b6ab0b97c49b8ccb365c
|
||||
F test/join2.test f2171c265e57ee298a27e57e7051d22962f9f324
|
||||
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
|
||||
@@ -572,7 +577,7 @@ F test/lastinsert.test 474d519c68cb79d07ecae56a763aa7f322c72f51
|
||||
F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200
|
||||
F test/like.test 0e5412f4dac4a849f613e1ef8b529d56a6e31d08
|
||||
F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da
|
||||
F test/limit.test 2db7b3b34fb925b8e847d583d2eb67531d0ce67e
|
||||
F test/limit.test cc0ab63385239b63c72452b0e93700bf5e8f0b99
|
||||
F test/loadext.test 2b5e249c51c986a5aff1f0950cf7ba30976c8f22
|
||||
F test/loadext2.test 0bcaeb4d81cd5b6e883fdfea3c1bdbe1f173cbca
|
||||
F test/lock.test 87af515b0c4cf928576d0f89946d67d7c265dfb4
|
||||
@@ -587,7 +592,7 @@ F test/lookaside.test 93f07bac140c5bb1d49f3892d2684decafdc7af2
|
||||
F test/main.test 39c4bb8a157f57298ed1659d6df89d9f35aaf2c8
|
||||
F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9
|
||||
F test/malloc.test bc745155ff4252d4f35ec8316625b0dfe2abc659
|
||||
F test/malloc3.test de8eca0c3e748878845fdca3663ec4b642073caf
|
||||
F test/malloc3.test 3e9eb921c4314acf4fb64230868fdb2e1ce60eea
|
||||
F test/malloc4.test 957337613002b7058a85116493a262f679f3a261
|
||||
F test/malloc5.test a577cbbcc1594c7763b9b3515b3633555751c7f0
|
||||
F test/malloc6.test 2f039d9821927eacae43e1831f815e157659a151
|
||||
@@ -601,7 +606,7 @@ F test/mallocC.test 3dffe16532f109293ce1ccecd0c31dca55ef08c4
|
||||
F test/mallocD.test f78c295e8e18ea3029e65ca08278690e00c22100
|
||||
F test/mallocE.test db1ed69d7eded1b080952e2a7c37f364ad241b08
|
||||
F test/mallocF.test 2d5c590ebc2fc7f0dcebdf5aa8498b9aed69107e
|
||||
F test/mallocG.test 4584d0d8ddb8009f16ca0c8bab1fa37f6358efa2
|
||||
F test/mallocG.test 0ff91b65c50bdaba680fb75d87fe4ad35bb7934f
|
||||
F test/mallocH.test 79b65aed612c9b3ed2dcdaa727c85895fd1bfbdb
|
||||
F test/mallocI.test a88c2b9627c8506bf4703d8397420043a786cdb6
|
||||
F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e
|
||||
@@ -613,7 +618,7 @@ F test/memdb.test 708a028d6d373e5b3842e4bdc8ba80998c9a4da6
|
||||
F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2
|
||||
F test/memsubsys1.test a8f9e37567453a5d1d9d37ec102d4d88ab6be33f
|
||||
F test/memsubsys2.test 3a1c1a9de48e5726faa85108b02459fae8cb9ee9
|
||||
F test/minmax.test c61518429e66e228efc79661fbd2dc3e4924ec44
|
||||
F test/minmax.test 42fbad0e81afaa6e0de41c960329f2b2c3526efd
|
||||
F test/minmax2.test b44bae787fc7b227597b01b0ca5575c7cb54d3bc
|
||||
F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354
|
||||
F test/minmax4.test 536a3360470633a177e42fbc19660d146b51daef
|
||||
@@ -623,7 +628,7 @@ F test/misc3.test fe55130a43e444ee75e2156ff75dc96e964b5738
|
||||
F test/misc4.test 9c078510fbfff05a9869a0b6d8b86a623ad2c4f6
|
||||
F test/misc5.test 528468b26d03303b1f047146e5eefc941b9069f5
|
||||
F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
|
||||
F test/misc7.test f00dad9a004da659330013e6f21819d018b683d3
|
||||
F test/misc7.test dd82ec9250b89178b96cd28b2aca70639d21e5b3
|
||||
F test/misuse.test ba4fb5d1a6101d1c171ea38b3c613d0661c83054
|
||||
F test/multiplex.test e08cc7177bd6d85990ee1d71100bb6c684c02256
|
||||
F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a
|
||||
@@ -634,13 +639,14 @@ F test/nan.test e9648b9d007c7045242af35e11a984d4b169443a
|
||||
F test/notify1.test 669b2b743618efdc18ca4b02f45423d5d2304abf
|
||||
F test/notify2.test 9503e51b9a272a5405c205ad61b7623d5a9ca489
|
||||
F test/notify3.test a86259abbfb923aa27d30f0fc038c88e5251488a
|
||||
F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347
|
||||
F test/notnull.test 2afad748d18fd66d01f66463de73b3e2501fb226
|
||||
F test/null.test a8b09b8ed87852742343b33441a9240022108993
|
||||
F test/openv2.test 0d3040974bf402e19b7df4b783e447289d7ab394
|
||||
F test/orderby1.test f33968647da5c546528fe4d2bf86c6a6a2e5a7ae
|
||||
F test/orderby2.test bc11009f7cd99d96b1b11e57b199b00633eb5b04
|
||||
F test/orderby3.test 8619d06a3debdcd80a27c0fdea5c40b468854b99
|
||||
F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3
|
||||
F test/pager1.test f4c57e14583da2183fe31555c67fb32feda96092
|
||||
F test/pager1.test 31c04bec797dda1bde337810b52efa08d1f1f08e
|
||||
F test/pager2.test 745b911dde3d1f24ae0870bd433dfa83d7c658c1
|
||||
F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f
|
||||
F test/pagerfault.test 452f2cc23e3bfcfa935f4442aec1da4fe1dc0442
|
||||
@@ -651,7 +657,7 @@ F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0
|
||||
F test/pcache.test 065aa286e722ab24f2e51792c1f093bf60656b16
|
||||
F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
|
||||
F test/permutations.test 360b92859c0af814b3fe10b68746936389606501
|
||||
F test/pragma.test a62f73293b0f0d79b0c87f8dd32d46fe53b0bd17
|
||||
F test/pragma.test 60d29cd3d8098a2c20bf4c072810f99e3bf2757a
|
||||
F test/pragma2.test 3a55f82b954242c642f8342b17dffc8b47472947
|
||||
F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
|
||||
F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301
|
||||
@@ -664,9 +670,10 @@ F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6
|
||||
F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459
|
||||
F test/randexpr1.test eda062a97e60f9c38ae8d806b03b0ddf23d796df
|
||||
F test/rdonly.test c267d050a1d9a6a321de502b737daf28821a518d
|
||||
F test/regexp1.test 5cbb6e7122ca51260d71079cf9245b63b8f64e1a
|
||||
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
|
||||
F test/releasetest.mk 2eced2f9ae701fd0a29e714a241760503ccba25a
|
||||
F test/releasetest.tcl e48fd8e0e8abad89f30e08620790533ae4e02010
|
||||
F test/releasetest.tcl 06d289d8255794073a58d2850742f627924545ce
|
||||
F test/rollback.test a1b4784b864331eae8b2a98c189efa2a8b11ff07
|
||||
F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81
|
||||
F test/rowid.test f777404492adb0e00868fd706a3721328fd3af48
|
||||
@@ -697,6 +704,7 @@ F test/select9.test c0ca3cd87a8ebb04de2cb1402c77df55d911a0ea
|
||||
F test/selectA.test 06d1032fa9009314c95394f2ca2e60d9f7ae8532
|
||||
F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25
|
||||
F test/selectC.test 871fb55d884d3de5943c4057ebd22c2459e71977
|
||||
F test/selectD.test 03f7c1ea8d5ab3c637cbc30fcbbbac96b988c162
|
||||
F test/server1.test 46803bd3fe8b99b30dbc5ff38ffc756f5c13a118
|
||||
F test/shared.test 1da9dbad400cee0d93f252ccf76e1ae007a63746
|
||||
F test/shared2.test 03eb4a8d372e290107d34b6ce1809919a698e879
|
||||
@@ -705,10 +713,10 @@ F test/shared4.test 72d90821e8d2fc918a08f16d32880868d8ee8e9d
|
||||
F test/shared6.test 866bb4982c45ce216c61ded5e8fde4e7e2f3ffa9
|
||||
F test/shared7.test 960760bc8d03e1419e70dea69cf41db62853616e
|
||||
F test/shared8.test b27befbefbe7f4517f1d6b7ff8f64a41ec74165d
|
||||
F test/shared9.test 614a3ca431adc73c857632deb4eff75bcaee40ec
|
||||
F test/shared_err.test 91e26ec4f3fbe07951967955585137e2f18993de
|
||||
F test/shared9.test 5f2a8f79b4d6c7d107a01ffa1ed05ae7e6333e21
|
||||
F test/shared_err.test 0079c05c97d88cfa03989b7c20a8b266983087aa
|
||||
F test/sharedlock.test ffa0a3c4ac192145b310f1254f8afca4d553eabf
|
||||
F test/shell1.test b7896eb84028f3bc8300caf1fc796a73728aad0b
|
||||
F test/shell1.test 4a2f57952719972c6f862134463f8712e953c038
|
||||
F test/shell2.test 037d6ad16e873354195d30bb2dc4b5321788154a
|
||||
F test/shell3.test 9196c42772d575685e722c92b4b39053c6ebba59
|
||||
F test/shell4.test aa4eef8118b412d1a01477a53426ece169ea86a9
|
||||
@@ -727,12 +735,12 @@ F test/speed3.test d32043614c08c53eafdc80f33191d5bd9b920523
|
||||
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
|
||||
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
|
||||
F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
|
||||
F test/spellfix.test 2953e9da0e46dab5f83059ef6bfdebca66e13418
|
||||
F test/spellfix.test 52ae2680b1247c52b9e2b2116de3fd26a78e6bd2
|
||||
F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298
|
||||
F test/stat.test be8d477306006ec696bc86757cfb34bec79447ce
|
||||
F test/stmt.test 25d64e3dbf9a3ce89558667d7f39d966fe2a71b9
|
||||
F test/subquery.test d4aea23ac267463d4aa604bf937c3992347b20f7
|
||||
F test/subquery2.test edcad5c118f0531c2e21bf16a09bbb105252d4cd
|
||||
F test/subquery2.test 91e1e364072aeff431d1f9689b15147e421d88c7
|
||||
F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
|
||||
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
|
||||
F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2
|
||||
@@ -745,8 +753,8 @@ F test/tclsqlite.test 37a61c2da7e3bfe3b8c1a2867199f6b860df5d43
|
||||
F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c
|
||||
F test/temptable.test 51edd31c65ed1560dd600b1796e8325df96318e2
|
||||
F test/temptrigger.test 26670ed7a39cf2296a7f0a9e0a1d7bdb7abe936d
|
||||
F test/tester.tcl 2f383e811010b05a83c0f00fc168cae1dd63a6d9
|
||||
F test/thread001.test 7cc2ce08f9cde95964736d11e91f9ab610f82f91
|
||||
F test/tester.tcl 2918ebca150b67ca25b1682f8ecd857af77fab05
|
||||
F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
|
||||
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
|
||||
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
|
||||
F test/thread004.test f51dfc3936184aaf73ee85f315224baad272a87f
|
||||
@@ -776,6 +784,7 @@ F test/tkt-5e10420e8d.test 904d1687b3c06d43e5b3555bbcf6802e7c0ffd84
|
||||
F test/tkt-5ee23731f.test 9db6e1d7209dc0794948b260d6f82b2b1de83a9f
|
||||
F test/tkt-752e1646fc.test ea78d88d14fe9866bdd991c634483334639e13bf
|
||||
F test/tkt-78e04e52ea.test 703e0bfb23d543edf0426a97e3bbd0ca346508ec
|
||||
F test/tkt-7a31705a7e6.test 5a7889fdb095ffbe1622413e0145de1637d421bd
|
||||
F test/tkt-7bbfb7d442.test dfa5c8097a8c353ae40705d6cddeb1f99c18b81a
|
||||
F test/tkt-80ba201079.test 105a721e6aad0ae3c5946d7615d1e4d03f6145b8
|
||||
F test/tkt-80e031a00f.test 9a154173461a4dbe2de49cda73963e04842d52f7
|
||||
@@ -783,6 +792,7 @@ F test/tkt-8454a207b9.test c583a9f814a82a2b5ba95207f55001c9f0cd816c
|
||||
F test/tkt-91e2e8ba6f.test 08c4f94ae07696b05c9b822da0b4e5337a2f54c5
|
||||
F test/tkt-94c04eaadb.test fa9c71192f7e2ea2d51bf078bc34e8da6088bf71
|
||||
F test/tkt-9d68c883.test 458f7d82a523d7644b54b497c986378a7d8c8b67
|
||||
F test/tkt-a7b7803e.test 159ef554234fa1f9fb318c751b284bd1cf858da4
|
||||
F test/tkt-b1d3a2e531.test 610ef582413171b379652663111b1f996d9f8f78
|
||||
F test/tkt-b351d95f9.test d14a503c414c5c58fdde3e80f9a3cfef986498c0
|
||||
F test/tkt-b72787b1.test a95e8cdad0b98af1853ac7f0afd4ab27b77bf5f3
|
||||
@@ -799,6 +809,7 @@ F test/tkt-f7b4edec.test d998a08ff2b18b7f62edce8e3044317c45efe6c7
|
||||
F test/tkt-f973c7ac31.test 1da0ed15ec2c7749fb5ce2828cd69d07153ad9f4
|
||||
F test/tkt-fa7bf5ec.test 9102dfea58aa371d78969da735f9392c57e2e035
|
||||
F test/tkt-fc62af4523.test 72825d3febdedcd5593a27989fc05accdbfc2bb4
|
||||
F test/tkt-fc7bd6358f.test 634bb4af7d661e82d6b61b80c86727bad698e08f
|
||||
F test/tkt1435.test f8c52c41de6e5ca02f1845f3a46e18e25cadac00
|
||||
F test/tkt1443.test bacc311da5c96a227bf8c167e77a30c99f8e8368
|
||||
F test/tkt1444.test a9d72f9e942708bd82dde6c707da61c489e213e9
|
||||
@@ -830,7 +841,7 @@ F test/tkt2686.test 6ee01c9b9e9c48f6d3a1fdd553b1cc4258f903d6
|
||||
F test/tkt2767.test 569000d842678f9cf2db7e0d1b27cbc9011381b0
|
||||
F test/tkt2817.test f31839e01f4243cff7399ef654d3af3558cb8d8d
|
||||
F test/tkt2820.test 39940276b3436d125deb7d8ebeee053e4cf13213
|
||||
F test/tkt2822.test a2b27a58df62d1b2e712f91dbe42ad3b7e0e77cc
|
||||
F test/tkt2822.test f391776423a7c0d0949edfce375708bfb0f3141e
|
||||
F test/tkt2832.test a9b0b74a02dca166a04d9e37739c414b10929caa
|
||||
F test/tkt2854.test e432965db29e27e16f539b2ba7f502eb2ccc49af
|
||||
F test/tkt2920.test a8737380e4ae6424e00c0273dc12775704efbebf
|
||||
@@ -848,7 +859,7 @@ F test/tkt3357.test 77c37c6482b526fe89941ce951c22d011f5922ed
|
||||
F test/tkt3419.test 1bbf36d7ea03b638c15804251287c2391f5c1f6b
|
||||
F test/tkt3424.test 61f831bd2b071bd128fa5d00fbda57e656ca5812
|
||||
F test/tkt3442.test 0adb70e9fe9cb750a702065a68ad647409dbc158
|
||||
F test/tkt3457.test eb68bb3b19c8677cff06c639ff15d206dbf17fd6
|
||||
F test/tkt3457.test 44e980fe5334753dcc27b94fa4deabc485a92f74
|
||||
F test/tkt3461.test 228ea328a5a21e8663f80ee3d212a6ad92549a19
|
||||
F test/tkt3493.test 1686cbde85f8721fc1bdc0ee72f2ef2f63139218
|
||||
F test/tkt3508.test d75704db9501625c7f7deec119fcaf1696aefb7d
|
||||
@@ -863,7 +874,7 @@ F test/tkt3718.test 3b59dcb5c4e7754dacd91e7fd353a61492cc402a
|
||||
F test/tkt3731.test 0c5f4cbffe102d43c3b2188af91a9e36348f974b
|
||||
F test/tkt3757.test 10cd679a88675c880533083fc79ac04324525595
|
||||
F test/tkt3761.test b95ea9c98f21cf91325f18a984887e62caceab33
|
||||
F test/tkt3762.test 2a9f3b03df44ec49ec0cfa8d5da6574c2a7853df
|
||||
F test/tkt3762.test 4d439ff7abdc8d9323150269d182c37c2d514576
|
||||
F test/tkt3773.test 7bca904d2a647a6a4a291bd86d7fd7c73855b789
|
||||
F test/tkt3791.test a6624b9a80b216a26cf473607f42f3e51898c267
|
||||
F test/tkt3793.test d90ffd75c52413908d15e1c44fc2ea9c80fcc449
|
||||
@@ -888,24 +899,25 @@ F test/trace2.test c1dc104a8d11a347c870cfea6235e3fc6f6cb06d
|
||||
F test/trans.test 6e1b4c6a42dba31bd65f8fa5e61a2708e08ddde6
|
||||
F test/trans2.test d5337e61de45e66b1fcbf9db833fa8c82e624b22
|
||||
F test/trans3.test 373ac5183cc56be69f48ae44090e7f672939f732
|
||||
F test/trigger1.test 30f343f91586765874a28ad539c06f5a5f049931
|
||||
F test/transitive1.test d04aa9023e425d6f2d4aa61dd81ee9e102f89062
|
||||
F test/trigger1.test dc47573ac79ffe0ee3eecaa517d70d8dacbccd03
|
||||
F test/trigger2.test 834187beafd1db383af0c659cfa49b0576832816
|
||||
F test/trigger3.test d2c60d8be271c355d61727411e753181e877230a
|
||||
F test/trigger3.test aa640bb2bbb03edd5ff69c055117ea088f121945
|
||||
F test/trigger4.test 74700b76ebf3947b2f7a92405141eb2cf2a5d359
|
||||
F test/trigger5.test 619391a3e9fc194081d22cefd830d811e7badf83
|
||||
F test/trigger6.test 0e411654f122552da6590f0b4e6f781048a4a9b9
|
||||
F test/trigger7.test b39e6dee1debe0ff9c2ef66326668f149f07c9c4
|
||||
F test/trigger8.test 30cb0530bd7c4728055420e3f739aa00412eafa4
|
||||
F test/trigger9.test 5b0789f1c5c4600961f8e68511b825b87be53e31
|
||||
F test/triggerA.test e0aaba16d3547193d36bbd82a1b0ed75e9c88d40
|
||||
F test/triggerA.test fe5597f47ee21bacb4936dc827994ed94161e332
|
||||
F test/triggerB.test 56780c031b454abac2340dbb3b71ac5c56c3d7fe
|
||||
F test/triggerC.test 29173df06f8e91bec2b95ea7048b30d1e1c7b9db
|
||||
F test/triggerC.test a7b4367392c755bc5fd5fff88011753e6b6afe90
|
||||
F test/triggerD.test 8e7f3921a92a5797d472732108109e44575fa650
|
||||
F test/tt3_checkpoint.c 415eccce672d681b297485fc20f44cdf0eac93af
|
||||
F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff
|
||||
F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84
|
||||
F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a
|
||||
F test/unique.test 083c7fff74695bcc27a71d75699deba3595bc9c2
|
||||
F test/unique.test cadb172bbd5a2e83cd644d186ccd602085e54edc
|
||||
F test/unixexcl.test a9870e46cc6f8390a494513d4f2bf55b5a8b3e46
|
||||
F test/unordered.test 93dce7b6c97a817a4fe26980c484605a4511f614
|
||||
F test/update.test 8bc86fd7ef1a00014f76dc6a6a7c974df4aef172
|
||||
@@ -917,8 +929,8 @@ F test/vacuum3.test 77ecdd54592b45a0bcb133339f99f1ae0ae94d0d
|
||||
F test/vacuum4.test d3f8ecff345f166911568f397d2432c16d2867d9
|
||||
F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
|
||||
F test/veryquick.test 7701bb609fe8bf6535514e8b849a309e8f00573b
|
||||
F test/view.test b182a67ec43f490b156b5a710827a341be83dd17
|
||||
F test/vtab1.test 10fb9e656fe4b318cd82ff1616a340acc01aac4b
|
||||
F test/view.test 4057630287bfa5955628fe90a13d4c225d1c7352
|
||||
F test/vtab1.test 4403f987860ebddef1ce2de6db7216421035339d
|
||||
F test/vtab2.test 7bcffc050da5c68f4f312e49e443063e2d391c0d
|
||||
F test/vtab3.test baad99fd27217f5d6db10660522e0b7192446de1
|
||||
F test/vtab4.test 942f8b8280b3ea8a41dae20e7822d065ca1cb275
|
||||
@@ -944,7 +956,7 @@ F test/wal5.test f58ed4b8b542f71c7441da12fbd769d99b362437
|
||||
F test/wal6.test 2e3bc767d9c2ce35c47106148d43fcbd072a93b3
|
||||
F test/wal7.test 2ae8f427d240099cc4b2dfef63cff44e2a68a1bd
|
||||
F test/wal8.test b3ee739fe8f7586aaebdc2367f477ebcf3e3b034
|
||||
F test/wal9.test 48c40803faf6849515c81213697e9f3376835981
|
||||
F test/wal9.test 378e76a9ad09cd9bee06c172ad3547b0129a6750
|
||||
F test/wal_common.tcl a98f17fba96206122eff624db0ab13ec377be4fe
|
||||
F test/walbak.test b9f68e39646375c2b877be906babcc15d38b4877
|
||||
F test/walbig.test f437473a16cfb314867c6b5d1dbcd519e73e3434
|
||||
@@ -961,16 +973,16 @@ F test/walro.test a31deb621033442a76c3a61e44929250d06f81b1
|
||||
F test/walshared.test 6dda2293880c300baf5d791c307f653094585761
|
||||
F test/walslow.test e7be6d9888f83aa5d3d3c7c08aa9b5c28b93609a
|
||||
F test/walthread.test de8dbaf6d9e41481c460ba31ca61e163d7348f8e
|
||||
F test/where.test 41b65069a227a61238c1387b050f029480ca5677
|
||||
F test/where2.test 43d4becaf5a5df854e6c21d624a1cb84c6904554
|
||||
F test/where.test 15ac8611c9439a2c5f4a6ac10cfe4c1ec9854c24
|
||||
F test/where2.test 399b3178289925a0aa976b3d60ef139740540ecd
|
||||
F test/where3.test 667e75642102c97a00bf9b23d3cb267db321d006
|
||||
F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2
|
||||
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
|
||||
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
|
||||
F test/where7.test 5c566388f0cc318b0032ce860f4ac5548e3c265a
|
||||
F test/where8.test a6c740fd286d7883e274e17b6230a9d672a7ab1f
|
||||
F test/where8.test 02619a9bfc6df7b19979a02852bac09c3c99477a
|
||||
F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739
|
||||
F test/where9.test bcab47eff78f1412a6aec1d6b8a3939d4a9db098
|
||||
F test/where9.test 0157862ccf0cfdf1a4622cdf697e5e2f09a8de44
|
||||
F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a
|
||||
F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5
|
||||
F test/whereC.test 13ff5ec0dba407c0e0c075980c75b3275a6774e5
|
||||
@@ -982,7 +994,7 @@ F test/win32lock.test b2a539e85ae6b2d78475e016a9636b4451dc7fb9
|
||||
F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
|
||||
F test/zerodamage.test e7f77fded01dfcdf92ac2c5400f1e35d7a21463c
|
||||
F tool/build-all-msvc.bat 74fb6e5cca66ebdb6c9bbafb2f8b802f08146d38 x
|
||||
F tool/build-shell.sh b64a481901fc9ffe5ca8812a2a9255b6cfb77381
|
||||
F tool/build-shell.sh a9c34a606e2e522ba9eeca1e07090f67dce8c912
|
||||
F tool/checkSpacing.c 810e51703529a204fc4e1eb060e9ab663e3c06d2
|
||||
F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
|
||||
F tool/extract.c 054069d81b095fbdc189a6f5d4466e40380505e2
|
||||
@@ -1005,9 +1017,9 @@ F tool/omittest.tcl 4665982e95a6e5c1bd806cf7bc3dea95be422d77
|
||||
F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c
|
||||
F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a
|
||||
F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5
|
||||
F tool/showdb.c aca2644aa4de7c0cad5821e50bbd55397e0974b8
|
||||
F tool/showdb.c acd24ea035a3bd2ffe266f1ef8a161812c29b2f0
|
||||
F tool/showjournal.c b62cecaab86a4053d944c276bb5232e4d17ece02
|
||||
F tool/showwal.c f09e5a80a293919290ec85a6a37c85a5ddcf37d9
|
||||
F tool/showwal.c 3f7f7da5ec0cba51b1449a75f700493377da57b5
|
||||
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
|
||||
F tool/space_used.tcl f714c41a59e326b8b9042f415b628b561bafa06b
|
||||
F tool/spaceanal.tcl 76f583a246a0b027f423252339e711f13198932e
|
||||
@@ -1025,10 +1037,10 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
|
||||
F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
|
||||
P 7d5fc1a339cf4f3597ab6a5f3e7101884d2d7673
|
||||
R 38c0a4b163ba004b3c0d2e19a002293a
|
||||
T *branch * tclMode
|
||||
T *sym-tclMode *
|
||||
P e899b058a703158012c054974bd9a909d75144d8
|
||||
R 769137243190ff2093b112f59a144071
|
||||
T *branch * omit-fixes
|
||||
T *sym-omit-fixes *
|
||||
T -sym-trunk *
|
||||
U mistachkin
|
||||
Z 962a729a6a99e4b42add9e81143f97fc
|
||||
U dan
|
||||
Z 6114da9985cb574374ef28f435a1a3f9
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
41fd9dd29034b2269e4b7f2626350124d37b5303
|
||||
938b91e8552516772060d4e55e2f79cca4c13e27
|
||||
+2
-2
@@ -473,7 +473,7 @@ static void analyzeOneTable(
|
||||
/* Do not gather statistics on views or virtual tables */
|
||||
return;
|
||||
}
|
||||
if( memcmp(pTab->zName, "sqlite_", 7)==0 ){
|
||||
if( sqlite3_strnicmp(pTab->zName, "sqlite_", 7)==0 ){
|
||||
/* Do not gather statistics on system tables */
|
||||
return;
|
||||
}
|
||||
@@ -883,7 +883,7 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
|
||||
if( pIndex==0 ) break;
|
||||
pIndex->aiRowEst[i] = v;
|
||||
if( *z==' ' ) z++;
|
||||
if( memcmp(z, "unordered", 10)==0 ){
|
||||
if( strcmp(z, "unordered")==0 ){
|
||||
pIndex->bUnordered = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
+1
-1
@@ -471,7 +471,7 @@ int sqlite3FixSrcList(
|
||||
pFix->zType, pFix->pName, pItem->zDatabase);
|
||||
return 1;
|
||||
}
|
||||
sqlite3_free(pItem->zDatabase);
|
||||
sqlite3DbFree(pFix->pParse->db, pItem->zDatabase);
|
||||
pItem->zDatabase = 0;
|
||||
pItem->pSchema = pFix->pSchema;
|
||||
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
|
||||
|
||||
+29
-6
@@ -212,7 +212,12 @@ static int isFatalError(int rc){
|
||||
** page iSrcPg from the source database. Copy this data into the
|
||||
** destination database.
|
||||
*/
|
||||
static int backupOnePage(sqlite3_backup *p, Pgno iSrcPg, const u8 *zSrcData){
|
||||
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);
|
||||
@@ -285,6 +290,9 @@ static int backupOnePage(sqlite3_backup *p, Pgno iSrcPg, const u8 *zSrcData){
|
||||
*/
|
||||
memcpy(zOut, zIn, nCopy);
|
||||
((u8 *)sqlite3PagerGetExtra(pDestPg))[0] = 0;
|
||||
if( iOff==0 && bUpdate==0 ){
|
||||
sqlite3Put4byte(&zOut[28], sqlite3BtreeLastPage(p->pSrc));
|
||||
}
|
||||
}
|
||||
sqlite3PagerUnref(pDestPg);
|
||||
}
|
||||
@@ -391,7 +399,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
DbPage *pSrcPg; /* Source page object */
|
||||
rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = backupOnePage(p, iSrcPg, sqlite3PagerGetData(pSrcPg));
|
||||
rc = backupOnePage(p, iSrcPg, sqlite3PagerGetData(pSrcPg), 0);
|
||||
sqlite3PagerUnref(pSrcPg);
|
||||
}
|
||||
}
|
||||
@@ -454,7 +462,6 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
nDestTruncate = nSrcPage * (pgszSrc/pgszDest);
|
||||
}
|
||||
assert( nDestTruncate>0 );
|
||||
sqlite3PagerTruncateImage(pDestPager, nDestTruncate);
|
||||
|
||||
if( pgszSrc<pgszDest ){
|
||||
/* If the source page-size is smaller than the destination page-size,
|
||||
@@ -468,6 +475,8 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
*/
|
||||
const i64 iSize = (i64)pgszSrc * (i64)nSrcPage;
|
||||
sqlite3_file * const pFile = sqlite3PagerFile(pDestPager);
|
||||
Pgno iPg;
|
||||
int nDstPage;
|
||||
i64 iOff;
|
||||
i64 iEnd;
|
||||
|
||||
@@ -478,13 +487,26 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
&& iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest
|
||||
));
|
||||
|
||||
/* This call ensures that all data required to recreate the original
|
||||
/* 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. */
|
||||
rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1);
|
||||
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);
|
||||
@@ -511,6 +533,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
rc = sqlite3PagerSync(pDestPager);
|
||||
}
|
||||
}else{
|
||||
sqlite3PagerTruncateImage(pDestPager, nDestTruncate);
|
||||
rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0);
|
||||
}
|
||||
|
||||
@@ -639,7 +662,7 @@ void sqlite3BackupUpdate(sqlite3_backup *pBackup, Pgno iPage, const u8 *aData){
|
||||
int rc;
|
||||
assert( p->pDestDb );
|
||||
sqlite3_mutex_enter(p->pDestDb->mutex);
|
||||
rc = backupOnePage(p, iPage, aData);
|
||||
rc = backupOnePage(p, iPage, aData, 1);
|
||||
sqlite3_mutex_leave(p->pDestDb->mutex);
|
||||
assert( rc!=SQLITE_BUSY && rc!=SQLITE_LOCKED );
|
||||
if( rc!=SQLITE_OK ){
|
||||
|
||||
+174
-97
@@ -43,6 +43,25 @@ int sqlite3BtreeTrace=1; /* True to enable tracing */
|
||||
*/
|
||||
#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
|
||||
@@ -2595,6 +2614,7 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
|
||||
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 ){
|
||||
@@ -2911,24 +2931,23 @@ static int relocatePage(
|
||||
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.
|
||||
** 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.
|
||||
** More specificly, this function attempts to re-organize the database so
|
||||
** that the last page of the file currently in use is no longer in use.
|
||||
**
|
||||
** If the nFin parameter is non-zero, this function assumes
|
||||
** that the caller will keep calling incrVacuumStep() until
|
||||
** it returns SQLITE_DONE or an error, and that nFin is the
|
||||
** number of pages the database file will contain after this
|
||||
** process is complete. If nFin is zero, it is assumed that
|
||||
** incrVacuumStep() will be called a finite amount of times
|
||||
** which may or may not empty the freelist. A full autovacuum
|
||||
** has nFin>0. A "PRAGMA incremental_vacuum" has nFin==0.
|
||||
** 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){
|
||||
static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){
|
||||
Pgno nFreeList; /* Number of pages still on the free-list */
|
||||
int rc;
|
||||
|
||||
@@ -2953,15 +2972,15 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
|
||||
}
|
||||
|
||||
if( eType==PTRMAP_FREEPAGE ){
|
||||
if( nFin==0 ){
|
||||
if( bCommit==0 ){
|
||||
/* Remove the page from the files free-list. This is not required
|
||||
** if nFin is non-zero. In that case, the free-list will be
|
||||
** 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, 1);
|
||||
rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iLastPg, BTALLOC_EXACT);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
@@ -2971,34 +2990,37 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
|
||||
} 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 nFin is zero, this loop runs exactly once and page pLastPg
|
||||
/* 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 nFin is greater than zero, then keep
|
||||
** 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, 0, 0);
|
||||
rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iNear, eMode);
|
||||
if( rc!=SQLITE_OK ){
|
||||
releasePage(pLastPg);
|
||||
return rc;
|
||||
}
|
||||
releasePage(pFreePg);
|
||||
}while( nFin!=0 && iFreePg>nFin );
|
||||
}while( bCommit && iFreePg>nFin );
|
||||
assert( iFreePg<iLastPg );
|
||||
|
||||
rc = sqlite3PagerWrite(pLastPg->pDbPage);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = relocatePage(pBt, pLastPg, eType, iPtrPage, iFreePg, nFin!=0);
|
||||
}
|
||||
rc = relocatePage(pBt, pLastPg, eType, iPtrPage, iFreePg, bCommit);
|
||||
releasePage(pLastPg);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
@@ -3006,29 +3028,39 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
|
||||
}
|
||||
}
|
||||
|
||||
if( nFin==0 ){
|
||||
iLastPg--;
|
||||
while( iLastPg==PENDING_BYTE_PAGE(pBt)||PTRMAP_ISPAGE(pBt, iLastPg) ){
|
||||
if( PTRMAP_ISPAGE(pBt, iLastPg) ){
|
||||
MemPage *pPg;
|
||||
rc = btreeGetPage(pBt, iLastPg, &pPg, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
rc = sqlite3PagerWrite(pPg->pDbPage);
|
||||
releasePage(pPg);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
if( bCommit==0 ){
|
||||
do {
|
||||
iLastPg--;
|
||||
}
|
||||
sqlite3PagerTruncateImage(pBt->pPager, 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.
|
||||
@@ -3046,11 +3078,21 @@ int sqlite3BtreeIncrVacuum(Btree *p){
|
||||
if( !pBt->autoVacuum ){
|
||||
rc = SQLITE_DONE;
|
||||
}else{
|
||||
invalidateAllOverflowCache(pBt);
|
||||
rc = incrVacuumStep(pBt, 0, btreePagecount(pBt));
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
|
||||
put4byte(&pBt->pPage1->aData[28], pBt->nPage);
|
||||
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);
|
||||
@@ -3077,9 +3119,7 @@ static int autoVacuumCommit(BtShared *pBt){
|
||||
if( !pBt->incrVacuum ){
|
||||
Pgno nFin; /* Number of pages in database after autovacuuming */
|
||||
Pgno nFree; /* Number of pages on the freelist initially */
|
||||
Pgno nPtrmap; /* Number of PtrMap pages to be freed */
|
||||
Pgno iFree; /* The next page to be freed */
|
||||
int nEntry; /* Number of entries on one ptrmap page */
|
||||
Pgno nOrig; /* Database size before freeing */
|
||||
|
||||
nOrig = btreePagecount(pBt);
|
||||
@@ -3092,26 +3132,18 @@ static int autoVacuumCommit(BtShared *pBt){
|
||||
}
|
||||
|
||||
nFree = get4byte(&pBt->pPage1->aData[36]);
|
||||
nEntry = pBt->usableSize/5;
|
||||
nPtrmap = (nFree-nOrig+PTRMAP_PAGENO(pBt, nOrig)+nEntry)/nEntry;
|
||||
nFin = nOrig - nFree - nPtrmap;
|
||||
if( nOrig>PENDING_BYTE_PAGE(pBt) && nFin<PENDING_BYTE_PAGE(pBt) ){
|
||||
nFin--;
|
||||
}
|
||||
while( PTRMAP_ISPAGE(pBt, nFin) || nFin==PENDING_BYTE_PAGE(pBt) ){
|
||||
nFin--;
|
||||
}
|
||||
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);
|
||||
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);
|
||||
sqlite3PagerTruncateImage(pBt->pPager, nFin);
|
||||
pBt->bDoTruncate = 1;
|
||||
pBt->nPage = nFin;
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
@@ -3166,6 +3198,9 @@ int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
if( pBt->bDoTruncate ){
|
||||
sqlite3PagerTruncateImage(pBt->pPager, pBt->nPage);
|
||||
}
|
||||
#endif
|
||||
rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zMaster, 0);
|
||||
sqlite3BtreeLeave(p);
|
||||
@@ -3181,6 +3216,9 @@ 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
|
||||
@@ -4853,21 +4891,23 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
|
||||
** 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 a (feeble) effort is made to
|
||||
** 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 "exact" parameter is not 0, and the page-number nearby exists
|
||||
** anywhere on the free-list, then it is guarenteed to be returned. This
|
||||
** is only used by auto-vacuum databases when allocating a new table.
|
||||
** 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,
|
||||
MemPage **ppPage,
|
||||
Pgno *pPgno,
|
||||
Pgno nearby,
|
||||
u8 exact
|
||||
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;
|
||||
@@ -4878,6 +4918,7 @@ static int allocateBtreePage(
|
||||
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]);
|
||||
@@ -4890,21 +4931,24 @@ static int allocateBtreePage(
|
||||
Pgno iTrunk;
|
||||
u8 searchList = 0; /* If the free-list must be searched for 'nearby' */
|
||||
|
||||
/* If the 'exact' parameter was true and a query of the pointer-map
|
||||
/* 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( exact && 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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
*pPgno = nearby;
|
||||
}else if( eMode==BTALLOC_LE ){
|
||||
searchList = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -4917,7 +4961,8 @@ static int allocateBtreePage(
|
||||
|
||||
/* 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.
|
||||
** 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;
|
||||
@@ -4959,11 +5004,13 @@ static int allocateBtreePage(
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
goto end_allocate_page;
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
}else if( searchList && nearby==iTrunk ){
|
||||
}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.
|
||||
*/
|
||||
assert( *pPgno==iTrunk );
|
||||
*pPgno = iTrunk;
|
||||
*ppPage = pTrunk;
|
||||
searchList = 0;
|
||||
rc = sqlite3PagerWrite(pTrunk->pDbPage);
|
||||
@@ -5026,14 +5073,24 @@ static int allocateBtreePage(
|
||||
unsigned char *aData = pTrunk->aData;
|
||||
if( nearby>0 ){
|
||||
u32 i;
|
||||
int dist;
|
||||
closest = 0;
|
||||
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;
|
||||
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{
|
||||
@@ -5047,7 +5104,9 @@ static int allocateBtreePage(
|
||||
goto end_allocate_page;
|
||||
}
|
||||
testcase( iPage==mxPage );
|
||||
if( !searchList || iPage==nearby ){
|
||||
if( !searchList
|
||||
|| (iPage==nearby || (iPage<nearby && eMode==BTALLOC_LE))
|
||||
){
|
||||
int noContent;
|
||||
*pPgno = iPage;
|
||||
TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d"
|
||||
@@ -5074,8 +5133,26 @@ static int allocateBtreePage(
|
||||
pPrevTrunk = 0;
|
||||
}while( searchList );
|
||||
}else{
|
||||
/* There are no pages on the freelist, so create a new page at the
|
||||
** end of the file */
|
||||
/* 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++;
|
||||
@@ -5090,7 +5167,7 @@ static int allocateBtreePage(
|
||||
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, 1);
|
||||
rc = btreeGetPage(pBt, pBt->nPage, &pPg, bNoContent);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3PagerWrite(pPg->pDbPage);
|
||||
releasePage(pPg);
|
||||
@@ -5104,7 +5181,7 @@ static int allocateBtreePage(
|
||||
*pPgno = pBt->nPage;
|
||||
|
||||
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
|
||||
rc = btreeGetPage(pBt, *pPgno, ppPage, 1);
|
||||
rc = btreeGetPage(pBt, *pPgno, ppPage, bNoContent);
|
||||
if( rc ) return rc;
|
||||
rc = sqlite3PagerWrite((*ppPage)->pDbPage);
|
||||
if( rc!=SQLITE_OK ){
|
||||
@@ -7119,7 +7196,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
|
||||
** be moved to the allocated page (unless the allocated page happens
|
||||
** to reside at pgnoRoot).
|
||||
*/
|
||||
rc = allocateBtreePage(pBt, &pPageMove, &pgnoMove, pgnoRoot, 1);
|
||||
rc = allocateBtreePage(pBt, &pPageMove, &pgnoMove, pgnoRoot, BTALLOC_EXACT);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
@@ -8026,7 +8103,7 @@ char *sqlite3BtreeIntegrityCheck(
|
||||
}
|
||||
i = PENDING_BYTE_PAGE(pBt);
|
||||
if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i);
|
||||
sqlite3StrAccumInit(&sCheck.errMsg, zErr, sizeof(zErr), 20000);
|
||||
sqlite3StrAccumInit(&sCheck.errMsg, zErr, sizeof(zErr), SQLITE_MAX_LENGTH);
|
||||
sCheck.errMsg.useMalloc = 2;
|
||||
|
||||
/* Check the integrity of the freelist
|
||||
|
||||
@@ -411,6 +411,7 @@ struct BtShared {
|
||||
#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 */
|
||||
|
||||
+31
-18
@@ -127,6 +127,7 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||
sqlite3 *db;
|
||||
Vdbe *v;
|
||||
|
||||
assert( pParse->pToplevel==0 );
|
||||
db = pParse->db;
|
||||
if( db->mallocFailed ) return;
|
||||
if( pParse->nested ) return;
|
||||
@@ -2446,8 +2447,8 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, j2);
|
||||
addr2 = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeAddOp3(v, OP_SorterCompare, iSorter, j2, regRecord);
|
||||
sqlite3HaltConstraint(
|
||||
pParse, OE_Abort, "indexed columns are not unique", P4_STATIC
|
||||
sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_UNIQUE,
|
||||
OE_Abort, "indexed columns are not unique", P4_STATIC
|
||||
);
|
||||
}else{
|
||||
addr2 = sqlite3VdbeCurrentAddr(v);
|
||||
@@ -2473,8 +2474,8 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
||||
** since sqlite3ReleaseTempRange() was called, it is safe to do so.
|
||||
*/
|
||||
sqlite3VdbeAddOp4(v, OP_IsUnique, iIdx, j2, regRowid, pRegKey, P4_INT32);
|
||||
sqlite3HaltConstraint(
|
||||
pParse, OE_Abort, "indexed columns are not unique", P4_STATIC);
|
||||
sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_UNIQUE,
|
||||
"indexed columns are not unique", P4_STATIC);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_IdxInsert, iIdx, regRecord, 0);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
|
||||
@@ -2593,7 +2594,7 @@ Index *sqlite3CreateIndex(
|
||||
assert( pTab!=0 );
|
||||
assert( pParse->nErr==0 );
|
||||
if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0
|
||||
&& memcmp(&pTab->zName[7],"altertab_",9)!=0 ){
|
||||
&& sqlite3StrNICmp(&pTab->zName[7],"altertab_",9)!=0 ){
|
||||
sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName);
|
||||
goto exit_create_index;
|
||||
}
|
||||
@@ -2690,10 +2691,8 @@ Index *sqlite3CreateIndex(
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
Expr *pExpr = pList->a[i].pExpr;
|
||||
if( pExpr ){
|
||||
CollSeq *pColl = pExpr->pColl;
|
||||
/* Either pColl!=0 or there was an OOM failure. But if an OOM
|
||||
** failure we have quit before reaching this point. */
|
||||
if( ALWAYS(pColl) ){
|
||||
CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr);
|
||||
if( pColl ){
|
||||
nExtra += (1 + sqlite3Strlen30(pColl->zName));
|
||||
}
|
||||
}
|
||||
@@ -2756,6 +2755,7 @@ Index *sqlite3CreateIndex(
|
||||
const char *zColName = pListItem->zName;
|
||||
Column *pTabCol;
|
||||
int requestedSortOrder;
|
||||
CollSeq *pColl; /* Collating sequence */
|
||||
char *zColl; /* Collation sequence name */
|
||||
|
||||
for(j=0, pTabCol=pTab->aCol; j<pTab->nCol; j++, pTabCol++){
|
||||
@@ -2768,14 +2768,11 @@ Index *sqlite3CreateIndex(
|
||||
goto exit_create_index;
|
||||
}
|
||||
pIndex->aiColumn[i] = j;
|
||||
/* Justification of the ALWAYS(pListItem->pExpr->pColl): Because of
|
||||
** the way the "idxlist" non-terminal is constructed by the parser,
|
||||
** if pListItem->pExpr is not null then either pListItem->pExpr->pColl
|
||||
** must exist or else there must have been an OOM error. But if there
|
||||
** was an OOM error, we would never reach this point. */
|
||||
if( pListItem->pExpr && ALWAYS(pListItem->pExpr->pColl) ){
|
||||
if( pListItem->pExpr
|
||||
&& (pColl = sqlite3ExprCollSeq(pParse, pListItem->pExpr))!=0
|
||||
){
|
||||
int nColl;
|
||||
zColl = pListItem->pExpr->pColl->zName;
|
||||
zColl = pColl->zName;
|
||||
nColl = sqlite3Strlen30(zColl) + 1;
|
||||
assert( nExtra>=nColl );
|
||||
memcpy(zExtra, zColl, nColl);
|
||||
@@ -3589,6 +3586,15 @@ int sqlite3OpenTempDatabase(Parse *pParse){
|
||||
void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
|
||||
Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
if( pToplevel!=pParse ){
|
||||
/* This branch is taken if a trigger is currently being coded. In this
|
||||
** case, set cookieGoto to a non-zero value to show that this function
|
||||
** has been called. This is used by the sqlite3ExprCodeConstants()
|
||||
** function. */
|
||||
pParse->cookieGoto = -1;
|
||||
}
|
||||
#endif
|
||||
if( pToplevel->cookieGoto==0 ){
|
||||
Vdbe *v = sqlite3GetVdbe(pToplevel);
|
||||
if( v==0 ) return; /* This only happens if there was a prior error */
|
||||
@@ -3686,12 +3692,19 @@ void sqlite3MayAbort(Parse *pParse){
|
||||
** error. The onError parameter determines which (if any) of the statement
|
||||
** and/or current transaction is rolled back.
|
||||
*/
|
||||
void sqlite3HaltConstraint(Parse *pParse, int onError, char *p4, int p4type){
|
||||
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, SQLITE_CONSTRAINT, onError, 0, p4, p4type);
|
||||
sqlite3VdbeAddOp4(v, OP_Halt, errCode, onError, 0, p4, p4type);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+18
-20
@@ -93,30 +93,28 @@ void sqlite3MaterializeView(
|
||||
int iCur /* Cursor number for ephemerial table */
|
||||
){
|
||||
SelectDest dest;
|
||||
Select *pDup;
|
||||
Select *pSel;
|
||||
SrcList *pFrom;
|
||||
sqlite3 *db = pParse->db;
|
||||
int iDb = sqlite3SchemaToIndex(db, pView->pSchema);
|
||||
|
||||
pDup = sqlite3SelectDup(db, pView->pSelect, 0);
|
||||
if( pWhere ){
|
||||
SrcList *pFrom;
|
||||
|
||||
pWhere = sqlite3ExprDup(db, pWhere, 0);
|
||||
pFrom = sqlite3SrcListAppend(db, 0, 0, 0);
|
||||
if( pFrom ){
|
||||
assert( pFrom->nSrc==1 );
|
||||
pFrom->a[0].zAlias = sqlite3DbStrDup(db, pView->zName);
|
||||
pFrom->a[0].pSelect = pDup;
|
||||
assert( pFrom->a[0].pOn==0 );
|
||||
assert( pFrom->a[0].pUsing==0 );
|
||||
}else{
|
||||
sqlite3SelectDelete(db, pDup);
|
||||
}
|
||||
pDup = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, 0, 0, 0);
|
||||
if( pDup ) pDup->selFlags |= SF_Materialize;
|
||||
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, pDup, &dest);
|
||||
sqlite3SelectDelete(db, pDup);
|
||||
sqlite3Select(pParse, pSel, &dest);
|
||||
sqlite3SelectDelete(db, pSel);
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) */
|
||||
|
||||
|
||||
+116
-69
@@ -31,7 +31,9 @@
|
||||
** SELECT * FROM t1 WHERE (select a from t1);
|
||||
*/
|
||||
char sqlite3ExprAffinity(Expr *pExpr){
|
||||
int op = pExpr->op;
|
||||
int op;
|
||||
pExpr = sqlite3ExprSkipCollate(pExpr);
|
||||
op = pExpr->op;
|
||||
if( op==TK_SELECT ){
|
||||
assert( pExpr->flags&EP_xIsSelect );
|
||||
return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
|
||||
@@ -56,66 +58,94 @@ char sqlite3ExprAffinity(Expr *pExpr){
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the explicit collating sequence for an expression to the
|
||||
** collating sequence supplied in the second argument.
|
||||
** Set the collating sequence for expression pExpr to be the collating
|
||||
** sequence named by pToken. Return a pointer to a new Expr node that
|
||||
** implements the COLLATE operator.
|
||||
**
|
||||
** If a memory allocation error occurs, that fact is recorded in pParse->db
|
||||
** and the pExpr parameter is returned unchanged.
|
||||
*/
|
||||
Expr *sqlite3ExprSetColl(Expr *pExpr, CollSeq *pColl){
|
||||
if( pExpr && pColl ){
|
||||
pExpr->pColl = pColl;
|
||||
pExpr->flags |= EP_ExpCollate;
|
||||
Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr *pExpr, Token *pCollName){
|
||||
if( pCollName->n>0 ){
|
||||
Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, 1);
|
||||
if( pNew ){
|
||||
pNew->pLeft = pExpr;
|
||||
pNew->flags |= EP_Collate;
|
||||
pExpr = pNew;
|
||||
}
|
||||
}
|
||||
return pExpr;
|
||||
}
|
||||
Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, const char *zC){
|
||||
Token s;
|
||||
assert( zC!=0 );
|
||||
s.z = zC;
|
||||
s.n = sqlite3Strlen30(s.z);
|
||||
return sqlite3ExprAddCollateToken(pParse, pExpr, &s);
|
||||
}
|
||||
|
||||
/*
|
||||
** Skip over any TK_COLLATE and/or TK_AS operators at the root of
|
||||
** an expression.
|
||||
*/
|
||||
Expr *sqlite3ExprSkipCollate(Expr *pExpr){
|
||||
while( pExpr && (pExpr->op==TK_COLLATE || pExpr->op==TK_AS) ){
|
||||
pExpr = pExpr->pLeft;
|
||||
}
|
||||
return pExpr;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the collating sequence for expression pExpr to be the collating
|
||||
** sequence named by pToken. Return a pointer to the revised expression.
|
||||
** The collating sequence is marked as "explicit" using the EP_ExpCollate
|
||||
** flag. An explicit collating sequence will override implicit
|
||||
** collating sequences.
|
||||
*/
|
||||
Expr *sqlite3ExprSetCollByToken(Parse *pParse, Expr *pExpr, Token *pCollName){
|
||||
char *zColl = 0; /* Dequoted name of collation sequence */
|
||||
CollSeq *pColl;
|
||||
sqlite3 *db = pParse->db;
|
||||
zColl = sqlite3NameFromToken(db, pCollName);
|
||||
pColl = sqlite3LocateCollSeq(pParse, zColl);
|
||||
sqlite3ExprSetColl(pExpr, pColl);
|
||||
sqlite3DbFree(db, zColl);
|
||||
return pExpr;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the default collation sequence for the expression pExpr. If
|
||||
** there is no default collation type, return 0.
|
||||
** Return the collation sequence for the expression pExpr. If
|
||||
** there is no defined collating sequence, return NULL.
|
||||
**
|
||||
** The collating sequence might be determined by a COLLATE operator
|
||||
** or by the presence of a column with a defined collating sequence.
|
||||
** COLLATE operators take first precedence. Left operands take
|
||||
** precedence over right operands.
|
||||
*/
|
||||
CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
|
||||
sqlite3 *db = pParse->db;
|
||||
CollSeq *pColl = 0;
|
||||
Expr *p = pExpr;
|
||||
while( p ){
|
||||
int op;
|
||||
pColl = p->pColl;
|
||||
if( pColl ) break;
|
||||
op = p->op;
|
||||
if( p->pTab!=0 && (
|
||||
op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_REGISTER || op==TK_TRIGGER
|
||||
)){
|
||||
/* op==TK_REGISTER && p->pTab!=0 happens when pExpr was originally
|
||||
** a TK_COLUMN but was previously evaluated and cached in a register */
|
||||
const char *zColl;
|
||||
int j = p->iColumn;
|
||||
if( j>=0 ){
|
||||
sqlite3 *db = pParse->db;
|
||||
zColl = p->pTab->aCol[j].zColl;
|
||||
pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0);
|
||||
pExpr->pColl = pColl;
|
||||
int op = p->op;
|
||||
if( op==TK_CAST || op==TK_UPLUS ){
|
||||
p = p->pLeft;
|
||||
continue;
|
||||
}
|
||||
assert( op!=TK_REGISTER || p->op2!=TK_COLLATE );
|
||||
if( op==TK_COLLATE ){
|
||||
if( db->init.busy ){
|
||||
/* Do not report errors when parsing while the schema */
|
||||
pColl = sqlite3FindCollSeq(db, ENC(db), p->u.zToken, 0);
|
||||
}else{
|
||||
pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if( op!=TK_CAST && op!=TK_UPLUS ){
|
||||
if( p->pTab!=0
|
||||
&& (op==TK_AGG_COLUMN || op==TK_COLUMN
|
||||
|| op==TK_REGISTER || op==TK_TRIGGER)
|
||||
){
|
||||
/* op==TK_REGISTER && p->pTab!=0 happens when pExpr was originally
|
||||
** a TK_COLUMN but was previously evaluated and cached in a register */
|
||||
int j = p->iColumn;
|
||||
if( j>=0 ){
|
||||
const char *zColl = p->pTab->aCol[j].zColl;
|
||||
pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if( p->flags & EP_Collate ){
|
||||
if( ALWAYS(p->pLeft) && (p->pLeft->flags & EP_Collate)!=0 ){
|
||||
p = p->pLeft;
|
||||
}else{
|
||||
p = p->pRight;
|
||||
}
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
p = p->pLeft;
|
||||
}
|
||||
if( sqlite3CheckCollSeq(pParse, pColl) ){
|
||||
pColl = 0;
|
||||
@@ -219,12 +249,10 @@ CollSeq *sqlite3BinaryCompareCollSeq(
|
||||
){
|
||||
CollSeq *pColl;
|
||||
assert( pLeft );
|
||||
if( pLeft->flags & EP_ExpCollate ){
|
||||
assert( pLeft->pColl );
|
||||
pColl = pLeft->pColl;
|
||||
}else if( pRight && pRight->flags & EP_ExpCollate ){
|
||||
assert( pRight->pColl );
|
||||
pColl = pRight->pColl;
|
||||
if( pLeft->flags & EP_Collate ){
|
||||
pColl = sqlite3ExprCollSeq(pParse, pLeft);
|
||||
}else if( pRight && (pRight->flags & EP_Collate)!=0 ){
|
||||
pColl = sqlite3ExprCollSeq(pParse, pRight);
|
||||
}else{
|
||||
pColl = sqlite3ExprCollSeq(pParse, pLeft);
|
||||
if( !pColl ){
|
||||
@@ -454,17 +482,11 @@ void sqlite3ExprAttachSubtrees(
|
||||
}else{
|
||||
if( pRight ){
|
||||
pRoot->pRight = pRight;
|
||||
if( pRight->flags & EP_ExpCollate ){
|
||||
pRoot->flags |= EP_ExpCollate;
|
||||
pRoot->pColl = pRight->pColl;
|
||||
}
|
||||
pRoot->flags |= EP_Collate & pRight->flags;
|
||||
}
|
||||
if( pLeft ){
|
||||
pRoot->pLeft = pLeft;
|
||||
if( pLeft->flags & EP_ExpCollate ){
|
||||
pRoot->flags |= EP_ExpCollate;
|
||||
pRoot->pColl = pLeft->pColl;
|
||||
}
|
||||
pRoot->flags |= EP_Collate & pLeft->flags;
|
||||
}
|
||||
exprSetHeight(pRoot);
|
||||
}
|
||||
@@ -616,7 +638,7 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
|
||||
*/
|
||||
ynVar i;
|
||||
for(i=0; i<pParse->nzVar; i++){
|
||||
if( pParse->azVar[i] && memcmp(pParse->azVar[i],z,n+1)==0 ){
|
||||
if( pParse->azVar[i] && strcmp(pParse->azVar[i],z)==0 ){
|
||||
pExpr->iColumn = x = (ynVar)i+1;
|
||||
break;
|
||||
}
|
||||
@@ -722,7 +744,7 @@ static int dupedExprStructSize(Expr *p, int flags){
|
||||
assert( !ExprHasProperty(p, EP_FromJoin) );
|
||||
assert( (p->flags2 & EP2_MallocedToken)==0 );
|
||||
assert( (p->flags2 & EP2_Irreducible)==0 );
|
||||
if( p->pLeft || p->pRight || p->pColl || p->x.pList ){
|
||||
if( p->pLeft || p->pRight || p->x.pList ){
|
||||
nSize = EXPR_REDUCEDSIZE | EP_Reduced;
|
||||
}else{
|
||||
nSize = EXPR_TOKENONLYSIZE | EP_TokenOnly;
|
||||
@@ -2746,6 +2768,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
sqlite3ReleaseTempReg(pParse, r4);
|
||||
break;
|
||||
}
|
||||
case TK_COLLATE:
|
||||
case TK_UPLUS: {
|
||||
inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
|
||||
break;
|
||||
@@ -2912,7 +2935,8 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
sqlite3VdbeAddOp4(
|
||||
v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0);
|
||||
}else{
|
||||
sqlite3HaltConstraint(pParse, pExpr->affinity, pExpr->u.zToken, 0);
|
||||
sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_TRIGGER,
|
||||
pExpr->affinity, pExpr->u.zToken, 0);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -3115,6 +3139,12 @@ void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){
|
||||
case TK_ISNULL: zUniOp = "ISNULL"; break;
|
||||
case TK_NOTNULL: zUniOp = "NOTNULL"; break;
|
||||
|
||||
case TK_COLLATE: {
|
||||
sqlite3ExplainExpr(pOut, pExpr->pLeft);
|
||||
sqlite3ExplainPrintf(pOut,".COLLATE(%s)",pExpr->u.zToken);
|
||||
break;
|
||||
}
|
||||
|
||||
case TK_AGG_FUNCTION:
|
||||
case TK_CONST_FUNC:
|
||||
case TK_FUNCTION: {
|
||||
@@ -3252,6 +3282,12 @@ void sqlite3ExplainExprList(Vdbe *pOut, ExprList *pList){
|
||||
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);
|
||||
}
|
||||
@@ -3333,6 +3369,9 @@ static int evalConstExpr(Walker *pWalker, Expr *pExpr){
|
||||
case TK_REGISTER: {
|
||||
return WRC_Prune;
|
||||
}
|
||||
case TK_COLLATE: {
|
||||
return WRC_Continue;
|
||||
}
|
||||
case TK_FUNCTION:
|
||||
case TK_AGG_FUNCTION:
|
||||
case TK_CONST_FUNC: {
|
||||
@@ -3354,9 +3393,11 @@ static int evalConstExpr(Walker *pWalker, Expr *pExpr){
|
||||
}
|
||||
if( isAppropriateForFactoring(pExpr) ){
|
||||
int r1 = ++pParse->nMem;
|
||||
int r2;
|
||||
r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1);
|
||||
if( NEVER(r1!=r2) ) sqlite3ReleaseTempReg(pParse, r1);
|
||||
int r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1);
|
||||
/* If r2!=r1, it means that register r1 is never used. That is harmless
|
||||
** but suboptimal, so we want to know about the situation to fix it.
|
||||
** Hence the following assert: */
|
||||
assert( r2==r1 );
|
||||
pExpr->op2 = pExpr->op;
|
||||
pExpr->op = TK_REGISTER;
|
||||
pExpr->iTable = r2;
|
||||
@@ -3773,7 +3814,15 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
|
||||
return 2;
|
||||
}
|
||||
if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2;
|
||||
if( pA->op!=pB->op ) return 2;
|
||||
if( pA->op!=pB->op ){
|
||||
if( pA->op==TK_COLLATE && sqlite3ExprCompare(pA->pLeft, pB)<2 ){
|
||||
return 1;
|
||||
}
|
||||
if( pB->op==TK_COLLATE && sqlite3ExprCompare(pA, pB->pLeft)<2 ){
|
||||
return 1;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
if( sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 2;
|
||||
if( sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 2;
|
||||
if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList) ) return 2;
|
||||
@@ -3785,11 +3834,9 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
|
||||
}else if( pA->op!=TK_COLUMN && ALWAYS(pA->op!=TK_AGG_COLUMN) && pA->u.zToken){
|
||||
if( ExprHasProperty(pB, EP_IntValue) || NEVER(pB->u.zToken==0) ) return 2;
|
||||
if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){
|
||||
return 2;
|
||||
return pA->op==TK_COLLATE ? 1 : 2;
|
||||
}
|
||||
}
|
||||
if( (pA->flags & EP_ExpCollate)!=(pB->flags & EP_ExpCollate) ) return 1;
|
||||
if( (pA->flags & EP_ExpCollate)!=0 && pA->pColl!=pB->pColl ) return 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+22
-15
@@ -21,8 +21,9 @@
|
||||
** --------------------------
|
||||
**
|
||||
** Foreign keys in SQLite come in two flavours: deferred and immediate.
|
||||
** If an immediate foreign key constraint is violated, SQLITE_CONSTRAINT
|
||||
** is returned and the current statement transaction rolled back. If a
|
||||
** 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.
|
||||
@@ -86,7 +87,8 @@
|
||||
** 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
|
||||
** 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
|
||||
@@ -142,7 +144,7 @@
|
||||
** A foreign key constraint requires that the key columns in the parent
|
||||
** table are collectively subject to a UNIQUE or PRIMARY KEY constraint.
|
||||
** Given that pParent is the parent table for foreign key constraint pFKey,
|
||||
** search the schema a unique index on the parent key columns.
|
||||
** 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
|
||||
@@ -178,7 +180,7 @@
|
||||
** into pParse. If an OOM error occurs, non-zero is returned and the
|
||||
** pParse->db->mallocFailed flag is set.
|
||||
*/
|
||||
static int locateFkeyIndex(
|
||||
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 */
|
||||
@@ -275,7 +277,9 @@ static int locateFkeyIndex(
|
||||
|
||||
if( !pIdx ){
|
||||
if( !pParse->disableTriggers ){
|
||||
sqlite3ErrorMsg(pParse, "foreign key mismatch");
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"foreign key mismatch - \"%w\" referencing \"%w\"",
|
||||
pFKey->pFrom->zName, pFKey->zTo);
|
||||
}
|
||||
sqlite3DbFree(pParse->db, aiCol);
|
||||
return 1;
|
||||
@@ -424,8 +428,8 @@ static void fkLookupParent(
|
||||
** incrementing a counter. This is necessary as the VM code is being
|
||||
** generated for will not open a statement transaction. */
|
||||
assert( nIncr==1 );
|
||||
sqlite3HaltConstraint(
|
||||
pParse, OE_Abort, "foreign key constraint failed", P4_STATIC
|
||||
sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY,
|
||||
OE_Abort, "foreign key constraint failed", P4_STATIC
|
||||
);
|
||||
}else{
|
||||
if( nIncr>0 && pFKey->isDeferred==0 ){
|
||||
@@ -511,12 +515,15 @@ static void fkScanChildren(
|
||||
** expression to the parent key column defaults. */
|
||||
if( pIdx ){
|
||||
Column *pCol;
|
||||
const char *zColl;
|
||||
iCol = pIdx->aiColumn[i];
|
||||
pCol = &pTab->aCol[iCol];
|
||||
if( pTab->iPKey==iCol ) iCol = -1;
|
||||
pLeft->iTable = regData+iCol+1;
|
||||
pLeft->affinity = pCol->affinity;
|
||||
pLeft->pColl = sqlite3LocateCollSeq(pParse, pCol->zColl);
|
||||
zColl = pCol->zColl;
|
||||
if( zColl==0 ) zColl = db->pDfltColl->zName;
|
||||
pLeft = sqlite3ExprAddCollateString(pParse, pLeft, zColl);
|
||||
}else{
|
||||
pLeft->iTable = regData;
|
||||
pLeft->affinity = SQLITE_AFF_INTEGER;
|
||||
@@ -662,8 +669,8 @@ void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){
|
||||
** any modifications to the schema are made. This is because statement
|
||||
** transactions are not able to rollback schema changes. */
|
||||
sqlite3VdbeAddOp2(v, OP_FkIfZero, 0, sqlite3VdbeCurrentAddr(v)+2);
|
||||
sqlite3HaltConstraint(
|
||||
pParse, OE_Abort, "foreign key constraint failed", P4_STATIC
|
||||
sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY,
|
||||
OE_Abort, "foreign key constraint failed", P4_STATIC
|
||||
);
|
||||
|
||||
if( iSkip ){
|
||||
@@ -733,7 +740,7 @@ void sqlite3FkCheck(
|
||||
}else{
|
||||
pTo = sqlite3LocateTable(pParse, 0, pFKey->zTo, zDb);
|
||||
}
|
||||
if( !pTo || locateFkeyIndex(pParse, pTo, pFKey, &pIdx, &aiFree) ){
|
||||
if( !pTo || sqlite3FkLocateIndex(pParse, pTo, pFKey, &pIdx, &aiFree) ){
|
||||
assert( isIgnoreErrors==0 || (regOld!=0 && regNew==0) );
|
||||
if( !isIgnoreErrors || db->mallocFailed ) return;
|
||||
if( pTo==0 ){
|
||||
@@ -813,7 +820,7 @@ void sqlite3FkCheck(
|
||||
continue;
|
||||
}
|
||||
|
||||
if( locateFkeyIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ){
|
||||
if( sqlite3FkLocateIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ){
|
||||
if( !isIgnoreErrors || db->mallocFailed ) return;
|
||||
continue;
|
||||
}
|
||||
@@ -868,7 +875,7 @@ u32 sqlite3FkOldmask(
|
||||
}
|
||||
for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){
|
||||
Index *pIdx = 0;
|
||||
locateFkeyIndex(pParse, pTab, p, &pIdx, 0);
|
||||
sqlite3FkLocateIndex(pParse, pTab, p, &pIdx, 0);
|
||||
if( pIdx ){
|
||||
for(i=0; i<pIdx->nColumn; i++) mask |= COLUMN_MASK(pIdx->aiColumn[i]);
|
||||
}
|
||||
@@ -994,7 +1001,7 @@ static Trigger *fkActionTrigger(
|
||||
int i; /* Iterator variable */
|
||||
Expr *pWhen = 0; /* WHEN clause for the trigger */
|
||||
|
||||
if( locateFkeyIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ) return 0;
|
||||
if( sqlite3FkLocateIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ) return 0;
|
||||
assert( aiCol || pFKey->nCol==1 );
|
||||
|
||||
for(i=0; i<pFKey->nCol; i++){
|
||||
|
||||
+59
@@ -192,6 +192,7 @@ static void instrFunc(
|
||||
int N = 1;
|
||||
int isText;
|
||||
|
||||
UNUSED_PARAMETER(argc);
|
||||
typeHaystack = sqlite3_value_type(argv[0]);
|
||||
typeNeedle = sqlite3_value_type(argv[1]);
|
||||
if( typeHaystack==SQLITE_NULL || typeNeedle==SQLITE_NULL ) return;
|
||||
@@ -961,6 +962,62 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** 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.
|
||||
@@ -1588,6 +1645,8 @@ void sqlite3RegisterGlobalFunctions(void){
|
||||
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 ),
|
||||
|
||||
+19
-22
@@ -1245,7 +1245,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
case OE_Fail: {
|
||||
char *zMsg;
|
||||
sqlite3VdbeAddOp3(v, OP_HaltIfNull,
|
||||
SQLITE_CONSTRAINT, onError, regData+i);
|
||||
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);
|
||||
@@ -1274,25 +1274,21 @@ void sqlite3GenerateConstraintChecks(
|
||||
onError = overrideError!=OE_Default ? overrideError : OE_Abort;
|
||||
for(i=0; i<pCheck->nExpr; i++){
|
||||
int allOk = sqlite3VdbeMakeLabel(v);
|
||||
Expr *pDup = sqlite3ExprDup(db, pCheck->a[i].pExpr, 0);
|
||||
if( !db->mallocFailed ){
|
||||
assert( pDup!=0 );
|
||||
sqlite3ExprIfTrue(pParse, pDup, allOk, SQLITE_JUMPIFNULL);
|
||||
if( onError==OE_Ignore ){
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
|
||||
sqlite3ExprIfTrue(pParse, pCheck->a[i].pExpr, allOk, SQLITE_JUMPIFNULL);
|
||||
if( onError==OE_Ignore ){
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
|
||||
}else{
|
||||
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{
|
||||
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, onError, zConsName, P4_DYNAMIC);
|
||||
zConsName = 0;
|
||||
}
|
||||
sqlite3VdbeResolveLabel(v, allOk);
|
||||
sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_CHECK,
|
||||
onError, zConsName, P4_DYNAMIC);
|
||||
}
|
||||
sqlite3ExprDelete(db, pDup);
|
||||
sqlite3VdbeResolveLabel(v, allOk);
|
||||
}
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_CHECK) */
|
||||
@@ -1321,8 +1317,8 @@ void sqlite3GenerateConstraintChecks(
|
||||
case OE_Rollback:
|
||||
case OE_Abort:
|
||||
case OE_Fail: {
|
||||
sqlite3HaltConstraint(
|
||||
pParse, onError, "PRIMARY KEY must be unique", P4_STATIC);
|
||||
sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_PRIMARYKEY,
|
||||
onError, "PRIMARY KEY must be unique", P4_STATIC);
|
||||
break;
|
||||
}
|
||||
case OE_Replace: {
|
||||
@@ -1449,7 +1445,8 @@ void sqlite3GenerateConstraintChecks(
|
||||
sqlite3StrAccumAppend(&errMsg,
|
||||
pIdx->nColumn>1 ? " are not unique" : " is not unique", -1);
|
||||
zErr = sqlite3StrAccumFinish(&errMsg);
|
||||
sqlite3HaltConstraint(pParse, onError, zErr, 0);
|
||||
sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_UNIQUE,
|
||||
onError, zErr, 0);
|
||||
sqlite3DbFree(errMsg.db, zErr);
|
||||
break;
|
||||
}
|
||||
@@ -1857,8 +1854,8 @@ static int xferOptimization(
|
||||
if( pDest->iPKey>=0 ){
|
||||
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
|
||||
addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid);
|
||||
sqlite3HaltConstraint(
|
||||
pParse, onError, "PRIMARY KEY must be unique", P4_STATIC);
|
||||
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 ){
|
||||
|
||||
@@ -59,6 +59,14 @@ static int createFile(JournalFile *p){
|
||||
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;
|
||||
@@ -228,6 +236,16 @@ int sqlite3JournalCreate(sqlite3_file *p){
|
||||
return createFile((JournalFile *)p);
|
||||
}
|
||||
|
||||
/*
|
||||
** The file-handle passed as the only argument is guaranteed to be an open
|
||||
** file. It may or may not be of class JournalFile. If the file is a
|
||||
** JournalFile, and the underlying file on disk has not yet been opened,
|
||||
** return 0. Otherwise, return 1.
|
||||
*/
|
||||
int sqlite3JournalExists(sqlite3_file *p){
|
||||
return (p->pMethods!=&JournalFileMethods || ((JournalFile *)p)->pReal!=0);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the number of bytes required to store a JournalFile that uses vfs
|
||||
** pVfs to create the underlying on-disk files.
|
||||
|
||||
@@ -378,6 +378,19 @@ static const sqlite3_api_routines sqlite3Apis = {
|
||||
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
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
+1
-1
@@ -1002,7 +1002,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){
|
||||
sqlite3VtabRollback(db);
|
||||
sqlite3EndBenignMalloc();
|
||||
|
||||
if( db->flags&SQLITE_InternChanges ){
|
||||
if( (db->flags&SQLITE_InternChanges)!=0 && db->init.busy==0 ){
|
||||
sqlite3ExpirePreparedStatements(db);
|
||||
sqlite3ResetAllSchemasOfConnection(db);
|
||||
}
|
||||
|
||||
+26
-21
@@ -412,11 +412,7 @@ static struct unix_syscall {
|
||||
#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\
|
||||
aSyscall[13].pCurrent)
|
||||
|
||||
#if SQLITE_ENABLE_LOCKING_STYLE
|
||||
{ "fchmod", (sqlite3_syscall_ptr)fchmod, 0 },
|
||||
#else
|
||||
{ "fchmod", (sqlite3_syscall_ptr)0, 0 },
|
||||
#endif
|
||||
#define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent)
|
||||
|
||||
#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
|
||||
@@ -441,9 +437,6 @@ static struct unix_syscall {
|
||||
{ "fchown", (sqlite3_syscall_ptr)posixFchown, 0 },
|
||||
#define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent)
|
||||
|
||||
{ "umask", (sqlite3_syscall_ptr)umask, 0 },
|
||||
#define osUmask ((mode_t(*)(mode_t))aSyscall[21].pCurrent)
|
||||
|
||||
}; /* End of the overrideable system calls */
|
||||
|
||||
/*
|
||||
@@ -548,14 +541,7 @@ static const char *unixNextSystemCall(sqlite3_vfs *p, const char *zName){
|
||||
*/
|
||||
static int robust_open(const char *z, int f, mode_t m){
|
||||
int fd;
|
||||
mode_t m2;
|
||||
mode_t origM = 0;
|
||||
if( m==0 ){
|
||||
m2 = SQLITE_DEFAULT_FILE_PERMISSIONS;
|
||||
}else{
|
||||
m2 = m;
|
||||
origM = osUmask(0);
|
||||
}
|
||||
mode_t m2 = m ? m : SQLITE_DEFAULT_FILE_PERMISSIONS;
|
||||
do{
|
||||
#if defined(O_CLOEXEC)
|
||||
fd = osOpen(z,f|O_CLOEXEC,m2);
|
||||
@@ -563,12 +549,20 @@ static int robust_open(const char *z, int f, mode_t m){
|
||||
fd = osOpen(z,f,m2);
|
||||
#endif
|
||||
}while( fd<0 && errno==EINTR );
|
||||
if( m ){
|
||||
osUmask(origM);
|
||||
}
|
||||
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)
|
||||
if( fd>=0 ) osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
|
||||
osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC);
|
||||
#endif
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
@@ -3581,6 +3575,9 @@ static void unixModeBit(unixFile *pFile, unsigned char mask, int *pArg){
|
||||
}
|
||||
}
|
||||
|
||||
/* Forward declaration */
|
||||
static int unixGetTempname(int nBuf, char *zBuf);
|
||||
|
||||
/*
|
||||
** Information and control of an open file handle.
|
||||
*/
|
||||
@@ -3618,6 +3615,14 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
*(char**)pArg = sqlite3_mprintf("%s", pFile->pVfs->zName);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
case SQLITE_FCNTL_TEMPFILENAME: {
|
||||
char *zTFile = sqlite3_malloc( pFile->pVfs->mxPathname );
|
||||
if( zTFile ){
|
||||
unixGetTempname(pFile->pVfs->mxPathname, zTFile);
|
||||
*(char**)pArg = zTFile;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
#ifdef SQLITE_DEBUG
|
||||
/* The pager calls this method to signal that it has done
|
||||
** a rollback and that the database is therefore unchanged and
|
||||
@@ -4750,7 +4755,7 @@ static int fillInUnixFile(
|
||||
"psow", SQLITE_POWERSAFE_OVERWRITE) ){
|
||||
pNew->ctrlFlags |= UNIXFILE_PSOW;
|
||||
}
|
||||
if( memcmp(pVfs->zName,"unix-excl",10)==0 ){
|
||||
if( strcmp(pVfs->zName,"unix-excl")==0 ){
|
||||
pNew->ctrlFlags |= UNIXFILE_EXCL;
|
||||
}
|
||||
|
||||
@@ -6983,7 +6988,7 @@ int sqlite3_os_init(void){
|
||||
|
||||
/* Double-check that the aSyscall[] array has been constructed
|
||||
** correctly. See ticket [bb3a86e890c8e96ab] */
|
||||
assert( ArraySize(aSyscall)==22 );
|
||||
assert( ArraySize(aSyscall)==21 );
|
||||
|
||||
/* Register all VFSes defined in the aVfs[] array */
|
||||
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
|
||||
|
||||
+84
-56
@@ -988,7 +988,7 @@ static const char *winNextSystemCall(sqlite3_vfs *p, const char *zName){
|
||||
** (if available).
|
||||
*/
|
||||
|
||||
void sqlite3_win32_write_debug(char *zBuf, int nBuf){
|
||||
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. */
|
||||
@@ -1621,9 +1621,10 @@ static void logIoerr(int nRetry){
|
||||
/*************************************************************************
|
||||
** This section contains code for WinCE only.
|
||||
*/
|
||||
#if !defined(SQLITE_MSVC_LOCALTIME_API) || !SQLITE_MSVC_LOCALTIME_API
|
||||
/*
|
||||
** Windows CE does not have a localtime() function. So create a
|
||||
** substitute.
|
||||
** 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)
|
||||
@@ -1647,6 +1648,7 @@ struct tm *__cdecl localtime(const time_t *t)
|
||||
y.tm_sec = pTm.wSecond;
|
||||
return &y;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define HANDLE_TO_WINFILE(a) (winFile*)&((char*)a)[-(int)offsetof(winFile,h)]
|
||||
|
||||
@@ -1668,15 +1670,17 @@ static void winceMutexAcquire(HANDLE h){
|
||||
** Create the mutex and shared memory used for locking in the file
|
||||
** descriptor pFile
|
||||
*/
|
||||
static BOOL winceCreateLock(const char *zFilename, winFile *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 FALSE;
|
||||
return SQLITE_IOERR_NOMEM;
|
||||
}
|
||||
|
||||
/* Initialize the local lockdata */
|
||||
@@ -1693,9 +1697,10 @@ static BOOL winceCreateLock(const char *zFilename, winFile *pFile){
|
||||
pFile->hMutex = osCreateMutexW(NULL, FALSE, zName);
|
||||
if (!pFile->hMutex){
|
||||
pFile->lastErrno = osGetLastError();
|
||||
winLogError(SQLITE_ERROR, pFile->lastErrno, "winceCreateLock1", zFilename);
|
||||
winLogError(SQLITE_IOERR, pFile->lastErrno,
|
||||
"winceCreateLock1", zFilename);
|
||||
sqlite3_free(zName);
|
||||
return FALSE;
|
||||
return SQLITE_IOERR;
|
||||
}
|
||||
|
||||
/* Acquire the mutex before continuing */
|
||||
@@ -1712,41 +1717,49 @@ static BOOL winceCreateLock(const char *zFilename, winFile *pFile){
|
||||
|
||||
/* Set a flag that indicates we're the first to create the memory so it
|
||||
** must be zero-initialized */
|
||||
if (osGetLastError() == ERROR_ALREADY_EXISTS){
|
||||
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){
|
||||
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){
|
||||
if( !pFile->shared ){
|
||||
pFile->lastErrno = osGetLastError();
|
||||
winLogError(SQLITE_ERROR, pFile->lastErrno,
|
||||
"winceCreateLock2", zFilename);
|
||||
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( 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 FALSE;
|
||||
return SQLITE_IOERR;
|
||||
}
|
||||
|
||||
/* Initialize the shared memory if we're supposed to */
|
||||
if (bInit) {
|
||||
if( bInit ){
|
||||
memset(pFile->shared, 0, sizeof(winceLock));
|
||||
}
|
||||
|
||||
winceMutexRelease(pFile->hMutex);
|
||||
return TRUE;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1825,7 +1838,8 @@ static BOOL winceLockFile(
|
||||
}
|
||||
|
||||
/* Want a pending lock? */
|
||||
else if (dwFileOffsetLow == (DWORD)PENDING_BYTE && nNumberOfBytesToLockLow == 1){
|
||||
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;
|
||||
@@ -1835,7 +1849,8 @@ static BOOL winceLockFile(
|
||||
}
|
||||
|
||||
/* Want a reserved lock? */
|
||||
else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE && nNumberOfBytesToLockLow == 1){
|
||||
else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE
|
||||
&& nNumberOfBytesToLockLow == 1){
|
||||
if (pFile->shared->bReserved == 0) {
|
||||
pFile->shared->bReserved = TRUE;
|
||||
pFile->local.bReserved = TRUE;
|
||||
@@ -1878,7 +1893,8 @@ static BOOL winceUnlockFile(
|
||||
|
||||
/* Did we just have a reader lock? */
|
||||
else if (pFile->local.nReaders){
|
||||
assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE || nNumberOfBytesToUnlockLow == 1);
|
||||
assert(nNumberOfBytesToUnlockLow == (DWORD)SHARED_SIZE
|
||||
|| nNumberOfBytesToUnlockLow == 1);
|
||||
pFile->local.nReaders --;
|
||||
if (pFile->local.nReaders == 0)
|
||||
{
|
||||
@@ -1889,7 +1905,8 @@ static BOOL winceUnlockFile(
|
||||
}
|
||||
|
||||
/* Releasing a pending lock */
|
||||
else if (dwFileOffsetLow == (DWORD)PENDING_BYTE && nNumberOfBytesToUnlockLow == 1){
|
||||
else if (dwFileOffsetLow == (DWORD)PENDING_BYTE
|
||||
&& nNumberOfBytesToUnlockLow == 1){
|
||||
if (pFile->local.bPending){
|
||||
pFile->local.bPending = FALSE;
|
||||
pFile->shared->bPending = FALSE;
|
||||
@@ -1897,7 +1914,8 @@ static BOOL winceUnlockFile(
|
||||
}
|
||||
}
|
||||
/* Releasing a reserved lock */
|
||||
else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE && nNumberOfBytesToUnlockLow == 1){
|
||||
else if (dwFileOffsetLow == (DWORD)RESERVED_BYTE
|
||||
&& nNumberOfBytesToUnlockLow == 1){
|
||||
if (pFile->local.bReserved) {
|
||||
pFile->local.bReserved = FALSE;
|
||||
pFile->shared->bReserved = FALSE;
|
||||
@@ -2063,6 +2081,7 @@ static int winClose(sqlite3_file *id){
|
||||
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; ); */
|
||||
@@ -2691,6 +2710,9 @@ static void winModeBit(winFile *pFile, unsigned char mask, int *pArg){
|
||||
}
|
||||
}
|
||||
|
||||
/* Forward declaration */
|
||||
static int getTempname(int nBuf, char *zBuf);
|
||||
|
||||
/*
|
||||
** Control and query of the open file handle.
|
||||
*/
|
||||
@@ -2751,6 +2773,14 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
case SQLITE_FCNTL_TEMPFILENAME: {
|
||||
char *zTFile = sqlite3MallocZero( pFile->pVfs->mxPathname );
|
||||
if( zTFile ){
|
||||
getTempname(pFile->pVfs->mxPathname, zTFile);
|
||||
*(char**)pArg = zTFile;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
return SQLITE_NOTFOUND;
|
||||
}
|
||||
@@ -2968,7 +2998,7 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
|
||||
(int)osGetCurrentProcessId(), i,
|
||||
bRc ? "ok" : "failed"));
|
||||
}
|
||||
if( p->hFile.h != INVALID_HANDLE_VALUE ){
|
||||
if( p->hFile.h!=NULL && p->hFile.h!=INVALID_HANDLE_VALUE ){
|
||||
SimulateIOErrorBenign(1);
|
||||
winClose((sqlite3_file *)&p->hFile);
|
||||
SimulateIOErrorBenign(0);
|
||||
@@ -3048,7 +3078,7 @@ static int winOpenSharedMemory(winFile *pDbFd){
|
||||
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, /* Mode flags */
|
||||
SQLITE_OPEN_WAL | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
|
||||
0);
|
||||
if( SQLITE_OK!=rc ){
|
||||
goto shm_open_err;
|
||||
@@ -3663,8 +3693,9 @@ static int winOpen(
|
||||
|| eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
|
||||
);
|
||||
|
||||
assert( id!=0 );
|
||||
UNUSED_PARAMETER(pVfs);
|
||||
assert( pFile!=0 );
|
||||
memset(pFile, 0, sizeof(winFile));
|
||||
pFile->h = INVALID_HANDLE_VALUE;
|
||||
|
||||
#if SQLITE_OS_WINRT
|
||||
if( !sqlite3_temp_directory ){
|
||||
@@ -3673,13 +3704,12 @@ static int winOpen(
|
||||
}
|
||||
#endif
|
||||
|
||||
pFile->h = INVALID_HANDLE_VALUE;
|
||||
|
||||
/* 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;
|
||||
@@ -3802,7 +3832,9 @@ static int winOpen(
|
||||
sqlite3_free(zConverted);
|
||||
if( isReadWrite && !isExclusive ){
|
||||
return winOpen(pVfs, zName, id,
|
||||
((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), pOutFlags);
|
||||
((flags|SQLITE_OPEN_READONLY) &
|
||||
~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
|
||||
pOutFlags);
|
||||
}else{
|
||||
return SQLITE_CANTOPEN_BKPT;
|
||||
}
|
||||
@@ -3816,26 +3848,13 @@ static int winOpen(
|
||||
}
|
||||
}
|
||||
|
||||
memset(pFile, 0, sizeof(*pFile));
|
||||
pFile->pMethod = &winIoMethod;
|
||||
pFile->h = h;
|
||||
pFile->lastErrno = NO_ERROR;
|
||||
pFile->pVfs = pVfs;
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
pFile->pShm = 0;
|
||||
#endif
|
||||
pFile->zPath = zName;
|
||||
if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){
|
||||
pFile->ctrlFlags |= WINFILE_PSOW;
|
||||
}
|
||||
|
||||
#if SQLITE_OS_WINCE
|
||||
if( isReadWrite && eType==SQLITE_OPEN_MAIN_DB
|
||||
&& !winceCreateLock(zName, pFile)
|
||||
&& (rc = winceCreateLock(zName, pFile))!=SQLITE_OK
|
||||
){
|
||||
osCloseHandle(h);
|
||||
sqlite3_free(zConverted);
|
||||
return SQLITE_CANTOPEN_BKPT;
|
||||
return rc;
|
||||
}
|
||||
if( isTemp ){
|
||||
pFile->zDeleteOnClose = zConverted;
|
||||
@@ -3845,6 +3864,15 @@ static int winOpen(
|
||||
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;
|
||||
}
|
||||
@@ -3889,7 +3917,8 @@ static int winDelete(
|
||||
attr = sAttrData.dwFileAttributes;
|
||||
}else{
|
||||
lastErrno = osGetLastError();
|
||||
if( lastErrno==ERROR_FILE_NOT_FOUND || lastErrno==ERROR_PATH_NOT_FOUND ){
|
||||
if( lastErrno==ERROR_FILE_NOT_FOUND
|
||||
|| lastErrno==ERROR_PATH_NOT_FOUND ){
|
||||
rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */
|
||||
}else{
|
||||
rc = SQLITE_ERROR;
|
||||
@@ -3901,7 +3930,8 @@ static int winDelete(
|
||||
#endif
|
||||
if ( attr==INVALID_FILE_ATTRIBUTES ){
|
||||
lastErrno = osGetLastError();
|
||||
if( lastErrno==ERROR_FILE_NOT_FOUND || lastErrno==ERROR_PATH_NOT_FOUND ){
|
||||
if( lastErrno==ERROR_FILE_NOT_FOUND
|
||||
|| lastErrno==ERROR_PATH_NOT_FOUND ){
|
||||
rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */
|
||||
}else{
|
||||
rc = SQLITE_ERROR;
|
||||
@@ -3928,7 +3958,8 @@ static int winDelete(
|
||||
attr = osGetFileAttributesA(zConverted);
|
||||
if ( attr==INVALID_FILE_ATTRIBUTES ){
|
||||
lastErrno = osGetLastError();
|
||||
if( lastErrno==ERROR_FILE_NOT_FOUND || lastErrno==ERROR_PATH_NOT_FOUND ){
|
||||
if( lastErrno==ERROR_FILE_NOT_FOUND
|
||||
|| lastErrno==ERROR_PATH_NOT_FOUND ){
|
||||
rc = SQLITE_IOERR_DELETE_NOENT; /* Already gone? */
|
||||
}else{
|
||||
rc = SQLITE_ERROR;
|
||||
@@ -4096,16 +4127,12 @@ static int winFullPathname(
|
||||
*/
|
||||
char zOut[MAX_PATH+1];
|
||||
memset(zOut, 0, MAX_PATH+1);
|
||||
cygwin_conv_to_win32_path(zRelative, zOut); /* POSIX to Win32 */
|
||||
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{
|
||||
/*
|
||||
** NOTE: The Cygwin docs state that the maximum length needed
|
||||
** for the buffer passed to cygwin_conv_to_full_win32_path
|
||||
** is MAX_PATH.
|
||||
*/
|
||||
cygwin_conv_to_full_win32_path(zRelative, zFull);
|
||||
cygwin_conv_path(CCP_POSIX_TO_WIN_A, zRelative, zFull, nFull);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
#endif
|
||||
@@ -4263,9 +4290,9 @@ static void winDlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
|
||||
UNUSED_PARAMETER(pVfs);
|
||||
getLastErrorMsg(osGetLastError(), nBuf, zBufOut);
|
||||
}
|
||||
static void (*winDlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){
|
||||
static void (*winDlSym(sqlite3_vfs *pVfs,void *pH,const char *zSym))(void){
|
||||
UNUSED_PARAMETER(pVfs);
|
||||
return (void(*)(void))osGetProcAddressA((HANDLE)pHandle, zSymbol);
|
||||
return (void(*)(void))osGetProcAddressA((HANDLE)pH, zSym);
|
||||
}
|
||||
static void winDlClose(sqlite3_vfs *pVfs, void *pHandle){
|
||||
UNUSED_PARAMETER(pVfs);
|
||||
@@ -4363,7 +4390,8 @@ static int winCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){
|
||||
#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;
|
||||
(sqlite3_int64)2000000000 + (sqlite3_int64)2000000000 +
|
||||
(sqlite3_int64)294967296;
|
||||
|
||||
#if SQLITE_OS_WINCE
|
||||
SYSTEMTIME time;
|
||||
|
||||
+51
-45
@@ -1838,6 +1838,8 @@ static int pager_error(Pager *pPager, int rc){
|
||||
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
|
||||
@@ -1891,7 +1893,7 @@ static int pager_error(Pager *pPager, int rc){
|
||||
** to the first error encountered (the journal finalization one) is
|
||||
** returned.
|
||||
*/
|
||||
static int pager_end_transaction(Pager *pPager, int hasMaster){
|
||||
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 */
|
||||
|
||||
@@ -1941,12 +1943,13 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){
|
||||
** file should be closed and deleted. If this connection writes to
|
||||
** the database file, it will do so using an in-memory journal.
|
||||
*/
|
||||
int bDelete = (!pPager->tempFile && sqlite3JournalExists(pPager->jfd));
|
||||
assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE
|
||||
|| pPager->journalMode==PAGER_JOURNALMODE_MEMORY
|
||||
|| pPager->journalMode==PAGER_JOURNALMODE_WAL
|
||||
);
|
||||
sqlite3OsClose(pPager->jfd);
|
||||
if( !pPager->tempFile ){
|
||||
if( bDelete ){
|
||||
rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
|
||||
}
|
||||
}
|
||||
@@ -1976,7 +1979,17 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){
|
||||
*/
|
||||
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))
|
||||
){
|
||||
@@ -2015,7 +2028,7 @@ static void pagerUnlockAndRollback(Pager *pPager){
|
||||
sqlite3EndBenignMalloc();
|
||||
}else if( !pPager->exclusiveMode ){
|
||||
assert( pPager->eState==PAGER_READER );
|
||||
pager_end_transaction(pPager, 0);
|
||||
pager_end_transaction(pPager, 0, 0);
|
||||
}
|
||||
}
|
||||
pager_unlock(pPager);
|
||||
@@ -2790,7 +2803,7 @@ end_playback:
|
||||
rc = sqlite3PagerSync(pPager);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = pager_end_transaction(pPager, zMaster[0]!='\0');
|
||||
rc = pager_end_transaction(pPager, zMaster[0]!='\0', 0);
|
||||
testcase( rc!=SQLITE_OK );
|
||||
}
|
||||
if( rc==SQLITE_OK && zMaster[0] && res ){
|
||||
@@ -3485,7 +3498,7 @@ void sqlite3PagerSetBusyhandler(
|
||||
void **ap = (void **)&pPager->xBusyHandler;
|
||||
assert( ((int(*)(void *))(ap[0]))==xBusyHandler );
|
||||
assert( ap[1]==pBusyHandlerArg );
|
||||
sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_BUSYHANDLER, (void *)ap);
|
||||
sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_BUSYHANDLER, (void *)ap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3742,12 +3755,26 @@ static void assertTruncateConstraint(Pager *pPager){
|
||||
** 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;
|
||||
assertTruncateConstraint(pPager);
|
||||
|
||||
/* 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. */
|
||||
}
|
||||
|
||||
|
||||
@@ -4800,6 +4827,11 @@ int sqlite3PagerSharedLock(Pager *pPager){
|
||||
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
|
||||
@@ -5884,36 +5916,6 @@ int sqlite3PagerCommitPhaseOne(
|
||||
#endif
|
||||
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
|
||||
|
||||
/* If this transaction has made the database smaller, then all pages
|
||||
** being discarded by the truncation must be written to the journal
|
||||
** file.
|
||||
**
|
||||
** Before reading the pages with page numbers larger than the
|
||||
** current value of Pager.dbSize, set dbSize back to the value
|
||||
** that it took at the start of the transaction. Otherwise, the
|
||||
** calls to sqlite3PagerGet() return zeroed pages instead of
|
||||
** reading data from the database file.
|
||||
*/
|
||||
if( pPager->dbSize<pPager->dbOrigSize
|
||||
&& pPager->journalMode!=PAGER_JOURNALMODE_OFF
|
||||
){
|
||||
Pgno i; /* Iterator variable */
|
||||
const Pgno iSkip = PAGER_MJ_PGNO(pPager); /* Pending lock page */
|
||||
const Pgno dbSize = pPager->dbSize; /* Database image size */
|
||||
pPager->dbSize = pPager->dbOrigSize;
|
||||
for( i=dbSize+1; i<=pPager->dbOrigSize; i++ ){
|
||||
if( !sqlite3BitvecTest(pPager->pInJournal, i) && i!=iSkip ){
|
||||
PgHdr *pPage; /* Page to journal */
|
||||
rc = sqlite3PagerGet(pPager, i, &pPage);
|
||||
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
|
||||
rc = sqlite3PagerWrite(pPage);
|
||||
sqlite3PagerUnref(pPage);
|
||||
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
|
||||
}
|
||||
}
|
||||
pPager->dbSize = dbSize;
|
||||
}
|
||||
|
||||
/* 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.
|
||||
@@ -5941,11 +5943,14 @@ int sqlite3PagerCommitPhaseOne(
|
||||
goto commit_phase_one_exit;
|
||||
}
|
||||
sqlite3PcacheCleanAll(pPager->pPCache);
|
||||
|
||||
/* If the file on disk is not the same size as the database image,
|
||||
** then use pager_truncate to grow or shrink the file here.
|
||||
*/
|
||||
if( pPager->dbSize!=pPager->dbFileSize ){
|
||||
|
||||
/* 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);
|
||||
@@ -6018,7 +6023,7 @@ int sqlite3PagerCommitPhaseTwo(Pager *pPager){
|
||||
}
|
||||
|
||||
PAGERTRACE(("COMMIT %d\n", PAGERID(pPager)));
|
||||
rc = pager_end_transaction(pPager, pPager->setMaster);
|
||||
rc = pager_end_transaction(pPager, pPager->setMaster, 1);
|
||||
return pager_error(pPager, rc);
|
||||
}
|
||||
|
||||
@@ -6063,11 +6068,11 @@ int sqlite3PagerRollback(Pager *pPager){
|
||||
if( pagerUseWal(pPager) ){
|
||||
int rc2;
|
||||
rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, -1);
|
||||
rc2 = pager_end_transaction(pPager, pPager->setMaster);
|
||||
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);
|
||||
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.
|
||||
@@ -6465,7 +6470,8 @@ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
|
||||
*/
|
||||
if( (pPg->flags&PGHDR_NEED_SYNC) && !isCommit ){
|
||||
needSyncPgno = pPg->pgno;
|
||||
assert( pageInJournal(pPg) || pPg->pgno>pPager->dbOrigSize );
|
||||
assert( pPager->journalMode==PAGER_JOURNALMODE_OFF ||
|
||||
pageInJournal(pPg) || pPg->pgno>pPager->dbOrigSize );
|
||||
assert( pPg->flags&PGHDR_DIRTY );
|
||||
}
|
||||
|
||||
|
||||
+22
-29
@@ -435,8 +435,8 @@ oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y)
|
||||
// The "distinct" nonterminal is true (1) if the DISTINCT keyword is
|
||||
// present and false (0) if it is not.
|
||||
//
|
||||
%type distinct {int}
|
||||
distinct(A) ::= DISTINCT. {A = 1;}
|
||||
%type distinct {u16}
|
||||
distinct(A) ::= DISTINCT. {A = SF_Distinct;}
|
||||
distinct(A) ::= ALL. {A = 0;}
|
||||
distinct(A) ::= . {A = 0;}
|
||||
|
||||
@@ -499,7 +499,8 @@ stl_prefix(A) ::= seltablist(X) joinop(Y). {
|
||||
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). {
|
||||
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);
|
||||
}
|
||||
@@ -512,25 +513,23 @@ seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) indexed_opt(I) on_opt(N) usi
|
||||
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,0,0,0);
|
||||
pSubquery = sqlite3SelectNew(pParse,0,F,0,0,0,0,SF_NestedFrom,0,0);
|
||||
A = sqlite3SrcListAppendFromTerm(pParse,X,0,0,&Z,pSubquery,N,U);
|
||||
}
|
||||
}
|
||||
|
||||
// A seltablist_paren nonterminal represents anything in a FROM that
|
||||
// is contained inside parentheses. This can be either a subquery or
|
||||
// a grouping of table and subqueries.
|
||||
//
|
||||
// %type seltablist_paren {Select*}
|
||||
// %destructor seltablist_paren {sqlite3SelectDelete(pParse->db, $$);}
|
||||
// seltablist_paren(A) ::= select(S). {A = S;}
|
||||
// seltablist_paren(A) ::= seltablist(F). {
|
||||
// sqlite3SrcListShiftJoinType(F);
|
||||
// A = sqlite3SelectNew(pParse,0,F,0,0,0,0,0,0,0);
|
||||
// }
|
||||
%endif SQLITE_OMIT_SUBQUERY
|
||||
|
||||
%type dbnm {Token}
|
||||
@@ -653,7 +652,8 @@ 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). {
|
||||
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");
|
||||
@@ -661,7 +661,8 @@ cmd ::= UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y) where_opt(W)
|
||||
}
|
||||
%endif
|
||||
%ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
||||
cmd ::= UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y) where_opt(W). {
|
||||
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);
|
||||
@@ -815,7 +816,7 @@ expr(A) ::= VARIABLE(X). {
|
||||
spanSet(&A, &X, &X);
|
||||
}
|
||||
expr(A) ::= expr(E) COLLATE ids(C). {
|
||||
A.pExpr = sqlite3ExprSetCollByToken(pParse, E.pExpr, &C);
|
||||
A.pExpr = sqlite3ExprAddCollateToken(pParse, E.pExpr, &C);
|
||||
A.zStart = E.zStart;
|
||||
A.zEnd = &C.z[C.n];
|
||||
}
|
||||
@@ -1140,22 +1141,14 @@ uniqueflag(A) ::= . {A = OE_None;}
|
||||
idxlist_opt(A) ::= . {A = 0;}
|
||||
idxlist_opt(A) ::= LP idxlist(X) RP. {A = X;}
|
||||
idxlist(A) ::= idxlist(X) COMMA nm(Y) collate(C) sortorder(Z). {
|
||||
Expr *p = 0;
|
||||
if( C.n>0 ){
|
||||
p = sqlite3Expr(pParse->db, TK_COLUMN, 0);
|
||||
sqlite3ExprSetCollByToken(pParse, p, &C);
|
||||
}
|
||||
Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &C);
|
||||
A = sqlite3ExprListAppend(pParse,X, p);
|
||||
sqlite3ExprListSetName(pParse,A,&Y,1);
|
||||
sqlite3ExprListCheckLength(pParse, A, "index");
|
||||
if( A ) A->a[A->nExpr-1].sortOrder = (u8)Z;
|
||||
}
|
||||
idxlist(A) ::= nm(Y) collate(C) sortorder(Z). {
|
||||
Expr *p = 0;
|
||||
if( C.n>0 ){
|
||||
p = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0);
|
||||
sqlite3ExprSetCollByToken(pParse, p, &C);
|
||||
}
|
||||
Expr *p = sqlite3ExprAddCollateToken(pParse, 0, &C);
|
||||
A = sqlite3ExprListAppend(pParse,0, p);
|
||||
sqlite3ExprListSetName(pParse, A, &Y, 1);
|
||||
sqlite3ExprListCheckLength(pParse, A, "index");
|
||||
|
||||
+135
-4
@@ -184,6 +184,9 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
|
||||
{ "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 },
|
||||
@@ -948,11 +951,14 @@ void sqlite3Pragma(
|
||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||
pTab = sqlite3FindTable(db, zRight, zDb);
|
||||
if( pTab ){
|
||||
int i;
|
||||
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);
|
||||
@@ -975,8 +981,14 @@ void sqlite3Pragma(
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, 5);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Integer,
|
||||
(pCol->colFlags&COLFLAG_PRIMKEY)!=0, 6);
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -992,6 +1004,7 @@ void sqlite3Pragma(
|
||||
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);
|
||||
@@ -1018,6 +1031,7 @@ void sqlite3Pragma(
|
||||
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);
|
||||
@@ -1081,6 +1095,7 @@ void sqlite3Pragma(
|
||||
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);
|
||||
@@ -1114,6 +1129,122 @@ void sqlite3Pragma(
|
||||
}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 ){
|
||||
@@ -1611,7 +1742,7 @@ void sqlite3Pragma(
|
||||
}else
|
||||
#endif
|
||||
#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
|
||||
if( sqlite3StrICmp(zLeft, "activate_extensions")==0 ){
|
||||
if( sqlite3StrICmp(zLeft, "activate_extensions")==0 && zRight ){
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
if( sqlite3StrNICmp(zRight, "see-", 4)==0 ){
|
||||
sqlite3_activate_see(&zRight[4]);
|
||||
|
||||
@@ -259,11 +259,15 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
||||
*/
|
||||
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) ){
|
||||
|
||||
+125
-65
@@ -68,6 +68,15 @@ static void incrAggFunctionDepth(Expr *pExpr, int N){
|
||||
** from the result in the result-set. We might fix this someday. Or
|
||||
** then again, we might not...
|
||||
**
|
||||
** If the reference is followed by a COLLATE operator, then make sure
|
||||
** the COLLATE operator is preserved. For example:
|
||||
**
|
||||
** SELECT a+b, c+d FROM t1 ORDER BY 1 COLLATE nocase;
|
||||
**
|
||||
** Should be transformed into:
|
||||
**
|
||||
** SELECT a+b, c+d FROM t1 ORDER BY (a+b) COLLATE nocase;
|
||||
**
|
||||
** The nSubquery parameter specifies how many levels of subquery the
|
||||
** alias is removed from the original expression. The usually value is
|
||||
** zero but it might be more if the alias is contained within a subquery
|
||||
@@ -91,8 +100,9 @@ static void resolveAlias(
|
||||
assert( pOrig!=0 );
|
||||
assert( pOrig->flags & EP_Resolved );
|
||||
db = pParse->db;
|
||||
pDup = sqlite3ExprDup(db, pOrig, 0);
|
||||
if( pDup==0 ) return;
|
||||
if( pOrig->op!=TK_COLUMN && zType[0]!='G' ){
|
||||
pDup = sqlite3ExprDup(db, pOrig, 0);
|
||||
incrAggFunctionDepth(pDup, nSubquery);
|
||||
pDup = sqlite3PExpr(pParse, TK_AS, pDup, 0, 0);
|
||||
if( pDup==0 ) return;
|
||||
@@ -100,32 +110,26 @@ static void resolveAlias(
|
||||
pEList->a[iCol].iAlias = (u16)(++pParse->nAlias);
|
||||
}
|
||||
pDup->iTable = pEList->a[iCol].iAlias;
|
||||
}else if( ExprHasProperty(pOrig, EP_IntValue) || pOrig->u.zToken==0 ){
|
||||
pDup = sqlite3ExprDup(db, pOrig, 0);
|
||||
if( pDup==0 ) return;
|
||||
}else{
|
||||
char *zToken = pOrig->u.zToken;
|
||||
assert( zToken!=0 );
|
||||
pOrig->u.zToken = 0;
|
||||
pDup = sqlite3ExprDup(db, pOrig, 0);
|
||||
pOrig->u.zToken = zToken;
|
||||
if( pDup==0 ) return;
|
||||
assert( (pDup->flags & (EP_Reduced|EP_TokenOnly))==0 );
|
||||
pDup->flags2 |= EP2_MallocedToken;
|
||||
pDup->u.zToken = sqlite3DbStrDup(db, zToken);
|
||||
}
|
||||
if( pExpr->flags & EP_ExpCollate ){
|
||||
pDup->pColl = pExpr->pColl;
|
||||
pDup->flags |= EP_ExpCollate;
|
||||
if( pExpr->op==TK_COLLATE ){
|
||||
pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken);
|
||||
}
|
||||
|
||||
/* Before calling sqlite3ExprDelete(), set the EP_Static flag. This
|
||||
** prevents ExprDelete() from deleting the Expr structure itself,
|
||||
** allowing it to be repopulated by the memcpy() on the following line.
|
||||
** The pExpr->u.zToken might point into memory that will be freed by the
|
||||
** sqlite3DbFree(db, pDup) on the last line of this block, so be sure to
|
||||
** make a copy of the token before doing the sqlite3DbFree().
|
||||
*/
|
||||
ExprSetProperty(pExpr, EP_Static);
|
||||
sqlite3ExprDelete(db, pExpr);
|
||||
memcpy(pExpr, pDup, sizeof(*pExpr));
|
||||
if( !ExprHasProperty(pExpr, EP_IntValue) && pExpr->u.zToken!=0 ){
|
||||
assert( (pExpr->flags & (EP_Reduced|EP_TokenOnly))==0 );
|
||||
pExpr->u.zToken = sqlite3DbStrDup(db, pExpr->u.zToken);
|
||||
pExpr->flags2 |= EP2_MallocedToken;
|
||||
}
|
||||
sqlite3DbFree(db, pDup);
|
||||
}
|
||||
|
||||
@@ -146,6 +150,35 @@ static int nameInUsingClause(IdList *pUsing, const char *zCol){
|
||||
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
|
||||
@@ -202,6 +235,20 @@ static int lookupName(
|
||||
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;
|
||||
@@ -210,31 +257,36 @@ static int lookupName(
|
||||
if( pSrcList ){
|
||||
for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
|
||||
Table *pTab;
|
||||
int iDb;
|
||||
Column *pCol;
|
||||
|
||||
pTab = pItem->pTab;
|
||||
assert( pTab!=0 && pTab->zName!=0 );
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
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 ){
|
||||
if( pItem->zAlias ){
|
||||
char *zTabName = pItem->zAlias;
|
||||
if( sqlite3StrICmp(zTabName, zTab)!=0 ) continue;
|
||||
}else{
|
||||
char *zTabName = pTab->zName;
|
||||
if( NEVER(zTabName==0) || sqlite3StrICmp(zTabName, zTab)!=0 ){
|
||||
continue;
|
||||
}
|
||||
if( zDb!=0 && sqlite3StrICmp(db->aDb[iDb].zName, zDb)!=0 ){
|
||||
continue;
|
||||
}
|
||||
const char *zTabName = pItem->zAlias ? pItem->zAlias : pTab->zName;
|
||||
assert( zTabName!=0 );
|
||||
if( sqlite3StrICmp(zTabName, zTab)!=0 ){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if( 0==(cntTab++) ){
|
||||
pExpr->iTable = pItem->iCursor;
|
||||
pExpr->pTab = pTab;
|
||||
pSchema = pTab->pSchema;
|
||||
pMatch = pItem;
|
||||
}
|
||||
for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
|
||||
@@ -248,17 +300,19 @@ static int lookupName(
|
||||
if( nameInUsingClause(pItem->pUsing, zCol) ) continue;
|
||||
}
|
||||
cnt++;
|
||||
pExpr->iTable = pItem->iCursor;
|
||||
pExpr->pTab = pTab;
|
||||
pMatch = pItem;
|
||||
pSchema = pTab->pSchema;
|
||||
/* 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
|
||||
@@ -593,7 +647,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
|
||||
pNC->nErr++;
|
||||
is_agg = 0;
|
||||
}else if( no_such_func ){
|
||||
}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 ){
|
||||
@@ -812,7 +866,7 @@ static int resolveCompoundOrderBy(
|
||||
int iCol = -1;
|
||||
Expr *pE, *pDup;
|
||||
if( pItem->done ) continue;
|
||||
pE = pItem->pExpr;
|
||||
pE = sqlite3ExprSkipCollate(pItem->pExpr);
|
||||
if( sqlite3ExprIsInteger(pE, &iCol) ){
|
||||
if( iCol<=0 || iCol>pEList->nExpr ){
|
||||
resolveOutOfRangeError(pParse, "ORDER", i+1, pEList->nExpr);
|
||||
@@ -830,14 +884,20 @@ static int resolveCompoundOrderBy(
|
||||
}
|
||||
}
|
||||
if( iCol>0 ){
|
||||
CollSeq *pColl = pE->pColl;
|
||||
int flags = pE->flags & EP_ExpCollate;
|
||||
/* Convert the ORDER BY term into an integer column number iCol,
|
||||
** taking care to preserve the COLLATE clause if it exists */
|
||||
Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0);
|
||||
if( pNew==0 ) return 1;
|
||||
pNew->flags |= EP_IntValue;
|
||||
pNew->u.iValue = iCol;
|
||||
if( pItem->pExpr==pE ){
|
||||
pItem->pExpr = pNew;
|
||||
}else{
|
||||
assert( pItem->pExpr->op==TK_COLLATE );
|
||||
assert( pItem->pExpr->pLeft==pE );
|
||||
pItem->pExpr->pLeft = pNew;
|
||||
}
|
||||
sqlite3ExprDelete(db, pE);
|
||||
pItem->pExpr = pE = sqlite3Expr(db, TK_INTEGER, 0);
|
||||
if( pE==0 ) return 1;
|
||||
pE->pColl = pColl;
|
||||
pE->flags |= EP_IntValue | flags;
|
||||
pE->u.iValue = iCol;
|
||||
pItem->iOrderByCol = (u16)iCol;
|
||||
pItem->done = 1;
|
||||
}else{
|
||||
@@ -942,11 +1002,11 @@ static int resolveOrderGroupBy(
|
||||
pItem->iOrderByCol = (u16)iCol;
|
||||
continue;
|
||||
}
|
||||
if( sqlite3ExprIsInteger(pE, &iCol) ){
|
||||
if( sqlite3ExprIsInteger(sqlite3ExprSkipCollate(pE), &iCol) ){
|
||||
/* The ORDER BY term is an integer constant. Again, set the column
|
||||
** number so that sqlite3ResolveOrderGroupBy() will convert the
|
||||
** order-by term to a copy of the result-set expression */
|
||||
if( iCol<1 ){
|
||||
if( iCol<1 || iCol>0xffff ){
|
||||
resolveOutOfRangeError(pParse, zType, i+1, nResult);
|
||||
return 1;
|
||||
}
|
||||
@@ -1023,23 +1083,6 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
||||
return WRC_Abort;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Recursively resolve names in all subqueries
|
||||
*/
|
||||
for(i=0; i<p->pSrc->nSrc; i++){
|
||||
@@ -1067,6 +1110,23 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
||||
}
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
+132
-60
@@ -55,7 +55,7 @@ Select *sqlite3SelectNew(
|
||||
ExprList *pGroupBy, /* the GROUP BY clause */
|
||||
Expr *pHaving, /* the HAVING clause */
|
||||
ExprList *pOrderBy, /* the ORDER BY clause */
|
||||
int isDistinct, /* true if the DISTINCT keyword is present */
|
||||
u16 selFlags, /* Flag parameters, such as SF_Distinct */
|
||||
Expr *pLimit, /* LIMIT value. NULL means not used */
|
||||
Expr *pOffset /* OFFSET value. NULL means no offset */
|
||||
){
|
||||
@@ -79,7 +79,7 @@ Select *sqlite3SelectNew(
|
||||
pNew->pGroupBy = pGroupBy;
|
||||
pNew->pHaving = pHaving;
|
||||
pNew->pOrderBy = pOrderBy;
|
||||
pNew->selFlags = isDistinct ? SF_Distinct : 0;
|
||||
pNew->selFlags = selFlags;
|
||||
pNew->op = TK_SELECT;
|
||||
pNew->pLimit = pLimit;
|
||||
pNew->pOffset = pOffset;
|
||||
@@ -1335,9 +1335,7 @@ static int selectColumnsFromExprList(
|
||||
for(i=0, pCol=aCol; i<nCol; i++, pCol++){
|
||||
/* Get an appropriate name for the column
|
||||
*/
|
||||
p = pEList->a[i].pExpr;
|
||||
assert( p->pRight==0 || ExprHasProperty(p->pRight, EP_IntValue)
|
||||
|| p->pRight->u.zToken==0 || p->pRight->u.zToken[0]!=0 );
|
||||
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);
|
||||
@@ -1375,6 +1373,9 @@ static int selectColumnsFromExprList(
|
||||
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);
|
||||
@@ -1706,6 +1707,8 @@ static int multiSelect(
|
||||
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);
|
||||
@@ -2333,12 +2336,13 @@ static int multiSelectOrderBy(
|
||||
for(i=0; i<nOrderBy; i++){
|
||||
CollSeq *pColl;
|
||||
Expr *pTerm = pOrderBy->a[i].pExpr;
|
||||
if( pTerm->flags & EP_ExpCollate ){
|
||||
pColl = pTerm->pColl;
|
||||
if( pTerm->flags & EP_Collate ){
|
||||
pColl = sqlite3ExprCollSeq(pParse, pTerm);
|
||||
}else{
|
||||
pColl = multiSelectCollSeq(pParse, p, aPermute[i]);
|
||||
pTerm->flags |= EP_ExpCollate;
|
||||
pTerm->pColl = pColl;
|
||||
if( pColl==0 ) pColl = db->pDfltColl;
|
||||
pOrderBy->a[i].pExpr =
|
||||
sqlite3ExprAddCollateString(pParse, pTerm, pColl->zName);
|
||||
}
|
||||
pKeyMerge->aColl[i] = pColl;
|
||||
pKeyMerge->aSortOrder[i] = pOrderBy->a[i].sortOrder;
|
||||
@@ -2362,7 +2366,8 @@ static int multiSelectOrderBy(
|
||||
}else{
|
||||
int nExpr = p->pEList->nExpr;
|
||||
assert( nOrderBy>=nExpr || db->mallocFailed );
|
||||
regPrev = sqlite3GetTempRange(pParse, nExpr+1);
|
||||
regPrev = pParse->nMem+1;
|
||||
pParse->nMem += nExpr+1;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regPrev);
|
||||
pKeyDup = sqlite3DbMallocZero(db,
|
||||
sizeof(*pKeyDup) + nExpr*(sizeof(CollSeq*)+1) );
|
||||
@@ -2541,14 +2546,9 @@ static int multiSelectOrderBy(
|
||||
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);
|
||||
|
||||
/* Release temporary registers
|
||||
*/
|
||||
if( regPrev ){
|
||||
sqlite3ReleaseTempRange(pParse, regPrev, nOrderBy+1);
|
||||
}
|
||||
|
||||
/* Jump to the this point in order to terminate the query.
|
||||
*/
|
||||
sqlite3VdbeResolveLabel(v, labelEnd);
|
||||
@@ -2608,9 +2608,6 @@ static Expr *substExpr(
|
||||
assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );
|
||||
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
|
||||
pNew = sqlite3ExprDup(db, pEList->a[pExpr->iColumn].pExpr, 0);
|
||||
if( pNew && pExpr->pColl ){
|
||||
pNew->pColl = pExpr->pColl;
|
||||
}
|
||||
sqlite3ExprDelete(db, pExpr);
|
||||
pExpr = pNew;
|
||||
}
|
||||
@@ -2963,12 +2960,15 @@ static int flattenSubquery(
|
||||
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;
|
||||
@@ -3161,34 +3161,43 @@ static int flattenSubquery(
|
||||
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
|
||||
|
||||
/*
|
||||
** Analyze the SELECT statement passed as an argument to see if it
|
||||
** is a min() or max() query. Return WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX if
|
||||
** it is, or 0 otherwise. At present, a query is considered to be
|
||||
** a min()/max() query if:
|
||||
** Based on the contents of the AggInfo structure indicated by the first
|
||||
** argument, this function checks if the following are true:
|
||||
**
|
||||
** 1. There is a single object in the FROM clause.
|
||||
** * 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.
|
||||
**
|
||||
** 2. There is a single expression in the result set, and it is
|
||||
** either min(x) or max(x), where x is a column reference.
|
||||
** 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(Select *p){
|
||||
Expr *pExpr;
|
||||
ExprList *pEList = p->pEList;
|
||||
static u8 minMaxQuery(AggInfo *pAggInfo, ExprList **ppMinMax){
|
||||
int eRet = WHERE_ORDERBY_NORMAL; /* Return value */
|
||||
|
||||
if( pEList->nExpr!=1 ) return WHERE_ORDERBY_NORMAL;
|
||||
pExpr = pEList->a[0].pExpr;
|
||||
if( pExpr->op!=TK_AGG_FUNCTION ) return 0;
|
||||
if( NEVER(ExprHasProperty(pExpr, EP_xIsSelect)) ) return 0;
|
||||
pEList = pExpr->x.pList;
|
||||
if( pEList==0 || pEList->nExpr!=1 ) return 0;
|
||||
if( pEList->a[0].pExpr->op!=TK_AGG_COLUMN ) return WHERE_ORDERBY_NORMAL;
|
||||
assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
||||
if( sqlite3StrICmp(pExpr->u.zToken,"min")==0 ){
|
||||
return WHERE_ORDERBY_MIN;
|
||||
}else if( sqlite3StrICmp(pExpr->u.zToken,"max")==0 ){
|
||||
return WHERE_ORDERBY_MAX;
|
||||
*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;
|
||||
}
|
||||
}
|
||||
}
|
||||
return WHERE_ORDERBY_NORMAL;
|
||||
|
||||
assert( *ppMinMax==0 || (*ppMinMax)->nExpr==1 );
|
||||
return eRet;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3283,14 +3292,16 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
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) || (p->selFlags & SF_Expanded)!=0 ){
|
||||
if( NEVER(p->pSrc==0) || (selFlags & SF_Expanded)!=0 ){
|
||||
return WRC_Prune;
|
||||
}
|
||||
p->selFlags |= SF_Expanded;
|
||||
pTabList = p->pSrc;
|
||||
pEList = p->pEList;
|
||||
|
||||
@@ -3333,6 +3344,12 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
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) ){
|
||||
@@ -3368,7 +3385,7 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
** that need expanding.
|
||||
*/
|
||||
for(k=0; k<pEList->nExpr; k++){
|
||||
Expr *pE = pEList->a[k].pExpr;
|
||||
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) );
|
||||
@@ -3386,10 +3403,18 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
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++){
|
||||
Expr *pE = a[k].pExpr;
|
||||
assert( pE->op!=TK_DOT || pE->pRight!=0 );
|
||||
if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pE->pRight->op!=TK_ALL) ){
|
||||
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);
|
||||
@@ -3404,32 +3429,43 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
/* This expression is a "*" or a "TABLE.*" and needs to be
|
||||
** expanded. */
|
||||
int tableSeen = 0; /* Set to 1 when TABLE matches */
|
||||
char *zTName; /* text of name of TABLE */
|
||||
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;
|
||||
}else{
|
||||
zTName = 0;
|
||||
}
|
||||
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( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){
|
||||
continue;
|
||||
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 : "*";
|
||||
}
|
||||
tableSeen = 1;
|
||||
for(j=0; j<pTab->nCol; j++){
|
||||
Expr *pExpr, *pRight;
|
||||
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.
|
||||
@@ -3438,6 +3474,7 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
assert(IsVirtual(pTab));
|
||||
continue;
|
||||
}
|
||||
tableSeen = 1;
|
||||
|
||||
if( i>0 && zTName==0 ){
|
||||
if( (pFrom->jointype & JT_NATURAL)!=0
|
||||
@@ -3460,6 +3497,10 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
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;
|
||||
@@ -3471,6 +3512,18 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -3609,6 +3662,7 @@ void sqlite3SelectPrep(
|
||||
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;
|
||||
@@ -3950,6 +4004,15 @@ int sqlite3Select(
|
||||
int addrEof;
|
||||
pItem->regReturn = ++pParse->nMem;
|
||||
addrEof = ++pParse->nMem;
|
||||
/* Before coding the OP_Goto to jump to the start of the main routine,
|
||||
** ensure that the jump to the verify-schema routine has already
|
||||
** been coded. Otherwise, the verify-schema would likely be coded as
|
||||
** part of the co-routine. If the main routine then accessed the
|
||||
** database before invoking the co-routine for the first time (for
|
||||
** example to initialize a LIMIT register from a sub-select), it would
|
||||
** be doing so without having verified the schema version and obtained
|
||||
** the required db locks. See ticket d6b36be38. */
|
||||
sqlite3CodeVerifySchema(pParse, -1);
|
||||
sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
addrTop = sqlite3VdbeAddOp1(v, OP_OpenPseudo, pItem->iCursor);
|
||||
sqlite3VdbeChangeP5(v, 1);
|
||||
@@ -4519,11 +4582,17 @@ int sqlite3Select(
|
||||
** Refer to code and comments in where.c for details.
|
||||
*/
|
||||
ExprList *pMinMax = 0;
|
||||
u8 flag = minMaxQuery(p);
|
||||
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 ){
|
||||
assert( !ExprHasProperty(p->pEList->a[0].pExpr, EP_xIsSelect) );
|
||||
assert( p->pEList->a[0].pExpr->x.pList->nExpr==1 );
|
||||
pMinMax = sqlite3ExprListDup(db, p->pEList->a[0].pExpr->x.pList,0);
|
||||
pMinMax = sqlite3ExprListDup(db, pMinMax, 0);
|
||||
pDel = pMinMax;
|
||||
if( pMinMax && !db->mallocFailed ){
|
||||
pMinMax->a[0].sortOrder = flag!=WHERE_ORDERBY_MIN ?1:0;
|
||||
@@ -4679,7 +4748,10 @@ void sqlite3ExplainSelect(Vdbe *pVdbe, Select *p){
|
||||
sqlite3ExplainPrintf(pVdbe, "(null-select)");
|
||||
return;
|
||||
}
|
||||
while( p->pPrior ) p = p->pPrior;
|
||||
while( p->pPrior ){
|
||||
p->pPrior->pNext = p;
|
||||
p = p->pPrior;
|
||||
}
|
||||
sqlite3ExplainPush(pVdbe);
|
||||
while( p ){
|
||||
explainOneSelect(pVdbe, p);
|
||||
|
||||
+61
-20
@@ -90,7 +90,8 @@ static int enableTimer = 0;
|
||||
#define IsDigit(X) isdigit((unsigned char)X)
|
||||
#define ToLower(X) (char)tolower((unsigned char)X)
|
||||
|
||||
#if !defined(_WIN32) && !defined(WIN32) && !defined(_WRS_KERNEL)
|
||||
#if !defined(_WIN32) && !defined(WIN32) && !defined(_WRS_KERNEL) \
|
||||
&& !defined(__minux)
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
@@ -1479,6 +1480,18 @@ static void open_db(struct callback_data *p){
|
||||
}
|
||||
#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
|
||||
}
|
||||
}
|
||||
@@ -1525,17 +1538,18 @@ static void resolve_backslashes(char *z){
|
||||
** Interpret zArg as a boolean value. Return either 0 or 1.
|
||||
*/
|
||||
static int booleanValue(char *zArg){
|
||||
int val = atoi(zArg);
|
||||
int j;
|
||||
for(j=0; zArg[j]; j++){
|
||||
zArg[j] = ToLower(zArg[j]);
|
||||
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( strcmp(zArg,"on")==0 ){
|
||||
val = 1;
|
||||
}else if( strcmp(zArg,"yes")==0 ){
|
||||
val = 1;
|
||||
if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){
|
||||
return 0;
|
||||
}
|
||||
return val;
|
||||
fprintf(stderr, "ERROR: Not a boolean value: \"%s\". Assuming \"no\".\n",
|
||||
zArg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1623,24 +1637,50 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
if( nArg==0 ) return 0; /* no tokens, no error */
|
||||
n = strlen30(azArg[0]);
|
||||
c = azArg[0][0];
|
||||
if( c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0 && nArg>1 && nArg<4){
|
||||
const char *zDestFile;
|
||||
const char *zDb;
|
||||
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;
|
||||
if( nArg==2 ){
|
||||
zDestFile = azArg[1];
|
||||
zDb = "main";
|
||||
}else{
|
||||
zDestFile = azArg[2];
|
||||
zDb = azArg[1];
|
||||
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 ){
|
||||
@@ -1742,7 +1782,8 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
p->echoOn = booleanValue(azArg[1]);
|
||||
}else
|
||||
|
||||
if( c=='e' && strncmp(azArg[0], "exit", n)==0 && nArg==1 ){
|
||||
if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
|
||||
if( nArg>1 && (rc = atoi(azArg[1]))!=0 ) exit(rc);
|
||||
rc = 2;
|
||||
}else
|
||||
|
||||
|
||||
+22
-2
@@ -478,7 +478,17 @@ int sqlite3_exec(
|
||||
#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
|
||||
@@ -852,7 +862,6 @@ struct sqlite3_io_methods {
|
||||
** compilation of the PRAGMA fails with an error. ^The [SQLITE_FCNTL_PRAGMA]
|
||||
** file control occurs at the beginning of pragma statement analysis and so
|
||||
** it is able to override built-in [PRAGMA] statements.
|
||||
** </ul>
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_BUSYHANDLER]]
|
||||
** ^This file-control may be invoked by SQLite on the database file handle
|
||||
@@ -864,6 +873,16 @@ struct sqlite3_io_methods {
|
||||
** the array as the only argument. If it returns non-zero, then the operation
|
||||
** should be retried. If it returns zero, the custom VFS should abandon the
|
||||
** current operation.
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_TEMPFILENAME]]
|
||||
** ^Application can invoke this file-control to have SQLite generate a
|
||||
** temporary filename using the same algorithm that is followed to generate
|
||||
** temporary filenames for TEMP tables and other internal uses. The
|
||||
** argument should be a char** which will be filled with the filename
|
||||
** written into memory obtained from [sqlite3_malloc()]. The caller should
|
||||
** invoke [sqlite3_free()] on the result to avoid a memory leak.
|
||||
**
|
||||
** </ul>
|
||||
*/
|
||||
#define SQLITE_FCNTL_LOCKSTATE 1
|
||||
#define SQLITE_GET_LOCKPROXYFILE 2
|
||||
@@ -880,6 +899,7 @@ struct sqlite3_io_methods {
|
||||
#define SQLITE_FCNTL_POWERSAFE_OVERWRITE 13
|
||||
#define SQLITE_FCNTL_PRAGMA 14
|
||||
#define SQLITE_FCNTL_BUSYHANDLER 15
|
||||
#define SQLITE_FCNTL_TEMPFILENAME 16
|
||||
|
||||
/*
|
||||
** CAPI3REF: Mutex Handle
|
||||
@@ -1577,7 +1597,7 @@ struct sqlite3_mem_methods {
|
||||
** [SQLITE_USE_URI] symbol defined.
|
||||
**
|
||||
** [[SQLITE_CONFIG_COVERING_INDEX_SCAN]] <dt>SQLITE_CONFIG_COVERING_INDEX_SCAN
|
||||
** <dd> This option taks a single integer argument which is interpreted as
|
||||
** <dd> This option takes a single integer argument which is interpreted as
|
||||
** a boolean in order to enable or disable the use of covering indices for
|
||||
** full table scans in the query optimizer. The default setting is determined
|
||||
** by the [SQLITE_ALLOW_COVERING_INDEX_SCAN] compile-time option, or is "on"
|
||||
|
||||
@@ -236,6 +236,20 @@ struct sqlite3_api_routines {
|
||||
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*);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -439,6 +453,20 @@ struct sqlite3_api_routines {
|
||||
#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;
|
||||
|
||||
+60
-45
@@ -200,7 +200,8 @@
|
||||
**
|
||||
** See also ticket #2741.
|
||||
*/
|
||||
#if !defined(_XOPEN_SOURCE) && !defined(__DARWIN__) && !defined(__APPLE__) && SQLITE_THREADSAFE
|
||||
#if !defined(_XOPEN_SOURCE) && !defined(__DARWIN__) \
|
||||
&& !defined(__APPLE__) && SQLITE_THREADSAFE
|
||||
# define _XOPEN_SOURCE 500 /* Needed to enable pthread recursive mutexes */
|
||||
#endif
|
||||
|
||||
@@ -575,6 +576,11 @@ struct BusyHandler {
|
||||
*/
|
||||
#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
|
||||
@@ -944,7 +950,7 @@ struct sqlite3 {
|
||||
#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 */
|
||||
/* 0x00000200 Unused */
|
||||
#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 */
|
||||
@@ -973,6 +979,7 @@ struct sqlite3 {
|
||||
#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 */
|
||||
|
||||
/*
|
||||
@@ -1150,19 +1157,7 @@ struct Column {
|
||||
** structure. Conceptually, a collating sequence consists of a name and
|
||||
** a comparison routine that defines the order of that sequence.
|
||||
**
|
||||
** There may two separate implementations of the collation function, one
|
||||
** that processes text in UTF-8 encoding (CollSeq.xCmp) and another that
|
||||
** processes text encoded in UTF-16 (CollSeq.xCmp16), using the machine
|
||||
** native byte order. When a collation sequence is invoked, SQLite selects
|
||||
** the version that will require the least expensive encoding
|
||||
** translations, if any.
|
||||
**
|
||||
** The CollSeq.pUser member variable is an extra parameter that passed in
|
||||
** as the first argument to the UTF-8 comparison function, xCmp.
|
||||
** CollSeq.pUser16 is the equivalent for the UTF-16 comparison function,
|
||||
** xCmp16.
|
||||
**
|
||||
** If both CollSeq.xCmp and CollSeq.xCmp16 are NULL, it means that the
|
||||
** If CollSeq.xCmp is NULL, it means that the
|
||||
** collating sequence is undefined. Indices built on an undefined
|
||||
** collating sequence may not be read or written.
|
||||
*/
|
||||
@@ -1496,20 +1491,20 @@ struct UnpackedRecord {
|
||||
** element.
|
||||
*/
|
||||
struct Index {
|
||||
char *zName; /* Name of this index */
|
||||
int *aiColumn; /* Which columns are used by this index. 1st is 0 */
|
||||
tRowcnt *aiRowEst; /* Result of 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; /* Array of size Index.nColumn. True==DESC, False==ASC */
|
||||
char **azColl; /* Array of collation sequence names for index */
|
||||
int nColumn; /* Number of columns in the table used by this index */
|
||||
int tnum; /* Page containing root of this index in database file */
|
||||
u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
|
||||
u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */
|
||||
u8 bUnordered; /* Use this index for == or IN queries only */
|
||||
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 */
|
||||
@@ -1690,7 +1685,6 @@ struct Expr {
|
||||
ExprList *pList; /* Function arguments or in "<expr> IN (<expr-list)" */
|
||||
Select *pSelect; /* Used for sub-selects and "<expr> IN (<select>)" */
|
||||
} x;
|
||||
CollSeq *pColl; /* The collation type of the column or 0 */
|
||||
|
||||
/* If the EP_Reduced flag is set in the Expr.flags mask, then no
|
||||
** space is allocated for the fields below this point. An attempt to
|
||||
@@ -1726,7 +1720,7 @@ struct Expr {
|
||||
#define EP_VarSelect 0x0020 /* pSelect is correlated, not constant */
|
||||
#define EP_DblQuoted 0x0040 /* token.z was originally in "..." */
|
||||
#define EP_InfixFunc 0x0080 /* True for an infix function: LIKE, GLOB, etc */
|
||||
#define EP_ExpCollate 0x0100 /* Collating sequence specified explicitly */
|
||||
#define EP_Collate 0x0100 /* Tree contains a TK_COLLATE opeartor */
|
||||
#define EP_FixedDest 0x0200 /* Result needed in a specific register */
|
||||
#define EP_IntValue 0x0400 /* Integer value contained in u.iValue */
|
||||
#define EP_xIsSelect 0x0800 /* x.pSelect is valid (otherwise x.pList is) */
|
||||
@@ -1784,18 +1778,27 @@ struct Expr {
|
||||
** 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 */
|
||||
u8 done; /* A flag to indicate when processing is finished */
|
||||
u16 iOrderByCol; /* For ORDER BY, column number in result set */
|
||||
u16 iAlias; /* Index into Parse.aAlias[] for zName */
|
||||
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 */
|
||||
};
|
||||
|
||||
@@ -1963,6 +1966,7 @@ struct WhereLevel {
|
||||
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 */
|
||||
@@ -2115,6 +2119,7 @@ struct Select {
|
||||
#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 */
|
||||
|
||||
|
||||
/*
|
||||
@@ -2343,6 +2348,7 @@ struct AuthContext {
|
||||
#define OPFLAG_TYPEOFARG 0x80 /* OP_Column only used for typeof() */
|
||||
#define OPFLAG_BULKCSR 0x01 /* OP_Open** used to open bulk cursor */
|
||||
#define OPFLAG_P2ISREG 0x02 /* P2 to OP_Open** is a register number */
|
||||
#define OPFLAG_PERMUTE 0x01 /* OP_Compare: use the permutation */
|
||||
|
||||
/*
|
||||
* Each trigger present in the database schema is stored as an instance of
|
||||
@@ -2826,13 +2832,13 @@ Index *sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
|
||||
void sqlite3DropIndex(Parse*, SrcList*, int);
|
||||
int sqlite3Select(Parse*, Select*, SelectDest*);
|
||||
Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
|
||||
Expr*,ExprList*,int,Expr*,Expr*);
|
||||
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 *);
|
||||
Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,Expr*,char*);
|
||||
#endif
|
||||
void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
|
||||
void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
|
||||
@@ -2900,7 +2906,7 @@ int sqlite3OpenTableAndIndices(Parse*, Table*, int, int);
|
||||
void sqlite3BeginWriteOperation(Parse*, int, int);
|
||||
void sqlite3MultiWrite(Parse*);
|
||||
void sqlite3MayAbort(Parse*);
|
||||
void sqlite3HaltConstraint(Parse*, int, char*, int);
|
||||
void sqlite3HaltConstraint(Parse*, int, int, char*, int);
|
||||
Expr *sqlite3ExprDup(sqlite3*,Expr*,int);
|
||||
ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int);
|
||||
SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int);
|
||||
@@ -3013,8 +3019,11 @@ int sqlite3VarintLen(u64 v);
|
||||
** 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 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
|
||||
|
||||
@@ -3034,8 +3043,9 @@ int sqlite3ReadSchema(Parse *pParse);
|
||||
CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
|
||||
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);
|
||||
CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
|
||||
Expr *sqlite3ExprSetColl(Expr*, CollSeq*);
|
||||
Expr *sqlite3ExprSetCollByToken(Parse *pParse, Expr*, Token*);
|
||||
Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, Token*);
|
||||
Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*);
|
||||
Expr *sqlite3ExprSkipCollate(Expr*);
|
||||
int sqlite3CheckCollSeq(Parse *, CollSeq *);
|
||||
int sqlite3CheckObjectName(Parse *, const char *);
|
||||
void sqlite3VdbeSetChanges(sqlite3 *, int);
|
||||
@@ -3082,6 +3092,7 @@ 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*);
|
||||
@@ -3220,8 +3231,10 @@ const char *sqlite3JournalModename(int);
|
||||
#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
|
||||
|
||||
|
||||
@@ -3253,8 +3266,10 @@ int sqlite3FindInIndex(Parse *, Expr *, int*);
|
||||
int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
|
||||
int sqlite3JournalSize(sqlite3_vfs *);
|
||||
int sqlite3JournalCreate(sqlite3_file *);
|
||||
int sqlite3JournalExists(sqlite3_file *p);
|
||||
#else
|
||||
#define sqlite3JournalSize(pVfs) ((pVfs)->szOsFile)
|
||||
#define sqlite3JournalExists(p) 1
|
||||
#endif
|
||||
|
||||
void sqlite3MemJournalOpen(sqlite3_file *);
|
||||
|
||||
@@ -3671,6 +3671,7 @@ static void init_all(Tcl_Interp *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*);
|
||||
@@ -3684,6 +3685,7 @@ static void init_all(Tcl_Interp *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);
|
||||
@@ -3714,6 +3716,7 @@ static void init_all(Tcl_Interp *interp){
|
||||
Sqlitetest_mutex_Init(interp);
|
||||
Sqlitetestschema_Init(interp);
|
||||
Sqlitetesttclvar_Init(interp);
|
||||
Sqlitetestfs_Init(interp);
|
||||
SqlitetestThread_Init(interp);
|
||||
SqlitetestOnefile_Init(interp);
|
||||
SqlitetestOsinst_Init(interp);
|
||||
@@ -3727,6 +3730,7 @@ static void init_all(Tcl_Interp *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);
|
||||
|
||||
+46
-3
@@ -138,6 +138,18 @@ const char *sqlite3TestErrorName(int rc){
|
||||
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;
|
||||
@@ -166,6 +178,7 @@ const char *sqlite3TestErrorName(int rc){
|
||||
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;
|
||||
@@ -5321,6 +5334,38 @@ static int file_control_vfsname(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: file_control_tempfilename DB ?AUXDB?
|
||||
**
|
||||
** Return a string that is a temporary filename
|
||||
*/
|
||||
static int file_control_tempfilename(
|
||||
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
sqlite3 *db;
|
||||
const char *zDbName = "main";
|
||||
char *zTName = 0;
|
||||
|
||||
if( objc!=2 && objc!=3 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"",
|
||||
Tcl_GetStringFromObj(objv[0], 0), " DB ?AUXDB?", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( objc==3 ){
|
||||
zDbName = Tcl_GetString(objv[2]);
|
||||
}
|
||||
sqlite3_file_control(db, zDbName, SQLITE_FCNTL_TEMPFILENAME, (void*)&zTName);
|
||||
Tcl_AppendResult(interp, zTName, (char*)0);
|
||||
sqlite3_free(zTName);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite3_vfs_list
|
||||
@@ -6150,6 +6195,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "file_control_persist_wal", file_control_persist_wal, 0 },
|
||||
{ "file_control_powersafe_overwrite",file_control_powersafe_overwrite,0},
|
||||
{ "file_control_vfsname", file_control_vfsname, 0 },
|
||||
{ "file_control_tempfilename", file_control_tempfilename, 0 },
|
||||
{ "sqlite3_vfs_list", vfs_list, 0 },
|
||||
{ "sqlite3_create_function_v2", test_create_function_v2, 0 },
|
||||
|
||||
@@ -6203,7 +6249,6 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
#ifdef SQLITE_DEBUG
|
||||
extern int sqlite3WhereTrace;
|
||||
extern int sqlite3OSTrace;
|
||||
extern int sqlite3VdbeAddopTrace;
|
||||
extern int sqlite3WalTrace;
|
||||
#endif
|
||||
#ifdef SQLITE_TEST
|
||||
@@ -6266,8 +6311,6 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
(char*)&query_plan, TCL_LINK_STRING|TCL_LINK_READ_ONLY);
|
||||
#endif
|
||||
#ifdef SQLITE_DEBUG
|
||||
Tcl_LinkVar(interp, "sqlite_addop_trace",
|
||||
(char*)&sqlite3VdbeAddopTrace, TCL_LINK_INT);
|
||||
Tcl_LinkVar(interp, "sqlite_where_trace",
|
||||
(char*)&sqlite3WhereTrace, TCL_LINK_INT);
|
||||
Tcl_LinkVar(interp, "sqlite_os_trace",
|
||||
|
||||
+1
-1
@@ -1389,7 +1389,7 @@ static int register_spellfix_module(
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
|
||||
sqlite3Spellfix1Register(db);
|
||||
sqlite3_spellfix1_register(db);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
+333
@@ -0,0 +1,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;
|
||||
}
|
||||
+1
-1
@@ -720,8 +720,8 @@ static int test_memdebug_settitle(
|
||||
#ifdef SQLITE_MEMDEBUG
|
||||
{
|
||||
const char *zTitle;
|
||||
zTitle = Tcl_GetString(objv[1]);
|
||||
extern int sqlite3MemdebugSettitle(const char*);
|
||||
zTitle = Tcl_GetString(objv[1]);
|
||||
sqlite3MemdebugSettitle(zTitle);
|
||||
}
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -1295,7 +1295,7 @@ int sqlite3_quota_remove(const char *zFilename){
|
||||
if( pGroup ){
|
||||
for(pFile=pGroup->pFiles; pFile && rc==SQLITE_OK; pFile=pNextFile){
|
||||
pNextFile = pFile->pNext;
|
||||
diff = memcmp(zFull, pFile->zFilename, nFull);
|
||||
diff = strncmp(zFull, pFile->zFilename, nFull);
|
||||
if( diff==0 && ((c = pFile->zFilename[nFull])==0 || c=='/' || c=='\\') ){
|
||||
if( pFile->nRef ){
|
||||
pFile->deleteOnClose = 1;
|
||||
|
||||
@@ -0,0 +1,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 *******************************/
|
||||
+25
-8
@@ -21,6 +21,11 @@
|
||||
# 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>
|
||||
@@ -739,22 +744,22 @@ static int utf8Len(unsigned char c, int N){
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE (non-zero) of the To side of the given cost matches
|
||||
** 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( memcmp(p->a+p->nFrom, z, p->nTo)!=0 ) return 0;
|
||||
if( strncmp(p->a+p->nFrom, z, p->nTo)!=0 ) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE (non-zero) of the To side of the given cost matches
|
||||
** 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( memcmp(p->a, z, p->nFrom)!=0 ) return 0;
|
||||
if( strncmp(p->a, z, p->nFrom)!=0 ) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1947,7 +1952,7 @@ static int spellfix1Init(
|
||||
);
|
||||
}
|
||||
for(i=3; rc==SQLITE_OK && i<argc; i++){
|
||||
if( memcmp(argv[i],"edit_cost_table=",16)==0 && pNew->zCostTable==0 ){
|
||||
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;
|
||||
@@ -2668,7 +2673,7 @@ static int spellfix1Update(
|
||||
if( zCmd==0 ){
|
||||
pVTab->zErrMsg = sqlite3_mprintf("%s.word may not be NULL",
|
||||
p->zTableName);
|
||||
return SQLITE_CONSTRAINT;
|
||||
return SQLITE_CONSTRAINT_NOTNULL;
|
||||
}
|
||||
if( strcmp(zCmd,"reset")==0 ){
|
||||
/* Reset the edit cost table (if there is one). */
|
||||
@@ -2676,6 +2681,18 @@ static int spellfix1Update(
|
||||
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;
|
||||
@@ -2809,7 +2826,7 @@ static int spellfix1Register(sqlite3 *db){
|
||||
/*
|
||||
** Register the spellfix1 virtual table and its associated functions.
|
||||
*/
|
||||
int sqlite3Spellfix1Register(sqlite3 *db){
|
||||
int sqlite3_spellfix1_register(sqlite3 *db){
|
||||
return spellfix1Register(db);
|
||||
}
|
||||
#endif
|
||||
@@ -2819,7 +2836,7 @@ int sqlite3Spellfix1Register(sqlite3 *db){
|
||||
/*
|
||||
** Extension load function.
|
||||
*/
|
||||
int sqlite3_extension_init(
|
||||
int sqlite3_spellfix1_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
|
||||
+1
-1
@@ -390,7 +390,7 @@ static void testSqllogStmt(struct SLConn *p, const char *zSql){
|
||||
** The SQLITE_CONFIG_SQLLOG callback registered by sqlite3_init_sqllog().
|
||||
*/
|
||||
static void testSqllog(void *pCtx, sqlite3 *db, const char *zSql, int eType){
|
||||
struct SLConn *p;
|
||||
struct SLConn *p = 0;
|
||||
sqlite3_mutex *master = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER);
|
||||
|
||||
assert( eType==0 || eType==1 || eType==2 );
|
||||
|
||||
+17
-15
@@ -265,7 +265,8 @@ static void tvfsExecTcl(
|
||||
const char *zMethod,
|
||||
Tcl_Obj *arg1,
|
||||
Tcl_Obj *arg2,
|
||||
Tcl_Obj *arg3
|
||||
Tcl_Obj *arg3,
|
||||
Tcl_Obj *arg4
|
||||
){
|
||||
int rc; /* Return code from Tcl_EvalObj() */
|
||||
Tcl_Obj *pEval;
|
||||
@@ -282,6 +283,7 @@ static void tvfsExecTcl(
|
||||
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 ){
|
||||
@@ -302,7 +304,7 @@ static int tvfsClose(sqlite3_file *pFile){
|
||||
|
||||
if( p->pScript && p->mask&TESTVFS_CLOSE_MASK ){
|
||||
tvfsExecTcl(p, "xClose",
|
||||
Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0
|
||||
Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0, 0
|
||||
);
|
||||
}
|
||||
|
||||
@@ -333,7 +335,7 @@ static int tvfsRead(
|
||||
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
|
||||
Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0, 0
|
||||
);
|
||||
tvfsResultCode(p, &rc);
|
||||
}
|
||||
@@ -362,7 +364,7 @@ static int tvfsWrite(
|
||||
if( p->pScript && p->mask&TESTVFS_WRITE_MASK ){
|
||||
tvfsExecTcl(p, "xWrite",
|
||||
Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId,
|
||||
Tcl_NewWideIntObj(iOfst)
|
||||
Tcl_NewWideIntObj(iOfst), Tcl_NewIntObj(iAmt)
|
||||
);
|
||||
tvfsResultCode(p, &rc);
|
||||
}
|
||||
@@ -390,7 +392,7 @@ static int tvfsTruncate(sqlite3_file *pFile, sqlite_int64 size){
|
||||
|
||||
if( p->pScript && p->mask&TESTVFS_TRUNCATE_MASK ){
|
||||
tvfsExecTcl(p, "xTruncate",
|
||||
Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0
|
||||
Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0, 0
|
||||
);
|
||||
tvfsResultCode(p, &rc);
|
||||
}
|
||||
@@ -431,7 +433,7 @@ static int tvfsSync(sqlite3_file *pFile, int flags){
|
||||
|
||||
tvfsExecTcl(p, "xSync",
|
||||
Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId,
|
||||
Tcl_NewStringObj(zFlags, -1)
|
||||
Tcl_NewStringObj(zFlags, -1), 0
|
||||
);
|
||||
tvfsResultCode(p, &rc);
|
||||
}
|
||||
@@ -578,7 +580,7 @@ static int tvfsOpen(
|
||||
z += strlen(z) + 1;
|
||||
}
|
||||
}
|
||||
tvfsExecTcl(p, "xOpen", Tcl_NewStringObj(pFd->zFilename, -1), pArg, 0);
|
||||
tvfsExecTcl(p, "xOpen", Tcl_NewStringObj(pFd->zFilename, -1), pArg, 0, 0);
|
||||
Tcl_DecrRefCount(pArg);
|
||||
if( tvfsResultCode(p, &rc) ){
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
@@ -635,7 +637,7 @@ static int tvfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
|
||||
|
||||
if( p->pScript && p->mask&TESTVFS_DELETE_MASK ){
|
||||
tvfsExecTcl(p, "xDelete",
|
||||
Tcl_NewStringObj(zPath, -1), Tcl_NewIntObj(dirSync), 0
|
||||
Tcl_NewStringObj(zPath, -1), Tcl_NewIntObj(dirSync), 0, 0
|
||||
);
|
||||
tvfsResultCode(p, &rc);
|
||||
}
|
||||
@@ -663,7 +665,7 @@ static int tvfsAccess(
|
||||
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
|
||||
Tcl_NewStringObj(zPath, -1), Tcl_NewStringObj(zArg, -1), 0, 0
|
||||
);
|
||||
if( tvfsResultCode(p, &rc) ){
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
@@ -691,7 +693,7 @@ static int tvfsFullPathname(
|
||||
Testvfs *p = (Testvfs *)pVfs->pAppData;
|
||||
if( p->pScript && p->mask&TESTVFS_FULLPATHNAME_MASK ){
|
||||
int rc;
|
||||
tvfsExecTcl(p, "xFullPathname", Tcl_NewStringObj(zPath, -1), 0, 0);
|
||||
tvfsExecTcl(p, "xFullPathname", Tcl_NewStringObj(zPath, -1), 0, 0, 0);
|
||||
if( tvfsResultCode(p, &rc) ){
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
}
|
||||
@@ -771,7 +773,7 @@ static int tvfsShmOpen(sqlite3_file *pFile){
|
||||
*/
|
||||
Tcl_ResetResult(p->interp);
|
||||
if( p->pScript && p->mask&TESTVFS_SHMOPEN_MASK ){
|
||||
tvfsExecTcl(p, "xShmOpen", Tcl_NewStringObj(pFd->zFilename, -1), 0, 0);
|
||||
tvfsExecTcl(p, "xShmOpen", Tcl_NewStringObj(pFd->zFilename, -1), 0, 0, 0);
|
||||
if( tvfsResultCode(p, &rc) ){
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
}
|
||||
@@ -841,7 +843,7 @@ static int tvfsShmMap(
|
||||
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
|
||||
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, pArg, 0
|
||||
);
|
||||
tvfsResultCode(p, &rc);
|
||||
Tcl_DecrRefCount(pArg);
|
||||
@@ -891,7 +893,7 @@ static int tvfsShmLock(
|
||||
}
|
||||
tvfsExecTcl(p, "xShmLock",
|
||||
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId,
|
||||
Tcl_NewStringObj(zLock, -1)
|
||||
Tcl_NewStringObj(zLock, -1), 0
|
||||
);
|
||||
tvfsResultCode(p, &rc);
|
||||
}
|
||||
@@ -937,7 +939,7 @@ static void tvfsShmBarrier(sqlite3_file *pFile){
|
||||
|
||||
if( p->pScript && p->mask&TESTVFS_SHMBARRIER_MASK ){
|
||||
tvfsExecTcl(p, "xShmBarrier",
|
||||
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
|
||||
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0, 0
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -961,7 +963,7 @@ static int tvfsShmUnmap(
|
||||
|
||||
if( p->pScript && p->mask&TESTVFS_SHMCLOSE_MASK ){
|
||||
tvfsExecTcl(p, "xShmUnmap",
|
||||
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
|
||||
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0, 0
|
||||
);
|
||||
tvfsResultCode(p, &rc);
|
||||
}
|
||||
|
||||
+3
-1
@@ -475,6 +475,7 @@ static int vfstraceFileControl(sqlite3_file *pFile, int op, void *pArg){
|
||||
case SQLITE_FCNTL_PERSIST_WAL: zOp = "PERSIST_WAL"; break;
|
||||
case SQLITE_FCNTL_OVERWRITE: zOp = "OVERWRITE"; break;
|
||||
case SQLITE_FCNTL_VFSNAME: zOp = "VFSNAME"; break;
|
||||
case SQLITE_FCNTL_TEMPFILENAME: zOp = "TEMPFILENAME"; break;
|
||||
case 0xca093fa0: zOp = "DB_UNCHANGED"; break;
|
||||
case SQLITE_FCNTL_PRAGMA: {
|
||||
const char *const* a = (const char*const*)pArg;
|
||||
@@ -496,7 +497,8 @@ static int vfstraceFileControl(sqlite3_file *pFile, int op, void *pArg){
|
||||
*(char**)pArg = sqlite3_mprintf("vfstrace.%s/%z",
|
||||
pInfo->zVfsName, *(char**)pArg);
|
||||
}
|
||||
if( op==SQLITE_FCNTL_PRAGMA && rc==SQLITE_OK && *(char**)pArg ){
|
||||
if( (op==SQLITE_FCNTL_PRAGMA || op==SQLITE_FCNTL_TEMPFILENAME)
|
||||
&& rc==SQLITE_OK && *(char**)pArg ){
|
||||
vfstrace_printf(pInfo, "%s.xFileControl(%s,%s) returns %s",
|
||||
pInfo->zVfsName, p->zFName, zOp, *(char**)pArg);
|
||||
}
|
||||
|
||||
@@ -729,6 +729,15 @@ static int codeTriggerProgram(
|
||||
*/
|
||||
pParse->eOrconf = (orconf==OE_Default)?pStep->orconf:(u8)orconf;
|
||||
|
||||
/* Clear the cookieGoto flag. When coding triggers, the cookieGoto
|
||||
** variable is used as a flag to indicate to sqlite3ExprCodeConstants()
|
||||
** that it is not safe to refactor constants (this happens after the
|
||||
** start of the first loop in the SQL statement is coded - at that
|
||||
** point code may be conditionally executed, so it is no longer safe to
|
||||
** initialize constant register values). */
|
||||
assert( pParse->cookieGoto==0 || pParse->cookieGoto==-1 );
|
||||
pParse->cookieGoto = 0;
|
||||
|
||||
switch( pStep->op ){
|
||||
case TK_UPDATE: {
|
||||
sqlite3Update(pParse,
|
||||
|
||||
+22
-10
@@ -422,7 +422,9 @@ void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
|
||||
** Print the value of a register for tracing purposes:
|
||||
*/
|
||||
static void memTracePrint(FILE *out, Mem *p){
|
||||
if( p->flags & MEM_Null ){
|
||||
if( p->flags & MEM_Invalid ){
|
||||
fprintf(out, " undefined");
|
||||
}else if( p->flags & MEM_Null ){
|
||||
fprintf(out, " NULL");
|
||||
}else if( (p->flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){
|
||||
fprintf(out, " si:%lld", p->u.i);
|
||||
@@ -867,7 +869,7 @@ case OP_Halt: {
|
||||
if( rc==SQLITE_BUSY ){
|
||||
p->rc = rc = SQLITE_BUSY;
|
||||
}else{
|
||||
assert( rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT );
|
||||
assert( rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT );
|
||||
assert( rc==SQLITE_OK || db->nDeferredCons>0 );
|
||||
rc = p->rc ? SQLITE_ERROR : SQLITE_DONE;
|
||||
}
|
||||
@@ -1077,6 +1079,9 @@ case OP_Copy: {
|
||||
while( 1 ){
|
||||
sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem);
|
||||
Deephemeralize(pOut);
|
||||
#ifdef SQLITE_DEBUG
|
||||
pOut->pScopyFrom = 0;
|
||||
#endif
|
||||
REGISTER_TRACE(pOp->p2+pOp->p3-n, pOut);
|
||||
if( (n--)==0 ) break;
|
||||
pOut++;
|
||||
@@ -1265,6 +1270,7 @@ case OP_Subtract: /* same as TK_MINUS, in1, in2, out3 */
|
||||
case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */
|
||||
case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */
|
||||
case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
|
||||
char bIntint; /* Started out as two integer operands */
|
||||
int flags; /* Combined MEM_* flags from both inputs */
|
||||
i64 iA; /* Integer value of left operand */
|
||||
i64 iB; /* Integer value of right operand */
|
||||
@@ -1281,6 +1287,7 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
|
||||
if( (pIn1->flags & pIn2->flags & MEM_Int)==MEM_Int ){
|
||||
iA = pIn1->u.i;
|
||||
iB = pIn2->u.i;
|
||||
bIntint = 1;
|
||||
switch( pOp->opcode ){
|
||||
case OP_Add: if( sqlite3AddInt64(&iB,iA) ) goto fp_math; break;
|
||||
case OP_Subtract: if( sqlite3SubInt64(&iB,iA) ) goto fp_math; break;
|
||||
@@ -1301,6 +1308,7 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
|
||||
pOut->u.i = iB;
|
||||
MemSetTypeFlag(pOut, MEM_Int);
|
||||
}else{
|
||||
bIntint = 0;
|
||||
fp_math:
|
||||
rA = sqlite3VdbeRealValue(pIn1);
|
||||
rB = sqlite3VdbeRealValue(pIn2);
|
||||
@@ -1332,7 +1340,7 @@ fp_math:
|
||||
}
|
||||
pOut->r = rB;
|
||||
MemSetTypeFlag(pOut, MEM_Real);
|
||||
if( (flags & MEM_Real)==0 ){
|
||||
if( (flags & MEM_Real)==0 && !bIntint ){
|
||||
sqlite3VdbeIntegerAffinity(pOut);
|
||||
}
|
||||
#endif
|
||||
@@ -1887,9 +1895,9 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
||||
** Set the permutation used by the OP_Compare operator to be the array
|
||||
** of integers in P4.
|
||||
**
|
||||
** The permutation is only valid until the next OP_Permutation, OP_Compare,
|
||||
** OP_Halt, or OP_ResultRow. Typically the OP_Permutation should occur
|
||||
** immediately prior to the OP_Compare.
|
||||
** The permutation is only valid until the next OP_Compare that has
|
||||
** the OPFLAG_PERMUTE bit set in P5. Typically the OP_Permutation should
|
||||
** occur immediately prior to the OP_Compare.
|
||||
*/
|
||||
case OP_Permutation: {
|
||||
assert( pOp->p4type==P4_INTARRAY );
|
||||
@@ -1898,12 +1906,17 @@ case OP_Permutation: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Compare P1 P2 P3 P4 *
|
||||
/* Opcode: Compare P1 P2 P3 P4 P5
|
||||
**
|
||||
** Compare two vectors of registers in reg(P1)..reg(P1+P3-1) (call this
|
||||
** vector "A") and in reg(P2)..reg(P2+P3-1) ("B"). Save the result of
|
||||
** the comparison for use by the next OP_Jump instruct.
|
||||
**
|
||||
** If P5 has the OPFLAG_PERMUTE bit set, then the order of comparison is
|
||||
** determined by the most recent OP_Permutation operator. If the
|
||||
** OPFLAG_PERMUTE bit is clear, then register are compared in sequential
|
||||
** order.
|
||||
**
|
||||
** P4 is a KeyInfo structure that defines collating sequences and sort
|
||||
** orders for the comparison. The permutation applies to registers
|
||||
** only. The KeyInfo elements are used sequentially.
|
||||
@@ -1922,6 +1935,7 @@ case OP_Compare: {
|
||||
CollSeq *pColl; /* Collating sequence to use on this term */
|
||||
int bRev; /* True for DESCENDING sort order */
|
||||
|
||||
if( (pOp->p5 & OPFLAG_PERMUTE)==0 ) aPermute = 0;
|
||||
n = pOp->p3;
|
||||
pKeyInfo = pOp->p4.pKeyInfo;
|
||||
assert( n>0 );
|
||||
@@ -2065,8 +2079,6 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */
|
||||
**
|
||||
** Check if OP_Once flag P1 is set. If so, jump to instruction P2. Otherwise,
|
||||
** set the flag and fall through to the next instruction.
|
||||
**
|
||||
** See also: JumpOnce
|
||||
*/
|
||||
case OP_Once: { /* jump */
|
||||
assert( pOp->p1<p->nOnceFlag );
|
||||
@@ -6051,7 +6063,7 @@ case OP_VUpdate: {
|
||||
assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) );
|
||||
db->lastRowid = lastRowid = rowid;
|
||||
}
|
||||
if( rc==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){
|
||||
if( (rc&0xff)==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){
|
||||
if( pOp->p5==OE_Ignore ){
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
|
||||
+2
-2
@@ -123,7 +123,7 @@ struct VdbeFrame {
|
||||
VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */
|
||||
void *token; /* Copy of SubProgram.token */
|
||||
i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */
|
||||
u16 nCursor; /* Number of entries in apCsr */
|
||||
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 */
|
||||
@@ -309,7 +309,7 @@ struct Vdbe {
|
||||
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 */
|
||||
u16 nCursor; /* Number of slots in apCsr[] */
|
||||
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 */
|
||||
|
||||
+1
-1
@@ -1198,7 +1198,7 @@ int sqlite3VdbeParameterIndex(Vdbe *p, const char *zName, int nName){
|
||||
if( zName ){
|
||||
for(i=0; i<p->nzVar; i++){
|
||||
const char *z = p->azVar[i];
|
||||
if( z && memcmp(z,zName,nName)==0 && z[nName]==0 ){
|
||||
if( z && strncmp(z,zName,nName)==0 && z[nName]==0 ){
|
||||
return i+1;
|
||||
}
|
||||
}
|
||||
|
||||
+23
-37
@@ -17,18 +17,6 @@
|
||||
#include "sqliteInt.h"
|
||||
#include "vdbeInt.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** When debugging the code generator in a symbolic debugger, one can
|
||||
** set the sqlite3VdbeAddopTrace to 1 and all opcodes will be printed
|
||||
** as they are added to the instruction stream.
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
int sqlite3VdbeAddopTrace = 0;
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Create a new virtual database engine.
|
||||
*/
|
||||
@@ -158,7 +146,9 @@ int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
|
||||
pOp->p4type = P4_NOTUSED;
|
||||
#ifdef SQLITE_DEBUG
|
||||
pOp->zComment = 0;
|
||||
if( sqlite3VdbeAddopTrace ) sqlite3VdbePrintOp(0, i, &p->aOp[i]);
|
||||
if( p->db->flags & SQLITE_VdbeAddopTrace ){
|
||||
sqlite3VdbePrintOp(0, i, &p->aOp[i]);
|
||||
}
|
||||
#endif
|
||||
#ifdef VDBE_PROFILE
|
||||
pOp->cycles = 0;
|
||||
@@ -377,7 +367,7 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
|
||||
|| (opcode==OP_FkCounter && pOp->p1==0 && pOp->p2==1)
|
||||
#endif
|
||||
|| ((opcode==OP_Halt || opcode==OP_HaltIfNull)
|
||||
&& (pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort))
|
||||
&& ((pOp->p1&0xff)==SQLITE_CONSTRAINT && pOp->p2==OE_Abort))
|
||||
){
|
||||
hasAbort = 1;
|
||||
break;
|
||||
@@ -512,7 +502,7 @@ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){
|
||||
pOut->p5 = 0;
|
||||
#ifdef SQLITE_DEBUG
|
||||
pOut->zComment = 0;
|
||||
if( sqlite3VdbeAddopTrace ){
|
||||
if( p->db->flags & SQLITE_VdbeAddopTrace ){
|
||||
sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]);
|
||||
}
|
||||
#endif
|
||||
@@ -866,22 +856,18 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
|
||||
i = sqlite3Strlen30(zTemp);
|
||||
for(j=0; j<pKeyInfo->nField; j++){
|
||||
CollSeq *pColl = pKeyInfo->aColl[j];
|
||||
if( pColl ){
|
||||
int n = sqlite3Strlen30(pColl->zName);
|
||||
if( i+n>nTemp-6 ){
|
||||
memcpy(&zTemp[i],",...",4);
|
||||
break;
|
||||
}
|
||||
zTemp[i++] = ',';
|
||||
if( pKeyInfo->aSortOrder[j] ){
|
||||
zTemp[i++] = '-';
|
||||
}
|
||||
memcpy(&zTemp[i], pColl->zName,n+1);
|
||||
i += n;
|
||||
}else if( i+4<nTemp-6 ){
|
||||
memcpy(&zTemp[i],",nil",4);
|
||||
i += 4;
|
||||
const char *zColl = pColl ? pColl->zName : "nil";
|
||||
int n = sqlite3Strlen30(zColl);
|
||||
if( i+n>nTemp-6 ){
|
||||
memcpy(&zTemp[i],",...",4);
|
||||
break;
|
||||
}
|
||||
zTemp[i++] = ',';
|
||||
if( pKeyInfo->aSortOrder[j] ){
|
||||
zTemp[i++] = '-';
|
||||
}
|
||||
memcpy(&zTemp[i], zColl, n+1);
|
||||
i += n;
|
||||
}
|
||||
zTemp[i++] = ')';
|
||||
zTemp[i] = 0;
|
||||
@@ -1542,7 +1528,7 @@ void sqlite3VdbeMakeReady(
|
||||
zEnd = &zCsr[nByte];
|
||||
}while( nByte && !db->mallocFailed );
|
||||
|
||||
p->nCursor = (u16)nCursor;
|
||||
p->nCursor = nCursor;
|
||||
p->nOnceFlag = nOnce;
|
||||
if( p->aVar ){
|
||||
p->nVar = (ynVar)nVar;
|
||||
@@ -1784,7 +1770,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
||||
if( needXcommit && db->xCommitCallback ){
|
||||
rc = db->xCommitCallback(db->pCommitArg);
|
||||
if( rc ){
|
||||
return SQLITE_CONSTRAINT;
|
||||
return SQLITE_CONSTRAINT_COMMITHOOK;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2076,14 +2062,14 @@ int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){
|
||||
** violations, return SQLITE_ERROR. Otherwise, SQLITE_OK.
|
||||
**
|
||||
** If there are outstanding FK violations and this function returns
|
||||
** SQLITE_ERROR, set the result of the VM to SQLITE_CONSTRAINT and write
|
||||
** an error message to it. Then return SQLITE_ERROR.
|
||||
** 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;
|
||||
p->rc = SQLITE_CONSTRAINT_FOREIGNKEY;
|
||||
p->errorAction = OE_Abort;
|
||||
sqlite3SetString(&p->zErrMsg, db, "foreign key constraint failed");
|
||||
return SQLITE_ERROR;
|
||||
@@ -2198,7 +2184,7 @@ int sqlite3VdbeHalt(Vdbe *p){
|
||||
sqlite3VdbeLeave(p);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
rc = SQLITE_CONSTRAINT;
|
||||
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
|
||||
@@ -2241,7 +2227,7 @@ int sqlite3VdbeHalt(Vdbe *p){
|
||||
if( eStatementOp ){
|
||||
rc = sqlite3VdbeCloseStatement(p, eStatementOp);
|
||||
if( rc ){
|
||||
if( p->rc==SQLITE_OK || p->rc==SQLITE_CONSTRAINT ){
|
||||
if( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_CONSTRAINT ){
|
||||
p->rc = rc;
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = 0;
|
||||
|
||||
@@ -32,7 +32,9 @@
|
||||
** 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 );
|
||||
|
||||
+360
-206
File diff suppressed because it is too large
Load Diff
+6
-2
@@ -2262,7 +2262,9 @@ do_test auth-4.3 {
|
||||
SQLITE_SELECT {} {} {} v1 \
|
||||
SQLITE_READ t2 a main v1 \
|
||||
SQLITE_READ t2 b main v1 \
|
||||
SQLITE_SELECT {} {} {} {} \
|
||||
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 \
|
||||
@@ -2288,7 +2290,9 @@ do_test auth-4.5 {
|
||||
SQLITE_SELECT {} {} {} v1 \
|
||||
SQLITE_READ t2 a main v1 \
|
||||
SQLITE_READ t2 b main v1 \
|
||||
SQLITE_SELECT {} {} {} {} \
|
||||
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 \
|
||||
|
||||
+6
-6
@@ -131,12 +131,12 @@ do_test auth2-2.3 {
|
||||
}
|
||||
set ::authargs
|
||||
} {SQLITE_SELECT {} {} {} {}
|
||||
SQLITE_READ v2 a main {}
|
||||
SQLITE_READ v2 b main {}
|
||||
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 {
|
||||
@@ -149,20 +149,20 @@ do_test auth2-2.4 {
|
||||
}
|
||||
set ::authargs
|
||||
} {SQLITE_SELECT {} {} {} {}
|
||||
SQLITE_READ v2 b main {}
|
||||
SQLITE_READ v2 a main {}
|
||||
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 v2 b main {}
|
||||
SQLITE_READ v2 a main {}
|
||||
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
|
||||
|
||||
@@ -257,5 +257,129 @@ do_execsql_test autoindex1-700 {
|
||||
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
|
||||
|
||||
+2
-4
@@ -63,8 +63,7 @@ do_execsql_test 2.1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE INDEX i1 ON t1(a, b);
|
||||
}
|
||||
|
||||
do_test 2.2 { file size test.db } 3072
|
||||
do_test 2.2 { file size test.db } [expr $AUTOVACUUM ? 4096 : 3072]
|
||||
|
||||
do_test 2.3 {
|
||||
sqlite3 db1 test.db2
|
||||
@@ -90,8 +89,7 @@ do_execsql_test 3.1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE INDEX i1 ON t1(a, b);
|
||||
}
|
||||
|
||||
do_test 3.2 { file size test.db } 12288
|
||||
do_test 3.2 { file size test.db } [expr $AUTOVACUUM ? 16384 : 12288]
|
||||
|
||||
do_test 3.3 {
|
||||
sqlite3 db1 test.db2
|
||||
|
||||
+8
-6
@@ -235,8 +235,9 @@ do_test capi2-3.13 {
|
||||
do_test capi2-3.13b {db changes} {0}
|
||||
|
||||
do_test capi2-3.14 {
|
||||
list [sqlite3_finalize $VM] [sqlite3_errmsg $DB]
|
||||
} {SQLITE_CONSTRAINT {column a is not unique}}
|
||||
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
|
||||
@@ -258,8 +259,9 @@ do_test capi2-3.18 {
|
||||
[get_column_names $VM]
|
||||
} {SQLITE_ERROR 0 {} {}}
|
||||
do_test capi2-3.19 {
|
||||
list [sqlite3_finalize $VM] [sqlite3_errmsg $DB]
|
||||
} {SQLITE_CONSTRAINT {t2.a may not be NULL}}
|
||||
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 {
|
||||
@@ -278,8 +280,8 @@ do_test capi2-3.23 {
|
||||
sqlite3_finalize $VM
|
||||
} {SQLITE_CONSTRAINT}
|
||||
do_test capi2-3.24 {
|
||||
sqlite3_errcode $DB
|
||||
} {SQLITE_CONSTRAINT}
|
||||
list [sqlite3_errcode $DB] [sqlite3_extended_errcode $DB]
|
||||
} {SQLITE_CONSTRAINT SQLITE_CONSTRAINT_UNIQUE}
|
||||
|
||||
# Two or more virtual machines exists at the same time.
|
||||
#
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
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 {
|
||||
@@ -413,4 +414,42 @@ do_test check-6.15 {
|
||||
|
||||
}
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# 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
|
||||
|
||||
@@ -75,6 +75,7 @@ do_test collate1-1.1 {
|
||||
}
|
||||
} {{} 0x119 0x2D}
|
||||
do_test collate1-1.2 {
|
||||
breakpoint
|
||||
execsql {
|
||||
SELECT c2 FROM collate1t1 ORDER BY 1 COLLATE hex;
|
||||
}
|
||||
|
||||
@@ -580,6 +580,7 @@ do_test conflict-9.19 {
|
||||
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}
|
||||
@@ -592,6 +593,7 @@ do_test conflict-9.21 {
|
||||
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}
|
||||
@@ -781,6 +783,7 @@ do_test conflict-12.3 {
|
||||
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;
|
||||
@@ -802,6 +805,7 @@ do_test conflict-13.1 {
|
||||
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);
|
||||
|
||||
+1
-1
@@ -168,7 +168,7 @@ foreach {tn sql temptables res} {
|
||||
6 "b FROM t1" {hash} {b B}
|
||||
7 "a FROM t1" {} {A a}
|
||||
8 "b COLLATE nocase FROM t1" {} {b}
|
||||
9 "b COLLATE nocase FROM t1 ORDER BY b COLLATE nocase" {} {B}
|
||||
9 "b COLLATE nocase FROM t1 ORDER BY b COLLATE nocase" {} {b}
|
||||
} {
|
||||
do_execsql_test 2.$tn.1 "SELECT DISTINCT $sql" $res
|
||||
do_temptables_test 2.$tn.2 "SELECT DISTINCT $sql" $temptables
|
||||
|
||||
+22
-21
@@ -627,7 +627,8 @@ proc test_efkey_57 {tn isError sql} {
|
||||
execsql $sql
|
||||
do_test e_fkey-18.$tn {
|
||||
catchsql { INSERT INTO t2 VALUES(NULL) }
|
||||
} [lindex {{0 {}} {1 {foreign key mismatch}}} $isError]
|
||||
} [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) }
|
||||
@@ -698,16 +699,16 @@ do_test e_fkey-19.2 {
|
||||
} {}
|
||||
do_test e_fkey-19.2 {
|
||||
catchsql { INSERT INTO child4 VALUES('xxx', 5) }
|
||||
} {1 {foreign key mismatch}}
|
||||
} {1 {foreign key mismatch - "child4" referencing "parent"}}
|
||||
do_test e_fkey-19.3 {
|
||||
catchsql { INSERT INTO child5 VALUES('xxx', 6) }
|
||||
} {1 {foreign key mismatch}}
|
||||
} {1 {foreign key mismatch - "child5" referencing "parent"}}
|
||||
do_test e_fkey-19.4 {
|
||||
catchsql { INSERT INTO child6 VALUES(2, 3) }
|
||||
} {1 {foreign key mismatch}}
|
||||
} {1 {foreign key mismatch - "child6" referencing "parent"}}
|
||||
do_test e_fkey-19.5 {
|
||||
catchsql { INSERT INTO child7 VALUES(3) }
|
||||
} {1 {foreign key mismatch}}
|
||||
} {1 {foreign key mismatch - "child7" referencing "parent"}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test errors in the database schema that are detected while preparing
|
||||
@@ -765,12 +766,12 @@ do_test e_fkey-20.1 {
|
||||
|
||||
foreach {tn tbl ptbl err} {
|
||||
2 c1 {} "no such table: main.nosuchtable"
|
||||
3 c2 p2 "foreign key mismatch"
|
||||
4 c3 p3 "foreign key mismatch"
|
||||
5 c4 p4 "foreign key mismatch"
|
||||
6 c5 p5 "foreign key mismatch"
|
||||
7 c6 p6 "foreign key mismatch"
|
||||
8 c7 p7 "foreign key mismatch"
|
||||
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')"
|
||||
@@ -820,22 +821,22 @@ do_test e_fkey-21.2 {
|
||||
} {}
|
||||
do_test e_fkey-21.3 {
|
||||
catchsql { INSERT INTO child9 VALUES('I') }
|
||||
} {1 {foreign key mismatch}}
|
||||
} {1 {foreign key mismatch - "child9" referencing "parent2"}}
|
||||
do_test e_fkey-21.4 {
|
||||
catchsql { INSERT INTO child9 VALUES('II') }
|
||||
} {1 {foreign key mismatch}}
|
||||
} {1 {foreign key mismatch - "child9" referencing "parent2"}}
|
||||
do_test e_fkey-21.5 {
|
||||
catchsql { INSERT INTO child9 VALUES(NULL) }
|
||||
} {1 {foreign key mismatch}}
|
||||
} {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}}
|
||||
} {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}}
|
||||
} {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}}
|
||||
} {1 {foreign key mismatch - "child10" referencing "parent2"}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test errors that are reported when creating the child table.
|
||||
@@ -1151,7 +1152,7 @@ do_test e_fkey-28.8 {
|
||||
CREATE TABLE c(a, b, FOREIGN KEY(a,b) REFERENCES p);
|
||||
}
|
||||
catchsql {DELETE FROM p}
|
||||
} {1 {foreign key mismatch}}
|
||||
} {1 {foreign key mismatch - "c" referencing "p"}}
|
||||
do_test e_fkey-28.9 {
|
||||
drop_all_tables
|
||||
execsql {
|
||||
@@ -1159,7 +1160,7 @@ do_test e_fkey-28.9 {
|
||||
CREATE TABLE c(a REFERENCES p);
|
||||
}
|
||||
catchsql {DELETE FROM p}
|
||||
} {1 {foreign key mismatch}}
|
||||
} {1 {foreign key mismatch - "c" referencing "p"}}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
@@ -2729,11 +2730,11 @@ do_test e_fkey-60.3 {
|
||||
do_test e_fkey-60.4 {
|
||||
execsql { CREATE TABLE nosuchtable(x PRIMARY KEY) }
|
||||
catchsql { DELETE FROM p }
|
||||
} {1 {foreign key mismatch}}
|
||||
} {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}}
|
||||
} {1 {foreign key mismatch - "c2" referencing "p"}}
|
||||
do_test e_fkey-60.6 {
|
||||
execsql { DROP TABLE c2 }
|
||||
execsql { DELETE FROM p }
|
||||
|
||||
+15
-10
@@ -141,8 +141,8 @@ do_insert_tests e_insert-0 {
|
||||
|
||||
delete_all_data
|
||||
|
||||
# EVIDENCE-OF: R-20288-20462 The first form (with the "VALUES" keyword)
|
||||
# creates a single new row in an existing table.
|
||||
# EVIDENCE-OF: R-21490-41092 The first form (with the "VALUES" keyword)
|
||||
# creates one or more new rows in an existing table.
|
||||
#
|
||||
do_insert_tests e_insert-1.1 {
|
||||
0 "SELECT count(*) FROM a2" {0}
|
||||
@@ -152,11 +152,14 @@ do_insert_tests e_insert-1.1 {
|
||||
|
||||
2a "INSERT INTO a2(a, b) VALUES(1, 2)" {}
|
||||
2b "SELECT count(*) FROM a2" {2}
|
||||
|
||||
3a "INSERT INTO a2(a) VALUES(3),(4)" {}
|
||||
3b "SELECT count(*) FROM a2" {4}
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-36040-20870 If no column-list is specified then the
|
||||
# number of values must be the same as the number of columns in the
|
||||
# table.
|
||||
# EVIDENCE-OF: R-53616-44976 If no column-list is specified then the
|
||||
# number of values inserted into each row must be the same as the number
|
||||
# of columns in the table.
|
||||
#
|
||||
# A test in the block above verifies that if the VALUES list has the
|
||||
# correct number of columns (for table a2, 3 columns) works. So these
|
||||
@@ -171,9 +174,10 @@ do_insert_tests e_insert-1.2 -error {
|
||||
4 "INSERT INTO a2 VALUES(1,2,3,4,5)" {a2 3 5}
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-04006-57648 In this case the result of evaluating the
|
||||
# left-most expression in the VALUES list is inserted into the left-most
|
||||
# column of the new row, and so on.
|
||||
# EVIDENCE-OF: R-34231-22576 In this case the result of evaluating the
|
||||
# left-most expression in each term of the VALUES list is inserted into
|
||||
# the left-most column of the each new row, and forth for each
|
||||
# subsequent expression.
|
||||
#
|
||||
delete_all_data
|
||||
do_insert_tests e_insert-1.3 {
|
||||
@@ -187,8 +191,9 @@ do_insert_tests e_insert-1.3 {
|
||||
3b "SELECT * FROM a2 WHERE oid=last_insert_rowid()" {2 x y}
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-62524-00361 If a column-list is specified, then the
|
||||
# number of values must match the number of specified columns.
|
||||
# EVIDENCE-OF: R-44710-64652 If a column-list is specified, then the
|
||||
# number of values in each term of the VALUS list must match the number
|
||||
# of specified columns.
|
||||
#
|
||||
do_insert_tests e_insert-1.4 -error {
|
||||
%d values for %d columns
|
||||
|
||||
+2
-2
@@ -261,9 +261,9 @@ foreach {tn uri error} "
|
||||
}
|
||||
|
||||
|
||||
# EVIDENCE-OF: R-09651-31805 If "ro" is specified, then the database is
|
||||
# EVIDENCE-OF: R-43036-46756 If "ro" is specified, then the database is
|
||||
# opened for read-only access, just as if the SQLITE_OPEN_READONLY flag
|
||||
# had been set in the third argument to sqlite3_prepare_v2().
|
||||
# had been set in the third argument to sqlite3_open_v2().
|
||||
#
|
||||
# EVIDENCE-OF: R-40137-26050 If the mode option is set to "rw", then the
|
||||
# database is opened for read-write (but not create) access, as if
|
||||
|
||||
@@ -80,12 +80,14 @@ do_test 2.2 {
|
||||
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
|
||||
|
||||
@@ -36,6 +36,12 @@ do_test filectrl-1.5 {
|
||||
sqlite3 db test_control_lockproxy.db
|
||||
file_control_lockproxy_test db [get_pwd]
|
||||
} {}
|
||||
do_test filectrl-1.6 {
|
||||
sqlite3 db test.db
|
||||
set fn [file_control_tempfilename db]
|
||||
puts -nonewline \[$fn\]
|
||||
set fn
|
||||
} {/etilqs_/}
|
||||
db close
|
||||
forcedelete .test_control_lockproxy.db-conch test.proxy
|
||||
finish_test
|
||||
|
||||
@@ -213,4 +213,39 @@ do_execsql_test filefmt-3.3 {
|
||||
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
|
||||
|
||||
|
||||
+31
-5
@@ -139,14 +139,21 @@ set FkeySimpleTests {
|
||||
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}}
|
||||
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 { catchsql $zSql } $res
|
||||
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
|
||||
|
||||
@@ -155,6 +162,12 @@ do_test fkey2-1.2.0 {
|
||||
} {}
|
||||
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
|
||||
|
||||
@@ -165,6 +178,12 @@ do_test fkey2-1.3.0 {
|
||||
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
|
||||
@@ -681,7 +700,7 @@ foreach zSql [list {
|
||||
do_test fkey2-10.1.[incr tn] {
|
||||
execsql $zSql
|
||||
catchsql { INSERT INTO c DEFAULT VALUES }
|
||||
} {1 {foreign key mismatch}}
|
||||
} {/1 {foreign key mismatch - "c" referencing "."}/}
|
||||
}
|
||||
|
||||
# "rowid" cannot be used as part of a child or parent key definition
|
||||
@@ -709,7 +728,7 @@ do_test fkey2-10.2.1 {
|
||||
INSERT INTO t1(rowid, a, b) VALUES(1, 1, 1);
|
||||
INSERT INTO t2 VALUES(1, 1);
|
||||
}
|
||||
} {1 {foreign key mismatch}}
|
||||
} {1 {foreign key mismatch - "t2" referencing "t1"}}
|
||||
do_test fkey2-10.2.2 {
|
||||
drop_all_tables
|
||||
catchsql {
|
||||
@@ -1223,7 +1242,7 @@ do_test fkey-2.14.3.8 {
|
||||
CREATE TABLE cc(a, b, FOREIGN KEY(a, b) REFERENCES pp(x, z));
|
||||
}
|
||||
catchsql { INSERT INTO cc VALUES(1, 2) }
|
||||
} {1 {foreign key mismatch}}
|
||||
} {1 {foreign key mismatch - "cc" referencing "pp"}}
|
||||
do_test fkey-2.14.3.9 {
|
||||
execsql { DROP TABLE cc }
|
||||
} {}
|
||||
@@ -1414,10 +1433,12 @@ 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
|
||||
@@ -1426,6 +1447,7 @@ ifcapable autoreset {
|
||||
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);
|
||||
@@ -1469,9 +1491,11 @@ do_test fkey2-17.1.12 {
|
||||
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 {
|
||||
@@ -1625,9 +1649,11 @@ do_test fkey2-19.2 {
|
||||
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
|
||||
|
||||
@@ -42,10 +42,12 @@ do_test fkey4-1.2 {
|
||||
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}
|
||||
|
||||
+310
@@ -0,0 +1,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
|
||||
@@ -29,6 +29,7 @@ do_malloc_test fkey_malloc-1 -sqlprep {
|
||||
INSERT INTO t2 VALUES('aaa');
|
||||
UPDATE t1 SET a = 'bbb';
|
||||
DELETE FROM t1;
|
||||
PRAGMA foreign_key_check;
|
||||
}
|
||||
|
||||
do_malloc_test fkey_malloc-2 -sqlprep {
|
||||
@@ -128,5 +129,3 @@ do_malloc_test fkey_malloc-7 -sqlprep {
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
|
||||
@@ -19,6 +19,11 @@ ifcapable !fts3 {
|
||||
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.
|
||||
|
||||
@@ -46,6 +46,8 @@ ifcapable !fts3 {
|
||||
# 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);
|
||||
@@ -522,4 +524,103 @@ 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
|
||||
|
||||
|
||||
@@ -44,12 +44,12 @@ proc do_unicode_token_test3 {tn args} {
|
||||
}
|
||||
|
||||
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}
|
||||
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.4 "\u1E9E" "0 ß \u1E9E"
|
||||
do_unicode_token_test 1.5 "\u1E9E" "0 \uDF \u1E9E"
|
||||
|
||||
do_unicode_token_test 1.6 "The quick brown fox" {
|
||||
@@ -60,12 +60,15 @@ do_unicode_token_test 1.7 "The\u00bfquick\u224ebrown\u2263fox" {
|
||||
}
|
||||
|
||||
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}
|
||||
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.10 "xx\u0301xx" "0 xxxx xx\u301xx"
|
||||
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"
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@@ -383,5 +386,3 @@ foreach T $tokenizers {
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
|
||||
+16
-1
@@ -1289,6 +1289,21 @@ do_test func-29.6 {
|
||||
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
|
||||
|
||||
@@ -74,6 +74,7 @@ do_test hook-3.6 {
|
||||
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}
|
||||
|
||||
@@ -0,0 +1,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
|
||||
|
||||
@@ -139,8 +139,9 @@ ifcapable shared_cache {
|
||||
# Figure out how big the database is and how many free pages it
|
||||
# has before running incremental-vacuum.
|
||||
#
|
||||
set nPage [expr {[file size test.db]/1024}]
|
||||
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.
|
||||
@@ -158,11 +159,11 @@ ifcapable shared_cache {
|
||||
set ::sqlite_io_error_hardhit 0
|
||||
|
||||
set nFree2 [execsql {pragma freelist_count} db1]
|
||||
set nPage2 [expr {[file size test.db]/1024}]
|
||||
set nPage2 [execsql {pragma page_count} db1]
|
||||
|
||||
do_test incrvacuum-ioerr-4.$iTest.2 {
|
||||
set shrink [expr {$nPage-$nPage2}]
|
||||
expr {$shrink==0 || $shrink==5}
|
||||
expr {$shrink==0 || $shrink==5 || ($nFree<5 && $shrink==$nFree)}
|
||||
} {1}
|
||||
|
||||
do_test incrvacuum-ioerr-4.$iTest.3 {
|
||||
|
||||
+4
-4
@@ -36,11 +36,10 @@ db close
|
||||
testvfs tvfs
|
||||
tvfs filter xWrite
|
||||
tvfs script write_cb
|
||||
proc write_cb {xCall file handle iOfst} {
|
||||
proc write_cb {xCall file handle iOfst args} {
|
||||
if {[file tail $file]=="test.db"} {
|
||||
lappend ::write_list [expr $iOfst/1024]
|
||||
}
|
||||
puts "$xCall $file $args"
|
||||
}
|
||||
|
||||
do_test 1.2 {
|
||||
@@ -65,11 +64,12 @@ do_test 1.3 {
|
||||
}
|
||||
set iPrev $iNext
|
||||
}
|
||||
puts -nonewline \
|
||||
" (forward=$nForward, back=$nBackward, noncontiguous=$nNoncont)"
|
||||
|
||||
expr {$nForward > $nBackward}
|
||||
expr {$nForward > 2*($nBackward + $nNoncont)}
|
||||
} {1}
|
||||
db close
|
||||
tvfs delete
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
+3
-1
@@ -166,6 +166,8 @@ for {set i 1} {$i<$max_count-5} {incr i 1} {
|
||||
} {1 interrupted}
|
||||
}
|
||||
|
||||
if {0} { # This doesn't work anymore since the collation factor is
|
||||
# no longer called during schema parsing.
|
||||
# Interrupt during parsing
|
||||
#
|
||||
do_test interrupt-5.1 {
|
||||
@@ -179,5 +181,5 @@ do_test interrupt-5.1 {
|
||||
CREATE INDEX fake ON fake1(a COLLATE fake_collation, b, c DESC);
|
||||
}
|
||||
} {1 interrupt}
|
||||
|
||||
}
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,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
|
||||
|
||||
+147
@@ -468,5 +468,152 @@ do_test limit-12.4 {
|
||||
}
|
||||
} {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
|
||||
|
||||
+53
-25
@@ -27,6 +27,24 @@ if {!$MEMDEBUG} {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
# Do not run these tests with an in-memory journal.
|
||||
#
|
||||
# In the pager layer, if an IO or OOM error occurs during a ROLLBACK, or
|
||||
# when flushing a page to disk due to cache-stress, the pager enters an
|
||||
# "error state". The only way out of the error state is to unlock the
|
||||
# database file and end the transaction, leaving whatever journal and
|
||||
# database files happen to be on disk in place. The next time the current
|
||||
# (or any other) connection opens a read transaction, hot-journal rollback
|
||||
# is performed if necessary.
|
||||
#
|
||||
# Of course, this doesn't work with an in-memory journal.
|
||||
#
|
||||
if {[permutation]=="inmemory_journal"} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# NOTES ON RECOVERING FROM A MALLOC FAILURE
|
||||
#
|
||||
@@ -147,6 +165,7 @@ if {!$MEMDEBUG} {
|
||||
# ::run_test_script. At the end of this file, the proc [run_test] is used
|
||||
# to execute the program (and all test cases contained therein).
|
||||
#
|
||||
set ::run_test_sql_id 0
|
||||
set ::run_test_script [list]
|
||||
proc TEST {id t} {lappend ::run_test_script -test [list $id $t]}
|
||||
proc PREP {p} {lappend ::run_test_script -prep [string trim $p]}
|
||||
@@ -162,13 +181,14 @@ proc DEBUG {s} {lappend ::run_test_script -debug $s}
|
||||
# transaction only.
|
||||
#
|
||||
proc SQL {a1 {a2 ""}} {
|
||||
# An SQL primitive parameter is a list of two elements, a boolean value
|
||||
# indicating if the statement may cause transaction rollback when malloc()
|
||||
# fails, and the sql statement itself.
|
||||
# An SQL primitive parameter is a list of three elements, an id, a boolean
|
||||
# value indicating if the statement may cause transaction rollback when
|
||||
# malloc() fails, and the sql statement itself.
|
||||
set id [incr ::run_test_sql_id]
|
||||
if {$a2 == ""} {
|
||||
lappend ::run_test_script -sql [list true [string trim $a1]]
|
||||
lappend ::run_test_script -sql [list $id true [string trim $a1]]
|
||||
} else {
|
||||
lappend ::run_test_script -sql [list false [string trim $a2]]
|
||||
lappend ::run_test_script -sql [list $id false [string trim $a2]]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,7 +278,7 @@ TEST 5 {
|
||||
set sql {
|
||||
BEGIN;DELETE FROM abc;
|
||||
}
|
||||
for {set i 1} {$i < 15} {incr i} {
|
||||
for {set i 1} {$i < 100} {incr i} {
|
||||
set a $i
|
||||
set b "String value $i"
|
||||
set c [string repeat X $i]
|
||||
@@ -529,12 +549,13 @@ proc run_test {arglist iRepeat {pcstart 0} {iFailStart 1}} {
|
||||
}
|
||||
|
||||
for {set i 0} {$i < $pcstart} {incr i} {
|
||||
set k2 [lindex $arglist [expr 2 * $i]]
|
||||
set v2 [lindex $arglist [expr 2 * $i + 1]]
|
||||
set k2 [lindex $arglist [expr {2 * $i}]]
|
||||
set v2 [lindex $arglist [expr {2 * $i + 1}]]
|
||||
set ac [sqlite3_get_autocommit $::DB] ;# Auto-Commit
|
||||
switch -- $k2 {
|
||||
-sql {db eval [lindex $v2 1]}
|
||||
-sql {db eval [lindex $v2 2]}
|
||||
-prep {db eval $v2}
|
||||
-debug {eval $v2}
|
||||
}
|
||||
set nac [sqlite3_get_autocommit $::DB] ;# New Auto-Commit
|
||||
if {$ac && !$nac} {set begin_pc $i}
|
||||
@@ -545,25 +566,31 @@ proc run_test {arglist iRepeat {pcstart 0} {iFailStart 1}} {
|
||||
set iFail $iFailStart
|
||||
set pc $pcstart
|
||||
while {$pc*2 < [llength $arglist]} {
|
||||
# Fetch the current instruction type and payload.
|
||||
set k [lindex $arglist [expr {2 * $pc}]]
|
||||
set v [lindex $arglist [expr {2 * $pc + 1}]]
|
||||
|
||||
# Id of this iteration:
|
||||
set k [lindex $arglist [expr 2 * $pc]]
|
||||
set iterid "pc=$pc.iFail=$iFail$k"
|
||||
set v [lindex $arglist [expr 2 * $pc + 1]]
|
||||
|
||||
switch -- $k {
|
||||
|
||||
-test {
|
||||
foreach {id script} $v {}
|
||||
set testid "malloc3-(test $id).$iterid"
|
||||
eval $script
|
||||
incr pc
|
||||
}
|
||||
|
||||
-sql {
|
||||
set ::rollback_hook_count 0
|
||||
|
||||
set id [lindex $v 0]
|
||||
set testid "malloc3-(integrity $id).$iterid"
|
||||
|
||||
set ac [sqlite3_get_autocommit $::DB] ;# Auto-Commit
|
||||
sqlite3_memdebug_fail $iFail -repeat 0
|
||||
set rc [catch {db eval [lindex $v 1]} msg] ;# True error occurs
|
||||
set rc [catch {db eval [lindex $v 2]} msg] ;# True error occurs
|
||||
set nac [sqlite3_get_autocommit $::DB] ;# New Auto-Commit
|
||||
|
||||
if {$rc != 0 && $nac && !$ac} {
|
||||
@@ -571,7 +598,7 @@ proc run_test {arglist iRepeat {pcstart 0} {iFailStart 1}} {
|
||||
# is set. Since an error occured we assume this was not a
|
||||
# commit - therefore a rollback occured. Check that the
|
||||
# rollback-hook was invoked.
|
||||
do_test malloc3-rollback_hook.$iterid {
|
||||
do_test malloc3-rollback_hook_count.$iterid {
|
||||
set ::rollback_hook_count
|
||||
} {1}
|
||||
}
|
||||
@@ -582,8 +609,9 @@ proc run_test {arglist iRepeat {pcstart 0} {iFailStart 1}} {
|
||||
# calls should be equal to the number of benign failures.
|
||||
# Otherwise a malloc() failed and the error was not reported.
|
||||
#
|
||||
if {$nFail!=$nBenign} {
|
||||
error "Unreported malloc() failure"
|
||||
set expr {$nFail!=$nBenign}
|
||||
if {[expr $expr]} {
|
||||
error "Unreported malloc() failure, test \"$testid\", $expr"
|
||||
}
|
||||
|
||||
if {$ac && !$nac} {
|
||||
@@ -595,24 +623,23 @@ proc run_test {arglist iRepeat {pcstart 0} {iFailStart 1}} {
|
||||
|
||||
incr pc
|
||||
set iFail 1
|
||||
integrity_check "malloc3-(integrity).$iterid"
|
||||
integrity_check $testid
|
||||
} elseif {[regexp {.*out of memory} $msg] || [db errorcode] == 3082} {
|
||||
# Out of memory error, as expected.
|
||||
#
|
||||
integrity_check "malloc3-(integrity).$iterid"
|
||||
integrity_check $testid
|
||||
incr iFail
|
||||
if {$nac && !$ac} {
|
||||
|
||||
if {![lindex $v 0] && [db errorcode] != 3082} {
|
||||
# error "Statement \"[lindex $v 1]\" caused a rollback"
|
||||
if {![lindex $v 1] && [db errorcode] != 3082} {
|
||||
# error "Statement \"[lindex $v 2]\" caused a rollback"
|
||||
}
|
||||
|
||||
for {set i $begin_pc} {$i < $pc} {incr i} {
|
||||
set k2 [lindex $arglist [expr 2 * $i]]
|
||||
set v2 [lindex $arglist [expr 2 * $i + 1]]
|
||||
set k2 [lindex $arglist [expr {2 * $i}]]
|
||||
set v2 [lindex $arglist [expr {2 * $i + 1}]]
|
||||
set catchupsql ""
|
||||
switch -- $k2 {
|
||||
-sql {set catchupsql [lindex $v2 1]}
|
||||
-sql {set catchupsql [lindex $v2 2]}
|
||||
-prep {set catchupsql $v2}
|
||||
}
|
||||
db eval $catchupsql
|
||||
@@ -622,7 +649,8 @@ proc run_test {arglist iRepeat {pcstart 0} {iFailStart 1}} {
|
||||
error $msg
|
||||
}
|
||||
|
||||
while {[lindex $arglist [expr 2 * ($pc -1)]] == "-test"} {
|
||||
# back up to the previous "-test" block.
|
||||
while {[lindex $arglist [expr {2 * ($pc - 1)}]] == "-test"} {
|
||||
incr pc -1
|
||||
}
|
||||
}
|
||||
@@ -642,7 +670,7 @@ proc run_test {arglist iRepeat {pcstart 0} {iFailStart 1}} {
|
||||
}
|
||||
}
|
||||
|
||||
# Turn of the Tcl interface's prepared statement caching facility. Then
|
||||
# Turn off the Tcl interface's prepared statement caching facility. Then
|
||||
# run the tests with "persistent" malloc failures.
|
||||
sqlite3_extended_result_codes db 1
|
||||
db cache size 0
|
||||
|
||||
@@ -53,6 +53,11 @@ do_malloc_test mallocG-3 -sqlprep {
|
||||
AND x BETWEEN 'i' AND 'm'
|
||||
}
|
||||
|
||||
ifcapable !utf16 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
proc utf16 {utf8} {
|
||||
set utf16 [encoding convertto unicode $utf8]
|
||||
append utf16 "\x00\x00"
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix minmax
|
||||
|
||||
do_test minmax-1.0 {
|
||||
execsql {
|
||||
@@ -536,7 +537,96 @@ do_test minmax-12.17 {
|
||||
}
|
||||
} {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
|
||||
|
||||
@@ -488,6 +488,34 @@ do_test misc7-21.1 {
|
||||
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
|
||||
|
||||
+26
-1
@@ -48,6 +48,7 @@ do_test notnull-1.2 {
|
||||
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;
|
||||
@@ -62,6 +63,7 @@ do_test notnull-1.4 {
|
||||
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;
|
||||
@@ -69,6 +71,7 @@ do_test notnull-1.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;
|
||||
@@ -104,6 +107,7 @@ do_test notnull-1.10 {
|
||||
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;
|
||||
@@ -146,6 +150,7 @@ do_test notnull-1.16 {
|
||||
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;
|
||||
@@ -153,6 +158,7 @@ do_test notnull-1.17 {
|
||||
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;
|
||||
@@ -174,6 +180,7 @@ do_test notnull-1.20 {
|
||||
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;
|
||||
@@ -190,6 +197,7 @@ do_test notnull-2.1 {
|
||||
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;
|
||||
@@ -198,6 +206,7 @@ do_test notnull-2.2 {
|
||||
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;
|
||||
@@ -214,6 +223,7 @@ do_test notnull-2.4 {
|
||||
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;
|
||||
@@ -222,6 +232,7 @@ do_test notnull-2.5 {
|
||||
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;
|
||||
@@ -262,6 +273,7 @@ do_test notnull-2.10 {
|
||||
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 {
|
||||
@@ -287,6 +299,7 @@ do_test notnull-3.2 {
|
||||
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;
|
||||
@@ -301,6 +314,7 @@ do_test notnull-3.4 {
|
||||
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;
|
||||
@@ -308,6 +322,7 @@ do_test notnull-3.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;
|
||||
@@ -343,6 +358,7 @@ do_test notnull-3.10 {
|
||||
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;
|
||||
@@ -385,6 +401,7 @@ do_test notnull-3.16 {
|
||||
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;
|
||||
@@ -392,6 +409,7 @@ do_test notnull-3.17 {
|
||||
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;
|
||||
@@ -413,6 +431,7 @@ do_test notnull-3.20 {
|
||||
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;
|
||||
@@ -429,6 +448,7 @@ do_test notnull-4.1 {
|
||||
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;
|
||||
@@ -437,6 +457,7 @@ do_test notnull-4.2 {
|
||||
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;
|
||||
@@ -453,6 +474,7 @@ do_test notnull-4.4 {
|
||||
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;
|
||||
@@ -461,6 +483,7 @@ do_test notnull-4.5 {
|
||||
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;
|
||||
@@ -501,6 +524,7 @@ do_test notnull-4.10 {
|
||||
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.
|
||||
#
|
||||
@@ -519,6 +543,7 @@ do_test notnull-5.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}
|
||||
@@ -531,9 +556,9 @@ do_test notnull-5.4 {
|
||||
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
|
||||
|
||||
|
||||
@@ -0,0 +1,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
|
||||
+9
-1
@@ -752,7 +752,7 @@ sqlite3 db test.db -readonly 1
|
||||
do_catchsql_test pager1.4.5.6 {
|
||||
SELECT * FROM t1;
|
||||
SELECT * FROM t2;
|
||||
} {1 {disk I/O error}}
|
||||
} {1 {attempt to write a readonly database}}
|
||||
db close
|
||||
|
||||
# Snapshot the file-system just before multi-file commit. Save the name
|
||||
@@ -883,12 +883,20 @@ do_execsql_test pager1.4.7.1 {
|
||||
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-}
|
||||
|
||||
+54
-4
@@ -534,12 +534,20 @@ do_test pragma-6.2.2 {
|
||||
b DEFAULT (5+3),
|
||||
c TEXT,
|
||||
d INTEGER DEFAULT NULL,
|
||||
e TEXT DEFAULT ''
|
||||
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 0 2 c TEXT 0 <<NULL>> 0 3 d INTEGER 0 NULL 0 4 e TEXT 0 '' 0}
|
||||
} {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 {
|
||||
@@ -1618,6 +1626,48 @@ 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
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,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
|
||||
+29
-10
@@ -81,6 +81,22 @@ array set ::Configs {
|
||||
-DSQLITE_DEFAULT_FILE_FORMAT=4
|
||||
-DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1
|
||||
}
|
||||
"Check-Symbols" {
|
||||
-DSQLITE_MEMDEBUG=1
|
||||
-DSQLITE_ENABLE_FTS3_PARENTHESIS=1
|
||||
-DSQLITE_ENABLE_FTS3=1
|
||||
-DSQLITE_ENABLE_RTREE=1
|
||||
-DSQLITE_ENABLE_MEMSYS5=1
|
||||
-DSQLITE_ENABLE_MEMSYS3=1
|
||||
-DSQLITE_ENABLE_COLUMN_METADATA=1
|
||||
-DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1
|
||||
-DSQLITE_SECURE_DELETE=1
|
||||
-DSQLITE_SOUNDEX=1
|
||||
-DSQLITE_ENABLE_ATOMIC_WRITE=1
|
||||
-DSQLITE_ENABLE_IOTRACE=1
|
||||
-DSQLITE_ENABLE_MEMORY_MANAGEMENT=1
|
||||
-DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1
|
||||
}
|
||||
"Debug-One" {
|
||||
-O2
|
||||
-DSQLITE_DEBUG=1
|
||||
@@ -164,7 +180,8 @@ array set ::Configs {
|
||||
|
||||
array set ::Platforms {
|
||||
Linux-x86_64 {
|
||||
"Debug-One" "checksymbols test"
|
||||
"Check-Symbols" checksymbols
|
||||
"Debug-One" test
|
||||
"Secure-Delete" test
|
||||
"Unlock-Notify" "QUICKTEST_INCLUDE=notify2.test test"
|
||||
"Update-Delete-Limit" test
|
||||
@@ -330,15 +347,17 @@ proc main {argv} {
|
||||
# If the configuration included the SQLITE_DEBUG option, then remove
|
||||
# it and run veryquick.test. If it did not include the SQLITE_DEBUG option
|
||||
# add it and run veryquick.test.
|
||||
set debug_idx [lsearch -glob $config_options -DSQLITE_DEBUG*]
|
||||
if {$debug_idx < 0} {
|
||||
run_test_suite "${zConfig}_debug" test [
|
||||
concat $config_options -DSQLITE_DEBUG=1
|
||||
]
|
||||
} else {
|
||||
run_test_suite "${zConfig}_ndebug" test [
|
||||
lreplace $config_options $debug_idx $debug_idx
|
||||
]
|
||||
if {$target!="checksymbols"} {
|
||||
set debug_idx [lsearch -glob $config_options -DSQLITE_DEBUG*]
|
||||
if {$debug_idx < 0} {
|
||||
run_test_suite "${zConfig}_debug" test [
|
||||
concat $config_options -DSQLITE_DEBUG=1
|
||||
]
|
||||
} else {
|
||||
run_test_suite "${zConfig}_ndebug" test [
|
||||
lreplace $config_options $debug_idx $debug_idx
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,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
|
||||
+24
-1
@@ -136,6 +136,30 @@ do_test 2.4 {
|
||||
set ::invoked_mycollate_db1
|
||||
} {0}
|
||||
|
||||
forcedelete test.db test.db2
|
||||
sqlite3 db1 test.db
|
||||
sqlite3 db2 test.db
|
||||
db1 collate mycollate mycollate_db1
|
||||
db2 collate mycollate mycollate_db2
|
||||
|
||||
do_test 2.13 {
|
||||
set ::invoked_mycollate_db1 0
|
||||
db1 eval {
|
||||
CREATE TABLE t1(a, CHECK (a COLLATE mycollate IN ('one', 'two', 'three')));
|
||||
INSERT INTO t1 VALUES('one');
|
||||
}
|
||||
db1 close
|
||||
set ::invoked_mycollate_db1
|
||||
} {1}
|
||||
do_test 2.14 {
|
||||
set ::invoked_mycollate_db1 0
|
||||
db2 eval {
|
||||
INSERT INTO t1 VALUES('two');
|
||||
}
|
||||
db2 close
|
||||
set ::invoked_mycollate_db1
|
||||
} {0}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# This test verifies that a bug causing a busy-handler belonging to one
|
||||
# shared-cache connection to be executed as a result of an sqlite3_step()
|
||||
@@ -204,4 +228,3 @@ db2 close
|
||||
|
||||
sqlite3_enable_shared_cache $::enable_shared_cache
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -401,6 +401,8 @@ do_malloc_test shared_err-8 -tclprep {
|
||||
execsql {INSERT INTO t1 VALUES($a, $b)} db2
|
||||
}
|
||||
execsql {COMMIT} db2
|
||||
execsql BEGIN
|
||||
execsql ROLLBACK
|
||||
set ::DB2 [sqlite3_connection_pointer db2]
|
||||
set ::STMT [sqlite3_prepare $::DB2 "SELECT a FROM t1 ORDER BY a" -1 DUMMY]
|
||||
sqlite3_step $::STMT ;# Cursor points at 0000000000
|
||||
@@ -409,8 +411,7 @@ do_malloc_test shared_err-8 -tclprep {
|
||||
execsql {
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(6, NULL);
|
||||
ROLLBACK;
|
||||
}
|
||||
ROLLBACK}
|
||||
} -cleanup {
|
||||
# UPDATE: As of [5668], if the rollback fails SQLITE_CORRUPT is returned.
|
||||
# So these tests have been updated to expect SQLITE_CORRUPT and its
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user