From f6e904bd9243498889ae3e628aeef9f697c728c9 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 7 Dec 2020 17:15:32 +0000 Subject: [PATCH 01/38] Begin adding new SQL functions that depend on -lm: ceil(), ceiling(), floor(), ln(), log(), and log10() so far. More to follow. FossilOrigin-Name: 4db5f2f7875f6df78630a7816fc018141a6eee2e295b44fc7627eb66d07881ea --- Makefile.msc | 3 ++ configure | 104 +++++++++++++++++++++++++++++++++++++++------- configure.ac | 14 +++++++ manifest | 25 +++++------ manifest.uuid | 2 +- src/ctime.c | 3 ++ src/func.c | 78 ++++++++++++++++++++++++++++++++++ src/sqliteInt.h | 6 +++ src/test_config.c | 6 +++ test/func7.test | 35 ++++++++++++++++ 10 files changed, 249 insertions(+), 27 deletions(-) create mode 100644 test/func7.test diff --git a/Makefile.msc b/Makefile.msc index 404e3b2360..af39679a8f 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -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. # diff --git a/configure b/configure index 90cb4d25e8..5a313189b1 100755 --- a/configure +++ b/configure @@ -1557,6 +1557,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 +3936,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:3939: $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:3942: $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:3945: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" @@ -5147,7 +5148,7 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 5150 "configure"' > conftest.$ac_ext + echo '#line 5151 "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -6672,11 +6673,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:6676: $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:6680: \$? = $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 +7012,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:7015: $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:7019: \$? = $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 +7117,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:7120: $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:7124: \$? = $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 +7172,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:7175: $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:7179: \$? = $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 +9552,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 9555 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -9647,7 +9648,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 9651 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11411,6 +11412,81 @@ else OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1" fi +########## +# Do we want to support math functions +# +# Check whether --enable-threadsafe was given. +if test "${enable_threadsafe+set}" = set; then : + enableval=$enable_threadsafe; +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 # diff --git a/configure.ac b/configure.ac index bb8f4bd563..5285581eec 100644 --- a/configure.ac +++ b/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(threadsafe, +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 # diff --git a/manifest b/manifest index 5e328f066a..9347e389ec 100644 --- a/manifest +++ b/manifest @@ -1,11 +1,11 @@ -C Fix\sharmless\scompiler\swarnings\sassociated\swith\sthe\srecent\sFTS5\senhancements. -D 2020-12-04T17:05:16.189 +C Begin\sadding\snew\sSQL\sfunctions\sthat\sdepend\son\s-lm:\s\sceil(),\sceiling(),\nfloor(),\sln(),\slog(),\sand\slog10()\sso\sfar.\s\sMore\sto\sfollow. +D 2020-12-07T17:15:32.150 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 F Makefile.in 0e88f5d095213a9ccd45c5bbd871c8ead498f886dff4493471fbf48b1f867f9d F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241 -F Makefile.msc dd10dbf63b2f8ac3e2f0542963a21bc69058976ac4355165f212a31c83d17f44 +F Makefile.msc ad07bbd645132533e1fd7164a03acfa9afecda378b3787c10f62ab4c7c45e6ea F README.md 1514a365ffca3c138e00c5cc839906108a01011a6b082bad19b09781e3aa498a F VERSION 92f3e4c5cdee6f0779aef1eae857dfc21d0eabb1f2af169dc90e63cd76b15bb2 F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50 @@ -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 79bcd87c8c18e4e60a9b0282c259b9db912e68c086cb65634628763b3c6b6321 x +F configure.ac b865a0e9724d09b5e510d07340901ecfceab706c8d21f26d55914f2d1be7dc7e F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd F doc/lemon.html c5d8ba85ac1daef7be8c2d389899480eb62451ff5c09b0c28ff8157bb8770746 @@ -487,7 +487,7 @@ F src/btreeInt.h ffd66480520d9d70222171b3a026d78b80833b5cea49c89867949f3e023d5f4 F src/build.c f6449d4e85e998e14d3f537e8ea898dca2fcb83c277db3e60945af9b9177db81 F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e -F src/ctime.c e98518d2d3d4029a13c805e07313fb60c877be56db76e90dd5f3af73085d0ce6 +F src/ctime.c 0bcc6a908779a520be534fd985b2185dfd457588b6798d0bcbf37755a044b7c3 F src/date.c dace306a10d9b02ee553d454c8e1cf8d3c9b932e137738a6b15b90253a9bfc10 F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a F src/dbstat.c 3aa79fc3aed7ce906e4ea6c10e85d657299e304f6049861fe300053ac57de36c @@ -495,7 +495,7 @@ F src/delete.c 927cf8f900583e79aca8f1a321979e0a8f053babd9a690b44b38f79de2cc09fe F src/expr.c 0d196ed5a2ebf96be7e8df88add4fabfad0dce16c0fed81a4b8f6a26e259797f F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 83372403298e6a7dd989a47aaacdbaa5b4307b5199dbd56e07d4896066b3de72 -F src/func.c 574f7e5a67e4b7a7855cf3478037717c8f44686c0cd727e1d7f7773414165c03 +F src/func.c d3113a23625daeb54331752421442af772abd851123550459dec96fedbe068e7 F src/global.c ed55af196a9b66e198aaeda3f5454c3aa7d7d050c6c938181fd044b70d180a81 F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 @@ -545,7 +545,7 @@ F src/shell.c.in e9f674ee4ec6c345679e8a5b16c869c6c59eb1540dd98ac69e4736ecddce009 F src/sqlite.h.in 0e2b4259e49a0eda54d9118eb18a04fcd60e0727a2fd2c81aade0bf57520e706 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e -F src/sqliteInt.h c897ea47eb7dfc1b337e2c5681dbf00eb43c2a1af2f0045a19adc1052aadc03d +F src/sqliteInt.h 6ab40b33a1f5edbb7d71c78e82e0f9c5291dcff4704df8e4f0ab0d9c1a0c06af F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -565,7 +565,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 5ea19bf0972a9d91728518b4d30e91477acce80496003ecbef3a7fb18d0bd081 +F src/test_config.c 98698f5242be88af75eaac54adde573471d5ed2f6484e0dac034cb1e763a551a F src/test_delete.c e2fe07646dff6300b48d49b2fee2fe192ed389e834dd635e3b3bac0ce0bf9f8f F src/test_demovfs.c 86142ba864d4297d54c5b2e972e74f3141ae4b30f05b3a95824184ed2d3d7f91 F src/test_devsym.c aff2255ea290d7718da08af30cdf18e470ff7325a5eff63e0057b1496ed66593 @@ -1026,6 +1026,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 7414f1ffb7aba86b6bcfdf0c3739a4e4717026ff583acd8b43ab21189300bcdc F test/fuzz-oss1.test e58330d01cbbd8215ee636b17a03fe220b37dbfa F test/fuzz.test 96083052bf5765e4518c1ba686ce2bab785670d1 F test/fuzz2.test 76dc35b32b6d6f965259508508abce75a6c4d7e1 @@ -1887,7 +1888,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 fd02dffceb0e21cd85c99d5481ab8567110d01c30ea701178547f32299944302 -R d3c2d5d830919ec315662cc1d113703f +P 1db7c751912beb57a697ac8e85b9c29e30da7b6c89207e9828bf08e56c58242f +R 6662031cc76e6cb57f52d5a4ee0696ea U drh -Z d16f9ab88139a6919756f891af8788a5 +Z 99632da1aa8e30b2d9d751e33b863567 diff --git a/manifest.uuid b/manifest.uuid index 9b7ad54cc9..7ffa11f57e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1db7c751912beb57a697ac8e85b9c29e30da7b6c89207e9828bf08e56c58242f \ No newline at end of file +4db5f2f7875f6df78630a7816fc018141a6eee2e295b44fc7627eb66d07881ea \ No newline at end of file diff --git a/src/ctime.c b/src/ctime.c index e3e1e79a95..f0fdccbdc1 100644 --- a/src/ctime.c +++ b/src/ctime.c @@ -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 diff --git a/src/func.c b/src/func.c index 5d00c94a92..09e44345dc 100644 --- a/src/func.c +++ b/src/func.c @@ -1904,6 +1904,75 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){ return 1; } +/* 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_type(argv[0]) ){ + case SQLITE_INTEGER: + sqlite3_result_int64(context, sqlite3_value_int64(argv[0])); + break; + case SQLITE_NULL: + break; + default: { + double (*x)(double) = (double(*)(double))sqlite3_user_data(context); + sqlite3_result_double(context, x(sqlite3_value_double(argv[0]))); + break; + } + } +} + +/* +** Implementation of SQL functions: +** +** ln(X) - natural logarithm +** log(X) - log base 10 +** log10(X) - log base 10 +** log(X,Y) - log base Y +*/ +static void logFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + double x, y, ans; + assert( argc==1 || argc==2 ); + if( sqlite3_value_type(argv[0])==SQLITE_NULL + || (x = sqlite3_value_double(argv[0]))<0.0 + ){ + return; /* Return NULL for a domain error */ + } + ans = log(x); + if( argc==2 ){ + if( sqlite3_value_type(argv[1])==SQLITE_NULL + || (y = sqlite3_value_double(argv[1]))<0.0 + ){ + return; /* Return NULL for a domain error */ + } + ans /= log(y); + }else if( sqlite3_user_data(context)!=0 ){ + /* Convert from natural logarithm to log base 10 */ + ans *= 0.43429448190325178672; + } + sqlite3_result_double(context, ans); +} +#endif /* SQLITE_ENABLE_MATH_FUNCTIONS */ + /* ** All of the FuncDef structures in the aBuiltinFunc[] array above ** to the global function hash table. This occurs at start-time (as @@ -2024,6 +2093,15 @@ void sqlite3RegisterBuiltinFunctions(void){ FUNCTION(coalesce, 0, 0, 0, 0 ), INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, 0 ), INLINE_FUNC(iif, 3, INLINEFUNC_iif, 0 ), +#ifdef SQLITE_ENABLE_MATH_FUNCTIONS + MFUNCTION(ceil, 1, ceil, ceilingFunc ), + MFUNCTION(ceiling, 1, ceil, ceilingFunc ), + MFUNCTION(floor, 1, floor, ceilingFunc ), + FUNCTION(ln, 1, 0, 0, logFunc ), + FUNCTION(log, 1, 1, 0, logFunc ), + FUNCTION(log10, 1, 1, 0, logFunc ), + FUNCTION(log, 2, 0, 0, logFunc ), +#endif /* SQLITE_ENABLE_MATH_FUNCTIONS */ }; #ifndef SQLITE_OMIT_ALTERTABLE sqlite3AlterFunctions(); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 1efa621427..438f79c092 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1864,6 +1864,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 @@ -1899,6 +1902,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} } diff --git a/src/test_config.c b/src/test_config.c index 362e92aa9a..8c4fba71db 100644 --- a/src/test_config.c +++ b/src/test_config.c @@ -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 diff --git a/test/func7.test b/test/func7.test new file mode 100644 index 0000000000..c7fce79dd6 --- /dev/null +++ b/test/func7.test @@ -0,0 +1,35 @@ +# 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('256',2); +} {1.61 2.0 2.0 8.0} +do_execsql_test func7-210 { + SELECT ln(-5), log(100.0,-5); +} {{} {}} + + +finish_test From 63f8f98a63ef23803f663e6b128d9b3fe8ef53b6 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 7 Dec 2020 21:13:06 +0000 Subject: [PATCH 02/38] Many more math functions. Semantics follows PG wherever possible. FossilOrigin-Name: 6b93627b5d9819abf179a3e4a82e7afe17cbcafdabbd5f058de9ed114c9d477f --- manifest | 14 ++-- manifest.uuid | 2 +- src/func.c | 190 ++++++++++++++++++++++++++++++++++++------ test/func7.test | 214 +++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 386 insertions(+), 34 deletions(-) diff --git a/manifest b/manifest index 9347e389ec..dccb95c603 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Begin\sadding\snew\sSQL\sfunctions\sthat\sdepend\son\s-lm:\s\sceil(),\sceiling(),\nfloor(),\sln(),\slog(),\sand\slog10()\sso\sfar.\s\sMore\sto\sfollow. -D 2020-12-07T17:15:32.150 +C Many\smore\smath\sfunctions.\s\sSemantics\sfollows\sPG\swherever\spossible. +D 2020-12-07T21:13:06.475 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -495,7 +495,7 @@ F src/delete.c 927cf8f900583e79aca8f1a321979e0a8f053babd9a690b44b38f79de2cc09fe F src/expr.c 0d196ed5a2ebf96be7e8df88add4fabfad0dce16c0fed81a4b8f6a26e259797f F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 83372403298e6a7dd989a47aaacdbaa5b4307b5199dbd56e07d4896066b3de72 -F src/func.c d3113a23625daeb54331752421442af772abd851123550459dec96fedbe068e7 +F src/func.c 7c3a41213179cce249d46283fc2237bc3424a041343866dbdb31914fed0edddc F src/global.c ed55af196a9b66e198aaeda3f5454c3aa7d7d050c6c938181fd044b70d180a81 F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 @@ -1026,7 +1026,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 7414f1ffb7aba86b6bcfdf0c3739a4e4717026ff583acd8b43ab21189300bcdc +F test/func7.test bb05a77daedf0e3f8764f323a49bc3b8d98f280a0bc6a370387117f4596bde05 F test/fuzz-oss1.test e58330d01cbbd8215ee636b17a03fe220b37dbfa F test/fuzz.test 96083052bf5765e4518c1ba686ce2bab785670d1 F test/fuzz2.test 76dc35b32b6d6f965259508508abce75a6c4d7e1 @@ -1888,7 +1888,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 1db7c751912beb57a697ac8e85b9c29e30da7b6c89207e9828bf08e56c58242f -R 6662031cc76e6cb57f52d5a4ee0696ea +P 4db5f2f7875f6df78630a7816fc018141a6eee2e295b44fc7627eb66d07881ea +R 5f3694d6742f321a9a8686c5ca8182de U drh -Z 99632da1aa8e30b2d9d751e33b863567 +Z 1fdfc343d2601875f5f91cade0f6a5bf diff --git a/manifest.uuid b/manifest.uuid index 7ffa11f57e..acf82a7c34 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4db5f2f7875f6df78630a7816fc018141a6eee2e295b44fc7627eb66d07881ea \ No newline at end of file +6b93627b5d9819abf179a3e4a82e7afe17cbcafdabbd5f058de9ed114c9d477f \ No newline at end of file diff --git a/src/func.c b/src/func.c index 09e44345dc..7bfd5bd6a7 100644 --- a/src/func.c +++ b/src/func.c @@ -1904,6 +1904,18 @@ 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 @@ -1923,17 +1935,19 @@ static void ceilingFunc( sqlite3_value **argv ){ assert( argc==1 ); - switch( sqlite3_value_type(argv[0]) ){ - case SQLITE_INTEGER: + switch( sqlite3_value_numeric_type(argv[0]) ){ + case SQLITE_INTEGER: { sqlite3_result_int64(context, sqlite3_value_int64(argv[0])); break; - case SQLITE_NULL: - break; - default: { + } + 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; + } } } @@ -1941,38 +1955,142 @@ static void ceilingFunc( ** Implementation of SQL functions: ** ** ln(X) - natural logarithm -** log(X) - log base 10 -** log10(X) - log base 10 -** log(X,Y) - log base Y +** 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, y, ans; + double x, b, ans; assert( argc==1 || argc==2 ); - if( sqlite3_value_type(argv[0])==SQLITE_NULL - || (x = sqlite3_value_double(argv[0]))<0.0 - ){ - return; /* Return NULL for a domain error */ + 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; } - ans = log(x); if( argc==2 ){ - if( sqlite3_value_type(argv[1])==SQLITE_NULL - || (y = sqlite3_value_double(argv[1]))<0.0 - ){ - return; /* Return NULL for a domain error */ + 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; } - ans /= log(y); - }else if( sqlite3_user_data(context)!=0 ){ - /* Convert from natural logarithm to log base 10 */ - ans *= 0.43429448190325178672; } 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 +){ + assert( argc==2 ); + int type0; + double v0, ans; + double (*x)(double); + 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 +){ + assert( argc==2 ); + int type0, type1; + double v0, v1, ans; + double (*x)(double,double); + 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 +){ + assert( argc==1 ); + int type0; + double x; + 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 @@ -2091,17 +2209,41 @@ void sqlite3RegisterBuiltinFunctions(void){ #endif FUNCTION(coalesce, 1, 0, 0, 0 ), FUNCTION(coalesce, 0, 0, 0, 0 ), - INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, 0 ), - INLINE_FUNC(iif, 3, INLINEFUNC_iif, 0 ), #ifdef SQLITE_ENABLE_MATH_FUNCTIONS MFUNCTION(ceil, 1, ceil, ceilingFunc ), MFUNCTION(ceiling, 1, ceil, ceilingFunc ), MFUNCTION(floor, 1, floor, ceilingFunc ), + MFUNCTION(trunc, 1, trunc, ceilingFunc ), 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 ), + MFUNCTION(acosh, 1, acosh, math1Func ), + MFUNCTION(asinh, 1, asinh, math1Func ), + MFUNCTION(atanh, 1, atanh, math1Func ), + 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 ), }; #ifndef SQLITE_OMIT_ALTERTABLE sqlite3AlterFunctions(); diff --git a/test/func7.test b/test/func7.test index c7fce79dd6..536f7eb414 100644 --- a/test/func7.test +++ b/test/func7.test @@ -25,11 +25,221 @@ 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('256',2); + 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(100.0,-5); + 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 From e2ce8c446fd3f2ce188af9b5b75584fb52f7839e Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 7 Dec 2020 21:19:17 +0000 Subject: [PATCH 03/38] Fix to the --disable-math option to ./configure. FossilOrigin-Name: 99ff6418492adcbaf2be728737735afa1c2997de5868395e69c53d08fc14491f --- configure | 35 ++++++++++++++++++----------------- configure.ac | 2 +- manifest | 14 +++++++------- manifest.uuid | 2 +- 4 files changed, 27 insertions(+), 26 deletions(-) diff --git a/configure b/configure index 5a313189b1..b094ef71ad 100755 --- a/configure +++ b/configure @@ -903,6 +903,7 @@ with_readline_inc enable_debug enable_amalgamation enable_load_extension +enable_math enable_memsys5 enable_memsys3 enable_all @@ -3936,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:3939: $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:3942: $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:3945: 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" @@ -5148,7 +5149,7 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 5151 "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=$? @@ -6673,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:6676: $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:6680: \$? = $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. @@ -7012,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:7015: $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:7019: \$? = $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. @@ -7117,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:7120: $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:7124: \$? = $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 @@ -7172,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:7175: $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:7179: \$? = $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 @@ -9552,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 9555 "configure" +#line 9556 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -9648,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 9651 "configure" +#line 9652 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11415,9 +11416,9 @@ fi ########## # Do we want to support math functions # -# Check whether --enable-threadsafe was given. -if test "${enable_threadsafe+set}" = set; then : - enableval=$enable_threadsafe; +# 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 diff --git a/configure.ac b/configure.ac index 5285581eec..ae73a5350e 100644 --- a/configure.ac +++ b/configure.ac @@ -589,7 +589,7 @@ fi ########## # Do we want to support math functions # -AC_ARG_ENABLE(threadsafe, +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 diff --git a/manifest b/manifest index dccb95c603..9811874330 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Many\smore\smath\sfunctions.\s\sSemantics\sfollows\sPG\swherever\spossible. -D 2020-12-07T21:13:06.475 +C Fix\sto\sthe\s--disable-math\soption\sto\s./configure. +D 2020-12-07T21:19:17.901 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -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 79bcd87c8c18e4e60a9b0282c259b9db912e68c086cb65634628763b3c6b6321 x -F configure.ac b865a0e9724d09b5e510d07340901ecfceab706c8d21f26d55914f2d1be7dc7e +F configure 7736c168f4fd717c8052e58428a89e645d15cf0e5a3d051e248aad859a3cb140 x +F configure.ac efdb70036084ea637226e378a14f932e70c0df9f1bc846a24a909c0e1613524a F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd F doc/lemon.html c5d8ba85ac1daef7be8c2d389899480eb62451ff5c09b0c28ff8157bb8770746 @@ -1888,7 +1888,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 4db5f2f7875f6df78630a7816fc018141a6eee2e295b44fc7627eb66d07881ea -R 5f3694d6742f321a9a8686c5ca8182de +P 6b93627b5d9819abf179a3e4a82e7afe17cbcafdabbd5f058de9ed114c9d477f +R 344d0bcab916063736a47d8c55992722 U drh -Z 1fdfc343d2601875f5f91cade0f6a5bf +Z c106f4c2e997d379fe9c71e8d1365827 diff --git a/manifest.uuid b/manifest.uuid index acf82a7c34..3b76d9f0d7 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6b93627b5d9819abf179a3e4a82e7afe17cbcafdabbd5f058de9ed114c9d477f \ No newline at end of file +99ff6418492adcbaf2be728737735afa1c2997de5868395e69c53d08fc14491f \ No newline at end of file From 0dffe465f76869016bc8b849f160c3d1a40505e8 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 7 Dec 2020 23:14:25 +0000 Subject: [PATCH 04/38] Fix a bad assert() in math1Func(). FossilOrigin-Name: 4b286129138d44e6f8e9b3450289941e01d20fdfb9d0b5d846031425e8ca6b49 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/func.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 9811874330..18c17599b4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sto\sthe\s--disable-math\soption\sto\s./configure. -D 2020-12-07T21:19:17.901 +C Fix\sa\sbad\sassert()\sin\smath1Func(). +D 2020-12-07T23:14:25.210 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -495,7 +495,7 @@ F src/delete.c 927cf8f900583e79aca8f1a321979e0a8f053babd9a690b44b38f79de2cc09fe F src/expr.c 0d196ed5a2ebf96be7e8df88add4fabfad0dce16c0fed81a4b8f6a26e259797f F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 83372403298e6a7dd989a47aaacdbaa5b4307b5199dbd56e07d4896066b3de72 -F src/func.c 7c3a41213179cce249d46283fc2237bc3424a041343866dbdb31914fed0edddc +F src/func.c c65447d69bbf743328e7e4e836475ac5fb4ab80213fe5b189b8b0109e942e7c1 F src/global.c ed55af196a9b66e198aaeda3f5454c3aa7d7d050c6c938181fd044b70d180a81 F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 @@ -1888,7 +1888,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 6b93627b5d9819abf179a3e4a82e7afe17cbcafdabbd5f058de9ed114c9d477f -R 344d0bcab916063736a47d8c55992722 +P 99ff6418492adcbaf2be728737735afa1c2997de5868395e69c53d08fc14491f +R 747ed0f69719082482a4ff82786fa288 U drh -Z c106f4c2e997d379fe9c71e8d1365827 +Z ac855459dfaf775bb9ffc51142afdf45 diff --git a/manifest.uuid b/manifest.uuid index 3b76d9f0d7..7e5c04ae26 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -99ff6418492adcbaf2be728737735afa1c2997de5868395e69c53d08fc14491f \ No newline at end of file +4b286129138d44e6f8e9b3450289941e01d20fdfb9d0b5d846031425e8ca6b49 \ No newline at end of file diff --git a/src/func.c b/src/func.c index 7bfd5bd6a7..169f231430 100644 --- a/src/func.c +++ b/src/func.c @@ -2021,7 +2021,7 @@ static void math1Func( int argc, sqlite3_value **argv ){ - assert( argc==2 ); + assert( argc==1 ); int type0; double v0, ans; double (*x)(double); From 2549e4cc2fef9fc969a9efdc723c2bcf1ac69f1f Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 8 Dec 2020 14:29:03 +0000 Subject: [PATCH 05/38] Enhance UPSERT parsing to allow multiple ON CONFLICT clauses. Only the very last clause may omit the conflict target, but the conflict target may now be omitted for the DO UPDATE resolution. FossilOrigin-Name: 2ca62f4c71df6544cb8039bdc80e3701d09697c38800534371f6d44532fcffae --- manifest | 19 +++-- manifest.uuid | 2 +- src/parse.y | 19 ++--- src/sqliteInt.h | 7 +- src/upsert.c | 189 +++++++++++++++++++++++++++--------------------- 5 files changed, 130 insertions(+), 106 deletions(-) diff --git a/manifest b/manifest index 18c17599b4..9471059ac9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sbad\sassert()\sin\smath1Func(). -D 2020-12-07T23:14:25.210 +C Enhance\sUPSERT\sparsing\sto\sallow\smultiple\sON\sCONFLICT\sclauses.\s\sOnly\sthe\nvery\slast\sclause\smay\somit\sthe\sconflict\starget,\sbut\sthe\sconflict\starget\smay\nnow\sbe\somitted\sfor\sthe\sDO\sUPDATE\sresolution. +D 2020-12-08T14:29:03.533 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -529,7 +529,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 72b884c73f2b446e7dc4c7169ec7fbb82e0e292eec733fcf554f0fde46f269f6 F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177 F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 F src/pcache1.c 6596e10baf3d8f84cc1585d226cf1ab26564a5f5caf85a15757a281ff977d51a @@ -545,7 +545,7 @@ F src/shell.c.in e9f674ee4ec6c345679e8a5b16c869c6c59eb1540dd98ac69e4736ecddce009 F src/sqlite.h.in 0e2b4259e49a0eda54d9118eb18a04fcd60e0727a2fd2c81aade0bf57520e706 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e -F src/sqliteInt.h 6ab40b33a1f5edbb7d71c78e82e0f9c5291dcff4704df8e4f0ab0d9c1a0c06af +F src/sqliteInt.h 351d29fad669d5c98066a89ab48259d451379edac3c24773c3c8ac5df66fd8ff F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -608,7 +608,7 @@ F src/tokenize.c 01dba3023659dc6f6b1e054c14b35a0074bd35de10466b99454d33278191d97 F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda F src/trigger.c 515e79206d40d1d4149129318582e79a6e9db590a7b74e226fdb5b2a6c7e1b10 F src/update.c 9f126204a6acb96bbe47391ae48e0fc579105d8e76a6d9c4fab3271367476580 -F src/upsert.c 2920de71b20f04fe25eb00b655d086f0ba60ea133c59d7fa3325c49838818e78 +F src/upsert.c 25673d007c2408fec47a6326b6d7ac265abd2cbc162d11f3b3c333de27d3c78a F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/util.c c0c7977de7ef9b8cb10f6c85f2d0557889a658f817b0455909a49179ba4c8002 F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286 @@ -1888,7 +1888,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 99ff6418492adcbaf2be728737735afa1c2997de5868395e69c53d08fc14491f -R 747ed0f69719082482a4ff82786fa288 +P 4b286129138d44e6f8e9b3450289941e01d20fdfb9d0b5d846031425e8ca6b49 +R 204aa888c3a8b96c5008bc9a579603f7 +T *branch * generalized-upsert +T *sym-generalized-upsert * +T -sym-trunk * U drh -Z ac855459dfaf775bb9ffc51142afdf45 +Z d13edca14ac31a65fc7ae7d7fdc7eaff diff --git a/manifest.uuid b/manifest.uuid index 7e5c04ae26..0eeaf11f2a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4b286129138d44e6f8e9b3450289941e01d20fdfb9d0b5d846031425e8ca6b49 \ No newline at end of file +2ca62f4c71df6544cb8039bdc80e3701d09697c38800534371f6d44532fcffae \ No newline at end of file diff --git a/src/parse.y b/src/parse.y index d3ec2b3da6..f28bb47414 100644 --- a/src/parse.y +++ b/src/parse.y @@ -952,20 +952,17 @@ cmd ::= with insert_cmd(R) INTO xfullname(X) idlist_opt(F) DEFAULT VALUES. } %type upsert {Upsert*} - -// Because upsert only occurs at the tip end of the INSERT rule for cmd, -// there is never a case where the value of the upsert pointer will not -// be destroyed by the cmd action. So comment-out the destructor to -// avoid unreachable code. -//%destructor upsert {sqlite3UpsertDelete(pParse->db,$$);} +%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;} diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 438f79c092..68c8680600 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3071,6 +3071,7 @@ struct Upsert { 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 */ + Upsert *pNextUpsert; /* Next ON CONFLICT clause in the list */ /* 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. @@ -4824,15 +4825,15 @@ 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); #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) #endif diff --git a/src/upsert.c b/src/upsert.c index 9a33f75d0a..ddd7c18428 100644 --- a/src/upsert.c +++ b/src/upsert.c @@ -18,15 +18,21 @@ /* ** 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); - } + p = pNext; + }while( p ); } +void sqlite3UpsertDelete(sqlite3 *db, Upsert *p){ + if( p ) upsertDelete(db, p); +} + /* ** Duplicate an Upsert object. @@ -37,7 +43,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,7 +56,8 @@ 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)); @@ -58,6 +66,7 @@ Upsert *sqlite3UpsertNew( sqlite3ExprDelete(db, pTargetWhere); sqlite3ExprListDelete(db, pSet); sqlite3ExprDelete(db, pWhere); + sqlite3UpsertDelete(db, pNext); return 0; }else{ pNew->pUpsertTarget = pTarget; @@ -65,6 +74,7 @@ Upsert *sqlite3UpsertNew( pNew->pUpsertSet = pSet; pNew->pUpsertWhere = pWhere; pNew->pUpsertIdx = 0; + pNew->pNextUpsert = pNext; } return pNew; } @@ -89,6 +99,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 +113,99 @@ 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; iiazColl[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; jja[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( iipUpsertTarget; + 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; iiazColl[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; jja[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( iipUpsertIdx = 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; } /* From 036e0675e6a0af385f03592a7ab56ba81e056174 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 8 Dec 2020 20:19:07 +0000 Subject: [PATCH 06/38] Experimental changes to vacuum to avoid loading large records entirely into memory. Currently only works in limited cases only - for rowid tables when the page-size does not change. FossilOrigin-Name: c90e063ca9ddcdd1e9f1a2e25a3f7d6e7ee798373ad8acf65b90536b0a124c0d --- manifest | 23 +++++++------- manifest.uuid | 2 +- src/btree.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/btree.h | 2 ++ src/insert.c | 21 +++++++------ src/vdbe.c | 38 ++++++++++++++++++----- 6 files changed, 142 insertions(+), 27 deletions(-) diff --git a/manifest b/manifest index 18c17599b4..6cf3a15c36 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sbad\sassert()\sin\smath1Func(). -D 2020-12-07T23:14:25.210 +C Experimental\schanges\sto\svacuum\sto\savoid\sloading\slarge\srecords\sentirely\sinto\smemory.\sCurrently\sonly\sworks\sin\slimited\scases\sonly\s-\sfor\srowid\stables\swhen\sthe\spage-size\sdoes\snot\schange. +D 2020-12-08T20:19:07.385 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -481,8 +481,8 @@ 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/btree.c 6d5cfd0e411e1db8042c94593a4847d85fc5398fa4860689d6f0d74cefa4e534 +F src/btree.h cff4cd182eb0d97802d82f398e4c8447f01bd2f5e501f70386b1097c910091cb F src/btreeInt.h ffd66480520d9d70222171b3a026d78b80833b5cea49c89867949f3e023d5f43 F src/build.c f6449d4e85e998e14d3f537e8ea898dca2fcb83c277db3e60945af9b9177db81 F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c @@ -501,7 +501,7 @@ 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 a64406fb5ae856fb30be018423eec9984a60a9b46d261447717c502b1fb781d3 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 8c9c8cd2bd8eecdb06d9b6e89de7e9e65bae45cc8fc33609cc74023a5c296067 F src/main.c 97e9f137354bc1f76dc9bb60a0a24f8c45cf73b33e80d3ee4c64155336fb820d @@ -612,7 +612,7 @@ F src/upsert.c 2920de71b20f04fe25eb00b655d086f0ba60ea133c59d7fa3325c49838818e78 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/util.c c0c7977de7ef9b8cb10f6c85f2d0557889a658f817b0455909a49179ba4c8002 F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286 -F src/vdbe.c d24a43b6b1ed2dba893636a14f5e56001444ab3fd5465e3bca8ab01799840acd +F src/vdbe.c 77fd09a782f72d5ff6e69363353e80e31d26bedd1d187e8813d781c74ba15770 F src/vdbe.h 83603854bfa5851af601fc0947671eb260f4363e62e960e8a994fb9bbcd2aaa1 F src/vdbeInt.h 3ca5e9fd6e095a8b6cf6bc3587a46fc93499503b2fe48951e1034ba9e2ce2f6e F src/vdbeapi.c c5e7cb2ab89a24d7f723e87b508f21bfb1359a04db5277d8a99fd1e015c12eb9 @@ -1888,7 +1888,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 99ff6418492adcbaf2be728737735afa1c2997de5868395e69c53d08fc14491f -R 747ed0f69719082482a4ff82786fa288 -U drh -Z ac855459dfaf775bb9ffc51142afdf45 +P 4b286129138d44e6f8e9b3450289941e01d20fdfb9d0b5d846031425e8ca6b49 +R ebe894c92d077c4bc1f846403c247ebe +T *branch * vacuum-lomem +T *sym-vacuum-lomem * +T -sym-trunk * +U dan +Z e00eb83dabf2298b62b079f62bce894b diff --git a/manifest.uuid b/manifest.uuid index 7e5c04ae26..ccd89eef6a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4b286129138d44e6f8e9b3450289941e01d20fdfb9d0b5d846031425e8ca6b49 \ No newline at end of file +c90e063ca9ddcdd1e9f1a2e25a3f7d6e7ee798373ad8acf65b90536b0a124c0d \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 4ac283101a..abc28c179a 100644 --- a/src/btree.c +++ b/src/btree.c @@ -6500,6 +6500,10 @@ static int fillInCell( /* Fill in the header. */ nHeader = pPage->childPtrSize; if( pPage->intKey ){ + if( pX->pData==(const void*)pPage->pBt->pTmpSpace ){ + *pnSize = pX->nData; + return SQLITE_OK; + } nPayload = pX->nData + pX->nZero; pSrc = pX->pData; nSrc = pX->nData; @@ -8912,6 +8916,85 @@ end_insert: return rc; } +int sqlite3BtreeTransfer( + BtCursor *pDest, + BtCursor *pSrc, + i64 iKey, + int seekResult +){ + int rc = SQLITE_OK; + BtreePayload x; + + memset(&x, 0, sizeof(x)); + x.nKey = iKey; + getCellInfo(pSrc); + if( pDest->pBt->usableSize!=pSrc->pBt->usableSize ){ + void *pFree = 0; + x.nData = pSrc->info.nPayload; + if( pSrc->info.nLocal==pSrc->info.nPayload ){ + x.pData = pSrc->info.pPayload; + }else{ + x.pData = pFree = sqlite3_malloc(pSrc->info.nPayload); + if( pFree==0 ){ + rc = SQLITE_NOMEM_BKPT; + }else{ + rc = sqlite3BtreePayload(pSrc, 0, x.nData, pFree); + } + } + if( rc==SQLITE_OK ){ + rc = sqlite3BtreeInsert(pDest, &x, OPFLAG_APPEND, seekResult); + } + sqlite3_free(pFree); + }else{ + /* Page sizes match. This means each overflow page (if any) and the + ** cell itself can be copied verbatim. */ + u8 *pCell = pDest->pBt->pTmpSpace; + x.pData = pCell; + x.nData = putVarint32(pCell, pSrc->info.nPayload); + x.nData += putVarint(&pCell[x.nData], iKey); + memcpy(&pCell[x.nData], pSrc->info.pPayload, pSrc->info.nLocal); + x.nData += pSrc->info.nLocal; + assert( pSrc->info.nLocal<=pSrc->info.nPayload ); + if( pSrc->info.nLocalinfo.nPayload ){ + Pager *pSrcPager = pSrc->pBt->pPager; + u8 *pPgno = &pCell[x.nData]; + Pgno ovfl; + x.nData += 4; + ovfl = get4byte(pSrc->info.pPayload + pSrc->info.nLocal); + do{ + MemPage *pNew = 0; + Pgno pgnoNew = 0; + if( rc==SQLITE_OK ){ + rc = allocateBtreePage(pDest->pBt, &pNew, &pgnoNew, 0, 0); + put4byte(pPgno, pgnoNew); + } + if( rc==SQLITE_OK ){ + pPgno = pNew->aData; + rc = sqlite3PagerWrite(pNew->pDbPage); + } + if( rc==SQLITE_OK ){ + DbPage *pOrig = 0; + void *pOrigData; + rc = sqlite3PagerGet(pSrcPager, ovfl, &pOrig, PAGER_GET_READONLY); + if( rc==SQLITE_OK ){ + pOrigData = sqlite3PagerGetData(pOrig); + memcpy(pNew->aData, pOrigData, pDest->pBt->usableSize); + put4byte(pNew->aData, 0); + ovfl = get4byte(pOrigData); + } + sqlite3PagerUnref(pOrig); + } + releasePage(pNew); + }while( rc==SQLITE_OK && ovfl>0 ); + } + if( rc==SQLITE_OK ){ + rc = sqlite3BtreeInsert(pDest, &x, OPFLAG_APPEND, seekResult); + } + } + + return rc; +} + /* ** Delete the entry that the cursor is pointing to. ** diff --git a/src/btree.h b/src/btree.h index 7a9ed2e3c6..abdfc33630 100644 --- a/src/btree.h +++ b/src/btree.h @@ -361,6 +361,8 @@ void sqlite3BtreeCursorList(Btree*); int sqlite3BtreeCheckpoint(Btree*, int, int *, int *); #endif +int sqlite3BtreeTransfer(BtCursor*, BtCursor*, i64, int); + /* ** If we are not using shared cache, then there is no need to ** use mutexes to access the BtShared structures. So make the diff --git a/src/insert.c b/src/insert.c index 393cd528f1..d801b47902 100644 --- a/src/insert.c +++ b/src/insert.c @@ -2783,11 +2783,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); @@ -2798,13 +2800,14 @@ static int xferOptimization( if( db->mDbFlags & DBFLAG_Vacuum ){ sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest); insFlags = OPFLAG_APPEND|OPFLAG_USESEEKRESULT; + sqlite3VdbeAddOp3(v, OP_Transfer, iDest, iSrc, regRowid); }else{ insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND; + sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1); + sqlite3VdbeAddOp4(v, OP_Insert, iDest, regData, regRowid, + (char*)pDest, P4_TABLE); + sqlite3VdbeChangeP5(v, insFlags); } - sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1); - sqlite3VdbeAddOp4(v, OP_Insert, iDest, regData, regRowid, - (char*)pDest, P4_TABLE); - sqlite3VdbeChangeP5(v, insFlags); sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0); sqlite3VdbeAddOp2(v, OP_Close, iDest, 0); diff --git a/src/vdbe.c b/src/vdbe.c index 1507fb3181..ea35e6aa56 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -3572,13 +3572,6 @@ case OP_Transaction: { && (iMeta!=pOp->p3 || db->aDb[pOp->p1].pSchema->iGeneration!=pOp->p4.i) ){ - /* - ** IMPLEMENTATION-OF: R-03189-51135 As each SQL statement runs, the schema - ** version is checked to ensure that the schema has not changed since the - ** SQL statement was prepared. - */ - sqlite3DbFree(db, p->zErrMsg); - p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed"); /* If the schema-cookie from the database file matches the cookie ** stored with the in-memory representation of the schema, do ** not reload the schema from the database file. @@ -3595,6 +3588,13 @@ case OP_Transaction: { if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){ sqlite3ResetOneSchema(db, pOp->p1); } + /* + ** IMPLEMENTATION-OF: R-03189-51135 As each SQL statement runs, the schema + ** version is checked to ensure that the schema has not changed since the + ** SQL statement was prepared. + */ + sqlite3DbFree(db, p->zErrMsg); + p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed"); p->expired = 1; rc = SQLITE_SCHEMA; } @@ -5143,6 +5143,30 @@ case OP_Insert: { break; } +/* Opcode: Transfer P1 P2 P3 * * +** Synopsis: intkey=r[P3] +** +** P1 and P2 are both cursors open on either intkey or index btrees. This +** instruction reads the current row from P2 and writes it into the +** table opened by P1. If P1 and P2 are opened on intkey tables, register +** P3 contains the rowid value to use when inserting into P1. +*/ +case OP_Transfer: { + VdbeCursor *pDest; /* Cursor to write to */ + VdbeCursor *pSrc; /* Cursor to read from */ + i64 iKey; /* Rowid value to insert with */ + + pDest = p->apCsr[pOp->p1]; + pSrc = p->apCsr[pOp->p2]; + iKey = aMem[pOp->p3].u.i; + + rc = sqlite3BtreeTransfer( + pDest->uc.pCursor, pSrc->uc.pCursor, iKey, pDest->seekResult + ); + 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. From 20b86324a1b3c78b5eee3872d1934ec21c911bfa Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 9 Dec 2020 01:34:48 +0000 Subject: [PATCH 07/38] Initialize all terms in the ON CONFLICT clause stack. FossilOrigin-Name: 5e683fd1cbde53f37cf8a2b1e981191e2b29e3376db554691767f33c37c7547e --- manifest | 15 ++++++--------- manifest.uuid | 2 +- src/insert.c | 19 ++++++++++++------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/manifest b/manifest index 9471059ac9..b6cfaef7fe 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhance\sUPSERT\sparsing\sto\sallow\smultiple\sON\sCONFLICT\sclauses.\s\sOnly\sthe\nvery\slast\sclause\smay\somit\sthe\sconflict\starget,\sbut\sthe\sconflict\starget\smay\nnow\sbe\somitted\sfor\sthe\sDO\sUPDATE\sresolution. -D 2020-12-08T14:29:03.533 +C Initialize\sall\sterms\sin\sthe\sON\sCONFLICT\sclause\sstack. +D 2020-12-09T01:34:48.233 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -501,7 +501,7 @@ 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 2fdfd14bf872501f041cb2220632dace2df63342151b9b30ebfb798df3f14632 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 8c9c8cd2bd8eecdb06d9b6e89de7e9e65bae45cc8fc33609cc74023a5c296067 F src/main.c 97e9f137354bc1f76dc9bb60a0a24f8c45cf73b33e80d3ee4c64155336fb820d @@ -1888,10 +1888,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 4b286129138d44e6f8e9b3450289941e01d20fdfb9d0b5d846031425e8ca6b49 -R 204aa888c3a8b96c5008bc9a579603f7 -T *branch * generalized-upsert -T *sym-generalized-upsert * -T -sym-trunk * +P 2ca62f4c71df6544cb8039bdc80e3701d09697c38800534371f6d44532fcffae +R 522b57bc98ce1a3ca7ad7f44cd4944b4 U drh -Z d13edca14ac31a65fc7ae7d7fdc7eaff +Z 6380cbc8ce17e23f96dde835eaec54ed diff --git a/manifest.uuid b/manifest.uuid index 0eeaf11f2a..f0390ac713 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2ca62f4c71df6544cb8039bdc80e3701d09697c38800534371f6d44532fcffae \ No newline at end of file +5e683fd1cbde53f37cf8a2b1e981191e2b29e3376db554691767f33c37c7547e \ No newline at end of file diff --git a/src/insert.c b/src/insert.c index 393cd528f1..137590a5e5 100644 --- a/src/insert.c +++ b/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 From 5602777e8fc872e638c0d9ccc116bebfd66e02e9 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 9 Dec 2020 13:11:02 +0000 Subject: [PATCH 08/38] Improved comments in sqliteInt.h. No changes to code. FossilOrigin-Name: 8ccb8d1d55fa5aaf625c30f0e7c10aa403d79b5574dbdfa3fd0271a4e546f7e3 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/sqliteInt.h | 14 ++++++++++---- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index b6cfaef7fe..ce2af91be7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Initialize\sall\sterms\sin\sthe\sON\sCONFLICT\sclause\sstack. -D 2020-12-09T01:34:48.233 +C Improved\scomments\sin\ssqliteInt.h.\s\sNo\schanges\sto\scode. +D 2020-12-09T13:11:02.579 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -545,7 +545,7 @@ F src/shell.c.in e9f674ee4ec6c345679e8a5b16c869c6c59eb1540dd98ac69e4736ecddce009 F src/sqlite.h.in 0e2b4259e49a0eda54d9118eb18a04fcd60e0727a2fd2c81aade0bf57520e706 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e -F src/sqliteInt.h 351d29fad669d5c98066a89ab48259d451379edac3c24773c3c8ac5df66fd8ff +F src/sqliteInt.h f8e462357ee34e6859f20e7f83adcca0809bbc1033a85a19d9be50a09930717a F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -1888,7 +1888,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 2ca62f4c71df6544cb8039bdc80e3701d09697c38800534371f6d44532fcffae -R 522b57bc98ce1a3ca7ad7f44cd4944b4 +P 5e683fd1cbde53f37cf8a2b1e981191e2b29e3376db554691767f33c37c7547e +R f2e8184a51a526d27f353dba2479feca U drh -Z 6380cbc8ce17e23f96dde835eaec54ed +Z 0139a36f3f85012162d949eb364157e1 diff --git a/manifest.uuid b/manifest.uuid index f0390ac713..0de188d914 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5e683fd1cbde53f37cf8a2b1e981191e2b29e3376db554691767f33c37c7547e \ No newline at end of file +8ccb8d1d55fa5aaf625c30f0e7c10aa403d79b5574dbdfa3fd0271a4e546f7e3 \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 68c8680600..06ddb3a613 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2304,16 +2304,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 */ @@ -3067,7 +3073,7 @@ 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 */ From ebbf36878ce2f1b7210be890eb676caf93c95ab2 Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 9 Dec 2020 16:32:11 +0000 Subject: [PATCH 09/38] Avoid loading large intkey rows when VACUUMing, even if the page-size is changing. FossilOrigin-Name: 0d2c3776065dc94119899ae4164995193b82fca7ac31868f3141b729d0b65ab9 --- manifest | 18 +++--- manifest.uuid | 2 +- src/btree.c | 157 ++++++++++++++++++++++++++++------------------ test/vacuum2.test | 2 +- test/vacuum6.test | 94 +++++++++++++++++++++++++++ 5 files changed, 200 insertions(+), 73 deletions(-) create mode 100644 test/vacuum6.test diff --git a/manifest b/manifest index 6cf3a15c36..9e63b89316 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Experimental\schanges\sto\svacuum\sto\savoid\sloading\slarge\srecords\sentirely\sinto\smemory.\sCurrently\sonly\sworks\sin\slimited\scases\sonly\s-\sfor\srowid\stables\swhen\sthe\spage-size\sdoes\snot\schange. -D 2020-12-08T20:19:07.385 +C Avoid\sloading\slarge\sintkey\srows\swhen\sVACUUMing,\seven\sif\sthe\spage-size\sis\schanging. +D 2020-12-09T16:32:11.593 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -481,7 +481,7 @@ F src/auth.c a3d5bfdba83d25abed1013a8c7a5f204e2e29b0c25242a56bc02bb0c07bf1e06 F src/backup.c 3014889fa06e20e6adfa0d07b60097eec1f6e5b06671625f476a714d2356513d F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 -F src/btree.c 6d5cfd0e411e1db8042c94593a4847d85fc5398fa4860689d6f0d74cefa4e534 +F src/btree.c 2dd52a7d6f473ef345ac028f49f3cc14e1207a3596b2d9fd92fe532e57da6328 F src/btree.h cff4cd182eb0d97802d82f398e4c8447f01bd2f5e501f70386b1097c910091cb F src/btreeInt.h ffd66480520d9d70222171b3a026d78b80833b5cea49c89867949f3e023d5f43 F src/build.c f6449d4e85e998e14d3f537e8ea898dca2fcb83c277db3e60945af9b9177db81 @@ -1650,10 +1650,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 7d3aea27ef3c671dafccbad5adc7848205c38ab14ee7a1dabe592e0794e132d7 F test/vacuummem.test 7b42abb3208bd82dd23a7536588396f295a314f2 F test/varint.test bbce22cda8fc4d135bcc2b589574be8410614e62 F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661 @@ -1888,10 +1889,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 4b286129138d44e6f8e9b3450289941e01d20fdfb9d0b5d846031425e8ca6b49 -R ebe894c92d077c4bc1f846403c247ebe -T *branch * vacuum-lomem -T *sym-vacuum-lomem * -T -sym-trunk * +P c90e063ca9ddcdd1e9f1a2e25a3f7d6e7ee798373ad8acf65b90536b0a124c0d +R 306b82fcb1780d3a4b54ba51609ce03f U dan -Z e00eb83dabf2298b62b079f62bce894b +Z fc13f09d46076f2b65a2bba6a14de43b diff --git a/manifest.uuid b/manifest.uuid index ccd89eef6a..e9576184e1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c90e063ca9ddcdd1e9f1a2e25a3f7d6e7ee798373ad8acf65b90536b0a124c0d \ No newline at end of file +0d2c3776065dc94119899ae4164995193b82fca7ac31868f3141b729d0b65ab9 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index abc28c179a..96ea9c4a04 100644 --- a/src/btree.c +++ b/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, int 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. @@ -6500,7 +6518,7 @@ static int fillInCell( /* Fill in the header. */ nHeader = pPage->childPtrSize; if( pPage->intKey ){ - if( pX->pData==(const void*)pPage->pBt->pTmpSpace ){ + if( pX->nZero<0 ){ *pnSize = pX->nData; return SQLITE_OK; } @@ -8924,72 +8942,89 @@ int sqlite3BtreeTransfer( ){ int rc = SQLITE_OK; BtreePayload x; + Pager *pSrcPager = pSrc->pBt->pPager; + u8 *pCell = pDest->pBt->pTmpSpace; + u8 *aOut; /* Pointer to next output buffer */ + int nOut; /* Size of output buffer aOut[] */ + const u8 *aIn; /* Pointer to next input buffer */ + int nIn; /* Size of input buffer aIn[] */ + int nRem; /* Bytes of data still to copy */ + u8 *pPgnoOut = 0; + Pgno ovflIn = 0; + DbPage *pPageIn = 0; + MemPage *pPageOut = 0; memset(&x, 0, sizeof(x)); x.nKey = iKey; getCellInfo(pSrc); - if( pDest->pBt->usableSize!=pSrc->pBt->usableSize ){ - void *pFree = 0; - x.nData = pSrc->info.nPayload; - if( pSrc->info.nLocal==pSrc->info.nPayload ){ - x.pData = pSrc->info.pPayload; - }else{ - x.pData = pFree = sqlite3_malloc(pSrc->info.nPayload); - if( pFree==0 ){ - rc = SQLITE_NOMEM_BKPT; - }else{ - rc = sqlite3BtreePayload(pSrc, 0, x.nData, pFree); + + x.pData = pCell; + x.nData = putVarint32(pCell, pSrc->info.nPayload); + x.nData += putVarint(&pCell[x.nData], iKey); + x.nZero = -1; + + nOut = btreePayloadToLocal(pDest->pPage, pSrc->info.nPayload); + aOut = &pCell[x.nData]; + nIn = pSrc->info.nLocal; + aIn = pSrc->info.pPayload; + nRem = pSrc->info.nPayload; + + x.nData += nOut; + if( nOutinfo.nPayload ){ + pPgnoOut = &pCell[x.nData]; + x.nData += 4; + } + + if( nRem>nIn ){ + 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(pDest->pBt, &pNew, &pgnoNew, 0, 0); + put4byte(pPgnoOut, pgnoNew); + releasePage(pPageOut); + pPageOut = pNew; + if( pPageOut ){ + pPgnoOut = pPageOut->aData; + put4byte(pPgnoOut, 0); + aOut = &pPgnoOut[4]; + nOut = MIN(pDest->pBt->usableSize - 4, nRem); } } - if( rc==SQLITE_OK ){ - rc = sqlite3BtreeInsert(pDest, &x, OPFLAG_APPEND, seekResult); - } - sqlite3_free(pFree); - }else{ - /* Page sizes match. This means each overflow page (if any) and the - ** cell itself can be copied verbatim. */ - u8 *pCell = pDest->pBt->pTmpSpace; - x.pData = pCell; - x.nData = putVarint32(pCell, pSrc->info.nPayload); - x.nData += putVarint(&pCell[x.nData], iKey); - memcpy(&pCell[x.nData], pSrc->info.pPayload, pSrc->info.nLocal); - x.nData += pSrc->info.nLocal; - assert( pSrc->info.nLocal<=pSrc->info.nPayload ); - if( pSrc->info.nLocalinfo.nPayload ){ - Pager *pSrcPager = pSrc->pBt->pPager; - u8 *pPgno = &pCell[x.nData]; - Pgno ovfl; - x.nData += 4; - ovfl = get4byte(pSrc->info.pPayload + pSrc->info.nLocal); - do{ - MemPage *pNew = 0; - Pgno pgnoNew = 0; - if( rc==SQLITE_OK ){ - rc = allocateBtreePage(pDest->pBt, &pNew, &pgnoNew, 0, 0); - put4byte(pPgno, pgnoNew); - } - if( rc==SQLITE_OK ){ - pPgno = pNew->aData; - rc = sqlite3PagerWrite(pNew->pDbPage); - } - if( rc==SQLITE_OK ){ - DbPage *pOrig = 0; - void *pOrigData; - rc = sqlite3PagerGet(pSrcPager, ovfl, &pOrig, PAGER_GET_READONLY); - if( rc==SQLITE_OK ){ - pOrigData = sqlite3PagerGetData(pOrig); - memcpy(pNew->aData, pOrigData, pDest->pBt->usableSize); - put4byte(pNew->aData, 0); - ovfl = get4byte(pOrigData); - } - sqlite3PagerUnref(pOrig); - } - releasePage(pNew); - }while( rc==SQLITE_OK && ovfl>0 ); - } - if( rc==SQLITE_OK ){ - rc = sqlite3BtreeInsert(pDest, &x, OPFLAG_APPEND, seekResult); - } + }while( nRem>0 && rc==SQLITE_OK ); + + releasePage(pPageOut); + sqlite3PagerUnref(pPageIn); + + if( rc==SQLITE_OK ){ + rc = sqlite3BtreeInsert(pDest, &x, OPFLAG_APPEND, seekResult); } return rc; diff --git a/test/vacuum2.test b/test/vacuum2.test index 0350c8ec42..89fdb506c5 100644 --- a/test/vacuum2.test +++ b/test/vacuum2.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 } diff --git a/test/vacuum6.test b/test/vacuum6.test new file mode 100644 index 0000000000..203b3329e2 --- /dev/null +++ b/test/vacuum6.test @@ -0,0 +1,94 @@ +# 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 +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 1 UNION ALL SELECT i+1 FROM s WHERE i<10000 + ) + INSERT INTO tx SELECT i, randomblob(i) FROM s; +} +foreach {tn pgsz} { + 1 2048 + 2 1024 + 3 65536 + 4 8192 +} { + do_execsql_test 4.1.$tn.1 " + PRAGMA page_size = $pgsz + " + do_execsql_test 4.1.$tn.2 VACUUM + integrity_check 4.1.$tn.3 +} + +finish_test From 1418b9daf66066941d1d2e58b2edc28b29575bb1 Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 9 Dec 2020 16:49:28 +0000 Subject: [PATCH 10/38] Add tests for a 'delete' command on a contentless table where values that weren't actually inserted are NULL. FossilOrigin-Name: 818c647cec7063b33b6c5de3e23599a1d61439fa6e9bf6c974b2522a5a9e1b44 --- ext/fts5/test/fts5delete.test | 23 ++++++++++++++++++++++- manifest | 14 +++++++------- manifest.uuid | 2 +- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/ext/fts5/test/fts5delete.test b/ext/fts5/test/fts5delete.test index 467e2e5707..1214fec4f4 100644 --- a/ext/fts5/test/fts5delete.test +++ b/ext/fts5/test/fts5delete.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 + diff --git a/manifest b/manifest index 18c17599b4..12a9b3e68c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sbad\sassert()\sin\smath1Func(). -D 2020-12-07T23:14:25.210 +C Add\stests\sfor\sa\s'delete'\scommand\son\sa\scontentless\stable\swhere\svalues\sthat\sweren't\sactually\sinserted\sare\sNULL. +D 2020-12-09T16:49:28.314 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -162,7 +162,7 @@ F ext/fts5/test/fts5corrupt.test 77ae6f41a7eba10620efb921cf7dbe218b0ef232b04519d F ext/fts5/test/fts5corrupt2.test 7453752ba12ce91690c469a6449d412561cc604b1dec994e16ab132952e7805f F ext/fts5/test/fts5corrupt3.test 1c26a651ea7e52fd69d54436fe4f02f6dd1268bc8b48ab851c7e1d374aa242b9 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 @@ -1888,7 +1888,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 99ff6418492adcbaf2be728737735afa1c2997de5868395e69c53d08fc14491f -R 747ed0f69719082482a4ff82786fa288 -U drh -Z ac855459dfaf775bb9ffc51142afdf45 +P 4b286129138d44e6f8e9b3450289941e01d20fdfb9d0b5d846031425e8ca6b49 +R 37fc0afc3fe30eb3e2571a975a076869 +U dan +Z 8a4734d621babbb70002204527e1408c diff --git a/manifest.uuid b/manifest.uuid index 7e5c04ae26..1e6307466a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4b286129138d44e6f8e9b3450289941e01d20fdfb9d0b5d846031425e8ca6b49 \ No newline at end of file +818c647cec7063b33b6c5de3e23599a1d61439fa6e9bf6c974b2522a5a9e1b44 \ No newline at end of file From e84ad92f17b96f1952f27645042bbf83fe6d0da5 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 9 Dec 2020 20:30:47 +0000 Subject: [PATCH 11/38] For upsert, the constraint check code generator uses a copy of the index list for the target table, which can potentially be reordered. FossilOrigin-Name: 3194c00c2c6a32bdfd5acc9fda5b38ae131d20cd3b7aea8512a41b2e76808f6a --- manifest | 19 +++++++++++-------- manifest.uuid | 2 +- src/insert.c | 48 +++++++++++++++++++++++++++++++++++++----------- src/sqliteInt.h | 12 ++++++++---- src/upsert.c | 4 ++-- 5 files changed, 59 insertions(+), 26 deletions(-) diff --git a/manifest b/manifest index ce2af91be7..7766814266 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improved\scomments\sin\ssqliteInt.h.\s\sNo\schanges\sto\scode. -D 2020-12-09T13:11:02.579 +C For\supsert,\sthe\sconstraint\scheck\scode\sgenerator\suses\sa\scopy\sof\sthe\sindex\slist\nfor\sthe\starget\stable,\swhich\scan\spotentially\sbe\sreordered. +D 2020-12-09T20:30:47.480 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -501,7 +501,7 @@ 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 2fdfd14bf872501f041cb2220632dace2df63342151b9b30ebfb798df3f14632 +F src/insert.c df28564b7d79f146266e906549687c74e3a5e9c4d8ba8697ef9c479ad83407e0 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 8c9c8cd2bd8eecdb06d9b6e89de7e9e65bae45cc8fc33609cc74023a5c296067 F src/main.c 97e9f137354bc1f76dc9bb60a0a24f8c45cf73b33e80d3ee4c64155336fb820d @@ -545,7 +545,7 @@ F src/shell.c.in e9f674ee4ec6c345679e8a5b16c869c6c59eb1540dd98ac69e4736ecddce009 F src/sqlite.h.in 0e2b4259e49a0eda54d9118eb18a04fcd60e0727a2fd2c81aade0bf57520e706 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e -F src/sqliteInt.h f8e462357ee34e6859f20e7f83adcca0809bbc1033a85a19d9be50a09930717a +F src/sqliteInt.h f01f37844eed0fab3e1fa8efe72cc327cf8e2ac121688ec94199d610978ecb09 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -608,7 +608,7 @@ F src/tokenize.c 01dba3023659dc6f6b1e054c14b35a0074bd35de10466b99454d33278191d97 F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda F src/trigger.c 515e79206d40d1d4149129318582e79a6e9db590a7b74e226fdb5b2a6c7e1b10 F src/update.c 9f126204a6acb96bbe47391ae48e0fc579105d8e76a6d9c4fab3271367476580 -F src/upsert.c 25673d007c2408fec47a6326b6d7ac265abd2cbc162d11f3b3c333de27d3c78a +F src/upsert.c 803c383d493546c71580e9e532d6c7f87fc337316a2ffc202ba1812158dfa8fb F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/util.c c0c7977de7ef9b8cb10f6c85f2d0557889a658f817b0455909a49179ba4c8002 F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286 @@ -1888,7 +1888,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 5e683fd1cbde53f37cf8a2b1e981191e2b29e3376db554691767f33c37c7547e -R f2e8184a51a526d27f353dba2479feca +P 8ccb8d1d55fa5aaf625c30f0e7c10aa403d79b5574dbdfa3fd0271a4e546f7e3 +R cb21a770762087a569cd96190733ebe7 +T *branch * generalized-upsert-ex1 +T *sym-generalized-upsert-ex1 * +T -sym-generalized-upsert * U drh -Z 0139a36f3f85012162d949eb364157e1 +Z d9a35c3fa2c53151f722f0a994f8bfdd diff --git a/manifest.uuid b/manifest.uuid index 0de188d914..ce7066ad55 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8ccb8d1d55fa5aaf625c30f0e7c10aa403d79b5574dbdfa3fd0271a4e546f7e3 \ No newline at end of file +3194c00c2c6a32bdfd5acc9fda5b38ae131d20cd3b7aea8512a41b2e76808f6a \ No newline at end of file diff --git a/src/insert.c b/src/insert.c index 137590a5e5..f10587f9f2 100644 --- a/src/insert.c +++ b/src/insert.c @@ -976,6 +976,9 @@ void sqlite3Insert( #ifndef SQLITE_OMIT_UPSERT if( pUpsert ){ Upsert *pNx; + int nIdx; + Index *pIdxList; + int *aReg; if( IsVirtual(pTab) ){ sqlite3ErrorMsg(pParse, "UPSERT not implemented for virtual table \"%s\"", pTab->zName); @@ -1000,6 +1003,26 @@ void sqlite3Insert( } pNx = pNx->pNextUpsert; }while( pNx!=0 ); + for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ + assert( pIdx ); + assert( aRegIdx[nIdx]>0 ); + } + if( nIdx==0 ){ + pUpsert->pIdxList = 0; + }else{ + u64 nByte = sizeof(Index)*nIdx + sizeof(int)*(nIdx+2); + pIdxList = sqlite3DbMallocRaw(db, nByte); + if( pIdxList==0 ) goto insert_cleanup; + aReg = (int*)&pIdxList[nIdx]; + for(i=0, pIdx=pTab->pIndex; ipNext, i++){ + memcpy(&pIdxList[i], pIdx, sizeof(Index)); + pIdxList[i].pNext = 0; + if( i ) pIdxList[i-1].pNext = &pIdxList[i]; + aReg[i] = aRegIdx[i]; + } + aReg[i] = aRegIdx[i]; + pUpsert->pIdxList = pIdxList; + } } #endif @@ -1512,7 +1535,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 */ @@ -1930,7 +1953,8 @@ 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++){ + pIdx = pUpsert ? pUpsert->pIdxList : pTab->pIndex; + for(ix=0; pIdx; pIdx=pIdx->pNext, ix++){ int regIdx; /* Range of registers hold conent for pIdx */ int regR; /* Range of registers holding conflicting PK */ int iThisCur; /* Cursor for this UNIQUE index */ @@ -1938,7 +1962,7 @@ 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 ){ + if( pUpIdx && pUpIdx->zName==pIdx->zName ){ addrUniqueOk = upsertJump+1; upsertBypass = sqlite3VdbeGoto(v, 0); VdbeComment((v, "Skip upsert subroutine")); @@ -1946,7 +1970,7 @@ void sqlite3GenerateConstraintChecks( }else{ addrUniqueOk = sqlite3VdbeMakeLabel(pParse); } - if( bAffinityDone==0 && (pUpIdx==0 || pUpIdx==pIdx) ){ + if( bAffinityDone==0 && (pUpIdx==0 || pUpIdx->zName==pIdx->zName) ){ sqlite3TableAffinity(v, pTab, regNewData+1); bAffinityDone = 1; } @@ -1999,7 +2023,7 @@ void sqlite3GenerateConstraintChecks( ** of a WITHOUT ROWID table and there has been no change the ** primary key, then no collision is possible. The collision detection ** logic below can all be skipped. */ - if( isUpdate && pPk==pIdx && pkChng==0 ){ + if( isUpdate && pPk && pPk->zName==pIdx->zName && pkChng==0 ){ sqlite3VdbeResolveLabel(v, addrUniqueOk); continue; } @@ -2017,7 +2041,7 @@ void sqlite3GenerateConstraintChecks( } /* Figure out if the upsert clause applies to this index */ - if( pUpIdx==pIdx ){ + if( pUpIdx && pUpIdx->zName==pIdx->zName ){ if( pUpsert->pUpsertSet==0 ){ onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */ }else{ @@ -2037,7 +2061,7 @@ void sqlite3GenerateConstraintChecks( ** is invoked. */ #ifndef SQLITE_ENABLE_PREUPDATE_HOOK if( (ix==0 && pIdx->pNext==0) /* Condition 3 */ - && pPk==pIdx /* Condition 2 */ + && pPk && pPk->zName==pIdx->zName /* Condition 2 */ && onError==OE_Replace /* Condition 1 */ && ( 0==(db->flags&SQLITE_RecTriggers) || /* Condition 4 */ 0==sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0)) @@ -2056,7 +2080,8 @@ void sqlite3GenerateConstraintChecks( regIdx, pIdx->nKeyCol); VdbeCoverage(v); /* Generate code to handle collisions */ - regR = (pIdx==pPk) ? regIdx : sqlite3GetTempRange(pParse, nPkField); + regR = (pPk && pIdx->zName==pPk->zName) ? + regIdx : sqlite3GetTempRange(pParse, nPkField); if( isUpdate || onError==OE_Replace ){ if( HasRowid(pTab) ){ sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR); @@ -2071,7 +2096,7 @@ void sqlite3GenerateConstraintChecks( int x; /* Extract the PRIMARY KEY from the end of the index entry and ** store it in registers regR..regR+nPk-1 */ - if( pIdx!=pPk ){ + if( pPk && pIdx->zName!=pPk->zName ){ for(i=0; inKeyCol; i++){ assert( pPk->aiColumn[i]>=0 ); x = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[i]); @@ -2152,7 +2177,8 @@ void sqlite3GenerateConstraintChecks( } sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur, regR, nPkField, 0, OE_Replace, - (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), iThisCur); + (pPk && pIdx->zName==pPk->zName ? ONEPASS_SINGLE : ONEPASS_OFF), + iThisCur); if( pTrigger && isUpdate ){ sqlite3VdbeAddOp1(v, OP_CursorUnlock, iDataCur); } @@ -2208,7 +2234,7 @@ void sqlite3GenerateConstraintChecks( break; } } - if( pUpIdx==pIdx ){ + if( pUpIdx && pUpIdx->zName==pIdx->zName ){ sqlite3VdbeGoto(v, upsertJump+1); sqlite3VdbeJumpHere(v, upsertBypass); }else{ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 06ddb3a613..8661f9058c 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3078,10 +3078,14 @@ struct Upsert { ExprList *pUpsertSet; /* The SET clause from an ON CONFLICT UPDATE */ Expr *pUpsertWhere; /* WHERE clause for the ON CONFLICT UPDATE */ Upsert *pNextUpsert; /* Next ON CONFLICT clause in the list */ - /* 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. */ + /* Above this point is the parse tree for the ON CONFLICT clauses. + ** The next group of fields stores intermediate data. */ + Index *pIdxList; + /* 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; /* Constraint that pUpsertTarget identifies */ SrcList *pUpsertSrc; /* Table to be updated */ int regData; /* First register holding array of VALUES */ diff --git a/src/upsert.c b/src/upsert.c index ddd7c18428..0f1f6d8a32 100644 --- a/src/upsert.c +++ b/src/upsert.c @@ -25,6 +25,7 @@ static void SQLITE_NOINLINE upsertDelete(sqlite3 *db, Upsert *p){ sqlite3ExprDelete(db, p->pUpsertTargetWhere); sqlite3ExprListDelete(db, p->pUpsertSet); sqlite3ExprDelete(db, p->pUpsertWhere); + sqlite3DbFree(db, p->pIdxList); sqlite3DbFree(db, p); p = pNext; }while( p ); @@ -60,7 +61,7 @@ Upsert *sqlite3UpsertNew( 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); @@ -73,7 +74,6 @@ Upsert *sqlite3UpsertNew( pNew->pUpsertTargetWhere = pTargetWhere; pNew->pUpsertSet = pSet; pNew->pUpsertWhere = pWhere; - pNew->pUpsertIdx = 0; pNew->pNextUpsert = pNext; } return pNew; From cd1b2d0b5431164787d4acad07940191af992c6a Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 9 Dec 2020 20:33:51 +0000 Subject: [PATCH 12/38] Transfer large index or WITHOUT ROWID records between b-trees when vacuuming without loading them into memory. FossilOrigin-Name: dfd4ca6891a893d0e9551689954d3e79114d5565f8a5264f96ad1d64fe1d6280 --- manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/btree.c | 30 +++++++++++++++++------------- src/btree.h | 1 + src/insert.c | 9 ++++++--- src/vdbe.c | 2 +- 6 files changed, 35 insertions(+), 27 deletions(-) diff --git a/manifest b/manifest index 9e63b89316..3a5de7a2d6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Avoid\sloading\slarge\sintkey\srows\swhen\sVACUUMing,\seven\sif\sthe\spage-size\sis\schanging. -D 2020-12-09T16:32:11.593 +C Transfer\slarge\sindex\sor\sWITHOUT\sROWID\srecords\sbetween\sb-trees\swhen\svacuuming\swithout\sloading\sthem\sinto\smemory. +D 2020-12-09T20:33:51.761 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -481,8 +481,8 @@ F src/auth.c a3d5bfdba83d25abed1013a8c7a5f204e2e29b0c25242a56bc02bb0c07bf1e06 F src/backup.c 3014889fa06e20e6adfa0d07b60097eec1f6e5b06671625f476a714d2356513d F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 -F src/btree.c 2dd52a7d6f473ef345ac028f49f3cc14e1207a3596b2d9fd92fe532e57da6328 -F src/btree.h cff4cd182eb0d97802d82f398e4c8447f01bd2f5e501f70386b1097c910091cb +F src/btree.c ce6a27f7d8be22aed5914e3c5bb7293eb6bc8fa43b332c0c2cdd71afcceb81e7 +F src/btree.h 78908bc31dd4cbd54762825346d7a24534773ec4ca42e16faf10a0a164d74ec4 F src/btreeInt.h ffd66480520d9d70222171b3a026d78b80833b5cea49c89867949f3e023d5f43 F src/build.c f6449d4e85e998e14d3f537e8ea898dca2fcb83c277db3e60945af9b9177db81 F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c @@ -501,7 +501,7 @@ 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 a64406fb5ae856fb30be018423eec9984a60a9b46d261447717c502b1fb781d3 +F src/insert.c 0c4f619e119dc6201fdc8f7ea4cbde9e71268cf3089b36c064c49c3e2d07077d F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 8c9c8cd2bd8eecdb06d9b6e89de7e9e65bae45cc8fc33609cc74023a5c296067 F src/main.c 97e9f137354bc1f76dc9bb60a0a24f8c45cf73b33e80d3ee4c64155336fb820d @@ -612,7 +612,7 @@ F src/upsert.c 2920de71b20f04fe25eb00b655d086f0ba60ea133c59d7fa3325c49838818e78 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/util.c c0c7977de7ef9b8cb10f6c85f2d0557889a658f817b0455909a49179ba4c8002 F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286 -F src/vdbe.c 77fd09a782f72d5ff6e69363353e80e31d26bedd1d187e8813d781c74ba15770 +F src/vdbe.c 334c2626ad478fc85c992856e71a6bdd95dc11bf0d7cfe10856ec915f3d9fbe5 F src/vdbe.h 83603854bfa5851af601fc0947671eb260f4363e62e960e8a994fb9bbcd2aaa1 F src/vdbeInt.h 3ca5e9fd6e095a8b6cf6bc3587a46fc93499503b2fe48951e1034ba9e2ce2f6e F src/vdbeapi.c c5e7cb2ab89a24d7f723e87b508f21bfb1359a04db5277d8a99fd1e015c12eb9 @@ -1889,7 +1889,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 c90e063ca9ddcdd1e9f1a2e25a3f7d6e7ee798373ad8acf65b90536b0a124c0d -R 306b82fcb1780d3a4b54ba51609ce03f +P 0d2c3776065dc94119899ae4164995193b82fca7ac31868f3141b729d0b65ab9 +R 2ada74530286abe77d1ee50368ad4c2c U dan -Z fc13f09d46076f2b65a2bba6a14de43b +Z b452c10135ea2f1997d2fa69cc2163a3 diff --git a/manifest.uuid b/manifest.uuid index e9576184e1..604f1fcaeb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0d2c3776065dc94119899ae4164995193b82fca7ac31868f3141b729d0b65ab9 \ No newline at end of file +dfd4ca6891a893d0e9551689954d3e79114d5565f8a5264f96ad1d64fe1d6280 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 96ea9c4a04..8087d3935b 100644 --- a/src/btree.c +++ b/src/btree.c @@ -6518,10 +6518,6 @@ static int fillInCell( /* Fill in the header. */ nHeader = pPage->childPtrSize; if( pPage->intKey ){ - if( pX->nZero<0 ){ - *pnSize = pX->nData; - return SQLITE_OK; - } nPayload = pX->nData + pX->nZero; pSrc = pX->pData; nSrc = pX->nData; @@ -8682,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 ); if( pCur->eState==CURSOR_FAULT ){ assert( pCur->skipNext!=SQLITE_OK ); @@ -8700,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( (pX->pKey==0)==(pCur->pKeyInfo==0) || (flags & BTREE_PREFORMAT) ); /* Save the positions of any other cursors open on this table. ** @@ -8810,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 ){ @@ -8827,8 +8824,15 @@ int sqlite3BtreeInsert( assert( pPage->isInit ); newCell = pBt->pTmpSpace; assert( newCell!=0 ); - rc = fillInCell(pPage, newCell, pX, &szNew); - if( rc ) goto end_insert; + if( flags & BTREE_PREFORMAT ){ + assert( pX->pData==pBt->pTmpSpace ); + szNew = pX->nData; + if( szNew<4 ) szNew = 4; + rc = SQLITE_OK; + }else{ + rc = fillInCell(pPage, newCell, pX, &szNew); + if( rc ) goto end_insert; + } assert( szNew==pPage->xCellSize(pPage, newCell) ); assert( szNew <= MX_CELL_SIZE(pBt) ); idx = pCur->ix; @@ -8959,9 +8963,8 @@ int sqlite3BtreeTransfer( getCellInfo(pSrc); x.pData = pCell; - x.nData = putVarint32(pCell, pSrc->info.nPayload); - x.nData += putVarint(&pCell[x.nData], iKey); - x.nZero = -1; + x.nData += putVarint32(pCell, pSrc->info.nPayload); + if( pDest->pKeyInfo==0 ) x.nData += putVarint(&pCell[x.nData], iKey); nOut = btreePayloadToLocal(pDest->pPage, pSrc->info.nPayload); aOut = &pCell[x.nData]; @@ -9024,7 +9027,8 @@ int sqlite3BtreeTransfer( sqlite3PagerUnref(pPageIn); if( rc==SQLITE_OK ){ - rc = sqlite3BtreeInsert(pDest, &x, OPFLAG_APPEND, seekResult); + int flags = BTREE_APPEND|BTREE_PREFORMAT; + rc = sqlite3BtreeInsert(pDest, &x, flags, seekResult); } return rc; diff --git a/src/btree.h b/src/btree.h index abdfc33630..4c2a872bb9 100644 --- a/src/btree.h +++ b/src/btree.h @@ -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 0x10 /* 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. diff --git a/src/insert.c b/src/insert.c index d801b47902..0af845e887 100644 --- a/src/insert.c +++ b/src/insert.c @@ -2851,13 +2851,16 @@ static int xferOptimization( if( i==pSrcIdx->nColumn ){ idxInsFlags = OPFLAG_USESEEKRESULT; sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest); + sqlite3VdbeAddOp3(v, OP_Transfer, iDest, iSrc, 0); } }else if( !HasRowid(pSrc) && pDestIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY ){ idxInsFlags |= OPFLAG_NCHANGE; } - sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1); - sqlite3VdbeAddOp2(v, OP_IdxInsert, iDest, regData); - sqlite3VdbeChangeP5(v, idxInsFlags|OPFLAG_APPEND); + if( idxInsFlags!=OPFLAG_USESEEKRESULT ){ + 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); sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0); diff --git a/src/vdbe.c b/src/vdbe.c index ea35e6aa56..74fede8562 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -5158,7 +5158,7 @@ case OP_Transfer: { pDest = p->apCsr[pOp->p1]; pSrc = p->apCsr[pOp->p2]; - iKey = aMem[pOp->p3].u.i; + iKey = pOp->p3 ? aMem[pOp->p3].u.i : 0; rc = sqlite3BtreeTransfer( pDest->uc.pCursor, pSrc->uc.pCursor, iKey, pDest->seekResult From d97a4c008dd7f58a0bbeabdd3d257b4487a77f92 Mon Sep 17 00:00:00 2001 From: mistachkin Date: Wed, 9 Dec 2020 23:35:51 +0000 Subject: [PATCH 13/38] Fix compilation issues with MSVC related to C99. FossilOrigin-Name: c0de6c1fb2c486be1da01e5e4ca8c5634ba37822e418d57f272e018c3e3fc0a2 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/func.c | 10 +++++++--- src/sqliteInt.h | 12 ++++++++++++ 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index 12a9b3e68c..617f92a7f3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\stests\sfor\sa\s'delete'\scommand\son\sa\scontentless\stable\swhere\svalues\sthat\sweren't\sactually\sinserted\sare\sNULL. -D 2020-12-09T16:49:28.314 +C Fix\scompilation\sissues\swith\sMSVC\srelated\sto\sC99. +D 2020-12-09T23:35:51.896 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -495,7 +495,7 @@ F src/delete.c 927cf8f900583e79aca8f1a321979e0a8f053babd9a690b44b38f79de2cc09fe F src/expr.c 0d196ed5a2ebf96be7e8df88add4fabfad0dce16c0fed81a4b8f6a26e259797f F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 83372403298e6a7dd989a47aaacdbaa5b4307b5199dbd56e07d4896066b3de72 -F src/func.c c65447d69bbf743328e7e4e836475ac5fb4ab80213fe5b189b8b0109e942e7c1 +F src/func.c 04b33016df7f4dcda295f71c6c776e2f49bfe0d50b5c5118240dfcd307d4755d F src/global.c ed55af196a9b66e198aaeda3f5454c3aa7d7d050c6c938181fd044b70d180a81 F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 @@ -545,7 +545,7 @@ F src/shell.c.in e9f674ee4ec6c345679e8a5b16c869c6c59eb1540dd98ac69e4736ecddce009 F src/sqlite.h.in 0e2b4259e49a0eda54d9118eb18a04fcd60e0727a2fd2c81aade0bf57520e706 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e -F src/sqliteInt.h 6ab40b33a1f5edbb7d71c78e82e0f9c5291dcff4704df8e4f0ab0d9c1a0c06af +F src/sqliteInt.h 6b9e04aff5ae385e8d0957bf64cb3c1c42f4bf5115788c7be76e85ca9875740b F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -1888,7 +1888,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 4b286129138d44e6f8e9b3450289941e01d20fdfb9d0b5d846031425e8ca6b49 -R 37fc0afc3fe30eb3e2571a975a076869 -U dan -Z 8a4734d621babbb70002204527e1408c +P 818c647cec7063b33b6c5de3e23599a1d61439fa6e9bf6c974b2522a5a9e1b44 +R f5a4c0e24239e1b152c6955913834244 +U mistachkin +Z ac2c81554df4b37487abc146a7fda901 diff --git a/manifest.uuid b/manifest.uuid index 1e6307466a..402122935f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -818c647cec7063b33b6c5de3e23599a1d61439fa6e9bf6c974b2522a5a9e1b44 \ No newline at end of file +c0de6c1fb2c486be1da01e5e4ca8c5634ba37822e418d57f272e018c3e3fc0a2 \ No newline at end of file diff --git a/src/func.c b/src/func.c index 169f231430..a29088a68d 100644 --- a/src/func.c +++ b/src/func.c @@ -2021,10 +2021,10 @@ static void math1Func( int argc, sqlite3_value **argv ){ - assert( argc==1 ); 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]); @@ -2043,10 +2043,10 @@ static void math2Func( int argc, sqlite3_value **argv ){ - assert( argc==2 ); 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]); @@ -2082,9 +2082,9 @@ static void signFunc( int argc, sqlite3_value **argv ){ - assert( argc==1 ); int type0; double x; + assert( argc==1 ); type0 = sqlite3_value_numeric_type(argv[0]); if( type0!=SQLITE_INTEGER && type0!=SQLITE_FLOAT ) return; x = sqlite3_value_double(argv[0]); @@ -2213,7 +2213,9 @@ void sqlite3RegisterBuiltinFunctions(void){ 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 ), @@ -2233,9 +2235,11 @@ void sqlite3RegisterBuiltinFunctions(void){ 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 ), diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 438f79c092..dd1d7e03ac 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -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 From 91f2717f22e5a7c3feab8224a16416677ad28e47 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 10 Dec 2020 12:49:26 +0000 Subject: [PATCH 14/38] The DO UPDATE code generator searches for the correct ON CONFLICT clause to use. FossilOrigin-Name: a47e35ee2d901baaa37e7229d190f934e1b0bd3510147cd4a2a49c4a1411416a --- manifest | 17 +++++++---------- manifest.uuid | 2 +- src/sqliteInt.h | 3 ++- src/upsert.c | 26 +++++++++++++++++++++----- 4 files changed, 31 insertions(+), 17 deletions(-) diff --git a/manifest b/manifest index 7766814266..abce3073d7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C For\supsert,\sthe\sconstraint\scheck\scode\sgenerator\suses\sa\scopy\sof\sthe\sindex\slist\nfor\sthe\starget\stable,\swhich\scan\spotentially\sbe\sreordered. -D 2020-12-09T20:30:47.480 +C The\sDO\sUPDATE\scode\sgenerator\ssearches\sfor\sthe\scorrect\sON\sCONFLICT\sclause\sto\nuse. +D 2020-12-10T12:49:26.425 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -545,7 +545,7 @@ F src/shell.c.in e9f674ee4ec6c345679e8a5b16c869c6c59eb1540dd98ac69e4736ecddce009 F src/sqlite.h.in 0e2b4259e49a0eda54d9118eb18a04fcd60e0727a2fd2c81aade0bf57520e706 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e -F src/sqliteInt.h f01f37844eed0fab3e1fa8efe72cc327cf8e2ac121688ec94199d610978ecb09 +F src/sqliteInt.h 0e042bd76044617ae919a294778ceacdb00a405d60de1b94c8ee4d2b81829bdb F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -608,7 +608,7 @@ F src/tokenize.c 01dba3023659dc6f6b1e054c14b35a0074bd35de10466b99454d33278191d97 F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda F src/trigger.c 515e79206d40d1d4149129318582e79a6e9db590a7b74e226fdb5b2a6c7e1b10 F src/update.c 9f126204a6acb96bbe47391ae48e0fc579105d8e76a6d9c4fab3271367476580 -F src/upsert.c 803c383d493546c71580e9e532d6c7f87fc337316a2ffc202ba1812158dfa8fb +F src/upsert.c 49170532578f2f30984b35e2c1e2f308b089c6814edf384d32158a53b25fc930 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/util.c c0c7977de7ef9b8cb10f6c85f2d0557889a658f817b0455909a49179ba4c8002 F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286 @@ -1888,10 +1888,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 8ccb8d1d55fa5aaf625c30f0e7c10aa403d79b5574dbdfa3fd0271a4e546f7e3 -R cb21a770762087a569cd96190733ebe7 -T *branch * generalized-upsert-ex1 -T *sym-generalized-upsert-ex1 * -T -sym-generalized-upsert * +P 3194c00c2c6a32bdfd5acc9fda5b38ae131d20cd3b7aea8512a41b2e76808f6a +R 8dc7164868d12444f67e9c3abe760e73 U drh -Z d9a35c3fa2c53151f722f0a994f8bfdd +Z 978ca06206ec1f9d5cc426705017394f diff --git a/manifest.uuid b/manifest.uuid index ce7066ad55..88e882cea1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3194c00c2c6a32bdfd5acc9fda5b38ae131d20cd3b7aea8512a41b2e76808f6a \ No newline at end of file +a47e35ee2d901baaa37e7229d190f934e1b0bd3510147cd4a2a49c4a1411416a \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 8661f9058c..23df9cc710 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3086,11 +3086,12 @@ struct Upsert { ** 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; /* Constraint that pUpsertTarget identifies */ + 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 */ int iIdxCur; /* Index of the first index cursor */ + int addrGenericUpdate; /* Address of routine for generic DO UPDATE */ }; /* diff --git a/src/upsert.c b/src/upsert.c index 0f1f6d8a32..63b9144419 100644 --- a/src/upsert.c +++ b/src/upsert.c @@ -229,11 +229,27 @@ 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; + while( + pUpsert->pUpsertTarget!=0 + && (pUpsert->pUpsertIdx==0 ? pIdx!=0 : + pUpsert->pUpsertIdx->zName!=pIdx->zName) + ){ + assert( pUpsert->pNextUpsert!=0 ); + pUpsert = pUpsert->pNextUpsert; + } + if( pUpsert->addrGenericUpdate>0 ){ + sqlite3VdbeAddOp2(v, OP_Goto, 0, pUpsert->addrGenericUpdate); + return; + } + VdbeNoopComment((v, "Begin DO UPDATE of UPSERT")); + if( pUpsert->pUpsertTarget==0 ){ + pUpsert->addrGenericUpdate = sqlite3VdbeCurrentAddr(v); + } if( pIdx && iCur!=iDataCur ){ if( HasRowid(pTab) ){ int regRowid = sqlite3GetTempReg(pParse); @@ -263,13 +279,13 @@ 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; inCol; 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, From 70f3eda5bedef47246d14a03e6ce4ce8a5c2ff50 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 10 Dec 2020 13:49:00 +0000 Subject: [PATCH 15/38] Add an optional function to the chsumvfs extension. When activated by the SQLITE_CKSUMVFS_INIT_FUNCNAME macro, this function will invoke the file-control that sets the number of reserved bytes to 8. This can be used to initialize a cksumvfs database file by programming languages that do not have access to the sqlite3_file_control() interface. FossilOrigin-Name: 01841fb4bf3d6c5fd5bcbc7d1338998c50f69f84ca475fba7cf764d636714678 --- ext/misc/cksumvfs.c | 40 ++++++++++++++++++++++++++++++++++++++++ manifest | 14 +++++++------- manifest.uuid | 2 +- 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/ext/misc/cksumvfs.c b/ext/misc/cksumvfs.c index a0888c0024..46f3a4f0b5 100644 --- a/ext/misc/cksumvfs.c +++ b/ext/misc/cksumvfs.c @@ -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; } diff --git a/manifest b/manifest index 617f92a7f3..ead9a8fa60 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\scompilation\sissues\swith\sMSVC\srelated\sto\sC99. -D 2020-12-09T23:35:51.896 +C Add\san\soptional\sfunction\sto\sthe\schsumvfs\sextension.\s\sWhen\sactivated\sby\nthe\sSQLITE_CKSUMVFS_INIT_FUNCNAME\smacro,\sthis\sfunction\swill\sinvoke\sthe\nfile-control\sthat\ssets\sthe\snumber\sof\sreserved\sbytes\sto\s8.\s\sThis\scan\sbe\nused\sto\sinitialize\sa\scksumvfs\sdatabase\sfile\sby\sprogramming\slanguages\nthat\sdo\snot\shave\saccess\sto\sthe\ssqlite3_file_control()\sinterface. +D 2020-12-10T13:49:00.833 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -291,7 +291,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 @@ -1888,7 +1888,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 818c647cec7063b33b6c5de3e23599a1d61439fa6e9bf6c974b2522a5a9e1b44 -R f5a4c0e24239e1b152c6955913834244 -U mistachkin -Z ac2c81554df4b37487abc146a7fda901 +P c0de6c1fb2c486be1da01e5e4ca8c5634ba37822e418d57f272e018c3e3fc0a2 +R 6c67d7c383f4b37d548756594c8d9b75 +U drh +Z ffe92d1035962188772639969e0a3892 diff --git a/manifest.uuid b/manifest.uuid index 402122935f..782a536fd6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c0de6c1fb2c486be1da01e5e4ca8c5634ba37822e418d57f272e018c3e3fc0a2 \ No newline at end of file +01841fb4bf3d6c5fd5bcbc7d1338998c50f69f84ca475fba7cf764d636714678 \ No newline at end of file From 7aae73588aeb9fd33d26f0d0a654bfbebdccf72c Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 10 Dec 2020 18:06:24 +0000 Subject: [PATCH 16/38] Better integrate the changes on this branch with OP_Insert and OP_IdxInsert. FossilOrigin-Name: 101cef14910d6e865a94bc870aed599321b893188062a9a61d70a9434992cf23 --- manifest | 22 +++---- manifest.uuid | 2 +- src/btree.c | 166 ++++++++++++++++++++++++------------------------ src/btree.h | 4 +- src/btreeInt.h | 1 + src/insert.c | 34 ++++++---- src/sqliteInt.h | 1 + src/vdbe.c | 26 +++----- 8 files changed, 129 insertions(+), 127 deletions(-) diff --git a/manifest b/manifest index 3a5de7a2d6..d9b671f413 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Transfer\slarge\sindex\sor\sWITHOUT\sROWID\srecords\sbetween\sb-trees\swhen\svacuuming\swithout\sloading\sthem\sinto\smemory. -D 2020-12-09T20:33:51.761 +C Better\sintegrate\sthe\schanges\son\sthis\sbranch\swith\sOP_Insert\sand\sOP_IdxInsert. +D 2020-12-10T18:06:24.603 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -481,9 +481,9 @@ F src/auth.c a3d5bfdba83d25abed1013a8c7a5f204e2e29b0c25242a56bc02bb0c07bf1e06 F src/backup.c 3014889fa06e20e6adfa0d07b60097eec1f6e5b06671625f476a714d2356513d F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 -F src/btree.c ce6a27f7d8be22aed5914e3c5bb7293eb6bc8fa43b332c0c2cdd71afcceb81e7 -F src/btree.h 78908bc31dd4cbd54762825346d7a24534773ec4ca42e16faf10a0a164d74ec4 -F src/btreeInt.h ffd66480520d9d70222171b3a026d78b80833b5cea49c89867949f3e023d5f43 +F src/btree.c b14822d4dd984340d8b1c46bf5d49b12ab3adf6b639c5f3b395fa541153b1ba3 +F src/btree.h 285f8377aa1353185a32bf455faafa9ff9a0d40d074d60509534d14990c7829e +F src/btreeInt.h 7614cae30f95b6aed0c7cac7718276a55cfe2c77058cbfd8bef5b75329757331 F src/build.c f6449d4e85e998e14d3f537e8ea898dca2fcb83c277db3e60945af9b9177db81 F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e @@ -501,7 +501,7 @@ 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 0c4f619e119dc6201fdc8f7ea4cbde9e71268cf3089b36c064c49c3e2d07077d +F src/insert.c 153c5b438d44ba0b8ae7ca467f8f6390b18958d14e681a26e5e861a2ac480750 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 8c9c8cd2bd8eecdb06d9b6e89de7e9e65bae45cc8fc33609cc74023a5c296067 F src/main.c 97e9f137354bc1f76dc9bb60a0a24f8c45cf73b33e80d3ee4c64155336fb820d @@ -545,7 +545,7 @@ F src/shell.c.in e9f674ee4ec6c345679e8a5b16c869c6c59eb1540dd98ac69e4736ecddce009 F src/sqlite.h.in 0e2b4259e49a0eda54d9118eb18a04fcd60e0727a2fd2c81aade0bf57520e706 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e -F src/sqliteInt.h 6ab40b33a1f5edbb7d71c78e82e0f9c5291dcff4704df8e4f0ab0d9c1a0c06af +F src/sqliteInt.h 47bc1232d1c68525876c6c2d2b602bf8f614f84e7650de6031301435b535bf30 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -612,7 +612,7 @@ F src/upsert.c 2920de71b20f04fe25eb00b655d086f0ba60ea133c59d7fa3325c49838818e78 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/util.c c0c7977de7ef9b8cb10f6c85f2d0557889a658f817b0455909a49179ba4c8002 F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286 -F src/vdbe.c 334c2626ad478fc85c992856e71a6bdd95dc11bf0d7cfe10856ec915f3d9fbe5 +F src/vdbe.c b8ac132f98ab4edb126c7784cfd6f479aa45e476c9e873c13ecd7bd6ffdd8668 F src/vdbe.h 83603854bfa5851af601fc0947671eb260f4363e62e960e8a994fb9bbcd2aaa1 F src/vdbeInt.h 3ca5e9fd6e095a8b6cf6bc3587a46fc93499503b2fe48951e1034ba9e2ce2f6e F src/vdbeapi.c c5e7cb2ab89a24d7f723e87b508f21bfb1359a04db5277d8a99fd1e015c12eb9 @@ -1889,7 +1889,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 0d2c3776065dc94119899ae4164995193b82fca7ac31868f3141b729d0b65ab9 -R 2ada74530286abe77d1ee50368ad4c2c +P dfd4ca6891a893d0e9551689954d3e79114d5565f8a5264f96ad1d64fe1d6280 +R 649db055ff8e87cb8a713e180a0e255a U dan -Z b452c10135ea2f1997d2fa69cc2163a3 +Z 6c3c81094000f4145ba4e14f9b1ea402 diff --git a/manifest.uuid b/manifest.uuid index 604f1fcaeb..36af76a357 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -dfd4ca6891a893d0e9551689954d3e79114d5565f8a5264f96ad1d64fe1d6280 \ No newline at end of file +101cef14910d6e865a94bc870aed599321b893188062a9a61d70a9434992cf23 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 8087d3935b..224d533b7c 100644 --- a/src/btree.c +++ b/src/btree.c @@ -8679,7 +8679,7 @@ int sqlite3BtreeInsert( unsigned char *newCell = 0; assert( (flags & (BTREE_SAVEPOSITION|BTREE_APPEND|BTREE_PREFORMAT))==flags ); - assert( (flags & BTREE_PREFORMAT)==0 || seekResult ); + assert( (flags & BTREE_PREFORMAT)==0 || seekResult || pCur->pKeyInfo==0 ); if( pCur->eState==CURSOR_FAULT ){ assert( pCur->skipNext!=SQLITE_OK ); @@ -8825,14 +8825,21 @@ int sqlite3BtreeInsert( newCell = pBt->pTmpSpace; assert( newCell!=0 ); if( flags & BTREE_PREFORMAT ){ - assert( pX->pData==pBt->pTmpSpace ); - szNew = pX->nData; - if( szNew<4 ) szNew = 4; rc = SQLITE_OK; + szNew = pBt->nPreformatSize; + if( szNew<4 ) szNew = 4; + if( ISAUTOVACUUM && szNew>pPage->maxLocal ){ + CellInfo info; + pPage->xParseCell(pPage, newCell, &info); + if( ISAUTOVACUUM && 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; } + if( rc ) goto end_insert; assert( szNew==pPage->xCellSize(pPage, newCell) ); assert( szNew <= MX_CELL_SIZE(pBt) ); idx = pCur->ix; @@ -8938,97 +8945,88 @@ end_insert: return rc; } -int sqlite3BtreeTransfer( - BtCursor *pDest, - BtCursor *pSrc, - i64 iKey, - int seekResult -){ +int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 iKey){ int rc = SQLITE_OK; - BtreePayload x; - Pager *pSrcPager = pSrc->pBt->pPager; - u8 *pCell = pDest->pBt->pTmpSpace; - u8 *aOut; /* Pointer to next output buffer */ - int nOut; /* Size of output buffer aOut[] */ + BtShared *pBt = pDest->pBt; + u8 *aOut = pBt->pTmpSpace; /* Pointer to next output buffer */ const u8 *aIn; /* Pointer to next input buffer */ int nIn; /* Size of input buffer aIn[] */ int nRem; /* Bytes of data still to copy */ - u8 *pPgnoOut = 0; - Pgno ovflIn = 0; - DbPage *pPageIn = 0; - MemPage *pPageOut = 0; - memset(&x, 0, sizeof(x)); - x.nKey = iKey; getCellInfo(pSrc); - - x.pData = pCell; - x.nData += putVarint32(pCell, pSrc->info.nPayload); - if( pDest->pKeyInfo==0 ) x.nData += putVarint(&pCell[x.nData], iKey); - - nOut = btreePayloadToLocal(pDest->pPage, pSrc->info.nPayload); - aOut = &pCell[x.nData]; + aOut += putVarint32(aOut, pSrc->info.nPayload); + if( pDest->pKeyInfo==0 ) aOut += putVarint(aOut, iKey); nIn = pSrc->info.nLocal; aIn = pSrc->info.pPayload; nRem = pSrc->info.nPayload; + if( nIn==nRem && nInpPage->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; + int nOut; /* Size of output buffer aOut[] */ - x.nData += nOut; - if( nOutinfo.nPayload ){ - pPgnoOut = &pCell[x.nData]; - x.nData += 4; - } - - if( nRem>nIn ){ - 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; + nOut = btreePayloadToLocal(pDest->pPage, pSrc->info.nPayload); + pBt->nPreformatSize = nOut + (aOut - pBt->pTmpSpace); + if( nOutinfo.nPayload ){ + pPgnoOut = &aOut[nOut]; + pBt->nPreformatSize += 4; + } + + if( nRem>nIn ){ + 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( rc==SQLITE_OK && nOut>0 ); - - if( rc==SQLITE_OK && nRem>0 ){ - Pgno pgnoNew; - MemPage *pNew = 0; - rc = allocateBtreePage(pDest->pBt, &pNew, &pgnoNew, 0, 0); - put4byte(pPgnoOut, pgnoNew); - releasePage(pPageOut); - pPageOut = pNew; - if( pPageOut ){ - pPgnoOut = pPageOut->aData; - put4byte(pPgnoOut, 0); - aOut = &pPgnoOut[4]; - nOut = MIN(pDest->pBt->usableSize - 4, nRem); - } - } - }while( nRem>0 && rc==SQLITE_OK ); - - releasePage(pPageOut); - sqlite3PagerUnref(pPageIn); - - if( rc==SQLITE_OK ){ - int flags = BTREE_APPEND|BTREE_PREFORMAT; - rc = sqlite3BtreeInsert(pDest, &x, flags, seekResult); + }while( nRem>0 && rc==SQLITE_OK ); + + releasePage(pPageOut); + sqlite3PagerUnref(pPageIn); } return rc; diff --git a/src/btree.h b/src/btree.h index 4c2a872bb9..e00c473c93 100644 --- a/src/btree.h +++ b/src/btree.h @@ -262,7 +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 0x10 /* 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. @@ -362,7 +362,7 @@ void sqlite3BtreeCursorList(Btree*); int sqlite3BtreeCheckpoint(Btree*, int, int *, int *); #endif -int sqlite3BtreeTransfer(BtCursor*, BtCursor*, i64, int); +int sqlite3BtreeTransferRow(BtCursor*, BtCursor*, i64); /* ** If we are not using shared cache, then there is no need to diff --git a/src/btreeInt.h b/src/btreeInt.h index c09699fbb5..851b8e6c1d 100644 --- a/src/btreeInt.h +++ b/src/btreeInt.h @@ -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() */ }; /* diff --git a/src/insert.c b/src/insert.c index 0af845e887..2a40acaa0c 100644 --- a/src/insert.c +++ b/src/insert.c @@ -2748,6 +2748,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 ); @@ -2797,17 +2798,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; - sqlite3VdbeAddOp3(v, OP_Transfer, iDest, iSrc, regRowid); + insFlags = OPFLAG_APPEND|OPFLAG_USESEEKRESULT|OPFLAG_PREFORMAT; }else{ - insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND; - sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1); - sqlite3VdbeAddOp4(v, OP_Insert, iDest, regData, regRowid, - (char*)pDest, P4_TABLE); - sqlite3VdbeChangeP5(v, insFlags); + 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); + } + sqlite3VdbeAddOp4(v, OP_Insert, iDest, regData, regRowid, + (char*)pDest, P4_TABLE); + sqlite3VdbeChangeP5(v, insFlags); + sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0); sqlite3VdbeAddOp2(v, OP_Close, iDest, 0); @@ -2849,18 +2859,18 @@ 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_Transfer, iDest, iSrc, 0); + sqlite3VdbeAddOp3(v, OP_RowCell, iDest, iSrc, regData); } }else if( !HasRowid(pSrc) && pDestIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY ){ idxInsFlags |= OPFLAG_NCHANGE; } - if( idxInsFlags!=OPFLAG_USESEEKRESULT ){ + 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_IdxInsert, iDest, regData); + sqlite3VdbeChangeP5(v, idxInsFlags|OPFLAG_APPEND); sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 438f79c092..fa24bf9ac0 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3517,6 +3517,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 diff --git a/src/vdbe.c b/src/vdbe.c index 74fede8562..e640dedbcd 100644 --- a/src/vdbe.c +++ b/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,29 +5144,20 @@ case OP_Insert: { break; } -/* Opcode: Transfer P1 P2 P3 * * -** Synopsis: intkey=r[P3] -** -** P1 and P2 are both cursors open on either intkey or index btrees. This -** instruction reads the current row from P2 and writes it into the -** table opened by P1. If P1 and P2 are opened on intkey tables, register -** P3 contains the rowid value to use when inserting into P1. +/* Opcode: RowCell P1 P2 P3 * * */ -case OP_Transfer: { +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 ); pDest = p->apCsr[pOp->p1]; pSrc = p->apCsr[pOp->p2]; iKey = pOp->p3 ? aMem[pOp->p3].u.i : 0; - - rc = sqlite3BtreeTransfer( - pDest->uc.pCursor, pSrc->uc.pCursor, iKey, pDest->seekResult - ); + 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 ** @@ -5822,7 +5814,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 ); @@ -5833,7 +5825,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 ); From d2ffc9721e0cc7ae5362bd80a0a65c4063eb7e18 Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 10 Dec 2020 19:20:15 +0000 Subject: [PATCH 17/38] Fix minor issues with new code on this branch. FossilOrigin-Name: f7fa76d0963e7b34026dc20c920bfbf7961033fe2b99503f6857157595f86823 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/btree.c | 15 +++++++++++++++ src/vdbe.c | 24 +++++++++++++++++------- test/vacuum6.test | 23 +++++++++++++++-------- 5 files changed, 56 insertions(+), 24 deletions(-) diff --git a/manifest b/manifest index 95ecdca302..44b269d0ac 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\strunk\schanges\sinto\sthis\sbranch. -D 2020-12-10T18:07:01.742 +C Fix\sminor\sissues\swith\snew\scode\son\sthis\sbranch. +D 2020-12-10T19:20:15.980 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -481,7 +481,7 @@ F src/auth.c a3d5bfdba83d25abed1013a8c7a5f204e2e29b0c25242a56bc02bb0c07bf1e06 F src/backup.c 3014889fa06e20e6adfa0d07b60097eec1f6e5b06671625f476a714d2356513d F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 -F src/btree.c b14822d4dd984340d8b1c46bf5d49b12ab3adf6b639c5f3b395fa541153b1ba3 +F src/btree.c de8d2a4d8dedf9187cc9019b8f882bc788ab8fe815b7f69042e880fbc11304dc F src/btree.h 285f8377aa1353185a32bf455faafa9ff9a0d40d074d60509534d14990c7829e F src/btreeInt.h 7614cae30f95b6aed0c7cac7718276a55cfe2c77058cbfd8bef5b75329757331 F src/build.c f6449d4e85e998e14d3f537e8ea898dca2fcb83c277db3e60945af9b9177db81 @@ -612,7 +612,7 @@ F src/upsert.c 2920de71b20f04fe25eb00b655d086f0ba60ea133c59d7fa3325c49838818e78 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/util.c c0c7977de7ef9b8cb10f6c85f2d0557889a658f817b0455909a49179ba4c8002 F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286 -F src/vdbe.c b8ac132f98ab4edb126c7784cfd6f479aa45e476c9e873c13ecd7bd6ffdd8668 +F src/vdbe.c 808c1503dd183578d7ebcf0e517e636c6005f783daadc9a27305b10597c1142e F src/vdbe.h 83603854bfa5851af601fc0947671eb260f4363e62e960e8a994fb9bbcd2aaa1 F src/vdbeInt.h 3ca5e9fd6e095a8b6cf6bc3587a46fc93499503b2fe48951e1034ba9e2ce2f6e F src/vdbeapi.c c5e7cb2ab89a24d7f723e87b508f21bfb1359a04db5277d8a99fd1e015c12eb9 @@ -1654,7 +1654,7 @@ F test/vacuum2.test 9fd45ce6ce29f5614c249e03938d3567c06a9e772d4f155949f8eafe2d8a F test/vacuum3.test 77ecdd54592b45a0bcb133339f99f1ae0ae94d0d F test/vacuum4.test 7ea76b769fffeb41f925303b04cbcf5a5bbeabe55e4c60ae754ff24eeeb7c010 F test/vacuum5.test 263b144d537e92ad8e9ca8a73cc6e1583f41cfd0dda9432b87f7806174a2f48c -F test/vacuum6.test 7d3aea27ef3c671dafccbad5adc7848205c38ab14ee7a1dabe592e0794e132d7 +F test/vacuum6.test e67488fa1341cc8034ba261807d429a8c06f4593ec1bb1651d8497d2d5df92c9 F test/vacuummem.test 7b42abb3208bd82dd23a7536588396f295a314f2 F test/varint.test bbce22cda8fc4d135bcc2b589574be8410614e62 F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661 @@ -1889,7 +1889,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 101cef14910d6e865a94bc870aed599321b893188062a9a61d70a9434992cf23 01841fb4bf3d6c5fd5bcbc7d1338998c50f69f84ca475fba7cf764d636714678 -R a5d793c28e830d9302f879f5ab38dd56 +P 7337eed629b4537b8fc2dc87c3c71d0a664128a91fd00f3c5f18843505beee90 +R 4dec8f74318b8721d36ac1bd02f7a778 U dan -Z 2458c10db91ae6ca73e242d0fd66a7be +Z 1308f2122d2b4d2b55d5a48e115dbda3 diff --git a/manifest.uuid b/manifest.uuid index e8cdfeec6b..7aba6f714d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7337eed629b4537b8fc2dc87c3c71d0a664128a91fd00f3c5f18843505beee90 \ No newline at end of file +f7fa76d0963e7b34026dc20c920bfbf7961033fe2b99503f6857157595f86823 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 224d533b7c..7522f01c36 100644 --- a/src/btree.c +++ b/src/btree.c @@ -8945,6 +8945,21 @@ 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; diff --git a/src/vdbe.c b/src/vdbe.c index e640dedbcd..904b5e2bc0 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -3572,6 +3572,13 @@ case OP_Transaction: { && (iMeta!=pOp->p3 || db->aDb[pOp->p1].pSchema->iGeneration!=pOp->p4.i) ){ + /* + ** IMPLEMENTATION-OF: R-03189-51135 As each SQL statement runs, the schema + ** version is checked to ensure that the schema has not changed since the + ** SQL statement was prepared. + */ + sqlite3DbFree(db, p->zErrMsg); + p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed"); /* If the schema-cookie from the database file matches the cookie ** stored with the in-memory representation of the schema, do ** not reload the schema from the database file. @@ -3588,13 +3595,6 @@ case OP_Transaction: { if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){ sqlite3ResetOneSchema(db, pOp->p1); } - /* - ** IMPLEMENTATION-OF: R-03189-51135 As each SQL statement runs, the schema - ** version is checked to ensure that the schema has not changed since the - ** SQL statement was prepared. - */ - sqlite3DbFree(db, p->zErrMsg); - p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed"); p->expired = 1; rc = SQLITE_SCHEMA; } @@ -5145,12 +5145,22 @@ case OP_Insert: { } /* 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; diff --git a/test/vacuum6.test b/test/vacuum6.test index 203b3329e2..51070fd0c7 100644 --- a/test/vacuum6.test +++ b/test/vacuum6.test @@ -34,6 +34,7 @@ do_execsql_test 1.1 { } #------------------------------------------------------------------------- +# reset_db foreach {tn sz} {1 400 2 4000 3 9999} { reset_db @@ -69,23 +70,29 @@ do_execsql_test 3.2 { } {ok} #------------------------------------------------------------------------- +# reset_db do_execsql_test 4.0 { CREATE TABLE tx(a, b); CREATE INDEX i1 ON tx(b); WITH s(i) AS ( - SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<10000 + SELECT 8000 UNION ALL SELECT i+1 FROM s WHERE i<10000 ) INSERT INTO tx SELECT i, randomblob(i) FROM s; -} -foreach {tn pgsz} { - 1 2048 - 2 1024 - 3 65536 - 4 8192 + + 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 page_size = $pgsz; + PRAGMA auto_vacuum = $av; " do_execsql_test 4.1.$tn.2 VACUUM integrity_check 4.1.$tn.3 From 9257ddbf87a2c3a8ecf7022f4a25975b89a1be3f Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 10 Dec 2020 19:54:13 +0000 Subject: [PATCH 18/38] Remove a redundant branch added by [56a54258560]. FossilOrigin-Name: b4d6f6d728738710249ad74236c31a1872fdff7dadabd4c4a67d05826eb5df9e --- manifest | 13 ++++++------- manifest.uuid | 2 +- src/btree.c | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 2b7531deb8..a3131d8cd4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Changes\sto\savoid\sloading\slarge\srecords\sinto\smemory\swithin\sVACUUM. -D 2020-12-10T19:51:39.987 +C Remove\sa\sredundant\sbranch\sadded\sby\s[56a54258560]. +D 2020-12-10T19:54:13.413 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -481,7 +481,7 @@ F src/auth.c a3d5bfdba83d25abed1013a8c7a5f204e2e29b0c25242a56bc02bb0c07bf1e06 F src/backup.c 3014889fa06e20e6adfa0d07b60097eec1f6e5b06671625f476a714d2356513d F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 -F src/btree.c de8d2a4d8dedf9187cc9019b8f882bc788ab8fe815b7f69042e880fbc11304dc +F src/btree.c 91da5fd5d99bc7e7422242419561bd9518e0229c243c48799303be7112ef5601 F src/btree.h 285f8377aa1353185a32bf455faafa9ff9a0d40d074d60509534d14990c7829e F src/btreeInt.h 7614cae30f95b6aed0c7cac7718276a55cfe2c77058cbfd8bef5b75329757331 F src/build.c f6449d4e85e998e14d3f537e8ea898dca2fcb83c277db3e60945af9b9177db81 @@ -1889,8 +1889,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 01841fb4bf3d6c5fd5bcbc7d1338998c50f69f84ca475fba7cf764d636714678 f7fa76d0963e7b34026dc20c920bfbf7961033fe2b99503f6857157595f86823 -R 4dec8f74318b8721d36ac1bd02f7a778 -T +closed f7fa76d0963e7b34026dc20c920bfbf7961033fe2b99503f6857157595f86823 +P 56a54258560fab715b83967634b2bd4c04be43cded112b46e85da9f99ee02f7c +R c82b011ba062cfde3acc0789a727fd1f U dan -Z 3adf74c0105eb40ca1b5c5d7fdb48232 +Z 9746b01cc9973ffd448104549b3bbdff diff --git a/manifest.uuid b/manifest.uuid index c98df885d4..8a864002ee 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -56a54258560fab715b83967634b2bd4c04be43cded112b46e85da9f99ee02f7c \ No newline at end of file +b4d6f6d728738710249ad74236c31a1872fdff7dadabd4c4a67d05826eb5df9e \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 7522f01c36..3ed365c5f7 100644 --- a/src/btree.c +++ b/src/btree.c @@ -8831,7 +8831,7 @@ int sqlite3BtreeInsert( if( ISAUTOVACUUM && szNew>pPage->maxLocal ){ CellInfo info; pPage->xParseCell(pPage, newCell, &info); - if( ISAUTOVACUUM && info.nPayload!=info.nLocal ){ + if( info.nPayload!=info.nLocal ){ Pgno ovfl = get4byte(&newCell[szNew-4]); ptrmapPut(pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, &rc); } From daf2761c62103f7bf126f8029dcf5fb473216f5f Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 10 Dec 2020 20:31:25 +0000 Subject: [PATCH 19/38] Use an iterator for the index loop in sqlite3GenerateConstraintChecks(). The idea is that this iterator can be enhanced to traverse the indexes in any order, as required by multi-index UPSERT. FossilOrigin-Name: 64a4a91ecc5dcde3fa07d3cf038c74b9ede63d36628ecfb35203a9dfbbfe113c --- manifest | 16 ++++----- manifest.uuid | 2 +- src/insert.c | 89 +++++++++++++++++++++++++++++++++++-------------- src/sqliteInt.h | 2 +- src/upsert.c | 2 +- 5 files changed, 75 insertions(+), 36 deletions(-) diff --git a/manifest b/manifest index abce3073d7..293f993ca7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C The\sDO\sUPDATE\scode\sgenerator\ssearches\sfor\sthe\scorrect\sON\sCONFLICT\sclause\sto\nuse. -D 2020-12-10T12:49:26.425 +C Use\san\siterator\sfor\sthe\sindex\sloop\sin\ssqlite3GenerateConstraintChecks().\nThe\sidea\sis\sthat\sthis\siterator\scan\sbe\senhanced\sto\straverse\sthe\sindexes\sin\nany\sorder,\sas\srequired\sby\smulti-index\sUPSERT. +D 2020-12-10T20:31:25.985 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -501,7 +501,7 @@ 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 df28564b7d79f146266e906549687c74e3a5e9c4d8ba8697ef9c479ad83407e0 +F src/insert.c ac236526a7f239d420291fae1bf7ea56c9e54f335598315a0ddf8ebb5a110120 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 8c9c8cd2bd8eecdb06d9b6e89de7e9e65bae45cc8fc33609cc74023a5c296067 F src/main.c 97e9f137354bc1f76dc9bb60a0a24f8c45cf73b33e80d3ee4c64155336fb820d @@ -545,7 +545,7 @@ F src/shell.c.in e9f674ee4ec6c345679e8a5b16c869c6c59eb1540dd98ac69e4736ecddce009 F src/sqlite.h.in 0e2b4259e49a0eda54d9118eb18a04fcd60e0727a2fd2c81aade0bf57520e706 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e -F src/sqliteInt.h 0e042bd76044617ae919a294778ceacdb00a405d60de1b94c8ee4d2b81829bdb +F src/sqliteInt.h 72c7bfc4831f171d25b7b03c9fb152f1a3bbf55f51d5bbcdef313ebfa5873bea F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -608,7 +608,7 @@ F src/tokenize.c 01dba3023659dc6f6b1e054c14b35a0074bd35de10466b99454d33278191d97 F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda F src/trigger.c 515e79206d40d1d4149129318582e79a6e9db590a7b74e226fdb5b2a6c7e1b10 F src/update.c 9f126204a6acb96bbe47391ae48e0fc579105d8e76a6d9c4fab3271367476580 -F src/upsert.c 49170532578f2f30984b35e2c1e2f308b089c6814edf384d32158a53b25fc930 +F src/upsert.c 4b960968084a1d2a301ddbc782f625dbb1c02e0e8d0b0d6ad4a1986ecf305729 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/util.c c0c7977de7ef9b8cb10f6c85f2d0557889a658f817b0455909a49179ba4c8002 F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286 @@ -1888,7 +1888,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 3194c00c2c6a32bdfd5acc9fda5b38ae131d20cd3b7aea8512a41b2e76808f6a -R 8dc7164868d12444f67e9c3abe760e73 +P a47e35ee2d901baaa37e7229d190f934e1b0bd3510147cd4a2a49c4a1411416a +R 57e2c4174298e4f52a8ae7fd60045bd5 U drh -Z 978ca06206ec1f9d5cc426705017394f +Z 27b1defd588019eb0041967767579913 diff --git a/manifest.uuid b/manifest.uuid index 88e882cea1..1fd8f4a00d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a47e35ee2d901baaa37e7229d190f934e1b0bd3510147cd4a2a49c4a1411416a \ No newline at end of file +64a4a91ecc5dcde3fa07d3cf038c74b9ede63d36628ecfb35203a9dfbbfe113c \ No newline at end of file diff --git a/src/insert.c b/src/insert.c index f10587f9f2..44cd8a3390 100644 --- a/src/insert.c +++ b/src/insert.c @@ -976,9 +976,6 @@ void sqlite3Insert( #ifndef SQLITE_OMIT_UPSERT if( pUpsert ){ Upsert *pNx; - int nIdx; - Index *pIdxList; - int *aReg; if( IsVirtual(pTab) ){ sqlite3ErrorMsg(pParse, "UPSERT not implemented for virtual table \"%s\"", pTab->zName); @@ -1003,26 +1000,6 @@ void sqlite3Insert( } pNx = pNx->pNextUpsert; }while( pNx!=0 ); - for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ - assert( pIdx ); - assert( aRegIdx[nIdx]>0 ); - } - if( nIdx==0 ){ - pUpsert->pIdxList = 0; - }else{ - u64 nByte = sizeof(Index)*nIdx + sizeof(int)*(nIdx+2); - pIdxList = sqlite3DbMallocRaw(db, nByte); - if( pIdxList==0 ) goto insert_cleanup; - aReg = (int*)&pIdxList[nIdx]; - for(i=0, pIdx=pTab->pIndex; ipNext, i++){ - memcpy(&pIdxList[i], pIdx, sizeof(Index)); - pIdxList[i].pNext = 0; - if( i ) pIdxList[i-1].pNext = &pIdxList[i]; - aReg[i] = aRegIdx[i]; - } - aReg[i] = aRegIdx[i]; - pUpsert->pIdxList = pIdxList; - } } #endif @@ -1427,6 +1404,62 @@ 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){ + int i = pIter->i; + *pIx = i; + return pIter->eType ? pIter->u.ax.aIdx[i].p : pIter->u.lx.pIdx; +} + +/* Return the next index from the list. Return NULL when out of indexes */ +static Index *indexIteratorNext(IndexIterator *pIter, int *pIx){ + int i = ++pIter->i; + if( pIter->eType ){ + if( i>=pIter->u.ax.nIdx ) return 0; + *pIx = pIter->u.ax.aIdx[i].ix; + return pIter->u.ax.aIdx[i].p; + }else{ + *pIx = i; + 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. @@ -1557,6 +1590,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 ixi; /* Index iterator */ isUpdate = regOldData!=0; db = pParse->db; @@ -1769,6 +1803,9 @@ void sqlite3GenerateConstraintChecks( VdbeComment((v, "UPSERT constraint goes first")); } } + ixi.eType = 0; + ixi.i = 0; + ixi.u.lx.pIdx = pTab->pIndex; /* Determine if it is possible that triggers (either explicitly coded ** triggers or FK resolution actions) might run as a result of deletes @@ -1953,8 +1990,10 @@ void sqlite3GenerateConstraintChecks( ** This loop also handles the case of the PRIMARY KEY index for a ** WITHOUT ROWID table. */ - pIdx = pUpsert ? pUpsert->pIdxList : pTab->pIndex; - for(ix=0; pIdx; pIdx=pIdx->pNext, ix++){ + for(pIdx = indexIteratorFirst(&ixi, &ix); + pIdx; + pIdx = indexIteratorNext(&ixi, &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 */ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 23df9cc710..83993f08c5 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3080,7 +3080,7 @@ struct Upsert { Upsert *pNextUpsert; /* Next ON CONFLICT clause in the list */ /* Above this point is the parse tree for the ON CONFLICT clauses. ** The next group of fields stores intermediate data. */ - Index *pIdxList; + 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 diff --git a/src/upsert.c b/src/upsert.c index 63b9144419..6b9bff6851 100644 --- a/src/upsert.c +++ b/src/upsert.c @@ -25,7 +25,7 @@ static void SQLITE_NOINLINE upsertDelete(sqlite3 *db, Upsert *p){ sqlite3ExprDelete(db, p->pUpsertTargetWhere); sqlite3ExprListDelete(db, p->pUpsertSet); sqlite3ExprDelete(db, p->pUpsertWhere); - sqlite3DbFree(db, p->pIdxList); + sqlite3DbFree(db, p->pToFree); sqlite3DbFree(db, p); p = pNext; }while( p ); From 61e280ad8a3ce9d14c65948265cd8732825e18dd Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 11 Dec 2020 01:17:06 +0000 Subject: [PATCH 20/38] Logic is in place to handle multiple ON CONFLICT clauses, but it does not work. Any use of ON CONFLICT will likely lead to memory faults. This is an incremental check-in to save my place. FossilOrigin-Name: 155142314feb007d526f8f67723636fd50dc52d1cd4d3a67dd93b105c9d5c2be --- manifest | 16 +++--- manifest.uuid | 2 +- src/insert.c | 140 +++++++++++++++++++++++++++++++++--------------- src/sqliteInt.h | 4 ++ src/upsert.c | 41 +++++++++++--- 5 files changed, 142 insertions(+), 61 deletions(-) diff --git a/manifest b/manifest index 293f993ca7..5bb77216d5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Use\san\siterator\sfor\sthe\sindex\sloop\sin\ssqlite3GenerateConstraintChecks().\nThe\sidea\sis\sthat\sthis\siterator\scan\sbe\senhanced\sto\straverse\sthe\sindexes\sin\nany\sorder,\sas\srequired\sby\smulti-index\sUPSERT. -D 2020-12-10T20:31:25.985 +C Logic\sis\sin\splace\sto\shandle\smultiple\sON\sCONFLICT\sclauses,\sbut\sit\sdoes\snot\swork.\nAny\suse\sof\sON\sCONFLICT\swill\slikely\slead\sto\smemory\sfaults.\s\sThis\sis\san\nincremental\scheck-in\sto\ssave\smy\splace. +D 2020-12-11T01:17:06.489 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -501,7 +501,7 @@ 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 ac236526a7f239d420291fae1bf7ea56c9e54f335598315a0ddf8ebb5a110120 +F src/insert.c c8d4bc0dcde4d9d42a1761e919a6a99668000e16840814f8bb643e161894b27f F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 8c9c8cd2bd8eecdb06d9b6e89de7e9e65bae45cc8fc33609cc74023a5c296067 F src/main.c 97e9f137354bc1f76dc9bb60a0a24f8c45cf73b33e80d3ee4c64155336fb820d @@ -545,7 +545,7 @@ F src/shell.c.in e9f674ee4ec6c345679e8a5b16c869c6c59eb1540dd98ac69e4736ecddce009 F src/sqlite.h.in 0e2b4259e49a0eda54d9118eb18a04fcd60e0727a2fd2c81aade0bf57520e706 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e -F src/sqliteInt.h 72c7bfc4831f171d25b7b03c9fb152f1a3bbf55f51d5bbcdef313ebfa5873bea +F src/sqliteInt.h aff99a1938b53530971fcfa7a6a5e6b47f986ddd673660bafb41f1c559747b72 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -608,7 +608,7 @@ F src/tokenize.c 01dba3023659dc6f6b1e054c14b35a0074bd35de10466b99454d33278191d97 F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda F src/trigger.c 515e79206d40d1d4149129318582e79a6e9db590a7b74e226fdb5b2a6c7e1b10 F src/update.c 9f126204a6acb96bbe47391ae48e0fc579105d8e76a6d9c4fab3271367476580 -F src/upsert.c 4b960968084a1d2a301ddbc782f625dbb1c02e0e8d0b0d6ad4a1986ecf305729 +F src/upsert.c 6471d9e0e5e05547f8a00d7d686714ac08fe89526de133abcf8e1c7a35f2cb82 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/util.c c0c7977de7ef9b8cb10f6c85f2d0557889a658f817b0455909a49179ba4c8002 F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286 @@ -1888,7 +1888,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 a47e35ee2d901baaa37e7229d190f934e1b0bd3510147cd4a2a49c4a1411416a -R 57e2c4174298e4f52a8ae7fd60045bd5 +P 64a4a91ecc5dcde3fa07d3cf038c74b9ede63d36628ecfb35203a9dfbbfe113c +R 750cd21a590114aba81487b95892f11b U drh -Z 27b1defd588019eb0041967767579913 +Z dd643da8c0e77547922105a9f9bf1ab2 diff --git a/manifest.uuid b/manifest.uuid index 1fd8f4a00d..7a1e0b0cb8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -64a4a91ecc5dcde3fa07d3cf038c74b9ede63d36628ecfb35203a9dfbbfe113c \ No newline at end of file +155142314feb007d526f8f67723636fd50dc52d1cd4d3a67dd93b105c9d5c2be \ No newline at end of file diff --git a/src/insert.c b/src/insert.c index 44cd8a3390..5e59221278 100644 --- a/src/insert.c +++ b/src/insert.c @@ -1450,7 +1450,10 @@ static Index *indexIteratorFirst(IndexIterator *pIter, int *pIx){ static Index *indexIteratorNext(IndexIterator *pIter, int *pIx){ int i = ++pIter->i; if( pIter->eType ){ - if( i>=pIter->u.ax.nIdx ) return 0; + 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{ @@ -1576,11 +1579,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 @@ -1590,7 +1593,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 ixi; /* Index iterator */ + IndexIterator sIdxIter; /* Index iterator */ isUpdate = regOldData!=0; db = pParse->db; @@ -1788,24 +1791,64 @@ 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.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->pUpsertSet==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 ); } } - ixi.eType = 0; - ixi.i = 0; - ixi.u.lx.pIdx = pTab->pIndex; /* Determine if it is possible that triggers (either explicitly coded ** triggers or FK resolution actions) might run as a result of deletes @@ -1866,11 +1909,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->pUpsertSet==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); } } @@ -1977,7 +2029,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); } @@ -1990,9 +2044,9 @@ void sqlite3GenerateConstraintChecks( ** This loop also handles the case of the PRIMARY KEY index for a ** WITHOUT ROWID table. */ - for(pIdx = indexIteratorFirst(&ixi, &ix); + for(pIdx = indexIteratorFirst(&sIdxIter, &ix); pIdx; - pIdx = indexIteratorNext(&ixi, &ix) + pIdx = indexIteratorNext(&sIdxIter, &ix) ){ int regIdx; /* Range of registers hold conent for pIdx */ int regR; /* Range of registers holding conflicting PK */ @@ -2001,15 +2055,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 && pUpIdx->zName==pIdx->zName ){ - 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->zName==pIdx->zName) ){ + addrUniqueOk = sqlite3VdbeMakeLabel(pParse); + if( bAffinityDone==0 ){ sqlite3TableAffinity(v, pTab, regNewData+1); bAffinityDone = 1; } @@ -2080,8 +2133,8 @@ void sqlite3GenerateConstraintChecks( } /* Figure out if the upsert clause applies to this index */ - if( pUpIdx && pUpIdx->zName==pIdx->zName ){ - if( pUpsert->pUpsertSet==0 ){ + if( pUpsertClause ){ + if( pUpsertClause->pUpsertSet==0 ){ onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */ }else{ onError = OE_Update; /* DO UPDATE */ @@ -2273,13 +2326,12 @@ void sqlite3GenerateConstraintChecks( break; } } - if( pUpIdx && pUpIdx->zName==pIdx->zName ){ - sqlite3VdbeGoto(v, upsertJump+1); - sqlite3VdbeJumpHere(v, upsertBypass); - }else{ - sqlite3VdbeResolveLabel(v, addrUniqueOk); - } + sqlite3VdbeResolveLabel(v, addrUniqueOk); if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField); + if( pUpsertClause && sqlite3UpsertNextIsIPK(pUpsertClause) ){ + sqlite3VdbeGoto(v, upsertIpkDelay+1); + sqlite3VdbeJumpHere(v, upsertIpkReturn); + } } /* If the IPK constraint is a REPLACE, run it last */ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 83993f08c5..403f31326d 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -4841,10 +4841,14 @@ const char *sqlite3JournalModename(int); 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(u,v,w,x,y,z) ((Upsert*)0) #define sqlite3UpsertDelete(x,y) #define sqlite3UpsertDup(x,y) ((Upsert*)0) +#define sqlite3UpsertOfIndex(x,y) ((Upsert*)0) +#define sqlite3UpsertNextIsIPK(x) 0 #endif diff --git a/src/upsert.c b/src/upsert.c index 6b9bff6851..0a9b67dbdb 100644 --- a/src/upsert.c +++ b/src/upsert.c @@ -208,6 +208,38 @@ int sqlite3UpsertAnalyzeTarget( 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( 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; +} + /* ** Generate bytecode that does an UPDATE as part of an upsert. ** @@ -234,14 +266,7 @@ void sqlite3UpsertDoUpdate( assert( v!=0 ); assert( pUpsert!=0 ); iDataCur = pUpsert->iDataCur; - while( - pUpsert->pUpsertTarget!=0 - && (pUpsert->pUpsertIdx==0 ? pIdx!=0 : - pUpsert->pUpsertIdx->zName!=pIdx->zName) - ){ - assert( pUpsert->pNextUpsert!=0 ); - pUpsert = pUpsert->pNextUpsert; - } + pUpsert = sqlite3UpsertOfIndex(pTop, pIdx); if( pUpsert->addrGenericUpdate>0 ){ sqlite3VdbeAddOp2(v, OP_Goto, 0, pUpsert->addrGenericUpdate); return; From 69871baa1589e6dc486fbbf82a6e90b1d98419dd Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 11 Dec 2020 14:22:44 +0000 Subject: [PATCH 21/38] Fix the expert extension so that it handles generated columns correctly. FossilOrigin-Name: c2ae7ba6f8f4b10bd734051a0cfa8ed9675bd58c82ede4e9eadfd7cbcc03b82d --- ext/expert/expert1.test | 26 +++++++++++++++++++++++++- ext/expert/sqlite3expert.c | 2 +- manifest | 14 +++++++------- manifest.uuid | 2 +- 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/ext/expert/expert1.test b/ext/expert/expert1.test index f49f1f5e5c..0e6fc82604 100644 --- a/ext/expert/expert1.test +++ b/ext/expert/expert1.test @@ -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 + diff --git a/ext/expert/sqlite3expert.c b/ext/expert/sqlite3expert.c index 5c13423204..863c6a3409 100644 --- a/ext/expert/sqlite3expert.c +++ b/ext/expert/sqlite3expert.c @@ -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); diff --git a/manifest b/manifest index a3131d8cd4..ff78950e97 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\sa\sredundant\sbranch\sadded\sby\s[56a54258560]. -D 2020-12-10T19:54:13.413 +C Fix\sthe\sexpert\sextension\sso\sthat\sit\shandles\sgenerated\scolumns\scorrectly. +D 2020-12-11T14:22:44.596 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -50,8 +50,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 @@ -1889,7 +1889,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 56a54258560fab715b83967634b2bd4c04be43cded112b46e85da9f99ee02f7c -R c82b011ba062cfde3acc0789a727fd1f +P b4d6f6d728738710249ad74236c31a1872fdff7dadabd4c4a67d05826eb5df9e +R fb55f5147e16371ec8e31fd2331cfcf7 U dan -Z 9746b01cc9973ffd448104549b3bbdff +Z 166ee843647c304936c75f8093a2d2ca diff --git a/manifest.uuid b/manifest.uuid index 8a864002ee..3fc850b622 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b4d6f6d728738710249ad74236c31a1872fdff7dadabd4c4a67d05826eb5df9e \ No newline at end of file +c2ae7ba6f8f4b10bd734051a0cfa8ed9675bd58c82ede4e9eadfd7cbcc03b82d \ No newline at end of file From d0a0538229a2a263163d320ac7ba36f3e133452c Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 11 Dec 2020 14:34:58 +0000 Subject: [PATCH 22/38] Fix the configure script on the autoconf distribution so that the --disable-threadsafe option works. See [https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=244459|FreeBSD bug 244459]. FossilOrigin-Name: e64ff2cce3c03ba27c3bf410948ece1424113e727870015eb3806b75d0d21f94 --- autoconf/configure.ac | 4 +++- manifest | 14 +++++++------- manifest.uuid | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/autoconf/configure.ac b/autoconf/configure.ac index 167626d59e..a86bd2ca39 100644 --- a/autoconf/configure.ac +++ b/autoconf/configure.ac @@ -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) diff --git a/manifest b/manifest index ff78950e97..f303725351 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sthe\sexpert\sextension\sso\sthat\sit\shandles\sgenerated\scolumns\scorrectly. -D 2020-12-11T14:22:44.596 +C Fix\sthe\sconfigure\sscript\son\sthe\sautoconf\sdistribution\sso\sthat\sthe\n--disable-threadsafe\soption\sworks.\s\sSee\n[https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=244459|FreeBSD\sbug\s244459]. +D 2020-12-11T14:34:58.941 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -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 @@ -1889,7 +1889,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 b4d6f6d728738710249ad74236c31a1872fdff7dadabd4c4a67d05826eb5df9e -R fb55f5147e16371ec8e31fd2331cfcf7 -U dan -Z 166ee843647c304936c75f8093a2d2ca +P c2ae7ba6f8f4b10bd734051a0cfa8ed9675bd58c82ede4e9eadfd7cbcc03b82d +R 081acf382e9d875924b95569479a3f66 +U drh +Z 18dbb49cec21f6cfe4518d963fb09370 diff --git a/manifest.uuid b/manifest.uuid index 3fc850b622..84bb652ffb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c2ae7ba6f8f4b10bd734051a0cfa8ed9675bd58c82ede4e9eadfd7cbcc03b82d \ No newline at end of file +e64ff2cce3c03ba27c3bf410948ece1424113e727870015eb3806b75d0d21f94 \ No newline at end of file From 771087833330bbb5f4081f61e67fb22da608ff75 Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 11 Dec 2020 16:03:19 +0000 Subject: [PATCH 23/38] Add an "#ifndef SQLITE_AMALGAMATION" block around the typedef for u64 in shathree.c. FossilOrigin-Name: b411f29e1a6415f4a241777c45591b8389e746cd8b40d9b225e073bcb0a3bdbf --- ext/misc/shathree.c | 3 +++ manifest | 14 +++++++------- manifest.uuid | 2 +- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/ext/misc/shathree.c b/ext/misc/shathree.c index 56eba564ce..75065e97c1 100644 --- a/ext/misc/shathree.c +++ b/ext/misc/shathree.c @@ -31,7 +31,10 @@ SQLITE_EXTENSION_INIT1 #include #include #include + +#ifndef SQLITE_AMALGAMATION typedef sqlite3_uint64 u64; +#endif /* SQLITE_AMALGAMATION */ /****************************************************************************** ** The Hash Engine diff --git a/manifest b/manifest index f303725351..274f153437 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sthe\sconfigure\sscript\son\sthe\sautoconf\sdistribution\sso\sthat\sthe\n--disable-threadsafe\soption\sworks.\s\sSee\n[https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=244459|FreeBSD\sbug\s244459]. -D 2020-12-11T14:34:58.941 +C Add\san\s"#ifndef\sSQLITE_AMALGAMATION"\sblock\saround\sthe\stypedef\sfor\su64\sin\sshathree.c. +D 2020-12-11T16:03:19.055 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -321,7 +321,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 @@ -1889,7 +1889,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 c2ae7ba6f8f4b10bd734051a0cfa8ed9675bd58c82ede4e9eadfd7cbcc03b82d -R 081acf382e9d875924b95569479a3f66 -U drh -Z 18dbb49cec21f6cfe4518d963fb09370 +P e64ff2cce3c03ba27c3bf410948ece1424113e727870015eb3806b75d0d21f94 +R 718f3d689418739102dd17603d779863 +U dan +Z ab9d6df0eec0ce68bf9b160e6deb9056 diff --git a/manifest.uuid b/manifest.uuid index 84bb652ffb..b066f6a7f4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e64ff2cce3c03ba27c3bf410948ece1424113e727870015eb3806b75d0d21f94 \ No newline at end of file +b411f29e1a6415f4a241777c45591b8389e746cd8b40d9b225e073bcb0a3bdbf \ No newline at end of file From ed4c54699df2c2a0494e96dacaf21d279ca0adf2 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 11 Dec 2020 16:49:51 +0000 Subject: [PATCH 24/38] Bug fixes so that legacy tests pass. New tests for new functionality have not yet been added. FossilOrigin-Name: aa76790e58cea9a2b707f5912fd66c76545e7417442553fc13c87f773a2fe1dd --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/insert.c | 16 ++++++++++++---- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index 5bb77216d5..09d7eda057 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Logic\sis\sin\splace\sto\shandle\smultiple\sON\sCONFLICT\sclauses,\sbut\sit\sdoes\snot\swork.\nAny\suse\sof\sON\sCONFLICT\swill\slikely\slead\sto\smemory\sfaults.\s\sThis\sis\san\nincremental\scheck-in\sto\ssave\smy\splace. -D 2020-12-11T01:17:06.489 +C Bug\sfixes\sso\sthat\slegacy\stests\spass.\s\sNew\stests\sfor\snew\sfunctionality\shave\nnot\syet\sbeen\sadded. +D 2020-12-11T16:49:51.732 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -501,7 +501,7 @@ 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 c8d4bc0dcde4d9d42a1761e919a6a99668000e16840814f8bb643e161894b27f +F src/insert.c 3f90efe0afbbf4a64f7fe37cb061527a86445f0a1b85a78038ae406b41fbf806 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 8c9c8cd2bd8eecdb06d9b6e89de7e9e65bae45cc8fc33609cc74023a5c296067 F src/main.c 97e9f137354bc1f76dc9bb60a0a24f8c45cf73b33e80d3ee4c64155336fb820d @@ -1888,7 +1888,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 64a4a91ecc5dcde3fa07d3cf038c74b9ede63d36628ecfb35203a9dfbbfe113c -R 750cd21a590114aba81487b95892f11b +P 155142314feb007d526f8f67723636fd50dc52d1cd4d3a67dd93b105c9d5c2be +R 63e742ce65925663b08e2a758de8f6e2 U drh -Z dd643da8c0e77547922105a9f9bf1ab2 +Z 0aa452b6f5f81d99a0b8c06fa6b89e8a diff --git a/manifest.uuid b/manifest.uuid index 7a1e0b0cb8..13c5d7b5a1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -155142314feb007d526f8f67723636fd50dc52d1cd4d3a67dd93b105c9d5c2be \ No newline at end of file +aa76790e58cea9a2b707f5912fd66c76545e7417442553fc13c87f773a2fe1dd \ No newline at end of file diff --git a/src/insert.c b/src/insert.c index 5e59221278..41503224ec 100644 --- a/src/insert.c +++ b/src/insert.c @@ -1441,9 +1441,14 @@ struct IndexListTerm { /* Return the first index on the list */ static Index *indexIteratorFirst(IndexIterator *pIter, int *pIx){ - int i = pIter->i; - *pIx = i; - return pIter->eType ? pIter->u.ax.aIdx[i].p : pIter->u.lx.pIdx; + 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 */ @@ -2328,7 +2333,10 @@ void sqlite3GenerateConstraintChecks( } sqlite3VdbeResolveLabel(v, addrUniqueOk); if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField); - if( pUpsertClause && sqlite3UpsertNextIsIPK(pUpsertClause) ){ + if( pUpsertClause + && upsertIpkReturn + && sqlite3UpsertNextIsIPK(pUpsertClause) + ){ sqlite3VdbeGoto(v, upsertIpkDelay+1); sqlite3VdbeJumpHere(v, upsertIpkReturn); } From d3e21a1098ea6b5002417514ba2c984c4d1871ff Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 11 Dec 2020 17:11:56 +0000 Subject: [PATCH 25/38] Small performance tweaks. FossilOrigin-Name: 5321d60c575ef8f888d1b315df02cf9ed96a3ffc61babbc1429aa73b2a61a190 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/insert.c | 17 ++++++++--------- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/manifest b/manifest index 09d7eda057..953046263d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Bug\sfixes\sso\sthat\slegacy\stests\spass.\s\sNew\stests\sfor\snew\sfunctionality\shave\nnot\syet\sbeen\sadded. -D 2020-12-11T16:49:51.732 +C Small\sperformance\stweaks. +D 2020-12-11T17:11:56.302 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -501,7 +501,7 @@ 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 3f90efe0afbbf4a64f7fe37cb061527a86445f0a1b85a78038ae406b41fbf806 +F src/insert.c 2b9b6a9cae187bf6c1d4220726511459a23d6089dd4025c4cb00657195c81ba8 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 8c9c8cd2bd8eecdb06d9b6e89de7e9e65bae45cc8fc33609cc74023a5c296067 F src/main.c 97e9f137354bc1f76dc9bb60a0a24f8c45cf73b33e80d3ee4c64155336fb820d @@ -1888,7 +1888,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 155142314feb007d526f8f67723636fd50dc52d1cd4d3a67dd93b105c9d5c2be -R 63e742ce65925663b08e2a758de8f6e2 +P aa76790e58cea9a2b707f5912fd66c76545e7417442553fc13c87f773a2fe1dd +R facb33fc25631aa36550b455921f2f42 U drh -Z 0aa452b6f5f81d99a0b8c06fa6b89e8a +Z 1d9f47d8176ed5a99b3ef4efb5d1d2d4 diff --git a/manifest.uuid b/manifest.uuid index 13c5d7b5a1..529b505cd2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -aa76790e58cea9a2b707f5912fd66c76545e7417442553fc13c87f773a2fe1dd \ No newline at end of file +5321d60c575ef8f888d1b315df02cf9ed96a3ffc61babbc1429aa73b2a61a190 \ No newline at end of file diff --git a/src/insert.c b/src/insert.c index 41503224ec..8306c602bc 100644 --- a/src/insert.c +++ b/src/insert.c @@ -1453,8 +1453,8 @@ static Index *indexIteratorFirst(IndexIterator *pIter, int *pIx){ /* Return the next index from the list. Return NULL when out of indexes */ static Index *indexIteratorNext(IndexIterator *pIter, int *pIx){ - int i = ++pIter->i; if( pIter->eType ){ + int i = ++pIter->i; if( i>=pIter->u.ax.nIdx ){ *pIx = i; return 0; @@ -1462,7 +1462,7 @@ static Index *indexIteratorNext(IndexIterator *pIter, int *pIx){ *pIx = pIter->u.ax.aIdx[i].ix; return pIter->u.ax.aIdx[i].p; }else{ - *pIx = i; + ++(*pIx); pIter->u.lx.pIdx = pIter->u.lx.pIdx->pNext; return pIter->u.lx.pIdx; } @@ -1798,6 +1798,7 @@ void sqlite3GenerateConstraintChecks( */ 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 ){ @@ -2120,7 +2121,7 @@ void sqlite3GenerateConstraintChecks( ** of a WITHOUT ROWID table and there has been no change the ** primary key, then no collision is possible. The collision detection ** logic below can all be skipped. */ - if( isUpdate && pPk && pPk->zName==pIdx->zName && pkChng==0 ){ + if( isUpdate && pPk==pIdx && pkChng==0 ){ sqlite3VdbeResolveLabel(v, addrUniqueOk); continue; } @@ -2158,7 +2159,7 @@ void sqlite3GenerateConstraintChecks( ** is invoked. */ #ifndef SQLITE_ENABLE_PREUPDATE_HOOK if( (ix==0 && pIdx->pNext==0) /* Condition 3 */ - && pPk && pPk->zName==pIdx->zName /* Condition 2 */ + && pPk==pIdx /* Condition 2 */ && onError==OE_Replace /* Condition 1 */ && ( 0==(db->flags&SQLITE_RecTriggers) || /* Condition 4 */ 0==sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0)) @@ -2177,8 +2178,7 @@ void sqlite3GenerateConstraintChecks( regIdx, pIdx->nKeyCol); VdbeCoverage(v); /* Generate code to handle collisions */ - regR = (pPk && pIdx->zName==pPk->zName) ? - 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); @@ -2193,7 +2193,7 @@ void sqlite3GenerateConstraintChecks( int x; /* Extract the PRIMARY KEY from the end of the index entry and ** store it in registers regR..regR+nPk-1 */ - if( pPk && pIdx->zName!=pPk->zName ){ + if( pIdx!=pPk ){ for(i=0; inKeyCol; i++){ assert( pPk->aiColumn[i]>=0 ); x = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[i]); @@ -2274,8 +2274,7 @@ void sqlite3GenerateConstraintChecks( } sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur, regR, nPkField, 0, OE_Replace, - (pPk && pIdx->zName==pPk->zName ? ONEPASS_SINGLE : ONEPASS_OFF), - iThisCur); + (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), iThisCur); if( pTrigger && isUpdate ){ sqlite3VdbeAddOp1(v, OP_CursorUnlock, iDataCur); } From 855aed19e224ebb5328b9fbffbf69cb8161630e8 Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 11 Dec 2020 19:01:24 +0000 Subject: [PATCH 26/38] Fix an assert() broken by recent changes to vacuum. FossilOrigin-Name: dd058da85ca54ae70e26cb0bdc75ff42998d4a8b29a5e2dcac44ee0e45776a85 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/btree.c | 2 +- test/vacuum6.test | 11 +++++++++++ 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 274f153437..c5e7ec8dc9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\san\s"#ifndef\sSQLITE_AMALGAMATION"\sblock\saround\sthe\stypedef\sfor\su64\sin\sshathree.c. -D 2020-12-11T16:03:19.055 +C Fix\san\sassert()\sbroken\sby\srecent\schanges\sto\svacuum. +D 2020-12-11T19:01:24.454 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -481,7 +481,7 @@ F src/auth.c a3d5bfdba83d25abed1013a8c7a5f204e2e29b0c25242a56bc02bb0c07bf1e06 F src/backup.c 3014889fa06e20e6adfa0d07b60097eec1f6e5b06671625f476a714d2356513d F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 -F src/btree.c 91da5fd5d99bc7e7422242419561bd9518e0229c243c48799303be7112ef5601 +F src/btree.c ea5e8bfe904d4818d97cae4eee229d7ce21a0a090ef5402ebac68840dc16713f F src/btree.h 285f8377aa1353185a32bf455faafa9ff9a0d40d074d60509534d14990c7829e F src/btreeInt.h 7614cae30f95b6aed0c7cac7718276a55cfe2c77058cbfd8bef5b75329757331 F src/build.c f6449d4e85e998e14d3f537e8ea898dca2fcb83c277db3e60945af9b9177db81 @@ -1654,7 +1654,7 @@ F test/vacuum2.test 9fd45ce6ce29f5614c249e03938d3567c06a9e772d4f155949f8eafe2d8a F test/vacuum3.test 77ecdd54592b45a0bcb133339f99f1ae0ae94d0d F test/vacuum4.test 7ea76b769fffeb41f925303b04cbcf5a5bbeabe55e4c60ae754ff24eeeb7c010 F test/vacuum5.test 263b144d537e92ad8e9ca8a73cc6e1583f41cfd0dda9432b87f7806174a2f48c -F test/vacuum6.test e67488fa1341cc8034ba261807d429a8c06f4593ec1bb1651d8497d2d5df92c9 +F test/vacuum6.test d3173a54edc81d13d99e4cf4972232b3cbb52f1d56ed48c3a939ef4e751c1ee8 F test/vacuummem.test 7b42abb3208bd82dd23a7536588396f295a314f2 F test/varint.test bbce22cda8fc4d135bcc2b589574be8410614e62 F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661 @@ -1889,7 +1889,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 e64ff2cce3c03ba27c3bf410948ece1424113e727870015eb3806b75d0d21f94 -R 718f3d689418739102dd17603d779863 +P b411f29e1a6415f4a241777c45591b8389e746cd8b40d9b225e073bcb0a3bdbf +R 5f1281ebbbf31df2eed9d78849a16b43 U dan -Z ab9d6df0eec0ce68bf9b160e6deb9056 +Z 63f7dff9f8374ff08b8e0cc7e378c500 diff --git a/manifest.uuid b/manifest.uuid index b066f6a7f4..e819bc2a41 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b411f29e1a6415f4a241777c45591b8389e746cd8b40d9b225e073bcb0a3bdbf \ No newline at end of file +dd058da85ca54ae70e26cb0bdc75ff42998d4a8b29a5e2dcac44ee0e45776a85 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 3ed365c5f7..1a151fe4ef 100644 --- a/src/btree.c +++ b/src/btree.c @@ -8697,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) || (flags & BTREE_PREFORMAT) ); + assert( (flags & BTREE_PREFORMAT) || (pX->pKey==0)==(pCur->pKeyInfo==0) ); /* Save the positions of any other cursors open on this table. ** diff --git a/test/vacuum6.test b/test/vacuum6.test index 51070fd0c7..e9a1542f25 100644 --- a/test/vacuum6.test +++ b/test/vacuum6.test @@ -29,10 +29,21 @@ 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 From 58b18a47df0ec28487bf7be3bf517b7f0f801686 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 11 Dec 2020 19:36:19 +0000 Subject: [PATCH 27/38] Begin adding test cases. Fix one bug found so far. More are pending. FossilOrigin-Name: aadd67ddf2a191629b5356395f75e4556aac904a6e2f6b83742fa4f26e4253a4 --- manifest | 13 +-- manifest.uuid | 2 +- src/insert.c | 1 + test/upsert5.test | 242 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 251 insertions(+), 7 deletions(-) create mode 100644 test/upsert5.test diff --git a/manifest b/manifest index 953046263d..728e086000 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Small\sperformance\stweaks. -D 2020-12-11T17:11:56.302 +C Begin\sadding\stest\scases.\s\sFix\sone\sbug\sfound\sso\sfar.\s\sMore\sare\spending. +D 2020-12-11T19:36:19.206 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -501,7 +501,7 @@ 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 2b9b6a9cae187bf6c1d4220726511459a23d6089dd4025c4cb00657195c81ba8 +F src/insert.c 7bb29b8acdd49917fe12cc14e164b9c49fc98f5f2725e5311a03b30349ca3880 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 8c9c8cd2bd8eecdb06d9b6e89de7e9e65bae45cc8fc33609cc74023a5c296067 F src/main.c 97e9f137354bc1f76dc9bb60a0a24f8c45cf73b33e80d3ee4c64155336fb820d @@ -1643,6 +1643,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 82acbe52e9a7d74b9eeb93dc219558f44dccd07ef5e07e74fec9eca7173e4bfe F test/upsertfault.test f21ca47740841fdb4d61acfa7b17646d773e67724fe8c185b71c018db8a94b35 F test/uri.test 3481026f00ade6dfe8adb7acb6e1e47b04369568 F test/uri2.test 9d3ba7a53ee167572d53a298ee4a5d38ec4a8fb7 @@ -1888,7 +1889,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 aa76790e58cea9a2b707f5912fd66c76545e7417442553fc13c87f773a2fe1dd -R facb33fc25631aa36550b455921f2f42 +P 5321d60c575ef8f888d1b315df02cf9ed96a3ffc61babbc1429aa73b2a61a190 +R 8ec7743a66623a70c1f2fd83cc9cbf09 U drh -Z 1d9f47d8176ed5a99b3ef4efb5d1d2d4 +Z d9c45c2e1447fdcad46c943d9137f6df diff --git a/manifest.uuid b/manifest.uuid index 529b505cd2..87fe70a5b0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5321d60c575ef8f888d1b315df02cf9ed96a3ffc61babbc1429aa73b2a61a190 \ No newline at end of file +aadd67ddf2a191629b5356395f75e4556aac904a6e2f6b83742fa4f26e4253a4 \ No newline at end of file diff --git a/src/insert.c b/src/insert.c index 8306c602bc..4fa337a2f2 100644 --- a/src/insert.c +++ b/src/insert.c @@ -2338,6 +2338,7 @@ void sqlite3GenerateConstraintChecks( ){ sqlite3VdbeGoto(v, upsertIpkDelay+1); sqlite3VdbeJumpHere(v, upsertIpkReturn); + upsertIpkReturn = 0; } } diff --git a/test/upsert5.test b/test/upsert5.test new file mode 100644 index 0000000000..e3840a9b32 --- /dev/null +++ b/test/upsert5.test @@ -0,0 +1,242 @@ +# 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} + +if {0} { + 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} +} + +} + +finish_test From 255c1c159b1082c712995436862e4dd4cfa20761 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 12 Dec 2020 00:28:15 +0000 Subject: [PATCH 28/38] New test cases with corresponding bug fixes. FossilOrigin-Name: f22c21a94ca4cad0217f91c1a5a275bc348cb6ba0f3a54c927533bc8d8c96a90 --- manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/insert.c | 6 +++--- src/sqliteInt.h | 2 +- src/upsert.c | 14 +++----------- test/upsert5.test | 38 ++++++++++++++++++++++++++++++++++++-- 6 files changed, 53 insertions(+), 27 deletions(-) diff --git a/manifest b/manifest index 728e086000..43fe5d0f2c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Begin\sadding\stest\scases.\s\sFix\sone\sbug\sfound\sso\sfar.\s\sMore\sare\spending. -D 2020-12-11T19:36:19.206 +C New\stest\scases\swith\scorresponding\sbug\sfixes. +D 2020-12-12T00:28:15.628 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -501,7 +501,7 @@ 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 7bb29b8acdd49917fe12cc14e164b9c49fc98f5f2725e5311a03b30349ca3880 +F src/insert.c ec68f3a8b9af7c6e127735af8f61633bc0a2c9cd24a961fb21331ac95c7df251 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 8c9c8cd2bd8eecdb06d9b6e89de7e9e65bae45cc8fc33609cc74023a5c296067 F src/main.c 97e9f137354bc1f76dc9bb60a0a24f8c45cf73b33e80d3ee4c64155336fb820d @@ -545,7 +545,7 @@ F src/shell.c.in e9f674ee4ec6c345679e8a5b16c869c6c59eb1540dd98ac69e4736ecddce009 F src/sqlite.h.in 0e2b4259e49a0eda54d9118eb18a04fcd60e0727a2fd2c81aade0bf57520e706 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e -F src/sqliteInt.h aff99a1938b53530971fcfa7a6a5e6b47f986ddd673660bafb41f1c559747b72 +F src/sqliteInt.h 31492bf5f9d7ccc4835d5e0a88758737812b0ee4c35c0b961840373dbd18bbb0 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -608,7 +608,7 @@ F src/tokenize.c 01dba3023659dc6f6b1e054c14b35a0074bd35de10466b99454d33278191d97 F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda F src/trigger.c 515e79206d40d1d4149129318582e79a6e9db590a7b74e226fdb5b2a6c7e1b10 F src/update.c 9f126204a6acb96bbe47391ae48e0fc579105d8e76a6d9c4fab3271367476580 -F src/upsert.c 6471d9e0e5e05547f8a00d7d686714ac08fe89526de133abcf8e1c7a35f2cb82 +F src/upsert.c 5ebb702817ee157badae0548098ea216cc1636e98eda63554e346968565c64c4 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/util.c c0c7977de7ef9b8cb10f6c85f2d0557889a658f817b0455909a49179ba4c8002 F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286 @@ -1643,7 +1643,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 82acbe52e9a7d74b9eeb93dc219558f44dccd07ef5e07e74fec9eca7173e4bfe +F test/upsert5.test 32ff55ed7e3dcfe62a8e54897c20e074d4629ddf72297092e79997f82ccf06b5 F test/upsertfault.test f21ca47740841fdb4d61acfa7b17646d773e67724fe8c185b71c018db8a94b35 F test/uri.test 3481026f00ade6dfe8adb7acb6e1e47b04369568 F test/uri2.test 9d3ba7a53ee167572d53a298ee4a5d38ec4a8fb7 @@ -1889,7 +1889,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 5321d60c575ef8f888d1b315df02cf9ed96a3ffc61babbc1429aa73b2a61a190 -R 8ec7743a66623a70c1f2fd83cc9cbf09 +P aadd67ddf2a191629b5356395f75e4556aac904a6e2f6b83742fa4f26e4253a4 +R ebc93beb1a5a9905106ef56cc676e95d U drh -Z d9c45c2e1447fdcad46c943d9137f6df +Z 4e2db7f4f46c9338f10a1365883b3835 diff --git a/manifest.uuid b/manifest.uuid index 87fe70a5b0..73f4c884b4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -aadd67ddf2a191629b5356395f75e4556aac904a6e2f6b83742fa4f26e4253a4 \ No newline at end of file +f22c21a94ca4cad0217f91c1a5a275bc348cb6ba0f3a54c927533bc8d8c96a90 \ No newline at end of file diff --git a/src/insert.c b/src/insert.c index 4fa337a2f2..d0f82dccfe 100644 --- a/src/insert.c +++ b/src/insert.c @@ -1804,7 +1804,7 @@ void sqlite3GenerateConstraintChecks( if( pUpsert->pUpsertTarget==0 ){ /* There is just on ON CONFLICT clause and it has no constraint-target */ assert( pUpsert->pNextUpsert==0 ); - if( pUpsert->pUpsertSet==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; @@ -1918,7 +1918,7 @@ void sqlite3GenerateConstraintChecks( if( pUpsert ){ pUpsertClause = sqlite3UpsertOfIndex(pUpsert,0); if( pUpsertClause!=0 ){ - if( pUpsertClause->pUpsertSet==0 ){ + if( pUpsertClause->isDoUpdate==0 ){ onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */ }else{ onError = OE_Update; /* DO UPDATE */ @@ -2140,7 +2140,7 @@ void sqlite3GenerateConstraintChecks( /* Figure out if the upsert clause applies to this index */ if( pUpsertClause ){ - if( pUpsertClause->pUpsertSet==0 ){ + if( pUpsertClause->isDoUpdate==0 ){ onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */ }else{ onError = OE_Update; /* DO UPDATE */ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 403f31326d..3c88c07806 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3078,6 +3078,7 @@ struct Upsert { ExprList *pUpsertSet; /* The SET clause from an ON CONFLICT UPDATE */ Expr *pUpsertWhere; /* WHERE clause for the ON CONFLICT UPDATE */ 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 */ @@ -3091,7 +3092,6 @@ struct Upsert { int regData; /* First register holding array of VALUES */ int iDataCur; /* Index of the data cursor */ int iIdxCur; /* Index of the first index cursor */ - int addrGenericUpdate; /* Address of routine for generic DO UPDATE */ }; /* diff --git a/src/upsert.c b/src/upsert.c index 0a9b67dbdb..cb173aa53f 100644 --- a/src/upsert.c +++ b/src/upsert.c @@ -74,6 +74,7 @@ Upsert *sqlite3UpsertNew( pNew->pUpsertTargetWhere = pTargetWhere; pNew->pUpsertSet = pSet; pNew->pUpsertWhere = pWhere; + pNew->isDoUpdate = pSet!=0; pNew->pNextUpsert = pNext; } return pNew; @@ -267,14 +268,7 @@ void sqlite3UpsertDoUpdate( assert( pUpsert!=0 ); iDataCur = pUpsert->iDataCur; pUpsert = sqlite3UpsertOfIndex(pTop, pIdx); - if( pUpsert->addrGenericUpdate>0 ){ - sqlite3VdbeAddOp2(v, OP_Goto, 0, pUpsert->addrGenericUpdate); - return; - } VdbeNoopComment((v, "Begin DO UPDATE of UPSERT")); - if( pUpsert->pUpsertTarget==0 ){ - pUpsert->addrGenericUpdate = sqlite3VdbeCurrentAddr(v); - } if( pIdx && iCur!=iDataCur ){ if( HasRowid(pTab) ){ int regRowid = sqlite3GetTempReg(pParse); @@ -313,10 +307,8 @@ void sqlite3UpsertDoUpdate( 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")); } diff --git a/test/upsert5.test b/test/upsert5.test index e3840a9b32..fe748f5f00 100644 --- a/test/upsert5.test +++ b/test/upsert5.test @@ -216,7 +216,6 @@ foreach {tn sql} { SELECT a,b,c,d,e FROM t1; } {1 e 3 4 5} -if {0} { do_execsql_test 1.$tn.400 { DELETE FROM t1; INSERT INTO t1(a,b,c,d,e) VALUES(1,2,3,4,5); @@ -235,7 +234,42 @@ if {0} { 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} } From 250af6e0fb8c9fab2aab73651e39b5832eccd331 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 12 Dec 2020 00:43:52 +0000 Subject: [PATCH 29/38] More test cases. No new problems discovered. FossilOrigin-Name: f34dd67e2d0dfc9e3b5d49148fb0162853119c097cbc3fe961878875ba98d8e3 --- manifest | 12 ++--- manifest.uuid | 2 +- test/upsert5.test | 121 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 43fe5d0f2c..3410b246b8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C New\stest\scases\swith\scorresponding\sbug\sfixes. -D 2020-12-12T00:28:15.628 +C More\stest\scases.\s\sNo\snew\sproblems\sdiscovered. +D 2020-12-12T00:43:52.775 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -1643,7 +1643,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 32ff55ed7e3dcfe62a8e54897c20e074d4629ddf72297092e79997f82ccf06b5 +F test/upsert5.test f49faf5f15b5c3641c6f5d7c7cc531ef5ac997567b2b6bb7bc96f7c88753ca0b F test/upsertfault.test f21ca47740841fdb4d61acfa7b17646d773e67724fe8c185b71c018db8a94b35 F test/uri.test 3481026f00ade6dfe8adb7acb6e1e47b04369568 F test/uri2.test 9d3ba7a53ee167572d53a298ee4a5d38ec4a8fb7 @@ -1889,7 +1889,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 aadd67ddf2a191629b5356395f75e4556aac904a6e2f6b83742fa4f26e4253a4 -R ebc93beb1a5a9905106ef56cc676e95d +P f22c21a94ca4cad0217f91c1a5a275bc348cb6ba0f3a54c927533bc8d8c96a90 +R 5a5b9a84e82bccc93a94b5f0a9cd7326 U drh -Z 4e2db7f4f46c9338f10a1365883b3835 +Z 16b3f3b436b8a24d4c2a8d5d463d0b17 diff --git a/manifest.uuid b/manifest.uuid index 73f4c884b4..bf1f11ba9a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f22c21a94ca4cad0217f91c1a5a275bc348cb6ba0f3a54c927533bc8d8c96a90 \ No newline at end of file +f34dd67e2d0dfc9e3b5d49148fb0162853119c097cbc3fe961878875ba98d8e3 \ No newline at end of file diff --git a/test/upsert5.test b/test/upsert5.test index fe748f5f00..c4747ddf18 100644 --- a/test/upsert5.test +++ b/test/upsert5.test @@ -271,6 +271,127 @@ foreach {tn sql} { 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 From 1c19848386babe4056e0e825433fcbe4b4ef1a5d Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 14 Dec 2020 13:52:03 +0000 Subject: [PATCH 30/38] Minor changes for test coverage. FossilOrigin-Name: e5a8fa50f4e5e5c24664452eda4af80904f75e5123b8f84353347dbd505d416d --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/parse.y | 7 ++++++- src/upsert.c | 2 +- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 3410b246b8..d18f0d5c73 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C More\stest\scases.\s\sNo\snew\sproblems\sdiscovered. -D 2020-12-12T00:43:52.775 +C Minor\schanges\sfor\stest\scoverage. +D 2020-12-14T13:52:03.476 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -529,7 +529,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 72b884c73f2b446e7dc4c7169ec7fbb82e0e292eec733fcf554f0fde46f269f6 +F src/parse.y 6c8aa09a7fa6e0867c3a3d67ef61b911aa392c9b084a61dc632cd93732aef8ad F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177 F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 F src/pcache1.c 6596e10baf3d8f84cc1585d226cf1ab26564a5f5caf85a15757a281ff977d51a @@ -608,7 +608,7 @@ F src/tokenize.c 01dba3023659dc6f6b1e054c14b35a0074bd35de10466b99454d33278191d97 F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda F src/trigger.c 515e79206d40d1d4149129318582e79a6e9db590a7b74e226fdb5b2a6c7e1b10 F src/update.c 9f126204a6acb96bbe47391ae48e0fc579105d8e76a6d9c4fab3271367476580 -F src/upsert.c 5ebb702817ee157badae0548098ea216cc1636e98eda63554e346968565c64c4 +F src/upsert.c df8f1727d62b5987c4fd302cd4d7c0c84ae57cd65683c5a34a740dfe24039235 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/util.c c0c7977de7ef9b8cb10f6c85f2d0557889a658f817b0455909a49179ba4c8002 F src/vacuum.c 492422c1463c076473bae1858799c7a0a5fe87a133d1223239447c422cd26286 @@ -1889,7 +1889,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 f22c21a94ca4cad0217f91c1a5a275bc348cb6ba0f3a54c927533bc8d8c96a90 -R 5a5b9a84e82bccc93a94b5f0a9cd7326 +P f34dd67e2d0dfc9e3b5d49148fb0162853119c097cbc3fe961878875ba98d8e3 +R e4ba77cafc1a5ebe11440b61ff8c6ede U drh -Z 16b3f3b436b8a24d4c2a8d5d463d0b17 +Z 22668862baa080d495b808bc49582152 diff --git a/manifest.uuid b/manifest.uuid index bf1f11ba9a..22965be8e2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f34dd67e2d0dfc9e3b5d49148fb0162853119c097cbc3fe961878875ba98d8e3 \ No newline at end of file +e5a8fa50f4e5e5c24664452eda4af80904f75e5123b8f84353347dbd505d416d \ No newline at end of file diff --git a/src/parse.y b/src/parse.y index f28bb47414..faec4b5cf5 100644 --- a/src/parse.y +++ b/src/parse.y @@ -952,7 +952,12 @@ cmd ::= with insert_cmd(R) INTO xfullname(X) idlist_opt(F) DEFAULT VALUES. } %type upsert {Upsert*} -%destructor upsert {sqlite3UpsertDelete(pParse->db,$$);} + +// Because upsert only occurs at the tip end of the INSERT rule for cmd, +// there is never a case where the value of the upsert pointer will not +// be destroyed by the cmd action. So comment-out the destructor to +// avoid unreachable code. +//%destructor upsert {sqlite3UpsertDelete(pParse->db,$$);} upsert(A) ::= . { A = 0; } upsert(A) ::= ON CONFLICT LP sortlist(T) RP where_opt(TW) DO UPDATE SET setlist(Z) where_opt(W) upsert(N). diff --git a/src/upsert.c b/src/upsert.c index cb173aa53f..982dc7dbc1 100644 --- a/src/upsert.c +++ b/src/upsert.c @@ -216,7 +216,7 @@ int sqlite3UpsertAnalyzeTarget( */ int sqlite3UpsertNextIsIPK(Upsert *pUpsert){ Upsert *pNext; - if( pUpsert==0 ) return 0; + if( NEVER(pUpsert==0) ) return 0; pNext = pUpsert->pNextUpsert; if( pNext==0 ) return 1; if( pNext->pUpsertTarget==0 ) return 1; From 59964b40103d530aa1e84ca873ecc146dc13fc80 Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 14 Dec 2020 15:25:14 +0000 Subject: [PATCH 31/38] Fix an integer overflow problem in new VACUUM code. FossilOrigin-Name: 59b4367fd852ba1bfefdff99a27b11657495a3f114ed6f85fdcf6c532f4a19fa --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/btree.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index c5e7ec8dc9..cb0f550f9e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\san\sassert()\sbroken\sby\srecent\schanges\sto\svacuum. -D 2020-12-11T19:01:24.454 +C Fix\san\sinteger\soverflow\sproblem\sin\snew\sVACUUM\scode. +D 2020-12-14T15:25:14.417 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -481,7 +481,7 @@ F src/auth.c a3d5bfdba83d25abed1013a8c7a5f204e2e29b0c25242a56bc02bb0c07bf1e06 F src/backup.c 3014889fa06e20e6adfa0d07b60097eec1f6e5b06671625f476a714d2356513d F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 -F src/btree.c ea5e8bfe904d4818d97cae4eee229d7ce21a0a090ef5402ebac68840dc16713f +F src/btree.c f8cdad7e00eedad4e4f5183aee8db354dd3622604a27bd2223811eeb182236fb F src/btree.h 285f8377aa1353185a32bf455faafa9ff9a0d40d074d60509534d14990c7829e F src/btreeInt.h 7614cae30f95b6aed0c7cac7718276a55cfe2c77058cbfd8bef5b75329757331 F src/build.c f6449d4e85e998e14d3f537e8ea898dca2fcb83c277db3e60945af9b9177db81 @@ -1889,7 +1889,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 b411f29e1a6415f4a241777c45591b8389e746cd8b40d9b225e073bcb0a3bdbf -R 5f1281ebbbf31df2eed9d78849a16b43 +P dd058da85ca54ae70e26cb0bdc75ff42998d4a8b29a5e2dcac44ee0e45776a85 +R 0d937f0ec9f044837ba6918ca3838d82 U dan -Z 63f7dff9f8374ff08b8e0cc7e378c500 +Z 57f4f0625729074fba29cd7d21629db2 diff --git a/manifest.uuid b/manifest.uuid index e819bc2a41..c8f28578db 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -dd058da85ca54ae70e26cb0bdc75ff42998d4a8b29a5e2dcac44ee0e45776a85 \ No newline at end of file +59b4367fd852ba1bfefdff99a27b11657495a3f114ed6f85fdcf6c532f4a19fa \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 1a151fe4ef..a3cf388ff9 100644 --- a/src/btree.c +++ b/src/btree.c @@ -1147,7 +1147,7 @@ static SQLITE_NOINLINE void btreeParseCellAdjustSizeForOverflow( ** 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, int nPayload){ +static int btreePayloadToLocal(MemPage *pPage, i64 nPayload){ int maxLocal; /* Maximum amount of payload held locally */ maxLocal = pPage->maxLocal; if( nPayload<=maxLocal ){ From 84b168ffa7b04a7d5fca80c0e98f7022673af119 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 15 Dec 2020 13:55:38 +0000 Subject: [PATCH 32/38] Change an fts5 assert() that can be triggered by a corrupt database to an if() condition. FossilOrigin-Name: ea0a7f103a6f6a9e57d7377140ff9f372bf2b156f86f148291fb05a7030f2b36 --- ext/fts5/fts5_expr.c | 4 +- ext/fts5/test/fts5corrupt3.test | 128 ++++++++++++++++++++++++++++++++ manifest | 17 ++--- manifest.uuid | 2 +- 4 files changed, 139 insertions(+), 12 deletions(-) diff --git a/ext/fts5/fts5_expr.c b/ext/fts5/fts5_expr.c index 392dde3ab4..088d8b8cae 100644 --- a/ext/fts5/fts5_expr.c +++ b/ext/fts5/fts5_expr.c @@ -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; diff --git a/ext/fts5/test/fts5corrupt3.test b/ext/fts5/test/fts5corrupt3.test index 4223d3c240..4554abbcfb 100644 --- a/ext/fts5/test/fts5corrupt3.test +++ b/ext/fts5/test/fts5corrupt3.test @@ -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 diff --git a/manifest b/manifest index 00e5a96cef..71aaea204e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhance\sUPSERT\sso\sthat\sit\sallows\smultiple\sON\sCONFLICT\sclauses\sand\sdoes\nnot\srequire\sa\sconflict\starget\sfor\sDO\sUPDATE. -D 2020-12-14T15:39:12.267 +C Change\san\sfts5\sassert()\sthat\scan\sbe\striggered\sby\sa\scorrupt\sdatabase\sto\san\sif()\scondition. +D 2020-12-15T13:55:38.138 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -117,7 +117,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 @@ -160,7 +160,7 @@ 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 619295b20dbc1d840b403ee07c878f52378849c3c02e44f2ee143b3e978a0aa7 F ext/fts5/test/fts5detail.test 31b240dbf6d44ac3507e2f8b65f29fdc12465ffd531212378c7ce1066766f54e @@ -1890,8 +1890,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 59b4367fd852ba1bfefdff99a27b11657495a3f114ed6f85fdcf6c532f4a19fa e5a8fa50f4e5e5c24664452eda4af80904f75e5123b8f84353347dbd505d416d -R 5965c0546552f5972781a0c11e3dea88 -T +closed e5a8fa50f4e5e5c24664452eda4af80904f75e5123b8f84353347dbd505d416d -U drh -Z 3b5c01b64f44977242fcbbbded19a49d +P 6b01a24daab1e5bcb0768ebf994368d941b1dfc217bf6b661211d900331e68cf +R a02cdc0a688d372d47b00b934b62e2f2 +U dan +Z 2a130663522021cad08d2a2db075511b diff --git a/manifest.uuid b/manifest.uuid index 8c7df83e8d..ab262d65eb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6b01a24daab1e5bcb0768ebf994368d941b1dfc217bf6b661211d900331e68cf \ No newline at end of file +ea0a7f103a6f6a9e57d7377140ff9f372bf2b156f86f148291fb05a7030f2b36 \ No newline at end of file From 0bf333467ca7abd3467f005863f652343fc38d8f Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 15 Dec 2020 16:28:07 +0000 Subject: [PATCH 33/38] When the -statstep option is passed to the "rbu" executable, print out memory stats right before exiting, as well as every -statstep steps. FossilOrigin-Name: 94f81b51176566409b7d16b30d861f48ad15bb43a145df6e02e0880f7c348109 --- ext/rbu/rbu.c | 7 +++++++ manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/ext/rbu/rbu.c b/ext/rbu/rbu.c index 02822c4a42..91773409cf 100644 --- a/ext/rbu/rbu.c +++ b/ext/rbu/rbu.c @@ -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; } diff --git a/manifest b/manifest index 71aaea204e..82f8be63a6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Change\san\sfts5\sassert()\sthat\scan\sbe\striggered\sby\sa\scorrupt\sdatabase\sto\san\sif()\scondition. -D 2020-12-15T13:55:38.138 +C When\sthe\s-statstep\soption\sis\spassed\sto\sthe\s"rbu"\sexecutable,\sprint\sout\smemory\sstats\sright\sbefore\sexiting,\sas\swell\sas\severy\s-statstep\ssteps. +D 2020-12-15T16:28:07.633 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -339,7 +339,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 @@ -1890,7 +1890,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 6b01a24daab1e5bcb0768ebf994368d941b1dfc217bf6b661211d900331e68cf -R a02cdc0a688d372d47b00b934b62e2f2 +P ea0a7f103a6f6a9e57d7377140ff9f372bf2b156f86f148291fb05a7030f2b36 +R a2929ff08e32fd95eef1d5a44bce177d U dan -Z 2a130663522021cad08d2a2db075511b +Z 7d2f5d8183adfe209996b488d97e46d6 diff --git a/manifest.uuid b/manifest.uuid index ab262d65eb..c48b781edb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ea0a7f103a6f6a9e57d7377140ff9f372bf2b156f86f148291fb05a7030f2b36 \ No newline at end of file +94f81b51176566409b7d16b30d861f48ad15bb43a145df6e02e0880f7c348109 \ No newline at end of file From 7f607066911c7957e93f9fb5c5f4d8bad17f04ba Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 15 Dec 2020 19:27:20 +0000 Subject: [PATCH 34/38] Fix another integer overflow triggered by a corrupt database in recently modified vacuum code. FossilOrigin-Name: 4e2dd2a53364f1fed48b995fd5d2642472585f6da5e4735e9da193ba7ff45514 --- manifest | 13 +++--- manifest.uuid | 2 +- src/btree.c | 2 +- test/corruptN.test | 106 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 8 deletions(-) create mode 100644 test/corruptN.test diff --git a/manifest b/manifest index 82f8be63a6..097c1231bf 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C When\sthe\s-statstep\soption\sis\spassed\sto\sthe\s"rbu"\sexecutable,\sprint\sout\smemory\sstats\sright\sbefore\sexiting,\sas\swell\sas\severy\s-statstep\ssteps. -D 2020-12-15T16:28:07.633 +C Fix\sanother\sinteger\soverflow\striggered\sby\sa\scorrupt\sdatabase\sin\srecently\smodified\svacuum\scode. +D 2020-12-15T19:27:20.474 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -481,7 +481,7 @@ F src/auth.c a3d5bfdba83d25abed1013a8c7a5f204e2e29b0c25242a56bc02bb0c07bf1e06 F src/backup.c 3014889fa06e20e6adfa0d07b60097eec1f6e5b06671625f476a714d2356513d F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 -F src/btree.c f8cdad7e00eedad4e4f5183aee8db354dd3622604a27bd2223811eeb182236fb +F src/btree.c b995dfb6a2d79e2be51ce65a6f54a52f2c327507c35f3f8558d0def711d59298 F src/btree.h 285f8377aa1353185a32bf455faafa9ff9a0d40d074d60509534d14990c7829e F src/btreeInt.h 7614cae30f95b6aed0c7cac7718276a55cfe2c77058cbfd8bef5b75329757331 F src/build.c f6449d4e85e998e14d3f537e8ea898dca2fcb83c277db3e60945af9b9177db81 @@ -791,6 +791,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 @@ -1890,7 +1891,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 ea0a7f103a6f6a9e57d7377140ff9f372bf2b156f86f148291fb05a7030f2b36 -R a2929ff08e32fd95eef1d5a44bce177d +P 94f81b51176566409b7d16b30d861f48ad15bb43a145df6e02e0880f7c348109 +R f70af48afc53d25055f1c1dd84b7bed4 U dan -Z 7d2f5d8183adfe209996b488d97e46d6 +Z 726142031de41291f3ae18db2fa43170 diff --git a/manifest.uuid b/manifest.uuid index c48b781edb..4aa36b8a6b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -94f81b51176566409b7d16b30d861f48ad15bb43a145df6e02e0880f7c348109 \ No newline at end of file +4e2dd2a53364f1fed48b995fd5d2642472585f6da5e4735e9da193ba7ff45514 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index a3cf388ff9..0f4b5aaa4d 100644 --- a/src/btree.c +++ b/src/btree.c @@ -8966,7 +8966,7 @@ int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 iKey){ u8 *aOut = pBt->pTmpSpace; /* Pointer to next output buffer */ const u8 *aIn; /* Pointer to next input buffer */ int nIn; /* Size of input buffer aIn[] */ - int nRem; /* Bytes of data still to copy */ + u32 nRem; /* Bytes of data still to copy */ getCellInfo(pSrc); aOut += putVarint32(aOut, pSrc->info.nPayload); diff --git a/test/corruptN.test b/test/corruptN.test new file mode 100644 index 0000000000..4f7667ce1e --- /dev/null +++ b/test/corruptN.test @@ -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 From 9463d793531c893859c5756741246b0cc5f3e412 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 16 Dec 2020 13:17:32 +0000 Subject: [PATCH 35/38] Fix a typo in the sqlite3_free_filename() documentation. FossilOrigin-Name: 48301edc90fe5811df0394b106edce7726d0ea86ac562c9f4db511b812a76433 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/sqlite.h.in | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 097c1231bf..fe92f0c21e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sanother\sinteger\soverflow\striggered\sby\sa\scorrupt\sdatabase\sin\srecently\smodified\svacuum\scode. -D 2020-12-15T19:27:20.474 +C Fix\sa\stypo\sin\sthe\ssqlite3_free_filename()\sdocumentation. +D 2020-12-16T13:17:32.129 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -542,7 +542,7 @@ F src/resolve.c 1948a92ca9eab776632816b97e57c61d933474a78aad4f4ef835c916a83dbb1c F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c c9b68506e5d8cc8d0e4b307b97a9800b050ac37dada80ae9c66f680f8fac3e09 F src/shell.c.in e9f674ee4ec6c345679e8a5b16c869c6c59eb1540dd98ac69e4736ecddce0090 -F src/sqlite.h.in 0e2b4259e49a0eda54d9118eb18a04fcd60e0727a2fd2c81aade0bf57520e706 +F src/sqlite.h.in 5b7593bb0f3658e682a9fcd1cd8fcedf244ec45ca93d645055a53172f55eb783 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e F src/sqliteInt.h ef8b4b3992d9460c9676c4695416f4141d5c5db4d3d78f89d20662361d6e21f1 @@ -1891,7 +1891,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 94f81b51176566409b7d16b30d861f48ad15bb43a145df6e02e0880f7c348109 -R f70af48afc53d25055f1c1dd84b7bed4 -U dan -Z 726142031de41291f3ae18db2fa43170 +P 4e2dd2a53364f1fed48b995fd5d2642472585f6da5e4735e9da193ba7ff45514 +R 3372ddf7c965d76aff4a452b717f27a6 +U drh +Z 51799b847b8818e6198c5e71c210a358 diff --git a/manifest.uuid b/manifest.uuid index 4aa36b8a6b..56b34a6d6e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4e2dd2a53364f1fed48b995fd5d2642472585f6da5e4735e9da193ba7ff45514 \ No newline at end of file +48301edc90fe5811df0394b106edce7726d0ea86ac562c9f4db511b812a76433 \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index c975b23351..79eecb4b08 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -3697,7 +3697,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 From e5baf5c28351cfaa8daa605e7f066894eac9eef6 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 16 Dec 2020 14:20:45 +0000 Subject: [PATCH 36/38] Remove an unnecessary and incorrect #ifdef. Fix harmless compiler warnings. FossilOrigin-Name: 31cd1bbfa5b06723288d99d1cb423f88353bdef770b82e9103f71a796d66f660 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/btree.c | 4 ++-- src/func.c | 1 + src/sqliteInt.h | 4 +--- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/manifest b/manifest index fe92f0c21e..89395f093a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\stypo\sin\sthe\ssqlite3_free_filename()\sdocumentation. -D 2020-12-16T13:17:32.129 +C Remove\san\sunnecessary\sand\sincorrect\s#ifdef.\s\sFix\sharmless\scompiler\swarnings. +D 2020-12-16T14:20:45.731 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -481,7 +481,7 @@ F src/auth.c a3d5bfdba83d25abed1013a8c7a5f204e2e29b0c25242a56bc02bb0c07bf1e06 F src/backup.c 3014889fa06e20e6adfa0d07b60097eec1f6e5b06671625f476a714d2356513d F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 -F src/btree.c b995dfb6a2d79e2be51ce65a6f54a52f2c327507c35f3f8558d0def711d59298 +F src/btree.c fae82794638b41f4fdd0e49d5196ceaa7848e6666dbbf412eb173c58c4fbf48c F src/btree.h 285f8377aa1353185a32bf455faafa9ff9a0d40d074d60509534d14990c7829e F src/btreeInt.h 7614cae30f95b6aed0c7cac7718276a55cfe2c77058cbfd8bef5b75329757331 F src/build.c f6449d4e85e998e14d3f537e8ea898dca2fcb83c277db3e60945af9b9177db81 @@ -495,7 +495,7 @@ F src/delete.c 927cf8f900583e79aca8f1a321979e0a8f053babd9a690b44b38f79de2cc09fe F src/expr.c 0d196ed5a2ebf96be7e8df88add4fabfad0dce16c0fed81a4b8f6a26e259797f F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 83372403298e6a7dd989a47aaacdbaa5b4307b5199dbd56e07d4896066b3de72 -F src/func.c 04b33016df7f4dcda295f71c6c776e2f49bfe0d50b5c5118240dfcd307d4755d +F src/func.c 2163afb2cfabb71768f9254b95dbab3b7d4cd94394f6cffb86704e0b7e6ccabe F src/global.c ed55af196a9b66e198aaeda3f5454c3aa7d7d050c6c938181fd044b70d180a81 F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 9d56a9079d523b648774c1784b74b89bd93fac7b365210157482e4319a468f38 @@ -545,7 +545,7 @@ F src/shell.c.in e9f674ee4ec6c345679e8a5b16c869c6c59eb1540dd98ac69e4736ecddce009 F src/sqlite.h.in 5b7593bb0f3658e682a9fcd1cd8fcedf244ec45ca93d645055a53172f55eb783 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e -F src/sqliteInt.h ef8b4b3992d9460c9676c4695416f4141d5c5db4d3d78f89d20662361d6e21f1 +F src/sqliteInt.h 6d8363d245354e360b5efa5f1dc4a7658f252dc80b1c9010264d64dfe77fdf1b F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -1891,7 +1891,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 4e2dd2a53364f1fed48b995fd5d2642472585f6da5e4735e9da193ba7ff45514 -R 3372ddf7c965d76aff4a452b717f27a6 +P 48301edc90fe5811df0394b106edce7726d0ea86ac562c9f4db511b812a76433 +R bc270d52af99cca590351162eea6886b U drh -Z 51799b847b8818e6198c5e71c210a358 +Z 53bb33e2ab1210ebb52c38429ca9bfe7 diff --git a/manifest.uuid b/manifest.uuid index 56b34a6d6e..1abcf7fc42 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -48301edc90fe5811df0394b106edce7726d0ea86ac562c9f4db511b812a76433 \ No newline at end of file +31cd1bbfa5b06723288d99d1cb423f88353bdef770b82e9103f71a796d66f660 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 0f4b5aaa4d..9b8005037e 100644 --- a/src/btree.c +++ b/src/btree.c @@ -8965,7 +8965,7 @@ int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 iKey){ BtShared *pBt = pDest->pBt; u8 *aOut = pBt->pTmpSpace; /* Pointer to next output buffer */ const u8 *aIn; /* Pointer to next input buffer */ - int nIn; /* Size of input buffer aIn[] */ + u32 nIn; /* Size of input buffer aIn[] */ u32 nRem; /* Bytes of data still to copy */ getCellInfo(pSrc); @@ -8983,7 +8983,7 @@ int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 iKey){ Pgno ovflIn = 0; DbPage *pPageIn = 0; MemPage *pPageOut = 0; - int nOut; /* Size of output buffer aOut[] */ + u32 nOut; /* Size of output buffer aOut[] */ nOut = btreePayloadToLocal(pDest->pPage, pSrc->info.nPayload); pBt->nPreformatSize = nOut + (aOut - pBt->pTmpSpace); diff --git a/src/func.c b/src/func.c index a29088a68d..e91fc256cb 100644 --- a/src/func.c +++ b/src/func.c @@ -2084,6 +2084,7 @@ static void signFunc( ){ 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; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index d91ba49d95..a0e05570e7 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1014,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 From 0a8b6a9f8f5a1b446cb4217efa37529bcc37bc1d Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 16 Dec 2020 21:09:45 +0000 Subject: [PATCH 37/38] Enhance the sqlite3BtreeTransferRow() routine so that it does more careful checks for corrupt database pages. FossilOrigin-Name: 85952e71175dae73c4e587a3b80783825d91fe8567a819e072da651c1ff4131b --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/btree.c | 6 ++++++ test/fuzzdata8.db | Bin 1616896 -> 1619968 bytes 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 89395f093a..efa169e37a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\san\sunnecessary\sand\sincorrect\s#ifdef.\s\sFix\sharmless\scompiler\swarnings. -D 2020-12-16T14:20:45.731 +C Enhance\sthe\ssqlite3BtreeTransferRow()\sroutine\sso\sthat\sit\sdoes\smore\scareful\nchecks\sfor\scorrupt\sdatabase\spages. +D 2020-12-16T21:09:45.084 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -481,7 +481,7 @@ F src/auth.c a3d5bfdba83d25abed1013a8c7a5f204e2e29b0c25242a56bc02bb0c07bf1e06 F src/backup.c 3014889fa06e20e6adfa0d07b60097eec1f6e5b06671625f476a714d2356513d F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 -F src/btree.c fae82794638b41f4fdd0e49d5196ceaa7848e6666dbbf412eb173c58c4fbf48c +F src/btree.c 0f9cb686871ae668817673f0823b55d1bcadbc86ea28bd22c590b064a8322d5a F src/btree.h 285f8377aa1353185a32bf455faafa9ff9a0d40d074d60509534d14990c7829e F src/btreeInt.h 7614cae30f95b6aed0c7cac7718276a55cfe2c77058cbfd8bef5b75329757331 F src/build.c f6449d4e85e998e14d3f537e8ea898dca2fcb83c277db3e60945af9b9177db81 @@ -1043,7 +1043,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 @@ -1891,7 +1891,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 48301edc90fe5811df0394b106edce7726d0ea86ac562c9f4db511b812a76433 -R bc270d52af99cca590351162eea6886b +P 31cd1bbfa5b06723288d99d1cb423f88353bdef770b82e9103f71a796d66f660 +R be1e2d0f672e56f934d1c99d7dc679ec U drh -Z 53bb33e2ab1210ebb52c38429ca9bfe7 +Z e48ee7782ade3dd763b30b3828175795 diff --git a/manifest.uuid b/manifest.uuid index 1abcf7fc42..d23f02d0c0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -31cd1bbfa5b06723288d99d1cb423f88353bdef770b82e9103f71a796d66f660 \ No newline at end of file +85952e71175dae73c4e587a3b80783825d91fe8567a819e072da651c1ff4131b \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 9b8005037e..a587332ce2 100644 --- a/src/btree.c +++ b/src/btree.c @@ -8973,6 +8973,9 @@ int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 iKey){ 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 && nInpPage->maxLocal ){ memcpy(aOut, aIn, nIn); @@ -8993,6 +8996,9 @@ int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 iKey){ } if( nRem>nIn ){ + if( aIn+nIn+4>pSrc->pPage->aDataEnd ){ + return SQLITE_CORRUPT_BKPT; + } ovflIn = get4byte(&pSrc->info.pPayload[nIn]); } diff --git a/test/fuzzdata8.db b/test/fuzzdata8.db index 39191fc8b1f03935f6b661eab5af1e2e2fba7285..47d0d5a165f0d64501d44be2fe3902b232d67776 100644 GIT binary patch delta 25797 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 E-@|?Jw*UYD delta 23001 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 From 13dd0228d318e98346adc1b4021d44dfd8869a7a Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 17 Dec 2020 11:24:26 +0000 Subject: [PATCH 38/38] Fix a problem with sqlite3_expanded_sql() that could occur with statements that use both numbered (e.g. "?1") and unnumbered (i.e. "?") parameters. FossilOrigin-Name: 2a6cd6833e44dd6a2ac388815f43be6508f6fa6db5e451e964276a6c87e6c5ae --- manifest | 16 +++++----- manifest.uuid | 2 +- src/vdbetrace.c | 2 +- test/trace3.test | 79 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index efa169e37a..d48de5b388 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhance\sthe\ssqlite3BtreeTransferRow()\sroutine\sso\sthat\sit\sdoes\smore\scareful\nchecks\sfor\scorrupt\sdatabase\spages. -D 2020-12-16T21:09:45.084 +C Fix\sa\sproblem\swith\ssqlite3_expanded_sql()\sthat\scould\soccur\swith\sstatements\sthat\suse\sboth\snumbered\s(e.g.\s"?1")\sand\sunnumbered\s(i.e.\s"?")\sparameters. +D 2020-12-17T11:24:26.721 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -620,7 +620,7 @@ F src/vdbeaux.c c76b7e96e189f5056d1de914d33d07bd03d3b88741f75375c8e18c9b11ffd379 F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b1 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 5f5fc793092f53bbdfde296c50f563fb7bda58cf48e9cf6a8bdfbc5abd409845 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 @@ -1595,7 +1595,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 @@ -1891,7 +1891,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 31cd1bbfa5b06723288d99d1cb423f88353bdef770b82e9103f71a796d66f660 -R be1e2d0f672e56f934d1c99d7dc679ec -U drh -Z e48ee7782ade3dd763b30b3828175795 +P 85952e71175dae73c4e587a3b80783825d91fe8567a819e072da651c1ff4131b +R 8413851e616b40793979ba3b0b321ea0 +U dan +Z a9095f79474677b3701cc55eacd5797f diff --git a/manifest.uuid b/manifest.uuid index d23f02d0c0..550b66bf87 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -85952e71175dae73c4e587a3b80783825d91fe8567a819e072da651c1ff4131b \ No newline at end of file +2a6cd6833e44dd6a2ac388815f43be6508f6fa6db5e451e964276a6c87e6c5ae \ No newline at end of file diff --git a/src/vdbetrace.c b/src/vdbetrace.c index 32c66af228..1095e7f589 100644 --- a/src/vdbetrace.c +++ b/src/vdbetrace.c @@ -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 ){ diff --git a/test/trace3.test b/test/trace3.test index 538dcd0942..e9935acfb8 100644 --- a/test/trace3.test +++ b/test/trace3.test @@ -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