mirror of
https://github.com/sqlite/sqlite.git
synced 2026-10-28 10:57:26 +03:00
Merge latest trunk changes into this branch.
FossilOrigin-Name: 9f41f604055553f0c62d4c0d5a00c6a43d1a938f36901238c52c065702b9c536
This commit is contained in:
@@ -380,6 +380,9 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_SESSION=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PREUPDATE_HOOK=1
|
||||
!ENDIF
|
||||
|
||||
# Always enable math functions on Windows
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_MATH_FUNCTIONS
|
||||
|
||||
# Should the rbu extension be enabled? If so, add compilation options
|
||||
# to enable it.
|
||||
#
|
||||
|
||||
@@ -87,7 +87,9 @@ AC_SUBST(READLINE_LIBS)
|
||||
AC_ARG_ENABLE(threadsafe, [AS_HELP_STRING(
|
||||
[--enable-threadsafe], [build a thread-safe library [default=yes]])],
|
||||
[], [enable_threadsafe=yes])
|
||||
if test x"$enable_threadsafe" != "xno"; then
|
||||
if test x"$enable_threadsafe" == "xno"; then
|
||||
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_THREADSAFE=0"
|
||||
else
|
||||
BUILD_CFLAGS="$BUILD_CFLAGS -D_REENTRANT=1 -DSQLITE_THREADSAFE=1"
|
||||
AC_SEARCH_LIBS(pthread_create, pthread)
|
||||
AC_SEARCH_LIBS(pthread_mutexattr_init, pthread)
|
||||
|
||||
105
configure
vendored
105
configure
vendored
@@ -903,6 +903,7 @@ with_readline_inc
|
||||
enable_debug
|
||||
enable_amalgamation
|
||||
enable_load_extension
|
||||
enable_math
|
||||
enable_memsys5
|
||||
enable_memsys3
|
||||
enable_all
|
||||
@@ -1557,6 +1558,7 @@ Optional Features:
|
||||
separately
|
||||
--disable-load-extension
|
||||
Disable loading of external extensions
|
||||
--disable-math Disable math functions
|
||||
--enable-memsys5 Enable MEMSYS5
|
||||
--enable-memsys3 Enable MEMSYS3
|
||||
--enable-all Enable FTS4, FTS5, Geopoly, JSON, RTree, Sessions
|
||||
@@ -3935,13 +3937,13 @@ if ${lt_cv_nm_interface+:} false; then :
|
||||
else
|
||||
lt_cv_nm_interface="BSD nm"
|
||||
echo "int some_variable = 0;" > conftest.$ac_ext
|
||||
(eval echo "\"\$as_me:3938: $ac_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:3940: $ac_compile\"" >&5)
|
||||
(eval "$ac_compile" 2>conftest.err)
|
||||
cat conftest.err >&5
|
||||
(eval echo "\"\$as_me:3941: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
|
||||
(eval echo "\"\$as_me:3943: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
|
||||
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
|
||||
cat conftest.err >&5
|
||||
(eval echo "\"\$as_me:3944: output\"" >&5)
|
||||
(eval echo "\"\$as_me:3946: output\"" >&5)
|
||||
cat conftest.out >&5
|
||||
if $GREP 'External.*some_variable' conftest.out > /dev/null; then
|
||||
lt_cv_nm_interface="MS dumpbin"
|
||||
@@ -5147,7 +5149,7 @@ ia64-*-hpux*)
|
||||
;;
|
||||
*-*-irix6*)
|
||||
# Find out which ABI we are using.
|
||||
echo '#line 5150 "configure"' > conftest.$ac_ext
|
||||
echo '#line 5152 "configure"' > conftest.$ac_ext
|
||||
if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
|
||||
(eval $ac_compile) 2>&5
|
||||
ac_status=$?
|
||||
@@ -6672,11 +6674,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:6675: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:6677: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>conftest.err)
|
||||
ac_status=$?
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:6679: \$? = $ac_status" >&5
|
||||
echo "$as_me:6681: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s "$ac_outfile"; then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
# So say no if there are warnings other than the usual output.
|
||||
@@ -7011,11 +7013,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:7014: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:7016: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>conftest.err)
|
||||
ac_status=$?
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:7018: \$? = $ac_status" >&5
|
||||
echo "$as_me:7020: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s "$ac_outfile"; then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
# So say no if there are warnings other than the usual output.
|
||||
@@ -7116,11 +7118,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:7119: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:7121: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>out/conftest.err)
|
||||
ac_status=$?
|
||||
cat out/conftest.err >&5
|
||||
echo "$as_me:7123: \$? = $ac_status" >&5
|
||||
echo "$as_me:7125: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s out/conftest2.$ac_objext
|
||||
then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
@@ -7171,11 +7173,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:7174: $lt_compile\"" >&5)
|
||||
(eval echo "\"\$as_me:7176: $lt_compile\"" >&5)
|
||||
(eval "$lt_compile" 2>out/conftest.err)
|
||||
ac_status=$?
|
||||
cat out/conftest.err >&5
|
||||
echo "$as_me:7178: \$? = $ac_status" >&5
|
||||
echo "$as_me:7180: \$? = $ac_status" >&5
|
||||
if (exit $ac_status) && test -s out/conftest2.$ac_objext
|
||||
then
|
||||
# The compiler can only warn and ignore the option if not recognized
|
||||
@@ -9551,7 +9553,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 9554 "configure"
|
||||
#line 9556 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@@ -9647,7 +9649,7 @@ else
|
||||
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
||||
lt_status=$lt_dlunknown
|
||||
cat > conftest.$ac_ext <<_LT_EOF
|
||||
#line 9650 "configure"
|
||||
#line 9652 "configure"
|
||||
#include "confdefs.h"
|
||||
|
||||
#if HAVE_DLFCN_H
|
||||
@@ -11411,6 +11413,81 @@ else
|
||||
OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1"
|
||||
fi
|
||||
|
||||
##########
|
||||
# Do we want to support math functions
|
||||
#
|
||||
# Check whether --enable-math was given.
|
||||
if test "${enable_math+set}" = set; then :
|
||||
enableval=$enable_math;
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support math functions" >&5
|
||||
$as_echo_n "checking whether to support math functions... " >&6; }
|
||||
if test "$enable_math" = "no"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
$as_echo "yes" >&6; }
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_MATH_FUNCTIONS"
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing ceil" >&5
|
||||
$as_echo_n "checking for library containing ceil... " >&6; }
|
||||
if ${ac_cv_search_ceil+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_func_search_save_LIBS=$LIBS
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char ceil ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return ceil ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
for ac_lib in '' m; do
|
||||
if test -z "$ac_lib"; then
|
||||
ac_res="none required"
|
||||
else
|
||||
ac_res=-l$ac_lib
|
||||
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
|
||||
fi
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
ac_cv_search_ceil=$ac_res
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext
|
||||
if ${ac_cv_search_ceil+:} false; then :
|
||||
break
|
||||
fi
|
||||
done
|
||||
if ${ac_cv_search_ceil+:} false; then :
|
||||
|
||||
else
|
||||
ac_cv_search_ceil=no
|
||||
fi
|
||||
rm conftest.$ac_ext
|
||||
LIBS=$ac_func_search_save_LIBS
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_ceil" >&5
|
||||
$as_echo "$ac_cv_search_ceil" >&6; }
|
||||
ac_res=$ac_cv_search_ceil
|
||||
if test "$ac_res" != no; then :
|
||||
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
|
||||
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
##########
|
||||
# Do we want to support memsys3 and/or memsys5
|
||||
#
|
||||
|
||||
14
configure.ac
14
configure.ac
@@ -586,6 +586,20 @@ else
|
||||
OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1"
|
||||
fi
|
||||
|
||||
##########
|
||||
# Do we want to support math functions
|
||||
#
|
||||
AC_ARG_ENABLE(math,
|
||||
AC_HELP_STRING([--disable-math],[Disable math functions]))
|
||||
AC_MSG_CHECKING([whether to support math functions])
|
||||
if test "$enable_math" = "no"; then
|
||||
AC_MSG_RESULT([no])
|
||||
else
|
||||
AC_MSG_RESULT([yes])
|
||||
OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_MATH_FUNCTIONS"
|
||||
AC_SEARCH_LIBS(ceil, m)
|
||||
fi
|
||||
|
||||
##########
|
||||
# Do we want to support memsys3 and/or memsys5
|
||||
#
|
||||
|
||||
@@ -28,6 +28,7 @@ if {[info commands sqlite3_expert_new]==""} {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
set CLI [test_binary_name sqlite3]
|
||||
set CMD [test_binary_name sqlite3_expert]
|
||||
|
||||
@@ -367,6 +368,29 @@ do_setup_rec_test $tn.17.5 {
|
||||
SEARCH TABLE example USING INDEX example_idx_0000cb3f (B=? AND A>?)
|
||||
}
|
||||
|
||||
do_setup_rec_test $tn.18.0 {
|
||||
CREATE TABLE SomeObject (
|
||||
a INTEGER PRIMARY KEY,
|
||||
x TEXT GENERATED ALWAYS AS(HEX(a)) VIRTUAL
|
||||
);
|
||||
} {
|
||||
SELECT x FROM SomeObject;
|
||||
} {
|
||||
(no new indexes)
|
||||
SCAN TABLE SomeObject
|
||||
}
|
||||
do_setup_rec_test $tn.18.1 {
|
||||
CREATE TABLE SomeObject (
|
||||
a INTEGER PRIMARY KEY,
|
||||
x TEXT GENERATED ALWAYS AS(HEX(a)) VIRTUAL
|
||||
);
|
||||
} {
|
||||
SELECT * FROM SomeObject WHERE x=?;
|
||||
} {
|
||||
CREATE INDEX SomeObject_idx_00000078 ON SomeObject(x);
|
||||
SEARCH TABLE SomeObject USING COVERING INDEX SomeObject_idx_00000078 (x=?)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
proc do_candidates_test {tn sql res} {
|
||||
@@ -430,5 +454,5 @@ do_execsql_test 5.3 {
|
||||
t2 t2_idx_0001295b {100 20 5}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -687,7 +687,7 @@ static int idxGetTableInfo(
|
||||
char *pCsr = 0;
|
||||
int nPk = 0;
|
||||
|
||||
rc = idxPrintfPrepareStmt(db, &p1, pzErrmsg, "PRAGMA table_info=%Q", zTab);
|
||||
rc = idxPrintfPrepareStmt(db, &p1, pzErrmsg, "PRAGMA table_xinfo=%Q", zTab);
|
||||
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(p1) ){
|
||||
const char *zCol = (const char*)sqlite3_column_text(p1, 1);
|
||||
nByte += 1 + STRLEN(zCol);
|
||||
|
||||
@@ -1500,8 +1500,8 @@ int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, i64 iFirst, int bDesc){
|
||||
}
|
||||
|
||||
/* If the iterator is not at a real match, skip forward until it is. */
|
||||
while( pRoot->bNomatch ){
|
||||
assert( pRoot->bEof==0 && rc==SQLITE_OK );
|
||||
while( pRoot->bNomatch && rc==SQLITE_OK ){
|
||||
assert( pRoot->bEof==0 );
|
||||
rc = fts5ExprNodeNext(p, pRoot, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
|
||||
@@ -10509,6 +10509,134 @@ do_catchsql_test 71.2 {
|
||||
INSERT INTO t1(t1) VALUES('integrity-check');
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_test 72.0 {
|
||||
sqlite3 db {}
|
||||
db deserialize [decode_hexdb {
|
||||
.open --hexdb
|
||||
| size 24576 pagesize 4096 filename crash-77b86d070d0ac6.db
|
||||
| page 1 offset 0
|
||||
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
|
||||
| 16: 10 00 01 01 00 40 20 20 00 00 00 00 00 00 00 06 .....@ ........
|
||||
| 32: 00 00 00 00 00 00 00 00 00 00 00 06 00 00 00 04 ................
|
||||
| 96: 00 00 00 00 0d 00 00 00 06 0d e2 00 0f c4 0f 6a ...............j
|
||||
| 112: 0e fc 0e 9d 0e 3d 0d e2 00 00 00 00 00 00 00 00 .....=..........
|
||||
| 3552: 00 00 59 06 06 17 21 21 01 7f 74 61 62 6c 65 74 ..Y...!!..tablet
|
||||
| 3568: 74 74 5f 63 6f 6e 66 69 67 74 74 74 5f 63 6f 6e tt_configttt_con
|
||||
| 3584: 66 69 67 06 43 52 45 41 54 45 20 54 41 42 4c 45 fig.CREATE TABLE
|
||||
| 3600: 20 27 74 74 74 5f 63 6f 6e 66 69 67 27 28 6b 20 'ttt_config'(k
|
||||
| 3616: 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 20 PRIMARY KEY, v)
|
||||
| 3632: 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5e 05 07 WITHOUT ROWID^..
|
||||
| 3648: 17 23 23 01 81 03 74 61 62 6c 65 74 74 74 5f 64 .##...tablettt_d
|
||||
| 3664: 6f 63 73 69 7a 65 74 74 74 5f 64 6f 63 73 69 7a ocsizettt_docsiz
|
||||
| 3680: 65 05 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 e.CREATE TABLE '
|
||||
| 3696: 74 74 74 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 ttt_docsize'(id
|
||||
| 3712: 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 INTEGER PRIMARY
|
||||
| 3728: 4b 45 59 2c 20 73 7a 20 42 4c 4f 42 29 5d 04 07 KEY, sz BLOB)]..
|
||||
| 3744: 17 23 23 01 81 01 74 61 62 6c 65 74 74 74 5f 63 .##...tablettt_c
|
||||
| 3760: 6f 6e 74 65 6e 74 74 74 74 5f 63 6f 6e 74 65 6e ontentttt_conten
|
||||
| 3776: 74 04 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 t.CREATE TABLE '
|
||||
| 3792: 74 74 74 5f 63 6f 6e 74 65 6e 74 27 28 69 64 20 ttt_content'(id
|
||||
| 3808: 49 4e 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 INTEGER PRIMARY
|
||||
| 3824: 4b 45 59 2c 20 63 30 2c 20 63 31 29 6c 03 07 17 KEY, c0, c1)l...
|
||||
| 3840: 1b 1b 01 81 2f 74 61 62 6c 65 74 74 74 5f 69 64 ..../tablettt_id
|
||||
| 3856: 78 74 74 74 5f 69 64 78 03 43 52 45 41 54 45 20 xttt_idx.CREATE
|
||||
| 3872: 54 41 42 4c 45 20 27 74 74 74 5f 69 64 78 27 28 TABLE 'ttt_idx'(
|
||||
| 3888: 73 65 67 69 64 2c 20 74 65 72 6d 2c 20 70 67 6e segid, term, pgn
|
||||
| 3904: 6f 2c 20 50 52 49 4d 41 52 59 20 4b 45 59 28 73 o, PRIMARY KEY(s
|
||||
| 3920: 65 67 69 64 2c 20 74 65 72 6d 29 29 20 57 49 54 egid, term)) WIT
|
||||
| 3936: 48 4f 55 54 20 52 4f 57 49 44 58 02 07 17 1d 1d HOUT ROWIDX.....
|
||||
| 3952: 01 81 03 74 61 62 6c 65 74 74 74 5f 64 61 74 61 ...tablettt_data
|
||||
| 3968: 74 74 74 5f 64 61 74 61 02 43 52 45 41 54 45 20 ttt_data.CREATE
|
||||
| 3984: 54 41 42 4c 45 20 27 74 74 74 5f 64 61 74 61 27 TABLE 'ttt_data'
|
||||
| 4000: 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d (id INTEGER PRIM
|
||||
| 4016: 41 52 59 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 ARY KEY, block B
|
||||
| 4032: 4c 4f 42 29 3a 01 06 17 13 13 08 5f 74 61 62 6c LOB):......_tabl
|
||||
| 4048: 65 74 74 74 74 74 74 43 52 45 41 54 45 20 56 49 ettttttCREATE VI
|
||||
| 4064: 52 54 55 41 4c 20 54 41 42 4c 45 20 74 74 74 20 RTUAL TABLE ttt
|
||||
| 4080: 55 53 49 4e 47 20 66 74 73 35 28 61 2c 20 62 29 USING fts5(a, b)
|
||||
| page 2 offset 4096
|
||||
| 0: 0d 0f 44 00 05 0e 81 00 0f e7 0e 81 0f af 0f 58 ..D............X
|
||||
| 16: 0e 98 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 3712: 00 15 0a 03 00 30 00 00 00 00 01 03 03 00 03 01 .....0..........
|
||||
| 3728: 01 01 02 01 01 03 01 01 81 24 8c 80 80 80 80 01 .........$......
|
||||
| 3744: 04 00 82 4c 00 00 00 9b 02 30 65 03 1a 02 05 05 ...L.....0e.....
|
||||
| 3760: 07 05 01 01 04 03 03 08 03 03 01 2e 02 05 05 07 ................
|
||||
| 3776: 05 07 05 07 05 01 01 04 03 03 08 03 03 08 03 03 ................
|
||||
| 3792: 08 03 03 02 01 65 03 1e 03 05 05 04 05 05 01 01 .....e..........
|
||||
| 3808: 03 06 04 04 06 04 03 01 36 03 05 05 04 05 05 04 ........6.......
|
||||
| 3824: 05 05 04 05 05 01 01 03 06 04 04 06 04 04 06 04 ................
|
||||
| 3840: 04 06 04 03 03 01 65 03 14 04 05 07 05 05 01 01 ......e.........
|
||||
| 3856: 02 08 0a 01 20 04 05 07 05 07 05 07 05 05 01 01 .... ...........
|
||||
| 3872: 02 08 0a 09 fa 04 01 65 03 02 0a 01 06 0a 1a 0a .......e........
|
||||
| 3888: 05 01 65 03 06 01 01 0a 01 0a 01 01 0a 0a 0a 04 ..e.............
|
||||
| 3904: 2b 31 21 0b 0f ef 00 14 2a 00 00 00 00 01 02 02 +1!.....*.......
|
||||
| 3920: 00 02 01 01 01 02 01 01 50 88 80 80 80 80 01 04 ........P.......
|
||||
| 3936: 00 81 24 00 00 00 47 02 30 65 02 1a 02 05 05 07 ..$...G.0e......
|
||||
| 3952: 05 01 01 04 03 03 08 03 03 02 01 65 02 1e 03 05 ...........e....
|
||||
| 3968: 05 04 05 05 01 01 03 06 04 04 06 04 03 03 01 65 ...............e
|
||||
| 3984: 02 14 04 05 07 05 05 01 01 02 08 0a 04 01 65 02 ..............e.
|
||||
| 4000: 02 0a 05 01 65 02 06 01 01 0a 04 12 14 0f 06 31 ....e..........1
|
||||
| 4016: 84 80 80 80 80 01 03 00 68 00 00 00 2b 02 30 65 ........h...+.0e
|
||||
| 4032: 01 10 02 05 05 01 01 04 03 9f 02 01 65 01 12 03 ............e...
|
||||
| 4048: 05 05 01 01 03 06 04 03 03 01 65 01 0e 14 05 05 ..........e.....
|
||||
| 4064: 01 01 02 08 04 0d 0e 06 01 03 00 12 04 4c 4c 00 .............LL.
|
||||
| 4080: 00 00 11 24 00 00 00 00 01 01 01 00 01 01 01 01 ...$............
|
||||
| page 3 offset 8192
|
||||
| 0: 0a 00 00 00 03 0f 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 4064: 00 00 00 00 00 00 00 00 00 00 00 00 06 04 01 0c ................
|
||||
| 4080: 01 03 02 06 04 01 0c 01 02 02 05 04 09 0c 01 02 ................
|
||||
| page 4 offset 12288
|
||||
| 0: 0d 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 3600: 00 00 00 00 00 00 00 00 00 00 81 52 04 06 00 81 ...........R....
|
||||
| 3616: 5d 81 55 65 20 65 65 20 65 65 65 20 65 20 65 65 ].Ue ee eee e ee
|
||||
| 3632: 20 65 65 65 20 65 20 65 65 20 65 65 65 65 20 65 eee e ee eeee e
|
||||
| 3648: 65 20 65 65 65 20 65 20 65 65 20 65 65 65 20 65 e eee e ee eee e
|
||||
| 3664: 20 65 65 20 65 65 55 65 20 65 65 20 65 65 65 20 ee eeUe ee eee
|
||||
| 3680: 65 20 65 65 20 65 65 65 20 65 20 65 65 20 65 65 e ee eee e ee ee
|
||||
| 3696: 65 65 20 65 65 20 65 65 65 20 65 20 65 65 20 65 ee ee eee e ee e
|
||||
| 3712: 65 65 20 65 20 65 65 20 65 65 65 65 65 65 20 65 ee e ee eeeeee e
|
||||
| 3728: 65 20 65 20 65 20 65 20 65 65 20 65 85 65 20 65 e e e e ee e.e e
|
||||
| 3744: 65 20 65 65 65 65 65 20 65 65 20 65 20 65 20 65 e eeeee ee e e e
|
||||
| 3760: 20 65 65 20 65 65 65 20 65 65 20 65 65 65 65 65 ee eee ee eeeee
|
||||
| 3776: 20 65 65 20 65 20 65 20 65 20 65 65 20 65 65 65 ee e e e ee eee
|
||||
| 3792: 20 65 65 20 65 65 65 65 65 20 65 65 20 65 20 65 ee eeeee ee e e
|
||||
| 3808: 20 65 20 65 65 20 65 65 65 20 65 65 20 65 65 6a e ee eee ee eej
|
||||
| 3824: 03 04 00 75 71 65 20 65 65 20 65 65 65 20 65 20 ...uqe ee eee e
|
||||
| 3840: 65 65 20 65 65 65 20 65 20 65 65 20 65 65 65 65 ee eee e ee eeee
|
||||
| 3856: 20 65 65 20 65 65 65 20 65 20 65 65 20 65 65 65 ee eee e ee eee
|
||||
| 3872: 20 65 20 65 65 20 65 65 65 65 65 65 20 65 65 20 e ee eeeeee ee
|
||||
| 3888: 65 20 65 20 65 20 65 64 20 65 65 65 20 65 65 20 e e e ed eee ee
|
||||
| 3904: 65 65 65 65 65 20 65 65 20 65 20 65 20 65 10 65 eeeee ee e e e.e
|
||||
| 3920: 65 20 65 65 65 10 65 65 20 65 65 6a 02 04 00 75 e eee.ee eej...u
|
||||
| 3936: 71 65 20 65 65 20 65 65 65 20 65 20 65 65 20 65 qe ee eee e ee e
|
||||
| 3952: 65 65 20 65 20 65 65 20 65 65 65 65 20 65 65 20 ee e ee eeee ee
|
||||
| 3968: 65 65 65 20 65 20 65 65 20 65 65 65 20 65 20 65 eee e ee eee e e
|
||||
| 3984: 65 20 65 65 65 66 65 65 20 65 65 20 65 20 65 20 e eeefee ee e e
|
||||
| 4000: 65 88 65 65 20 65 65 65 30 65 65 20 65 65 65 65 e.ee eee0ee eeee
|
||||
| 4016: 65 20 65 65 20 65 20 65 20 65 20 65 65 20 65 65 e ee e e e ee ee
|
||||
| 4032: 65 20 65 65 20 65 65 37 01 04 00 41 3f 65 20 65 e ee ee7...A?e e
|
||||
| 4048: 65 20 65 65 65 20 65 20 65 65 20 65 65 65 20 65 e eee e ee eee e
|
||||
| 4064: 20 65 65 20 65 65 65 65 65 65 20 65 65 20 65 20 ee eeeeee ee e
|
||||
| 4080: 65 20 65 20 65 65 20 65 65 65 20 65 65 20 65 65 e e ee eee ee ee
|
||||
| page 5 offset 16384
|
||||
| 0: 0d 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 4064: 00 00 00 00 05 04 03 00 10 21 21 05 03 03 00 10 .........!!.....
|
||||
| 4080: 11 11 05 02 03 00 10 11 11 05 01 03 00 10 09 09 ................
|
||||
| page 6 offset 20480
|
||||
| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
|
||||
| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
|
||||
| end crash-77b86d070d0ac6.db
|
||||
}]} {}
|
||||
|
||||
do_catchsql_test 72.1 {
|
||||
INSERT INTO ttt(ttt) VALUES('integrity-check');
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
do_catchsql_test 72.1 {
|
||||
SELECT 1 FROM ttt('e* NOT ee*');
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
sqlite3_fts5_may_be_corrupt 0
|
||||
finish_test
|
||||
|
||||
@@ -91,6 +91,27 @@ do_catchsql_test 2.4 {
|
||||
SELECT rowid FROM test_idx WHERE test_idx MATCH 'two' ORDER BY rank;
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE tx USING fts5(a, b, c, d, content=);
|
||||
INSERT INTO tx(rowid, a, c) VALUES(1, 'abc def', 'a b c');
|
||||
INSERT INTO tx(rowid, a, c) VALUES(5, 'a b c', 'a b d def');
|
||||
}
|
||||
do_execsql_test 3.1 {
|
||||
INSERT INTO tx(tx, rowid, a, b, c, d)
|
||||
VALUES('delete', 5, 'a b c', NULL, 'a b d def', NULL);
|
||||
}
|
||||
do_execsql_test 3.2 {
|
||||
INSERT INTO tx(tx) VALUES('integrity-check');
|
||||
}
|
||||
do_execsql_test 3.3 {
|
||||
INSERT INTO tx(tx, rowid, a, b, c, d)
|
||||
VALUES('delete', 1, 'abc def', NULL, 'a b c', NULL);
|
||||
}
|
||||
do_execsql_test 3.4 {
|
||||
INSERT INTO tx(tx) VALUES('integrity-check');
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -356,6 +356,41 @@ static void cksmVerifyFunc(
|
||||
sqlite3_result_int(context, memcmp(data+nByte-8,cksum,8)==0);
|
||||
}
|
||||
|
||||
#ifdef SQLITE_CKSUMVFS_INIT_FUNCNAME
|
||||
/*
|
||||
** SQL function: initialize_cksumvfs(SCHEMANAME)
|
||||
**
|
||||
** This SQL functions (whose name is actually determined at compile-time
|
||||
** by the value of the SQLITE_CKSUMVFS_INIT_FUNCNAME macro) invokes:
|
||||
**
|
||||
** sqlite3_file_control(db, SCHEMANAME, SQLITE_FCNTL_RESERVE_BYTE, &n);
|
||||
**
|
||||
** In order to set the reserve bytes value to 8, so that cksumvfs will
|
||||
** operation. This feature is provided (if and only if the
|
||||
** SQLITE_CKSUMVFS_INIT_FUNCNAME compile-time option is set to a string
|
||||
** which is the name of the SQL function) so as to provide the ability
|
||||
** to invoke the file-control in programming languages that lack
|
||||
** direct access to the sqlite3_file_control() interface (ex: Java).
|
||||
**
|
||||
** This interface is undocumented, apart from this comment. Usage
|
||||
** example:
|
||||
**
|
||||
** 1. Compile with -DSQLITE_CKSUMVFS_INIT_FUNCNAME="ckvfs_init"
|
||||
** 2. Run: "SELECT cksum_init('main'); VACUUM;"
|
||||
*/
|
||||
static void cksmInitFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
int nByte = 8;
|
||||
const char *zSchemaName = (const char*)sqlite3_value_text(argv[0]);
|
||||
sqlite3 *db = sqlite3_context_db_handle(context);
|
||||
sqlite3_file_control(db, zSchemaName, SQLITE_FCNTL_RESERVE_BYTES, &nByte);
|
||||
/* Return NULL */
|
||||
}
|
||||
#endif /* SQLITE_CKSUMBFS_INIT_FUNCNAME */
|
||||
|
||||
/*
|
||||
** Close a cksm-file.
|
||||
*/
|
||||
@@ -746,6 +781,11 @@ static int cksmRegisterFunc(
|
||||
rc = sqlite3_create_function(db, "verify_checksum", 1,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
|
||||
0, cksmVerifyFunc, 0, 0);
|
||||
#ifdef SQLITE_CKSUMVFS_INIT_FUNCNAME
|
||||
(void)sqlite3_create_function(db, SQLITE_CKSUMVFS_INIT_FUNCNAME, 1,
|
||||
SQLITE_UTF8|SQLITE_DIRECTONLY,
|
||||
0, cksmInitFunc, 0, 0);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,10 @@ SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifndef SQLITE_AMALGAMATION
|
||||
typedef sqlite3_uint64 u64;
|
||||
#endif /* SQLITE_AMALGAMATION */
|
||||
|
||||
/******************************************************************************
|
||||
** The Hash Engine
|
||||
|
||||
@@ -183,6 +183,13 @@ int main(int argc, char **argv){
|
||||
break;
|
||||
}
|
||||
|
||||
if( nStatStep>0 ){
|
||||
sqlite3_int64 nUsed;
|
||||
sqlite3_int64 nHighwater;
|
||||
sqlite3_status64(SQLITE_STATUS_MEMORY_USED, &nUsed, &nHighwater, 0);
|
||||
fprintf(stdout, "memory used=%lld highwater=%lld\n", nUsed, nHighwater);
|
||||
}
|
||||
|
||||
sqlite3_free(zErrmsg);
|
||||
return (rc==SQLITE_OK || rc==SQLITE_DONE) ? 0 : 1;
|
||||
}
|
||||
|
||||
70
manifest
70
manifest
@@ -1,11 +1,11 @@
|
||||
C Update\sthis\sbranch\swith\slatest\strunk\schanges.
|
||||
D 2020-12-04T18:47:28.471
|
||||
C Merge\slatest\strunk\schanges\sinto\sthis\sbranch.
|
||||
D 2020-12-17T11:30:12.233
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
F Makefile.in 2ebc6d03e09710d5dddc6e8417276ff8ef7bfaaa0cb6ced02791889f2601560f
|
||||
F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241
|
||||
F Makefile.msc ced17643f4198195bfce76310930ee6f2ebdf8ba2e0d6f7ab1f361fa2cc650a3
|
||||
F Makefile.msc adc7fa1be430e6081e07bfafb2f14032dbb5ff056d1c812c634382815ececc81
|
||||
F README.md 1514a365ffca3c138e00c5cc839906108a01011a6b082bad19b09781e3aa498a
|
||||
F VERSION 92f3e4c5cdee6f0779aef1eae857dfc21d0eabb1f2af169dc90e63cd76b15bb2
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
@@ -18,7 +18,7 @@ F autoconf/Makefile.fallback 22fe523eb36dfce31e0f6349f782eb084e86a5620b2b0b4f84a
|
||||
F autoconf/Makefile.msc e0f1dafc48d000fd6ddfdb01815271528db55cbc7299ca888df5b93367f0d5a4
|
||||
F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7
|
||||
F autoconf/README.txt 4f04b0819303aabaa35fff5f7b257fb0c1ef95f1
|
||||
F autoconf/configure.ac 3cd933b959fe514eebd1ca1717dfddbf2c9b825b6bc2c5f744deaf5d63af9288
|
||||
F autoconf/configure.ac 55be6fc04a5b030b367fe317b72dc8c0eafc4713991fe6182cf647b02fb782cb
|
||||
F autoconf/tea/Makefile.in b438a7020446c8a8156e8d97c8914a04833da6fd
|
||||
F autoconf/tea/README 3e9a3c060f29a44344ab50aec506f4db903fb873
|
||||
F autoconf/tea/aclocal.m4 52c47aac44ce0ddb1f918b6993e8beb8eee88f43
|
||||
@@ -34,8 +34,8 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63
|
||||
F config.guess 883205ddf25b46f10c181818bf42c09da9888884af96f79e1719264345053bd6
|
||||
F config.h.in 6376abec766e9a0785178b1823b5a587e9f1ccbc
|
||||
F config.sub c2d0260f17f3e4bc0b6808fccf1b291cb5e9126c14fc5890efc77b9fd0175559
|
||||
F configure 73234664de11cb7f1f1b198fe6775d8b0f01d25480d325a7b9f9645675bf6b79 x
|
||||
F configure.ac 73545c21eebcef9398d85c982c7be260f07708256778221b541f83ae8c6f61eb
|
||||
F configure 7736c168f4fd717c8052e58428a89e645d15cf0e5a3d051e248aad859a3cb140 x
|
||||
F configure.ac efdb70036084ea637226e378a14f932e70c0df9f1bc846a24a909c0e1613524a
|
||||
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
|
||||
F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd
|
||||
F doc/lemon.html c5d8ba85ac1daef7be8c2d389899480eb62451ff5c09b0c28ff8157bb8770746
|
||||
@@ -51,8 +51,8 @@ F ext/async/sqlite3async.c 6f247666b495c477628dd19364d279c78ea48cd90c72d9f9b98ad
|
||||
F ext/async/sqlite3async.h 46b47c79357b97ad85d20d2795942c0020dc20c532114a49808287f04aa5309a
|
||||
F ext/expert/README.md b321c2762bb93c18ea102d5a5f7753a4b8bac646cb392b3b437f633caf2020c3
|
||||
F ext/expert/expert.c d548d603a4cc9e61f446cc179c120c6713511c413f82a4a32b1e1e69d3f086a4
|
||||
F ext/expert/expert1.test dba6e752cc701621771f925f3872b183fa688f7b4a9f4822631fc02bdbffc45a
|
||||
F ext/expert/sqlite3expert.c 216e250acc54b8aaa9ff5c1e1b2256788abc3994dd1d757626102718122e6a91
|
||||
F ext/expert/expert1.test 63d778d964e55ef2d1a723043d91c59e7dc6ef1649d91c78c0bef00f9c6f1427
|
||||
F ext/expert/sqlite3expert.c de51b187c629a4c4264d5de0b77862641e11426f7a963a92abf2d4077085fc8c
|
||||
F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b
|
||||
F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72
|
||||
F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e
|
||||
@@ -118,7 +118,7 @@ F ext/fts5/fts5Int.h 26c74dd5776f798436fbf604a0bf0e8de263b35b5060b05c15f9085845d
|
||||
F ext/fts5/fts5_aux.c f558e1fb9f0f86a4f7489e258c162e1f947de5ff2709087fbb465fddb7092f98
|
||||
F ext/fts5/fts5_buffer.c 5a5fe0159752c0fb0a5a93c722e9db2662822709490769d482b76a6dc8aaca70
|
||||
F ext/fts5/fts5_config.c be54f44fca491e96c6923a4b9a736f2da2b13811600eb6e38d1bcc91c4ea2e61
|
||||
F ext/fts5/fts5_expr.c e527e3a7410393075598cec544e3831798a8c88b3e8878e2cfb7cb147113e925
|
||||
F ext/fts5/fts5_expr.c 016bd06030679bd31b0f07ef87d62c42031e5da25cb3174a84e5b0f6ef4b47b0
|
||||
F ext/fts5/fts5_hash.c 1aa93c9b5f461afba66701ee226297dc78402b3bdde81e90a10de5fe3df14959
|
||||
F ext/fts5/fts5_index.c 7be3a7dcf4458a2d58a1c6ae0290921c9df226bff7eb9bc82f14e667b27aeb20
|
||||
F ext/fts5/fts5_main.c b4e4931c7fcc9acfa0c3b8b5e5e80b5b424b8d9207aae3a22b674bd35ccf149d
|
||||
@@ -161,9 +161,9 @@ F ext/fts5/test/fts5connect.test 08030168fc96fc278fa81f28654fb7e90566f33aff269c0
|
||||
F ext/fts5/test/fts5content.test 213506436fb2c87567b8e31f6d43ab30aab99354cec74ed679f22aad0cdbf283
|
||||
F ext/fts5/test/fts5corrupt.test 77ae6f41a7eba10620efb921cf7dbe218b0ef232b04519deb43581cb17a57ebe
|
||||
F ext/fts5/test/fts5corrupt2.test 7453752ba12ce91690c469a6449d412561cc604b1dec994e16ab132952e7805f
|
||||
F ext/fts5/test/fts5corrupt3.test 1c26a651ea7e52fd69d54436fe4f02f6dd1268bc8b48ab851c7e1d374aa242b9
|
||||
F ext/fts5/test/fts5corrupt3.test 6de9f4f73fec1d996460d2f65576590e1e7074f9c28b8db9c19287c588c6f552
|
||||
F ext/fts5/test/fts5corrupt4.test f4c08e2182a48d8b70975fd869ee5391855c06d8a0ff87b6a2529e7c5a88a1d3
|
||||
F ext/fts5/test/fts5delete.test 4a15fb03b6c7eac62ac807a3a32b7f0dc74f0d479c410e3e3568ae96b9469290
|
||||
F ext/fts5/test/fts5delete.test 619295b20dbc1d840b403ee07c878f52378849c3c02e44f2ee143b3e978a0aa7
|
||||
F ext/fts5/test/fts5detail.test 31b240dbf6d44ac3507e2f8b65f29fdc12465ffd531212378c7ce1066766f54e
|
||||
F ext/fts5/test/fts5determin.test 1b77879b2ae818b5b71c859e534ee334dac088b7cf3ff3bf76a2c82b1c788d11
|
||||
F ext/fts5/test/fts5dlidx.test b90852c55881b29dbac6380b274de27beae623ac4b6d567c6c8fb9cdc315a86e
|
||||
@@ -292,7 +292,7 @@ F ext/misc/blobio.c a867c4c4617f6ec223a307ebfe0eabb45e0992f74dd47722b96f3e631c0e
|
||||
F ext/misc/btreeinfo.c d28ce349b40054eaa9473e835837bad7a71deec33ba13e39f963d50933bfa0f9
|
||||
F ext/misc/carray.c b75a0f207391038bf1540d3372f482a95c3613511c7c474db51ede1196321c7c
|
||||
F ext/misc/carray.h de74ac70b2338f416723f7d538026e8ec0b7f1d388319f8f140c9a4d7677f02e
|
||||
F ext/misc/cksumvfs.c c4e7ebeae5aa578df98f23bddb63ecbcbe913ee3c32b8b769525af100d752061
|
||||
F ext/misc/cksumvfs.c 688a59d6c5dc7e7e0aba09654d8cbeeb7d04bad8cf57902df86aa06c2f723ff4
|
||||
F ext/misc/closure.c dbfd8543b2a017ae6b1a5843986b22ddf99ff126ec9634a2f4047cd14c85c243
|
||||
F ext/misc/completion.c 6dafd7f4348eecc7be9e920d4b419d1fb2af75d938cd9c59a20cfe8beb2f22b9
|
||||
F ext/misc/compress.c 3354c77a7c8e86e07d849916000cdac451ed96500bfb5bd83b20eb61eee012c9
|
||||
@@ -322,7 +322,7 @@ F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d385
|
||||
F ext/misc/scrub.c 2a44b0d44c69584c0580ad2553f6290a307a49df4668941d2812135bfb96a946
|
||||
F ext/misc/series.c c6bd5d249e5199a1b55aeee4d0e6576ff3a68702fc475dbd64503a32903516c7
|
||||
F ext/misc/sha1.c c8f2253c8792ffab9517695ea7d88c079f0395a5505eefef5c8198fe184ed5ac
|
||||
F ext/misc/shathree.c 135b7c145db4a09b1650c3e7aff9cb538763a9a361e834c015dd1aaf8d5c9a00
|
||||
F ext/misc/shathree.c 5398f945a30b4792c757ab16b03cf54ce3b542fe933bbd43e2d6d40c5443b12e
|
||||
F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
|
||||
F ext/misc/spellfix.c 94df9bbfa514a563c1484f684a2df3d128a2f7209a84ca3ca100c68a0163e29f
|
||||
F ext/misc/sqlar.c 0ace5d3c10fe736dc584bf1159a36b8e2e60fab309d310cd8a0eecd9036621b6
|
||||
@@ -340,7 +340,7 @@ F ext/misc/vtshim.c 1976e6dd68dd0d64508c91a6dfab8e75f8aaf6cd
|
||||
F ext/misc/wholenumber.c 520f34c3099e5b7d546f13708607dc2fa173c46b68952eecf0d19cd675fec85e
|
||||
F ext/misc/zipfile.c e35e035bc2765b1ccdcb15f9815c2112843fcbc8f36aa071f0e5935df7072228
|
||||
F ext/misc/zorder.c b0ff58fa643afa1d846786d51ea8d5c4b6b35aa0254ab5a82617db92f3adda64
|
||||
F ext/rbu/rbu.c 8681f6157db6adc82c34af24b14ea8a3be0146ad2a3b6c1d5da6cb8a5796c8ce
|
||||
F ext/rbu/rbu.c b880ca5cb857d6d6f52e72eb7397813058ef48c78c5402cd04ff2b6b5437f622
|
||||
F ext/rbu/rbu1.test 221d9c18a5e600ac9ac6b1810d99d9f99163a7909ba61597876ab6e4d4beb3d6
|
||||
F ext/rbu/rbu10.test 0a201c32202143f23c81c0144503da339786fc20acb7a2fda11601b65659f314
|
||||
F ext/rbu/rbu11.test 5c834cf491086b45e071eabf71f708febc143e86a384a92de69e0b1a4cace144
|
||||
@@ -482,13 +482,13 @@ F src/auth.c a3d5bfdba83d25abed1013a8c7a5f204e2e29b0c25242a56bc02bb0c07bf1e06
|
||||
F src/backup.c 3014889fa06e20e6adfa0d07b60097eec1f6e5b06671625f476a714d2356513d
|
||||
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
||||
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
|
||||
F src/btree.c ee14224322b9e4172d01e691e2f289f6c630ae39b7906f84b72dc780b9e42a76
|
||||
F src/btree.h dcdff4037d75b3f032a5de0d922fcfaf35d48589417f634fa8627362709315f9
|
||||
F src/btreeInt.h ffd66480520d9d70222171b3a026d78b80833b5cea49c89867949f3e023d5f43
|
||||
F src/btree.c 0f9cb686871ae668817673f0823b55d1bcadbc86ea28bd22c590b064a8322d5a
|
||||
F src/btree.h 285f8377aa1353185a32bf455faafa9ff9a0d40d074d60509534d14990c7829e
|
||||
F src/btreeInt.h 7614cae30f95b6aed0c7cac7718276a55cfe2c77058cbfd8bef5b75329757331
|
||||
F src/build.c 33e7b9f5d7c574148d54fe62fd997341adc3d411a3fae42e5aaa3528214ef238
|
||||
F src/callback.c d8cdf5d697a31cf54a2b64bce9001fe24f3522a566f44c9fe1eb3a0c7e291c56
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c f5eaef0a5985fab6fc21e8b00aeaea1ca862a09c1ea5e505b0ad1da157eec247
|
||||
F src/ctime.c fbb38984bd42a7119829603ebc1323ed3623c1bf0b521e9b77508c1e52d476d8
|
||||
F src/date.c dace306a10d9b02ee553d454c8e1cf8d3c9b932e137738a6b15b90253a9bfc10
|
||||
F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a
|
||||
F src/dbstat.c 3aa79fc3aed7ce906e4ea6c10e85d657299e304f6049861fe300053ac57de36c
|
||||
@@ -496,13 +496,13 @@ F src/delete.c 927cf8f900583e79aca8f1a321979e0a8f053babd9a690b44b38f79de2cc09fe
|
||||
F src/expr.c 0d196ed5a2ebf96be7e8df88add4fabfad0dce16c0fed81a4b8f6a26e259797f
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 6cf1e15c986e5a393399ce337e4c085bf872117b8b095b04c79ae39d1f6a069a
|
||||
F src/func.c 574f7e5a67e4b7a7855cf3478037717c8f44686c0cd727e1d7f7773414165c03
|
||||
F src/func.c 2163afb2cfabb71768f9254b95dbab3b7d4cd94394f6cffb86704e0b7e6ccabe
|
||||
F src/global.c ed55af196a9b66e198aaeda3f5454c3aa7d7d050c6c938181fd044b70d180a81
|
||||
F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19
|
||||
F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38
|
||||
F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c 7e081d33aab4a9d761c39dccf3c3872c35501565d2ed9db66301918d23bc7901
|
||||
F src/insert.c 7300982986b0aae32382ce57438998b92efa64e9a7169378e83c1c5d0e2ecdb3
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c 8c9c8cd2bd8eecdb06d9b6e89de7e9e65bae45cc8fc33609cc74023a5c296067
|
||||
F src/main.c 72b8badf580e56e4d9043075b1fe481bd260441491527c9d2b53de22e2bdf9ee
|
||||
@@ -530,7 +530,7 @@ F src/os_win.c 77d39873836f1831a9b0b91894fec45ab0e9ca8e067dc8c549e1d1eca1566fe9
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c c49952ac5e9cc536778eff528091d79d38b3e45cbeeed4695dc05e207dc6547d
|
||||
F src/pager.h 4bf9b3213a4b2bebbced5eaa8b219cf25d4a82f385d093cd64b7e93e5285f66f
|
||||
F src/parse.y 9ce4dfb772608ed5bd3c32f33e943e021e3b06cfd2c01932d4280888fdd2ebed
|
||||
F src/parse.y 6c8aa09a7fa6e0867c3a3d67ef61b911aa392c9b084a61dc632cd93732aef8ad
|
||||
F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177
|
||||
F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
|
||||
F src/pcache1.c 6596e10baf3d8f84cc1585d226cf1ab26564a5f5caf85a15757a281ff977d51a
|
||||
@@ -543,10 +543,10 @@ F src/resolve.c 1948a92ca9eab776632816b97e57c61d933474a78aad4f4ef835c916a83dbb1c
|
||||
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
|
||||
F src/select.c c9b68506e5d8cc8d0e4b307b97a9800b050ac37dada80ae9c66f680f8fac3e09
|
||||
F src/shell.c.in e18bd7ab9f43919f26a5dafc3d22f9286913216163ea7911438d7c2cade91f59
|
||||
F src/sqlite.h.in a730b36fdb3f418ef98066a41878c6a4d4f8b34d0425853adda0cda704deb80e
|
||||
F src/sqlite.h.in cdee22392f1d6ca1437a8d112079252ead4e9fd85f8a3077c19a2b0a0338cce2
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e
|
||||
F src/sqliteInt.h c62e228ba6f2eac15bad42812f148f48f16195531ce7994f6d5efb9aac212bd7
|
||||
F src/sqliteInt.h a697022ddc03711530fd1f29b187f3148c1d268c2665ba1838f1ad90d483d5cf
|
||||
F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
|
||||
F src/status.c d0956e57c71160155f620a3efeb1e5c05a3f8b9a897dd09c5263268e5d237579
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
@@ -566,7 +566,7 @@ F src/test_backup.c bf5da90c9926df0a4b941f2d92825a01bbe090a0
|
||||
F src/test_bestindex.c 78809f11026f18a93fcfd798d9479cba37e1201c830260bf1edc674b2fa9b857
|
||||
F src/test_blob.c ae4a0620b478548afb67963095a7417cd06a4ec0a56adb453542203bfdcb31ce
|
||||
F src/test_btree.c 8b2dc8b8848cf3a4db93f11578f075e82252a274
|
||||
F src/test_config.c 9eaeaa599673b8e8732b80540549250a1f1b5bab5de4bfd76b1566f495bc95ab
|
||||
F src/test_config.c c7625911811828ba7065c4c789d68a61835f42239d5bd7f4a08aba7c44ccded9
|
||||
F src/test_delete.c e2fe07646dff6300b48d49b2fee2fe192ed389e834dd635e3b3bac0ce0bf9f8f
|
||||
F src/test_demovfs.c 86142ba864d4297d54c5b2e972e74f3141ae4b30f05b3a95824184ed2d3d7f91
|
||||
F src/test_devsym.c aff2255ea290d7718da08af30cdf18e470ff7325a5eff63e0057b1496ed66593
|
||||
@@ -610,11 +610,11 @@ F src/tokenize.c 369a8ef43e4e3ef2818ad6cf6ef7b167973fc297ca93af4dfab4453db214ec3
|
||||
F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda
|
||||
F src/trigger.c e9eb8ceb72f852057951b1bfb94be677573682f49c77aab13e3e5a3dd36f3f91
|
||||
F src/update.c 9f126204a6acb96bbe47391ae48e0fc579105d8e76a6d9c4fab3271367476580
|
||||
F src/upsert.c 2920de71b20f04fe25eb00b655d086f0ba60ea133c59d7fa3325c49838818e78
|
||||
F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235
|
||||
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
|
||||
F src/util.c c0c7977de7ef9b8cb10f6c85f2d0557889a658f817b0455909a49179ba4c8002
|
||||
F src/vacuum.c 724188c5afbba905b310e8d8e78530956d16e6d60a3ba8a1105d05732d7d8601
|
||||
F src/vdbe.c 05d7dbe213ee570e33e89fb34f9bcfd9926bb9f7b1cf2fd9a65b5e3a2e83e950
|
||||
F src/vdbe.c f7079a162c0b33847c8353b4eda24e01998fb566e581d1a9987b7005923d96da
|
||||
F src/vdbe.h 9e947bd4a40e3b65159b699571c8246c209f6bda6e13979a1ab623faa2f0d23f
|
||||
F src/vdbeInt.h 3ca5e9fd6e095a8b6cf6bc3587a46fc93499503b2fe48951e1034ba9e2ce2f6e
|
||||
F src/vdbeapi.c c5e7cb2ab89a24d7f723e87b508f21bfb1359a04db5277d8a99fd1e015c12eb9
|
||||
@@ -622,7 +622,7 @@ F src/vdbeaux.c 533d41dab3537c81727142af61a409797f5922d474504ec6123e4819e7d1e538
|
||||
F src/vdbeblob.c 40028e015fe557a945c99edb6cbf844ea96d853c3e8ac4eb5c1e49bff59f154e
|
||||
F src/vdbemem.c 947f2a65910edb4014dc981d33e414a68c51f169f9df8c4c493a0ba840b6eb1f
|
||||
F src/vdbesort.c f5b5e473a7cee44e47a94817b042fd7172cf3aa2c0a7928a8339d612bcfdec5a
|
||||
F src/vdbetrace.c fa3bf238002f0bbbdfb66cc8afb0cea284ff9f148d6439bc1f6f2b4c3b7143f0
|
||||
F src/vdbetrace.c 666c6fd9f1b62be6999e072a45b913e3c2c3518bc60dfd4d54fe304130acb724
|
||||
F src/vdbevtab.c f99b275366c5fc5e2d99f734729880994ab9500bdafde7fae3b02d562b9d323c
|
||||
F src/vtab.c 54b6ab9f5ab772f56e9f3a95543207943e775ec699b7cbbfd3a99c264cad377f
|
||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
@@ -793,6 +793,7 @@ F test/corruptJ.test 4d5ccc4bf959464229a836d60142831ef76a5aa4
|
||||
F test/corruptK.test 5b4212fe346699831c5ad559a62c54e11c0611bdde1ea8423a091f9c01aa32af
|
||||
F test/corruptL.test 22589f503602cc5984e80f27f46c4de2134f24f1515ba2440513c377cb692258
|
||||
F test/corruptM.test 7d574320e08c1b36caa3e47262061f186367d593a7e305d35f15289cc2c3e067
|
||||
F test/corruptN.test 781c5f26a2d8918f03d45ac4968a738031eeb113a4b153c7588756d9b09c7b04
|
||||
F test/cost.test 1d156ce9858780a966c062694687afe0343a0ed12d081d071fb57027e726bafc
|
||||
F test/count.test e0699a15712bc2a4679d60e408921c2cce7f6365a30340e790c98e0f334a9c77
|
||||
F test/countofview.test e17d6e6688cf74f22783c9ec6e788c0790ee4fbbaee713affd00b1ac0bb39b86
|
||||
@@ -1028,6 +1029,7 @@ F test/func3.test 2bb0f31ab7baaed690b962a88544d7be6b34fa389364bc36a44e441ed3e3f1
|
||||
F test/func4.test 2285fb5792d593fef442358763f0fd9de806eda47dbc7a5934df57ffdc484c31
|
||||
F test/func5.test 863e6d1bd0013d09c17236f8a13ea34008dd857d87d85a13a673960e4c25d82a
|
||||
F test/func6.test 90e42b64c4f9fb6f04f44cb8a1da586c8542502e926b19c76504fe74ff2a9b7c
|
||||
F test/func7.test bb05a77daedf0e3f8764f323a49bc3b8d98f280a0bc6a370387117f4596bde05
|
||||
F test/fuzz-oss1.test e58330d01cbbd8215ee636b17a03fe220b37dbfa
|
||||
F test/fuzz.test 96083052bf5765e4518c1ba686ce2bab785670d1
|
||||
F test/fuzz2.test 76dc35b32b6d6f965259508508abce75a6c4d7e1
|
||||
@@ -1043,7 +1045,7 @@ F test/fuzzdata4.db b502c7d5498261715812dd8b3c2005bad08b3a26e6489414bd13926cd3e4
|
||||
F test/fuzzdata5.db e35f64af17ec48926481cfaf3b3855e436bd40d1cfe2d59a9474cb4b748a52a5
|
||||
F test/fuzzdata6.db 92a80e4afc172c24f662a10a612d188fb272de4a9bd19e017927c95f737de6d7
|
||||
F test/fuzzdata7.db 0166b56fd7a6b9636a1d60ef0a060f86ddaecf99400a666bb6e5bbd7199ad1f2
|
||||
F test/fuzzdata8.db f8451a1fd38efbea8c1a7cdf5d02259c4702446a9fabf566becd306b64a50236
|
||||
F test/fuzzdata8.db 7f6c5443d67ba040f760b4d28da54cc9f68174fa212ae34ccb86c645de761ec4
|
||||
F test/fuzzer1.test 3d4c4b7e547aba5e5511a2991e3e3d07166cfbb8
|
||||
F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14
|
||||
F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536
|
||||
@@ -1602,7 +1604,7 @@ F test/tokenize.test ce430a7aed48fc98301611429595883fdfcab5d7
|
||||
F test/tpch01.test 7c4eb8cdd79c568f46d344b3e789c9fdb8a766d112871352704861f3fca32a2a
|
||||
F test/trace.test a659a9862957f4789e37a92b3bf6d2caf5c86b02cdeefc41e850ae53acf6992a
|
||||
F test/trace2.test f5cb67ad3bc09e0c58e8cca78dfd0b5639259983
|
||||
F test/trace3.test 1dff966888773ff1bfea01c080caf15417892b3f998408fe920c4791f7337144
|
||||
F test/trace3.test ae2004df24b585fed9046cc0bae4601762bc6fc4aa321d475f1350bba5047f31
|
||||
F test/trans.test 45f6f9ab6f66a7b5744f1caac06b558f95da62501916906cf55586a896f9f439
|
||||
F test/trans2.test 62bd045bfc7a1c14c5ba83ba64d21ade31583f76
|
||||
F test/trans3.test 91a100e5412b488e22a655fe423a14c26403ab94
|
||||
@@ -1652,6 +1654,7 @@ F test/upsert1.test 88f9e258c6a0eeeb85937b08831e8daad440ba41f125af48439e9d33f266
|
||||
F test/upsert2.test 9c3cdbb1a890227f6504ce4b0e3de68f4cdfa16bb21d8641208a9239896c5a09
|
||||
F test/upsert3.test 88d7d590a1948a9cb6eac1b54b0642f67a9f35a1fc0f19b200e97d5d39e3179c
|
||||
F test/upsert4.test 25d2a1da92f149331ae0c51ca6e3eee78189577585eab92de149900d62994fa5
|
||||
F test/upsert5.test f49faf5f15b5c3641c6f5d7c7cc531ef5ac997567b2b6bb7bc96f7c88753ca0b
|
||||
F test/upsertfault.test f21ca47740841fdb4d61acfa7b17646d773e67724fe8c185b71c018db8a94b35
|
||||
F test/uri.test 3481026f00ade6dfe8adb7acb6e1e47b04369568
|
||||
F test/uri2.test 9d3ba7a53ee167572d53a298ee4a5d38ec4a8fb7
|
||||
@@ -1659,10 +1662,11 @@ F test/userauth01.test e740a2697a7b40d7c5003a7d7edaee16acd349a9
|
||||
F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae
|
||||
F test/vacuum-into.test 48f4cec354fb6f27c98ef58d2fe49a11b71ff131af0cd9140efacc9858b9f670
|
||||
F test/vacuum.test ce91c39f7f91a4273bf620efad21086b5aa6ef1d
|
||||
F test/vacuum2.test aa048abee196c16c9ba308465494009057b79f9b
|
||||
F test/vacuum2.test 9fd45ce6ce29f5614c249e03938d3567c06a9e772d4f155949f8eafe2d8af520
|
||||
F test/vacuum3.test 77ecdd54592b45a0bcb133339f99f1ae0ae94d0d
|
||||
F test/vacuum4.test 7ea76b769fffeb41f925303b04cbcf5a5bbeabe55e4c60ae754ff24eeeb7c010
|
||||
F test/vacuum5.test 263b144d537e92ad8e9ca8a73cc6e1583f41cfd0dda9432b87f7806174a2f48c
|
||||
F test/vacuum6.test d3173a54edc81d13d99e4cf4972232b3cbb52f1d56ed48c3a939ef4e751c1ee8
|
||||
F test/vacuummem.test 7b42abb3208bd82dd23a7536588396f295a314f2
|
||||
F test/varint.test bbce22cda8fc4d135bcc2b589574be8410614e62
|
||||
F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661
|
||||
@@ -1897,7 +1901,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 73b5f614cd6603d6cf9605ac4ccb510a2560fca70a8a3f3f930cf2a4e853c301 1db7c751912beb57a697ac8e85b9c29e30da7b6c89207e9828bf08e56c58242f
|
||||
R 0a0cd3f6dc7d7a2ed4f824c3b5f54a44
|
||||
P 846e8444f761a4f3e3e0fb89e87b329799a6e8dd32ac7580dc20eb6ff9ed0d36 2a6cd6833e44dd6a2ac388815f43be6508f6fa6db5e451e964276a6c87e6c5ae
|
||||
R 04e4b24540263b7819b2517f7180918b
|
||||
U dan
|
||||
Z a637d8c8811fdbe0dc1e41aaa95a98fc
|
||||
Z e0c0174ae97094c5a1097ed7b89818f2
|
||||
|
||||
@@ -1 +1 @@
|
||||
846e8444f761a4f3e3e0fb89e87b329799a6e8dd32ac7580dc20eb6ff9ed0d36
|
||||
9f41f604055553f0c62d4c0d5a00c6a43d1a938f36901238c52c065702b9c536
|
||||
149
src/btree.c
149
src/btree.c
@@ -1143,6 +1143,24 @@ static SQLITE_NOINLINE void btreeParseCellAdjustSizeForOverflow(
|
||||
pInfo->nSize = (u16)(&pInfo->pPayload[pInfo->nLocal] - pCell) + 4;
|
||||
}
|
||||
|
||||
/*
|
||||
** Given a record with nPayload bytes of payload stored within btree
|
||||
** page pPage, return the number of bytes of payload stored locally.
|
||||
*/
|
||||
static int btreePayloadToLocal(MemPage *pPage, i64 nPayload){
|
||||
int maxLocal; /* Maximum amount of payload held locally */
|
||||
maxLocal = pPage->maxLocal;
|
||||
if( nPayload<=maxLocal ){
|
||||
return nPayload;
|
||||
}else{
|
||||
int minLocal; /* Minimum amount of payload held locally */
|
||||
int surplus; /* Overflow payload available for local storage */
|
||||
minLocal = pPage->minLocal;
|
||||
surplus = minLocal + (nPayload - minLocal)%(pPage->pBt->usableSize-4);
|
||||
return ( surplus <= maxLocal ) ? surplus : minLocal;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** The following routines are implementations of the MemPage.xParseCell()
|
||||
** method.
|
||||
@@ -8660,7 +8678,8 @@ int sqlite3BtreeInsert(
|
||||
unsigned char *oldCell;
|
||||
unsigned char *newCell = 0;
|
||||
|
||||
assert( (flags & (BTREE_SAVEPOSITION|BTREE_APPEND))==flags );
|
||||
assert( (flags & (BTREE_SAVEPOSITION|BTREE_APPEND|BTREE_PREFORMAT))==flags );
|
||||
assert( (flags & BTREE_PREFORMAT)==0 || seekResult || pCur->pKeyInfo==0 );
|
||||
|
||||
if( pCur->eState==CURSOR_FAULT ){
|
||||
assert( pCur->skipNext!=SQLITE_OK );
|
||||
@@ -8678,7 +8697,7 @@ int sqlite3BtreeInsert(
|
||||
** keys with no associated data. If the cursor was opened expecting an
|
||||
** intkey table, the caller should be inserting integer keys with a
|
||||
** blob of associated data. */
|
||||
assert( (pX->pKey==0)==(pCur->pKeyInfo==0) );
|
||||
assert( (flags & BTREE_PREFORMAT) || (pX->pKey==0)==(pCur->pKeyInfo==0) );
|
||||
|
||||
/* Save the positions of any other cursors open on this table.
|
||||
**
|
||||
@@ -8788,7 +8807,7 @@ int sqlite3BtreeInsert(
|
||||
|| CORRUPT_DB );
|
||||
|
||||
pPage = pCur->pPage;
|
||||
assert( pPage->intKey || pX->nKey>=0 );
|
||||
assert( pPage->intKey || pX->nKey>=0 || (flags & BTREE_PREFORMAT) );
|
||||
assert( pPage->leaf || !pPage->intKey );
|
||||
if( pPage->nFree<0 ){
|
||||
if( pCur->eState>CURSOR_INVALID ){
|
||||
@@ -8805,7 +8824,21 @@ int sqlite3BtreeInsert(
|
||||
assert( pPage->isInit );
|
||||
newCell = pBt->pTmpSpace;
|
||||
assert( newCell!=0 );
|
||||
rc = fillInCell(pPage, newCell, pX, &szNew);
|
||||
if( flags & BTREE_PREFORMAT ){
|
||||
rc = SQLITE_OK;
|
||||
szNew = pBt->nPreformatSize;
|
||||
if( szNew<4 ) szNew = 4;
|
||||
if( ISAUTOVACUUM && szNew>pPage->maxLocal ){
|
||||
CellInfo info;
|
||||
pPage->xParseCell(pPage, newCell, &info);
|
||||
if( info.nPayload!=info.nLocal ){
|
||||
Pgno ovfl = get4byte(&newCell[szNew-4]);
|
||||
ptrmapPut(pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, &rc);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
rc = fillInCell(pPage, newCell, pX, &szNew);
|
||||
}
|
||||
if( rc ) goto end_insert;
|
||||
assert( szNew==pPage->xCellSize(pPage, newCell) );
|
||||
assert( szNew <= MX_CELL_SIZE(pBt) );
|
||||
@@ -8912,6 +8945,114 @@ end_insert:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is used as part of copying the current row from cursor
|
||||
** pSrc into cursor pDest. If the cursors are open on intkey tables, then
|
||||
** parameter iKey is used as the rowid value when the record is copied
|
||||
** into pDest. Otherwise, the record is copied verbatim.
|
||||
**
|
||||
** This function does not actually write the new value to cursor pDest.
|
||||
** Instead, it creates and populates any required overflow pages and
|
||||
** writes the data for the new cell into the BtShared.pTmpSpace buffer
|
||||
** for the destination database. The size of the cell, in bytes, is left
|
||||
** in BtShared.nPreformatSize. The caller completes the insertion by
|
||||
** calling sqlite3BtreeInsert() with the BTREE_PREFORMAT flag specified.
|
||||
**
|
||||
** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
|
||||
*/
|
||||
int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 iKey){
|
||||
int rc = SQLITE_OK;
|
||||
BtShared *pBt = pDest->pBt;
|
||||
u8 *aOut = pBt->pTmpSpace; /* Pointer to next output buffer */
|
||||
const u8 *aIn; /* Pointer to next input buffer */
|
||||
u32 nIn; /* Size of input buffer aIn[] */
|
||||
u32 nRem; /* Bytes of data still to copy */
|
||||
|
||||
getCellInfo(pSrc);
|
||||
aOut += putVarint32(aOut, pSrc->info.nPayload);
|
||||
if( pDest->pKeyInfo==0 ) aOut += putVarint(aOut, iKey);
|
||||
nIn = pSrc->info.nLocal;
|
||||
aIn = pSrc->info.pPayload;
|
||||
if( aIn+nIn>pSrc->pPage->aDataEnd ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
nRem = pSrc->info.nPayload;
|
||||
if( nIn==nRem && nIn<pDest->pPage->maxLocal ){
|
||||
memcpy(aOut, aIn, nIn);
|
||||
pBt->nPreformatSize = nIn + (aOut - pBt->pTmpSpace);
|
||||
}else{
|
||||
Pager *pSrcPager = pSrc->pBt->pPager;
|
||||
u8 *pPgnoOut = 0;
|
||||
Pgno ovflIn = 0;
|
||||
DbPage *pPageIn = 0;
|
||||
MemPage *pPageOut = 0;
|
||||
u32 nOut; /* Size of output buffer aOut[] */
|
||||
|
||||
nOut = btreePayloadToLocal(pDest->pPage, pSrc->info.nPayload);
|
||||
pBt->nPreformatSize = nOut + (aOut - pBt->pTmpSpace);
|
||||
if( nOut<pSrc->info.nPayload ){
|
||||
pPgnoOut = &aOut[nOut];
|
||||
pBt->nPreformatSize += 4;
|
||||
}
|
||||
|
||||
if( nRem>nIn ){
|
||||
if( aIn+nIn+4>pSrc->pPage->aDataEnd ){
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
ovflIn = get4byte(&pSrc->info.pPayload[nIn]);
|
||||
}
|
||||
|
||||
do {
|
||||
nRem -= nOut;
|
||||
do{
|
||||
assert( nOut>0 );
|
||||
if( nIn>0 ){
|
||||
int nCopy = MIN(nOut, nIn);
|
||||
memcpy(aOut, aIn, nCopy);
|
||||
nOut -= nCopy;
|
||||
nIn -= nCopy;
|
||||
aOut += nCopy;
|
||||
aIn += nCopy;
|
||||
}
|
||||
if( nOut>0 ){
|
||||
sqlite3PagerUnref(pPageIn);
|
||||
pPageIn = 0;
|
||||
rc = sqlite3PagerGet(pSrcPager, ovflIn, &pPageIn, PAGER_GET_READONLY);
|
||||
if( rc==SQLITE_OK ){
|
||||
aIn = (const u8*)sqlite3PagerGetData(pPageIn);
|
||||
ovflIn = get4byte(aIn);
|
||||
aIn += 4;
|
||||
nIn = pSrc->pBt->usableSize - 4;
|
||||
}
|
||||
}
|
||||
}while( rc==SQLITE_OK && nOut>0 );
|
||||
|
||||
if( rc==SQLITE_OK && nRem>0 ){
|
||||
Pgno pgnoNew;
|
||||
MemPage *pNew = 0;
|
||||
rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0);
|
||||
put4byte(pPgnoOut, pgnoNew);
|
||||
if( ISAUTOVACUUM && pPageOut ){
|
||||
ptrmapPut(pBt, pgnoNew, PTRMAP_OVERFLOW2, pPageOut->pgno, &rc);
|
||||
}
|
||||
releasePage(pPageOut);
|
||||
pPageOut = pNew;
|
||||
if( pPageOut ){
|
||||
pPgnoOut = pPageOut->aData;
|
||||
put4byte(pPgnoOut, 0);
|
||||
aOut = &pPgnoOut[4];
|
||||
nOut = MIN(pBt->usableSize - 4, nRem);
|
||||
}
|
||||
}
|
||||
}while( nRem>0 && rc==SQLITE_OK );
|
||||
|
||||
releasePage(pPageOut);
|
||||
sqlite3PagerUnref(pPageIn);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete the entry that the cursor is pointing to.
|
||||
**
|
||||
|
||||
@@ -262,6 +262,7 @@ int sqlite3BtreeDelete(BtCursor*, u8 flags);
|
||||
#define BTREE_SAVEPOSITION 0x02 /* Leave cursor pointing at NEXT or PREV */
|
||||
#define BTREE_AUXDELETE 0x04 /* not the primary delete operation */
|
||||
#define BTREE_APPEND 0x08 /* Insert is likely an append */
|
||||
#define BTREE_PREFORMAT 0x80 /* Insert is likely an append */
|
||||
|
||||
/* An instance of the BtreePayload object describes the content of a single
|
||||
** entry in either an index or table btree.
|
||||
@@ -361,6 +362,8 @@ void sqlite3BtreeCursorList(Btree*);
|
||||
int sqlite3BtreeCheckpoint(Btree*, int, int *, int *);
|
||||
#endif
|
||||
|
||||
int sqlite3BtreeTransferRow(BtCursor*, BtCursor*, i64);
|
||||
|
||||
/*
|
||||
** If we are not using shared cache, then there is no need to
|
||||
** use mutexes to access the BtShared structures. So make the
|
||||
|
||||
@@ -455,6 +455,7 @@ struct BtShared {
|
||||
Btree *pWriter; /* Btree with currently open write transaction */
|
||||
#endif
|
||||
u8 *pTmpSpace; /* Temp space sufficient to hold a single cell */
|
||||
int nPreformatSize; /* Size of last cell written by TransferRow() */
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -259,6 +259,9 @@ static const char * const sqlite3azCompileOpt[] = {
|
||||
#ifdef SQLITE_ENABLE_LOCKING_STYLE
|
||||
"ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
|
||||
#endif
|
||||
#if SQLITE_ENABLE_MATH_FUNCTIONS
|
||||
"ENABLE_MATH_FUNCTIONS"
|
||||
#endif
|
||||
#if SQLITE_ENABLE_MEMORY_MANAGEMENT
|
||||
"ENABLE_MEMORY_MANAGEMENT",
|
||||
#endif
|
||||
|
||||
225
src/func.c
225
src/func.c
@@ -1904,6 +1904,194 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Mathematical Constants */
|
||||
#ifndef M_PI
|
||||
# define M_PI 3.141592653589793238462643383279502884
|
||||
#endif
|
||||
#ifndef M_LN10
|
||||
# define M_LN10 2.302585092994045684017991454684364208
|
||||
#endif
|
||||
#ifndef M_LN2
|
||||
# define M_LN2 0.693147180559945309417232121458176568
|
||||
#endif
|
||||
|
||||
|
||||
/* Extra math functions that require linking with -lm
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_MATH_FUNCTIONS
|
||||
/*
|
||||
** Implementation SQL functions:
|
||||
**
|
||||
** ceil(X)
|
||||
** ceiling(X)
|
||||
** floor(X)
|
||||
**
|
||||
** The sqlite3_user_data() pointer is a pointer to the libm implementation
|
||||
** of the underlying C function.
|
||||
*/
|
||||
static void ceilingFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
assert( argc==1 );
|
||||
switch( sqlite3_value_numeric_type(argv[0]) ){
|
||||
case SQLITE_INTEGER: {
|
||||
sqlite3_result_int64(context, sqlite3_value_int64(argv[0]));
|
||||
break;
|
||||
}
|
||||
case SQLITE_FLOAT: {
|
||||
double (*x)(double) = (double(*)(double))sqlite3_user_data(context);
|
||||
sqlite3_result_double(context, x(sqlite3_value_double(argv[0])));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of SQL functions:
|
||||
**
|
||||
** ln(X) - natural logarithm
|
||||
** log(X) - log X base 10
|
||||
** log10(X) - log X base 10
|
||||
** log(B,X) - log X base B
|
||||
*/
|
||||
static void logFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
double x, b, ans;
|
||||
assert( argc==1 || argc==2 );
|
||||
switch( sqlite3_value_numeric_type(argv[0]) ){
|
||||
case SQLITE_INTEGER:
|
||||
case SQLITE_FLOAT:
|
||||
x = sqlite3_value_double(argv[0]);
|
||||
if( x<0.0 ) return;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
if( argc==2 ){
|
||||
switch( sqlite3_value_numeric_type(argv[0]) ){
|
||||
case SQLITE_INTEGER:
|
||||
case SQLITE_FLOAT:
|
||||
b = x;
|
||||
x = sqlite3_value_double(argv[1]);
|
||||
if( x<0.0 ) return;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
ans = log(x)/log(b);
|
||||
}else{
|
||||
ans = log(x);
|
||||
switch( SQLITE_PTR_TO_INT(sqlite3_user_data(context)) ){
|
||||
case 1:
|
||||
/* Convert from natural logarithm to log base 10 */
|
||||
ans *= 1.0/M_LN10;
|
||||
break;
|
||||
case 2:
|
||||
/* Convert from natural logarithm to log base 2 */
|
||||
ans *= 1.0/M_LN2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
sqlite3_result_double(context, ans);
|
||||
}
|
||||
|
||||
/*
|
||||
** Functions to converts degrees to radians and radians to degrees.
|
||||
*/
|
||||
static double degToRad(double x){ return x*(M_PI/180.0); }
|
||||
static double radToDeg(double x){ return x*(180.0/M_PI); }
|
||||
|
||||
/*
|
||||
** Implementation of 1-argument SQL math functions:
|
||||
**
|
||||
** exp(X) - Compute e to the X-th power
|
||||
*/
|
||||
static void math1Func(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
int type0;
|
||||
double v0, ans;
|
||||
double (*x)(double);
|
||||
assert( argc==1 );
|
||||
type0 = sqlite3_value_numeric_type(argv[0]);
|
||||
if( type0!=SQLITE_INTEGER && type0!=SQLITE_FLOAT ) return;
|
||||
v0 = sqlite3_value_double(argv[0]);
|
||||
x = (double(*)(double))sqlite3_user_data(context);
|
||||
ans = x(v0);
|
||||
sqlite3_result_double(context, ans);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of 2-argument SQL math functions:
|
||||
**
|
||||
** power(X,Y) - Compute X to the Y-th power
|
||||
*/
|
||||
static void math2Func(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
int type0, type1;
|
||||
double v0, v1, ans;
|
||||
double (*x)(double,double);
|
||||
assert( argc==2 );
|
||||
type0 = sqlite3_value_numeric_type(argv[0]);
|
||||
if( type0!=SQLITE_INTEGER && type0!=SQLITE_FLOAT ) return;
|
||||
type1 = sqlite3_value_numeric_type(argv[1]);
|
||||
if( type1!=SQLITE_INTEGER && type1!=SQLITE_FLOAT ) return;
|
||||
v0 = sqlite3_value_double(argv[0]);
|
||||
v1 = sqlite3_value_double(argv[1]);
|
||||
x = (double(*)(double,double))sqlite3_user_data(context);
|
||||
ans = x(v0, v1);
|
||||
sqlite3_result_double(context, ans);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of 2-argument SQL math functions:
|
||||
**
|
||||
** power(X,Y) - Compute X to the Y-th power
|
||||
*/
|
||||
static void piFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
assert( argc==0 );
|
||||
sqlite3_result_double(context, M_PI);
|
||||
}
|
||||
|
||||
#endif /* SQLITE_ENABLE_MATH_FUNCTIONS */
|
||||
|
||||
/*
|
||||
** Implementation of sign(X) function.
|
||||
*/
|
||||
static void signFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
int type0;
|
||||
double x;
|
||||
UNUSED_PARAMETER(argc);
|
||||
assert( argc==1 );
|
||||
type0 = sqlite3_value_numeric_type(argv[0]);
|
||||
if( type0!=SQLITE_INTEGER && type0!=SQLITE_FLOAT ) return;
|
||||
x = sqlite3_value_double(argv[0]);
|
||||
sqlite3_result_int(context, x<0.0 ? -1 : x>0.0 ? +1 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
** All of the FuncDef structures in the aBuiltinFunc[] array above
|
||||
** to the global function hash table. This occurs at start-time (as
|
||||
@@ -2022,6 +2210,43 @@ void sqlite3RegisterBuiltinFunctions(void){
|
||||
#endif
|
||||
FUNCTION(coalesce, 1, 0, 0, 0 ),
|
||||
FUNCTION(coalesce, 0, 0, 0, 0 ),
|
||||
#ifdef SQLITE_ENABLE_MATH_FUNCTIONS
|
||||
MFUNCTION(ceil, 1, ceil, ceilingFunc ),
|
||||
MFUNCTION(ceiling, 1, ceil, ceilingFunc ),
|
||||
MFUNCTION(floor, 1, floor, ceilingFunc ),
|
||||
#if SQLITE_HAVE_C99_MATH_FUNCS
|
||||
MFUNCTION(trunc, 1, trunc, ceilingFunc ),
|
||||
#endif
|
||||
FUNCTION(ln, 1, 0, 0, logFunc ),
|
||||
FUNCTION(log, 1, 1, 0, logFunc ),
|
||||
FUNCTION(log10, 1, 1, 0, logFunc ),
|
||||
FUNCTION(log2, 1, 2, 0, logFunc ),
|
||||
FUNCTION(log, 2, 0, 0, logFunc ),
|
||||
MFUNCTION(exp, 1, exp, math1Func ),
|
||||
MFUNCTION(pow, 2, pow, math2Func ),
|
||||
MFUNCTION(power, 2, pow, math2Func ),
|
||||
MFUNCTION(mod, 2, fmod, math2Func ),
|
||||
MFUNCTION(acos, 1, acos, math1Func ),
|
||||
MFUNCTION(asin, 1, asin, math1Func ),
|
||||
MFUNCTION(atan, 1, atan, math1Func ),
|
||||
MFUNCTION(atan2, 2, atan2, math2Func ),
|
||||
MFUNCTION(cos, 1, cos, math1Func ),
|
||||
MFUNCTION(sin, 1, sin, math1Func ),
|
||||
MFUNCTION(tan, 1, tan, math1Func ),
|
||||
MFUNCTION(cosh, 1, cosh, math1Func ),
|
||||
MFUNCTION(sinh, 1, sinh, math1Func ),
|
||||
MFUNCTION(tanh, 1, tanh, math1Func ),
|
||||
#if SQLITE_HAVE_C99_MATH_FUNCS
|
||||
MFUNCTION(acosh, 1, acosh, math1Func ),
|
||||
MFUNCTION(asinh, 1, asinh, math1Func ),
|
||||
MFUNCTION(atanh, 1, atanh, math1Func ),
|
||||
#endif
|
||||
MFUNCTION(sqrt, 1, sqrt, math1Func ),
|
||||
MFUNCTION(radians, 1, degToRad, math1Func ),
|
||||
MFUNCTION(degrees, 1, radToDeg, math1Func ),
|
||||
FUNCTION(pi, 0, 0, 0, piFunc ),
|
||||
#endif /* SQLITE_ENABLE_MATH_FUNCTIONS */
|
||||
FUNCTION(sign, 1, 0, 0, signFunc ),
|
||||
INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, 0 ),
|
||||
INLINE_FUNC(iif, 3, INLINEFUNC_iif, 0 ),
|
||||
};
|
||||
|
||||
262
src/insert.c
262
src/insert.c
@@ -975,6 +975,7 @@ void sqlite3Insert(
|
||||
}
|
||||
#ifndef SQLITE_OMIT_UPSERT
|
||||
if( pUpsert ){
|
||||
Upsert *pNx;
|
||||
if( IsVirtual(pTab) ){
|
||||
sqlite3ErrorMsg(pParse, "UPSERT not implemented for virtual table \"%s\"",
|
||||
pTab->zName);
|
||||
@@ -988,13 +989,17 @@ void sqlite3Insert(
|
||||
goto insert_cleanup;
|
||||
}
|
||||
pTabList->a[0].iCursor = iDataCur;
|
||||
pUpsert->pUpsertSrc = pTabList;
|
||||
pUpsert->regData = regData;
|
||||
pUpsert->iDataCur = iDataCur;
|
||||
pUpsert->iIdxCur = iIdxCur;
|
||||
if( pUpsert->pUpsertTarget ){
|
||||
sqlite3UpsertAnalyzeTarget(pParse, pTabList, pUpsert);
|
||||
}
|
||||
pNx = pUpsert;
|
||||
do{
|
||||
pNx->pUpsertSrc = pTabList;
|
||||
pNx->regData = regData;
|
||||
pNx->iDataCur = iDataCur;
|
||||
pNx->iIdxCur = iIdxCur;
|
||||
if( pNx->pUpsertTarget ){
|
||||
sqlite3UpsertAnalyzeTarget(pParse, pTabList, pNx);
|
||||
}
|
||||
pNx = pNx->pNextUpsert;
|
||||
}while( pNx!=0 );
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1399,6 +1404,70 @@ int sqlite3ExprReferencesUpdatedColumn(
|
||||
return w.eCode!=0;
|
||||
}
|
||||
|
||||
/*
|
||||
** The sqlite3GenerateConstraintChecks() routine usually wants to visit
|
||||
** the indexes of a table in the order provided in the Table->pIndex list.
|
||||
** However, sometimes (rarely - when there is an upsert) it wants to visit
|
||||
** the indexes in a different order. The following data structures accomplish
|
||||
** this.
|
||||
**
|
||||
** The IndexIterator object is used to walk through all of the indexes
|
||||
** of a table in either Index.pNext order, or in some other order established
|
||||
** by an array of IndexListTerm objects.
|
||||
*/
|
||||
typedef struct IndexListTerm IndexListTerm;
|
||||
typedef struct IndexIterator IndexIterator;
|
||||
struct IndexIterator {
|
||||
int eType; /* 0 for Index.pNext list. 1 for an array of IndexListTerm */
|
||||
int i; /* Index of the current item from the list */
|
||||
union {
|
||||
struct { /* Use this object for eType==0: A Index.pNext list */
|
||||
Index *pIdx; /* The current Index */
|
||||
} lx;
|
||||
struct { /* Use this object for eType==1; Array of IndexListTerm */
|
||||
int nIdx; /* Size of the array */
|
||||
IndexListTerm *aIdx; /* Array of IndexListTerms */
|
||||
} ax;
|
||||
} u;
|
||||
};
|
||||
|
||||
/* When IndexIterator.eType==1, then each index is an array of instances
|
||||
** of the following object
|
||||
*/
|
||||
struct IndexListTerm {
|
||||
Index *p; /* The index */
|
||||
int ix; /* Which entry in the original Table.pIndex list is this index*/
|
||||
};
|
||||
|
||||
/* Return the first index on the list */
|
||||
static Index *indexIteratorFirst(IndexIterator *pIter, int *pIx){
|
||||
assert( pIter->i==0 );
|
||||
if( pIter->eType ){
|
||||
*pIx = pIter->u.ax.aIdx[0].ix;
|
||||
return pIter->u.ax.aIdx[0].p;
|
||||
}else{
|
||||
*pIx = 0;
|
||||
return pIter->u.lx.pIdx;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the next index from the list. Return NULL when out of indexes */
|
||||
static Index *indexIteratorNext(IndexIterator *pIter, int *pIx){
|
||||
if( pIter->eType ){
|
||||
int i = ++pIter->i;
|
||||
if( i>=pIter->u.ax.nIdx ){
|
||||
*pIx = i;
|
||||
return 0;
|
||||
}
|
||||
*pIx = pIter->u.ax.aIdx[i].ix;
|
||||
return pIter->u.ax.aIdx[i].p;
|
||||
}else{
|
||||
++(*pIx);
|
||||
pIter->u.lx.pIdx = pIter->u.lx.pIdx->pNext;
|
||||
return pIter->u.lx.pIdx;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code to do constraint checks prior to an INSERT or an UPDATE
|
||||
** on table pTab.
|
||||
@@ -1507,7 +1576,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
){
|
||||
Vdbe *v; /* VDBE under constrution */
|
||||
Index *pIdx; /* Pointer to one of the indices */
|
||||
Index *pPk = 0; /* The PRIMARY KEY index */
|
||||
Index *pPk = 0; /* The PRIMARY KEY index for WITHOUT ROWID tables */
|
||||
sqlite3 *db; /* Database connection */
|
||||
int i; /* loop counter */
|
||||
int ix; /* Index loop counter */
|
||||
@@ -1515,11 +1584,11 @@ void sqlite3GenerateConstraintChecks(
|
||||
int onError; /* Conflict resolution strategy */
|
||||
int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
|
||||
int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */
|
||||
Index *pUpIdx = 0; /* Index to which to apply the upsert */
|
||||
u8 isUpdate; /* True if this is an UPDATE operation */
|
||||
Upsert *pUpsertClause = 0; /* The specific ON CONFLICT clause for pIdx */
|
||||
u8 isUpdate; /* True if this is an UPDATE operation */
|
||||
u8 bAffinityDone = 0; /* True if the OP_Affinity operation has been run */
|
||||
int upsertBypass = 0; /* Address of Goto to bypass upsert subroutine */
|
||||
int upsertJump = 0; /* Address of Goto that jumps into upsert subroutine */
|
||||
int upsertIpkReturn = 0; /* Address of Goto at end of IPK uniqueness check */
|
||||
int upsertIpkDelay = 0; /* Address of Goto to bypass initial IPK check */
|
||||
int ipkTop = 0; /* Top of the IPK uniqueness check */
|
||||
int ipkBottom = 0; /* OP_Goto at the end of the IPK uniqueness check */
|
||||
/* Variables associated with retesting uniqueness constraints after
|
||||
@@ -1529,6 +1598,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
int lblRecheckOk = 0; /* Each recheck jumps to this label if it passes */
|
||||
Trigger *pTrigger; /* List of DELETE triggers on the table pTab */
|
||||
int nReplaceTrig = 0; /* Number of replace triggers coded */
|
||||
IndexIterator sIdxIter; /* Index iterator */
|
||||
|
||||
isUpdate = regOldData!=0;
|
||||
db = pParse->db;
|
||||
@@ -1726,19 +1796,63 @@ void sqlite3GenerateConstraintChecks(
|
||||
** list of indexes attached to a table puts all OE_Replace indexes last
|
||||
** in the list. See sqlite3CreateIndex() for where that happens.
|
||||
*/
|
||||
|
||||
sIdxIter.eType = 0;
|
||||
sIdxIter.i = 0;
|
||||
sIdxIter.u.ax.aIdx = 0; /* Silence harmless compiler warning */
|
||||
sIdxIter.u.lx.pIdx = pTab->pIndex;
|
||||
if( pUpsert ){
|
||||
if( pUpsert->pUpsertTarget==0 ){
|
||||
/* An ON CONFLICT DO NOTHING clause, without a constraint-target.
|
||||
** Make all unique constraint resolution be OE_Ignore */
|
||||
assert( pUpsert->pUpsertSet==0 );
|
||||
overrideError = OE_Ignore;
|
||||
pUpsert = 0;
|
||||
}else if( (pUpIdx = pUpsert->pUpsertIdx)!=0 ){
|
||||
/* If the constraint-target uniqueness check must be run first.
|
||||
** Jump to that uniqueness check now */
|
||||
upsertJump = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
VdbeComment((v, "UPSERT constraint goes first"));
|
||||
/* There is just on ON CONFLICT clause and it has no constraint-target */
|
||||
assert( pUpsert->pNextUpsert==0 );
|
||||
if( pUpsert->isDoUpdate==0 ){
|
||||
/* A single ON CONFLICT DO NOTHING clause, without a constraint-target.
|
||||
** Make all unique constraint resolution be OE_Ignore */
|
||||
overrideError = OE_Ignore;
|
||||
pUpsert = 0;
|
||||
}else{
|
||||
/* A single ON CONFLICT DO UPDATE. Make all resolutions OE_Update */
|
||||
overrideError = OE_Update;
|
||||
}
|
||||
}else if( pTab->pIndex!=0 ){
|
||||
/* Otherwise, we'll need to run the IndexListTerm array version of the
|
||||
** iterator to ensure that all of the ON CONFLICT conditions are
|
||||
** checked first and in order. */
|
||||
int nIdx, jj;
|
||||
u64 nByte;
|
||||
Upsert *pTerm;
|
||||
u8 *bUsed;
|
||||
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){
|
||||
assert( aRegIdx[nIdx]>0 );
|
||||
}
|
||||
sIdxIter.eType = 1;
|
||||
sIdxIter.u.ax.nIdx = nIdx;
|
||||
nByte = (sizeof(IndexListTerm)+1)*nIdx + nIdx;
|
||||
sIdxIter.u.ax.aIdx = sqlite3DbMallocZero(db, nByte);
|
||||
if( sIdxIter.u.ax.aIdx==0 ) return; /* OOM */
|
||||
bUsed = (u8*)&sIdxIter.u.ax.aIdx[nIdx];
|
||||
pUpsert->pToFree = sIdxIter.u.ax.aIdx;
|
||||
for(i=0, pTerm=pUpsert; pTerm; pTerm=pTerm->pNextUpsert){
|
||||
if( pTerm->pUpsertTarget==0 ) break;
|
||||
if( pTerm->pUpsertIdx==0 ) continue; /* Skip ON CONFLICT for the IPK */
|
||||
jj = 0;
|
||||
pIdx = pTab->pIndex;
|
||||
while( ALWAYS(pIdx!=0) && pIdx!=pTerm->pUpsertIdx ){
|
||||
pIdx = pIdx->pNext;
|
||||
jj++;
|
||||
}
|
||||
if( bUsed[jj] ) continue; /* Duplicate ON CONFLICT clause ignored */
|
||||
bUsed[jj] = 1;
|
||||
sIdxIter.u.ax.aIdx[i].p = pIdx;
|
||||
sIdxIter.u.ax.aIdx[i].ix = jj;
|
||||
i++;
|
||||
}
|
||||
for(jj=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, jj++){
|
||||
if( bUsed[jj] ) continue;
|
||||
sIdxIter.u.ax.aIdx[i].p = pIdx;
|
||||
sIdxIter.u.ax.aIdx[i].ix = jj;
|
||||
i++;
|
||||
}
|
||||
assert( i==nIdx );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1801,11 +1915,20 @@ void sqlite3GenerateConstraintChecks(
|
||||
}
|
||||
|
||||
/* figure out whether or not upsert applies in this case */
|
||||
if( pUpsert && pUpsert->pUpsertIdx==0 ){
|
||||
if( pUpsert->pUpsertSet==0 ){
|
||||
onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */
|
||||
}else{
|
||||
onError = OE_Update; /* DO UPDATE */
|
||||
if( pUpsert ){
|
||||
pUpsertClause = sqlite3UpsertOfIndex(pUpsert,0);
|
||||
if( pUpsertClause!=0 ){
|
||||
if( pUpsertClause->isDoUpdate==0 ){
|
||||
onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */
|
||||
}else{
|
||||
onError = OE_Update; /* DO UPDATE */
|
||||
}
|
||||
}
|
||||
if( pUpsertClause!=pUpsert ){
|
||||
/* The first ON CONFLICT clause has a conflict target other than
|
||||
** the IPK. We have to jump ahead to that first ON CONFLICT clause
|
||||
** and then come back here and deal with the IPK afterwards */
|
||||
upsertIpkDelay = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1912,7 +2035,9 @@ void sqlite3GenerateConstraintChecks(
|
||||
}
|
||||
}
|
||||
sqlite3VdbeResolveLabel(v, addrRowidOk);
|
||||
if( ipkTop ){
|
||||
if( pUpsert && pUpsertClause!=pUpsert ){
|
||||
upsertIpkReturn = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
}else if( ipkTop ){
|
||||
ipkBottom = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
sqlite3VdbeJumpHere(v, ipkTop-1);
|
||||
}
|
||||
@@ -1925,7 +2050,10 @@ void sqlite3GenerateConstraintChecks(
|
||||
** This loop also handles the case of the PRIMARY KEY index for a
|
||||
** WITHOUT ROWID table.
|
||||
*/
|
||||
for(ix=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, ix++){
|
||||
for(pIdx = indexIteratorFirst(&sIdxIter, &ix);
|
||||
pIdx;
|
||||
pIdx = indexIteratorNext(&sIdxIter, &ix)
|
||||
){
|
||||
int regIdx; /* Range of registers hold conent for pIdx */
|
||||
int regR; /* Range of registers holding conflicting PK */
|
||||
int iThisCur; /* Cursor for this UNIQUE index */
|
||||
@@ -1933,15 +2061,14 @@ void sqlite3GenerateConstraintChecks(
|
||||
int addrConflictCk; /* First opcode in the conflict check logic */
|
||||
|
||||
if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */
|
||||
if( pUpIdx==pIdx ){
|
||||
addrUniqueOk = upsertJump+1;
|
||||
upsertBypass = sqlite3VdbeGoto(v, 0);
|
||||
VdbeComment((v, "Skip upsert subroutine"));
|
||||
sqlite3VdbeJumpHere(v, upsertJump);
|
||||
}else{
|
||||
addrUniqueOk = sqlite3VdbeMakeLabel(pParse);
|
||||
if( pUpsert ){
|
||||
pUpsertClause = sqlite3UpsertOfIndex(pUpsert, pIdx);
|
||||
if( upsertIpkDelay && pUpsertClause==pUpsert ){
|
||||
sqlite3VdbeJumpHere(v, upsertIpkDelay);
|
||||
}
|
||||
}
|
||||
if( bAffinityDone==0 && (pUpIdx==0 || pUpIdx==pIdx) ){
|
||||
addrUniqueOk = sqlite3VdbeMakeLabel(pParse);
|
||||
if( bAffinityDone==0 ){
|
||||
sqlite3TableAffinity(v, pTab, regNewData+1);
|
||||
bAffinityDone = 1;
|
||||
}
|
||||
@@ -2012,8 +2139,8 @@ void sqlite3GenerateConstraintChecks(
|
||||
}
|
||||
|
||||
/* Figure out if the upsert clause applies to this index */
|
||||
if( pUpIdx==pIdx ){
|
||||
if( pUpsert->pUpsertSet==0 ){
|
||||
if( pUpsertClause ){
|
||||
if( pUpsertClause->isDoUpdate==0 ){
|
||||
onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */
|
||||
}else{
|
||||
onError = OE_Update; /* DO UPDATE */
|
||||
@@ -2051,7 +2178,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
regIdx, pIdx->nKeyCol); VdbeCoverage(v);
|
||||
|
||||
/* Generate code to handle collisions */
|
||||
regR = (pIdx==pPk) ? regIdx : sqlite3GetTempRange(pParse, nPkField);
|
||||
regR = pIdx==pPk ? regIdx : sqlite3GetTempRange(pParse, nPkField);
|
||||
if( isUpdate || onError==OE_Replace ){
|
||||
if( HasRowid(pTab) ){
|
||||
sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR);
|
||||
@@ -2203,13 +2330,16 @@ void sqlite3GenerateConstraintChecks(
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( pUpIdx==pIdx ){
|
||||
sqlite3VdbeGoto(v, upsertJump+1);
|
||||
sqlite3VdbeJumpHere(v, upsertBypass);
|
||||
}else{
|
||||
sqlite3VdbeResolveLabel(v, addrUniqueOk);
|
||||
}
|
||||
sqlite3VdbeResolveLabel(v, addrUniqueOk);
|
||||
if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField);
|
||||
if( pUpsertClause
|
||||
&& upsertIpkReturn
|
||||
&& sqlite3UpsertNextIsIPK(pUpsertClause)
|
||||
){
|
||||
sqlite3VdbeGoto(v, upsertIpkDelay+1);
|
||||
sqlite3VdbeJumpHere(v, upsertIpkReturn);
|
||||
upsertIpkReturn = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the IPK constraint is a REPLACE, run it last */
|
||||
@@ -2748,6 +2878,7 @@ static int xferOptimization(
|
||||
iDest = pParse->nTab++;
|
||||
regAutoinc = autoIncBegin(pParse, iDbDest, pDest);
|
||||
regData = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regData);
|
||||
regRowid = sqlite3GetTempReg(pParse);
|
||||
sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite);
|
||||
assert( HasRowid(pDest) || destHasUniqueIdx );
|
||||
@@ -2783,11 +2914,13 @@ static int xferOptimization(
|
||||
emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
|
||||
if( pDest->iPKey>=0 ){
|
||||
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
|
||||
sqlite3VdbeVerifyAbortable(v, onError);
|
||||
addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid);
|
||||
VdbeCoverage(v);
|
||||
sqlite3RowidConstraint(pParse, onError, pDest);
|
||||
sqlite3VdbeJumpHere(v, addr2);
|
||||
if( (db->mDbFlags & DBFLAG_Vacuum)==0 ){
|
||||
sqlite3VdbeVerifyAbortable(v, onError);
|
||||
addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid);
|
||||
VdbeCoverage(v);
|
||||
sqlite3RowidConstraint(pParse, onError, pDest);
|
||||
sqlite3VdbeJumpHere(v, addr2);
|
||||
}
|
||||
autoIncStep(pParse, regAutoinc, regRowid);
|
||||
}else if( pDest->pIndex==0 && !(db->mDbFlags & DBFLAG_VacuumInto) ){
|
||||
addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid);
|
||||
@@ -2795,16 +2928,26 @@ static int xferOptimization(
|
||||
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
|
||||
assert( (pDest->tabFlags & TF_Autoincrement)==0 );
|
||||
}
|
||||
|
||||
if( db->mDbFlags & DBFLAG_Vacuum ){
|
||||
sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);
|
||||
insFlags = OPFLAG_APPEND|OPFLAG_USESEEKRESULT;
|
||||
insFlags = OPFLAG_APPEND|OPFLAG_USESEEKRESULT|OPFLAG_PREFORMAT;
|
||||
}else{
|
||||
insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND;
|
||||
insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND|OPFLAG_PREFORMAT;
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
||||
if( db->xPreUpdateCallback ){
|
||||
sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
|
||||
insFlags &= ~OPFLAG_PREFORMAT;
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
sqlite3VdbeAddOp3(v, OP_RowCell, iDest, iSrc, regRowid);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
|
||||
sqlite3VdbeAddOp4(v, OP_Insert, iDest, regData, regRowid,
|
||||
(char*)pDest, P4_TABLE);
|
||||
(char*)pDest, P4_TABLE);
|
||||
sqlite3VdbeChangeP5(v, insFlags);
|
||||
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
|
||||
@@ -2846,13 +2989,16 @@ static int xferOptimization(
|
||||
if( sqlite3_stricmp(sqlite3StrBINARY, zColl) ) break;
|
||||
}
|
||||
if( i==pSrcIdx->nColumn ){
|
||||
idxInsFlags = OPFLAG_USESEEKRESULT;
|
||||
idxInsFlags = OPFLAG_USESEEKRESULT|OPFLAG_PREFORMAT;
|
||||
sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);
|
||||
sqlite3VdbeAddOp3(v, OP_RowCell, iDest, iSrc, regData);
|
||||
}
|
||||
}else if( !HasRowid(pSrc) && pDestIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY ){
|
||||
idxInsFlags |= OPFLAG_NCHANGE;
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
|
||||
if( idxInsFlags!=(OPFLAG_USESEEKRESULT|OPFLAG_PREFORMAT) ){
|
||||
sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, iDest, regData);
|
||||
sqlite3VdbeChangeP5(v, idxInsFlags|OPFLAG_APPEND);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v);
|
||||
|
||||
12
src/parse.y
12
src/parse.y
@@ -960,12 +960,14 @@ cmd ::= with insert_cmd(R) INTO xfullname(X) idlist_opt(F) DEFAULT VALUES.
|
||||
//%destructor upsert {sqlite3UpsertDelete(pParse->db,$$);}
|
||||
upsert(A) ::= . { A = 0; }
|
||||
upsert(A) ::= ON CONFLICT LP sortlist(T) RP where_opt(TW)
|
||||
DO UPDATE SET setlist(Z) where_opt(W).
|
||||
{ A = sqlite3UpsertNew(pParse->db,T,TW,Z,W);}
|
||||
upsert(A) ::= ON CONFLICT LP sortlist(T) RP where_opt(TW) DO NOTHING.
|
||||
{ A = sqlite3UpsertNew(pParse->db,T,TW,0,0); }
|
||||
DO UPDATE SET setlist(Z) where_opt(W) upsert(N).
|
||||
{ A = sqlite3UpsertNew(pParse->db,T,TW,Z,W,N);}
|
||||
upsert(A) ::= ON CONFLICT LP sortlist(T) RP where_opt(TW) DO NOTHING upsert(N).
|
||||
{ A = sqlite3UpsertNew(pParse->db,T,TW,0,0,N); }
|
||||
upsert(A) ::= ON CONFLICT DO NOTHING.
|
||||
{ A = sqlite3UpsertNew(pParse->db,0,0,0,0); }
|
||||
{ A = sqlite3UpsertNew(pParse->db,0,0,0,0,0); }
|
||||
upsert(A) ::= ON CONFLICT DO UPDATE SET setlist(Z) where_opt(W).
|
||||
{ A = sqlite3UpsertNew(pParse->db,0,0,Z,W,0);}
|
||||
|
||||
%type insert_cmd {int}
|
||||
insert_cmd(A) ::= INSERT orconf(R). {A = R;}
|
||||
|
||||
@@ -3698,7 +3698,7 @@ sqlite3_file *sqlite3_database_file_object(const char*);
|
||||
** If the Y parameter to sqlite3_free_filename(Y) is anything other
|
||||
** than a NULL pointer or a pointer previously acquired from
|
||||
** sqlite3_create_filename(), then bad things such as heap
|
||||
** corruption or segfaults may occur. The value Y should be
|
||||
** corruption or segfaults may occur. The value Y should not be
|
||||
** used again after sqlite3_free_filename(Y) has been called. This means
|
||||
** that if the [sqlite3_vfs.xOpen()] method of a VFS has been called using Y,
|
||||
** then the corresponding [sqlite3_module.xClose() method should also be
|
||||
|
||||
@@ -119,6 +119,18 @@
|
||||
# define MSVC_VERSION 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Some C99 functions in "math.h" are only present for MSVC when its version
|
||||
** is associated with Visual Studio 2013 or higher.
|
||||
*/
|
||||
#ifndef SQLITE_HAVE_C99_MATH_FUNCS
|
||||
# if MSVC_VERSION==0 || MSVC_VERSION>=1800
|
||||
# define SQLITE_HAVE_C99_MATH_FUNCS (1)
|
||||
# else
|
||||
# define SQLITE_HAVE_C99_MATH_FUNCS (0)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Needed for various definitions... */
|
||||
#if defined(__GNUC__) && !defined(_GNU_SOURCE)
|
||||
# define _GNU_SOURCE
|
||||
@@ -1002,11 +1014,9 @@ extern u32 sqlite3SelectTrace;
|
||||
/*
|
||||
** Macros for "wheretrace"
|
||||
*/
|
||||
#if !defined(SQLITE_AMAGAMATION)
|
||||
extern u32 sqlite3WhereTrace;
|
||||
#endif
|
||||
#if defined(SQLITE_DEBUG) \
|
||||
&& (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE))
|
||||
extern u32 sqlite3WhereTrace;
|
||||
# define WHERETRACE(K,X) if(sqlite3WhereTrace&(K)) sqlite3DebugPrintf X
|
||||
# define WHERETRACE_ENABLED 1
|
||||
#else
|
||||
@@ -1881,6 +1891,9 @@ struct FuncDestructor {
|
||||
** a single query. The iArg is ignored. The user-data is always set
|
||||
** to a NULL pointer. The bNC parameter is not used.
|
||||
**
|
||||
** MFUNCTION(zName, nArg, xPtr, xFunc)
|
||||
** For math-library functions. xPtr is an arbitrary pointer.
|
||||
**
|
||||
** PURE_DATE(zName, nArg, iArg, bNC, xFunc)
|
||||
** Used for "pure" date/time functions, this macro is like DFUNCTION
|
||||
** except that it does set the SQLITE_FUNC_CONSTANT flags. iArg is
|
||||
@@ -1916,6 +1929,9 @@ struct FuncDestructor {
|
||||
#define SFUNCTION(zName, nArg, iArg, bNC, xFunc) \
|
||||
{nArg, SQLITE_UTF8|SQLITE_DIRECTONLY|SQLITE_FUNC_UNSAFE, \
|
||||
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
|
||||
#define MFUNCTION(zName, nArg, xPtr, xFunc) \
|
||||
{nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \
|
||||
xPtr, 0, xFunc, 0, 0, 0, #zName, {0} }
|
||||
#define INLINE_FUNC(zName, nArg, iArg, mFlags) \
|
||||
{nArg, SQLITE_UTF8|SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \
|
||||
SQLITE_INT_TO_PTR(iArg), 0, noopFunc, 0, 0, 0, #zName, {0} }
|
||||
@@ -2318,16 +2334,22 @@ struct FKey {
|
||||
** is returned. REPLACE means that preexisting database rows that caused
|
||||
** a UNIQUE constraint violation are removed so that the new insert or
|
||||
** update can proceed. Processing continues and no error is reported.
|
||||
** UPDATE applies to insert operations only and means that the insert
|
||||
** is omitted and the DO UPDATE clause of an upsert is run instead.
|
||||
**
|
||||
** RESTRICT, SETNULL, and CASCADE actions apply only to foreign keys.
|
||||
** RESTRICT, SETNULL, SETDFLT, and CASCADE actions apply only to foreign keys.
|
||||
** RESTRICT is the same as ABORT for IMMEDIATE foreign keys and the
|
||||
** same as ROLLBACK for DEFERRED keys. SETNULL means that the foreign
|
||||
** key is set to NULL. CASCADE means that a DELETE or UPDATE of the
|
||||
** key is set to NULL. SETDFLT means that the foreign key is set
|
||||
** to its default value. CASCADE means that a DELETE or UPDATE of the
|
||||
** referenced table row is propagated into the row that holds the
|
||||
** foreign key.
|
||||
**
|
||||
** The OE_Default value is a place holder that means to use whatever
|
||||
** conflict resolution algorthm is required from context.
|
||||
**
|
||||
** The following symbolic values are used to record which type
|
||||
** of action to take.
|
||||
** of conflict resolution action to take.
|
||||
*/
|
||||
#define OE_None 0 /* There is no constraint to check */
|
||||
#define OE_Rollback 1 /* Fail the operation and rollback the transaction */
|
||||
@@ -3081,15 +3103,21 @@ struct NameContext {
|
||||
** WHERE clause is omitted.
|
||||
*/
|
||||
struct Upsert {
|
||||
ExprList *pUpsertTarget; /* Optional description of conflicting index */
|
||||
ExprList *pUpsertTarget; /* Optional description of conflict target */
|
||||
Expr *pUpsertTargetWhere; /* WHERE clause for partial index targets */
|
||||
ExprList *pUpsertSet; /* The SET clause from an ON CONFLICT UPDATE */
|
||||
Expr *pUpsertWhere; /* WHERE clause for the ON CONFLICT UPDATE */
|
||||
/* The fields above comprise the parse tree for the upsert clause.
|
||||
** The fields below are used to transfer information from the INSERT
|
||||
** processing down into the UPDATE processing while generating code.
|
||||
** Upsert owns the memory allocated above, but not the memory below. */
|
||||
Index *pUpsertIdx; /* Constraint that pUpsertTarget identifies */
|
||||
Upsert *pNextUpsert; /* Next ON CONFLICT clause in the list */
|
||||
u8 isDoUpdate; /* True for DO UPDATE. False for DO NOTHING */
|
||||
/* Above this point is the parse tree for the ON CONFLICT clauses.
|
||||
** The next group of fields stores intermediate data. */
|
||||
void *pToFree; /* Free memory when deleting the Upsert object */
|
||||
/* All fields above are owned by the Upsert object and must be freed
|
||||
** when the Upsert is destroyed. The fields below are used to transfer
|
||||
** information from the INSERT processing down into the UPDATE processing
|
||||
** while generating code. The fields below are owned by the INSERT
|
||||
** statement and will be freed by INSERT processing. */
|
||||
Index *pUpsertIdx; /* UNIQUE constraint specified by pUpsertTarget */
|
||||
SrcList *pUpsertSrc; /* Table to be updated */
|
||||
int regData; /* First register holding array of VALUES */
|
||||
int iDataCur; /* Index of the data cursor */
|
||||
@@ -3530,6 +3558,7 @@ struct AuthContext {
|
||||
#define OPFLAG_SAVEPOSITION 0x02 /* OP_Delete/Insert: save cursor pos */
|
||||
#define OPFLAG_AUXDELETE 0x04 /* OP_Delete: index in a DELETE op */
|
||||
#define OPFLAG_NOCHNG_MAGIC 0x6d /* OP_MakeRecord: serialtype 10 is ok */
|
||||
#define OPFLAG_PREFORMAT 0x80 /* OP_Insert uses preformatted cell */
|
||||
|
||||
/*
|
||||
* Each trigger present in the database schema is stored as an instance of
|
||||
@@ -4864,15 +4893,19 @@ const char *sqlite3JournalModename(int);
|
||||
#define sqlite3WithDelete(x,y)
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_UPSERT
|
||||
Upsert *sqlite3UpsertNew(sqlite3*,ExprList*,Expr*,ExprList*,Expr*);
|
||||
Upsert *sqlite3UpsertNew(sqlite3*,ExprList*,Expr*,ExprList*,Expr*,Upsert*);
|
||||
void sqlite3UpsertDelete(sqlite3*,Upsert*);
|
||||
Upsert *sqlite3UpsertDup(sqlite3*,Upsert*);
|
||||
int sqlite3UpsertAnalyzeTarget(Parse*,SrcList*,Upsert*);
|
||||
void sqlite3UpsertDoUpdate(Parse*,Upsert*,Table*,Index*,int);
|
||||
Upsert *sqlite3UpsertOfIndex(Upsert*,Index*);
|
||||
int sqlite3UpsertNextIsIPK(Upsert*);
|
||||
#else
|
||||
#define sqlite3UpsertNew(v,w,x,y,z) ((Upsert*)0)
|
||||
#define sqlite3UpsertNew(u,v,w,x,y,z) ((Upsert*)0)
|
||||
#define sqlite3UpsertDelete(x,y)
|
||||
#define sqlite3UpsertDup(x,y) ((Upsert*)0)
|
||||
#define sqlite3UpsertDup(x,y) ((Upsert*)0)
|
||||
#define sqlite3UpsertOfIndex(x,y) ((Upsert*)0)
|
||||
#define sqlite3UpsertNextIsIPK(x) 0
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -154,6 +154,12 @@ static void set_options(Tcl_Interp *interp){
|
||||
Tcl_SetVar2(interp, "sqlite_options", "deserialize", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_MATH_FUNCTIONS
|
||||
Tcl_SetVar2(interp, "sqlite_options", "mathlib", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "mathlib", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_MEMSYS3
|
||||
Tcl_SetVar2(interp, "sqlite_options", "mem3", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
|
||||
244
src/upsert.c
244
src/upsert.c
@@ -18,15 +18,22 @@
|
||||
/*
|
||||
** Free a list of Upsert objects
|
||||
*/
|
||||
void sqlite3UpsertDelete(sqlite3 *db, Upsert *p){
|
||||
if( p ){
|
||||
static void SQLITE_NOINLINE upsertDelete(sqlite3 *db, Upsert *p){
|
||||
do{
|
||||
Upsert *pNext = p->pNextUpsert;
|
||||
sqlite3ExprListDelete(db, p->pUpsertTarget);
|
||||
sqlite3ExprDelete(db, p->pUpsertTargetWhere);
|
||||
sqlite3ExprListDelete(db, p->pUpsertSet);
|
||||
sqlite3ExprDelete(db, p->pUpsertWhere);
|
||||
sqlite3DbFree(db, p->pToFree);
|
||||
sqlite3DbFree(db, p);
|
||||
}
|
||||
p = pNext;
|
||||
}while( p );
|
||||
}
|
||||
void sqlite3UpsertDelete(sqlite3 *db, Upsert *p){
|
||||
if( p ) upsertDelete(db, p);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Duplicate an Upsert object.
|
||||
@@ -37,7 +44,8 @@ Upsert *sqlite3UpsertDup(sqlite3 *db, Upsert *p){
|
||||
sqlite3ExprListDup(db, p->pUpsertTarget, 0),
|
||||
sqlite3ExprDup(db, p->pUpsertTargetWhere, 0),
|
||||
sqlite3ExprListDup(db, p->pUpsertSet, 0),
|
||||
sqlite3ExprDup(db, p->pUpsertWhere, 0)
|
||||
sqlite3ExprDup(db, p->pUpsertWhere, 0),
|
||||
sqlite3UpsertDup(db, p->pNextUpsert)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -49,22 +57,25 @@ Upsert *sqlite3UpsertNew(
|
||||
ExprList *pTarget, /* Target argument to ON CONFLICT, or NULL */
|
||||
Expr *pTargetWhere, /* Optional WHERE clause on the target */
|
||||
ExprList *pSet, /* UPDATE columns, or NULL for a DO NOTHING */
|
||||
Expr *pWhere /* WHERE clause for the ON CONFLICT UPDATE */
|
||||
Expr *pWhere, /* WHERE clause for the ON CONFLICT UPDATE */
|
||||
Upsert *pNext /* Next ON CONFLICT clause in the list */
|
||||
){
|
||||
Upsert *pNew;
|
||||
pNew = sqlite3DbMallocRaw(db, sizeof(Upsert));
|
||||
pNew = sqlite3DbMallocZero(db, sizeof(Upsert));
|
||||
if( pNew==0 ){
|
||||
sqlite3ExprListDelete(db, pTarget);
|
||||
sqlite3ExprDelete(db, pTargetWhere);
|
||||
sqlite3ExprListDelete(db, pSet);
|
||||
sqlite3ExprDelete(db, pWhere);
|
||||
sqlite3UpsertDelete(db, pNext);
|
||||
return 0;
|
||||
}else{
|
||||
pNew->pUpsertTarget = pTarget;
|
||||
pNew->pUpsertTargetWhere = pTargetWhere;
|
||||
pNew->pUpsertSet = pSet;
|
||||
pNew->pUpsertWhere = pWhere;
|
||||
pNew->pUpsertIdx = 0;
|
||||
pNew->isDoUpdate = pSet!=0;
|
||||
pNew->pNextUpsert = pNext;
|
||||
}
|
||||
return pNew;
|
||||
}
|
||||
@@ -89,6 +100,7 @@ int sqlite3UpsertAnalyzeTarget(
|
||||
Expr *pTerm; /* One term of the conflict-target clause */
|
||||
NameContext sNC; /* Context for resolving symbolic names */
|
||||
Expr sCol[2]; /* Index column converted into an Expr */
|
||||
int nClause = 0; /* Counter of ON CONFLICT clauses */
|
||||
|
||||
assert( pTabList->nSrc==1 );
|
||||
assert( pTabList->a[0].pTab!=0 );
|
||||
@@ -102,87 +114,131 @@ int sqlite3UpsertAnalyzeTarget(
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
sNC.pParse = pParse;
|
||||
sNC.pSrcList = pTabList;
|
||||
rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget);
|
||||
if( rc ) return rc;
|
||||
rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere);
|
||||
if( rc ) return rc;
|
||||
|
||||
/* Check to see if the conflict target matches the rowid. */
|
||||
pTab = pTabList->a[0].pTab;
|
||||
pTarget = pUpsert->pUpsertTarget;
|
||||
iCursor = pTabList->a[0].iCursor;
|
||||
if( HasRowid(pTab)
|
||||
&& pTarget->nExpr==1
|
||||
&& (pTerm = pTarget->a[0].pExpr)->op==TK_COLUMN
|
||||
&& pTerm->iColumn==XN_ROWID
|
||||
){
|
||||
/* The conflict-target is the rowid of the primary table */
|
||||
assert( pUpsert->pUpsertIdx==0 );
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Initialize sCol[0..1] to be an expression parse tree for a
|
||||
** single column of an index. The sCol[0] node will be the TK_COLLATE
|
||||
** operator and sCol[1] will be the TK_COLUMN operator. Code below
|
||||
** will populate the specific collation and column number values
|
||||
** prior to comparing against the conflict-target expression.
|
||||
*/
|
||||
memset(sCol, 0, sizeof(sCol));
|
||||
sCol[0].op = TK_COLLATE;
|
||||
sCol[0].pLeft = &sCol[1];
|
||||
sCol[1].op = TK_COLUMN;
|
||||
sCol[1].iTable = pTabList->a[0].iCursor;
|
||||
|
||||
/* Check for matches against other indexes */
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
int ii, jj, nn;
|
||||
if( !IsUniqueIndex(pIdx) ) continue;
|
||||
if( pTarget->nExpr!=pIdx->nKeyCol ) continue;
|
||||
if( pIdx->pPartIdxWhere ){
|
||||
if( pUpsert->pUpsertTargetWhere==0 ) continue;
|
||||
if( sqlite3ExprCompare(pParse, pUpsert->pUpsertTargetWhere,
|
||||
pIdx->pPartIdxWhere, iCursor)!=0 ){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
nn = pIdx->nKeyCol;
|
||||
for(ii=0; ii<nn; ii++){
|
||||
Expr *pExpr;
|
||||
sCol[0].u.zToken = (char*)pIdx->azColl[ii];
|
||||
if( pIdx->aiColumn[ii]==XN_EXPR ){
|
||||
assert( pIdx->aColExpr!=0 );
|
||||
assert( pIdx->aColExpr->nExpr>ii );
|
||||
pExpr = pIdx->aColExpr->a[ii].pExpr;
|
||||
if( pExpr->op!=TK_COLLATE ){
|
||||
sCol[0].pLeft = pExpr;
|
||||
pExpr = &sCol[0];
|
||||
}
|
||||
}else{
|
||||
sCol[0].pLeft = &sCol[1];
|
||||
sCol[1].iColumn = pIdx->aiColumn[ii];
|
||||
pExpr = &sCol[0];
|
||||
}
|
||||
for(jj=0; jj<nn; jj++){
|
||||
if( sqlite3ExprCompare(pParse, pTarget->a[jj].pExpr, pExpr,iCursor)<2 ){
|
||||
break; /* Column ii of the index matches column jj of target */
|
||||
}
|
||||
}
|
||||
if( jj>=nn ){
|
||||
/* The target contains no match for column jj of the index */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( ii<nn ){
|
||||
/* Column ii of the index did not match any term of the conflict target.
|
||||
** Continue the search with the next index. */
|
||||
for(; pUpsert && pUpsert->pUpsertTarget;
|
||||
pUpsert=pUpsert->pNextUpsert, nClause++){
|
||||
rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget);
|
||||
if( rc ) return rc;
|
||||
rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere);
|
||||
if( rc ) return rc;
|
||||
|
||||
/* Check to see if the conflict target matches the rowid. */
|
||||
pTab = pTabList->a[0].pTab;
|
||||
pTarget = pUpsert->pUpsertTarget;
|
||||
iCursor = pTabList->a[0].iCursor;
|
||||
if( HasRowid(pTab)
|
||||
&& pTarget->nExpr==1
|
||||
&& (pTerm = pTarget->a[0].pExpr)->op==TK_COLUMN
|
||||
&& pTerm->iColumn==XN_ROWID
|
||||
){
|
||||
/* The conflict-target is the rowid of the primary table */
|
||||
assert( pUpsert->pUpsertIdx==0 );
|
||||
continue;
|
||||
}
|
||||
pUpsert->pUpsertIdx = pIdx;
|
||||
return SQLITE_OK;
|
||||
|
||||
/* Initialize sCol[0..1] to be an expression parse tree for a
|
||||
** single column of an index. The sCol[0] node will be the TK_COLLATE
|
||||
** operator and sCol[1] will be the TK_COLUMN operator. Code below
|
||||
** will populate the specific collation and column number values
|
||||
** prior to comparing against the conflict-target expression.
|
||||
*/
|
||||
memset(sCol, 0, sizeof(sCol));
|
||||
sCol[0].op = TK_COLLATE;
|
||||
sCol[0].pLeft = &sCol[1];
|
||||
sCol[1].op = TK_COLUMN;
|
||||
sCol[1].iTable = pTabList->a[0].iCursor;
|
||||
|
||||
/* Check for matches against other indexes */
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
int ii, jj, nn;
|
||||
if( !IsUniqueIndex(pIdx) ) continue;
|
||||
if( pTarget->nExpr!=pIdx->nKeyCol ) continue;
|
||||
if( pIdx->pPartIdxWhere ){
|
||||
if( pUpsert->pUpsertTargetWhere==0 ) continue;
|
||||
if( sqlite3ExprCompare(pParse, pUpsert->pUpsertTargetWhere,
|
||||
pIdx->pPartIdxWhere, iCursor)!=0 ){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
nn = pIdx->nKeyCol;
|
||||
for(ii=0; ii<nn; ii++){
|
||||
Expr *pExpr;
|
||||
sCol[0].u.zToken = (char*)pIdx->azColl[ii];
|
||||
if( pIdx->aiColumn[ii]==XN_EXPR ){
|
||||
assert( pIdx->aColExpr!=0 );
|
||||
assert( pIdx->aColExpr->nExpr>ii );
|
||||
pExpr = pIdx->aColExpr->a[ii].pExpr;
|
||||
if( pExpr->op!=TK_COLLATE ){
|
||||
sCol[0].pLeft = pExpr;
|
||||
pExpr = &sCol[0];
|
||||
}
|
||||
}else{
|
||||
sCol[0].pLeft = &sCol[1];
|
||||
sCol[1].iColumn = pIdx->aiColumn[ii];
|
||||
pExpr = &sCol[0];
|
||||
}
|
||||
for(jj=0; jj<nn; jj++){
|
||||
if( sqlite3ExprCompare(pParse,pTarget->a[jj].pExpr,pExpr,iCursor)<2 ){
|
||||
break; /* Column ii of the index matches column jj of target */
|
||||
}
|
||||
}
|
||||
if( jj>=nn ){
|
||||
/* The target contains no match for column jj of the index */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( ii<nn ){
|
||||
/* Column ii of the index did not match any term of the conflict target.
|
||||
** Continue the search with the next index. */
|
||||
continue;
|
||||
}
|
||||
pUpsert->pUpsertIdx = pIdx;
|
||||
break;
|
||||
}
|
||||
if( pUpsert->pUpsertIdx==0 ){
|
||||
char zWhich[16];
|
||||
if( nClause==0 && pUpsert->pNextUpsert==0 ){
|
||||
zWhich[0] = 0;
|
||||
}else{
|
||||
sqlite3_snprintf(sizeof(zWhich),zWhich,"%r ", nClause+1);
|
||||
}
|
||||
sqlite3ErrorMsg(pParse, "%sON CONFLICT clause does not match any "
|
||||
"PRIMARY KEY or UNIQUE constraint", zWhich);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
}
|
||||
sqlite3ErrorMsg(pParse, "ON CONFLICT clause does not match any "
|
||||
"PRIMARY KEY or UNIQUE constraint");
|
||||
return SQLITE_ERROR;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if pUpsert is the last ON CONFLICT clause with a
|
||||
** conflict target, or if pUpsert is followed by another ON CONFLICT
|
||||
** clause that targets the INTEGER PRIMARY KEY.
|
||||
*/
|
||||
int sqlite3UpsertNextIsIPK(Upsert *pUpsert){
|
||||
Upsert *pNext;
|
||||
if( NEVER(pUpsert==0) ) return 0;
|
||||
pNext = pUpsert->pNextUpsert;
|
||||
if( pNext==0 ) return 1;
|
||||
if( pNext->pUpsertTarget==0 ) return 1;
|
||||
if( pNext->pUpsertIdx==0 ) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Given the list of ON CONFLICT clauses described by pUpsert, and
|
||||
** a particular index pIdx, return a pointer to the particular ON CONFLICT
|
||||
** clause that applies to the index. Or, if the index is not subject to
|
||||
** any ON CONFLICT clause, return NULL.
|
||||
*/
|
||||
Upsert *sqlite3UpsertOfIndex(Upsert *pUpsert, Index *pIdx){
|
||||
while(
|
||||
pUpsert
|
||||
&& pUpsert->pUpsertTarget!=0
|
||||
&& pUpsert->pUpsertIdx!=pIdx
|
||||
){
|
||||
pUpsert = pUpsert->pNextUpsert;
|
||||
}
|
||||
return pUpsert;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -206,11 +262,13 @@ void sqlite3UpsertDoUpdate(
|
||||
SrcList *pSrc; /* FROM clause for the UPDATE */
|
||||
int iDataCur;
|
||||
int i;
|
||||
Upsert *pTop = pUpsert;
|
||||
|
||||
assert( v!=0 );
|
||||
assert( pUpsert!=0 );
|
||||
VdbeNoopComment((v, "Begin DO UPDATE of UPSERT"));
|
||||
iDataCur = pUpsert->iDataCur;
|
||||
pUpsert = sqlite3UpsertOfIndex(pTop, pIdx);
|
||||
VdbeNoopComment((v, "Begin DO UPDATE of UPSERT"));
|
||||
if( pIdx && iCur!=iDataCur ){
|
||||
if( HasRowid(pTab) ){
|
||||
int regRowid = sqlite3GetTempReg(pParse);
|
||||
@@ -240,19 +298,17 @@ void sqlite3UpsertDoUpdate(
|
||||
sqlite3VdbeJumpHere(v, i);
|
||||
}
|
||||
}
|
||||
/* pUpsert does not own pUpsertSrc - the outer INSERT statement does. So
|
||||
** we have to make a copy before passing it down into sqlite3Update() */
|
||||
pSrc = sqlite3SrcListDup(db, pUpsert->pUpsertSrc, 0);
|
||||
/* pUpsert does not own pTop->pUpsertSrc - the outer INSERT statement does.
|
||||
** So we have to make a copy before passing it down into sqlite3Update() */
|
||||
pSrc = sqlite3SrcListDup(db, pTop->pUpsertSrc, 0);
|
||||
/* excluded.* columns of type REAL need to be converted to a hard real */
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
|
||||
sqlite3VdbeAddOp1(v, OP_RealAffinity, pUpsert->regData+i);
|
||||
sqlite3VdbeAddOp1(v, OP_RealAffinity, pTop->regData+i);
|
||||
}
|
||||
}
|
||||
sqlite3Update(pParse, pSrc, pUpsert->pUpsertSet,
|
||||
pUpsert->pUpsertWhere, OE_Abort, 0, 0, pUpsert);
|
||||
pUpsert->pUpsertSet = 0; /* Will have been deleted by sqlite3Update() */
|
||||
pUpsert->pUpsertWhere = 0; /* Will have been deleted by sqlite3Update() */
|
||||
sqlite3Update(pParse, pSrc, sqlite3ExprListDup(db,pUpsert->pUpsertSet,0),
|
||||
sqlite3ExprDup(db,pUpsert->pUpsertWhere,0), OE_Abort, 0, 0, pUpsert);
|
||||
VdbeNoopComment((v, "End DO UPDATE of UPSERT"));
|
||||
}
|
||||
|
||||
|
||||
32
src/vdbe.c
32
src/vdbe.c
@@ -5126,7 +5126,8 @@ case OP_Insert: {
|
||||
}
|
||||
x.pKey = 0;
|
||||
rc = sqlite3BtreeInsert(pC->uc.pCursor, &x,
|
||||
(pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION)), seekResult
|
||||
(pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION|OPFLAG_PREFORMAT)),
|
||||
seekResult
|
||||
);
|
||||
pC->deferredMoveto = 0;
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
@@ -5143,6 +5144,31 @@ case OP_Insert: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: RowCell P1 P2 P3 * *
|
||||
**
|
||||
** P1 and P2 are both open cursors. Both must be opened on the same type
|
||||
** of table - intkey or index. This opcode is used as part of copying
|
||||
** the current row from P2 into P1. If the cursors are opened on intkey
|
||||
** tables, register P3 contains the rowid to use with the new record in
|
||||
** P1. If they are opened on index tables, P3 is not used.
|
||||
**
|
||||
** This opcode must be followed by either an Insert or InsertIdx opcode
|
||||
** with the OPFLAG_PREFORMAT flag set to complete the insert operation.
|
||||
*/
|
||||
case OP_RowCell: {
|
||||
VdbeCursor *pDest; /* Cursor to write to */
|
||||
VdbeCursor *pSrc; /* Cursor to read from */
|
||||
i64 iKey; /* Rowid value to insert with */
|
||||
assert( pOp[1].opcode==OP_Insert || pOp[1].opcode==OP_IdxInsert );
|
||||
assert( pOp[1].p5 & OPFLAG_PREFORMAT );
|
||||
pDest = p->apCsr[pOp->p1];
|
||||
pSrc = p->apCsr[pOp->p2];
|
||||
iKey = pOp->p3 ? aMem[pOp->p3].u.i : 0;
|
||||
rc = sqlite3BtreeTransferRow(pDest->uc.pCursor, pSrc->uc.pCursor, iKey);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
break;
|
||||
};
|
||||
|
||||
/* Opcode: Delete P1 P2 P3 P4 P5
|
||||
**
|
||||
** Delete the record at which the P1 cursor is currently pointing.
|
||||
@@ -5798,7 +5824,7 @@ case OP_IdxInsert: { /* in2 */
|
||||
assert( pC!=0 );
|
||||
assert( !isSorter(pC) );
|
||||
pIn2 = &aMem[pOp->p2];
|
||||
assert( pIn2->flags & MEM_Blob );
|
||||
assert( (pIn2->flags & MEM_Blob) || (pOp->p5 & OPFLAG_PREFORMAT) );
|
||||
if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
|
||||
assert( pC->eCurType==CURTYPE_BTREE );
|
||||
assert( pC->isTable==0 );
|
||||
@@ -5809,7 +5835,7 @@ case OP_IdxInsert: { /* in2 */
|
||||
x.aMem = aMem + pOp->p3;
|
||||
x.nMem = (u16)pOp->p4.i;
|
||||
rc = sqlite3BtreeInsert(pC->uc.pCursor, &x,
|
||||
(pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION)),
|
||||
(pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION|OPFLAG_PREFORMAT)),
|
||||
((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0)
|
||||
);
|
||||
assert( pC->deferredMoveto==0 );
|
||||
|
||||
@@ -125,7 +125,7 @@ char *sqlite3VdbeExpandSql(
|
||||
assert( idx>0 );
|
||||
}
|
||||
zRawSql += nToken;
|
||||
nextIndex = idx + 1;
|
||||
nextIndex = MAX(idx + 1, nextIndex);
|
||||
assert( idx>0 && idx<=p->nVar );
|
||||
pVar = &p->aVar[idx-1];
|
||||
if( pVar->flags & MEM_Null ){
|
||||
|
||||
106
test/corruptN.test
Normal file
106
test/corruptN.test
Normal file
@@ -0,0 +1,106 @@
|
||||
# 2020-12-16
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix corruptN
|
||||
|
||||
# These tests deal with corrupt database files
|
||||
#
|
||||
database_may_be_corrupt
|
||||
|
||||
reset_db
|
||||
do_test 1.0 {
|
||||
sqlite3 db {}
|
||||
db deserialize [decode_hexdb {
|
||||
.open --hexdb
|
||||
| size 4096 pagesize 512 filename sql024239.txt.db
|
||||
| page 1 offset 0
|
||||
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
|
||||
| 16: 02 00 01 01 00 40 20 20 00 00 00 0c 00 00 00 07 .....@ ........
|
||||
| 32: 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 04 ................
|
||||
| 48: 00 00 00 00 89 00 00 04 00 10 00 01 0a 00 00 01 ................
|
||||
| 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0c ................
|
||||
| 96: 00 2e 2c 50 0d 00 00 00 06 01 06 00 01 da 01 b0 ..,P............
|
||||
| 112: 01 56 01 86 01 2a 01 06 00 00 00 00 00 00 00 00 .V...*..........
|
||||
| 256: 00 00 00 00 00 00 22 07 06 17 11 11 01 31 74 61 .............1ta
|
||||
| 272: 62 6c 65 74 34 74 34 07 43 52 45 41 54 45 20 54 blet4t4.CREATE T
|
||||
| 288: 41 42 4c 45 20 74 34 28 78 29 2a 06 06 17 13 11 ABLE t4(x)*.....
|
||||
| 304: 01 3f 69 6e 64 65 78 74 33 78 74 33 05 43 52 45 .?indext3xt3.CRE
|
||||
| 320: 41 54 45 20 49 4e 44 45 58 20 74 33 78 20 4f 4e ATE INDEX t3x ON
|
||||
| 336: 20 74 33 28 78 29 2e 04 06 17 15 11 01 45 69 6e t3(x).......Ein
|
||||
| 352: 64 65 78 74 32 63 64 74 32 05 43 52 45 41 54 45 dext2cdt2.CREATE
|
||||
| 368: 20 49 4e 44 45 58 20 74 32 63 64 20 4f 4e 20 74 INDEX t2cd ON t
|
||||
| 384: 32 28 63 2c 64 29 28 05 06 17 11 11 01 3d 74 61 2(c,d)(......=ta
|
||||
| 400: 62 6c 65 74 33 74 33 07 43 52 45 41 54 45 20 54 blet3t3.CREATE T
|
||||
| 416: 41 42 4c 45 20 74 33 28 63 2c 78 2c 65 2c 66 29 ABLE t3(c,x,e,f)
|
||||
| 432: 28 02 06 17 11 11 01 3d 74 61 62 6c 65 74 32 74 (......=tablet2t
|
||||
| 448: 32 03 43 52 45 41 54 45 20 54 41 42 4c 45 20 74 2.CREATE TABLE t
|
||||
| 464: 32 28 63 2c 64 2c 65 2c 66 29 24 01 06 17 11 11 2(c,d,e,f)$.....
|
||||
| 480: 01 35 74 61 62 6c 65 74 31 74 31 02 43 52 45 41 .5tablet1t1.CREA
|
||||
| 496: 54 45 20 54 41 42 4c 45 20 74 31 28 61 2c 62 29 TE TABLE t1(a,b)
|
||||
| page 2 offset 512
|
||||
| 0: 0d 00 00 00 04 01 41 00 01 fa 01 f3 01 de 01 cf ......A.........
|
||||
| 160: 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 .. .............
|
||||
| 448: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0d ................
|
||||
| 464: 04 03 17 17 73 65 76 65 6e 65 69 67 68 74 13 03 ....seveneight..
|
||||
| 480: 03 07 07 40 14 00 00 00 00 00 00 40 18 00 00 00 ...@.......@....
|
||||
| 496: 00 00 00 05 02 03 01 01 03 04 04 01 03 09 01 02 ................
|
||||
| page 3 offset 1024
|
||||
| 0: 0d 00 00 00 08 01 54 00 01 f7 01 ec 01 c5 01 aa ......T.........
|
||||
| 16: 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 112: 00 00 dd 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 336: 00 00 00 00 19 08 05 17 17 17 17 65 69 67 68 74 ...........eight
|
||||
| 352: 65 69 67 68 74 73 65 76 65 6e 73 65 76 65 6e 25 eightsevenseven%
|
||||
| 368: 07 05 07 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 432: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 ................
|
||||
| 480: 00 00 0f 04 17 17 01 65 69 67 68 74 65 69 67 68 .......eighteigh
|
||||
| 496: 74 08 15 04 07 07 01 40 18 00 00 00 00 00 00 40 t......@.......@
|
||||
| page 4 offset 1536
|
||||
| 0: 18 00 00 00 00 00 00 07 07 04 01 01 01 04 04 06 ................
|
||||
| 16: 07 04 01 01 01 02 02 05 0f 04 17 17 01 73 6d 76 .............smv
|
||||
| 32: 65 6e 65 69 67 68 74 04 15 04 07 07 01 40 14 00 eneight......@..
|
||||
| page 5 offset 2048
|
||||
| 0: 0a 00 00 00 08 01 96 00 01 fa 01 c4 01 f2 01 bc ................
|
||||
| 16: 01 dc 01 e1 01 96 01 cc 00 00 00 00 00 00 00 00 ................
|
||||
| 160: 00 00 00 00 00 00 32 00 00 00 00 00 00 00 00 00 ......2.........
|
||||
| 368: 00 00 00 08 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 400: 00 00 00 00 00 00 0f 04 17 17 01 85 69 67 68 74 ............ight
|
||||
| 416: 65 69 67 68 74 08 15 04 07 07 01 40 18 00 00 00 eight......@....
|
||||
| 432: 00 00 00 40 18 00 00 00 00 00 00 07 07 04 01 01 ...@............
|
||||
| 448: 01 04 04 06 07 04 01 01 01 02 02 05 0f 04 17 17 ................
|
||||
| 464: 01 73 6d 76 65 6e 65 69 67 68 74 04 15 04 07 07 .smveneight.....
|
||||
| 480: 01 40 14 00 00 00 00 00 00 40 18 00 00 00 00 00 .@.......@......
|
||||
| 496: 00 03 07 04 01 01 01 03 04 02 05 04 03 01 09 02 ................
|
||||
| page 6 offset 2560
|
||||
| 0: 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| 16: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 00 ................
|
||||
| 304: 00 00 00 26 00 00 00 00 00 00 00 00 00 00 00 00 ...&............
|
||||
| page 7 offset 3072
|
||||
| 0: 0d 00 00 00 08 01 c2 00 01 fb 01 f6 01 f1 01 ec ................
|
||||
| 16: 01 e0 01 d4 01 cb 01 c2 00 00 00 00 00 00 00 00 ................
|
||||
| 128: 00 00 00 00 00 00 00 00 00 00 00 00 00 20 00 04 ............. ..
|
||||
| 384: 00 00 00 00 00 00 00 00 00 07 08 02 17 65 69 fc .............ei.
|
||||
| 400: 68 74 07 07 02 17 65 69 67 68 74 0a fb fd f8 bf ht....eight.....
|
||||
| 416: e7 ff ff ff 00 00 00 0a 05 02 07 40 18 00 00 00 ...........@....
|
||||
| 432: 00 00 00 03 04 02 01 04 03 03 02 01 04 03 02 01 ................
|
||||
| 448: ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 ................
|
||||
| end sql024239.txt.db
|
||||
}]} {}
|
||||
|
||||
do_catchsql_test 1.1 {
|
||||
VACUUM;
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
|
||||
finish_test
|
||||
245
test/func7.test
Normal file
245
test/func7.test
Normal file
@@ -0,0 +1,245 @@
|
||||
# 2020-12-07
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#*************************************************************************
|
||||
#
|
||||
# Test cases for SQL functions based off the standard math library
|
||||
#
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
ifcapable !mathlib {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_execsql_test func7-100 {
|
||||
SELECT ceil(99.9), ceiling(-99.01), floor(17), floor(-17.99);
|
||||
} {100.0 -99.0 17 -18.0}
|
||||
do_execsql_test func7-110 {
|
||||
SELECT quote(ceil(NULL)), ceil('-99.99');
|
||||
} {NULL -99.0}
|
||||
do_execsql_test func7-200 {
|
||||
SELECT round(ln(5),2), log(100.0), log(100), log(2,'256');
|
||||
} {1.61 2.0 2.0 8.0}
|
||||
do_execsql_test func7-210 {
|
||||
SELECT ln(-5), log(-5,100.0);
|
||||
} {{} {}}
|
||||
|
||||
# Test cases derived from PostgreSQL documentation
|
||||
#
|
||||
do_execsql_test func7-pg-100 {
|
||||
SELECT abs(-17.4)
|
||||
} {17.4}
|
||||
do_execsql_test func7-pg-110 {
|
||||
SELECT ceil(42.2)
|
||||
} {43.0}
|
||||
do_execsql_test func7-pg-120 {
|
||||
SELECT ceil(-42.2)
|
||||
} {-42.0}
|
||||
do_execsql_test func7-pg-130 {
|
||||
SELECT round(exp(1.0),7)
|
||||
} {2.7182818}
|
||||
do_execsql_test func7-pg-140 {
|
||||
SELECT floor(42.8)
|
||||
} {42.0}
|
||||
do_execsql_test func7-pg-150 {
|
||||
SELECT floor(-42.8)
|
||||
} {-43.0}
|
||||
do_execsql_test func7-pg-160 {
|
||||
SELECT round(ln(2.0),7)
|
||||
} {0.6931472}
|
||||
do_execsql_test func7-pg-170 {
|
||||
SELECT log(100.0)
|
||||
} {2.0}
|
||||
do_execsql_test func7-pg-180 {
|
||||
SELECT log10(1000.0)
|
||||
} {3.0}
|
||||
do_execsql_test func7-pg-190 {
|
||||
SELECT log(2.0, 64.0)
|
||||
} {6.0}
|
||||
do_execsql_test func7-pg-200 {
|
||||
SELECT mod(9,4);
|
||||
} {1.0}
|
||||
do_execsql_test func7-pg-210 {
|
||||
SELECT round(pi(),7);
|
||||
} {3.1415927}
|
||||
do_execsql_test func7-pg-220 {
|
||||
SELECT power(9,3);
|
||||
} {729.0}
|
||||
do_execsql_test func7-pg-230 {
|
||||
SELECT round(radians(45.0),7);
|
||||
} {0.7853982}
|
||||
do_execsql_test func7-pg-240 {
|
||||
SELECT round(42.4);
|
||||
} {42.0}
|
||||
do_execsql_test func7-pg-250 {
|
||||
SELECT round(42.4382,2);
|
||||
} {42.44}
|
||||
do_execsql_test func7-pg-260 {
|
||||
SELECT sign(-8.4);
|
||||
} {-1}
|
||||
do_execsql_test func7-pg-270 {
|
||||
SELECT round( sqrt(2), 7);
|
||||
} {1.4142136}
|
||||
do_execsql_test func7-pg-280 {
|
||||
SELECT trunc(42.8), trunc(-42.8);
|
||||
} {42.0 -42.0}
|
||||
do_execsql_test func7-pg-300 {
|
||||
SELECT acos(1);
|
||||
} {0.0}
|
||||
do_execsql_test func7-pg-301 {
|
||||
SELECT degrees(acos(0.5));
|
||||
} {60.0}
|
||||
do_execsql_test func7-pg-310 {
|
||||
SELECT round( asin(1), 7);
|
||||
} {1.5707963}
|
||||
do_execsql_test func7-pg-311 {
|
||||
SELECT degrees( asin(0.5) );
|
||||
} {30.0}
|
||||
do_execsql_test func7-pg-320 {
|
||||
SELECT round( atan(1), 7);
|
||||
} {0.7853982}
|
||||
do_execsql_test func7-pg-321 {
|
||||
SELECT degrees( atan(1) );
|
||||
} {45.0}
|
||||
do_execsql_test func7-pg-330 {
|
||||
SELECT round( atan2(1,0), 7);
|
||||
} {1.5707963}
|
||||
do_execsql_test func7-pg-331 {
|
||||
SELECT degrees( atan2(1,0) );
|
||||
} {90.0}
|
||||
do_execsql_test func7-pg-400 {
|
||||
SELECT cos(0);
|
||||
} {1.0}
|
||||
do_execsql_test func7-pg-401 {
|
||||
SELECT cos( radians(60.0) );
|
||||
} {0.5}
|
||||
do_execsql_test func7-pg-400 {
|
||||
SELECT cos(0);
|
||||
} {1.0}
|
||||
do_execsql_test func7-pg-410 {
|
||||
SELECT round( sin(1), 7);
|
||||
} {0.841471}
|
||||
do_execsql_test func7-pg-411 {
|
||||
SELECT sin( radians(30) );
|
||||
} {0.5}
|
||||
do_execsql_test func7-pg-420 {
|
||||
SELECT round( tan(1), 7);
|
||||
} {1.5574077}
|
||||
do_execsql_test func7-pg-421 {
|
||||
SELECT tan( radians(45) );
|
||||
} {1.0}
|
||||
do_execsql_test func7-pg-500 {
|
||||
SELECT round( sinh(1), 7);
|
||||
} {1.1752012}
|
||||
do_execsql_test func7-pg-510 {
|
||||
SELECT round( cosh(0), 7);
|
||||
} {1.0}
|
||||
do_execsql_test func7-pg-520 {
|
||||
SELECT round( tanh(1), 7);
|
||||
} {0.7615942}
|
||||
do_execsql_test func7-pg-530 {
|
||||
SELECT round( asinh(1), 7);
|
||||
} {0.8813736}
|
||||
do_execsql_test func7-pg-540 {
|
||||
SELECT round( acosh(1), 7);
|
||||
} {0.0}
|
||||
do_execsql_test func7-pg-550 {
|
||||
SELECT round( atanh(0.5), 7);
|
||||
} {0.5493061}
|
||||
|
||||
# Test cases derived from MySQL documentation
|
||||
#
|
||||
do_execsql_test func7-mysql-100 {
|
||||
SELECT acos(1);
|
||||
} {0.0}
|
||||
do_execsql_test func7-mysql-110 {
|
||||
SELECT acos(1.0001);
|
||||
} {{}}
|
||||
do_execsql_test func7-mysql-120 {
|
||||
SELECT round( acos(0.0), 7);
|
||||
} {1.5707963}
|
||||
do_execsql_test func7-mysql-130 {
|
||||
SELECT round( asin(0.2), 7);
|
||||
} {0.2013579}
|
||||
do_execsql_test func7-mysql-140 {
|
||||
SELECT asin('foo');
|
||||
} {{}} ;# Note: MySQL returns 0 here, not NULL.
|
||||
# SQLite deliberately returns NULL.
|
||||
# SQLServer and Oracle throw an error.
|
||||
do_execsql_test func7-mysql-150 {
|
||||
SELECT round( atan(2), 7), round( atan(-2), 7);
|
||||
} {1.1071487 -1.1071487}
|
||||
do_execsql_test func7-mysql-160 {
|
||||
SELECT round( atan2(-2,2), 7), round( atan2(pi(),0), 7);
|
||||
} {-0.7853982 1.5707963}
|
||||
do_execsql_test func7-mysql-170 {
|
||||
SELECT ceiling(1.23), ceiling(-1.23);
|
||||
} {2.0 -1.0}
|
||||
do_execsql_test func7-mysql-180 {
|
||||
SELECT cos(pi());
|
||||
} {-1.0}
|
||||
do_execsql_test func7-mysql-190 {
|
||||
SELECT degrees(pi()), degrees(pi()/2);
|
||||
} {180.0 90.0}
|
||||
do_execsql_test func7-mysql-190 {
|
||||
SELECT round( exp(2), 7), round( exp(-2), 7), exp(0);
|
||||
} {7.3890561 0.1353353 1.0}
|
||||
do_execsql_test func7-mysql-200 {
|
||||
SELECT floor(1.23), floor(-1.23);
|
||||
} {1.0 -2.0}
|
||||
do_execsql_test func7-mysql-210 {
|
||||
SELECT round(ln(2),7), quote(ln(-2));
|
||||
} {0.6931472 NULL}
|
||||
#do_execsql_test func7-mysql-220 {
|
||||
# SELECT round(log(2),7), log(-2);
|
||||
#} {0.6931472 NULL}
|
||||
# log() means natural logarithm in MySQL
|
||||
do_execsql_test func7-mysql-230 {
|
||||
SELECT log(2,65536), log(10,100), quote(log(1,100));
|
||||
} {16.0 2.0 Inf}
|
||||
do_execsql_test func7-mysql-240 {
|
||||
SELECT log2(65536), quote(log2(-100));
|
||||
} {16.0 NULL}
|
||||
do_execsql_test func7-mysql-250 {
|
||||
SELECT round(log10(2),7), log10(100), quote(log10(-100));
|
||||
} {0.30103 2.0 NULL}
|
||||
do_execsql_test func7-mysql-260 {
|
||||
SELECT mod(234,10), 253%7, mod(29,9), 29%9;
|
||||
} {4.0 1 2.0 2}
|
||||
do_execsql_test func7-mysql-270 {
|
||||
SELECT mod(34.5,3);
|
||||
} {1.5}
|
||||
do_execsql_test func7-mysql-280 {
|
||||
SELECT pow(2,2), pow(2,-2);
|
||||
} {4.0 0.25}
|
||||
do_execsql_test func7-mysql-281 {
|
||||
SELECT power(2,2), power(2,-2);
|
||||
} {4.0 0.25}
|
||||
do_execsql_test func7-mysql-290 {
|
||||
SELECT round(radians(90),7);
|
||||
} {1.5707963}
|
||||
do_execsql_test func7-mysql-300 {
|
||||
SELECT sign(-32), sign(0), sign(234);
|
||||
} {-1 0 1}
|
||||
do_execsql_test func7-mysql-310 {
|
||||
SELECT sin(pi()) BETWEEN -1.0e-15 AND 1.0e-15;
|
||||
} {1}
|
||||
do_execsql_test func7-mysql-320 {
|
||||
SELECT sqrt(4), round(sqrt(20),7), quote(sqrt(-16));
|
||||
} {2.0 4.472136 NULL}
|
||||
do_execsql_test func7-mysql-330 {
|
||||
SELECT tan(pi()) BETWEEN -1.0e-15 AND 1.0e-15;
|
||||
} {1}
|
||||
do_execsql_test func7-mysql-331 {
|
||||
SELECT round(tan(pi()+1),7);
|
||||
} {1.5574077}
|
||||
|
||||
|
||||
finish_test
|
||||
Binary file not shown.
@@ -251,4 +251,83 @@ do_test trace3-11.2 {
|
||||
set ::stmtlist(record)
|
||||
} {/^-?\d+$/}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_test 12.1.0 {
|
||||
set ::STMT [sqlite3_prepare_v2 $DB \
|
||||
"SELECT ?1 || ?1 || ?1 || ?2 || ?3 || ?4 || ? || ?1 || ?" -1 TAIL
|
||||
]
|
||||
sqlite3_bind_parameter_count $::STMT
|
||||
} {6}
|
||||
|
||||
do_test 12.1.1 {
|
||||
sqlite3_bind_text $STMT 1 "A" 1
|
||||
sqlite3_bind_text $STMT 2 "B" 1
|
||||
sqlite3_bind_text $STMT 3 "C" 1
|
||||
sqlite3_bind_text $STMT 4 "D" 1
|
||||
sqlite3_bind_text $STMT 5 "E" 1
|
||||
sqlite3_bind_text $STMT 6 "F" 1
|
||||
sqlite3_expanded_sql $STMT
|
||||
} {SELECT 'A' || 'A' || 'A' || 'B' || 'C' || 'D' || 'E' || 'A' || 'F'}
|
||||
|
||||
do_test 12.1.2 {
|
||||
sqlite3_step $STMT
|
||||
sqlite3_column_text $STMT 0
|
||||
} {AAABCDEAF}
|
||||
|
||||
do_test 12.1.3 {
|
||||
sqlite3_finalize $STMT
|
||||
} {SQLITE_OK}
|
||||
|
||||
do_test 12.2.0 {
|
||||
execsql {
|
||||
CREATE TABLE nameFtsFuzzySearchTable(
|
||||
word, distance, langid, score, top, scope
|
||||
);
|
||||
}
|
||||
set ::STMT [sqlite3_prepare_v2 $DB {
|
||||
SELECT
|
||||
substr(word,1,length(?1)-1) AS term,
|
||||
distance,
|
||||
langid,
|
||||
score
|
||||
FROM
|
||||
nameFtsFuzzySearchTable
|
||||
WHERE
|
||||
word MATCH (?1) AND abs(?1) = abs(term)
|
||||
AND top = ?2 AND distance > ?3 AND scope = ?4 AND langid = ?
|
||||
GROUP BY term, langid
|
||||
HAVING (1.0 - ((distance / 100.0) / CAST( length(?1) - 1 AS REAL ))) >= ?
|
||||
} -1 TAIL]
|
||||
sqlite3_bind_parameter_count $::STMT
|
||||
} {6}
|
||||
|
||||
do_test 12.1.1 {
|
||||
sqlite3_bind_text $STMT 1 "A" 1
|
||||
sqlite3_bind_text $STMT 2 "B" 1
|
||||
sqlite3_bind_text $STMT 3 "C" 1
|
||||
sqlite3_bind_text $STMT 4 "D" 1
|
||||
sqlite3_bind_text $STMT 5 "E" 1
|
||||
sqlite3_bind_text $STMT 6 "F" 1
|
||||
sqlite3_expanded_sql $STMT
|
||||
} {
|
||||
SELECT
|
||||
substr(word,1,length('A')-1) AS term,
|
||||
distance,
|
||||
langid,
|
||||
score
|
||||
FROM
|
||||
nameFtsFuzzySearchTable
|
||||
WHERE
|
||||
word MATCH ('A') AND abs('A') = abs(term)
|
||||
AND top = 'B' AND distance > 'C' AND scope = 'D' AND langid = 'E'
|
||||
GROUP BY term, langid
|
||||
HAVING (1.0 - ((distance / 100.0) / CAST( length('A') - 1 AS REAL ))) >= 'F'
|
||||
}
|
||||
|
||||
do_test 12.1.2 {
|
||||
sqlite3_finalize $STMT
|
||||
} {SQLITE_OK}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
397
test/upsert5.test
Normal file
397
test/upsert5.test
Normal file
@@ -0,0 +1,397 @@
|
||||
# 2020-12-11
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Test cases for generalized UPSERT
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix upsert5
|
||||
|
||||
foreach {tn sql} {
|
||||
1 { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c UNIQUE, d UNIQUE, e UNIQUE) }
|
||||
2 { CREATE TABLE t1(a INT PRIMARY KEY, b, c UNIQUE, d UNIQUE, e UNIQUE) }
|
||||
3 { CREATE TABLE t1(a INT PRIMARY KEY, b, c UNIQUE, d UNIQUE, e UNIQUE) WITHOUT ROWID}
|
||||
4 { CREATE TABLE t1(e UNIQUE, d UNIQUE, c UNIQUE, a INTEGER PRIMARY KEY, b) }
|
||||
5 { CREATE TABLE t1(e UNIQUE, d UNIQUE, c UNIQUE, a INT PRIMARY KEY, b) }
|
||||
6 { CREATE TABLE t1(e UNIQUE, d UNIQUE, c UNIQUE, a INT PRIMARY KEY, b) WITHOUT ROWID}
|
||||
} {
|
||||
reset_db
|
||||
execsql $sql
|
||||
|
||||
do_execsql_test 1.$tn.100 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,3,4,5)
|
||||
ON CONFLICT(a) DO UPDATE SET b='a'
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 a 3 4 5}
|
||||
do_execsql_test 1.$tn.101 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,3,4,5)
|
||||
ON CONFLICT(a) DO UPDATE SET b='a'
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 c 3 4 5}
|
||||
do_execsql_test 1.$tn.102 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,4,5)
|
||||
ON CONFLICT(a) DO UPDATE SET b='a'
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 d 3 4 5}
|
||||
do_execsql_test 1.$tn.103 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,94,5)
|
||||
ON CONFLICT(a) DO UPDATE SET b='a'
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 e 3 4 5}
|
||||
do_execsql_test 1.$tn.200 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 a 3 4 5}
|
||||
do_execsql_test 1.$tn.201 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,3,94,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 c 3 4 5}
|
||||
do_execsql_test 1.$tn.202 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,3,4,5)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 c 3 4 5}
|
||||
do_execsql_test 1.$tn.203 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,5)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 a 3 4 5}
|
||||
do_execsql_test 1.$tn.204 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,4,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 a 3 4 5}
|
||||
do_execsql_test 1.$tn.210 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 a 3 4 5}
|
||||
do_execsql_test 1.$tn.211 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,4,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 d 3 4 5}
|
||||
do_execsql_test 1.$tn.212 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,5)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 a 3 4 5}
|
||||
do_execsql_test 1.$tn.213 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,94,5)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 e 3 4 5}
|
||||
do_execsql_test 1.$tn.214 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,94,5)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 e 3 4 5}
|
||||
do_execsql_test 1.$tn.215 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,5)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 e 3 4 5}
|
||||
do_execsql_test 1.$tn.216 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 a 3 4 5}
|
||||
|
||||
do_execsql_test 1.$tn.300 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a1'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a2'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a3'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a4'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a5'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 a1 3 4 5}
|
||||
do_execsql_test 1.$tn.301 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,94,5)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a1'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a2'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a3'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a4'
|
||||
ON CONFLICT(a) DO UPDATE SET b='a5'
|
||||
ON CONFLICT(e) DO UPDATE SET b='e';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 e 3 4 5}
|
||||
|
||||
do_execsql_test 1.$tn.400 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 x 3 4 5}
|
||||
do_execsql_test 1.$tn.401 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,94,5)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 x 3 4 5}
|
||||
do_execsql_test 1.$tn.402 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 x 3 4 5}
|
||||
do_execsql_test 1.$tn.403 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,3,94,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 c 3 4 5}
|
||||
do_execsql_test 1.$tn.404 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,3,4,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 c 3 4 5}
|
||||
do_execsql_test 1.$tn.405 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,4,5)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 d 3 4 5}
|
||||
|
||||
do_execsql_test 1.$tn.410 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95)
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 x 3 4 5}
|
||||
do_execsql_test 1.$tn.411 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,94,5)
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 x 3 4 5}
|
||||
do_execsql_test 1.$tn.412 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,4,95)
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 x 3 4 5}
|
||||
do_execsql_test 1.$tn.413 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,3,94,95)
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 x 3 4 5}
|
||||
|
||||
do_execsql_test 1.$tn.420 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95)
|
||||
ON CONFLICT(c) DO NOTHING
|
||||
ON CONFLICT(d) DO NOTHING
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 x 3 4 5}
|
||||
do_execsql_test 1.$tn.421 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,94,5)
|
||||
ON CONFLICT(c) DO NOTHING
|
||||
ON CONFLICT(d) DO NOTHING
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 x 3 4 5}
|
||||
do_execsql_test 1.$tn.422 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,4,95)
|
||||
ON CONFLICT(c) DO NOTHING
|
||||
ON CONFLICT(d) DO NOTHING
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 2 3 4 5}
|
||||
do_execsql_test 1.$tn.423 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,3,94,95)
|
||||
ON CONFLICT(c) DO NOTHING
|
||||
ON CONFLICT(d) DO NOTHING
|
||||
ON CONFLICT DO UPDATE set b='x';
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 2 3 4 5}
|
||||
|
||||
do_execsql_test 1.$tn.500 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT DO NOTHING;
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 2 3 4 5}
|
||||
do_execsql_test 1.$tn.501 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,93,94,5)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT DO NOTHING;
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 2 3 4 5}
|
||||
do_execsql_test 1.$tn.502 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,94,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT DO NOTHING;
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 2 3 4 5}
|
||||
do_execsql_test 1.$tn.503 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,3,94,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT DO NOTHING;
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 c 3 4 5}
|
||||
do_execsql_test 1.$tn.504 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(91,NULL,3,4,95)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT DO NOTHING;
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 c 3 4 5}
|
||||
do_execsql_test 1.$tn.505 {
|
||||
DELETE FROM t1;
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5);
|
||||
INSERT INTO t1(a,b,c,d,e) VALUES(1,NULL,93,4,5)
|
||||
ON CONFLICT(c) DO UPDATE SET b='c'
|
||||
ON CONFLICT(d) DO UPDATE SET b='d'
|
||||
ON CONFLICT DO NOTHING;
|
||||
SELECT a,b,c,d,e FROM t1;
|
||||
} {1 d 3 4 5}
|
||||
|
||||
}
|
||||
|
||||
finish_test
|
||||
@@ -56,7 +56,7 @@ do_test vacuum2-2.1 {
|
||||
}
|
||||
hexio_get_int [hexio_read test.db 24 4]
|
||||
} [expr {[hexio_get_int [hexio_read test.db 24 4]]+3}]
|
||||
do_test vacuum2-2.1 {
|
||||
do_test vacuum2-2.2 {
|
||||
execsql {
|
||||
VACUUM
|
||||
}
|
||||
|
||||
112
test/vacuum6.test
Normal file
112
test/vacuum6.test
Normal file
@@ -0,0 +1,112 @@
|
||||
# 2016-08-19
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# This file implements a test for VACUUM on attached databases.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix vacuum6
|
||||
|
||||
# If the VACUUM statement is disabled in the current build, skip all
|
||||
# the tests in this file.
|
||||
#
|
||||
ifcapable !vacuum {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(x INTEGER PRIMARY KEY, y);
|
||||
INSERT INTO t1 VALUES(1, 1);
|
||||
} {}
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
VACUUM
|
||||
}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 1.2 {
|
||||
CREATE TABLE t1(x,b);
|
||||
CREATE INDEX x1 ON t1(x);
|
||||
CREATE INDEX x2 ON t1(x);
|
||||
CREATE INDEX x3 ON t1(x);
|
||||
INSERT INTO t1 SELECT 2,'';
|
||||
VACUUM;
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
foreach {tn sz} {1 400 2 4000 3 9999} {
|
||||
reset_db
|
||||
do_execsql_test 2.$tn.1 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100
|
||||
)
|
||||
INSERT INTO t1 SELECT i, randomblob($sz) FROM s;
|
||||
}
|
||||
|
||||
do_execsql_test 2.$tn.2 {
|
||||
vacuum;
|
||||
}
|
||||
|
||||
do_execsql_test 2.$tn.3 {
|
||||
PRAGMA integrity_check;
|
||||
} {ok}
|
||||
}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 3.0 {
|
||||
PRAGMA page_size = 1024;
|
||||
CREATE TABLE t1(x INTEGER PRIMARY KEY, y);
|
||||
INSERT INTO t1 VALUES(2, randomblob(1200));
|
||||
} {}
|
||||
do_execsql_test 3.1 {
|
||||
PRAGMA page_size = 512;
|
||||
VACUUM;
|
||||
}
|
||||
do_execsql_test 3.2 {
|
||||
PRAGMA integrity_check
|
||||
} {ok}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 4.0 {
|
||||
CREATE TABLE tx(a, b);
|
||||
CREATE INDEX i1 ON tx(b);
|
||||
WITH s(i) AS (
|
||||
SELECT 8000 UNION ALL SELECT i+1 FROM s WHERE i<10000
|
||||
)
|
||||
INSERT INTO tx SELECT i, randomblob(i) FROM s;
|
||||
|
||||
SELECT sum(length(b)) FROM tx;
|
||||
} {18009000}
|
||||
foreach {tn pgsz av} {
|
||||
1 2048 0
|
||||
2 1024 1
|
||||
3 65536 0
|
||||
4 8192 1
|
||||
5 512 0
|
||||
6 4096 1
|
||||
} {
|
||||
do_execsql_test 4.1.$tn.1 "
|
||||
PRAGMA page_size = $pgsz;
|
||||
PRAGMA auto_vacuum = $av;
|
||||
"
|
||||
do_execsql_test 4.1.$tn.2 VACUUM
|
||||
integrity_check 4.1.$tn.3
|
||||
}
|
||||
|
||||
finish_test
|
||||
Reference in New Issue
Block a user