From 1e48d79f71f334f8e7347d013e47a2cd7b099106 Mon Sep 17 00:00:00 2001 From: larrybr Date: Sat, 7 May 2022 02:21:17 +0000 Subject: [PATCH 001/108] Create new branch named "import-leak-plug" FossilOrigin-Name: 4a4cecab23ef2aab20b1db466d045d56921590eb67563ab5a31f7b0a0f75c533 --- manifest | 13 ++++++++----- manifest.uuid | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/manifest b/manifest index 7cf52986c1..0a9a9820e1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Perserve\sthe\srequested\sreserved-bytes\ssize\sfor\sthe\sdatabase\sfile\swhen\ndoing\sa\sVACUUM. -D 2022-05-06T22:29:45.170 +C Create\snew\sbranch\snamed\s"import-leak-plug" +D 2022-05-07T02:21:17.769 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -1953,8 +1953,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 217b33234dc3dc36b5b6add50c170869421057a56a7576d1a61767956248d5c9 +P dac6d87c71606f3ec7ce601be6d17357d323476ecb60dbb167030146783b62b2 R fb5b71dd78e91f00920386e6c95ee22a -U drh -Z 5c19e3fe26f9144dbbad9274556b129a +T *branch * import-leak-plug +T *sym-import-leak-plug * +T -sym-trunk * +U larrybr +Z 513f56eca52f57dd200e788d0d348907 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 80d0655a95..f893f4fe4c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -dac6d87c71606f3ec7ce601be6d17357d323476ecb60dbb167030146783b62b2 \ No newline at end of file +4a4cecab23ef2aab20b1db466d045d56921590eb67563ab5a31f7b0a0f75c533 \ No newline at end of file From fa5dfa89109ca06d4a0de998659550d7e3bf2595 Mon Sep 17 00:00:00 2001 From: larrybr Date: Sat, 7 May 2022 03:53:14 +0000 Subject: [PATCH 002/108] Stop a memory leak in .import, and add leak complaint to CLI debug builds. FossilOrigin-Name: f5f09368b33b6af00f96e5b8f763e7ee2d00ba6af2aee0f2ca86bb58c03d0b71 --- manifest | 15 ++++++--------- manifest.uuid | 2 +- src/shell.c.in | 35 +++++++++++++++++++---------------- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/manifest b/manifest index 0a9a9820e1..7ac50b6a3c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Create\snew\sbranch\snamed\s"import-leak-plug" -D 2022-05-07T02:21:17.769 +C Stop\sa\smemory\sleak\sin\s.import,\sand\sadd\sleak\scomplaint\sto\sCLI\sdebug\sbuilds. +D 2022-05-07T03:53:14.691 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -554,7 +554,7 @@ F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c e9ee235c4151d2b7fa47435a219bfd30bf516a804d2f004639858087ebf3137b F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c 151adca2c9ea6f51215e4351bb8eb4f0012bf98c3d5a5c991d4a019c7cbb143e -F src/shell.c.in ae0a6fae983caac6f8c824733f0599dfdf7b3a7e8efdef3cb5e3ab2e457ffc35 +F src/shell.c.in 6b7ddce6ebfb52633236c174928f84558fa7471eed99ce189014d40df990c97b F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h f49e28c25bd941e79794db5415fdf7b202deb3bc072ed6f1ed273d578703684e @@ -1953,11 +1953,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P dac6d87c71606f3ec7ce601be6d17357d323476ecb60dbb167030146783b62b2 -R fb5b71dd78e91f00920386e6c95ee22a -T *branch * import-leak-plug -T *sym-import-leak-plug * -T -sym-trunk * +P 4a4cecab23ef2aab20b1db466d045d56921590eb67563ab5a31f7b0a0f75c533 +R fa3a4ab48fbdc17706ad46278227efc1 U larrybr -Z 513f56eca52f57dd200e788d0d348907 +Z 88cf4bfe2e519f3edccdf0d39a577138 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index f893f4fe4c..d9046afb0b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4a4cecab23ef2aab20b1db466d045d56921590eb67563ab5a31f7b0a0f75c533 \ No newline at end of file +f5f09368b33b6af00f96e5b8f763e7ee2d00ba6af2aee0f2ca86bb58c03d0b71 \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index 95a32f5247..5e9bfa220a 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -8883,8 +8883,7 @@ static int do_meta_command(char *zLine, ShellState *p){ }else{ utf8_printf(p->out, "ERROR: extra argument: \"%s\". Usage:\n", z); showHelp(p->out, "import"); - rc = 1; - goto meta_command_exit; + goto import_cleanup_fail; } }else if( strcmp(z,"-v")==0 ){ eVerbose++; @@ -8905,15 +8904,16 @@ static int do_meta_command(char *zLine, ShellState *p){ }else{ utf8_printf(p->out, "ERROR: unknown option: \"%s\". Usage:\n", z); showHelp(p->out, "import"); - rc = 1; - goto meta_command_exit; + goto import_cleanup_fail; } } if( zTable==0 ){ utf8_printf(p->out, "ERROR: missing %s argument. Usage:\n", zFile==0 ? "FILE" : "TABLE"); showHelp(p->out, "import"); + import_cleanup_fail: rc = 1; + import_cleanup(&sCtx); goto meta_command_exit; } seenInterrupt = 0; @@ -8925,22 +8925,20 @@ static int do_meta_command(char *zLine, ShellState *p){ if( nSep==0 ){ raw_printf(stderr, "Error: non-null column separator required for import\n"); - rc = 1; - goto meta_command_exit; + goto import_cleanup_fail; } if( nSep>1 ){ raw_printf(stderr, "Error: multi-character column separators not allowed" " for import\n"); - rc = 1; - goto meta_command_exit; + goto import_cleanup_fail; } nSep = strlen30(p->rowSeparator); if( nSep==0 ){ raw_printf(stderr, "Error: non-null row separator required for import\n"); rc = 1; - goto meta_command_exit; + goto import_cleanup_fail; } if( nSep==2 && p->mode==MODE_Csv && strcmp(p->rowSeparator,SEP_CrLf)==0 ){ /* When importing CSV (only), if the row separator is set to the @@ -8953,8 +8951,7 @@ static int do_meta_command(char *zLine, ShellState *p){ if( nSep>1 ){ raw_printf(stderr, "Error: multi-character row separators not allowed" " for import\n"); - rc = 1; - goto meta_command_exit; + goto import_cleanup_fail; } sCtx.cColSep = p->colSeparator[0]; sCtx.cRowSep = p->rowSeparator[0]; @@ -8964,8 +8961,7 @@ static int do_meta_command(char *zLine, ShellState *p){ if( sCtx.zFile[0]=='|' ){ #ifdef SQLITE_OMIT_POPEN raw_printf(stderr, "Error: pipes are not supported in this OS\n"); - rc = 1; - goto meta_command_exit; + goto import_cleanup_fail; #else sCtx.in = popen(sCtx.zFile+1, "r"); sCtx.zFile = ""; @@ -8977,9 +8973,7 @@ static int do_meta_command(char *zLine, ShellState *p){ } if( sCtx.in==0 ){ utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile); - rc = 1; - import_cleanup(&sCtx); - goto meta_command_exit; + goto import_cleanup_fail; } if( eVerbose>=2 || (eVerbose>=1 && useOutputMode) ){ char zSep[2]; @@ -11863,6 +11857,9 @@ int SQLITE_CDECL main(int argc, char **argv){ #else int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ char **argv; +#endif +#ifdef SQLITE_DEBUG + sqlite3_uint64 mem_main_enter = sqlite3_memory_used(); #endif char *zErrMsg = 0; ShellState data; @@ -12430,5 +12427,11 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ /* Clear the global data structure so that valgrind will detect memory ** leaks */ memset(&data, 0, sizeof(data)); +#ifdef SQLITE_DEBUG + if( sqlite3_memory_used()>mem_main_enter ){ + utf8_printf(stderr, "Memory leaked: %u bytes\n", + (unsigned int)(sqlite3_memory_used()-mem_main_enter)); + } +#endif return rc; } From 2f5f674066bcbcb7863658f51074dea273a0ab42 Mon Sep 17 00:00:00 2001 From: larrybr Date: Mon, 9 May 2022 12:29:47 +0000 Subject: [PATCH 003/108] Simplify .import leak plug and arrange for CLI to be run under valgrind. FossilOrigin-Name: 0d3e2380197aa3e725591266acaeb0d43a7e794ca9153e6c56253cdcf60720b1 --- manifest | 24 ++++++++++++------------ manifest.uuid | 2 +- src/shell.c.in | 34 ++++++++++++++++------------------ test/shell1.test | 2 +- test/shell3.test | 2 +- test/shell4.test | 7 ++++--- test/shell5.test | 2 +- test/shell8.test | 2 +- test/tester.tcl | 28 +++++++++++++++++++++++++++- 9 files changed, 64 insertions(+), 39 deletions(-) diff --git a/manifest b/manifest index 7ac50b6a3c..54db67c2c8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Stop\sa\smemory\sleak\sin\s.import,\sand\sadd\sleak\scomplaint\sto\sCLI\sdebug\sbuilds. -D 2022-05-07T03:53:14.691 +C Simplify\s.import\sleak\splug\sand\sarrange\sfor\sCLI\sto\sbe\srun\sunder\svalgrind. +D 2022-05-09T12:29:47.606 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -554,7 +554,7 @@ F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c e9ee235c4151d2b7fa47435a219bfd30bf516a804d2f004639858087ebf3137b F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c 151adca2c9ea6f51215e4351bb8eb4f0012bf98c3d5a5c991d4a019c7cbb143e -F src/shell.c.in 6b7ddce6ebfb52633236c174928f84558fa7471eed99ce189014d40df990c97b +F src/shell.c.in 0ad33896c3e79a9578c507c8f0589290cbc98b0af1f31ca0cf8ddbb7601e60ef F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h f49e28c25bd941e79794db5415fdf7b202deb3bc072ed6f1ed273d578703684e @@ -1397,14 +1397,14 @@ F test/sharedA.test 49d87ec54ab640fbbc3786ee3c01de94aaa482a3a9f834ad3fe92770eb69 F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939 F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304 -F test/shell1.test f7a2ef8260aa01f20be3185118213b1ae70518fdcd2105f3e25b021b5ca800ac +F test/shell1.test e4b4de56f454708e0747b52915135baa2cbfec4965406d6eaf02a4a5c22a9880 F test/shell2.test 7a3a23a9f57b99453f1679b1fe8072cb30e382a622874c0c4d97695fadb0a787 -F test/shell3.test a50628ab1d78d90889d9d3f32fb2c084ee15674771e96afe954aaa0accd1de3c -F test/shell4.test 8f6c0fce4abed19a8a7f7262517149812a04caa905d01bdc8f5e92573504b759 -F test/shell5.test 78a7a8516b1e7de560748881424f621321549023d3e5f7ed2e1c56497f64c06c +F test/shell3.test 91febeac0412812bf6370abb8ed72700e32bf8f9878849414518f662dfd55e8a +F test/shell4.test 7dc8a515705bc093d8ffe381670e8fa7a969661e8ed177c35c847e3c6dfc35e2 +F test/shell5.test c8b6c54f26ec537f8558273d7ed293ca3725ef42e6b12b8f151718628bd1473b F test/shell6.test 1ceb51b2678c472ba6cf1e5da96679ce8347889fe2c3bf93a0e0fa73f00b00d3 F test/shell7.test 115132f66d0463417f408562cc2cf534f6bbc6d83a6d50f0072a9eb171bae97f -F test/shell8.test 388471d16e4de767333107e30653983f186232c0e863f4490bb230419e830aae +F test/shell8.test 3fd093d481aaa94dc77fb73f1044c1f19c7efe3477a395cc4f7450133bc54915 F test/shmlock.test 3dbf017d34ab0c60abe6a44e447d3552154bd0c87b41eaf5ceacd408dd13fda5 F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3 F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5 @@ -1482,7 +1482,7 @@ F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30 F test/temptable2.test d2940417496e2b9548e01d09990763fbe88c316504033256d51493e1f1a5ce6a F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637 F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc -F test/tester.tcl 18448c7801d44cc5f2690f54f803da49ed994b3968f73a393cff329e55926679 +F test/tester.tcl eea76fe47703d4bd2d12ddc761fb0be623f9a7b878e50a2dcb7bd6fe4b3040f1 F test/thread001.test b61a29dd87cf669f5f6ac96124a7c97d71b0c80d9012746072055877055cf9ef F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58 F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7 @@ -1953,8 +1953,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 4a4cecab23ef2aab20b1db466d045d56921590eb67563ab5a31f7b0a0f75c533 -R fa3a4ab48fbdc17706ad46278227efc1 +P f5f09368b33b6af00f96e5b8f763e7ee2d00ba6af2aee0f2ca86bb58c03d0b71 +R 84088aa54a74f88fa3741dd082a651c8 U larrybr -Z 88cf4bfe2e519f3edccdf0d39a577138 +Z 4cea09d549ba44b05dc5240e31984b9e # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index d9046afb0b..b8969acb8f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f5f09368b33b6af00f96e5b8f763e7ee2d00ba6af2aee0f2ca86bb58c03d0b71 \ No newline at end of file +0d3e2380197aa3e725591266acaeb0d43a7e794ca9153e6c56253cdcf60720b1 \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index 5e9bfa220a..1c22103f84 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -8862,16 +8862,12 @@ static int do_meta_command(char *zLine, ShellState *p){ failIfSafeMode(p, "cannot run .import in safe mode"); memset(&sCtx, 0, sizeof(sCtx)); - sCtx.z = sqlite3_malloc64(120); - if( sCtx.z==0 ){ - import_cleanup(&sCtx); - shell_out_of_memory(); - } if( p->mode==MODE_Ascii ){ xRead = ascii_read_one_field; }else{ xRead = csv_read_one_field; } + rc = 1; for(i=1; iout, "ERROR: extra argument: \"%s\". Usage:\n", z); showHelp(p->out, "import"); - goto import_cleanup_fail; + goto meta_command_exit; } }else if( strcmp(z,"-v")==0 ){ eVerbose++; @@ -8904,16 +8900,13 @@ static int do_meta_command(char *zLine, ShellState *p){ }else{ utf8_printf(p->out, "ERROR: unknown option: \"%s\". Usage:\n", z); showHelp(p->out, "import"); - goto import_cleanup_fail; + goto meta_command_exit; } } if( zTable==0 ){ utf8_printf(p->out, "ERROR: missing %s argument. Usage:\n", zFile==0 ? "FILE" : "TABLE"); showHelp(p->out, "import"); - import_cleanup_fail: - rc = 1; - import_cleanup(&sCtx); goto meta_command_exit; } seenInterrupt = 0; @@ -8925,20 +8918,19 @@ static int do_meta_command(char *zLine, ShellState *p){ if( nSep==0 ){ raw_printf(stderr, "Error: non-null column separator required for import\n"); - goto import_cleanup_fail; + goto meta_command_exit; } if( nSep>1 ){ - raw_printf(stderr, + raw_printf(stderr, "Error: multi-character column separators not allowed" " for import\n"); - goto import_cleanup_fail; + goto meta_command_exit; } nSep = strlen30(p->rowSeparator); if( nSep==0 ){ raw_printf(stderr, "Error: non-null row separator required for import\n"); - rc = 1; - goto import_cleanup_fail; + goto meta_command_exit; } if( nSep==2 && p->mode==MODE_Csv && strcmp(p->rowSeparator,SEP_CrLf)==0 ){ /* When importing CSV (only), if the row separator is set to the @@ -8951,7 +8943,7 @@ static int do_meta_command(char *zLine, ShellState *p){ if( nSep>1 ){ raw_printf(stderr, "Error: multi-character row separators not allowed" " for import\n"); - goto import_cleanup_fail; + goto meta_command_exit; } sCtx.cColSep = p->colSeparator[0]; sCtx.cRowSep = p->rowSeparator[0]; @@ -8961,7 +8953,7 @@ static int do_meta_command(char *zLine, ShellState *p){ if( sCtx.zFile[0]=='|' ){ #ifdef SQLITE_OMIT_POPEN raw_printf(stderr, "Error: pipes are not supported in this OS\n"); - goto import_cleanup_fail; + goto meta_command_exit; #else sCtx.in = popen(sCtx.zFile+1, "r"); sCtx.zFile = ""; @@ -8973,8 +8965,9 @@ static int do_meta_command(char *zLine, ShellState *p){ } if( sCtx.in==0 ){ utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile); - goto import_cleanup_fail; + goto meta_command_exit; } + rc = 0; if( eVerbose>=2 || (eVerbose>=1 && useOutputMode) ){ char zSep[2]; zSep[1] = 0; @@ -8986,6 +8979,11 @@ static int do_meta_command(char *zLine, ShellState *p){ output_c_string(p->out, zSep); utf8_printf(p->out, "\n"); } + sCtx.z = sqlite3_malloc64(120); + if( sCtx.z==0 ){ + import_cleanup(&sCtx); + shell_out_of_memory(); + } /* Below, resources must be freed before exit. */ while( (nSkip--)>0 ){ while( xRead(&sCtx) && sCtx.cTerm==sCtx.cColSep ){} diff --git a/test/shell1.test b/test/shell1.test index 3c7061c55d..26426535b7 100644 --- a/test/shell1.test +++ b/test/shell1.test @@ -23,7 +23,7 @@ # set testdir [file dirname $argv0] source $testdir/tester.tcl -set CLI [test_find_cli] +set CLI [test_cli_invocation] db close forcedelete test.db test.db-journal test.db-wal sqlite3 db test.db diff --git a/test/shell3.test b/test/shell3.test index e5a0c124e0..f8d69946e7 100644 --- a/test/shell3.test +++ b/test/shell3.test @@ -22,7 +22,7 @@ # set testdir [file dirname $argv0] source $testdir/tester.tcl -set CLI [test_find_cli] +set CLI [test_cli_invocation] db close forcedelete test.db test.db-journal test.db-wal sqlite3 db test.db diff --git a/test/shell4.test b/test/shell4.test index ee7d2b856f..068072202d 100644 --- a/test/shell4.test +++ b/test/shell4.test @@ -23,7 +23,8 @@ # set testdir [file dirname $argv0] source $testdir/tester.tcl -set CLI [test_find_cli] +set CLI [test_cli_invocation] +set CLI_ONLY [test_find_cli] db close forcedelete test.db test.db-journal test.db-wal sqlite3 db test.db @@ -130,13 +131,13 @@ do_test shell4-3.1 { set fd [open t1.txt wb] puts $fd "SELECT 'squirrel';" close $fd - exec $::CLI :memory: --interactive ".read t1.txt" + exec $::CLI_ONLY :memory: --interactive ".read t1.txt" } {squirrel} do_test shell4-3.2 { set fd [open t1.txt wb] puts $fd "SELECT 'pound: \302\243';" close $fd - exec $::CLI :memory: --interactive ".read t1.txt" + exec $::CLI_ONLY :memory: --interactive ".read t1.txt" } {pound: £} do_test shell4-4.1 { diff --git a/test/shell5.test b/test/shell5.test index 00d89f8d78..39018a0ce9 100644 --- a/test/shell5.test +++ b/test/shell5.test @@ -21,7 +21,7 @@ # set testdir [file dirname $argv0] source $testdir/tester.tcl -set CLI [test_find_cli] +set CLI [test_cli_invocation] db close forcedelete test.db test.db-journal test.db-wal diff --git a/test/shell8.test b/test/shell8.test index ddb4a47b82..bee6039232 100644 --- a/test/shell8.test +++ b/test/shell8.test @@ -19,7 +19,7 @@ set testprefix shell8 ifcapable !vtab { finish_test; return } -set CLI [test_find_cli] +set CLI [test_cli_invocation] # Check to make sure the shell has been compiled with ".archive" support. # diff --git a/test/tester.tcl b/test/tester.tcl index 9d29fdb8df..4dee3b5a8b 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -2478,7 +2478,7 @@ proc test_find_binary {nm} { } # Find the name of the 'shell' executable (e.g. "sqlite3.exe") to use for -# the tests in shell[1-5].test. If no such executable can be found, invoke +# the tests in shell*.test. If no such executable can be found, invoke # [finish_test ; return] in the callers context. # proc test_find_cli {} { @@ -2487,6 +2487,32 @@ proc test_find_cli {} { return $prog } +# Find invocation of the 'shell' executable (e.g. "sqlite3.exe") to use +# for the tests in shell*.test with optional valgrind prefix when the +# environment variable SQLITE_CLI_VALGRIND_OPT is set. The set value +# operates as follows: +# empty or 0 => no valgrind prefix; +# 1 => valgrind options for memory leak check; +# other => use value as valgrind options. +# If shell not found, invoke [finish_test ; return] in callers context. +# +proc test_cli_invocation {} { + set prog [test_find_binary sqlite3] + if {$prog==""} { return -code return } + if {[info exists ::env(SQLITE_CLI_VALGRIND_OPT)]} { + set vgo $::env(SQLITE_CLI_VALGRIND_OPT) + if {$vgo == 0 || $vgo eq ""} { + return $prog + } elseif {$vgo == 1} { + return "valgrind -q --leak-check=yes $prog" + } else { + return "valgrind $vgo $prog" + } + } else { + return $prog + } +} + # Find the name of the 'sqldiff' executable (e.g. "sqlite3.exe") to use for # the tests in sqldiff tests. If no such executable can be found, invoke # [finish_test ; return] in the callers context. From 1a5321998104db5403014f82b420ea01a90e5624 Mon Sep 17 00:00:00 2001 From: larrybr Date: Mon, 9 May 2022 18:33:14 +0000 Subject: [PATCH 004/108] Create new branch named "echo-sql" FossilOrigin-Name: 042f2935c9d07668eff6ad8a071c82aa12ccbf9a783dff7b74ddd6b4c82cf573 --- manifest | 13 ++++++++----- manifest.uuid | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/manifest b/manifest index 9377830496..78f2918525 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Minor\sSTAT4\stest\scase\schange\sdue\sto\sthe\sANALYZE\senhancement\sof\n[eb59c46a5aed69bc|check-in\seb59c46a5aed69bc]. -D 2022-05-09T17:55:34.846 +C Create\snew\sbranch\snamed\s"echo-sql" +D 2022-05-09T18:33:14.893 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -1953,8 +1953,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 387c852375bba62df040330944c9e979a6993f95ece3443597c5fc66e34263ca +P 8ce2fecb580da53fc01c53d8de10e2cc99499094215429ba925e777717e369b2 R cbb8544fd969bd1dbd19e4e7428f857d -U drh -Z 4859f8d06796c35fb9e8207cbbd745d2 +T *branch * echo-sql +T *sym-echo-sql * +T -sym-trunk * +U larrybr +Z f4321988b00d4866eeca04cb0c3ef2be # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 24609f9f4b..9874916027 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8ce2fecb580da53fc01c53d8de10e2cc99499094215429ba925e777717e369b2 \ No newline at end of file +042f2935c9d07668eff6ad8a071c82aa12ccbf9a783dff7b74ddd6b4c82cf573 \ No newline at end of file From f015a3d19ffec002dc25114d7ebc5630892a5882 Mon Sep 17 00:00:00 2001 From: larrybr Date: Tue, 10 May 2022 01:11:51 +0000 Subject: [PATCH 005/108] Cause most shell tests to be run under Tcl suite valgrind config. FossilOrigin-Name: cd085b36ff777396ac2705c030c1518f8094a70a0b0ba4a628776429524d20f0 --- manifest | 14 +++++++------- manifest.uuid | 2 +- test/permutations.test | 3 ++- test/tester.tcl | 11 ++++++++--- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index 54db67c2c8..7c801c8035 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Simplify\s.import\sleak\splug\sand\sarrange\sfor\sCLI\sto\sbe\srun\sunder\svalgrind. -D 2022-05-09T12:29:47.606 +C Cause\smost\sshell\stests\sto\sbe\srun\sunder\sTcl\ssuite\svalgrind\sconfig. +D 2022-05-10T01:11:51.402 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -1294,7 +1294,7 @@ F test/parser1.test 6ccdf5e459a5dc4673d3273dc311a7e9742ca952dd0551a6a6320d27035c F test/pcache.test c8acbedd3b6fd0f9a7ca887a83b11d24a007972b F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442 F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff -F test/permutations.test 68b6dcd2667acdc643140d502c0b6c503abe444495cf5d16aa3a4f0391604020 +F test/permutations.test cf5f31bab83a452288b2a050880152cdf99d62e9aab71948268d549debcc6942 F test/pg_common.tcl 3b27542224db1e713ae387459b5d117c836a5f6e328846922993b6d2b7640d9f F test/pragma.test cae534c12a033a5c319ccc94f50b32811acdef9f67bf19a82ff42697caccd69f F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f @@ -1482,7 +1482,7 @@ F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30 F test/temptable2.test d2940417496e2b9548e01d09990763fbe88c316504033256d51493e1f1a5ce6a F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637 F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc -F test/tester.tcl eea76fe47703d4bd2d12ddc761fb0be623f9a7b878e50a2dcb7bd6fe4b3040f1 +F test/tester.tcl f453db5abee4c60e8c3b5c6a87476da1b00ac162e9ab382b779b5dd994fab015 F test/thread001.test b61a29dd87cf669f5f6ac96124a7c97d71b0c80d9012746072055877055cf9ef F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58 F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7 @@ -1953,8 +1953,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P f5f09368b33b6af00f96e5b8f763e7ee2d00ba6af2aee0f2ca86bb58c03d0b71 -R 84088aa54a74f88fa3741dd082a651c8 +P 0d3e2380197aa3e725591266acaeb0d43a7e794ca9153e6c56253cdcf60720b1 +R 8b383cc869801f72e74e4d10a3a8a711 U larrybr -Z 4cea09d549ba44b05dc5240e31984b9e +Z 8c26ccdbc4c29d056a0925b62032154d # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index b8969acb8f..51469b9721 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0d3e2380197aa3e725591266acaeb0d43a7e794ca9153e6c56253cdcf60720b1 \ No newline at end of file +cd085b36ff777396ac2705c030c1518f8094a70a0b0ba4a628776429524d20f0 \ No newline at end of file diff --git a/test/permutations.test b/test/permutations.test index 0987daeb1d..f2710da0f1 100644 --- a/test/permutations.test +++ b/test/permutations.test @@ -217,7 +217,8 @@ test_suite "valgrind" -prefix "" -description { fail under valgrind) omitted. } -files [ test_set $allquicktests -exclude *malloc* *ioerr* *fault* *_err* wal.test \ - shell*.test crash8.test atof1.test selectG.test \ + shell2.test shell6.test shell7.test \ + crash8.test atof1.test selectG.test \ tkt-fc62af4523.test numindex1.test corruptK.test ] -initialize { set ::G(valgrind) 1 diff --git a/test/tester.tcl b/test/tester.tcl index 4dee3b5a8b..3407506c74 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -2499,12 +2499,17 @@ proc test_find_cli {} { proc test_cli_invocation {} { set prog [test_find_binary sqlite3] if {$prog==""} { return -code return } - if {[info exists ::env(SQLITE_CLI_VALGRIND_OPT)]} { - set vgo $::env(SQLITE_CLI_VALGRIND_OPT) + set vgrun [expr {[permutation]=="valgrind"}] + if {$vgrun || [info exists ::env(SQLITE_CLI_VALGRIND_OPT)]} { + if {$vgrun} { + set vgo "--quiet" + } else { + set vgo $::env(SQLITE_CLI_VALGRIND_OPT) + } if {$vgo == 0 || $vgo eq ""} { return $prog } elseif {$vgo == 1} { - return "valgrind -q --leak-check=yes $prog" + return "valgrind --quiet --leak-check=yes $prog" } else { return "valgrind $vgo $prog" } From 527c39de8002d777e2865578e222987387004984 Mon Sep 17 00:00:00 2001 From: larrybr Date: Tue, 10 May 2022 14:55:45 +0000 Subject: [PATCH 006/108] For CLI, add ".echo sql" dot-command. FossilOrigin-Name: 35cef458ca114649ee16e00714d817d57673b96c007454946cc411ae90fd06ce --- manifest | 17 +++++++---------- manifest.uuid | 2 +- src/shell.c.in | 44 ++++++++++++++++++++++++++++++-------------- test/shell1.test | 4 ++-- 4 files changed, 40 insertions(+), 27 deletions(-) diff --git a/manifest b/manifest index 78f2918525..cbf88beb38 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Create\snew\sbranch\snamed\s"echo-sql" -D 2022-05-09T18:33:14.893 +C For\sCLI,\sadd\s".echo\ssql"\sdot-command. +D 2022-05-10T14:55:45.872 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -554,7 +554,7 @@ F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c e9ee235c4151d2b7fa47435a219bfd30bf516a804d2f004639858087ebf3137b F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c 6c0fba59d2a74bf606065f23e3bb6a8f29106c84f90ec34290ac4245e83b918c -F src/shell.c.in ae0a6fae983caac6f8c824733f0599dfdf7b3a7e8efdef3cb5e3ab2e457ffc35 +F src/shell.c.in af2e55dbd1b3d1ea5b8c677f815ec8180aefef22299996f8ae64090d02d51aca F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h f49e28c25bd941e79794db5415fdf7b202deb3bc072ed6f1ed273d578703684e @@ -1397,7 +1397,7 @@ F test/sharedA.test 49d87ec54ab640fbbc3786ee3c01de94aaa482a3a9f834ad3fe92770eb69 F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939 F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304 -F test/shell1.test f7a2ef8260aa01f20be3185118213b1ae70518fdcd2105f3e25b021b5ca800ac +F test/shell1.test eb2a7b768a1a20d70a8a205b11a8e3fd94b7f8d98d45aa9fb90433202609b0c3 F test/shell2.test 7a3a23a9f57b99453f1679b1fe8072cb30e382a622874c0c4d97695fadb0a787 F test/shell3.test a50628ab1d78d90889d9d3f32fb2c084ee15674771e96afe954aaa0accd1de3c F test/shell4.test 8f6c0fce4abed19a8a7f7262517149812a04caa905d01bdc8f5e92573504b759 @@ -1953,11 +1953,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 8ce2fecb580da53fc01c53d8de10e2cc99499094215429ba925e777717e369b2 -R cbb8544fd969bd1dbd19e4e7428f857d -T *branch * echo-sql -T *sym-echo-sql * -T -sym-trunk * +P 042f2935c9d07668eff6ad8a071c82aa12ccbf9a783dff7b74ddd6b4c82cf573 +R 07eb71d25f3d8f2bd4c7dba58c10c9bc U larrybr -Z f4321988b00d4866eeca04cb0c3ef2be +Z 3914159597ff5b5d38d2aff90cf08aad # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 9874916027..3a75e353d5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -042f2935c9d07668eff6ad8a071c82aa12ccbf9a783dff7b74ddd6b4c82cf573 \ No newline at end of file +35cef458ca114649ee16e00714d817d57673b96c007454946cc411ae90fd06ce \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index 95a32f5247..1f446cadb9 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -1191,10 +1191,11 @@ struct ShellState { #define SHFLG_PreserveRowid 0x00000008 /* .dump preserves rowid values */ #define SHFLG_Newlines 0x00000010 /* .dump --newline flag */ #define SHFLG_CountChanges 0x00000020 /* .changes setting */ -#define SHFLG_Echo 0x00000040 /* .echo or --echo setting */ -#define SHFLG_HeaderSet 0x00000080 /* showHeader has been specified */ -#define SHFLG_DumpDataOnly 0x00000100 /* .dump show data only */ -#define SHFLG_DumpNoSys 0x00000200 /* .dump omits system tables */ +#define SHFLG_Echo 0x00000040 /* .echo on/off, or --echo setting */ +#define SHFLG_EchoSql 0x00000080 /* .echo sql, before prepare */ +#define SHFLG_HeaderSet 0x00000100 /* showHeader has been specified */ +#define SHFLG_DumpDataOnly 0x00000200 /* .dump show data only */ +#define SHFLG_DumpNoSys 0x00000400 /* .dump omits system tables */ /* ** Macros for testing and setting shellFlgs @@ -3796,6 +3797,11 @@ static int shell_exec( } #endif + /* Echo the sql statement(s) if echoing SQL early (before prepare.) */ + if( pArg && ShellHasFlag(pArg, SHFLG_EchoSql) ){ + utf8_printf(pArg->out, "%s\n", zSql); + } + while( zSql[0] && (SQLITE_OK == rc) ){ static const char *zStmtSql; rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover); @@ -3824,7 +3830,6 @@ static int shell_exec( if( pArg && ShellHasFlag(pArg, SHFLG_Echo) ){ utf8_printf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql); } - /* Show the EXPLAIN QUERY PLAN if .eqp is on */ if( pArg && pArg->autoEQP && sqlite3_stmt_isexplain(pStmt)==0 ){ sqlite3_stmt *pExplain; @@ -8437,8 +8442,8 @@ static int do_meta_command(char *zLine, ShellState *p){ int i; int savedShowHeader = p->showHeader; int savedShellFlags = p->shellFlgs; - ShellClearFlag(p, - SHFLG_PreserveRowid|SHFLG_Newlines|SHFLG_Echo + ShellClearFlag(p, + SHFLG_PreserveRowid|SHFLG_Newlines|SHFLG_Echo|SHFLG_EchoSql |SHFLG_DumpDataOnly|SHFLG_DumpNoSys); for(i=1; imode = MODE_Csv; sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma); sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf); @@ -10629,7 +10639,8 @@ static int do_meta_command(char *zLine, ShellState *p){ goto meta_command_exit; } utf8_printf(p->out, "%12.12s: %s\n","echo", - azBool[ShellHasFlag(p, SHFLG_Echo)]); + (ShellHasFlag(p, SHFLG_EchoSql)) + ? "sql" : azBool[ShellHasFlag(p, SHFLG_Echo)]); utf8_printf(p->out, "%12.12s: %s\n","eqp", azBool[p->autoEQP&3]); utf8_printf(p->out, "%12.12s: %s\n","explain", p->mode==MODE_Explain ? "on" : p->autoExplain ? "auto" : "off"); @@ -11379,7 +11390,7 @@ static QuickScanState quickscan(char *zLine, QuickScanState qss){ cWait = 0; qss = QSS_SETV(qss, 0); goto PlainScan; - default: assert(0); + default: assert(0); } } } @@ -11400,7 +11411,7 @@ static int line_is_command_terminator(char *zLine){ zLine += 2; /* SQL Server */ else return 0; - return quickscan(zLine,QSS_Start)==QSS_Start; + return quickscan(zLine, QSS_Start)==QSS_Start; } /* @@ -11722,7 +11733,8 @@ static const char zOptions[] = #if !defined(SQLITE_OMIT_DESERIALIZE) " -deserialize open the database using sqlite3_deserialize()\n" #endif - " -echo print commands before execution\n" + " -echo print inputs before execution\n" + " -echo-sql print SQL before prepare\n" " -init FILENAME read/process named file\n" " -[no]header turn headers on or off\n" #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) @@ -12229,7 +12241,11 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ data.showHeader = 0; ShellSetFlag(&data, SHFLG_HeaderSet); }else if( strcmp(z,"-echo")==0 ){ + ShellClearFlag(&data, SHFLG_EchoSql); ShellSetFlag(&data, SHFLG_Echo); + }else if( strcmp(z,"-echo-sql")==0 ){ + ShellClearFlag(&data, SHFLG_Echo); + ShellSetFlag(&data, SHFLG_EchoSql); }else if( strcmp(z,"-eqp")==0 ){ data.autoEQP = AUTOEQP_on; }else if( strcmp(z,"-eqpfull")==0 ){ diff --git a/test/shell1.test b/test/shell1.test index 3c7061c55d..f2aac1a524 100644 --- a/test/shell1.test +++ b/test/shell1.test @@ -313,7 +313,7 @@ do_test shell1-3.4.2 { # .echo ON|OFF Turn command echo on or off do_test shell1-3.5.1 { catchcmd "test.db" ".echo" -} {1 {Usage: .echo on|off}} +} {1 {Usage: .echo on|off|sql}} do_test shell1-3.5.2 { catchcmd "test.db" ".echo ON" } {0 {}} @@ -323,7 +323,7 @@ do_test shell1-3.5.3 { do_test shell1-3.5.4 { # too many arguments catchcmd "test.db" ".echo OFF BAD" -} {1 {Usage: .echo on|off}} +} {1 {Usage: .echo on|off|sql}} # .exit Exit this program do_test shell1-3.6.1 { From de695eab882de2537bbba4160fb2629dc21a544a Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 10 May 2022 15:55:10 +0000 Subject: [PATCH 007/108] Fix a harmless UBSAN warning. FossilOrigin-Name: 8f9355028bc7baeeb10ee9a5e29f093adac6c2f149596dec0be827be4ce491cb --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/select.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index e7fde4d1c6..ca99a17505 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Simplified\s"hidden"\sand\s"no-expand"\shandling\sin\sthe\s*-expander. -D 2022-05-10T00:24:01.438 +C Fix\sa\sharmless\sUBSAN\swarning. +D 2022-05-10T15:55:10.266 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -553,7 +553,7 @@ F src/printf.c 512574910a45341c8ad244bd3d4939968ebdfde215645b676fff01cc46e90757 F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c e9ee235c4151d2b7fa47435a219bfd30bf516a804d2f004639858087ebf3137b F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 -F src/select.c cd17de0cab436f0efc4cfeeeef1b8e03c41c40335ec757eff68e341e6a3f763f +F src/select.c 5096a2e8ab0511a413e7f5e45453fea4102d99c5636c46792581ae67899a76d7 F src/shell.c.in ae0a6fae983caac6f8c824733f0599dfdf7b3a7e8efdef3cb5e3ab2e457ffc35 F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 @@ -1953,8 +1953,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 8ce2fecb580da53fc01c53d8de10e2cc99499094215429ba925e777717e369b2 -R 1d734b9b8260c8ccdbe3f05b6dc084ca +P c6c3115f3a008cf9b0d7c5c812f17e38c8a75a904032c5f05f0bea03a7340527 +R 2807b2267081068427cca811153cf146 U drh -Z 5869ac2082a6ad38c03068b658209d1b +Z ee606463c5289401618f87c78d0ff20c # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index cc85684e99..2383f63a7f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c6c3115f3a008cf9b0d7c5c812f17e38c8a75a904032c5f05f0bea03a7340527 \ No newline at end of file +8f9355028bc7baeeb10ee9a5e29f093adac6c2f149596dec0be827be4ce491cb \ No newline at end of file diff --git a/src/select.c b/src/select.c index b53c0c9151..e767aa0153 100644 --- a/src/select.c +++ b/src/select.c @@ -7707,7 +7707,7 @@ int sqlite3Select( eDist = sqlite3WhereIsDistinct(pWInfo); updateAccumulator(pParse, regAcc, pAggInfo, eDist); if( eDist!=WHERE_DISTINCT_NOOP ){ - struct AggInfo_func *pF = &pAggInfo->aFunc[0]; + struct AggInfo_func *pF = pAggInfo->aFunc; if( pF ){ fixDistinctOpenEph(pParse, eDist, pF->iDistinct, pF->iDistAddr); } From d2b960cf41f9642d84e997137c66788a10b3cbf8 Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 10 May 2022 17:42:55 +0000 Subject: [PATCH 008/108] Fix a stale requirement mark. FossilOrigin-Name: 3eda4030f73384abf18b97cd8a4606e10b23e382d1b72dff7526aebfde23e0af --- manifest | 14 +++++++------- manifest.uuid | 2 +- test/e_select.test | 7 ++++--- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index 58b04384af..e13b717e7c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Sync\sw/\strunk -D 2022-05-10T14:57:38.059 +C Fix\sa\sstale\srequirement\smark. +D 2022-05-10T17:42:55.876 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -879,7 +879,7 @@ F test/e_fts3.test 17ba7c373aba4d4f5696ba147ee23fd1a1ef70782af050e03e262ca187c5e F test/e_insert.test f02f7f17852b2163732c6611d193f84fc67bc641fb4882c77a464076e5eba80e F test/e_reindex.test 2b0e29344497d9a8a999453a003cb476b6b1d2eef2d6c120f83c2d3a429f3164 F test/e_resolve.test a61751c368b109db73df0f20fc75fb47e166b1d8 -F test/e_select.test 9b7ca08975c5444844b35ee60e09f973787a9f3317719715e8e6669abdf6aba2 +F test/e_select.test 89fa483f68d868f1be3d6f56180ed42d979979c266e051bf8b5e66a251e6b44a F test/e_select2.test aceb80ab927d46fba5ce7586ebabf23e2bb0604f F test/e_totalchanges.test c927f7499dc3aa28b9b556b7d6d115a2f0fe41f012b128d16bf1f3b30e9b41e4 F test/e_update.test f46c2554d915c9197548681e8d8c33a267e84528 @@ -1953,8 +1953,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 35cef458ca114649ee16e00714d817d57673b96c007454946cc411ae90fd06ce c6c3115f3a008cf9b0d7c5c812f17e38c8a75a904032c5f05f0bea03a7340527 -R f7b2f45a58e73d19b8d50de0bb6840c3 -U larrybr -Z 774454cea980d5e07191a21244229d21 +P b7285f92bb9bfd8471e51ee5b6dbd7030b1f731683876e8ecca4a8c033688736 +R 72fca0ee51c12a7f90dd5313ccb28616 +U drh +Z 747367051d653b31d41a6b7e7bda4d15 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 152665be1f..a070db8f67 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b7285f92bb9bfd8471e51ee5b6dbd7030b1f731683876e8ecca4a8c033688736 \ No newline at end of file +3eda4030f73384abf18b97cd8a4606e10b23e382d1b72dff7526aebfde23e0af \ No newline at end of file diff --git a/test/e_select.test b/test/e_select.test index 1ffd4021b6..5a3f0d30dc 100644 --- a/test/e_select.test +++ b/test/e_select.test @@ -618,11 +618,12 @@ foreach {tn select res} { } { do_join_test e_select-1.7.$tn $select $res } -# EVIDENCE-OF: R-42531-52874 If the join-operator is a "LEFT JOIN" or + +# EVIDENCE-OF: R-24610-05866 If the join-operator is a "LEFT JOIN" or # "LEFT OUTER JOIN", then after the ON or USING filtering clauses have # been applied, an extra row is added to the output for each row in the -# original left-hand input dataset that corresponds to no rows at all in -# the composite dataset (if any). +# original left-hand input dataset that does not match any row in the +# right-hand dataset. # do_execsql_test e_select-1.8.0 { CREATE TABLE t7(a, b, c); From 0338f53b05bf38602f9b226f7be904396a30a80e Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 10 May 2022 18:18:45 +0000 Subject: [PATCH 009/108] Fix a stale requirement mark. FossilOrigin-Name: fcda7fb1f184a31a67572aae15f3cdcd60f8aac199106a7b0f90aca251ca7017 --- manifest | 13 +++++++------ manifest.uuid | 2 +- test/e_select.test | 7 ++++--- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index ca99a17505..6bb848b2c2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sharmless\sUBSAN\swarning. -D 2022-05-10T15:55:10.266 +C Fix\sa\sstale\srequirement\smark. +D 2022-05-10T18:18:45.504 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -879,7 +879,7 @@ F test/e_fts3.test 17ba7c373aba4d4f5696ba147ee23fd1a1ef70782af050e03e262ca187c5e F test/e_insert.test f02f7f17852b2163732c6611d193f84fc67bc641fb4882c77a464076e5eba80e F test/e_reindex.test 2b0e29344497d9a8a999453a003cb476b6b1d2eef2d6c120f83c2d3a429f3164 F test/e_resolve.test a61751c368b109db73df0f20fc75fb47e166b1d8 -F test/e_select.test 9b7ca08975c5444844b35ee60e09f973787a9f3317719715e8e6669abdf6aba2 +F test/e_select.test 89fa483f68d868f1be3d6f56180ed42d979979c266e051bf8b5e66a251e6b44a F test/e_select2.test aceb80ab927d46fba5ce7586ebabf23e2bb0604f F test/e_totalchanges.test c927f7499dc3aa28b9b556b7d6d115a2f0fe41f012b128d16bf1f3b30e9b41e4 F test/e_update.test f46c2554d915c9197548681e8d8c33a267e84528 @@ -1953,8 +1953,9 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P c6c3115f3a008cf9b0d7c5c812f17e38c8a75a904032c5f05f0bea03a7340527 -R 2807b2267081068427cca811153cf146 +P 8f9355028bc7baeeb10ee9a5e29f093adac6c2f149596dec0be827be4ce491cb +Q +3eda4030f73384abf18b97cd8a4606e10b23e382d1b72dff7526aebfde23e0af +R ad1a743739340ac35d67b569c30d27a5 U drh -Z ee606463c5289401618f87c78d0ff20c +Z a581d18ac49ad52a81b01edb2bbc696b # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 2383f63a7f..5e403d2fa4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8f9355028bc7baeeb10ee9a5e29f093adac6c2f149596dec0be827be4ce491cb \ No newline at end of file +fcda7fb1f184a31a67572aae15f3cdcd60f8aac199106a7b0f90aca251ca7017 \ No newline at end of file diff --git a/test/e_select.test b/test/e_select.test index 1ffd4021b6..5a3f0d30dc 100644 --- a/test/e_select.test +++ b/test/e_select.test @@ -618,11 +618,12 @@ foreach {tn select res} { } { do_join_test e_select-1.7.$tn $select $res } -# EVIDENCE-OF: R-42531-52874 If the join-operator is a "LEFT JOIN" or + +# EVIDENCE-OF: R-24610-05866 If the join-operator is a "LEFT JOIN" or # "LEFT OUTER JOIN", then after the ON or USING filtering clauses have # been applied, an extra row is added to the output for each row in the -# original left-hand input dataset that corresponds to no rows at all in -# the composite dataset (if any). +# original left-hand input dataset that does not match any row in the +# right-hand dataset. # do_execsql_test e_select-1.8.0 { CREATE TABLE t7(a, b, c); From 825ecf9c055c6b3ba9ef1c319cbcf933dca12c7a Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 10 May 2022 18:43:54 +0000 Subject: [PATCH 010/108] New requirement marks. FossilOrigin-Name: e8479e56c615a6eb38b58e6d360bea8528ec14a9d7b0798b95d3eb513bd08f0f --- manifest | 17 ++++++++--------- manifest.uuid | 2 +- test/join.test | 16 ++++++++++++++++ test/join8.test | 23 +++++++++++++++++++++++ test/vtab6.test | 4 ++++ 5 files changed, 52 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 6bb848b2c2..70c67e0168 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sstale\srequirement\smark. -D 2022-05-10T18:18:45.504 +C New\srequirement\smarks. +D 2022-05-10T18:43:54.263 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -1141,14 +1141,14 @@ F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4 F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b F test/istrue.test e7f285bb70282625c258e866ce6337d4c762922f5a300e1b50f958aef6e7d9c9 -F test/join.test e5f165dfd84fd46406ddae6614b0122c3bfa23a26ef62966442e1503c40d96aa +F test/join.test edeaff6edc1c1a2bcfebee343744e04d000f861c3d67cb653114f88565f8c955 F test/join2.test 466b07233820f5deee66a6c3bf6e4500c8bbf7b83649e67606f5f649c07928c0 F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join5.test d22b6cba8fb59ab3f1c82701434c360705eb12d4ce200c449f37b018fc47681a F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c F test/join7.test 8e72de4b45e5e930d18c305c7efe86015fb2552731e4e03ea226353036b0dab0 -F test/join8.test 68f5ec206cd88610c19ab8edb4789a174a55cdb1732619a95db8fd33dbb13783 +F test/join8.test fef259c42d56bbe150b777726b185b0bc060d4290daf9f879abc68321f8ad6db F test/join9.test 9056ddd3b0c0f4f9d658f4521038d9a37dc23ead8ca9a505d0b0db2b6a471e05 F test/joinA.test 7eab225dc1c1ab258a5e62513a4ed7cabbd3db971d59d5d92f4fb6fa14c12f6a F test/joinB.test 1b2ba3fc8568b49411787fccbf540570c148e9b6a53a30f80691cb6268098ded @@ -1719,7 +1719,7 @@ F test/vtab2.test 14d4ab26cee13ba6cf5c5601b158e4f57552d3b055cdd9406cf7f711e9c840 F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e F test/vtab4.test 8e73ed268f3d596bc3590f45fc948fb40f28e9c3 F test/vtab5.test 889f444970393c73f1e077e2bdc5d845e157a391 -F test/vtab6.test fa609a4af96da30beceefa3cb624abe9be38c4747ab373d98179b24027d6b798 +F test/vtab6.test 2525a2fe2e44ccbed1d758cb2977fb8ab8f07d5312ed8d8799d3529647d11f2f F test/vtab7.test 70c6f4a1d6177144a8236e4172d5fba92e683440374664ad1f04851fbb335d3c F test/vtab8.test e19fa4a538fcd1bb66c22825fa8f71618fb13583 F test/vtab9.test ea58d2b95d61955f87226381716b2d0b1d4e4f9b @@ -1953,9 +1953,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 8f9355028bc7baeeb10ee9a5e29f093adac6c2f149596dec0be827be4ce491cb -Q +3eda4030f73384abf18b97cd8a4606e10b23e382d1b72dff7526aebfde23e0af -R ad1a743739340ac35d67b569c30d27a5 +P fcda7fb1f184a31a67572aae15f3cdcd60f8aac199106a7b0f90aca251ca7017 +R 696e923f15f9da5ccd48142298e15665 U drh -Z a581d18ac49ad52a81b01edb2bbc696b +Z 324ce18ac7f904101887dd5ff565ea9a # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 5e403d2fa4..de6635c4e1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -fcda7fb1f184a31a67572aae15f3cdcd60f8aac199106a7b0f90aca251ca7017 \ No newline at end of file +e8479e56c615a6eb38b58e6d360bea8528ec14a9d7b0798b95d3eb513bd08f0f \ No newline at end of file diff --git a/test/join.test b/test/join.test index 38cfb74569..09ede1a4af 100644 --- a/test/join.test +++ b/test/join.test @@ -250,6 +250,19 @@ do_test join-2.1 { } } {1 2 3 4 2 3 4 5 3 4 5 {}} +# EVIDENCE-OF: R-52129-05406 you can say things like "OUTER LEFT NATURAL +# JOIN" which means the same as "NATURAL LEFT OUTER JOIN". +do_test join-2.1b { + execsql { + SELECT * FROM t1 OUTER LEFT NATURAL JOIN t2; + } +} {1 2 3 4 2 3 4 5 3 4 5 {}} +do_test join-2.1c { + execsql { + SELECT * FROM t1 NATURAL LEFT OUTER JOIN t2; + } +} {1 2 3 4 2 3 4 5 3 4 5 {}} + # ticket #3522 do_test join-2.1.1 { execsql2 { @@ -328,6 +341,9 @@ do_test join-3.6 { SELECT * FROM t1 JOIN t2 ON t3.a=t2.b; } } {1 {no such column: t3.a}} + +# EVIDENCE-OF: R-47973-48020 you cannot say "INNER OUTER JOIN", because +# that would be contradictory. do_test join-3.7 { catchsql { SELECT * FROM t1 INNER OUTER JOIN t2; diff --git a/test/join8.test b/test/join8.test index 3a3b06a1c4..ab05722912 100644 --- a/test/join8.test +++ b/test/join8.test @@ -20,6 +20,8 @@ ifcapable !vtab { } db null NULL +# EVIDENCE-OF: R-33754-02880 you can say "LEFT RIGHT JOIN" which is the +# same as "FULL JOIN". do_execsql_test join8-10 { CREATE TABLE t1(a,b,c); CREATE TABLE t2(x,y); @@ -226,6 +228,27 @@ do_execsql_test join8-7010 { - - - - - - - - 305 5 - - - - - - - - 310 10 } + +# EVIDENCE-OF: R-33754-02880 you can say "LEFT RIGHT JOIN" which is the +# same as "FULL JOIN". +do_execsql_test join8-7011 { + WITH t0 AS MATERIALIZED ( + SELECT t1.*, t2.*, t3.* + FROM t1 INNER JOIN t2 ON t1.b=t2.b AND t2.x>0 + RIGHT JOIN t3 ON t1.c=t3.c AND t3.y>0 + ) + SELECT * FROM t0 LEFT RIGHT JOIN t4 ON t0.a=t4.d AND t4.z>0 + ORDER BY coalesce(t0.a, t0.y+200, t4.d); +} { + 6 106 206 306 106 6 206 6 - - + - - - - - - 200 0 - - + - - - - - - 203 3 - - + - - - - - - 209 9 - - + - - - - - - - - 300 0 + - - - - - - - - 305 5 + - - - - - - - - 310 10 +} + do_execsql_test join8-7020 { EXPLAIN QUERY PLAN WITH t0 AS MATERIALIZED ( diff --git a/test/vtab6.test b/test/vtab6.test index 2ee5e27051..1c220e11fe 100644 --- a/test/vtab6.test +++ b/test/vtab6.test @@ -277,11 +277,15 @@ do_test vtab6-3.6 { SELECT * FROM t1 JOIN t2 ON t3.a=t2.b; } } {1 {no such column: t3.a}} + +# EVIDENCE-OF: R-47973-48020 you cannot say "INNER OUTER JOIN", because +# that would be contradictory. do_test vtab6-3.7 { catchsql { SELECT * FROM t1 INNER OUTER JOIN t2; } } {1 {unknown join type: INNER OUTER}} + do_test vtab6-3.7 { catchsql { SELECT * FROM t1 LEFT BOGUS JOIN t2; From cc212e4450e5a3f38b88508f1e3d90045deb8fd1 Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 10 May 2022 23:28:12 +0000 Subject: [PATCH 011/108] Fix a bug in the sqlite3WhereMalloc() routines that were added by chekc-in [f237e1d8cc41b937]. The bug was detected by dbsqlfuzz test case 4c5e3e89bc251d28378be88233f531b84ec66901. FossilOrigin-Name: 764b71267e0b31ff7eaf2a0def7526a1a02dce4d5b456dea060d97ed342efdd1 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/whereInt.h | 2 +- test/where.test | 16 +++++++++++++++- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 70c67e0168..6950e71c35 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C New\srequirement\smarks. -D 2022-05-10T18:43:54.263 +C Fix\sa\sbug\sin\sthe\ssqlite3WhereMalloc()\sroutines\sthat\swere\sadded\sby\nchekc-in\s[f237e1d8cc41b937].\s\sThe\sbug\swas\sdetected\sby\sdbsqlfuzz\ntest\scase\s4c5e3e89bc251d28378be88233f531b84ec66901. +D 2022-05-10T23:28:12.577 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -641,7 +641,7 @@ F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b F src/where.c aa585b89bd65a81e44bdfb871b55f65bf8fda88e1bc85efda6c236fe8d2bd788 -F src/whereInt.h 4db5a877a9d1f38b5c928c1c84297c07f30b9a3bc1f5f66214cf1a8ef90a0556 +F src/whereInt.h 8da918f392bf202ccc0ee61291455b33ad171d209445f1ff3eaf62e0b6f6b363 F src/wherecode.c 72f8eeed5527450c8e2258160a7bd04534a76c161230d100da0f43a86c6e29ac F src/whereexpr.c e036477ac8424de50ae5b36a71103405d3f86b33ba11125ec7a2a99d501b0622 F src/window.c fff1b51757438c664e471d5184634e48dcdf8ea34b640f3b1b0810b1e06de18c @@ -1777,7 +1777,7 @@ F test/walthread.test 14b20fcfa6ae152f5d8e12f5dc8a8a724b7ef189f5d8ef1e2ceab79f2a F test/walvfs.test bccb3e0d235ef85e276f491d34db32c9ada1ea67be8d9f10aabe7b30319ec656 F test/wapp.tcl b440cd8cf57953d3a49e7ee81e6a18f18efdaf113b69f7d8482b0710a64566ec F test/wapptest.tcl 899594e25684861d5b0c0880fb012364def50ef8097041b8ddf74be5ba7fa270 x -F test/where.test 8c6bbd0cae8feae142a7946e3484a802fa566bacf38452b1c3e48cb77321f9a4 +F test/where.test d13cd7c24e80009d2b54e2f7a8893c457afa49c64f99359c9eb3fe668ba1d9d4 F test/where2.test 03c21a11e7b90e2845fc3c8b4002fc44cc2797fa74c86ee47d70bd7ea4f29ed6 F test/where3.test 5b4ffc0ac2ea0fe92f02b1244b7531522fe4d7bccf6fa8741d54e82c10e67753 F test/where4.test 4a371bfcc607f41d233701bdec33ac2972908ba8 @@ -1953,8 +1953,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P fcda7fb1f184a31a67572aae15f3cdcd60f8aac199106a7b0f90aca251ca7017 -R 696e923f15f9da5ccd48142298e15665 +P e8479e56c615a6eb38b58e6d360bea8528ec14a9d7b0798b95d3eb513bd08f0f +R 138cd6c9984d4a6160f946571e22144b U drh -Z 324ce18ac7f904101887dd5ff565ea9a +Z 0d2c71b3b15aea0bdd92f3cefbd28a5b # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index de6635c4e1..21cc4dc141 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e8479e56c615a6eb38b58e6d360bea8528ec14a9d7b0798b95d3eb513bd08f0f \ No newline at end of file +764b71267e0b31ff7eaf2a0def7526a1a02dce4d5b456dea060d97ed342efdd1 \ No newline at end of file diff --git a/src/whereInt.h b/src/whereInt.h index 93ab937c88..41417d2e7f 100644 --- a/src/whereInt.h +++ b/src/whereInt.h @@ -41,7 +41,7 @@ typedef struct WhereRightJoin WhereRightJoin; */ struct WhereMemBlock { WhereMemBlock *pNext; /* Next block in the chain */ - u8 sz; /* Bytes of space */ + u64 sz; /* Bytes of space */ }; /* diff --git a/test/where.test b/test/where.test index 2f53f2cb49..e28861bc10 100644 --- a/test/where.test +++ b/test/where.test @@ -11,7 +11,6 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the use of indices in WHERE clases. # -# $Id: where.test,v 1.50 2008/11/03 09:06:06 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -1603,4 +1602,19 @@ if {[permutation]!="valgrind"} { } {0} } +# 2022-05-10 dbsqlfuzz 4c5e3e89bc251d28378be88233f531b84ec66901 +# +reset_db +do_execsql_test where-28.1 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b INT); + CREATE INDEX t1b ON t1(b,b,b,b,b,b,b,b,b,b,b,b,b); + INSERT INTO t1(a,b) VALUES(1,1),(15,2),(19,5); + UPDATE t1 SET b=999 WHERE a IN (SELECT 15) AND b IN (1,2); + SELECT * FROM t1; +} { + 1 1 + 15 999 + 19 5 +} + finish_test From e8346d0a889c89ec8a78e65abc33257a6c6fb81a Mon Sep 17 00:00:00 2001 From: drh <> Date: Wed, 11 May 2022 16:46:27 +0000 Subject: [PATCH 012/108] For the unix VFS, rewrite the xFullPathname method so that it automatically resolves all symbolic links, rendering a canonical pathname that contains no symlinks. FossilOrigin-Name: 40c9273d0e0e74e1df22e996a5d486e838f4320defd2121e2d95eeed8aea6235 --- manifest | 17 ++-- manifest.uuid | 2 +- src/os.h | 7 ++ src/os_unix.c | 253 ++++++++++++++++++++------------------------------ 4 files changed, 121 insertions(+), 158 deletions(-) diff --git a/manifest b/manifest index 6950e71c35..506b6ed4cc 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sbug\sin\sthe\ssqlite3WhereMalloc()\sroutines\sthat\swere\sadded\sby\nchekc-in\s[f237e1d8cc41b937].\s\sThe\sbug\swas\sdetected\sby\sdbsqlfuzz\ntest\scase\s4c5e3e89bc251d28378be88233f531b84ec66901. -D 2022-05-10T23:28:12.577 +C For\sthe\sunix\sVFS,\srewrite\sthe\sxFullPathname\smethod\sso\sthat\sit\sautomatically\nresolves\sall\ssymbolic\slinks,\srendering\sa\scanonical\spathname\sthat\scontains\nno\ssymlinks. +D 2022-05-11T16:46:27.636 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -534,10 +534,10 @@ F src/mutex_unix.c dd2b3f1cc1863079bc1349ac0fec395a500090c4fe4e11ab775310a49f2f9 F src/mutex_w32.c caa50e1c0258ac4443f52e00fe8aaea73b6d0728bd8856bedfff822cae418541 F src/notify.c 89a97dc854c3aa62ad5f384ef50c5a4a11d70fcc69f86de3e991573421130ed6 F src/os.c b1c4f2d485961e9a5b6b648c36687d25047c252222e9660b7cc25a6e1ea436ab -F src/os.h 26890f540b475598cd9881dcc68931377b8d429d3ea3e2eeb64470cde64199f8 +F src/os.h 1ff5ae51d339d0e30d8a9d814f4b8f8e448169304d83a7ed9db66a65732f3e63 F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85 F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586 -F src/os_unix.c 1f71ec8c87621f75c9c5ea973f5e8ce2f1d23fe760c01ed2814fe4b98b639825 +F src/os_unix.c 33fe706af9423563d4c7d4148e9f8bc1fb4b3669c4e32e66b5f1b963c6225f61 F src/os_win.c a8ea80037e81127ca01959daa87387cc135f325c88dc745376c4f760de852a10 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a F src/pager.c 42120492784fc9bcd9082b5c9b5e329b7318c357f9f3574a1bbfcf7418910356 @@ -1953,8 +1953,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P e8479e56c615a6eb38b58e6d360bea8528ec14a9d7b0798b95d3eb513bd08f0f -R 138cd6c9984d4a6160f946571e22144b +P 764b71267e0b31ff7eaf2a0def7526a1a02dce4d5b456dea060d97ed342efdd1 +R 569af1c5eabca94740251c005b203dc3 +T *branch * resolve-symlinks +T *sym-resolve-symlinks * +T -sym-trunk * U drh -Z 0d2c71b3b15aea0bdd92f3cefbd28a5b +Z ce762f1e70449d535056ec1fff3f1e36 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 21cc4dc141..bc8e305b6b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -764b71267e0b31ff7eaf2a0def7526a1a02dce4d5b456dea060d97ed342efdd1 \ No newline at end of file +40c9273d0e0e74e1df22e996a5d486e838f4320defd2121e2d95eeed8aea6235 \ No newline at end of file diff --git a/src/os.h b/src/os.h index 1a8eff3298..aeb01721c2 100644 --- a/src/os.h +++ b/src/os.h @@ -39,6 +39,13 @@ # define SQLITE_MAX_PATHLEN FILENAME_MAX #endif +/* Maximum number of symlinks that will be resolved while trying to +** expand a filename in xFullPathname() in the VFS. +*/ +#ifndef SQLITE_MAX_SYMLINK +# define SQLITE_MAX_SYMLINK 200 +#endif + /* ** The default size of a disk sector */ diff --git a/src/os_unix.c b/src/os_unix.c index 03ac3e46c9..b9beb53aad 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -6423,86 +6423,99 @@ static int unixAccess( } /* -** If the last component of the pathname in z[0]..z[j-1] is something -** other than ".." then back it out and return true. If the last -** component is empty or if it is ".." then return false. +** A pathname under construction */ -static int unixBackupDir(const char *z, int *pJ){ - int j = *pJ; - int i; - if( j<=0 ) return 0; - for(i=j-1; i>0 && z[i-1]!='/'; i--){} - if( i==0 ) return 0; - if( z[i]=='.' && i==j-2 && z[i+1]=='.' ) return 0; - *pJ = i-1; - return 1; +typedef struct DbPath DbPath; +struct DbPath { + int rc; /* Non-zero following any error */ + int nSymlink; /* Number of symlinks resolved */ + char *zOut; /* Write the pathname here */ + int nOut; /* Bytes of space available to zOut[] */ + int nUsed; /* Bytes of zOut[] currently being used */ +}; + +/* Forward reference */ +static void appendAllPathElements(DbPath*,const char*); + +/* +** Append a single path element to the DbPath under construction +*/ +static void appendOnePathElement( + DbPath *pPath, /* Path under construction, to which to append zName */ + const char *zName, /* Name to append to pPath. Not zero-terminated */ + int nName /* Number of significant bytes in zName */ +){ + assert( nName>0 ); + assert( zName!=0 ); + if( zName[0]=='.' ){ + if( nName==1 ) return; + if( zName[1]=='.' && nName==2 ){ + if( pPath->nUsed<=1 ){ + pPath->rc = SQLITE_ERROR; + return; + } + assert( pPath->zOut[0]=='/' ); + while( pPath->zOut[--pPath->nUsed]!='/' ){} + return; + } + } + if( pPath->nUsed + nName + 2 >= pPath->nOut ){ + pPath->rc = SQLITE_ERROR; + return; + } + pPath->zOut[pPath->nUsed++] = '/'; + memcpy(&pPath->zOut[pPath->nUsed], zName, nName); + pPath->nUsed += nName; +#if defined(HAVE_READLINK) && defined(HAVE_LSTAT) + if( pPath->rc==SQLITE_OK ){ + const char *zIn; + struct stat buf; + pPath->zOut[pPath->nUsed] = 0; + zIn = pPath->zOut; + if( osLstat(zIn, &buf)!=0 ){ + if( errno!=ENOENT ){ + pPath->rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat", zIn); + } + }else if( S_ISLNK(buf.st_mode) ){ + ssize_t got; + char zLnk[SQLITE_MAX_PATHLEN+2]; + if( pPath->nSymlink++ > SQLITE_MAX_SYMLINK ){ + pPath->rc = SQLITE_CANTOPEN_BKPT; + return; + } + got = readlink(zIn, zLnk, sizeof(zLnk)-2); + if( got<=0 || got>=sizeof(zLnk)-2 ){ + pPath->rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn); + return; + } + zLnk[got] = 0; + if( zLnk[0]=='/' ){ + pPath->nUsed = 0; + }else{ + pPath->nUsed -= nName + 1; + } + appendAllPathElements(pPath, zLnk); + } + } +#endif } /* -** Convert a relative pathname into a full pathname. Also -** simplify the pathname as follows: -** -** Remove all instances of /./ -** Remove all isntances of /X/../ for any X +** Append all path elements in zPath to the DbPath under construction. */ -static int mkFullPathname( - const char *zPath, /* Input path */ - char *zOut, /* Output buffer */ - int nOut /* Allocated size of buffer zOut */ +static void appendAllPathElements( + DbPath *pPath, /* Path under construction, to which to append zName */ + const char *zPath /* Path to append to pPath. Is zero-terminated */ ){ - int nPath = sqlite3Strlen30(zPath); - int iOff = 0; - int i, j; - if( zPath[0]!='/' ){ - if( osGetcwd(zOut, nOut-2)==0 ){ - return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath); + int i = 0; + int j = 0; + do{ + while( zPath[i] && zPath[i]!='/' ){ i++; } + if( i>j ){ + appendOnePathElement(pPath, &zPath[j], i-j); } - iOff = sqlite3Strlen30(zOut); - zOut[iOff++] = '/'; - } - if( (iOff+nPath+1)>nOut ){ - /* SQLite assumes that xFullPathname() nul-terminates the output buffer - ** even if it returns an error. */ - zOut[iOff] = '\0'; - return SQLITE_CANTOPEN_BKPT; - } - sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath); - - /* Remove duplicate '/' characters. Except, two // at the beginning - ** of a pathname is allowed since this is important on windows. */ - for(i=j=1; zOut[i]; i++){ - zOut[j++] = zOut[i]; - while( zOut[i]=='/' && zOut[i+1]=='/' ) i++; - } - zOut[j] = 0; - - assert( zOut[0]=='/' ); - for(i=j=0; zOut[i]; i++){ - if( zOut[i]=='/' ){ - /* Skip over internal "/." directory components */ - if( zOut[i+1]=='.' && zOut[i+2]=='/' ){ - i += 1; - continue; - } - - /* If this is a "/.." directory component then back out the - ** previous term of the directory if it is something other than "..". - */ - if( zOut[i+1]=='.' - && zOut[i+2]=='.' - && zOut[i+3]=='/' - && unixBackupDir(zOut, &j) - ){ - i += 2; - continue; - } - } - if( ALWAYS(j>=0) ) zOut[j] = zOut[i]; - j++; - } - if( NEVER(j==0) ) zOut[j++] = '/'; - zOut[j] = 0; - return SQLITE_OK; + j = i+1; + }while( zPath[i++] ); } /* @@ -6520,86 +6533,26 @@ static int unixFullPathname( int nOut, /* Size of output buffer in bytes */ char *zOut /* Output buffer */ ){ -#if !defined(HAVE_READLINK) || !defined(HAVE_LSTAT) - return mkFullPathname(zPath, zOut, nOut); -#else - int rc = SQLITE_OK; - int nByte; - int nLink = 0; /* Number of symbolic links followed so far */ - const char *zIn = zPath; /* Input path for each iteration of loop */ - char *zDel = 0; - - assert( pVfs->mxPathname==MAX_PATHNAME ); - UNUSED_PARAMETER(pVfs); - - /* It's odd to simulate an io-error here, but really this is just - ** using the io-error infrastructure to test that SQLite handles this - ** function failing. This function could fail if, for example, the - ** current working directory has been unlinked. - */ - SimulateIOError( return SQLITE_ERROR ); - - do { - - /* Call stat() on path zIn. Set bLink to true if the path is a symbolic - ** link, or false otherwise. */ - int bLink = 0; - struct stat buf; - if( osLstat(zIn, &buf)!=0 ){ - if( errno!=ENOENT ){ - rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat", zIn); - } - }else{ - bLink = S_ISLNK(buf.st_mode); + DbPath path; + path.rc = 0; + path.nUsed = 0; + path.nSymlink = 0; + path.nOut = nOut; + path.zOut = zOut; + if( zPath[0]!='/' ){ + char zPwd[SQLITE_MAX_PATHLEN+2]; + if( osGetcwd(zPwd, sizeof(zPwd)-2)==0 ){ + return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath); } - - if( bLink ){ - nLink++; - if( zDel==0 ){ - zDel = sqlite3_malloc(nOut); - if( zDel==0 ) rc = SQLITE_NOMEM_BKPT; - }else if( nLink>=SQLITE_MAX_SYMLINKS ){ - rc = SQLITE_CANTOPEN_BKPT; - } - - if( rc==SQLITE_OK ){ - nByte = osReadlink(zIn, zDel, nOut-1); - if( nByte<0 ){ - rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn); - }else{ - if( zDel[0]!='/' ){ - int n; - for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--); - if( nByte+n+1>nOut ){ - rc = SQLITE_CANTOPEN_BKPT; - }else{ - memmove(&zDel[n], zDel, nByte+1); - memcpy(zDel, zIn, n); - nByte += n; - } - } - zDel[nByte] = '\0'; - } - } - - zIn = zDel; - } - - assert( rc!=SQLITE_OK || zIn!=zOut || zIn[0]=='/' ); - if( rc==SQLITE_OK && zIn!=zOut ){ - rc = mkFullPathname(zIn, zOut, nOut); - } - if( bLink==0 ) break; - zIn = zOut; - }while( rc==SQLITE_OK ); - - sqlite3_free(zDel); - if( rc==SQLITE_OK && nLink ) rc = SQLITE_OK_SYMLINK; - return rc; -#endif /* HAVE_READLINK && HAVE_LSTAT */ + appendAllPathElements(&path, zPwd); + } + appendAllPathElements(&path, zPath); + zOut[path.nUsed] = 0; + if( path.rc || path.nUsed<2 ) return SQLITE_CANTOPEN_BKPT; + if( path.nSymlink ) return SQLITE_OK_SYMLINK; + return SQLITE_OK; } - #ifndef SQLITE_OMIT_LOAD_EXTENSION /* ** Interfaces for opening a shared library, finding entry points From b302c065d82f1636ad8e88339eb9629b485f01f7 Mon Sep 17 00:00:00 2001 From: drh <> Date: Wed, 11 May 2022 17:45:50 +0000 Subject: [PATCH 013/108] Use osReadlink() in os_unix.c, not readlink() directly. FossilOrigin-Name: c3da4c1611cebd9f9d695892a3ffddc47d5f0db1a1ea8bd2b4f83ef7673b68de --- manifest | 15 ++++++--------- manifest.uuid | 2 +- src/os_unix.c | 2 +- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index 506b6ed4cc..3d59d54c1f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C For\sthe\sunix\sVFS,\srewrite\sthe\sxFullPathname\smethod\sso\sthat\sit\sautomatically\nresolves\sall\ssymbolic\slinks,\srendering\sa\scanonical\spathname\sthat\scontains\nno\ssymlinks. -D 2022-05-11T16:46:27.636 +C Use\sosReadlink()\sin\sos_unix.c,\snot\sreadlink()\sdirectly. +D 2022-05-11T17:45:50.754 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -537,7 +537,7 @@ F src/os.c b1c4f2d485961e9a5b6b648c36687d25047c252222e9660b7cc25a6e1ea436ab F src/os.h 1ff5ae51d339d0e30d8a9d814f4b8f8e448169304d83a7ed9db66a65732f3e63 F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85 F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586 -F src/os_unix.c 33fe706af9423563d4c7d4148e9f8bc1fb4b3669c4e32e66b5f1b963c6225f61 +F src/os_unix.c 02becb87c58245d2831f10f4f1a9108a465f8091cc598b2a9c78976f51a4e446 F src/os_win.c a8ea80037e81127ca01959daa87387cc135f325c88dc745376c4f760de852a10 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a F src/pager.c 42120492784fc9bcd9082b5c9b5e329b7318c357f9f3574a1bbfcf7418910356 @@ -1953,11 +1953,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 764b71267e0b31ff7eaf2a0def7526a1a02dce4d5b456dea060d97ed342efdd1 -R 569af1c5eabca94740251c005b203dc3 -T *branch * resolve-symlinks -T *sym-resolve-symlinks * -T -sym-trunk * +P 40c9273d0e0e74e1df22e996a5d486e838f4320defd2121e2d95eeed8aea6235 +R 114ae783653c7381e516a0c261b8b619 U drh -Z ce762f1e70449d535056ec1fff3f1e36 +Z 2491ed383edd9ee3426ed6172f3e61ac # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index bc8e305b6b..53003c0ad1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -40c9273d0e0e74e1df22e996a5d486e838f4320defd2121e2d95eeed8aea6235 \ No newline at end of file +c3da4c1611cebd9f9d695892a3ffddc47d5f0db1a1ea8bd2b4f83ef7673b68de \ No newline at end of file diff --git a/src/os_unix.c b/src/os_unix.c index b9beb53aad..da50f2de1e 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -6483,7 +6483,7 @@ static void appendOnePathElement( pPath->rc = SQLITE_CANTOPEN_BKPT; return; } - got = readlink(zIn, zLnk, sizeof(zLnk)-2); + got = osReadlink(zIn, zLnk, sizeof(zLnk)-2); if( got<=0 || got>=sizeof(zLnk)-2 ){ pPath->rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn); return; From 175fdcb91258906ca1de270193360a12d7be8506 Mon Sep 17 00:00:00 2001 From: larrybr Date: Wed, 11 May 2022 20:29:32 +0000 Subject: [PATCH 014/108] Zap stray --help output from intermediate version. FossilOrigin-Name: deb7372b18cc8fb9d305085498fd24b3c2c17bd920ae2d03fa885af02ad47008 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/shell.c.in | 1 - 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 95eb715273..735dc7b027 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Change\s.echo\son\seffect\sso\sthat\sSQL\sis\sechoed\sbefore\sprepare.\sThis\sslightly\salters\sechoed\soutput\swhen\smultiple\sSQL\sstatements\sare\ssubmitted\sat\sonce.\sAlso\ssync\swith\strunk. -D 2022-05-11T19:59:31.774 +C Zap\sstray\s--help\soutput\sfrom\sintermediate\sversion. +D 2022-05-11T20:29:32.525 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -554,7 +554,7 @@ F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c e9ee235c4151d2b7fa47435a219bfd30bf516a804d2f004639858087ebf3137b F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c 5096a2e8ab0511a413e7f5e45453fea4102d99c5636c46792581ae67899a76d7 -F src/shell.c.in cf90e67622f3d1a1874a4080ac1ab6b9393a09ca4cf7d820b45a62ff2429a6c0 +F src/shell.c.in afaed94af09f12ec99b4b9685e20273ad5bb5cdfcb6e2600cfb50f5a1ffe8e63 F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h f49e28c25bd941e79794db5415fdf7b202deb3bc072ed6f1ed273d578703684e @@ -1953,8 +1953,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 3eda4030f73384abf18b97cd8a4606e10b23e382d1b72dff7526aebfde23e0af d55273e36e312336b8fc77dc771657d3b2c3437fbbd79f3be37701982560d634 -R aa68945421e08aa1a970b0abab882c1b +P c1eff632c41809214edea2850a93852fff66da3ca0dc393e8fe55e0976d422fd +R 56f20e29d8d8bd4f94a878cd8e451873 U larrybr -Z c1c6d0984d4c87f2c4cc513f1bf72524 +Z ec90e5296e8a585e62fc3cef12515b0b # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 867849108d..7137a75b91 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c1eff632c41809214edea2850a93852fff66da3ca0dc393e8fe55e0976d422fd \ No newline at end of file +deb7372b18cc8fb9d305085498fd24b3c2c17bd920ae2d03fa885af02ad47008 \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index e560b06481..0408230b22 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -11714,7 +11714,6 @@ static const char zOptions[] = " -deserialize open the database using sqlite3_deserialize()\n" #endif " -echo print inputs before execution\n" - " -echo-sql print SQL before prepare\n" " -init FILENAME read/process named file\n" " -[no]header turn headers on or off\n" #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) From 902e2602c2792cbb3b4101f8cde3e0de610d2186 Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 12 May 2022 11:45:20 +0000 Subject: [PATCH 015/108] Add IS NOT DISTINCT FROM and IS DISTINCT FROM binary operators which are equivalent to IS and IS NOT, respectively, for compatability with PostgreSQL and hence standard SQL. FossilOrigin-Name: db27611e172102483eaede3981d473e3d5bf93d98bc68f480398b1573876349d --- manifest | 15 +++++++-------- manifest.uuid | 2 +- src/parse.y | 8 ++++++++ test/expr.test | 24 ++++++++++++++++++++++++ 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 7f2a9c3b13..33ab787219 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sthe\s".echo"\scommand\sof\sthe\sCLI\sso\sthat\sit\sshows\sthe\sresults\sof\sinput\nlines\simmediately,\sbefore\sinvoking\ssqlite3_prepare(). -D 2022-05-12T11:01:41.992 +C Add\sIS\sNOT\sDISTINCT\sFROM\sand\sIS\sDISTINCT\sFROM\sbinary\soperators\swhich\sare\nequivalent\sto\sIS\sand\sIS\sNOT,\srespectively,\sfor\scompatability\swith\sPostgreSQL\nand\shence\sstandard\sSQL. +D 2022-05-12T11:45:20.320 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -542,7 +542,7 @@ F src/os_win.c a8ea80037e81127ca01959daa87387cc135f325c88dc745376c4f760de852a10 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a F src/pager.c 42120492784fc9bcd9082b5c9b5e329b7318c357f9f3574a1bbfcf7418910356 F src/pager.h f82e9844166e1585f5786837ddc7709966138ced17f568c16af7ccf946c2baa3 -F src/parse.y b86d56b446afb9c203d8354dc6c422818a62b4bbab52b76ab3da06d7b1d07e44 +F src/parse.y efcb41d403be7bcecd6a95e51f73f89043e768cd0650a392c9b7ee0edbf1cc67 F src/pcache.c 084e638432c610f95aea72b8509f0845d2791293f39d1b82f0c0a7e089c3bb6b F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 F src/pcache1.c 54881292a9a5db202b2c0ac541c5e3ef9a5e8c4f1c1383adb2601d5499a60e65 @@ -901,7 +901,7 @@ F test/exclusive.test 7ff63be7503990921838d5c9f77f6e33e68e48ed1a9d48cd28745bf650 F test/exclusive2.test 984090e8e9d1b331d2e8111daf6e5d61dda0bef7 F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7 F test/exists.test 79a75323c78f02bbe9c251ea502a092f9ef63dac -F test/expr.test e1afcdb1038e4d3fa67a3df323347c38750946e2e1b4e385bdc75d26284f2dac +F test/expr.test 5c06696478212e5a04e04b043f993373f6f8e5ce5a80f5548a84703b123b6caa F test/expr2.test c27327ae9c017a7ff6280123f67aff496f912da74d78c888926d68b46ec75fd8 F test/exprfault.test 497cc0b8fe6a677f49b55cb485e040f709ec2834b84f25912fe9c2dfeeda33db F test/extension01.test 00d13cec817f331a687a243e0e5a2d87b0e358c9 @@ -1953,9 +1953,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P d55273e36e312336b8fc77dc771657d3b2c3437fbbd79f3be37701982560d634 deb7372b18cc8fb9d305085498fd24b3c2c17bd920ae2d03fa885af02ad47008 -R 56f20e29d8d8bd4f94a878cd8e451873 -T +closed deb7372b18cc8fb9d305085498fd24b3c2c17bd920ae2d03fa885af02ad47008 +P cf7fdabdba3a7600ea730263ca80ba80154645dfa15c31c037b780d6cb70e530 +R 3d6af656fb4de79992bd7eb88f082265 U drh -Z cf10466c2750403d999365883982fc9d +Z 3682303474f6dcc00e17a0b96d46c4cc # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 8dd1a1187b..d36477989d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cf7fdabdba3a7600ea730263ca80ba80154645dfa15c31c037b780d6cb70e530 \ No newline at end of file +db27611e172102483eaede3981d473e3d5bf93d98bc68f480398b1573876349d \ No newline at end of file diff --git a/src/parse.y b/src/parse.y index 37560a2e0b..565130a05c 100644 --- a/src/parse.y +++ b/src/parse.y @@ -1218,6 +1218,14 @@ expr(A) ::= expr(A) IS NOT expr(Y). { A = sqlite3PExpr(pParse,TK_ISNOT,A,Y); binaryToUnaryIfNull(pParse, Y, A, TK_NOTNULL); } +expr(A) ::= expr(A) IS NOT DISTINCT FROM expr(Y). { + A = sqlite3PExpr(pParse,TK_IS,A,Y); + binaryToUnaryIfNull(pParse, Y, A, TK_ISNULL); +} +expr(A) ::= expr(A) IS DISTINCT FROM expr(Y). { + A = sqlite3PExpr(pParse,TK_ISNOT,A,Y); + binaryToUnaryIfNull(pParse, Y, A, TK_NOTNULL); +} expr(A) ::= NOT(B) expr(X). {A = sqlite3PExpr(pParse, @B, X, 0);/*A-overwrites-B*/} diff --git a/test/expr.test b/test/expr.test index c64b6cb706..55b1dc9502 100644 --- a/test/expr.test +++ b/test/expr.test @@ -181,29 +181,53 @@ if {[working_64bit_int]} { } test_expr expr-1.111 {i1=NULL, i2=8} {i1 IS i2} 0 +test_expr expr-1.111b {i1=NULL, i2=8} {i1 IS NOT DISTINCT FROM i2} 0 test_expr expr-1.112 {i1=NULL, i2=NULL} {i1 IS i2} 1 +test_expr expr-1.112b {i1=NULL, i2=NULL} {i1 IS NOT DISTINCT FROM i2} 1 test_expr expr-1.113 {i1=6, i2=NULL} {i1 IS i2} 0 +test_expr expr-1.113b {i1=6, i2=NULL} {i1 IS NOT DISTINCT FROM i2} 0 test_expr expr-1.114 {i1=6, i2=6} {i1 IS i2} 1 +test_expr expr-1.114b {i1=6, i2=6} {i1 IS NOT DISTINCT FROM i2} 1 test_expr expr-1.115 {i1=NULL, i2=8} \ {CASE WHEN i1 IS i2 THEN 'yes' ELSE 'no' END} no +test_expr expr-1.115b {i1=NULL, i2=8} \ + {CASE WHEN i1 IS NOT DISTINCT FROM i2 THEN 'yes' ELSE 'no' END} no test_expr expr-1.116 {i1=NULL, i2=NULL} \ {CASE WHEN i1 IS i2 THEN 'yes' ELSE 'no' END} yes +test_expr expr-1.116b {i1=NULL, i2=NULL} \ + {CASE WHEN i1 IS NOT DISTINCT FROM i2 THEN 'yes' ELSE 'no' END} yes test_expr expr-1.117 {i1=6, i2=NULL} \ {CASE WHEN i1 IS i2 THEN 'yes' ELSE 'no' END} no +test_expr expr-1.117b {i1=6, i2=NULL} \ + {CASE WHEN i1 IS NOT DISTINCT FROM i2 THEN 'yes' ELSE 'no' END} no test_expr expr-1.118 {i1=8, i2=8} \ {CASE WHEN i1 IS i2 THEN 'yes' ELSE 'no' END} yes +test_expr expr-1.118b {i1=8, i2=8} \ + {CASE WHEN i1 IS NOT DISTINCT FROM i2 THEN 'yes' ELSE 'no' END} yes test_expr expr-1.119 {i1=NULL, i2=8} {i1 IS NOT i2} 1 +test_expr expr-1.119b {i1=NULL, i2=8} {i1 IS DISTINCT FROM i2} 1 test_expr expr-1.120 {i1=NULL, i2=NULL} {i1 IS NOT i2} 0 +test_expr expr-1.120b {i1=NULL, i2=NULL} {i1 IS DISTINCT FROM i2} 0 test_expr expr-1.121 {i1=6, i2=NULL} {i1 IS NOT i2} 1 +test_expr expr-1.121b {i1=6, i2=NULL} {i1 IS DISTINCT FROM i2} 1 test_expr expr-1.122 {i1=6, i2=6} {i1 IS NOT i2} 0 +test_expr expr-1.122b {i1=6, i2=6} {i1 IS DISTINCT FROM i2} 0 test_expr expr-1.123 {i1=NULL, i2=8} \ {CASE WHEN i1 IS NOT i2 THEN 'yes' ELSE 'no' END} yes +test_expr expr-1.123b {i1=NULL, i2=8} \ + {CASE WHEN i1 IS DISTINCT FROM i2 THEN 'yes' ELSE 'no' END} yes test_expr expr-1.124 {i1=NULL, i2=NULL} \ {CASE WHEN i1 IS NOT i2 THEN 'yes' ELSE 'no' END} no +test_expr expr-1.124b {i1=NULL, i2=NULL} \ + {CASE WHEN i1 IS DISTINCT FROM i2 THEN 'yes' ELSE 'no' END} no test_expr expr-1.125 {i1=6, i2=NULL} \ {CASE WHEN i1 IS NOT i2 THEN 'yes' ELSE 'no' END} yes +test_expr expr-1.125b {i1=6, i2=NULL} \ + {CASE WHEN i1 IS DISTINCT FROM i2 THEN 'yes' ELSE 'no' END} yes test_expr expr-1.126 {i1=8, i2=8} \ {CASE WHEN i1 IS NOT i2 THEN 'yes' ELSE 'no' END} no +test_expr expr-1.126b {i1=8, i2=8} \ + {CASE WHEN i1 IS DISTINCT FROM i2 THEN 'yes' ELSE 'no' END} no do_catchsql_test expr-1.127 { SELECT 1 IS #1; From d631c6af80fa779c504a53d29666540fc87bea93 Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 12 May 2022 11:56:44 +0000 Subject: [PATCH 016/108] Ensure that ON clauses are applied to the correct outer join. FossilOrigin-Name: c7e3a13a3288c577209be99c630fbe924e19880e8af1aa8a83b517acaa8b43d7 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/wherecode.c | 3 ++- test/join8.test | 23 +++++++++++++++++++++++ 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 33ab787219..cfd91f551a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sIS\sNOT\sDISTINCT\sFROM\sand\sIS\sDISTINCT\sFROM\sbinary\soperators\swhich\sare\nequivalent\sto\sIS\sand\sIS\sNOT,\srespectively,\sfor\scompatability\swith\sPostgreSQL\nand\shence\sstandard\sSQL. -D 2022-05-12T11:45:20.320 +C Ensure\sthat\sON\sclauses\sare\sapplied\sto\sthe\scorrect\souter\sjoin. +D 2022-05-12T11:56:44.510 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -642,7 +642,7 @@ F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b F src/where.c aa585b89bd65a81e44bdfb871b55f65bf8fda88e1bc85efda6c236fe8d2bd788 F src/whereInt.h 8da918f392bf202ccc0ee61291455b33ad171d209445f1ff3eaf62e0b6f6b363 -F src/wherecode.c 72f8eeed5527450c8e2258160a7bd04534a76c161230d100da0f43a86c6e29ac +F src/wherecode.c c1f7210872a75f0c79323133168faef4bafd4ecbd78594374f21738fdb9bb72e F src/whereexpr.c e036477ac8424de50ae5b36a71103405d3f86b33ba11125ec7a2a99d501b0622 F src/window.c fff1b51757438c664e471d5184634e48dcdf8ea34b640f3b1b0810b1e06de18c F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 @@ -1148,7 +1148,7 @@ F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join5.test d22b6cba8fb59ab3f1c82701434c360705eb12d4ce200c449f37b018fc47681a F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c F test/join7.test 8e72de4b45e5e930d18c305c7efe86015fb2552731e4e03ea226353036b0dab0 -F test/join8.test fef259c42d56bbe150b777726b185b0bc060d4290daf9f879abc68321f8ad6db +F test/join8.test 9b83dc70b7e9f7d4ee0022a0fe44ec1858f103530c7eb253c10adb63aad16ec4 F test/join9.test 9056ddd3b0c0f4f9d658f4521038d9a37dc23ead8ca9a505d0b0db2b6a471e05 F test/joinA.test 7eab225dc1c1ab258a5e62513a4ed7cabbd3db971d59d5d92f4fb6fa14c12f6a F test/joinB.test 1b2ba3fc8568b49411787fccbf540570c148e9b6a53a30f80691cb6268098ded @@ -1953,8 +1953,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P cf7fdabdba3a7600ea730263ca80ba80154645dfa15c31c037b780d6cb70e530 -R 3d6af656fb4de79992bd7eb88f082265 +P db27611e172102483eaede3981d473e3d5bf93d98bc68f480398b1573876349d +R afe0cdc3523728a1b8ae188a6e9f6b30 U drh -Z 3682303474f6dcc00e17a0b96d46c4cc +Z 2be2867ba128a1ce436a897eb9d120e9 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index d36477989d..75e5a275dd 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -db27611e172102483eaede3981d473e3d5bf93d98bc68f480398b1573876349d \ No newline at end of file +c7e3a13a3288c577209be99c630fbe924e19880e8af1aa8a83b517acaa8b43d7 \ No newline at end of file diff --git a/src/wherecode.c b/src/wherecode.c index a942e6e7fb..979944e2ea 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -2621,7 +2621,8 @@ Bitmask sqlite3WhereCodeOneLoopStart( pE = pTerm->pExpr; assert( pE!=0 ); if( (pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ)) - && !ExprHasProperty(pE,EP_FromJoin|EP_InnerJoin) + && (!ExprHasProperty(pE,EP_FromJoin|EP_InnerJoin) + || pE->w.iJoin!=pTabItem->iCursor) ){ continue; } diff --git a/test/join8.test b/test/join8.test index ab05722912..05d400470a 100644 --- a/test/join8.test +++ b/test/join8.test @@ -260,4 +260,27 @@ do_execsql_test join8-7020 { ORDER BY coalesce(t0.a, t0.y+200, t4.d); } {/.*BLOOM FILTER ON t2.*BLOOM FILTER ON t3.*BLOOM FILTER ON t4.*/} +# 2022-05-12 Difference with PG found (by Dan) while exploring +# https://sqlite.org/forum/forumpost/677a0ab93fcd9ccd +# +reset_db +do_execsql_test join8-8000 { + CREATE TABLE t1(a INT, b INT); + CREATE TABLE t2(c INT, d INT); + CREATE TABLE t3(e INT, f INT); + INSERT INTO t1 VALUES(1, 2); + INSERT INTO t2 VALUES(3, 4); + INSERT INTO t3 VALUES(5, 6); +} {} +do_execsql_test join8-8010 { + SELECT * + FROM t3 LEFT JOIN t2 ON true + JOIN t1 ON (t3.e IS t2.c); +} {} +do_execsql_test join8-8020 { + SELECT * + FROM t3 LEFT JOIN t2 ON true + JOIN t1 ON (t3.e IS NOT DISTINCT FROM t2.c); +} {} + finish_test From 8b0e5c3c7e801ae07e956fed979d0bf865e7b838 Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 12 May 2022 17:09:33 +0000 Subject: [PATCH 017/108] Fix a harmless compiler warning in the CLI. FossilOrigin-Name: 7a2ac303d1436a423a635db63d195097c88160ff46855194f6e630f9d3b3fa82 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/shell.c.in | 1 - 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index cfd91f551a..ccb8064533 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Ensure\sthat\sON\sclauses\sare\sapplied\sto\sthe\scorrect\souter\sjoin. -D 2022-05-12T11:56:44.510 +C Fix\sa\sharmless\scompiler\swarning\sin\sthe\sCLI. +D 2022-05-12T17:09:33.863 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -554,7 +554,7 @@ F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c e9ee235c4151d2b7fa47435a219bfd30bf516a804d2f004639858087ebf3137b F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c 5096a2e8ab0511a413e7f5e45453fea4102d99c5636c46792581ae67899a76d7 -F src/shell.c.in afaed94af09f12ec99b4b9685e20273ad5bb5cdfcb6e2600cfb50f5a1ffe8e63 +F src/shell.c.in 176cad562152cbbafe7ecc9c83c82850e2c3d0cf33ec0a52d67341d35c842f22 F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h f49e28c25bd941e79794db5415fdf7b202deb3bc072ed6f1ed273d578703684e @@ -1953,8 +1953,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P db27611e172102483eaede3981d473e3d5bf93d98bc68f480398b1573876349d -R afe0cdc3523728a1b8ae188a6e9f6b30 +P c7e3a13a3288c577209be99c630fbe924e19880e8af1aa8a83b517acaa8b43d7 +R 0a3845fefd0ad6aac7e45fbf280fa0ff U drh -Z 2be2867ba128a1ce436a897eb9d120e9 +Z 54875c2875e3e9b4c71ab954fb3fc0b2 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 75e5a275dd..f04f438eda 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c7e3a13a3288c577209be99c630fbe924e19880e8af1aa8a83b517acaa8b43d7 \ No newline at end of file +7a2ac303d1436a423a635db63d195097c88160ff46855194f6e630f9d3b3fa82 \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index 0408230b22..cace8bf2f4 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -8962,7 +8962,6 @@ static int do_meta_command(char *zLine, ShellState *p){ utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile); goto meta_command_exit; } - rc = 0; if( eVerbose>=2 || (eVerbose>=1 && useOutputMode) ){ char zSep[2]; zSep[1] = 0; From 67a99dbee8832e713a0ad0fa9def5f017f923c9e Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 13 May 2022 14:52:04 +0000 Subject: [PATCH 018/108] Improved names for flags on the Expr object: EP_FromJoin becames EP_OuterON and EP_InnerJoin becomes EP_InnerON. FossilOrigin-Name: 1ffea07ff98b894729c698b681cc7433df3bbfccd8a0529a706908602a636937 --- manifest | 28 ++++++++++++++-------------- manifest.uuid | 2 +- src/expr.c | 16 ++++++++-------- src/printf.c | 2 +- src/resolve.c | 2 +- src/select.c | 42 +++++++++++++++++++++--------------------- src/sqliteInt.h | 48 ++++++++++++++++++++++++------------------------ src/treeview.c | 5 ++++- src/where.c | 16 ++++++++-------- src/wherecode.c | 14 +++++++------- src/whereexpr.c | 18 +++++++++--------- 11 files changed, 98 insertions(+), 95 deletions(-) diff --git a/manifest b/manifest index ccb8064533..e78851efcb 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sharmless\scompiler\swarning\sin\sthe\sCLI. -D 2022-05-12T17:09:33.863 +C Improved\snames\sfor\sflags\son\sthe\sExpr\sobject:\s\sEP_FromJoin\sbecames\nEP_OuterON\sand\sEP_InnerJoin\sbecomes\sEP_InnerON. +D 2022-05-13T14:52:04.811 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -504,7 +504,7 @@ F src/date.c 15082566229d4b1e5f24fdb490bf9bcc68824b911d70e3573ef075a1b9e2d26f F src/dbpage.c 90661a87e1db8bfbc8d2ebbdcd3749651ddb287c555c07a28fb17c7c591ffb68 F src/dbstat.c 861e08690fcb0f2ee1165eff0060ea8d4f3e2ea10f80dab7d32ad70443a6ff2d F src/delete.c a8e844af211a48b13b5b358be77a12c860c6a557c21990ad51a548e2536500ce -F src/expr.c d955e8954e03e637c19033241806b04f6a937d0657f6261f2d9e4cdfe674b478 +F src/expr.c 8c5ca4fb4089cc3a3441f25087356702a45c6aca417b76fcb82622428fb7265e F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c d965ede15d8360c09ed59348940649ee647b192e784466837d7aefa836d1d91e F src/func.c a3407a6fbb0d4088d8d502e46f0ace63e0aeae7467ae23a9ca9815bbf9239761 @@ -549,16 +549,16 @@ F src/pcache1.c 54881292a9a5db202b2c0ac541c5e3ef9a5e8c4f1c1383adb2601d5499a60e65 F src/pragma.c d1aead03e8418ff586c7cfca344c50a914b8eb06abd841e8e91a982d823671da F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7 F src/prepare.c c62820c15dcb63013519c8e41d9f928d7478672cc902cfd0581c733c271dbf45 -F src/printf.c 512574910a45341c8ad244bd3d4939968ebdfde215645b676fff01cc46e90757 +F src/printf.c 320fd82b2b203e584c87e5a85e80a4be8d926f8aacbccc53ec6b01bbc305ef8c F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c -F src/resolve.c e9ee235c4151d2b7fa47435a219bfd30bf516a804d2f004639858087ebf3137b +F src/resolve.c a4eb3c617027fd049b07432f3b942ea7151fa793a332a11a7d0f58c9539e104f F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 -F src/select.c 5096a2e8ab0511a413e7f5e45453fea4102d99c5636c46792581ae67899a76d7 +F src/select.c 74060a09f66c0c056f3c61627e22cb484af0bbfa29d7d14dcf17c684742c15de F src/shell.c.in 176cad562152cbbafe7ecc9c83c82850e2c3d0cf33ec0a52d67341d35c842f22 F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h f49e28c25bd941e79794db5415fdf7b202deb3bc072ed6f1ed273d578703684e -F src/sqliteInt.h 7c8146fc57f2e009152eb93ad41eab28490f9c31691559f281a80f9077ec1f2a +F src/sqliteInt.h ba4057968afd2fbd0fd72c1a6d6cc5a7b568437f47b476106993da32bde5645b F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4a3da6d77eeb3531cb0dbdf7047772a2a1b99f98c69e90ce009c75fe6328b2c0 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -618,7 +618,7 @@ F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c a38f52058b517929e264094abd0b5fd1e8e145a1aa43bc6f6a72ae5218f96c98 -F src/treeview.c 4153f2f044d13a3216e64271dfd1e59a3fa40222a45e6da248708088634e6f06 +F src/treeview.c ae4a3c115c630ab5b779b66590a2d029329f2df050c2f35195cf1bbd2922decb F src/trigger.c 4fe4c1ac811755aff49d669d2e52e414eb5dfa6e172e849ab7b6825e70a571c0 F src/update.c 2cfaded82ca80ff56afb8c3ae5e88284e0824bfd86119827cc22481959f96f92 F src/upsert.c 8789047a8f0a601ea42fa0256d1ba3190c13746b6ba940fe2d25643a7e991937 @@ -640,10 +640,10 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c aa585b89bd65a81e44bdfb871b55f65bf8fda88e1bc85efda6c236fe8d2bd788 +F src/where.c d4d543f06b09ff8bac05072b015a2181f9c48561b1a146158aaaf09e40817567 F src/whereInt.h 8da918f392bf202ccc0ee61291455b33ad171d209445f1ff3eaf62e0b6f6b363 -F src/wherecode.c c1f7210872a75f0c79323133168faef4bafd4ecbd78594374f21738fdb9bb72e -F src/whereexpr.c e036477ac8424de50ae5b36a71103405d3f86b33ba11125ec7a2a99d501b0622 +F src/wherecode.c 51aba5a09657c0400f76453e221aebe2abf488f6ef6345ae89c32468e36a0639 +F src/whereexpr.c 98e4e3fb3d10be2039de9b059ba04c6f5a500d17e9bd2ccc470d14f44b2a317d F src/window.c fff1b51757438c664e471d5184634e48dcdf8ea34b640f3b1b0810b1e06de18c F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627 @@ -1953,8 +1953,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P c7e3a13a3288c577209be99c630fbe924e19880e8af1aa8a83b517acaa8b43d7 -R 0a3845fefd0ad6aac7e45fbf280fa0ff +P 7a2ac303d1436a423a635db63d195097c88160ff46855194f6e630f9d3b3fa82 +R 76628c449717fbf73d51bf54cb4d3e31 U drh -Z 54875c2875e3e9b4c71ab954fb3fc0b2 +Z db742fa17a2891de768f2e234d496fc9 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index f04f438eda..c5b99fbd4d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7a2ac303d1436a423a635db63d195097c88160ff46855194f6e630f9d3b3fa82 \ No newline at end of file +1ffea07ff98b894729c698b681cc7433df3bbfccd8a0529a706908602a636937 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 1ebc73be93..2965457d92 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1347,7 +1347,7 @@ static int dupedExprStructSize(const Expr *p, int flags){ nSize = EXPR_FULLSIZE; }else{ assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) ); - assert( !ExprHasProperty(p, EP_FromJoin) ); + assert( !ExprHasProperty(p, EP_OuterON) ); assert( !ExprHasProperty(p, EP_MemToken) ); assert( !ExprHasVVAProperty(p, EP_NoReduce) ); if( p->pLeft || p->x.pList ){ @@ -2173,7 +2173,7 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){ /* If pWalker->eCode is 2 then any term of the expression that comes from ** the ON or USING clauses of an outer join disqualifies the expression ** from being considered constant. */ - if( pWalker->eCode==2 && ExprHasProperty(pExpr, EP_FromJoin) ){ + if( pWalker->eCode==2 && ExprHasProperty(pExpr, EP_OuterON) ){ pWalker->eCode = 0; return WRC_Abort; } @@ -2320,10 +2320,10 @@ int sqlite3ExprIsTableConstraint(Expr *pExpr, const SrcItem *pSrc){ return 0; /* rule (3) */ } if( pSrc->fg.jointype & JT_LEFT ){ - if( !ExprHasProperty(pExpr, EP_FromJoin) ) return 0; /* rule (4a) */ + if( !ExprHasProperty(pExpr, EP_OuterON) ) return 0; /* rule (4a) */ if( pExpr->w.iJoin!=pSrc->iCursor ) return 0; /* rule (4b) */ }else{ - if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0; /* rule (5) */ + if( ExprHasProperty(pExpr, EP_OuterON) ) return 0; /* rule (5) */ } return sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor); /* rules (1), (2) */ } @@ -5078,8 +5078,8 @@ static void exprCodeBetween( ** so that the sqlite3ExprCodeTarget() routine will not attempt to move ** it into the Parse.pConstExpr list. We should use a new bit for this, ** for clarity, but we are out of bits in the Expr.flags field so we - ** have to reuse the EP_FromJoin bit. Bummer. */ - pDel->flags |= EP_FromJoin; + ** have to reuse the EP_OuterON bit. Bummer. */ + pDel->flags |= EP_OuterON; sqlite3ExprCodeTarget(pParse, &exprAnd, dest); } sqlite3ReleaseTempReg(pParse, regFree1); @@ -5764,7 +5764,7 @@ int sqlite3ExprImpliesExpr( static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){ testcase( pExpr->op==TK_AGG_COLUMN ); testcase( pExpr->op==TK_AGG_FUNCTION ); - if( ExprHasProperty(pExpr, EP_FromJoin) ) return WRC_Prune; + if( ExprHasProperty(pExpr, EP_OuterON) ) return WRC_Prune; switch( pExpr->op ){ case TK_ISNOT: case TK_ISNULL: @@ -5861,7 +5861,7 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){ ** False positives are not allowed, however. A false positive may result ** in an incorrect answer. ** -** Terms of p that are marked with EP_FromJoin (and hence that come from +** Terms of p that are marked with EP_OuterON (and hence that come from ** the ON or USING clauses of OUTER JOINS) are excluded from the analysis. ** ** This routine is used to check if a LEFT JOIN can be converted into diff --git a/src/printf.c b/src/printf.c index f55b6ef660..41ce4ac7ab 100644 --- a/src/printf.c +++ b/src/printf.c @@ -954,7 +954,7 @@ void sqlite3RecordErrorByteOffset(sqlite3 *db, const char *z){ ** as the error offset. */ void sqlite3RecordErrorOffsetOfExpr(sqlite3 *db, const Expr *pExpr){ - while( pExpr && (ExprHasProperty(pExpr,EP_FromJoin) || pExpr->w.iOfst<=0) ){ + while( pExpr && (ExprHasProperty(pExpr,EP_OuterON) || pExpr->w.iOfst<=0) ){ pExpr = pExpr->pLeft; } if( pExpr==0 ) return; diff --git a/src/resolve.c b/src/resolve.c index d7e32911e9..175f81a10e 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -928,7 +928,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ } sqlite3WalkExpr(pWalker, pExpr->pLeft); if( 0==sqlite3ExprCanBeNull(pExpr->pLeft) && !IN_RENAME_OBJECT ){ - testcase( ExprHasProperty(pExpr, EP_FromJoin) ); + testcase( ExprHasProperty(pExpr, EP_OuterON) ); assert( !ExprHasProperty(pExpr, EP_IntValue) ); if( pExpr->op==TK_NOTNULL ){ pExpr->u.zToken = "true"; diff --git a/src/select.c b/src/select.c index e767aa0153..ccbe3f4fc8 100644 --- a/src/select.c +++ b/src/select.c @@ -378,11 +378,11 @@ static int tableAndColumnIndex( } /* -** Set the EP_FromJoin property on all terms of the given expression. +** Set the EP_OuterON property on all terms of the given expression. ** And set the Expr.w.iJoin to iTable for every term in the ** expression. ** -** The EP_FromJoin property is used on terms of an expression to tell +** The EP_OuterON property is used on terms of an expression to tell ** the OUTER JOIN processing logic that this term is part of the ** join restriction specified in the ON or USING clause and not a part ** of the more general WHERE clause. These terms are moved over to the @@ -404,7 +404,7 @@ static int tableAndColumnIndex( ** the output, which is incorrect. */ void sqlite3SetJoinExpr(Expr *p, int iTable, u32 joinFlag){ - assert( joinFlag==EP_FromJoin || joinFlag==EP_InnerJoin ); + assert( joinFlag==EP_OuterON || joinFlag==EP_InnerON ); while( p ){ ExprSetProperty(p, joinFlag); assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) ); @@ -425,17 +425,17 @@ void sqlite3SetJoinExpr(Expr *p, int iTable, u32 joinFlag){ } /* Undo the work of sqlite3SetJoinExpr(). In the expression p, convert every -** term that is marked with EP_FromJoin and w.iJoin==iTable into -** an ordinary term that omits the EP_FromJoin mark. +** term that is marked with EP_OuterON and w.iJoin==iTable into +** an ordinary term that omits the EP_OuterON mark. ** ** This happens when a LEFT JOIN is simplified into an ordinary JOIN. */ static void unsetJoinExpr(Expr *p, int iTable){ while( p ){ - if( ExprHasProperty(p, EP_FromJoin) + if( ExprHasProperty(p, EP_OuterON) && (iTable<0 || p->w.iJoin==iTable) ){ - ExprClearProperty(p, EP_FromJoin); - ExprSetProperty(p, EP_InnerJoin); + ExprClearProperty(p, EP_OuterON); + ExprSetProperty(p, EP_InnerON); } if( p->op==TK_COLUMN && p->iTable==iTable ){ ExprClearProperty(p, EP_CanBeNull); @@ -463,8 +463,8 @@ static void unsetJoinExpr(Expr *p, int iTable){ ** ** * ON and USING clauses result in extra terms being added to the ** WHERE clause to enforce the specified constraints. The extra -** WHERE clause terms will be tagged with EP_FromJoin or -** EP_InnerJoin so that we know that they originated in ON/USING. +** WHERE clause terms will be tagged with EP_OuterON or +** EP_InnerON so that we know that they originated in ON/USING. ** ** The terms of a FROM clause are contained in the Select.pSrc structure. ** The left most table is the first entry in Select.pSrc. The right-most @@ -489,7 +489,7 @@ static int sqlite3ProcessJoin(Parse *pParse, Select *p){ u32 joinType; if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue; - joinType = (pRight->fg.jointype & JT_OUTER)!=0 ? EP_FromJoin : EP_InnerJoin; + joinType = (pRight->fg.jointype & JT_OUTER)!=0 ? EP_OuterON : EP_InnerON; /* If this is a NATURAL join, synthesize an approprate USING clause ** to specify which columns should be joined. @@ -3762,7 +3762,7 @@ static Expr *substExpr( Expr *pExpr /* Expr in which substitution occurs */ ){ if( pExpr==0 ) return 0; - if( ExprHasProperty(pExpr, EP_FromJoin) + if( ExprHasProperty(pExpr, EP_OuterON) && pExpr->w.iJoin==pSubst->iTable ){ pExpr->w.iJoin = pSubst->iNewTable; @@ -3803,9 +3803,9 @@ static Expr *substExpr( if( pSubst->isOuterJoin ){ ExprSetProperty(pNew, EP_CanBeNull); } - if( ExprHasProperty(pExpr,EP_FromJoin|EP_InnerJoin) ){ + if( ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) ){ sqlite3SetJoinExpr(pNew, pExpr->w.iJoin, - pExpr->flags & (EP_FromJoin|EP_InnerJoin)); + pExpr->flags & (EP_OuterON|EP_InnerON)); } sqlite3ExprDelete(db, pExpr); pExpr = pNew; @@ -3969,7 +3969,7 @@ static int renumberCursorsCb(Walker *pWalker, Expr *pExpr){ if( op==TK_COLUMN || op==TK_IF_NULL_ROW ){ renumberCursorDoMapping(pWalker, &pExpr->iTable); } - if( ExprHasProperty(pExpr, EP_FromJoin) ){ + if( ExprHasProperty(pExpr, EP_OuterON) ){ renumberCursorDoMapping(pWalker, &pExpr->w.iJoin); } return WRC_Continue; @@ -4547,7 +4547,7 @@ static int flattenSubquery( pWhere = pSub->pWhere; pSub->pWhere = 0; if( isOuterJoin>0 ){ - sqlite3SetJoinExpr(pWhere, iNewParent, EP_FromJoin); + sqlite3SetJoinExpr(pWhere, iNewParent, EP_OuterON); } if( pWhere ){ if( pParent->pWhere ){ @@ -4680,7 +4680,7 @@ static void constInsert( static void findConstInWhere(WhereConst *pConst, Expr *pExpr){ Expr *pRight, *pLeft; if( NEVER(pExpr==0) ) return; - if( ExprHasProperty(pExpr, EP_FromJoin) ) return; + if( ExprHasProperty(pExpr, EP_OuterON) ) return; if( pExpr->op==TK_AND ){ findConstInWhere(pConst, pExpr->pRight); findConstInWhere(pConst, pExpr->pLeft); @@ -4716,9 +4716,9 @@ static int propagateConstantExprRewriteOne( int i; if( pConst->pOomFault[0] ) return WRC_Prune; if( pExpr->op!=TK_COLUMN ) return WRC_Continue; - if( ExprHasProperty(pExpr, EP_FixedCol|EP_FromJoin) ){ + if( ExprHasProperty(pExpr, EP_FixedCol|EP_OuterON) ){ testcase( ExprHasProperty(pExpr, EP_FixedCol) ); - testcase( ExprHasProperty(pExpr, EP_FromJoin) ); + testcase( ExprHasProperty(pExpr, EP_OuterON) ); return WRC_Continue; } for(i=0; inConst; i++){ @@ -5003,12 +5003,12 @@ static int pushDownWhereTerms( #if 0 /* Legacy code. Checks now done by sqlite3ExprIsTableConstraint() */ if( isLeftJoin - && (ExprHasProperty(pWhere,EP_FromJoin)==0 + && (ExprHasProperty(pWhere,EP_OuterON)==0 || pWhere->w.iJoin!=iCursor) ){ return 0; /* restriction (4) */ } - if( ExprHasProperty(pWhere,EP_FromJoin) + if( ExprHasProperty(pWhere,EP_OuterON) && pWhere->w.iJoin!=iCursor ){ return 0; /* restriction (5) */ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 7cbdb46215..ff11d12a2d 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2847,7 +2847,7 @@ struct Expr { ** TK_SELECT_COLUMN: column of the result vector */ i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */ union { - int iJoin; /* If EP_FromJoin, the right table of the join */ + int iJoin; /* If EP_OuterON, the right table of the join */ int iOfst; /* else: start of token from start of statement */ } w; AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */ @@ -2868,29 +2868,29 @@ struct Expr { ** EP_Agg == NC_HasAgg == SF_HasAgg ** EP_Win == NC_HasWin */ -#define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */ -#define EP_Distinct 0x000002 /* Aggregate function with DISTINCT keyword */ -#define EP_HasFunc 0x000004 /* Contains one or more functions of any kind */ -#define EP_FixedCol 0x000008 /* TK_Column with a known fixed value */ +#define EP_OuterON 0x000001 /* Originates in ON/USING clause of outer join */ +#define EP_InnerON 0x000002 /* Originates in ON/USING of an inner join */ +#define EP_Distinct 0x000004 /* Aggregate function with DISTINCT keyword */ +#define EP_HasFunc 0x000008 /* Contains one or more functions of any kind */ #define EP_Agg 0x000010 /* Contains one or more aggregate functions */ -#define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */ -#define EP_DblQuoted 0x000040 /* token.z was originally in "..." */ -#define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */ -#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */ -#define EP_Commuted 0x000200 /* Comparison operator has been commuted */ -#define EP_IntValue 0x000400 /* Integer value contained in u.iValue */ -#define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */ -#define EP_Skip 0x001000 /* Operator does not contribute to affinity */ -#define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */ -#define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */ +#define EP_FixedCol 0x000020 /* TK_Column with a known fixed value */ +#define EP_VarSelect 0x000040 /* pSelect is correlated, not constant */ +#define EP_DblQuoted 0x000080 /* token.z was originally in "..." */ +#define EP_InfixFunc 0x000100 /* True for an infix function: LIKE, GLOB, etc */ +#define EP_Collate 0x000200 /* Tree contains a TK_COLLATE operator */ +#define EP_Commuted 0x000400 /* Comparison operator has been commuted */ +#define EP_IntValue 0x000800 /* Integer value contained in u.iValue */ +#define EP_xIsSelect 0x001000 /* x.pSelect is valid (otherwise x.pList is) */ +#define EP_Skip 0x002000 /* Operator does not contribute to affinity */ +#define EP_Reduced 0x004000 /* Expr struct EXPR_REDUCEDSIZE bytes only */ #define EP_Win 0x008000 /* Contains window functions */ -#define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */ -#define EP_IfNullRow 0x020000 /* The TK_IF_NULL_ROW opcode */ -#define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */ -#define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */ -#define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */ -#define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */ -#define EP_InnerJoin 0x400000 /* Originates in ON/USING of an inner join */ +#define EP_TokenOnly 0x010000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */ +#define EP_MemToken 0x020000 /* Need to sqlite3DbFree() Expr.zToken */ +#define EP_IfNullRow 0x040000 /* The TK_IF_NULL_ROW opcode */ +#define EP_Unlikely 0x080000 /* unlikely() or likelihood() function */ +#define EP_ConstFunc 0x100000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */ +#define EP_CanBeNull 0x200000 /* Can be null despite NOT NULL constraint */ +#define EP_Subquery 0x400000 /* Tree contains a TK_SELECT operator */ #define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */ #define EP_WinFunc 0x1000000 /* TK_FUNCTION with Expr.y.pWin set */ #define EP_Subrtn 0x2000000 /* Uses Expr.y.sub. TK_IN, _SELECT, or _EXISTS */ @@ -2913,8 +2913,8 @@ struct Expr { #define ExprHasAllProperty(E,P) (((E)->flags&(P))==(P)) #define ExprSetProperty(E,P) (E)->flags|=(P) #define ExprClearProperty(E,P) (E)->flags&=~(P) -#define ExprAlwaysTrue(E) (((E)->flags&(EP_FromJoin|EP_IsTrue))==EP_IsTrue) -#define ExprAlwaysFalse(E) (((E)->flags&(EP_FromJoin|EP_IsFalse))==EP_IsFalse) +#define ExprAlwaysTrue(E) (((E)->flags&(EP_OuterON|EP_IsTrue))==EP_IsTrue) +#define ExprAlwaysFalse(E) (((E)->flags&(EP_OuterON|EP_IsFalse))==EP_IsFalse) /* Macros used to ensure that the correct members of unions are accessed ** in Expr. diff --git a/src/treeview.c b/src/treeview.c index 3ff300c38b..4e9ff3eb2c 100644 --- a/src/treeview.c +++ b/src/treeview.c @@ -489,9 +489,12 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ sqlite3StrAccumInit(&x, 0, zFlgs, sizeof(zFlgs), 0); sqlite3_str_appendf(&x, " fg.af=%x.%c", pExpr->flags, pExpr->affExpr ? pExpr->affExpr : 'n'); - if( ExprHasProperty(pExpr, EP_FromJoin) ){ + if( ExprHasProperty(pExpr, EP_OuterON) ){ sqlite3_str_appendf(&x, " iJoin=%d", pExpr->w.iJoin); } + if( ExprHasProperty(pExpr, EP_InnerON) ){ + sqlite3_str_appendf(&x, " inner-ON"); + } if( ExprHasProperty(pExpr, EP_FromDDL) ){ sqlite3_str_appendf(&x, " DDL"); } diff --git a/src/where.c b/src/where.c index a9c6db64e5..8cbf9da89b 100644 --- a/src/where.c +++ b/src/where.c @@ -330,7 +330,7 @@ static WhereTerm *whereScanNext(WhereScan *pScan){ && (iColumn!=XN_EXPR || sqlite3ExprCompareSkip(pTerm->pExpr->pLeft, pScan->pIdxExpr,iCur)==0) - && (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_FromJoin)) + && (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_OuterON)) ){ if( (pTerm->eOperator & WO_EQUIV)!=0 && pScan->nEquivaiCur) @@ -757,7 +757,7 @@ static int termCanDriveIndex( if( pTerm->leftCursor!=pSrc->iCursor ) return 0; if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) return 0; if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 - && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) + && !ExprHasProperty(pTerm->pExpr, EP_OuterON) && (pTerm->eOperator & WO_IS) ){ /* Cannot use an IS term from the WHERE clause as an index driver for @@ -1181,7 +1181,7 @@ static sqlite3_index_info *allocateIndexInfo( ** RIGHT JOIN. See tag-20191211-001 for the ** equivalent restriction for ordinary tables. */ if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 - && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) + && !ExprHasProperty(pTerm->pExpr, EP_OuterON) ){ continue; } @@ -2059,7 +2059,7 @@ void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm){ memcpy(zType, "....", 5); if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V'; if( pTerm->eOperator & WO_EQUIV ) zType[1] = 'E'; - if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L'; + if( ExprHasProperty(pTerm->pExpr, EP_OuterON) ) zType[2] = 'L'; if( pTerm->wtFlags & TERM_CODED ) zType[3] = 'C'; if( pTerm->eOperator & WO_SINGLE ){ assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); @@ -2836,7 +2836,7 @@ static int whereLoopAddBtreeIndex( ** RIGHT JOIN. Only constraints in the ** ON clause are allowed. See tag-20191211-002 for the vtab equivalent. */ if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 - && !ExprHasProperty(pTerm->pExpr, EP_FromJoin|EP_InnerJoin) + && !ExprHasProperty(pTerm->pExpr, EP_OuterON|EP_InnerON) ){ continue; } @@ -3205,8 +3205,8 @@ static int whereUsablePartialIndex( for(i=0, pTerm=pWC->a; inTerm; i++, pTerm++){ Expr *pExpr; pExpr = pTerm->pExpr; - if( (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->w.iJoin==iTab) - && (isLeft==0 || ExprHasProperty(pExpr, EP_FromJoin)) + if( (!ExprHasProperty(pExpr, EP_OuterON) || pExpr->w.iJoin==iTab) + && (isLeft==0 || ExprHasProperty(pExpr, EP_OuterON)) && sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, iTab) && (pTerm->wtFlags & TERM_VNULL)==0 ){ @@ -5214,7 +5214,7 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin( pEnd = pWInfo->sWC.a + pWInfo->sWC.nTerm; for(pTerm=pWInfo->sWC.a; pTermprereqAll & pLoop->maskSelf)!=0 ){ - if( !ExprHasProperty(pTerm->pExpr, EP_FromJoin) + if( !ExprHasProperty(pTerm->pExpr, EP_OuterON) || pTerm->pExpr->w.iJoin!=pItem->iCursor ){ break; diff --git a/src/wherecode.c b/src/wherecode.c index 979944e2ea..2d7602ae38 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -350,7 +350,7 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){ int nLoop = 0; assert( pTerm!=0 ); while( (pTerm->wtFlags & TERM_CODED)==0 - && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin)) + && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_OuterON)) && (pLevel->notReady & pTerm->prereqAll)==0 ){ if( nLoop && (pTerm->wtFlags & TERM_LIKE)!=0 ){ @@ -1072,7 +1072,7 @@ static void codeCursorHint( */ if( pTabItem->fg.jointype & JT_LEFT ){ Expr *pExpr = pTerm->pExpr; - if( !ExprHasProperty(pExpr, EP_FromJoin) + if( !ExprHasProperty(pExpr, EP_OuterON) || pExpr->w.iJoin!=pTabItem->iCursor ){ sWalker.eCode = 0; @@ -1081,7 +1081,7 @@ static void codeCursorHint( if( sWalker.eCode ) continue; } }else{ - if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue; + if( ExprHasProperty(pTerm->pExpr, EP_OuterON) ) continue; } /* All terms in pWLoop->aLTerm[] except pEndRange are used to initialize @@ -2412,7 +2412,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( Expr *pDelete; /* Local copy of OR clause term */ int jmp1 = 0; /* Address of jump operation */ testcase( (pTabItem[0].fg.jointype & JT_LEFT)!=0 - && !ExprHasProperty(pOrExpr, EP_FromJoin) + && !ExprHasProperty(pOrExpr, EP_OuterON) ); /* See TH3 vtab25.400 and ticket 614b25314c766238 */ pDelete = pOrExpr = sqlite3ExprDup(db, pOrExpr, 0); if( db->mallocFailed ){ @@ -2621,7 +2621,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( pE = pTerm->pExpr; assert( pE!=0 ); if( (pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ)) - && (!ExprHasProperty(pE,EP_FromJoin|EP_InnerJoin) + && (!ExprHasProperty(pE,EP_OuterON|EP_InnerON) || pE->w.iJoin!=pTabItem->iCursor) ){ continue; @@ -2693,7 +2693,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( sqlite3WhereTermPrint(pTerm, pWC->nTerm-j); } #endif - assert( !ExprHasProperty(pE, EP_FromJoin) ); + assert( !ExprHasProperty(pE, EP_OuterON) ); assert( (pTerm->prereqRight & pLevel->notReady)!=0 ); assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); pAlt = sqlite3WhereFindTerm(pWC, iCur, pTerm->u.x.leftColumn, notReady, @@ -2846,7 +2846,7 @@ SQLITE_NOINLINE void sqlite3WhereRightJoinLoop( WhereTerm *pTerm = &pWC->a[k]; if( pTerm->wtFlags & TERM_VIRTUAL ) break; if( pTerm->prereqAll & ~mAll ) continue; - if( ExprHasProperty(pTerm->pExpr, EP_FromJoin|EP_InnerJoin) ) continue; + if( ExprHasProperty(pTerm->pExpr, EP_OuterON|EP_InnerON) ) continue; pSubWhere = sqlite3ExprAnd(pParse, pSubWhere, sqlite3ExprDup(pParse->db, pTerm->pExpr, 0)); } diff --git a/src/whereexpr.c b/src/whereexpr.c index 89c6a466ce..8559bd57d9 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -462,7 +462,7 @@ static int isAuxiliaryVtabOperator( */ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){ if( pDerived ){ - pDerived->flags |= pBase->flags & EP_FromJoin; + pDerived->flags |= pBase->flags & EP_OuterON; pDerived->w.iJoin = pBase->w.iJoin; } } @@ -917,7 +917,7 @@ static int termIsEquivalence(Parse *pParse, Expr *pExpr){ CollSeq *pColl; if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0; if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0; - if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0; + if( ExprHasProperty(pExpr, EP_OuterON) ) return 0; aff1 = sqlite3ExprAffinity(pExpr->pLeft); aff2 = sqlite3ExprAffinity(pExpr->pRight); if( aff1!=aff2 @@ -1109,7 +1109,7 @@ static void exprAnalyze( } #endif - if( ExprHasProperty(pExpr, EP_FromJoin) ){ + if( ExprHasProperty(pExpr, EP_OuterON) ){ Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->w.iJoin); prereqAll |= x; extraRight = x-1; /* ON clause terms may not be used with an index @@ -1184,7 +1184,7 @@ static void exprAnalyze( pNew->eOperator = (operatorMask(pDup->op) + eExtraOp) & opMask; }else if( op==TK_ISNULL - && !ExprHasProperty(pExpr,EP_FromJoin) + && !ExprHasProperty(pExpr,EP_OuterON) && 0==sqlite3ExprCanBeNull(pLeft) ){ assert( !ExprHasProperty(pExpr, EP_IntValue) ); @@ -1255,7 +1255,7 @@ static void exprAnalyze( else if( pExpr->op==TK_NOTNULL ){ if( pExpr->pLeft->op==TK_COLUMN && pExpr->pLeft->iColumn>=0 - && !ExprHasProperty(pExpr, EP_FromJoin) + && !ExprHasProperty(pExpr, EP_OuterON) ){ Expr *pNewExpr; Expr *pLeft = pExpr->pLeft; @@ -1459,8 +1459,8 @@ static void exprAnalyze( Expr *pNewExpr; pNewExpr = sqlite3PExpr(pParse, TK_MATCH, 0, sqlite3ExprDup(db, pRight, 0)); - if( ExprHasProperty(pExpr, EP_FromJoin) && pNewExpr ){ - ExprSetProperty(pNewExpr, EP_FromJoin); + if( ExprHasProperty(pExpr, EP_OuterON) && pNewExpr ){ + ExprSetProperty(pNewExpr, EP_OuterON); pNewExpr->w.iJoin = pExpr->w.iJoin; } idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC); @@ -1827,9 +1827,9 @@ void sqlite3WhereTabFuncArgs( sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0); pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, pRhs); if( pItem->fg.jointype & (JT_LEFT|JT_LTORJ) ){ - joinType = EP_FromJoin; + joinType = EP_OuterON; }else{ - joinType = EP_InnerJoin; + joinType = EP_InnerON; } sqlite3SetJoinExpr(pTerm, pItem->iCursor, joinType); whereClauseInsert(pWC, pTerm, TERM_DYNAMIC); From d38355796044a0d76a039ea6cb7e18f20e64d845 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 13 May 2022 15:31:30 +0000 Subject: [PATCH 019/108] New test cases for outer joins. Case joinE-32 currently gets an incorrect answer. See [forum:/forumpost/41cc3851d8|forum post 41cc3851d8] for the bug report. FossilOrigin-Name: 02b24863e6dc617c9260f79292a96b7c861d088268e77fd17204570515eb792c --- manifest | 11 +- manifest.uuid | 2 +- test/joinE.test | 366 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 373 insertions(+), 6 deletions(-) create mode 100644 test/joinE.test diff --git a/manifest b/manifest index e78851efcb..738512ea3b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improved\snames\sfor\sflags\son\sthe\sExpr\sobject:\s\sEP_FromJoin\sbecames\nEP_OuterON\sand\sEP_InnerJoin\sbecomes\sEP_InnerON. -D 2022-05-13T14:52:04.811 +C New\stest\scases\sfor\souter\sjoins.\s\sCase\sjoinE-32\scurrently\sgets\san\sincorrect\nanswer.\s\sSee\s[forum:/forumpost/41cc3851d8|forum\spost\s41cc3851d8]\sfor\sthe\sbug\nreport. +D 2022-05-13T15:31:30.015 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -1154,6 +1154,7 @@ F test/joinA.test 7eab225dc1c1ab258a5e62513a4ed7cabbd3db971d59d5d92f4fb6fa14c12f F test/joinB.test 1b2ba3fc8568b49411787fccbf540570c148e9b6a53a30f80691cb6268098ded F test/joinC.test 1f1a602c2127f55f136e2cbd3bf2d26546614bf8cffe5902ec1ac9c07f87f207 F test/joinD.test 7f0f4dd1f2767330bf1fda5c9cc8a437015a54bcd2355036b4d04ddfc1519d76 +F test/joinE.test b610b61c6e7484d1d93d0544da2c9821ef55c55ca0c36f465db6ac6f8a236903 F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497 F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4 F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e @@ -1953,8 +1954,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 7a2ac303d1436a423a635db63d195097c88160ff46855194f6e630f9d3b3fa82 -R 76628c449717fbf73d51bf54cb4d3e31 +P 1ffea07ff98b894729c698b681cc7433df3bbfccd8a0529a706908602a636937 +R c7a9689e86e2884096bfe487c1ca7e7e U drh -Z db742fa17a2891de768f2e234d496fc9 +Z 94eee899c46b87f17cfa9d895d400453 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index c5b99fbd4d..ef5c015141 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1ffea07ff98b894729c698b681cc7433df3bbfccd8a0529a706908602a636937 \ No newline at end of file +02b24863e6dc617c9260f79292a96b7c861d088268e77fd17204570515eb792c \ No newline at end of file diff --git a/test/joinE.test b/test/joinE.test new file mode 100644 index 0000000000..0b2bcbd0f0 --- /dev/null +++ b/test/joinE.test @@ -0,0 +1,366 @@ +# 2022-05-13 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file implements tests for JOINs that use Bloom filters. +# +# The test case output is (mostly) all generated by PostgreSQL 14. This +# test module was created as follows: +# +# 1. Run a TCL script (included at the bottom of this file) that +# generates an input script for "psql" that will run man +# diverse tests on joins. +# +# 2. Run the script from step (1) through psql and collect the +# output. +# +# 3. Make a few minor global search-and-replace operations to convert +# the psql output into a form suitable for this test module. +# +# 4. Add this header, and the script content at the footer. +# +# A few extra tests that were not generated from postgresql output are +# added at the end. +# +set testdir [file dirname $argv0] +source $testdir/tester.tcl +db nullvalue - +db eval { + CREATE TABLE t1(a INT); + INSERT INTO t1 VALUES(1),(NULL); + CREATE TABLE t2(b INT); + INSERT INTO t2 VALUES(2),(NULL); +} +do_execsql_test joinE-1 { + SELECT a, b + FROM t1 INNER JOIN t2 ON true + ORDER BY coalesce(a,b,3); +} { + 1 2 + 1 - + - 2 + - - +} +do_execsql_test joinE-2 { + SELECT a, b + FROM t1 INNER JOIN t2 ON true WHERE a IS NULL + ORDER BY coalesce(a,b,3); +} { + - 2 + - - +} +do_execsql_test joinE-3 { + SELECT a, b + FROM t1 INNER JOIN t2 ON a IS NULL + ORDER BY coalesce(a,b,3); +} { + - 2 + - - +} +do_execsql_test joinE-4 { + SELECT a, b + FROM t1 INNER JOIN t2 ON true WHERE b IS NULL + ORDER BY coalesce(a,b,3); +} { + 1 - + - - +} +do_execsql_test joinE-5 { + SELECT a, b + FROM t1 INNER JOIN t2 ON b IS NULL + ORDER BY coalesce(a,b,3); +} { + 1 - + - - +} +do_execsql_test joinE-6 { + SELECT a, b + FROM t1 LEFT JOIN t2 ON true + ORDER BY coalesce(a,b,3); +} { + 1 2 + 1 - + - 2 + - - +} +do_execsql_test joinE-7 { + SELECT a, b + FROM t1 LEFT JOIN t2 ON true WHERE a IS NULL + ORDER BY coalesce(a,b,3); +} { + - 2 + - - +} +do_execsql_test joinE-8 { + SELECT a, b + FROM t1 LEFT JOIN t2 ON a IS NULL + ORDER BY coalesce(a,b,3); +} { + 1 - + - 2 + - - +} +do_execsql_test joinE-9 { + SELECT a, b + FROM t1 LEFT JOIN t2 ON true WHERE b IS NULL + ORDER BY coalesce(a,b,3); +} { + 1 - + - - +} +do_execsql_test joinE-10 { + SELECT a, b + FROM t1 LEFT JOIN t2 ON b IS NULL + ORDER BY coalesce(a,b,3); +} { + 1 - + - - +} +do_execsql_test joinE-11 { + SELECT a, b + FROM t1 RIGHT JOIN t2 ON true + ORDER BY coalesce(a,b,3); +} { + 1 2 + 1 - + - 2 + - - +} +do_execsql_test joinE-12 { + SELECT a, b + FROM t1 RIGHT JOIN t2 ON true WHERE a IS NULL + ORDER BY coalesce(a,b,3); +} { + - 2 + - - +} +do_execsql_test joinE-13 { + SELECT a, b + FROM t1 RIGHT JOIN t2 ON a IS NULL + ORDER BY coalesce(a,b,3); +} { + - 2 + - - +} +do_execsql_test joinE-14 { + SELECT a, b + FROM t1 RIGHT JOIN t2 ON true WHERE b IS NULL + ORDER BY coalesce(a,b,3); +} { + 1 - + - - +} +do_execsql_test joinE-15 { + SELECT a, b + FROM t1 RIGHT JOIN t2 ON b IS NULL + ORDER BY coalesce(a,b,3); +} { + 1 - + - 2 + - - +} +do_execsql_test joinE-16 { + SELECT a, b + FROM t1 FULL JOIN t2 ON true + ORDER BY coalesce(a,b,3); +} { + 1 2 + 1 - + - 2 + - - +} +do_execsql_test joinE-17 { + SELECT a, b + FROM t1 FULL JOIN t2 ON true WHERE a IS NULL + ORDER BY coalesce(a,b,3); +} { + - 2 + - - +} + +# PG-14 is unable to perform this join. It says: FULL JOIN is only +# supported with merge-joinable or hash-joinable join conditions +# +# do_execsql_test joinE-18 { +# SELECT a, b +# FROM t1 FULL JOIN t2 ON a IS NULL +# ORDER BY coalesce(a,b,3); +# } { +# } + +do_execsql_test joinE-19 { + SELECT a, b + FROM t1 FULL JOIN t2 ON true WHERE b IS NULL + ORDER BY coalesce(a,b,3); +} { + 1 - + - - +} + +# PG-14 is unable to perform this join. It says: FULL JOIN is only +# supported with merge-joinable or hash-joinable join conditions +# +# do_execsql_test joinE-20 { +# SELECT a, b +# FROM t1 FULL JOIN t2 ON b IS NULL +# ORDER BY coalesce(a,b,3); +# } { +# } + +db eval { + DELETE FROM t1; + INSERT INTO t1 VALUES(1); + DELETE FROM t2; + INSERT INTO t2 VALUES(NULL); +} + +do_execsql_test joinE-21 { + SELECT a, b + FROM t1 INNER JOIN t2 ON true + ORDER BY coalesce(a,b,3); +} { + 1 - +} +do_execsql_test joinE-22 { + SELECT a, b + FROM t1 INNER JOIN t2 ON true WHERE a IS NULL + ORDER BY coalesce(a,b,3); +} { +} +do_execsql_test joinE-23 { + SELECT a, b + FROM t1 INNER JOIN t2 ON a IS NULL + ORDER BY coalesce(a,b,3); +} { +} +do_execsql_test joinE-24 { + SELECT a, b + FROM t1 INNER JOIN t2 ON true WHERE b IS NULL + ORDER BY coalesce(a,b,3); +} { + 1 - +} +do_execsql_test joinE-25 { + SELECT a, b + FROM t1 INNER JOIN t2 ON b IS NULL + ORDER BY coalesce(a,b,3); +} { + 1 - +} +do_execsql_test joinE-26 { + SELECT a, b + FROM t1 LEFT JOIN t2 ON true + ORDER BY coalesce(a,b,3); +} { + 1 - +} +do_execsql_test joinE-27 { + SELECT a, b + FROM t1 LEFT JOIN t2 ON true WHERE a IS NULL + ORDER BY coalesce(a,b,3); +} { +} +do_execsql_test joinE-28 { + SELECT a, b + FROM t1 LEFT JOIN t2 ON a IS NULL + ORDER BY coalesce(a,b,3); +} { + 1 - +} +do_execsql_test joinE-29 { + SELECT a, b + FROM t1 LEFT JOIN t2 ON true WHERE b IS NULL + ORDER BY coalesce(a,b,3); +} { + 1 - +} +do_execsql_test joinE-30 { + SELECT a, b + FROM t1 LEFT JOIN t2 ON b IS NULL + ORDER BY coalesce(a,b,3); +} { + 1 - +} +do_execsql_test joinE-31 { + SELECT a, b + FROM t1 RIGHT JOIN t2 ON true + ORDER BY coalesce(a,b,3); +} { + 1 - +} + +do_execsql_test joinE-32 { + SELECT a, b + FROM t1 RIGHT JOIN t2 ON true WHERE a IS NULL + ORDER BY coalesce(a,b,3); +} { +} + +do_execsql_test joinE-33 { + SELECT a, b + FROM t1 RIGHT JOIN t2 ON a IS NULL + ORDER BY coalesce(a,b,3); +} { + - - +} +do_execsql_test joinE-34 { + SELECT a, b + FROM t1 RIGHT JOIN t2 ON true WHERE b IS NULL + ORDER BY coalesce(a,b,3); +} { + 1 - +} +do_execsql_test joinE-35 { + SELECT a, b + FROM t1 RIGHT JOIN t2 ON b IS NULL + ORDER BY coalesce(a,b,3); +} { + 1 - +} +do_execsql_test joinE-36 { + SELECT a, b + FROM t1 FULL JOIN t2 ON true + ORDER BY coalesce(a,b,3); +} { + 1 - +} +do_execsql_test joinE-37 { + SELECT a, b + FROM t1 FULL JOIN t2 ON true WHERE a IS NULL + ORDER BY coalesce(a,b,3); +} { +} + +# PG-14 is unable +# +# do_execsql_test joinE-38 { +# SELECT a, b +# FROM t1 FULL JOIN t2 ON a IS NULL +# ORDER BY coalesce(a,b,3); +# } { +# } + +do_execsql_test joinE-39 { + SELECT a, b + FROM t1 FULL JOIN t2 ON true WHERE b IS NULL + ORDER BY coalesce(a,b,3); +} { + 1 - +} + +# PG-14 is unable +# do_execsql_test joinE-40 { +# SELECT a, b +# FROM t1 FULL JOIN t2 ON b IS NULL +# ORDER BY coalesce(a,b,3); +# } { +# } + +finish_test From f8d2745f99fdde443cbc8c828c231f536c17884b Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 13 May 2022 15:36:47 +0000 Subject: [PATCH 020/108] Corrections to the header comment to the new joinE.test script. Add the generator TCL as a comment at the bottom of the script. FossilOrigin-Name: 2f4456f67f64f131fc852ad9a7420eb43b57b879a9bec7e4b295f1dc0d7bfa56 --- manifest | 12 +++---- manifest.uuid | 2 +- test/joinE.test | 83 +++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 87 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 738512ea3b..90053099e7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C New\stest\scases\sfor\souter\sjoins.\s\sCase\sjoinE-32\scurrently\sgets\san\sincorrect\nanswer.\s\sSee\s[forum:/forumpost/41cc3851d8|forum\spost\s41cc3851d8]\sfor\sthe\sbug\nreport. -D 2022-05-13T15:31:30.015 +C Corrections\sto\sthe\sheader\scomment\sto\sthe\snew\sjoinE.test\sscript.\s\sAdd\sthe\ngenerator\sTCL\sas\sa\scomment\sat\sthe\sbottom\sof\sthe\sscript. +D 2022-05-13T15:36:47.140 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -1154,7 +1154,7 @@ F test/joinA.test 7eab225dc1c1ab258a5e62513a4ed7cabbd3db971d59d5d92f4fb6fa14c12f F test/joinB.test 1b2ba3fc8568b49411787fccbf540570c148e9b6a53a30f80691cb6268098ded F test/joinC.test 1f1a602c2127f55f136e2cbd3bf2d26546614bf8cffe5902ec1ac9c07f87f207 F test/joinD.test 7f0f4dd1f2767330bf1fda5c9cc8a437015a54bcd2355036b4d04ddfc1519d76 -F test/joinE.test b610b61c6e7484d1d93d0544da2c9821ef55c55ca0c36f465db6ac6f8a236903 +F test/joinE.test d5d182f3812771e2c0d97c9dcf5dbe4c41c8e21c82560e59358731c4a3981d6b F test/journal1.test c7b768041b7f494471531e17abc2f4f5ebf9e5096984f43ed17c4eb80ba34497 F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4 F test/journal3.test 7c3cf23ffc77db06601c1fcfc9743de8441cb77db9d1aa931863d94f5ffa140e @@ -1954,8 +1954,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 1ffea07ff98b894729c698b681cc7433df3bbfccd8a0529a706908602a636937 -R c7a9689e86e2884096bfe487c1ca7e7e +P 02b24863e6dc617c9260f79292a96b7c861d088268e77fd17204570515eb792c +R 167bc393f082329eafd5eddb2ff31acf U drh -Z 94eee899c46b87f17cfa9d895d400453 +Z 3187fb402b840f2b66e20fdf22743291 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index ef5c015141..0747926b91 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -02b24863e6dc617c9260f79292a96b7c861d088268e77fd17204570515eb792c \ No newline at end of file +2f4456f67f64f131fc852ad9a7420eb43b57b879a9bec7e4b295f1dc0d7bfa56 \ No newline at end of file diff --git a/test/joinE.test b/test/joinE.test index 0b2bcbd0f0..8c8e72ab2d 100644 --- a/test/joinE.test +++ b/test/joinE.test @@ -26,9 +26,6 @@ # # 4. Add this header, and the script content at the footer. # -# A few extra tests that were not generated from postgresql output are -# added at the end. -# set testdir [file dirname $argv0] source $testdir/tester.tcl db nullvalue - @@ -364,3 +361,83 @@ do_execsql_test joinE-39 { # } finish_test + +############################################################################## +# This is the PG-14 test script generator +# +# puts " +# \\pset border off +# \\pset tuples_only on +# \\pset null - +# +# DROP TABLE IF EXISTS t1; +# DROP TABLE IF EXISTS t2; +# CREATE TABLE t1(a INT); +# INSERT INTO t1 VALUES(1),(NULL); +# CREATE TABLE t2(b INT); +# INSERT INTO t2 VALUES(2),(NULL); +# " +# +# proc echo {prefix txt} { +# regsub -all {\n} $txt \n$prefix txt +# puts "$prefix$txt" +# } +# +# set n 0 +# set k 0 +# foreach j1 {INNER LEFT RIGHT FULL} { +# foreach on1 { +# true +# {true WHERE a IS NULL} +# {a IS NULL} +# {true WHERE b IS NULL} +# {b IS NULL} +# } { +# +# incr n +# incr k +# set q1 "" +# append q1 "SELECT a, b\n" +# append q1 " FROM t1 $j1 JOIN t2 ON $on1\n" +# append q1 " ORDER BY coalesce(a,b,3);" +# +# echo "\\qecho " "do_execsql_test joinE-$n \{" +# echo "\\qecho X " $q1 +# echo "\\qecho " "\} \{" +# puts $q1 +# echo "\\qecho " "\}" +# +# } +# } +# +# puts " +# DELETE FROM t1; +# INSERT INTO t1 VALUES(1); +# DELETE FROM t2; +# INSERT INTO t2 VALUES(NULL); +# " +# +# foreach j1 {INNER LEFT RIGHT FULL} { +# foreach on1 { +# true +# {true WHERE a IS NULL} +# {a IS NULL} +# {true WHERE b IS NULL} +# {b IS NULL} +# } { +# +# incr n +# incr k +# set q1 "" +# append q1 "SELECT a, b\n" +# append q1 " FROM t1 $j1 JOIN t2 ON $on1\n" +# append q1 " ORDER BY coalesce(a,b,3);" +# +# echo "\\qecho " "do_execsql_test joinE-$n \{" +# echo "\\qecho X " $q1 +# echo "\\qecho " "\} \{" +# puts $q1 +# echo "\\qecho " "\}" +# +# } +# } From a6e8ee12e2bbb353ae4548e38083d1855f7b86aa Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 13 May 2022 16:38:40 +0000 Subject: [PATCH 021/108] Redefine the acccess rules for the Expr.w union so that the Expr.w.iJoin member is accessible on either EP_OuterON or EP_InnerON. FossilOrigin-Name: 6f741d6cfb8831a3ac966257ac4519bcc8156293447bf50323c2d9b170125974 --- manifest | 20 ++++++++++---------- manifest.uuid | 2 +- src/expr.c | 1 + src/printf.c | 4 +++- src/sqliteInt.h | 2 +- src/treeview.c | 4 ++-- src/whereexpr.c | 4 ++-- 7 files changed, 20 insertions(+), 17 deletions(-) diff --git a/manifest b/manifest index 90053099e7..6f34da7163 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Corrections\sto\sthe\sheader\scomment\sto\sthe\snew\sjoinE.test\sscript.\s\sAdd\sthe\ngenerator\sTCL\sas\sa\scomment\sat\sthe\sbottom\sof\sthe\sscript. -D 2022-05-13T15:36:47.140 +C Redefine\sthe\sacccess\srules\sfor\sthe\sExpr.w\sunion\sso\sthat\sthe\sExpr.w.iJoin\nmember\sis\saccessible\son\seither\sEP_OuterON\sor\sEP_InnerON. +D 2022-05-13T16:38:40.228 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -504,7 +504,7 @@ F src/date.c 15082566229d4b1e5f24fdb490bf9bcc68824b911d70e3573ef075a1b9e2d26f F src/dbpage.c 90661a87e1db8bfbc8d2ebbdcd3749651ddb287c555c07a28fb17c7c591ffb68 F src/dbstat.c 861e08690fcb0f2ee1165eff0060ea8d4f3e2ea10f80dab7d32ad70443a6ff2d F src/delete.c a8e844af211a48b13b5b358be77a12c860c6a557c21990ad51a548e2536500ce -F src/expr.c 8c5ca4fb4089cc3a3441f25087356702a45c6aca417b76fcb82622428fb7265e +F src/expr.c d73ac75456ac14b1147eecc8c30bf08a0cb91b7f97c62632222a52f6222a9aa9 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c d965ede15d8360c09ed59348940649ee647b192e784466837d7aefa836d1d91e F src/func.c a3407a6fbb0d4088d8d502e46f0ace63e0aeae7467ae23a9ca9815bbf9239761 @@ -549,7 +549,7 @@ F src/pcache1.c 54881292a9a5db202b2c0ac541c5e3ef9a5e8c4f1c1383adb2601d5499a60e65 F src/pragma.c d1aead03e8418ff586c7cfca344c50a914b8eb06abd841e8e91a982d823671da F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7 F src/prepare.c c62820c15dcb63013519c8e41d9f928d7478672cc902cfd0581c733c271dbf45 -F src/printf.c 320fd82b2b203e584c87e5a85e80a4be8d926f8aacbccc53ec6b01bbc305ef8c +F src/printf.c 6166a30417b05c5b2f82e1f183f75faa2926ad60531c0b688a57dbc951441a20 F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c a4eb3c617027fd049b07432f3b942ea7151fa793a332a11a7d0f58c9539e104f F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 @@ -558,7 +558,7 @@ F src/shell.c.in 176cad562152cbbafe7ecc9c83c82850e2c3d0cf33ec0a52d67341d35c842f2 F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h f49e28c25bd941e79794db5415fdf7b202deb3bc072ed6f1ed273d578703684e -F src/sqliteInt.h ba4057968afd2fbd0fd72c1a6d6cc5a7b568437f47b476106993da32bde5645b +F src/sqliteInt.h 1f9e228f1b416536833913a8a1733f01a36e85f0330bbd90a0dd68f9a8613ee3 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4a3da6d77eeb3531cb0dbdf7047772a2a1b99f98c69e90ce009c75fe6328b2c0 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -618,7 +618,7 @@ F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c a38f52058b517929e264094abd0b5fd1e8e145a1aa43bc6f6a72ae5218f96c98 -F src/treeview.c ae4a3c115c630ab5b779b66590a2d029329f2df050c2f35195cf1bbd2922decb +F src/treeview.c 73facf395c8841653b9a54e789d8c80e15bc3d0d1cb9d16104c2d889c15e33cd F src/trigger.c 4fe4c1ac811755aff49d669d2e52e414eb5dfa6e172e849ab7b6825e70a571c0 F src/update.c 2cfaded82ca80ff56afb8c3ae5e88284e0824bfd86119827cc22481959f96f92 F src/upsert.c 8789047a8f0a601ea42fa0256d1ba3190c13746b6ba940fe2d25643a7e991937 @@ -643,7 +643,7 @@ F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b F src/where.c d4d543f06b09ff8bac05072b015a2181f9c48561b1a146158aaaf09e40817567 F src/whereInt.h 8da918f392bf202ccc0ee61291455b33ad171d209445f1ff3eaf62e0b6f6b363 F src/wherecode.c 51aba5a09657c0400f76453e221aebe2abf488f6ef6345ae89c32468e36a0639 -F src/whereexpr.c 98e4e3fb3d10be2039de9b059ba04c6f5a500d17e9bd2ccc470d14f44b2a317d +F src/whereexpr.c efed370c684dce04eab949202c5452bbde993efb198de43c7a88f59411ad2a2c F src/window.c fff1b51757438c664e471d5184634e48dcdf8ea34b640f3b1b0810b1e06de18c F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627 @@ -1954,8 +1954,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 02b24863e6dc617c9260f79292a96b7c861d088268e77fd17204570515eb792c -R 167bc393f082329eafd5eddb2ff31acf +P 2f4456f67f64f131fc852ad9a7420eb43b57b879a9bec7e4b295f1dc0d7bfa56 +R 9b69af380ecbac169382f655ff732cd6 U drh -Z 3187fb402b840f2b66e20fdf22743291 +Z e0160850b64686ab8a3060154919b222 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 0747926b91..fa8f720046 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2f4456f67f64f131fc852ad9a7420eb43b57b879a9bec7e4b295f1dc0d7bfa56 \ No newline at end of file +6f741d6cfb8831a3ac966257ac4519bcc8156293447bf50323c2d9b170125974 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 2965457d92..64c0651687 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1069,6 +1069,7 @@ Expr *sqlite3ExprFunction( sqlite3ExprListDelete(db, pList); /* Avoid memory leak when malloc fails */ return 0; } + assert( !ExprHasProperty(pNew, EP_InnerON|EP_OuterON) ); pNew->w.iOfst = (int)(pToken->z - pParse->zTail); if( pList && pList->nExpr > pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] diff --git a/src/printf.c b/src/printf.c index 41ce4ac7ab..f0bfa53279 100644 --- a/src/printf.c +++ b/src/printf.c @@ -954,7 +954,9 @@ void sqlite3RecordErrorByteOffset(sqlite3 *db, const char *z){ ** as the error offset. */ void sqlite3RecordErrorOffsetOfExpr(sqlite3 *db, const Expr *pExpr){ - while( pExpr && (ExprHasProperty(pExpr,EP_OuterON) || pExpr->w.iOfst<=0) ){ + while( pExpr + && (ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) || pExpr->w.iOfst<=0) + ){ pExpr = pExpr->pLeft; } if( pExpr==0 ) return; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index ff11d12a2d..22f38ae912 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2847,7 +2847,7 @@ struct Expr { ** TK_SELECT_COLUMN: column of the result vector */ i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */ union { - int iJoin; /* If EP_OuterON, the right table of the join */ + int iJoin; /* If EP_OuterON or EP_InnerON, the right table */ int iOfst; /* else: start of token from start of statement */ } w; AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */ diff --git a/src/treeview.c b/src/treeview.c index 4e9ff3eb2c..90408b0a57 100644 --- a/src/treeview.c +++ b/src/treeview.c @@ -490,10 +490,10 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ sqlite3_str_appendf(&x, " fg.af=%x.%c", pExpr->flags, pExpr->affExpr ? pExpr->affExpr : 'n'); if( ExprHasProperty(pExpr, EP_OuterON) ){ - sqlite3_str_appendf(&x, " iJoin=%d", pExpr->w.iJoin); + sqlite3_str_appendf(&x, " outer.iJoin=%d", pExpr->w.iJoin); } if( ExprHasProperty(pExpr, EP_InnerON) ){ - sqlite3_str_appendf(&x, " inner-ON"); + sqlite3_str_appendf(&x, " inner.iJoin=%d", pExpr->w.iJoin); } if( ExprHasProperty(pExpr, EP_FromDDL) ){ sqlite3_str_appendf(&x, " DDL"); diff --git a/src/whereexpr.c b/src/whereexpr.c index 8559bd57d9..22dd730ef1 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -461,8 +461,8 @@ static int isAuxiliaryVtabOperator( ** a join, then transfer the appropriate markings over to derived. */ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){ - if( pDerived ){ - pDerived->flags |= pBase->flags & EP_OuterON; + if( pDerived && ExprHasProperty(pBase, EP_OuterON|EP_InnerON) ){ + pDerived->flags |= pBase->flags & (EP_OuterON|EP_InnerON); pDerived->w.iJoin = pBase->w.iJoin; } } From 767bc8de8e3859777eab42a32e034ef807759f8a Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 13 May 2022 17:45:52 +0000 Subject: [PATCH 022/108] Defer generating WHERE clause constraints for a RIGHT JOIN until after the ON-clause processing for the RIGHT JOIN has done its own row elimination. This fixes and incorrect output from some RIGHT JOINs that was identified by [forum:/forumpost/41cc3851d864c5e6|forum post 41cc3851d864c5e6]. FossilOrigin-Name: 238d9c247cf69cc77fdb1af9d42ebe258610a533ac4204e2ddf8af17f24d18c4 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/wherecode.c | 38 +++++++++++++++++++++++++------------- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/manifest b/manifest index 6f34da7163..f8617c2bc5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Redefine\sthe\sacccess\srules\sfor\sthe\sExpr.w\sunion\sso\sthat\sthe\sExpr.w.iJoin\nmember\sis\saccessible\son\seither\sEP_OuterON\sor\sEP_InnerON. -D 2022-05-13T16:38:40.228 +C Defer\sgenerating\sWHERE\sclause\sconstraints\sfor\sa\sRIGHT\sJOIN\suntil\safter\sthe\nON-clause\sprocessing\sfor\sthe\sRIGHT\sJOIN\shas\sdone\sits\sown\srow\selimination.\nThis\sfixes\sand\sincorrect\soutput\sfrom\ssome\sRIGHT\sJOINs\sthat\swas\sidentified\nby\s[forum:/forumpost/41cc3851d864c5e6|forum\spost\s41cc3851d864c5e6]. +D 2022-05-13T17:45:52.976 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -642,7 +642,7 @@ F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b F src/where.c d4d543f06b09ff8bac05072b015a2181f9c48561b1a146158aaaf09e40817567 F src/whereInt.h 8da918f392bf202ccc0ee61291455b33ad171d209445f1ff3eaf62e0b6f6b363 -F src/wherecode.c 51aba5a09657c0400f76453e221aebe2abf488f6ef6345ae89c32468e36a0639 +F src/wherecode.c 4ffa652982b8233b028bed36a4cb6d9293484e75b80f236772ff3c1a91816eca F src/whereexpr.c efed370c684dce04eab949202c5452bbde993efb198de43c7a88f59411ad2a2c F src/window.c fff1b51757438c664e471d5184634e48dcdf8ea34b640f3b1b0810b1e06de18c F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 @@ -1954,8 +1954,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 2f4456f67f64f131fc852ad9a7420eb43b57b879a9bec7e4b295f1dc0d7bfa56 -R 9b69af380ecbac169382f655ff732cd6 +P 6f741d6cfb8831a3ac966257ac4519bcc8156293447bf50323c2d9b170125974 +R bc3436cf9c17c2665a43b91d0b429cda U drh -Z e0160850b64686ab8a3060154919b222 +Z 7f18b62d8d1b8431770b8960ee426eac # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index fa8f720046..b0fc81ce25 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6f741d6cfb8831a3ac966257ac4519bcc8156293447bf50323c2d9b170125974 \ No newline at end of file +238d9c247cf69cc77fdb1af9d42ebe258610a533ac4204e2ddf8af17f24d18c4 \ No newline at end of file diff --git a/src/wherecode.c b/src/wherecode.c index 2d7602ae38..e079b944e3 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -2620,10 +2620,12 @@ Bitmask sqlite3WhereCodeOneLoopStart( } pE = pTerm->pExpr; assert( pE!=0 ); - if( (pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ)) + if( (pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT)) && (!ExprHasProperty(pE,EP_OuterON|EP_InnerON) || pE->w.iJoin!=pTabItem->iCursor) ){ + /* Defer processing WHERE clause constraints until after outer + ** join processing. tag-20220513a */ continue; } @@ -2764,18 +2766,8 @@ Bitmask sqlite3WhereCodeOneLoopStart( pLevel->addrFirst = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin); VdbeComment((v, "record LEFT JOIN hit")); - for(pTerm=pWC->a, j=0; jnBase; j++, pTerm++){ - testcase( pTerm->wtFlags & TERM_VIRTUAL ); - testcase( pTerm->wtFlags & TERM_CODED ); - if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; - if( (pTerm->prereqAll & pLevel->notReady)!=0 ){ - assert( pWInfo->untestedTerms ); - continue; - } - if( pTabItem->fg.jointype & JT_LTORJ ) continue; - assert( pTerm->pExpr ); - sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL); - pTerm->wtFlags |= TERM_CODED; + if( pLevel->pRJ==0 ){ + goto code_outer_join_constraints; /* WHERE clause constraints */ } } @@ -2791,6 +2783,26 @@ Bitmask sqlite3WhereCodeOneLoopStart( pRJ->addrSubrtn = sqlite3VdbeCurrentAddr(v); assert( pParse->withinRJSubrtn < 255 ); pParse->withinRJSubrtn++; + + /* WHERE clause constraints must be deferred until after outer join + ** row elimination has completed, since WHERE clause constraints apply + ** to the results of the OUTER JOIN. The following loop generates the + ** appropriate WHERE clause constraint checks. tag-20220513a. + */ + code_outer_join_constraints: + for(pTerm=pWC->a, j=0; jnBase; j++, pTerm++){ + testcase( pTerm->wtFlags & TERM_VIRTUAL ); + testcase( pTerm->wtFlags & TERM_CODED ); + if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; + if( (pTerm->prereqAll & pLevel->notReady)!=0 ){ + assert( pWInfo->untestedTerms ); + continue; + } + if( pTabItem->fg.jointype & JT_LTORJ ) continue; + assert( pTerm->pExpr ); + sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL); + pTerm->wtFlags |= TERM_CODED; + } } #if WHERETRACE_ENABLED /* 0x20800 */ From f69dad8c53c70002c5b2b9755bb89f4051f15eae Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 13 May 2022 19:50:29 +0000 Subject: [PATCH 023/108] Walk back the optimization from check-in [cc458317bd77046c] that tries to reuse the same ephemeral cursor of a list subquery when that subquery is reused, as it does not work in cases where the list subquery is used both for lookups and for scans. FossilOrigin-Name: 12ee29d632ae4b585ef6bc07d3289d00c121268945dffd5673b251d95874e3f8 --- manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/expr.c | 6 +----- src/sqliteInt.h | 1 - src/wherecode.c | 3 +-- test/join8.test | 11 +++++++++++ 6 files changed, 23 insertions(+), 18 deletions(-) diff --git a/manifest b/manifest index f8617c2bc5..d877295091 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Defer\sgenerating\sWHERE\sclause\sconstraints\sfor\sa\sRIGHT\sJOIN\suntil\safter\sthe\nON-clause\sprocessing\sfor\sthe\sRIGHT\sJOIN\shas\sdone\sits\sown\srow\selimination.\nThis\sfixes\sand\sincorrect\soutput\sfrom\ssome\sRIGHT\sJOINs\sthat\swas\sidentified\nby\s[forum:/forumpost/41cc3851d864c5e6|forum\spost\s41cc3851d864c5e6]. -D 2022-05-13T17:45:52.976 +C Walk\sback\sthe\soptimization\sfrom\scheck-in\s[cc458317bd77046c]\sthat\stries\sto\nreuse\sthe\ssame\sephemeral\scursor\sof\sa\slist\ssubquery\swhen\sthat\ssubquery\sis\nreused,\sas\sit\sdoes\snot\swork\sin\scases\swhere\sthe\slist\ssubquery\sis\sused\sboth\nfor\slookups\sand\sfor\sscans. +D 2022-05-13T19:50:29.681 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -504,7 +504,7 @@ F src/date.c 15082566229d4b1e5f24fdb490bf9bcc68824b911d70e3573ef075a1b9e2d26f F src/dbpage.c 90661a87e1db8bfbc8d2ebbdcd3749651ddb287c555c07a28fb17c7c591ffb68 F src/dbstat.c 861e08690fcb0f2ee1165eff0060ea8d4f3e2ea10f80dab7d32ad70443a6ff2d F src/delete.c a8e844af211a48b13b5b358be77a12c860c6a557c21990ad51a548e2536500ce -F src/expr.c d73ac75456ac14b1147eecc8c30bf08a0cb91b7f97c62632222a52f6222a9aa9 +F src/expr.c b4328d113e600cf99897d32d733b3db7e6c46689adf6745bd3a1d88f7eb4d613 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c d965ede15d8360c09ed59348940649ee647b192e784466837d7aefa836d1d91e F src/func.c a3407a6fbb0d4088d8d502e46f0ace63e0aeae7467ae23a9ca9815bbf9239761 @@ -558,7 +558,7 @@ F src/shell.c.in 176cad562152cbbafe7ecc9c83c82850e2c3d0cf33ec0a52d67341d35c842f2 F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h f49e28c25bd941e79794db5415fdf7b202deb3bc072ed6f1ed273d578703684e -F src/sqliteInt.h 1f9e228f1b416536833913a8a1733f01a36e85f0330bbd90a0dd68f9a8613ee3 +F src/sqliteInt.h fbe2d12cc13e80ac88c69ecde5ef9f052025fba78aa10f3eed0c71a5302e9a76 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4a3da6d77eeb3531cb0dbdf7047772a2a1b99f98c69e90ce009c75fe6328b2c0 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -642,7 +642,7 @@ F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b F src/where.c d4d543f06b09ff8bac05072b015a2181f9c48561b1a146158aaaf09e40817567 F src/whereInt.h 8da918f392bf202ccc0ee61291455b33ad171d209445f1ff3eaf62e0b6f6b363 -F src/wherecode.c 4ffa652982b8233b028bed36a4cb6d9293484e75b80f236772ff3c1a91816eca +F src/wherecode.c 76e9d8e8ce50b58fbfabc4cea2e8e7205c4b6a94551c80d24f768009d2a68fc3 F src/whereexpr.c efed370c684dce04eab949202c5452bbde993efb198de43c7a88f59411ad2a2c F src/window.c fff1b51757438c664e471d5184634e48dcdf8ea34b640f3b1b0810b1e06de18c F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 @@ -1148,7 +1148,7 @@ F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join5.test d22b6cba8fb59ab3f1c82701434c360705eb12d4ce200c449f37b018fc47681a F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c F test/join7.test 8e72de4b45e5e930d18c305c7efe86015fb2552731e4e03ea226353036b0dab0 -F test/join8.test 9b83dc70b7e9f7d4ee0022a0fe44ec1858f103530c7eb253c10adb63aad16ec4 +F test/join8.test e736975960adc06e94eed24f2ba6eacf6a6026dbf42d67ed65c4afb2faca59d2 F test/join9.test 9056ddd3b0c0f4f9d658f4521038d9a37dc23ead8ca9a505d0b0db2b6a471e05 F test/joinA.test 7eab225dc1c1ab258a5e62513a4ed7cabbd3db971d59d5d92f4fb6fa14c12f6a F test/joinB.test 1b2ba3fc8568b49411787fccbf540570c148e9b6a53a30f80691cb6268098ded @@ -1954,8 +1954,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 6f741d6cfb8831a3ac966257ac4519bcc8156293447bf50323c2d9b170125974 -R bc3436cf9c17c2665a43b91d0b429cda +P 238d9c247cf69cc77fdb1af9d42ebe258610a533ac4204e2ddf8af17f24d18c4 +R 9a86ed9913b4ded0c8e7923e434811db U drh -Z 7f18b62d8d1b8431770b8960ee426eac +Z c59d4810013018d66fb5815f061f58db # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index b0fc81ce25..2f3c29acc2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -238d9c247cf69cc77fdb1af9d42ebe258610a533ac4204e2ddf8af17f24d18c4 \ No newline at end of file +12ee29d632ae4b585ef6bc07d3289d00c121268945dffd5673b251d95874e3f8 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 64c0651687..b7e6c25fa5 100644 --- a/src/expr.c +++ b/src/expr.c @@ -2746,11 +2746,7 @@ int sqlite3FindInIndex( assert( pX->op==TK_IN ); mustBeUnique = (inFlags & IN_INDEX_LOOP)!=0; - if( pX->iTable && (inFlags & IN_INDEX_REUSE_CUR)!=0 ){ - iTab = pX->iTable; - }else{ - iTab = pParse->nTab++; - } + iTab = pParse->nTab++; /* If the RHS of this IN(...) operator is a SELECT, and if it matters ** whether or not the SELECT result contains NULL values, check whether diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 22f38ae912..a22bb72883 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -5322,7 +5322,6 @@ const char *sqlite3JournalModename(int); #define IN_INDEX_NOOP_OK 0x0001 /* OK to return IN_INDEX_NOOP */ #define IN_INDEX_MEMBERSHIP 0x0002 /* IN operator used for membership test */ #define IN_INDEX_LOOP 0x0004 /* IN operator used as a loop */ -#define IN_INDEX_REUSE_CUR 0x0008 /* Reuse prior table cursor */ int sqlite3FindInIndex(Parse *, Expr *, u32, int*, int*, int*); int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int); diff --git a/src/wherecode.c b/src/wherecode.c index e079b944e3..4d23622754 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -623,8 +623,7 @@ static int codeEqualityTerm( sqlite3ExprDelete(db, pX); }else{ aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq); - eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP|IN_INDEX_REUSE_CUR, 0, aiMap,&iTab); - iTab = pExpr->iTable; + eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap, &iTab); } pX = pExpr; } diff --git a/test/join8.test b/test/join8.test index 05d400470a..76bda946cd 100644 --- a/test/join8.test +++ b/test/join8.test @@ -283,4 +283,15 @@ do_execsql_test join8-8020 { JOIN t1 ON (t3.e IS NOT DISTINCT FROM t2.c); } {} +# 2022-05-13 The idea of reusing subquery cursors does not +# work, if the cursors are used both for scanning and lookups. +# +reset_db +db null - +do_execsql_test join8-9000 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT, c TEXT, d REAL); + INSERT INTO t1 VALUES(1,'E','bb',NULL),(2,NULL,NULL,NULL); + SELECT * FROM t1 NATURAL RIGHT JOIN t1 AS t2 WHERE (a,b) IN (SELECT a+0, b FROM t1); +} {1 E bb -} + finish_test From 556527a15426a3362ddcde357096b091280f4825 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 13 May 2022 20:11:32 +0000 Subject: [PATCH 024/108] Transitive equality constriants do not work on a RIGHT JOIN, since the right-hand side might be a non-matched row. FossilOrigin-Name: 0f96810b840dd6f209562635b21f55a7ed6210c01336fcfeb3b79e08a615a28d --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/wherecode.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index d877295091..dd38d6bca1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Walk\sback\sthe\soptimization\sfrom\scheck-in\s[cc458317bd77046c]\sthat\stries\sto\nreuse\sthe\ssame\sephemeral\scursor\sof\sa\slist\ssubquery\swhen\sthat\ssubquery\sis\nreused,\sas\sit\sdoes\snot\swork\sin\scases\swhere\sthe\slist\ssubquery\sis\sused\sboth\nfor\slookups\sand\sfor\sscans. -D 2022-05-13T19:50:29.681 +C Transitive\sequality\sconstriants\sdo\snot\swork\son\sa\sRIGHT\sJOIN,\ssince\sthe\nright-hand\sside\smight\sbe\sa\snon-matched\srow. +D 2022-05-13T20:11:32.182 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -642,7 +642,7 @@ F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b F src/where.c d4d543f06b09ff8bac05072b015a2181f9c48561b1a146158aaaf09e40817567 F src/whereInt.h 8da918f392bf202ccc0ee61291455b33ad171d209445f1ff3eaf62e0b6f6b363 -F src/wherecode.c 76e9d8e8ce50b58fbfabc4cea2e8e7205c4b6a94551c80d24f768009d2a68fc3 +F src/wherecode.c c45ba0294d9c412f9ee57831bbf1fa14f8be1599e529d6d02416d4b608926c64 F src/whereexpr.c efed370c684dce04eab949202c5452bbde993efb198de43c7a88f59411ad2a2c F src/window.c fff1b51757438c664e471d5184634e48dcdf8ea34b640f3b1b0810b1e06de18c F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 @@ -1954,8 +1954,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 238d9c247cf69cc77fdb1af9d42ebe258610a533ac4204e2ddf8af17f24d18c4 -R 9a86ed9913b4ded0c8e7923e434811db +P 12ee29d632ae4b585ef6bc07d3289d00c121268945dffd5673b251d95874e3f8 +R 3b32753c02e0328fbac2d9ecf908b93f U drh -Z c59d4810013018d66fb5815f061f58db +Z 14b7465680d1bfc87bc9e1512c0fb518 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 2f3c29acc2..8841481812 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -12ee29d632ae4b585ef6bc07d3289d00c121268945dffd5673b251d95874e3f8 \ No newline at end of file +0f96810b840dd6f209562635b21f55a7ed6210c01336fcfeb3b79e08a615a28d \ No newline at end of file diff --git a/src/wherecode.c b/src/wherecode.c index 4d23622754..4e0fdd58a0 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -2686,7 +2686,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) continue; if( (pTerm->eOperator & WO_EQUIV)==0 ) continue; if( pTerm->leftCursor!=iCur ) continue; - if( pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ) ) continue; + if( pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT) ) continue; pE = pTerm->pExpr; #ifdef WHERETRACE_ENABLED /* 0x800 */ if( sqlite3WhereTrace & 0x800 ){ From 086b800fcddcb6e5d3aaf3b09b7268e68f4e95f0 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 13 May 2022 23:01:28 +0000 Subject: [PATCH 025/108] Change an unreachable branch into an assert(). FossilOrigin-Name: 778e57a558dc3f819ca57623bcb85f58c8fbeb28bc12a1e2edbdd1244e9107c5 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/expr.c | 5 ++--- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index dd38d6bca1..3f8f2e4399 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Transitive\sequality\sconstriants\sdo\snot\swork\son\sa\sRIGHT\sJOIN,\ssince\sthe\nright-hand\sside\smight\sbe\sa\snon-matched\srow. -D 2022-05-13T20:11:32.182 +C Change\san\sunreachable\sbranch\sinto\san\sassert(). +D 2022-05-13T23:01:28.631 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -504,7 +504,7 @@ F src/date.c 15082566229d4b1e5f24fdb490bf9bcc68824b911d70e3573ef075a1b9e2d26f F src/dbpage.c 90661a87e1db8bfbc8d2ebbdcd3749651ddb287c555c07a28fb17c7c591ffb68 F src/dbstat.c 861e08690fcb0f2ee1165eff0060ea8d4f3e2ea10f80dab7d32ad70443a6ff2d F src/delete.c a8e844af211a48b13b5b358be77a12c860c6a557c21990ad51a548e2536500ce -F src/expr.c b4328d113e600cf99897d32d733b3db7e6c46689adf6745bd3a1d88f7eb4d613 +F src/expr.c 19507ae3244402860cac2944be3b92bf9a8b50212fbfabaf7e9817127fec7c00 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c d965ede15d8360c09ed59348940649ee647b192e784466837d7aefa836d1d91e F src/func.c a3407a6fbb0d4088d8d502e46f0ace63e0aeae7467ae23a9ca9815bbf9239761 @@ -1954,8 +1954,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 12ee29d632ae4b585ef6bc07d3289d00c121268945dffd5673b251d95874e3f8 -R 3b32753c02e0328fbac2d9ecf908b93f +P 0f96810b840dd6f209562635b21f55a7ed6210c01336fcfeb3b79e08a615a28d +R 8c1b51d90f1ade9d0405d38079e89004 U drh -Z 14b7465680d1bfc87bc9e1512c0fb518 +Z 3783ffda9c8935c9c4c32a5060a3eb20 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 8841481812..1270c03081 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0f96810b840dd6f209562635b21f55a7ed6210c01336fcfeb3b79e08a615a28d \ No newline at end of file +778e57a558dc3f819ca57623bcb85f58c8fbeb28bc12a1e2edbdd1244e9107c5 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index b7e6c25fa5..93b23049df 100644 --- a/src/expr.c +++ b/src/expr.c @@ -3080,9 +3080,8 @@ void sqlite3CodeRhsOfIN( assert( ExprUseYSub(pExpr) ); sqlite3VdbeAddOp2(v, OP_Gosub, pExpr->y.sub.regReturn, pExpr->y.sub.iAddr); - if( iTab!=pExpr->iTable ){ - sqlite3VdbeAddOp2(v, OP_OpenDup, iTab, pExpr->iTable); - } + assert( iTab!=pExpr->iTable ); + sqlite3VdbeAddOp2(v, OP_OpenDup, iTab, pExpr->iTable); sqlite3VdbeJumpHere(v, addrOnce); return; } From c93bf1d4629bae83633a96c8a7edf1a5c9483824 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 14 May 2022 15:59:42 +0000 Subject: [PATCH 026/108] Improvements to the decision of when to check ON constraints for an inner join that is an operand to a RIGHT JOIN. Fix for issue identify by [forum:/forumpost/c06b10ad7e|forum post c06b10ad7e]. FossilOrigin-Name: 9d17233c7d98bf25c1a518d067e778708b3db6d6302edd8d7e376ba0ba4f1c30 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/wherecode.c | 20 ++++++++++++-------- test/join8.test | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 16 deletions(-) diff --git a/manifest b/manifest index 3f8f2e4399..0a4277735f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Change\san\sunreachable\sbranch\sinto\san\sassert(). -D 2022-05-13T23:01:28.631 +C Improvements\sto\sthe\sdecision\sof\swhen\sto\scheck\sON\sconstraints\sfor\san\sinner\njoin\sthat\sis\san\soperand\sto\sa\sRIGHT\sJOIN.\s\sFix\sfor\sissue\sidentify\sby\n[forum:/forumpost/c06b10ad7e|forum\spost\sc06b10ad7e]. +D 2022-05-14T15:59:42.367 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -642,7 +642,7 @@ F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b F src/where.c d4d543f06b09ff8bac05072b015a2181f9c48561b1a146158aaaf09e40817567 F src/whereInt.h 8da918f392bf202ccc0ee61291455b33ad171d209445f1ff3eaf62e0b6f6b363 -F src/wherecode.c c45ba0294d9c412f9ee57831bbf1fa14f8be1599e529d6d02416d4b608926c64 +F src/wherecode.c 2a8a73bcf1886632f2b2247c79395f94852a4b74484d8aa70a005892ce73d339 F src/whereexpr.c efed370c684dce04eab949202c5452bbde993efb198de43c7a88f59411ad2a2c F src/window.c fff1b51757438c664e471d5184634e48dcdf8ea34b640f3b1b0810b1e06de18c F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 @@ -1148,7 +1148,7 @@ F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join5.test d22b6cba8fb59ab3f1c82701434c360705eb12d4ce200c449f37b018fc47681a F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c F test/join7.test 8e72de4b45e5e930d18c305c7efe86015fb2552731e4e03ea226353036b0dab0 -F test/join8.test e736975960adc06e94eed24f2ba6eacf6a6026dbf42d67ed65c4afb2faca59d2 +F test/join8.test 0558cbab9ae545801278e824cd65f64a98309050f8c66182e1cfe7a892fd3add F test/join9.test 9056ddd3b0c0f4f9d658f4521038d9a37dc23ead8ca9a505d0b0db2b6a471e05 F test/joinA.test 7eab225dc1c1ab258a5e62513a4ed7cabbd3db971d59d5d92f4fb6fa14c12f6a F test/joinB.test 1b2ba3fc8568b49411787fccbf540570c148e9b6a53a30f80691cb6268098ded @@ -1954,8 +1954,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 0f96810b840dd6f209562635b21f55a7ed6210c01336fcfeb3b79e08a615a28d -R 8c1b51d90f1ade9d0405d38079e89004 +P 778e57a558dc3f819ca57623bcb85f58c8fbeb28bc12a1e2edbdd1244e9107c5 +R 09aeae61cd90b7d055124f3c701f239f U drh -Z 3783ffda9c8935c9c4c32a5060a3eb20 +Z 41a70168dfca4248dc5d36d0e11691b8 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 1270c03081..f0092674dd 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -778e57a558dc3f819ca57623bcb85f58c8fbeb28bc12a1e2edbdd1244e9107c5 \ No newline at end of file +9d17233c7d98bf25c1a518d067e778708b3db6d6302edd8d7e376ba0ba4f1c30 \ No newline at end of file diff --git a/src/wherecode.c b/src/wherecode.c index 4e0fdd58a0..3902c24f95 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -2619,15 +2619,19 @@ Bitmask sqlite3WhereCodeOneLoopStart( } pE = pTerm->pExpr; assert( pE!=0 ); - if( (pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT)) - && (!ExprHasProperty(pE,EP_OuterON|EP_InnerON) - || pE->w.iJoin!=pTabItem->iCursor) - ){ - /* Defer processing WHERE clause constraints until after outer - ** join processing. tag-20220513a */ - continue; + if( pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT) ){ + if( !ExprHasProperty(pE,EP_OuterON|EP_InnerON) ){ + /* Defer processing WHERE clause constraints until after outer + ** join processing. tag-20220513a */ + continue; + }else{ + Bitmask m = sqlite3WhereGetMask(&pWInfo->sMaskSet, pE->w.iJoin); + if( m & pLevel->notReady ){ + /* An ON clause that is not ripe */ + continue; + } + } } - if( iLoop==1 && !sqlite3ExprCoveredByIndex(pE, pLevel->iTabCur, pIdx) ){ iNext = 2; continue; diff --git a/test/join8.test b/test/join8.test index 76bda946cd..ffa1a60f52 100644 --- a/test/join8.test +++ b/test/join8.test @@ -294,4 +294,51 @@ do_execsql_test join8-9000 { SELECT * FROM t1 NATURAL RIGHT JOIN t1 AS t2 WHERE (a,b) IN (SELECT a+0, b FROM t1); } {1 E bb -} +# 2022-05-14 https://sqlite.org/forum/forumpost/c06b10ad7e +# +reset_db +db null - +do_execsql_test join8-10000 { + CREATE TABLE t1(c0 INT UNIQUE); + CREATE TABLE t2(c0); + CREATE TABLE t2i(c0 INT); + CREATE TABLE t3(c0 INT); + INSERT INTO t1 VALUES(1); + INSERT INTO t2 VALUES(2); + INSERT INTO t2i VALUES(2); + INSERT INTO t3 VALUES(3); +} {} +do_execsql_test join8-10010 { + SELECT DISTINCT t1.c0, t3.c0 + FROM t2 NATURAL JOIN t1 RIGHT JOIN t3 ON t1.c0; +} {- 3} +do_execsql_test join8-10020 { + SELECT t1.c0, t3.c0 + FROM t2 NATURAL JOIN t1 RIGHT JOIN t3 ON t1.c0; +} {- 3} +do_execsql_test join8-10030 { + SELECT DISTINCT t1.c0, t3.c0 + FROM t2 NATURAL CROSS JOIN t1 RIGHT JOIN t3 ON t1.c0; +} {- 3} +do_execsql_test join8-10040 { + SELECT t1.c0, t3.c0 + FROM t1 NATURAL CROSS JOIN t2 RIGHT JOIN t3 ON t1.c0; +} {- 3} +do_execsql_test join8-10050 { + SELECT DISTINCT t1.c0, t3.c0 + FROM t2i NATURAL JOIN t1 RIGHT JOIN t3 ON t1.c0; +} {- 3} +do_execsql_test join8-10060 { + SELECT DISTINCT +t1.c0, t3.c0 + FROM t2 NATURAL JOIN t1 RIGHT JOIN t3 ON t1.c0; +} {- 3} +do_execsql_test join8-10070 { + SELECT DISTINCT +t1.c0, t3.c0 + FROM t1 NATURAL CROSS JOIN t2 RIGHT JOIN t3 ON t1.c0; +} {- 3} +do_execsql_test join8-10080 { + SELECT DISTINCT t1.c0, t3.c0 + FROM t2 NATURAL JOIN t1 RIGHT JOIN t3 ON t1.c0<>0; +} {- 3} + finish_test From d83997ba7f0a099218481db3555dd44ddf352fde Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 14 May 2022 17:40:47 +0000 Subject: [PATCH 027/108] Improved debugging comment generation for the OP_Column opcode. FossilOrigin-Name: 3e073bfddfcd652dfae8656d8978a4de427d21847fdaccfce53b6b895ad33f01 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/vdbeaux.c | 6 ++---- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index 0a4277735f..cda1c3f8ca 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improvements\sto\sthe\sdecision\sof\swhen\sto\scheck\sON\sconstraints\sfor\san\sinner\njoin\sthat\sis\san\soperand\sto\sa\sRIGHT\sJOIN.\s\sFix\sfor\sissue\sidentify\sby\n[forum:/forumpost/c06b10ad7e|forum\spost\sc06b10ad7e]. -D 2022-05-14T15:59:42.367 +C Improved\sdebugging\scomment\sgeneration\sfor\sthe\sOP_Column\sopcode. +D 2022-05-14T17:40:47.718 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -629,7 +629,7 @@ F src/vdbe.c a6a20956fa128c0b8d3c5592a9a3db890a46cf626f46ffee0cab2ac5bf8d04b2 F src/vdbe.h 07641758ca8b4f4c6d81ea667ea167c541e6ece21f5574da11e3d21ec37e2662 F src/vdbeInt.h ef43f7fdc5fde29fc3fd29c506c12830f366178fdb4edbbf0cbc3dfbd1278b5f F src/vdbeapi.c 354c893f1500cf524cc45c32879b9c68893a28b77e3442c24668d6afe4236217 -F src/vdbeaux.c f406d8d8b461f260aeaa69d265c5d175ff0a9f84d6153c87975cdfbf9d681922 +F src/vdbeaux.c 75c4f75ed7e1d12eb3d80093a160ec998c839f3008a1c3c967fc5acf522d0e3c F src/vdbeblob.c 5e61ce31aca17db8fb60395407457a8c1c7fb471dde405e0cd675974611dcfcd F src/vdbemem.c 7189090b72baa025f945a1ac8c61ee420c645254476e8a191d555db76dfea5d4 F src/vdbesort.c 43756031ca7430f7aec3ef904824a7883c4ede783e51f280d99b9b65c0796e35 @@ -1954,8 +1954,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 778e57a558dc3f819ca57623bcb85f58c8fbeb28bc12a1e2edbdd1244e9107c5 -R 09aeae61cd90b7d055124f3c701f239f +P 9d17233c7d98bf25c1a518d067e778708b3db6d6302edd8d7e376ba0ba4f1c30 +R 3e11d035d04bb8add88257d626a130df U drh -Z 41a70168dfca4248dc5d36d0e11691b8 +Z 4f25ce32e3f912e3438ae5561148601c # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index f0092674dd..f030da8c3d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9d17233c7d98bf25c1a518d067e778708b3db6d6302edd8d7e376ba0ba4f1c30 \ No newline at end of file +3e073bfddfcd652dfae8656d8978a4de427d21847fdaccfce53b6b895ad33f01 \ No newline at end of file diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 9e702edcd5..b2e471e0c9 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1576,11 +1576,9 @@ char *sqlite3VdbeDisplayComment( }else if( c=='X' ){ if( pOp->zComment && pOp->zComment[0] ){ sqlite3_str_appendall(&x, pOp->zComment); - }else{ - sqlite3_str_appendall(&x, zSynopsis+1); + seenCom = 1; + break; } - seenCom = 1; - break; }else{ int v1 = translateP(c, pOp); int v2; From 96d5549778c369e723157498e26496144a1caeae Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 14 May 2022 19:05:13 +0000 Subject: [PATCH 028/108] Do not allow an index scan on an index-on-expression for a RIGHT JOIN because the index might not be positioned on the correct row when running the the right-join no-match loop. dbsqlfuzz 39ee60004ff027a9e2846cf76e02cd5ac0953739 FossilOrigin-Name: 2277f9ba7087dd993ac0f4007c523aa9cf74dba187f53af03d8c164886726fee --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/where.c | 11 +++++++++-- test/join8.test | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index cda1c3f8ca..85cf3a7bf2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improved\sdebugging\scomment\sgeneration\sfor\sthe\sOP_Column\sopcode. -D 2022-05-14T17:40:47.718 +C Do\snot\sallow\san\sindex\sscan\son\san\sindex-on-expression\sfor\sa\sRIGHT\sJOIN\sbecause\nthe\sindex\smight\snot\sbe\spositioned\son\sthe\scorrect\srow\swhen\srunning\sthe\nthe\sright-join\sno-match\sloop.\ndbsqlfuzz\s39ee60004ff027a9e2846cf76e02cd5ac0953739 +D 2022-05-14T19:05:13.161 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -640,7 +640,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c d4d543f06b09ff8bac05072b015a2181f9c48561b1a146158aaaf09e40817567 +F src/where.c 2ee27fed4a5564cddfc6710a539037d18e39e75cdf90b3f48d476c3b9767592e F src/whereInt.h 8da918f392bf202ccc0ee61291455b33ad171d209445f1ff3eaf62e0b6f6b363 F src/wherecode.c 2a8a73bcf1886632f2b2247c79395f94852a4b74484d8aa70a005892ce73d339 F src/whereexpr.c efed370c684dce04eab949202c5452bbde993efb198de43c7a88f59411ad2a2c @@ -1148,7 +1148,7 @@ F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join5.test d22b6cba8fb59ab3f1c82701434c360705eb12d4ce200c449f37b018fc47681a F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c F test/join7.test 8e72de4b45e5e930d18c305c7efe86015fb2552731e4e03ea226353036b0dab0 -F test/join8.test 0558cbab9ae545801278e824cd65f64a98309050f8c66182e1cfe7a892fd3add +F test/join8.test adf30584c6d0cc61816b24fd6f3cc8386ce89f579da4b65a6c8e05c2f2dce08e F test/join9.test 9056ddd3b0c0f4f9d658f4521038d9a37dc23ead8ca9a505d0b0db2b6a471e05 F test/joinA.test 7eab225dc1c1ab258a5e62513a4ed7cabbd3db971d59d5d92f4fb6fa14c12f6a F test/joinB.test 1b2ba3fc8568b49411787fccbf540570c148e9b6a53a30f80691cb6268098ded @@ -1954,8 +1954,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 9d17233c7d98bf25c1a518d067e778708b3db6d6302edd8d7e376ba0ba4f1c30 -R 3e11d035d04bb8add88257d626a130df +P 3e073bfddfcd652dfae8656d8978a4de427d21847fdaccfce53b6b895ad33f01 +R 45a6d14271adb894f8a23a1d1403bcc8 U drh -Z 4f25ce32e3f912e3438ae5561148601c +Z e0ba2eaedaa5d31f63ce00b4accf03e3 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index f030da8c3d..42b2c148f1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3e073bfddfcd652dfae8656d8978a4de427d21847fdaccfce53b6b895ad33f01 \ No newline at end of file +2277f9ba7087dd993ac0f4007c523aa9cf74dba187f53af03d8c164886726fee \ No newline at end of file diff --git a/src/where.c b/src/where.c index 8cbf9da89b..b0b1e37074 100644 --- a/src/where.c +++ b/src/where.c @@ -3482,7 +3482,14 @@ static int whereLoopAddBtree( } ApplyCostMultiplier(pNew->rRun, pTab->costMult); whereLoopOutputAdjust(pWC, pNew, rSize); - rc = whereLoopInsert(pBuilder, pNew); + if( (pSrc->fg.jointype & JT_RIGHT)!=0 && pProbe->aColExpr ){ + /* Do not do an SCAN of a index-on-expression in a RIGHT JOIN + ** because the cursor used to access the index might not be + ** positioned to the correct row during the right-join no-match + ** loop. */ + }else{ + rc = whereLoopInsert(pBuilder, pNew); + } pNew->nOut = rSize; if( rc ) break; } @@ -6168,6 +6175,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ } assert( pWInfo->nLevel<=pTabList->nSrc ); + if( pWInfo->pExprMods ) whereUndoExprMods(pWInfo); for(i=0, pLevel=pWInfo->a; inLevel; i++, pLevel++){ int k, last; VdbeOp *pOp, *pLastOp; @@ -6304,7 +6312,6 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ /* Final cleanup */ - if( pWInfo->pExprMods ) whereUndoExprMods(pWInfo); pParse->nQueryLoop = pWInfo->savedNQueryLoop; whereInfoFree(db, pWInfo); return; diff --git a/test/join8.test b/test/join8.test index ffa1a60f52..6dee54b0ae 100644 --- a/test/join8.test +++ b/test/join8.test @@ -341,4 +341,38 @@ do_execsql_test join8-10080 { FROM t2 NATURAL JOIN t1 RIGHT JOIN t3 ON t1.c0<>0; } {- 3} +# 2022-05-14 +# index-on-expr scan on a RIGHT JOIN +# dbsqlfuzz 39ee60004ff027a9e2846cf76e02cd5ac0953739 +# +reset_db +db null - +do_execsql_test join8-11000 { + CREATE TABLE t1(a); + CREATE TABLE t2(b); + INSERT INTO t2 VALUES(0),(1),(2); + SELECT * FROM t1 RIGHT JOIN t2 ON (a=b) WHERE 99+(b+1)!=99; +} {- 0 - 1 - 2} +do_execsql_test join8-11010 { + CREATE INDEX t2b ON t2(b+1) WHERE b IS NOT NULL; + SELECT * FROM t1 RIGHT JOIN t2 ON (a=b) WHERE 99+(b+1)!=99; +} {- 0 - 1 - 2} +do_execsql_test join8-11020 { + DROP TABLE t1; + DROP TABLE t2; + CREATE TABLE t1(a); + CREATE TABLE t2(b, c, d); + INSERT INTO t2 VALUES(1, 3, 'not-4'); + SELECT b, d FROM t1 RIGHT JOIN t2 WHERE (b+0)=1 AND d!=4; +} {1 not-4} +do_execsql_test join8-11030 { + CREATE INDEX i2 ON t2((b+0), d); + SELECT b, d FROM t1 RIGHT JOIN t2 WHERE (b+0)=1 AND d!=4; +} {1 not-4} +do_execsql_test join8-11040 { + DROP INDEX i2; + CREATE INDEX i2 ON t2((b+0), d) WHERE d IS NOT NULL; + SELECT b, d FROM t1 RIGHT JOIN t2 WHERE (b+0)=1 AND d!=4; +} {1 not-4} + finish_test From 07576c3fe826591628734da70c090fc6a76ddc06 Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 16 May 2022 16:10:04 +0000 Subject: [PATCH 029/108] Fix a problem in test file swarmvtab3.test causing occasional failures. FossilOrigin-Name: f935c155ef205802c16b4ebea4a3fb01bf5689662b7b4f2af56f0f9021d6d4b1 --- manifest | 14 +++++++------- manifest.uuid | 2 +- test/swarmvtab3.test | 4 +++- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 85cf3a7bf2..a85da37ade 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Do\snot\sallow\san\sindex\sscan\son\san\sindex-on-expression\sfor\sa\sRIGHT\sJOIN\sbecause\nthe\sindex\smight\snot\sbe\spositioned\son\sthe\scorrect\srow\swhen\srunning\sthe\nthe\sright-join\sno-match\sloop.\ndbsqlfuzz\s39ee60004ff027a9e2846cf76e02cd5ac0953739 -D 2022-05-14T19:05:13.161 +C Fix\sa\sproblem\sin\stest\sfile\sswarmvtab3.test\scausing\soccasional\sfailures. +D 2022-05-16T16:10:04.466 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -1463,7 +1463,7 @@ F test/subtype1.test 7fe09496352f97053af1437150751be2d0a0cae8 F test/superlock.test ec94f0556b6488d97f71c79f9061ae08d9ab8f12 F test/swarmvtab.test 250231404fcac88f61a6c147bb0e3a118ed879278cd3ccb0ae2d3a729e1e8e26 F test/swarmvtab2.test c948cb2fdfc5b01d85e8f6d6504854202dc1a0782ab2a0ed61538f27cbd0aa5c -F test/swarmvtab3.test 247aa38b6ebd2b99db2075847ae47e789ac34f1c2ab5c720dfcffd990004c544 +F test/swarmvtab3.test 41a3ab47cb7a834d4e5336425103b617410a67bb95d335ef536f887587ece073 F test/swarmvtabfault.test 8a67a9f27c61073a47990829e92bc0c64420a807cb642b15a25f6c788210ed95 F test/symlink.test 72b22238d4405ba34df8e60b335d290a3b1129fd5c260835c944c1e4e77288a9 F test/symlink2.test 9531f475a53d8781c4f81373f87faf2e2aff4f5fb2102ec6386e0c827916a670 @@ -1954,8 +1954,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 3e073bfddfcd652dfae8656d8978a4de427d21847fdaccfce53b6b895ad33f01 -R 45a6d14271adb894f8a23a1d1403bcc8 -U drh -Z e0ba2eaedaa5d31f63ce00b4accf03e3 +P 2277f9ba7087dd993ac0f4007c523aa9cf74dba187f53af03d8c164886726fee +R 68c24df5ae8824ce38e34e7cd46a31f1 +U dan +Z e76e8801e618c61286f9010190950bf1 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 42b2c148f1..22087ddd3d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2277f9ba7087dd993ac0f4007c523aa9cf74dba187f53af03d8c164886726fee \ No newline at end of file +f935c155ef205802c16b4ebea4a3fb01bf5689662b7b4f2af56f0f9021d6d4b1 \ No newline at end of file diff --git a/test/swarmvtab3.test b/test/swarmvtab3.test index b062f9e952..8ca2471308 100644 --- a/test/swarmvtab3.test +++ b/test/swarmvtab3.test @@ -148,11 +148,13 @@ catch { array unset ::dbcache } # random integer between 0 and 1,000,000 # 0 and 99. do_test 2.1 { + catch { array unset ctx_used } for {set i 0} {$i < 100} {incr i} { while 1 { set ctx [expr abs(int(rand() *1000000))] - if {[info exists ::dbcache($ctx)]==0} break + if {[info exists ctx_used($ctx)]==0} break } + set ctx_used($ctx) 1 set file test_remote.db$ctx forcedelete $file From c7d7ebd75587bec2227befda16c298bf175b5fa9 Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 16 May 2022 16:55:22 +0000 Subject: [PATCH 030/108] Add memory barriers to multi-threaded code in test4.c. FossilOrigin-Name: 9260f4e0fdc8066b4772999bacb5f4130ef714d4ac1967029ceacff618bc48ff --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/test4.c | 15 +++++++++++++++ 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index a85da37ade..f301d1271b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sproblem\sin\stest\sfile\sswarmvtab3.test\scausing\soccasional\sfailures. -D 2022-05-16T16:10:04.466 +C Add\smemory\sbarriers\sto\smulti-threaded\scode\sin\stest4.c. +D 2022-05-16T16:55:22.768 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -566,7 +566,7 @@ F src/tclsqlite.c 1f6673991147bc2cecc08a40d22f9803b84c805b24b499fe727f392256f734 F src/test1.c 1356984e97bff07e4a8cc3863e892f05b3348678a74783bb6f350b76316736f1 F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5 F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644 -F src/test4.c 7c4420e01c577b5c4add2cb03119743b1a357543d347773b9e717195ea967159 +F src/test4.c 4533b76419e7feb41b40582554663ed3cd77aaa54e135cf76b3205098cd6e664 F src/test5.c 328aae2c010c57a9829d255dc099d6899311672d F src/test6.c ae73a3a42bbc982fb9e301b84d30bda65a307be48c6dff20aba1461e17a9b0ce F src/test7.c 5612e9aecf934d6df7bba6ce861fdf5ba5456010 @@ -1954,8 +1954,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 2277f9ba7087dd993ac0f4007c523aa9cf74dba187f53af03d8c164886726fee -R 68c24df5ae8824ce38e34e7cd46a31f1 +P f935c155ef205802c16b4ebea4a3fb01bf5689662b7b4f2af56f0f9021d6d4b1 +R c061fe23c974300044233fa5c2c2a108 U dan -Z e76e8801e618c61286f9010190950bf1 +Z f437a9eddd805a091e05b9805ba19805 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 22087ddd3d..270e063e23 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f935c155ef205802c16b4ebea4a3fb01bf5689662b7b4f2af56f0f9021d6d4b1 \ No newline at end of file +9260f4e0fdc8066b4772999bacb5f4130ef714d4ac1967029ceacff618bc48ff \ No newline at end of file diff --git a/src/test4.c b/src/test4.c index 5da9cc488d..2043a33830 100644 --- a/src/test4.c +++ b/src/test4.c @@ -60,6 +60,11 @@ struct Thread { #define N_THREAD 26 static Thread threadset[N_THREAD]; +static void test_barrier(){ + sqlite3_mutex *pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_APP1); + sqlite3_mutex_enter(pMutex); + sqlite3_mutex_leave(pMutex); +} /* ** The main loop for a thread. Threads use busy waiting. @@ -76,16 +81,20 @@ static void *test_thread_main(void *pArg){ p->db = 0; } p->pStmt = 0; + test_barrier(); p->completed = 1; while( p->opnum<=p->completed ) sched_yield(); + test_barrier(); while( p->xOp ){ if( p->zErr && p->zErr!=p->zStaticErr ){ sqlite3_free(p->zErr); p->zErr = 0; } (*p->xOp)(p); + test_barrier(); p->completed++; while( p->opnum<=p->completed ) sched_yield(); + test_barrier(); } if( p->pStmt ){ sqlite3_finalize(p->pStmt); @@ -99,6 +108,7 @@ static void *test_thread_main(void *pArg){ sqlite3_free(p->zErr); p->zErr = 0; } + test_barrier(); p->completed++; #ifndef SQLITE_OMIT_DEPRECATED sqlite3_thread_cleanup(); @@ -166,7 +176,9 @@ static int SQLITE_TCLAPI tcl_thread_create( ** Wait for a thread to reach its idle state. */ static void test_thread_wait(Thread *p){ + test_barrier(); while( p->opnum>p->completed ) sched_yield(); + test_barrier(); } /* @@ -456,6 +468,7 @@ static int SQLITE_TCLAPI tcl_thread_compile( threadset[i].xOp = do_compile; sqlite3_free(threadset[i].zArg); threadset[i].zArg = sqlite3_mprintf("%s", argv[2]); + test_barrier(); threadset[i].opnum++; return TCL_OK; } @@ -507,6 +520,7 @@ static int SQLITE_TCLAPI tcl_thread_step( } test_thread_wait(&threadset[i]); threadset[i].xOp = do_step; + test_barrier(); threadset[i].opnum++; return TCL_OK; } @@ -551,6 +565,7 @@ static int SQLITE_TCLAPI tcl_thread_finalize( threadset[i].xOp = do_finalize; sqlite3_free(threadset[i].zArg); threadset[i].zArg = 0; + test_barrier(); threadset[i].opnum++; return TCL_OK; } From ff16267d7da5ddbf1edb683d4524e5f8d7d7ae11 Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 17 May 2022 14:59:05 +0000 Subject: [PATCH 031/108] Add the sqlite3_db_name() interface. FossilOrigin-Name: 2ad152236c408cbb1f942b221de4bf3cbaa9c35313d7eb07a63f46b6040fc981 --- manifest | 20 ++++++++++---------- manifest.uuid | 2 +- src/loadext.c | 5 +++-- src/main.c | 18 ++++++++++++++++++ src/sqlite.h.in | 20 ++++++++++++++++++++ src/sqlite3ext.h | 3 +++ 6 files changed, 55 insertions(+), 13 deletions(-) diff --git a/manifest b/manifest index f301d1271b..0d33f28d54 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\smemory\sbarriers\sto\smulti-threaded\scode\sin\stest4.c. -D 2022-05-16T16:55:22.768 +C Add\sthe\ssqlite3_db_name()\sinterface. +D 2022-05-17T14:59:05.338 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -516,8 +516,8 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/insert.c 173845e5a6bac96ae937409e4f876b631f26b31dabb9df8fd0eb3b130b2bb3a7 F src/json.c 7749b98c62f691697c7ee536b570c744c0583cab4a89200fdd0fc2aa8cc8cbd6 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa -F src/loadext.c 0705c2747212934183398f09891415d2f7f3113d0f543ccb205640210b20e617 -F src/main.c 135858d2ede0b83d779e71b07ede9c1d6b6eaab7b77bc2a85729584152769faf +F src/loadext.c 853385cc7a604157e137585097949252d5d0c731768e16b044608e5c95c3614b +F src/main.c e946f1d9e30bf49cf399ddf860cfd2319e3a97bbaabfb8e87d6ab985a20d54ad F src/malloc.c a9127efdcef92d6934c6339ea9813075b90edc0ce2e5c723556381a3828fb720 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de @@ -555,9 +555,9 @@ F src/resolve.c a4eb3c617027fd049b07432f3b942ea7151fa793a332a11a7d0f58c9539e104f F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c 74060a09f66c0c056f3c61627e22cb484af0bbfa29d7d14dcf17c684742c15de F src/shell.c.in 176cad562152cbbafe7ecc9c83c82850e2c3d0cf33ec0a52d67341d35c842f22 -F src/sqlite.h.in 2a35f62185eb5e7ecc64a2f68442b538ce9be74f80f28a00abc24837edcf1c17 +F src/sqlite.h.in d15c307939039086adca159dd340a94b79b69827e74c6d661f343eeeaefba896 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 -F src/sqlite3ext.h f49e28c25bd941e79794db5415fdf7b202deb3bc072ed6f1ed273d578703684e +F src/sqlite3ext.h a988810c9b21c0dc36dc7a62735012339dc76fc7ab448fb0792721d30eacb69d F src/sqliteInt.h fbe2d12cc13e80ac88c69ecde5ef9f052025fba78aa10f3eed0c71a5302e9a76 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4a3da6d77eeb3531cb0dbdf7047772a2a1b99f98c69e90ce009c75fe6328b2c0 @@ -1954,8 +1954,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P f935c155ef205802c16b4ebea4a3fb01bf5689662b7b4f2af56f0f9021d6d4b1 -R c061fe23c974300044233fa5c2c2a108 -U dan -Z f437a9eddd805a091e05b9805ba19805 +P 9260f4e0fdc8066b4772999bacb5f4130ef714d4ac1967029ceacff618bc48ff +R d21e2300c9b9f847363079df1fcdef69 +U drh +Z 456d2006914746a322619f144cfb48fc # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 270e063e23..e411b5aaea 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9260f4e0fdc8066b4772999bacb5f4130ef714d4ac1967029ceacff618bc48ff \ No newline at end of file +2ad152236c408cbb1f942b221de4bf3cbaa9c35313d7eb07a63f46b6040fc981 \ No newline at end of file diff --git a/src/loadext.c b/src/loadext.c index bba431096d..dd15d9a4da 100644 --- a/src/loadext.c +++ b/src/loadext.c @@ -503,11 +503,12 @@ static const sqlite3_api_routines sqlite3Apis = { /* Version 3.39.0 and later */ #ifndef SQLITE_OMIT_DESERIALIZE sqlite3_deserialize, - sqlite3_serialize + sqlite3_serialize, #else 0, - 0 + 0, #endif + sqlite3_db_name }; /* True if x is the directory separator character diff --git a/src/main.c b/src/main.c index c40b3162ab..3ae1f4fe30 100644 --- a/src/main.c +++ b/src/main.c @@ -4626,6 +4626,24 @@ Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){ return iDb<0 ? 0 : db->aDb[iDb].pBt; } +/* +** Return the name of the N-th database schema. Return NULL if N is out +** of range. +*/ +const char *sqlite3_db_name(sqlite3 *db, int N){ +#ifdef SQLITE_ENABLE_API_ARMOR + if( !sqlite3SafetyCheckOk(db) ){ + (void)SQLITE_MISUSE_BKPT; + return 0; + } +#endif + if( N<0 || N>=db->nDb ){ + return 0; + }else{ + return db->aDb[N].zDbSName; + } +} + /* ** Return the filename of the database associated with a database ** connection. diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 9c4df2292d..7c3664253d 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -6276,6 +6276,26 @@ int sqlite3_get_autocommit(sqlite3*); */ sqlite3 *sqlite3_db_handle(sqlite3_stmt*); +/* +** CAPI3REF: Return The Schema Name For A Database Connection +** METHOD: sqlite3 +** +** ^The sqlite3_db_name(D,N) interface returns a pointer to the schema name +** for the N-th database on database connection D, or a NULL pointer of N is +** out of range. +** +** Space to hold the string that is returned by sqlite3_db_name() is managed +** by SQLite itself. The string might be deallocated by any operation that +** changes the schema, including [ATTACH] or [DETACH] or calls to +** [sqlite3_serialize()] or [sqlite3_deserialize()], even operations that +** occur on a different thread. Applications that need to +** remember the string long-term should make their own copy. Applications that +** are accessing the same database connection simultaneously on multiple +** threads should mutex-protect calls to this API and should make their own +** private copy of the result prior to releasing the mutex. +*/ +const char *sqlite3_db_name(sqlite3 *db, int N); + /* ** CAPI3REF: Return The Filename For A Database Connection ** METHOD: sqlite3 diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h index a75dd496e7..2cdd0e429b 100644 --- a/src/sqlite3ext.h +++ b/src/sqlite3ext.h @@ -356,6 +356,7 @@ struct sqlite3_api_routines { sqlite3_int64,sqlite3_int64,unsigned); unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*, unsigned int); + const char *(*db_name)(sqlite3*,int); }; /* @@ -674,10 +675,12 @@ typedef int (*sqlite3_loadext_entry)( #define sqlite3_vtab_in sqlite3_api->vtab_in #define sqlite3_vtab_in_first sqlite3_api->vtab_in_first #define sqlite3_vtab_in_next sqlite3_api->vtab_in_next +/* Version 3.39.0 and later */ #ifndef SQLITE_OMIT_DESERIALIZE #define sqlite3_deserialize sqlite3_api->deserialize #define sqlite3_serialize sqlite3_api->serialize #endif +#define sqlite3_db_name sqlite3_api->db_name #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) From 5348fbe3322570f9fb3b1376cc8f7d25d74e3be3 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 17 May 2022 15:01:01 +0000 Subject: [PATCH 032/108] Avoid treating constant expressions like "? IN ()" or "? NOT IN ()" as integers if they appear in a GROUP BY or ORDER BY clause. FossilOrigin-Name: d8b249e8cdf0babe1427d0587dbdc27a52ec06a5ef3a20dfb05a0ea4adb85858 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/parse.y | 3 ++- test/in.test | 9 +++++++++ 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 0d33f28d54..e73180ebad 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\ssqlite3_db_name()\sinterface. -D 2022-05-17T14:59:05.338 +C Avoid\streating\sconstant\sexpressions\slike\s"?\sIN\s()"\sor\s"?\sNOT\sIN\s()"\sas\sintegers\sif\sthey\sappear\sin\sa\sGROUP\sBY\sor\sORDER\sBY\sclause. +D 2022-05-17T15:01:01.127 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -542,7 +542,7 @@ F src/os_win.c a8ea80037e81127ca01959daa87387cc135f325c88dc745376c4f760de852a10 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a F src/pager.c 42120492784fc9bcd9082b5c9b5e329b7318c357f9f3574a1bbfcf7418910356 F src/pager.h f82e9844166e1585f5786837ddc7709966138ced17f568c16af7ccf946c2baa3 -F src/parse.y efcb41d403be7bcecd6a95e51f73f89043e768cd0650a392c9b7ee0edbf1cc67 +F src/parse.y ad9a59d0078267e5aea4cf62f244c0ce6fcec9a91edd365e929c75d3a1716563 F src/pcache.c 084e638432c610f95aea72b8509f0845d2791293f39d1b82f0c0a7e089c3bb6b F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 F src/pcache1.c 54881292a9a5db202b2c0ac541c5e3ef9a5e8c4f1c1383adb2601d5499a60e65 @@ -1089,7 +1089,7 @@ F test/hook2.test b9ff3b8c6519fb67f33192f1afe86e7782ee4ac8 F test/icu.test 716a6b89fbabe5cc63e0cd4c260befb08fd7b9d761f04d43669233292f0753b1 F test/ieee754.test b0945d12be7d255f3dfa18e2511b17ca37e0edd2b803231c52d05b86c04ab26e F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8 -F test/in.test 15de58ee017f43d36390812e9a51217d1b2db7758f97d0df48296ef178ea560b +F test/in.test 55503d3633c434120d8b2d5966a34f0d9a55393a589050b1366afe4b188093c7 F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75 F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0 F test/in4.test fdd1d8134da8376985c2edba6035a2de1f6c731524d2ffa651419e8fe2cd1c5a @@ -1954,8 +1954,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 9260f4e0fdc8066b4772999bacb5f4130ef714d4ac1967029ceacff618bc48ff -R d21e2300c9b9f847363079df1fcdef69 -U drh -Z 456d2006914746a322619f144cfb48fc +P 2ad152236c408cbb1f942b221de4bf3cbaa9c35313d7eb07a63f46b6040fc981 +R 43491feb68bb986ef951c6ac394e5e71 +U dan +Z 4bd491f85f12c206c1579a88f589c75a # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index e411b5aaea..d58fe49873 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2ad152236c408cbb1f942b221de4bf3cbaa9c35313d7eb07a63f46b6040fc981 \ No newline at end of file +d8b249e8cdf0babe1427d0587dbdc27a52ec06a5ef3a20dfb05a0ea4adb85858 \ No newline at end of file diff --git a/src/parse.y b/src/parse.y index 565130a05c..fb3c3f38cd 100644 --- a/src/parse.y +++ b/src/parse.y @@ -1271,7 +1271,8 @@ expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] { ** regardless of the value of expr1. */ sqlite3ExprUnmapAndDelete(pParse, A); - A = sqlite3Expr(pParse->db, TK_INTEGER, N ? "1" : "0"); + A = sqlite3Expr(pParse->db, TK_STRING, N ? "true" : "false"); + if( A ) sqlite3ExprIdToTrueFalse(A); }else{ Expr *pRHS = Y->a[0].pExpr; if( Y->nExpr==1 && sqlite3ExprIsConstant(pRHS) && A->op!=TK_VECTOR ){ diff --git a/test/in.test b/test/in.test index b0eb371cb7..7c4cc51878 100644 --- a/test/in.test +++ b/test/in.test @@ -798,4 +798,13 @@ do_execsql_test in-20.1 { SELECT (1 IN (2 IS TRUE)); } {1} +# Forum post: https://sqlite.org/forum/forumpost/5782619992. +# +reset_db +do_execsql_test in-21.1 { + CREATE TABLE t0(c0); + SELECT COUNT(*) FROM t0 ORDER BY (t0.c0 IN ()); +} {0} + + finish_test From b8b2d9c5e1ab01c93bff9010985f0a80d288a606 Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 17 May 2022 15:11:57 +0000 Subject: [PATCH 033/108] Fix harmless compiler warnings in the new unixFullPathname implementation. FossilOrigin-Name: f7e1ceb5b59a876cfd04a8aac0ee2b322c970555b9c361b4953d711ef6596e37 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/os_unix.c | 3 ++- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index e73180ebad..7f1d327e7e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Avoid\streating\sconstant\sexpressions\slike\s"?\sIN\s()"\sor\s"?\sNOT\sIN\s()"\sas\sintegers\sif\sthey\sappear\sin\sa\sGROUP\sBY\sor\sORDER\sBY\sclause. -D 2022-05-17T15:01:01.127 +C Fix\sharmless\scompiler\swarnings\sin\sthe\snew\sunixFullPathname\simplementation. +D 2022-05-17T15:11:57.632 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -537,7 +537,7 @@ F src/os.c b1c4f2d485961e9a5b6b648c36687d25047c252222e9660b7cc25a6e1ea436ab F src/os.h 1ff5ae51d339d0e30d8a9d814f4b8f8e448169304d83a7ed9db66a65732f3e63 F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85 F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586 -F src/os_unix.c 02becb87c58245d2831f10f4f1a9108a465f8091cc598b2a9c78976f51a4e446 +F src/os_unix.c 2df2b33db88f00af13805d4573ee126bc5973f9e3b91d03c575fa7ba64e7dc41 F src/os_win.c a8ea80037e81127ca01959daa87387cc135f325c88dc745376c4f760de852a10 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a F src/pager.c 42120492784fc9bcd9082b5c9b5e329b7318c357f9f3574a1bbfcf7418910356 @@ -1954,8 +1954,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 2ad152236c408cbb1f942b221de4bf3cbaa9c35313d7eb07a63f46b6040fc981 -R 43491feb68bb986ef951c6ac394e5e71 -U dan -Z 4bd491f85f12c206c1579a88f589c75a +P d8b249e8cdf0babe1427d0587dbdc27a52ec06a5ef3a20dfb05a0ea4adb85858 +R 56c8d067b3c475439a951ae630953e32 +U drh +Z 99cc78493b68b2d09cacc03a9e60389c # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index d58fe49873..e1be3622c7 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d8b249e8cdf0babe1427d0587dbdc27a52ec06a5ef3a20dfb05a0ea4adb85858 \ No newline at end of file +f7e1ceb5b59a876cfd04a8aac0ee2b322c970555b9c361b4953d711ef6596e37 \ No newline at end of file diff --git a/src/os_unix.c b/src/os_unix.c index da50f2de1e..b933de3765 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -6484,7 +6484,7 @@ static void appendOnePathElement( return; } got = osReadlink(zIn, zLnk, sizeof(zLnk)-2); - if( got<=0 || got>=sizeof(zLnk)-2 ){ + if( got<=0 || got>=(ssize_t)sizeof(zLnk)-2 ){ pPath->rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn); return; } @@ -6534,6 +6534,7 @@ static int unixFullPathname( char *zOut /* Output buffer */ ){ DbPath path; + UNUSED_PARAMETER(pVfs); path.rc = 0; path.nUsed = 0; path.nSymlink = 0; From f8cd3d2b5c71b305754407e20ef282a0aeb2e0eb Mon Sep 17 00:00:00 2001 From: stephan Date: Wed, 18 May 2022 17:14:24 +0000 Subject: [PATCH 034/108] Initial version of an sqlfiddle-style application using a WASM build of the sqlite3 shell. FossilOrigin-Name: af9c21c9e0caf05adac7a9fcde39a9164c89f1c78b767b6fdd74a1405a3d373f --- Makefile.in | 21 ++++ ext/fiddle/Makefile | 5 + ext/fiddle/fiddle.in.html | 208 ++++++++++++++++++++++++++++++++++++++ ext/fiddle/index.md | 71 +++++++++++++ manifest | 22 ++-- manifest.uuid | 2 +- src/shell.c.in | 130 ++++++++++++++++++++++-- 7 files changed, 443 insertions(+), 16 deletions(-) create mode 100644 ext/fiddle/Makefile create mode 100644 ext/fiddle/fiddle.in.html create mode 100644 ext/fiddle/index.md diff --git a/Makefile.in b/Makefile.in index e5d30d030b..92b2525d58 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1512,3 +1512,24 @@ sqlite3.def: $(REAL_LIBOBJ) sqlite3.dll: $(REAL_LIBOBJ) sqlite3.def $(TCC) -shared -o $@ sqlite3.def \ -Wl,"--strip-all" $(REAL_LIBOBJ) + + +# +# fiddle section +# +fiddle_dir = ext/fiddle +fiddle_tmpl = $(fiddle_dir)/fiddle.in.html +fiddle_html = $(fiddle_dir)/fiddle.html +fiddle_generated = $(fiddle_html) \ + $(fiddle_dir)/fiddle.js \ + $(fiddle_dir)/fiddle.wasm +clean-fiddle: + rm -f $(fiddle_generated) +clean: clean-fiddle +emcc_flags = -sEXPORTED_RUNTIME_METHODS=ccall,cwrap \ + -sEXPORTED_FUNCTIONS=_fiddle_exec \ + --shell-file $(fiddle_tmpl) +$(fiddle_html): Makefile sqlite3.c shell.c $(fiddle_tmpl) + emcc -o $@ $(emcc_flags) sqlite3.c shell.c + +fiddle: $(fiddle_html) diff --git a/ext/fiddle/Makefile b/ext/fiddle/Makefile new file mode 100644 index 0000000000..a3bc352aec --- /dev/null +++ b/ext/fiddle/Makefile @@ -0,0 +1,5 @@ +default: + make -C ../.. fiddle + +clean: + make -C ../../ clean-fiddle diff --git a/ext/fiddle/fiddle.in.html b/ext/fiddle/fiddle.in.html new file mode 100644 index 0000000000..ddd7d6984c --- /dev/null +++ b/ext/fiddle/fiddle.in.html @@ -0,0 +1,208 @@ + + + + + + sqlite3 fiddle + + + +
sqlite3 fiddle
+
emscripten
+
Downloading...
+
+ +
+
+
+ +
+ + +
+
+
+ +
+ +
+
+
+
+ Options +
+ + +
+
+
+ + {{{ SCRIPT }}} + + diff --git a/ext/fiddle/index.md b/ext/fiddle/index.md new file mode 100644 index 0000000000..9f5ab41b9a --- /dev/null +++ b/ext/fiddle/index.md @@ -0,0 +1,71 @@ +This directory houses a "fiddle"-style application which embeds a +[Web Assembly (WASM)](https://en.wikipedia.org/wiki/WebAssembly) +build of the sqlite3 shell app into an HTML page, effectively running +the shell in a client-side browser. + +It requires [emscripten][] and that the build environment be set up for +emscripten. A mini-HOWTO for setting that up follows... + +First, install the Emscripten SDK, as documented +[here](https://emscripten.org/docs/getting_started/downloads.html) and summarized +below for Linux environments: + +``` +# Clone the emscripten repository: +$ git clone https://github.com/emscripten-core/emsdk.git +$ cd emsdk + +# Download and install the latest SDK tools: +$ ./emsdk install latest + +# Make the "latest" SDK "active" for the current user: +$ ./emsdk activate latest +``` + +Those parts only need to be run once. The following needs to be run for each +shell instance which needs the `emcc` compiler: + +``` +# Activate PATH and other environment variables in the current terminal: +$ source ./emsdk_env.sh + +$ which emcc +/path/to/emsdk/upstream/emscripten/emcc +``` + +That `env` script needs to be sourced for building this application from the +top of the sqlite3 build tree: + +``` +$ make fiddle +``` + +Or: + +``` +$ cd ext/fiddle +$ make +``` + +That will generate the fiddle application under +[ext/fiddle](/dir/ext/fiddle), as `fiddle.html`. That application +cannot, due to XMLHttpRequest security limitations, run if the HTML +file is opened directly in the browser (i.e. if it is opened using a +`file://` URL), so it needs to be served via an HTTP server. For +example, using [althttpd][]: + +``` +$ cd ext/fiddle +$ althttpd -debug 1 -jail 0 -port 9090 -root . +``` + +Then browse to `http://localhost:9090/fiddle.html`. + +Note that when serving this app via [althttpd][], it must be a version +from 2022-05-17 or newer so that it recognizes the `.wasm` file +extension and responds with the mimetype `application/wasm`, as the +wasm loader is pedantic about that detail. + + +[emscripten]: https://emscripten.org +[althttpd]: https://sqlite.org/althttpd diff --git a/manifest b/manifest index 7f1d327e7e..2cc14ec5e2 100644 --- a/manifest +++ b/manifest @@ -1,9 +1,9 @@ -C Fix\sharmless\scompiler\swarnings\sin\sthe\snew\sunixFullPathname\simplementation. -D 2022-05-17T15:11:57.632 +C Initial\sversion\sof\san\ssqlfiddle-style\sapplication\susing\sa\sWASM\sbuild\sof\sthe\ssqlite3\sshell. +D 2022-05-18T17:14:24.622 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 -F Makefile.in b210ad2733317f1a4353085dfb9d385ceec30b0e6a61d20a5accabecac6b1949 +F Makefile.in ff32504cde350caaf4d52abfdca5dd1fa88b21e53071a0f9cc3539b6789c3606 F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241 F Makefile.msc b28a8a7a977e7312f6859f560348e1eb110c21bd6cf9fab0d16537c0a514eef3 F README.md 8b8df9ca852aeac4864eb1e400002633ee6db84065bd01b78c33817f97d31f5e @@ -55,6 +55,9 @@ F ext/expert/expert1.test 3c642a4e7bbb14f21ddab595436fb465a4733f47a0fe5b2855e1d5 F ext/expert/sqlite3expert.c 6ca30d73b9ed75bd56d6e0d7f2c962d2affaa72c505458619d0ff5d9cdfac204 F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72 +F ext/fiddle/Makefile ea647919e6ac4b50edde1490f60ee87e8ccd75141e4aa650718c6f28eb323bbc +F ext/fiddle/fiddle.in.html 85db5e736f82fd2cae1c4f61b5af62239cc5db363b9eb6f4e383e0d97c59b322 +F ext/fiddle/index.md 08d25ec6fe2a56923e8ea6e5d6c80907bf3a60f9c40a6841a8f402e402dd5f22 F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b F ext/fts1/ft_hash.h 06df7bba40dadd19597aa400a875dbc2fed705ea @@ -554,7 +557,7 @@ F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c a4eb3c617027fd049b07432f3b942ea7151fa793a332a11a7d0f58c9539e104f F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c 74060a09f66c0c056f3c61627e22cb484af0bbfa29d7d14dcf17c684742c15de -F src/shell.c.in 176cad562152cbbafe7ecc9c83c82850e2c3d0cf33ec0a52d67341d35c842f22 +F src/shell.c.in 1892f21aafee8eca543881ef429f6166386ca1ae0051252e91d1235bd6f4217b F src/sqlite.h.in d15c307939039086adca159dd340a94b79b69827e74c6d661f343eeeaefba896 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h a988810c9b21c0dc36dc7a62735012339dc76fc7ab448fb0792721d30eacb69d @@ -1954,8 +1957,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P d8b249e8cdf0babe1427d0587dbdc27a52ec06a5ef3a20dfb05a0ea4adb85858 -R 56c8d067b3c475439a951ae630953e32 -U drh -Z 99cc78493b68b2d09cacc03a9e60389c +P f7e1ceb5b59a876cfd04a8aac0ee2b322c970555b9c361b4953d711ef6596e37 +R f9ce230cf39758aaeb408ee00f09f455 +T *branch * fiddle +T *sym-fiddle * +T -sym-trunk * +U stephan +Z 33db0432b22b9541a19d442c2dec2c8e # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index e1be3622c7..9427d521e0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f7e1ceb5b59a876cfd04a8aac0ee2b322c970555b9c361b4953d711ef6596e37 \ No newline at end of file +af9c21c9e0caf05adac7a9fcde39a9164c89f1c78b767b6fdd74a1405a3d373f \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index cace8bf2f4..b46a00de66 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -229,6 +229,16 @@ static void setTextMode(FILE *file, int isOutput){ # define setTextMode(X,Y) #endif +/* +** When compiling with emcc (a.k.a. emscripten), we're building a +** WebAssembly (WASM) bundle and need to disable and rewire a few +** things. +*/ +#ifdef __EMSCRIPTEN__ +#define SQLITE_SHELL_WASM_MODE +#else +#undef SQLITE_SHELL_WASM_MODE +#endif /* True if the timer is enabled */ static int enableTimer = 0; @@ -691,6 +701,7 @@ static char *local_getline(char *zLine, FILE *in){ ** be freed by the caller or else passed back into this routine via the ** zPrior argument for reuse. */ +#ifndef SQLITE_SHELL_WASM_MODE static char *one_input_line(FILE *in, char *zPrior, int isContinuation){ char *zPrompt; char *zResult; @@ -710,7 +721,7 @@ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){ } return zResult; } - +#endif /* !SQLITE_SHELL_WASM_MODE */ /* ** Return the value of a hexadecimal digit. Return -1 if the input @@ -1009,16 +1020,18 @@ INCLUDE test_windirent.h INCLUDE test_windirent.c #define dirent DIRENT #endif -INCLUDE ../ext/misc/shathree.c -INCLUDE ../ext/misc/fileio.c -INCLUDE ../ext/misc/completion.c -INCLUDE ../ext/misc/appendvfs.c INCLUDE ../ext/misc/memtrace.c +INCLUDE ../ext/misc/shathree.c INCLUDE ../ext/misc/uint.c INCLUDE ../ext/misc/decimal.c INCLUDE ../ext/misc/ieee754.c INCLUDE ../ext/misc/series.c INCLUDE ../ext/misc/regexp.c +#ifndef SQLITE_SHELL_WASM_MODE +INCLUDE ../ext/misc/fileio.c +INCLUDE ../ext/misc/completion.c +INCLUDE ../ext/misc/appendvfs.c +#endif #ifdef SQLITE_HAVE_ZLIB INCLUDE ../ext/misc/zipfile.c INCLUDE ../ext/misc/sqlar.c @@ -1149,8 +1162,18 @@ struct ShellState { char *zNonce; /* Nonce for temporary safe-mode excapes */ EQPGraph sGraph; /* Information for the graphical EXPLAIN QUERY PLAN */ ExpertInfo expert; /* Valid if previous command was ".expert OPT..." */ +#ifdef SQLITE_SHELL_WASM_MODE + struct { + const char * zInput; /* Input string from wasm/JS proxy */ + char const * zPos; /* Cursor pos into zInput */ + } wasm; +#endif }; +#ifdef SQLITE_SHELL_WASM_MODE +static ShellState shellState; +#endif + /* Allowed values for ShellState.autoEQP */ @@ -4991,14 +5014,16 @@ static void open_db(ShellState *p, int openFlags){ #ifndef SQLITE_OMIT_LOAD_EXTENSION sqlite3_enable_load_extension(p->db, 1); #endif - sqlite3_fileio_init(p->db, 0, 0); sqlite3_shathree_init(p->db, 0, 0); - sqlite3_completion_init(p->db, 0, 0); sqlite3_uint_init(p->db, 0, 0); sqlite3_decimal_init(p->db, 0, 0); sqlite3_regexp_init(p->db, 0, 0); sqlite3_ieee_init(p->db, 0, 0); sqlite3_series_init(p->db, 0, 0); +#ifndef SQLITE_SHELL_WASM_MODE + sqlite3_fileio_init(p->db, 0, 0); + sqlite3_completion_init(p->db, 0, 0); +#endif #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB) sqlite3_dbdata_init(p->db, 0, 0); #endif @@ -11467,6 +11492,39 @@ static void echo_group_input(ShellState *p, const char *zDo){ if( ShellHasFlag(p, SHFLG_Echo) ) utf8_printf(p->out, "%s\n", zDo); } +#ifdef SQLITE_SHELL_WASM_MODE +/* +** Alternate one_input_line() impl for wasm mode. This is not in the primary impl +** because we need the global shellState and cannot access it from that function +** without moving lots of code around (creating a larger/messier diff). +*/ +static char *one_input_line(FILE *in, char *zPrior, int isContinuation){ + /* Parse the next line from shellState.wasm.zInput. */ + const char *zBegin = shellState.wasm.zPos; + const char *z = zBegin; + char *zLine = 0; + int nZ = 0; + + UNUSED_PARAMETER(in); + UNUSED_PARAMETER(isContinuation); + if(!z || !*z){ + return 0; + } + while(*z && isspace(*z)) ++z; + zBegin = z; + for(; *z && '\n'!=*z; ++nZ, ++z){} + if(nZ>0 && '\r'==zBegin[nZ-1]){ + --nZ; + } + shellState.wasm.zPos = z; + zLine = realloc(zPrior, nZ+1); + shell_check_oom(zLine); + memcpy(zLine, zBegin, (size_t)nZ); + zLine[nZ] = 0; + return zLine; +} +#endif /* SQLITE_SHELL_WASM_MODE */ + /* ** Read input from *in and process it. If *in==0 then input ** is interactive - the user is typing it it. Otherwise, input @@ -11848,6 +11906,10 @@ static char *cmdline_option_value(int argc, char **argv, int i){ # endif #endif +#ifdef SQLITE_SHELL_WASM_MODE +# define main fiddle_main +#endif + #if SQLITE_SHELL_IS_UTF8 int SQLITE_CDECL main(int argc, char **argv){ #else @@ -11858,7 +11920,11 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ sqlite3_uint64 mem_main_enter = sqlite3_memory_used(); #endif char *zErrMsg = 0; +#ifdef SQLITE_SHELL_WASM_MODE +# define data shellState +#else ShellState data; +#endif const char *zInitFile = 0; int i; int rc = 0; @@ -11874,8 +11940,13 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ setBinaryMode(stdin, 0); setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */ +#ifdef SQLITE_SHELL_WASM_MODE + stdin_is_interactive = 0; + stdout_is_console = 1; +#else stdin_is_interactive = isatty(0); stdout_is_console = isatty(1); +#endif #if !defined(_WIN32_WCE) if( getenv("SQLITE_DEBUG_BREAK") ){ @@ -12131,7 +12202,9 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ #endif } data.out = stdout; +#ifndef SQLITE_SHELL_WASM_MODE sqlite3_appendvfs_init(0,0,0); +#endif /* Go ahead and open the database file if it already exists. If the ** file does not exist, delay opening it. This prevents empty database @@ -12397,6 +12470,9 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ rc = process_input(&data); } } +#ifndef SQLITE_SHELL_WASM_MODE + /* In WASM mode we have to leave the db state in place so that + ** client code can "push" SQL into it after this call returns. */ free(azCmd); set_table_name(&data, 0); if( data.db ){ @@ -12429,5 +12505,45 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ (unsigned int)(sqlite3_memory_used()-mem_main_enter)); } #endif +#endif /* !SQLITE_SHELL_WASM_MODE */ return rc; } + + +#ifdef SQLITE_SHELL_WASM_MODE +/* +** Trivial exportable function for emscripten. Needs to be exported using: +** +** emcc ..flags... -sEXPORTED_FUNCTIONS=_fiddle_exec -sEXPORTED_RUNTIME_METHODS=ccall,cwrap +** +** (Note the underscore before the function name.) It processes zSql +** as if it were input to the sqlite3 shell and redirects all output +** to the wasm binding. +*/ +void fiddle_exec(char const * zSql){ + static int once = 0; + int rc = 0; + if(!once){ + /* Simulate an argv array for main() */ + static char * argv[] = {"fiddle", "-bail", "-safe"}; + rc = fiddle_main((int)(sizeof(argv)/sizeof(argv[0])), argv); + once = rc ? -1 : 1; + memset(&shellState.wasm, 0, sizeof(shellState.wasm)); + printf( + "SQLite version %s %.19s\n" /*extra-version-info*/, + sqlite3_libversion(), sqlite3_sourceid() + ); + puts("WASM shell"); + puts("Enter \".help\" for usage hints."); + puts("Connected to a transient in-memory database."); + } + if(once<0){ + puts("DB init failed. Not executing SQL."); + }else if(zSql && *zSql){ + shellState.wasm.zInput = zSql; + shellState.wasm.zPos = zSql; + process_input(&shellState); + memset(&shellState.wasm, 0, sizeof(shellState.wasm)); + } +} +#endif /* SQLITE_SHELL_WASM_MODE */ From 9f69b9411e9425e8d0be06f7c46598369dd87869 Mon Sep 17 00:00:00 2001 From: stephan Date: Wed, 18 May 2022 17:22:02 +0000 Subject: [PATCH 035/108] Increased default size of the fiddle output area, changed the .nullvalue default in the input area, and minor CSS tweaks. FossilOrigin-Name: 281aaae73167828bdf0bb2c07f83622475ab29b5755ac7fb8584c8e919c0a09b --- ext/fiddle/fiddle.in.html | 7 +++++-- manifest | 15 ++++++--------- manifest.uuid | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ext/fiddle/fiddle.in.html b/ext/fiddle/fiddle.in.html index ddd7d6984c..6df7ae7be7 100644 --- a/ext/fiddle/fiddle.in.html +++ b/ext/fiddle/fiddle.in.html @@ -50,6 +50,9 @@ .button-bar button { margin: 0.25em 1em; } + label { + cursor: pointer; + } @@ -62,7 +65,7 @@
- +
diff --git a/manifest b/manifest index 2cc14ec5e2..b3746c5eaf 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Initial\sversion\sof\san\ssqlfiddle-style\sapplication\susing\sa\sWASM\sbuild\sof\sthe\ssqlite3\sshell. -D 2022-05-18T17:14:24.622 +C Increased\sdefault\ssize\sof\sthe\sfiddle\soutput\sarea,\schanged\sthe\s.nullvalue\sdefault\sin\sthe\sinput\sarea,\sand\sminor\sCSS\stweaks. +D 2022-05-18T17:22:02.563 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -56,7 +56,7 @@ F ext/expert/sqlite3expert.c 6ca30d73b9ed75bd56d6e0d7f2c962d2affaa72c505458619d0 F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72 F ext/fiddle/Makefile ea647919e6ac4b50edde1490f60ee87e8ccd75141e4aa650718c6f28eb323bbc -F ext/fiddle/fiddle.in.html 85db5e736f82fd2cae1c4f61b5af62239cc5db363b9eb6f4e383e0d97c59b322 +F ext/fiddle/fiddle.in.html 3659d42f050e8f6544f8b46bd56f39c81655b8f4c094ad1f753c74567b2cf7f2 F ext/fiddle/index.md 08d25ec6fe2a56923e8ea6e5d6c80907bf3a60f9c40a6841a8f402e402dd5f22 F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b @@ -1957,11 +1957,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P f7e1ceb5b59a876cfd04a8aac0ee2b322c970555b9c361b4953d711ef6596e37 -R f9ce230cf39758aaeb408ee00f09f455 -T *branch * fiddle -T *sym-fiddle * -T -sym-trunk * +P af9c21c9e0caf05adac7a9fcde39a9164c89f1c78b767b6fdd74a1405a3d373f +R 3b664192bd5ef6de339309209f084d85 U stephan -Z 33db0432b22b9541a19d442c2dec2c8e +Z f2dd4c4723165b12480a254a01ad4fae # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 9427d521e0..daed1e0943 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -af9c21c9e0caf05adac7a9fcde39a9164c89f1c78b767b6fdd74a1405a3d373f \ No newline at end of file +281aaae73167828bdf0bb2c07f83622475ab29b5755ac7fb8584c8e919c0a09b \ No newline at end of file From 8ae45e4c6bce027c8b8e721f7d4b79854f4fb3a0 Mon Sep 17 00:00:00 2001 From: stephan Date: Wed, 18 May 2022 17:40:19 +0000 Subject: [PATCH 036/108] The fiddle input/output areas now stretch and shrink as needed to account for their available space. FossilOrigin-Name: 4eec05457fabe8248b8fd48d6187e772b69429ed64e99f02d0ad6b1230b5835e --- ext/fiddle/fiddle.in.html | 7 +++++-- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/ext/fiddle/fiddle.in.html b/ext/fiddle/fiddle.in.html index 6df7ae7be7..a86f07ef76 100644 --- a/ext/fiddle/fiddle.in.html +++ b/ext/fiddle/fiddle.in.html @@ -6,7 +6,10 @@ sqlite3 fiddle @@ -81,6 +85,7 @@ select * from t;
+
@@ -92,7 +97,6 @@ select * from t;
-
+ --> {{{ SCRIPT }}} diff --git a/ext/fiddle/module-post.js b/ext/fiddle/module-post.js new file mode 100644 index 0000000000..bc6f3b2b9f --- /dev/null +++ b/ext/fiddle/module-post.js @@ -0,0 +1,87 @@ +/* This is the --post-js file for emcc. It gets appended to the + generated fiddle.js. It should contain all app-level code. + + Maintenance achtung: do not call any wasm-bound functions from + outside of the onRuntimeInitialized() function. They are not + permitted to be called until after the module init is complete, + which does not happen until after this file is processed. Once that + init is finished, Module.onRuntimeInitialized() will be + triggered. All app-level init code should go into that callback or + be triggered via it. Calling wasm-bound functions before that + callback is run will trigger an assertion in the wasm environment. +*/ +window.Module.onRuntimeInitialized = function(){ + 'use strict'; + const Module = window.Module /* wasm module as set up by emscripten */; + delete Module.onRuntimeInitialized; + const taInput = document.querySelector('#input'); + const btnClearIn = document.querySelector('#btn-clear'); + document.querySelectorAll('button').forEach(function(e){ + e.removeAttribute('disabled'); + }); + btnClearIn.addEventListener('click',function(){ + taInput.value = ''; + },false); + // Ctrl-enter and shift-enter both run the current SQL. + taInput.addEventListener('keydown',function(ev){ + if((ev.ctrlKey || ev.shiftKey) && 13 === ev.keyCode){ + ev.preventDefault(); + ev.stopPropagation(); + btnRun.click(); + } + }, false); + const taOutput = document.querySelector('#output'); + const btnClearOut = document.querySelector('#btn-clear-output'); + btnClearOut.addEventListener('click',function(){ + taOutput.value = ''; + },false); + /* Sends the given text to the shell. If it's null or empty, this + is a no-op except that the very first call will initialize the + db and output an informational header. */ + const doExec = function f(sql){ + if(!f._) f._ = Module.cwrap('fiddle_exec', null, ['string']); + if(Module._isDead){ + Module.printErr("shell module has exit()ed. Cannot run SQL."); + return; + } + if(Module.config.autoClearOutput) taOutput.value=''; + f._(sql); + }; + const btnRun = document.querySelector('#btn-run'); + btnRun.addEventListener('click',function(){ + const sql = taInput.value.trim(); + if(sql){ + doExec(sql); + } + },false); + + document.querySelector('#opt-cb-sbs') + .addEventListener('change', function(){ + document.querySelector('#main-wrapper').classList[ + this.checked ? 'add' : 'remove' + ]('side-by-side'); + }, false); + document.querySelector('#btn-notes-caveats') + .addEventListener('click', function(){ + document.querySelector('#notes-caveats').remove(); + }, false); + + /* For each checkbox with data-config=X, set up a binding to + Module.config[X]. */ + document.querySelectorAll('input[type=checkbox][data-config]') + .forEach(function(e){ + e.checked = !!Module.config[e.dataset.config]; + e.addEventListener('change', function(){ + Module.config[this.dataset.config] = this.checked; + }, false); + }); + + /* For each button with data-cmd=X, map a click handler which + calls doExec(X). */ + const cmdClick = function(){doExec(this.dataset.cmd);}; + document.querySelectorAll('button[data-cmd]').forEach( + e => e.addEventListener('click', cmdClick, false) + ); + + doExec(null)/*sets up the db and outputs the header*/; +}; diff --git a/ext/fiddle/module-pre.js b/ext/fiddle/module-pre.js new file mode 100644 index 0000000000..23cb7983c6 --- /dev/null +++ b/ext/fiddle/module-pre.js @@ -0,0 +1,100 @@ +/* This is the --pre-js file for emcc. It gets prepended to the + generated fiddle.js. It should contain only code which is relevant + to the setup and initialization of the wasm module. */ +(function(){ + 'use strict'; + + /** + What follows is part of the emscripten core setup. Do not + modify it without understanding what it's doing. + */ + const statusElement = document.getElementById('status'); + const progressElement = document.getElementById('progress'); + const spinnerElement = document.getElementById('spinner'); + const Module = window.Module = { + /* Config object. Referenced by certain Module methods and + app-level code. */ + config: { + /* If true, the Module.print() impl will auto-scroll + the output widget to the bottom when it receives output, + else it won't. */ + autoScrollOutput: true, + /* If true, the output area will be cleared before each + command is run, else it will not. */ + autoClearOutput: false, + /* If true, Module.print() will echo its output to + the console, in addition to its normal output widget. */ + printToConsole: false, + }, + preRun: [], + postRun: [], + //onRuntimeInitialized: function(){}, + print: (function f() { + if(!f._){ + f._ = document.getElementById('output'); + } + f._.value = ''; // clear browser cache + return function(text) { + if(arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' '); + // These replacements are necessary if you render to raw HTML + //text = text.replace(/&/g, "&"); + //text = text.replace(//g, ">"); + //text = text.replace('\n', '
', 'g'); + //console.log("arguments",arguments); + if(window.Module.config.printToConsole) console.log(text); + f._.value += text + "\n"; + if(window.Module.config.autoScrollOutput){ + f._.scrollTop = f._.scrollHeight; + } + }; + })(), + setStatus: function f(text) { + if(!f.last) f.last = { time: Date.now(), text: '' }; + if(text === f.last.text) return; + const m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/); + const now = Date.now(); + if(m && now - f.last.time < 30) return; // if this is a progress update, skip it if too soon + f.last.time = now; + f.last.text = text; + if(m) { + text = m[1]; + progressElement.value = parseInt(m[2])*100; + progressElement.max = parseInt(m[4])*100; + progressElement.hidden = false; + spinnerElement.hidden = false; + } else { + progressElement.value = null; + progressElement.max = null; + progressElement.hidden = true; + if(!text) spinnerElement.hidden = true; + } + statusElement.innerHTML = text; + }, + totalDependencies: 0, + monitorRunDependencies: function(left) { + this.totalDependencies = Math.max(this.totalDependencies, left); + this.setStatus(left + ? ('Preparing... (' + (this.totalDependencies-left) + + '/' + this.totalDependencies + ')') + : 'All downloads complete.'); + } + }; + Module.printErr = Module.print/*capture stderr output*/; + Module.setStatus('Downloading...'); + window.onerror = function(/*message, source, lineno, colno, error*/) { + const err = arguments[4]; + if(err && 'ExitStatus'==err.name){ + Module._isDead = true; + Module.printErr("FATAL ERROR:", err.message); + Module.printErr("Restarting the app requires reloading the page."); + const taOutput = document.querySelector('#output'); + if(taOutput) taOutput.classList.add('error'); + } + Module.setStatus('Exception thrown, see JavaScript console'); + spinnerElement.style.display = 'none'; + Module.setStatus = function(text) { + if(text) console.error('[post-exception status] ' + text); + }; + }; +})(); diff --git a/manifest b/manifest index 66bed235f6..33c3e8de43 100644 --- a/manifest +++ b/manifest @@ -1,9 +1,9 @@ -C Added\san\soption\sto\sauto-clear\sthe\soutput\sarea\sbefore\ssubmitting\sthe\sinput.\sExperimentally\sinverted\sthe\scolors\sin\sthe\sinput/output\sareas. -D 2022-05-19T09:22:16.127 +C Split\sthe\sfiddle\sJS\scode\sinto\sseparate\spre-/post-init\sfiles\sto\ssimplify\sediting.\semcc\swill\scombine\sthese\sinto\sthe\sfinal\sfiddle.js,\sso\sthe\snumber\sof\soutput\sdeliverables\sdoes\snot\schange. +D 2022-05-19T09:55:14.804 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 -F Makefile.in 92890acbab78c76f32ebb1ad50b961c3fc413f7b05052663c8b17d1b7f74a697 +F Makefile.in 7835a8858609cd5f40b84e86cca78bd2c25c54f2e8b22fa76b16acf83509cb63 F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241 F Makefile.msc b28a8a7a977e7312f6859f560348e1eb110c21bd6cf9fab0d16537c0a514eef3 F README.md 8b8df9ca852aeac4864eb1e400002633ee6db84065bd01b78c33817f97d31f5e @@ -56,8 +56,10 @@ F ext/expert/sqlite3expert.c 6ca30d73b9ed75bd56d6e0d7f2c962d2affaa72c505458619d0 F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72 F ext/fiddle/Makefile ea647919e6ac4b50edde1490f60ee87e8ccd75141e4aa650718c6f28eb323bbc -F ext/fiddle/fiddle.in.html 05192302452a1ff410a12de04d10802c89fd90c67d2e7a0983cca599b78d802d +F ext/fiddle/fiddle.in.html 69f8eeb8dc22cbaca2c890ed689d65dd8ad00e896b1a29caae8a22893fc51d8e F ext/fiddle/index.md d9c1c308d8074341bc3b11d1d39073cd77754cb3ca9aeb949f23fdd8323d81cf +F ext/fiddle/module-post.js 8d62f2199cb367267b7799f259c43673f43578f788f30e106a17b2eccbc8a918 +F ext/fiddle/module-pre.js 31661050c461fa05fbaa564e5369795eed8957458ea81fd2038157d852ff93c8 F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b F ext/fts1/ft_hash.h 06df7bba40dadd19597aa400a875dbc2fed705ea @@ -1957,8 +1959,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 6661d60527820417bbfd01c782d242c5190252ea703fc6f56376537d5c8f6a1e -R 1ba355c6c9a1901c14ddac3fca9f90fb +P 1a1e4e7fdbd0ec61218c3a311164086316d825181f3fc1c1ec235b63488746ef +R 845cc95de5a1a485fbec7d915e3ef826 U stephan -Z 350abcb9556383a2d29c463740d62bfd +Z 439fa3de2a51242095eb61aca5099555 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index a70a303356..565d54b618 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1a1e4e7fdbd0ec61218c3a311164086316d825181f3fc1c1ec235b63488746ef \ No newline at end of file +d3d8ea011868bcfa11bb3fe2db78eea6e77ac1005534d9c091f9a81e03f0a7e6 \ No newline at end of file From 618a375e9f12e78ea0c2449bcf5ed7a769fc6796 Mon Sep 17 00:00:00 2001 From: stephan Date: Thu, 19 May 2022 10:24:50 +0000 Subject: [PATCH 045/108] #if'd out the '.log' command in WASM builds. Cleaned up the user-visible parts of the WASM module initialization. FossilOrigin-Name: b5fa12f824690c1022e4d69b0f5c3949324b311557a7412810741731db7e2cce --- ext/fiddle/fiddle.in.html | 48 ++++++++++++++++++++++++++++----------- ext/fiddle/module-post.js | 40 ++++++++++++++++++++------------ ext/fiddle/module-pre.js | 9 ++++---- manifest | 18 +++++++-------- manifest.uuid | 2 +- src/shell.c.in | 4 ++++ 6 files changed, 79 insertions(+), 42 deletions(-) diff --git a/ext/fiddle/fiddle.in.html b/ext/fiddle/fiddle.in.html index a9c2a57321..b78019565a 100644 --- a/ext/fiddle/fiddle.in.html +++ b/ext/fiddle/fiddle.in.html @@ -5,13 +5,14 @@ sqlite3 fiddle
sqlite3 fiddle
-
emscripten
+
+
+
Initializing app...
+
+ On a slow internet connection this may take a moment. If this + message displays for "a long time", intialization may have + failed and the JavaScript console may contain clues as to why. +
+
Downloading...
-
+
Options
@@ -120,7 +142,7 @@
-
+
- - - + + +
- +
-
+
Notes and Caveats diff --git a/ext/fiddle/module-post.js b/ext/fiddle/module-post.js index bc6f3b2b9f..41dfa35769 100644 --- a/ext/fiddle/module-post.js +++ b/ext/fiddle/module-post.js @@ -14,11 +14,23 @@ window.Module.onRuntimeInitialized = function(){ 'use strict'; const Module = window.Module /* wasm module as set up by emscripten */; delete Module.onRuntimeInitialized; - const taInput = document.querySelector('#input'); - const btnClearIn = document.querySelector('#btn-clear'); - document.querySelectorAll('button').forEach(function(e){ - e.removeAttribute('disabled'); - }); + + /* querySelectorAll() proxy */ + const EAll = function(/*[element=document,] cssSelector*/){ + return (arguments.length>1 ? arguments[0] : document) + .querySelectorAll(arguments[arguments.length-1]); + }; + /* querySelector() proxy */ + const E = function(/*[element=document,] cssSelector*/){ + return (arguments.length>1 ? arguments[0] : document) + .querySelector(arguments[arguments.length-1]); + }; + + // Unhide all elements which start out hidden + EAll('.initially-hidden').forEach((e)=>e.classList.remove('initially-hidden')); + + const taInput = E('#input'); + const btnClearIn = E('#btn-clear'); btnClearIn.addEventListener('click',function(){ taInput.value = ''; },false); @@ -30,8 +42,8 @@ window.Module.onRuntimeInitialized = function(){ btnRun.click(); } }, false); - const taOutput = document.querySelector('#output'); - const btnClearOut = document.querySelector('#btn-clear-output'); + const taOutput = E('#output'); + const btnClearOut = E('#btn-clear-output'); btnClearOut.addEventListener('click',function(){ taOutput.value = ''; },false); @@ -47,7 +59,7 @@ window.Module.onRuntimeInitialized = function(){ if(Module.config.autoClearOutput) taOutput.value=''; f._(sql); }; - const btnRun = document.querySelector('#btn-run'); + const btnRun = E('#btn-run'); btnRun.addEventListener('click',function(){ const sql = taInput.value.trim(); if(sql){ @@ -55,20 +67,20 @@ window.Module.onRuntimeInitialized = function(){ } },false); - document.querySelector('#opt-cb-sbs') + E('#opt-cb-sbs') .addEventListener('change', function(){ - document.querySelector('#main-wrapper').classList[ + E('#main-wrapper').classList[ this.checked ? 'add' : 'remove' ]('side-by-side'); }, false); - document.querySelector('#btn-notes-caveats') + E('#btn-notes-caveats') .addEventListener('click', function(){ - document.querySelector('#notes-caveats').remove(); + E('#notes-caveats').remove(); }, false); /* For each checkbox with data-config=X, set up a binding to Module.config[X]. */ - document.querySelectorAll('input[type=checkbox][data-config]') + EAll('input[type=checkbox][data-config]') .forEach(function(e){ e.checked = !!Module.config[e.dataset.config]; e.addEventListener('change', function(){ @@ -79,7 +91,7 @@ window.Module.onRuntimeInitialized = function(){ /* For each button with data-cmd=X, map a click handler which calls doExec(X). */ const cmdClick = function(){doExec(this.dataset.cmd);}; - document.querySelectorAll('button[data-cmd]').forEach( + EAll('button[data-cmd]').forEach( e => e.addEventListener('click', cmdClick, false) ); diff --git a/ext/fiddle/module-pre.js b/ext/fiddle/module-pre.js index 23cb7983c6..67c6f5a9a0 100644 --- a/ext/fiddle/module-pre.js +++ b/ext/fiddle/module-pre.js @@ -64,12 +64,11 @@ progressElement.hidden = false; spinnerElement.hidden = false; } else { - progressElement.value = null; - progressElement.max = null; - progressElement.hidden = true; - if(!text) spinnerElement.hidden = true; + progressElement.remove(); + if(!text) spinnerElement.remove(); } - statusElement.innerHTML = text; + if(text) statusElement.innerText = text; + else statusElement.remove(); }, totalDependencies: 0, monitorRunDependencies: function(left) { diff --git a/manifest b/manifest index 33c3e8de43..eb4115d318 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Split\sthe\sfiddle\sJS\scode\sinto\sseparate\spre-/post-init\sfiles\sto\ssimplify\sediting.\semcc\swill\scombine\sthese\sinto\sthe\sfinal\sfiddle.js,\sso\sthe\snumber\sof\soutput\sdeliverables\sdoes\snot\schange. -D 2022-05-19T09:55:14.804 +C #if'd\sout\sthe\s'.log'\scommand\sin\sWASM\sbuilds.\sCleaned\sup\sthe\suser-visible\sparts\sof\sthe\sWASM\smodule\sinitialization. +D 2022-05-19T10:24:50.097 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -56,10 +56,10 @@ F ext/expert/sqlite3expert.c 6ca30d73b9ed75bd56d6e0d7f2c962d2affaa72c505458619d0 F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72 F ext/fiddle/Makefile ea647919e6ac4b50edde1490f60ee87e8ccd75141e4aa650718c6f28eb323bbc -F ext/fiddle/fiddle.in.html 69f8eeb8dc22cbaca2c890ed689d65dd8ad00e896b1a29caae8a22893fc51d8e +F ext/fiddle/fiddle.in.html fc5bb8e6c13cac9880dfb41eceed3ff031d51d2a73bf66da51e5cc171e1ee28c F ext/fiddle/index.md d9c1c308d8074341bc3b11d1d39073cd77754cb3ca9aeb949f23fdd8323d81cf -F ext/fiddle/module-post.js 8d62f2199cb367267b7799f259c43673f43578f788f30e106a17b2eccbc8a918 -F ext/fiddle/module-pre.js 31661050c461fa05fbaa564e5369795eed8957458ea81fd2038157d852ff93c8 +F ext/fiddle/module-post.js 5d0eafba848a3e129c46ab1e1af99dcc7e8b7fc207f86ad05c5f45079cca9b6d +F ext/fiddle/module-pre.js 7c093908bd7768c96fb812e5fc1f15073ab129527fa2124a6f3e5076455761ed F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b F ext/fts1/ft_hash.h 06df7bba40dadd19597aa400a875dbc2fed705ea @@ -559,7 +559,7 @@ F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c a4eb3c617027fd049b07432f3b942ea7151fa793a332a11a7d0f58c9539e104f F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c 74060a09f66c0c056f3c61627e22cb484af0bbfa29d7d14dcf17c684742c15de -F src/shell.c.in ce99ca3e14211ca8d3eb82ba012504422ef42a59e4abd38c9a08a9638aee8694 +F src/shell.c.in cc3e19b2d2eefbadc4139b016c097d6478eae01d14eca993368ee5cff8820fff F src/sqlite.h.in d15c307939039086adca159dd340a94b79b69827e74c6d661f343eeeaefba896 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h a988810c9b21c0dc36dc7a62735012339dc76fc7ab448fb0792721d30eacb69d @@ -1959,8 +1959,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 1a1e4e7fdbd0ec61218c3a311164086316d825181f3fc1c1ec235b63488746ef -R 845cc95de5a1a485fbec7d915e3ef826 +P d3d8ea011868bcfa11bb3fe2db78eea6e77ac1005534d9c091f9a81e03f0a7e6 +R d7744af6398d083bf2a1bc37b40874d9 U stephan -Z 439fa3de2a51242095eb61aca5099555 +Z 4e1f89c6494ab0a52794383c827e3145 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 565d54b618..e83553ea74 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d3d8ea011868bcfa11bb3fe2db78eea6e77ac1005534d9c091f9a81e03f0a7e6 \ No newline at end of file +b5fa12f824690c1022e4d69b0f5c3949324b311557a7412810741731db7e2cce \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index c892a25bef..9a0859293b 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -4353,7 +4353,9 @@ static const char *(azHelp[]) = { #if !defined(SQLITE_OMIT_LOAD_EXTENSION) && !defined(SQLITE_SHELL_WASM_MODE) ".load FILE ?ENTRY? Load an extension library", #endif +#ifndef SQLITE_SHELL_WASM_MODE ".log FILE|off Turn logging on or off. FILE can be stderr/stdout", +#endif ".mode MODE ?OPTIONS? Set output mode", " MODE is one of:", " ascii Columns/rows delimited by 0x1F and 0x1E", @@ -9386,6 +9388,7 @@ static int do_meta_command(char *zLine, ShellState *p){ }else #endif +#ifndef SQLITE_SHELL_WASM_MODE if( c=='l' && strncmp(azArg[0], "log", n)==0 ){ failIfSafeMode(p, "cannot run .log in safe mode"); if( nArg!=2 ){ @@ -9397,6 +9400,7 @@ static int do_meta_command(char *zLine, ShellState *p){ p->pLog = output_file_open(zFile, 0); } }else +#endif if( c=='m' && strncmp(azArg[0], "mode", n)==0 ){ const char *zMode = 0; From 403445be23d35991b4675b7590e84a28c850fc15 Mon Sep 17 00:00:00 2001 From: stephan Date: Thu, 19 May 2022 10:38:54 +0000 Subject: [PATCH 046/108] Ensure that the output area is cleared of any init-time messages which the emscripten bootstrapping process emits when downloading of the wasm module is slow. FossilOrigin-Name: 1d8d0593573f9fc8e0990a292a4b3317d8a4c323d60514d0768543dd65c24d1e --- ext/fiddle/module-post.js | 1 + ext/fiddle/module-pre.js | 20 +++++++++++++------- manifest | 14 +++++++------- manifest.uuid | 2 +- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/ext/fiddle/module-post.js b/ext/fiddle/module-post.js index 41dfa35769..5f91d0ca25 100644 --- a/ext/fiddle/module-post.js +++ b/ext/fiddle/module-post.js @@ -95,5 +95,6 @@ window.Module.onRuntimeInitialized = function(){ e => e.addEventListener('click', cmdClick, false) ); + Module.print(null/*clear any output generated by the init process*/); doExec(null)/*sets up the db and outputs the header*/; }; diff --git a/ext/fiddle/module-pre.js b/ext/fiddle/module-pre.js index 67c6f5a9a0..9e9c88f22e 100644 --- a/ext/fiddle/module-pre.js +++ b/ext/fiddle/module-pre.js @@ -30,10 +30,13 @@ postRun: [], //onRuntimeInitialized: function(){}, print: (function f() { - if(!f._){ - f._ = document.getElementById('output'); - } - f._.value = ''; // clear browser cache + /* Maintenance reminder: we currently require/expect a textarea + output element. It might be nice to extend this to behave + differently if the output element is a non-textarea element, + in which case it would need to append the given text as a TEXT + node and add a line break. */ + const outputElem = document.getElementById('output'); + outputElem.value = ''; // clear browser cache return function(text) { if(arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' '); // These replacements are necessary if you render to raw HTML @@ -41,11 +44,14 @@ //text = text.replace(//g, ">"); //text = text.replace('\n', '
', 'g'); - //console.log("arguments",arguments); + if(null===text){/*special case: clear output*/ + outputElem.value = ''; + return; + } if(window.Module.config.printToConsole) console.log(text); - f._.value += text + "\n"; + outputElem.value += text + "\n"; if(window.Module.config.autoScrollOutput){ - f._.scrollTop = f._.scrollHeight; + outputElem.scrollTop = outputElem.scrollHeight; } }; })(), diff --git a/manifest b/manifest index eb4115d318..45fdebe913 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C #if'd\sout\sthe\s'.log'\scommand\sin\sWASM\sbuilds.\sCleaned\sup\sthe\suser-visible\sparts\sof\sthe\sWASM\smodule\sinitialization. -D 2022-05-19T10:24:50.097 +C Ensure\sthat\sthe\soutput\sarea\sis\scleared\sof\sany\sinit-time\smessages\swhich\sthe\semscripten\sbootstrapping\sprocess\semits\swhen\sdownloading\sof\sthe\swasm\smodule\sis\sslow. +D 2022-05-19T10:38:54.185 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -58,8 +58,8 @@ F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be F ext/fiddle/Makefile ea647919e6ac4b50edde1490f60ee87e8ccd75141e4aa650718c6f28eb323bbc F ext/fiddle/fiddle.in.html fc5bb8e6c13cac9880dfb41eceed3ff031d51d2a73bf66da51e5cc171e1ee28c F ext/fiddle/index.md d9c1c308d8074341bc3b11d1d39073cd77754cb3ca9aeb949f23fdd8323d81cf -F ext/fiddle/module-post.js 5d0eafba848a3e129c46ab1e1af99dcc7e8b7fc207f86ad05c5f45079cca9b6d -F ext/fiddle/module-pre.js 7c093908bd7768c96fb812e5fc1f15073ab129527fa2124a6f3e5076455761ed +F ext/fiddle/module-post.js 5295dfb2bd744cb0ad03d219e8e14123b1bb8ad39054f8b65c3358df4d746cd2 +F ext/fiddle/module-pre.js baff3e5f693db09f693af0bf398c0c89cdef04bdc3ffb6ad4ed02775077fdea4 F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b F ext/fts1/ft_hash.h 06df7bba40dadd19597aa400a875dbc2fed705ea @@ -1959,8 +1959,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P d3d8ea011868bcfa11bb3fe2db78eea6e77ac1005534d9c091f9a81e03f0a7e6 -R d7744af6398d083bf2a1bc37b40874d9 +P b5fa12f824690c1022e4d69b0f5c3949324b311557a7412810741731db7e2cce +R e7797da2d1a4378761bd408e0f019d9d U stephan -Z 4e1f89c6494ab0a52794383c827e3145 +Z 2f01ae6f2a6a94715d9eed3abad05b24 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index e83553ea74..cb51321570 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b5fa12f824690c1022e4d69b0f5c3949324b311557a7412810741731db7e2cce \ No newline at end of file +1d8d0593573f9fc8e0990a292a4b3317d8a4c323d60514d0768543dd65c24d1e \ No newline at end of file From 6da6f31cca0e3a4cdb2330b7f51cc0bfe540f21f Mon Sep 17 00:00:00 2001 From: stephan Date: Thu, 19 May 2022 10:58:59 +0000 Subject: [PATCH 047/108] fiddle make target now accepts fiddle_cflags=... from the CLI to overrid -Ox and such for one-off builds. FossilOrigin-Name: 4609a4f8626ae3d8179cae27e391bd06ffda18e9ef9e1b78745b36c7e8dd25db --- Makefile.in | 9 ++++++--- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Makefile.in b/Makefile.in index 158d174d31..d2b5fc3474 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1518,7 +1518,6 @@ sqlite3.dll: $(REAL_LIBOBJ) sqlite3.def # fiddle section # fiddle_dir = ext/fiddle -fiddle_tmpl = $(fiddle_dir)/fiddle.in.html fiddle_html = $(fiddle_dir)/fiddle.html fiddle_generated = $(fiddle_html) \ $(fiddle_dir)/fiddle.js \ @@ -1537,8 +1536,12 @@ emcc_flags = $(emcc_opt) \ -sEXIT_RUNTIME=1 \ --pre-js $(fiddle_dir)/module-pre.js \ --post-js $(fiddle_dir)/module-post.js \ - --shell-file $(fiddle_tmpl) -$(fiddle_html): Makefile sqlite3.c shell.c $(fiddle_tmpl) \ + --shell-file $(fiddle_dir)/fiddle.in.html \ + $(fiddle_cflags) +# $(fiddle_cflags) is intended to be passed to make via the CLI in +# order to override, e.g., -Ox for one-off builds. +$(fiddle_html): Makefile sqlite3.c shell.c \ + $(fiddle_dir)/fiddle.in.html \ $(fiddle_dir)/module-pre.js $(fiddle_dir)/module-post.js emcc -o $@ $(emcc_flags) sqlite3.c shell.c fiddle: $(fiddle_html) diff --git a/manifest b/manifest index 45fdebe913..0a5f20a3c7 100644 --- a/manifest +++ b/manifest @@ -1,9 +1,9 @@ -C Ensure\sthat\sthe\soutput\sarea\sis\scleared\sof\sany\sinit-time\smessages\swhich\sthe\semscripten\sbootstrapping\sprocess\semits\swhen\sdownloading\sof\sthe\swasm\smodule\sis\sslow. -D 2022-05-19T10:38:54.185 +C fiddle\smake\starget\snow\saccepts\sfiddle_cflags=...\sfrom\sthe\sCLI\sto\soverrid\s-Ox\sand\ssuch\sfor\sone-off\sbuilds. +D 2022-05-19T10:58:59.923 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 -F Makefile.in 7835a8858609cd5f40b84e86cca78bd2c25c54f2e8b22fa76b16acf83509cb63 +F Makefile.in 04cd03b6d3b1f1ec84b5b052f37d0a8708000f3d9584e6106f1b8e2e1f559987 F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241 F Makefile.msc b28a8a7a977e7312f6859f560348e1eb110c21bd6cf9fab0d16537c0a514eef3 F README.md 8b8df9ca852aeac4864eb1e400002633ee6db84065bd01b78c33817f97d31f5e @@ -1959,8 +1959,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P b5fa12f824690c1022e4d69b0f5c3949324b311557a7412810741731db7e2cce -R e7797da2d1a4378761bd408e0f019d9d +P 1d8d0593573f9fc8e0990a292a4b3317d8a4c323d60514d0768543dd65c24d1e +R 95e0243279f406591d2490a8625a64de U stephan -Z 2f01ae6f2a6a94715d9eed3abad05b24 +Z 342f02945f9525abd872463c70c813a2 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index cb51321570..1b25cdb1c6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1d8d0593573f9fc8e0990a292a4b3317d8a4c323d60514d0768543dd65c24d1e \ No newline at end of file +4609a4f8626ae3d8179cae27e391bd06ffda18e9ef9e1b78745b36c7e8dd25db \ No newline at end of file From 38240592ad483954d9d10055dec39ebd1af504ce Mon Sep 17 00:00:00 2001 From: stephan Date: Thu, 19 May 2022 15:58:13 +0000 Subject: [PATCH 048/108] Numerous layout tweaks, the most significant being that the layout now adapts to the window size. Swapped positions of the input/output areas. This version supports, by uncommenting a few bits, a jquery.terminal-based view but alternatives to that 300kb dependency are still under investigation. FossilOrigin-Name: 1aad3642c9fc14c25223628a309d84decc8d73a123e42d6efdc36d855b5b0666 --- ext/fiddle/fiddle.in.html | 142 +++++++++++++++++++++----------------- ext/fiddle/module-post.js | 129 ++++++++++++++++++++++++++++++++-- ext/fiddle/module-pre.js | 3 +- manifest | 16 ++--- manifest.uuid | 2 +- 5 files changed, 212 insertions(+), 80 deletions(-) diff --git a/ext/fiddle/fiddle.in.html b/ext/fiddle/fiddle.in.html index b78019565a..a14bf5b4b4 100644 --- a/ext/fiddle/fiddle.in.html +++ b/ext/fiddle/fiddle.in.html @@ -4,6 +4,8 @@ sqlite3 fiddle + -
sqlite3 fiddle
+
sqlite3 fiddle
Initializing app...
@@ -123,75 +154,56 @@
-
- Options -
- - - - - - - - - - - - -
-
-
-
- -
- - - +
+ + + +
+
+
+ +
+ +
-
- -
- -
-
-
-
-
- Notes and Caveats - -
-

- This JavaScript application runs a C application which has been - compiled into WASM (Web Assembly). As such, it has certain - limitations. Those include, but are not limited to: -

-
    -
  • It cannot recover after a call to - exit(). If the native code triggers - an exit, reloading the page is the only way to restart - the application. (Making the app restartable without reloading - the page would require significant surgery in the C code.) -
  • -
  • It cannot perform any file I/O, and running - any command which attempts to do so might trigger an - exit(). -
  • -
  • A number of dot-commands available in the CLI shell are - explicitly removed from this version of the shell. -
  • -
-
+
+ + +
sqlite3-api.js tests
+ +
+
+
Initializing app...
+
+ On a slow internet connection this may take a moment. If this + message displays for "a long time", intialization may have + failed and the JavaScript console may contain clues as to why. +
+
+
Downloading...
+
+ +
+
Everything on this page happens in the dev console.
+ + + + + diff --git a/ext/fiddle/testing1.js b/ext/fiddle/testing1.js new file mode 100644 index 0000000000..d1b15e2810 --- /dev/null +++ b/ext/fiddle/testing1.js @@ -0,0 +1,23 @@ +/* + 2022-05-22 + + The author disclaims copyright to this source code. In place of a + legal notice, here is a blessing: + + * May you do good and not evil. + * May you find forgiveness for yourself and forgive others. + * May you share freely, never taking more than you give. + + *********************************************************************** + + A basic test script for sqlite3-api.js. +*/ +(function(){ + self.Module.onRuntimeInitialized = function(){ + console.log("Loading sqlite3-api.js..."); + self.Module.loadSqliteAPI(function(S){ + console.log("Loaded module:",S.sqlite3_libversion(), + S.sqlite3_sourceid()); + }); + }; +})(self/*window or worker*/); diff --git a/manifest b/manifest index 8bc74a5e82..34fda5bf97 100644 --- a/manifest +++ b/manifest @@ -1,9 +1,9 @@ -C Minor\sfiddle-related\sbuild\srestructuring\sto\ssupport\supcoming\sdevelopment\sof\sthe\sC-style\swasm\ssqlite3\sinterface,\splus\ssome\scommentary\sabout\sthe\splans\sand\sgoals\sfor\sthat. -D 2022-05-21T21:13:44.686 +C Build\srefactoring\sfor\sthe\sfiddle/wasm\sbits.\sSet\sup\swasm\sbinding\sof\sa\schunk\sof\sthe\score\sC\sAPI\sand\sadded\ssome\sinfastructure\sfor\screating\stest\spages\sfor\sit. +D 2022-05-22T00:27:19.296 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 -F Makefile.in 62df7206650987c76f15b2e1c23830976858892815b9fc4d283c850628e0c724 +F Makefile.in a192a8de35ba61e6d695a3bd430b021e7cbf7ea473497028540801fe7b659282 F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241 F Makefile.msc b28a8a7a977e7312f6859f560348e1eb110c21bd6cf9fab0d16537c0a514eef3 F README.md 8b8df9ca852aeac4864eb1e400002633ee6db84065bd01b78c33817f97d31f5e @@ -55,13 +55,19 @@ F ext/expert/expert1.test 3c642a4e7bbb14f21ddab595436fb465a4733f47a0fe5b2855e1d5 F ext/expert/sqlite3expert.c 6ca30d73b9ed75bd56d6e0d7f2c962d2affaa72c505458619d0ff5d9cdfac204 F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72 -F ext/fiddle/EXPORTED_FUNCTIONS 487fc7c83d45c48326f731c89162ed17ab15767e5efede8999d7d6c6e2d04c0f +F ext/fiddle/EXPORTED_FUNCTIONS.fiddle 487fc7c83d45c48326f731c89162ed17ab15767e5efede8999d7d6c6e2d04c0f w ext/fiddle/EXPORTED_FUNCTIONS +F ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 4b06e6c3ce8c8389274079ffb6b441ffff1a55e32a448cf21ce1da45a16c8a01 F ext/fiddle/EXPORTED_RUNTIME_METHODS 91d5dcb0168ee056fa1a340cb8ab3c23d922622f8dad39d28919dd8af2b3ade0 -F ext/fiddle/Makefile b2904d52c10a7c984cfab95c54fb85f33aa8a6b2653faf1527d08ce57114be46 -F ext/fiddle/fiddle-worker.js 28e50e021e84aaedf4cbdb2ef25e4183f1e5be8da7996a50fc8d0b5ed78fa00a -F ext/fiddle/fiddle.html f536878dbaa35ba4d9ad8c87dda7fb2ea5502fdd824577d83b2265d65b8ca4d1 -F ext/fiddle/fiddle.js 9361d451845ac3c97c5492c24c8d18b8fe2deff07741462bdf8e39c375be25b2 +F ext/fiddle/Makefile 9277c73e208b9c8093659256c9f07409c877e366480c7c22ec545ee345451d95 +F ext/fiddle/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f +F ext/fiddle/fiddle-worker.js c22557b641b47fa1473d3465a4e69fe06b8b09b924955805a4202c8201ddc429 +F ext/fiddle/fiddle.html 657c6c3f860c322fba3c69fa4f7a1209e2d2ce44b4bc65a3e154e3a97c047a7c +F ext/fiddle/fiddle.js f9c79164428e96a5909532f18a8bc8f8c8ec4f738bfc09ad3d2a532c2400f9f0 F ext/fiddle/index.md d9c1c308d8074341bc3b11d1d39073cd77754cb3ca9aeb949f23fdd8323d81cf +F ext/fiddle/sqlite3-api.js d3c6da99850e146e50dc42039ac027e5d9b08b9f24eb22b31d1982c49930ee7c +F ext/fiddle/testing-common.js 37b014758db7e5e74278e37dc712ced2fc9b40d0617f5ed0b8b64a6bd9c0a45d +F ext/fiddle/testing1.html 68cec1b1c8646a071717e5979f22e4268e6d36d96ba13ad68333351acdbcf1d1 +F ext/fiddle/testing1.js 0fb900c768b06c2ec3922ab522f721a68b0756d200e3c66602461f45910bcd39 F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b F ext/fts1/ft_hash.h 06df7bba40dadd19597aa400a875dbc2fed705ea @@ -1961,8 +1967,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 5ff3326856bc190cee15a5fca5ded89aacc4bf931a8df98726a872b310e2a4fc -R 3ab23a2e617cc2f177067d0130c7a41f +P c7cfdd4c3682659352642461d3307bf8180703b121ec1802ba5881f8e1ef9809 +R d89e623e1614875df0e3a579152a2be9 U stephan -Z 0792a8e58fb57cfdbc5dcb7974589bd6 +Z fd89698a5fe01334529b2fb407d595a1 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index b2ce3cbe35..a0a10eb4c2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c7cfdd4c3682659352642461d3307bf8180703b121ec1802ba5881f8e1ef9809 \ No newline at end of file +dea098b64eb95c395b346ebcae687afe42b7d21df48833527808c02226300a66 \ No newline at end of file From d60b7275c3a8734ab8ebeeb5277b2fbb49f49484 Mon Sep 17 00:00:00 2001 From: stephan Date: Sun, 22 May 2022 14:07:44 +0000 Subject: [PATCH 066/108] WASM OO wrapper #1: prepare() and bind() APIs are in place but are untested, pending fetch/get APIs. FossilOrigin-Name: 84c8f63a1c446331a3afe52b0c8bdfa6980f24aa4cf600f576877fef5e650c39 --- ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 | 4 + ext/fiddle/sqlite3-api.js | 81 +++--- ext/fiddle/testing1.js | 389 +++++++++++++++++++++++++- manifest | 18 +- manifest.uuid | 2 +- 5 files changed, 436 insertions(+), 58 deletions(-) diff --git a/ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 b/ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 index 6bb557e99d..09f6e8ba79 100644 --- a/ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 +++ b/ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 @@ -1,6 +1,8 @@ _sqlite3_bind_blob _sqlite3_bind_double _sqlite3_bind_int +_sqlite3_bind_int64 +_sqlite3_bind_null _sqlite3_bind_parameter_index _sqlite3_bind_text _sqlite3_changes @@ -16,9 +18,11 @@ _sqlite3_column_text _sqlite3_column_type _sqlite3_create_function_v2 _sqlite3_data_count +_sqlite3_db_filename _sqlite3_errmsg _sqlite3_exec _sqlite3_finalize +_sqlite3_interrupt _sqlite3_libversion _sqlite3_open _sqlite3_prepare_v2 diff --git a/ext/fiddle/sqlite3-api.js b/ext/fiddle/sqlite3-api.js index 65e6b00f61..83e46bbcaf 100644 --- a/ext/fiddle/sqlite3-api.js +++ b/ext/fiddle/sqlite3-api.js @@ -85,6 +85,7 @@ SQLITE_FLOAT: 2, SQLITE_TEXT: 3, SQLITE_BLOB: 4, + SQLITE_NULL: 5, /* sqlite encodings, used for creating UDFs, noting that we will only support UTF8. */ SQLITE_UTF8: 1 @@ -102,61 +103,61 @@ use for the JS-side binding. That's required when overloading a binding for two different uses. */ - ["sqlite3_open", "number", ["string", "number"]], - ["sqlite3_close_v2", "number", ["number"]], - ["sqlite3_exec", "number", - ["number", "string", "number", "number", "number"]], + ["sqlite3_bind_blob","number",["number", "number", "number", "number", "number"]], + ["sqlite3_bind_double","number",["number", "number", "number"]], + ["sqlite3_bind_int","number",["number", "number", "number"]], + ["sqlite3_bind_int64","number",["number", "number", "number"]], + ["sqlite3_bind_null","void",["number"]], + ["sqlite3_bind_parameter_index","number",["number", "string"]], + ["sqlite3_bind_text","number",["number", "number", "number", "number", "number"]], ["sqlite3_changes", "number", ["number"]], + ["sqlite3_clear_bindings","number",["number"]], + ["sqlite3_close_v2", "number", ["number"]], + ["sqlite3_column_blob","number", ["number", "number"]], + ["sqlite3_column_bytes","number",["number", "number"]], + ["sqlite3_column_count", "number", ["number"]], + ["sqlite3_column_count","number",["number"]], + ["sqlite3_column_double","number",["number", "number"]], + ["sqlite3_column_name","string",["number", "number"]], + ["sqlite3_column_text","string",["number", "number"]], + ["sqlite3_column_type","number",["number", "number"]], + ["sqlite3_create_function_v2", "number", + ["number", "string", "number", "number","number", + "number", "number", "number", "number"]], + ["sqlite3_data_count", "number", ["number"]], + ["sqlite3_db_filename", "string", ["number", "string"]], + ["sqlite3_errmsg", "string", ["number"]], + ["sqlite3_exec", "number", ["number", "string", "number", "number", "number"]], + ["sqlite3_finalize", "number", ["number"]], + ["sqlite3_interrupt", "void", ["number"]], + ["sqlite3_libversion", "string", []], + ["sqlite3_open", "number", ["string", "number"]], ["sqlite3_prepare_v2", "number", ["number", "string", "number", "number", "number"]], - ["sqlite3_prepare_v2_sqlptr", + ["sqlite3_prepare_v2_sqlptr", "sqlite3_prepare_v2", /* Impl which requires that the 2nd argument be a pointer to the SQL, instead of a string. This is used for cases where we require a non-NULL value for the final argument. We may or may not need this, depending on how our higher-level API shapes up, but this code's spiritual guide (sql.js) uses it we we'll include it. */ - "sqlite3_prepare_v2", "number", ["number", "number", "number", "number", "number"]], - ["sqlite3_bind_text","number",["number", "number", "number", "number", "number"]], - ["sqlite3_bind_blob","number",["number", "number", "number", "number", "number"]], - ["sqlite3_bind_double","number",["number", "number", "number"]], - ["sqlite3_bind_int","number",["number", "number", "number"]], - ["sqlite3_bind_parameter_index","number",["number", "string"]], - ["sqlite3_step", "number", ["number"]], - ["sqlite3_errmsg", "string", ["number"]], - ["sqlite3_column_count","number",["number"]], - ["sqlite3_data_count", "number", ["number"]], - ["sqlite3_column_count", "number", ["number"]], - ["sqlite3_column_double","number",["number", "number"]], - ["sqlite3_column_text","string",["number", "number"]], - ["sqlite3_column_blob","number", ["number", "number"]], - ["sqlite3_column_bytes","number",["number", "number"]], - ["sqlite3_column_type","number",["number", "number"]], - ["sqlite3_column_name","string",["number", "number"]], ["sqlite3_reset", "number", ["number"]], - ["sqlite3_clear_bindings","number",["number"]], - ["sqlite3_finalize", "number", ["number"]], - ["sqlite3_create_function_v2", "number", - ["number", "string", "number", "number", - "number", "number", "number", "number", - "number"]], - ["sqlite3_value_type", "number", ["number"]], - ["sqlite3_value_bytes","number",["number"]], - ["sqlite3_value_text", "string", ["number"]], - ["sqlite3_value_blob", "number", ["number"]], - ["sqlite3_value_double","number",["number"]], + ["sqlite3_result_blob",null,["number", "number", "number", "number"]], ["sqlite3_result_double",null,["number", "number"]], + ["sqlite3_result_error",null,["number", "string", "number"]], + ["sqlite3_result_int",null,["number", "number"]], ["sqlite3_result_null",null,["number"]], ["sqlite3_result_text",null,["number", "string", "number", "number"]], - ["sqlite3_result_blob",null,["number", "number", "number", "number"]], - ["sqlite3_result_int",null,["number", "number"]], - ["sqlite3_result_error",null,["number", "string", "number"]], - ["sqlite3_libversion", "string", []], - ["sqlite3_sourceid", "string", []] + ["sqlite3_sourceid", "string", []], + ["sqlite3_step", "number", ["number"]], + ["sqlite3_value_blob", "number", ["number"]], + ["sqlite3_value_bytes","number",["number"]], + ["sqlite3_value_double","number",["number"]], + ["sqlite3_value_text", "string", ["number"]], + ["sqlite3_value_type", "number", ["number"]] //["sqlite3_sql", "string", ["number"]], //["sqlite3_normalized_sql", "string", ["number"]] - ].forEach(function(e){ - const a = Array.prototype.slice.call(e); + ].forEach(function(a){ const k = (4==a.length) ? a.shift() : a[0]; api[k] = cwrap.apply(this, a); }); diff --git a/ext/fiddle/testing1.js b/ext/fiddle/testing1.js index d1b15e2810..a24d63f105 100644 --- a/ext/fiddle/testing1.js +++ b/ext/fiddle/testing1.js @@ -12,12 +12,385 @@ A basic test script for sqlite3-api.js. */ -(function(){ - self.Module.onRuntimeInitialized = function(){ - console.log("Loading sqlite3-api.js..."); - self.Module.loadSqliteAPI(function(S){ - console.log("Loaded module:",S.sqlite3_libversion(), - S.sqlite3_sourceid()); - }); +const setupAPI = function(S/*sqlite3 module*/){ + + /* memory for use in some pointer-passing routines */ + const pPtrArg = stackAlloc(4); + const dummyArg = {/*for restricting Stmt constructor to internal use*/}; + const toss = function(){ + throw new Error(Array.prototype.join.apply(arguments, ' ')); }; -})(self/*window or worker*/); + + /** + The DB class wraps a sqlite3 db handle. + */ + const DB = function(name/*TODO: openMode flags*/){ + if(!name) name = ':memory:'; + else if('string'!==typeof name){ + toss("TODO: support blob image of db here."); + } + this.checkRc(S.sqlite3_open(name, pPtrArg)); + this.pDb = getValue(pPtrArg, "i32"); + this.filename = name; + this._statements = {/*array of open Stmt _pointers_*/}; + }; + + /** + This class wraps sqlite3_stmt. Calling this constructor + directly will trigger an exception. Use DB.prepare() to create + new instances. + */ + const Stmt = function(){ + if(dummyArg!=arguments[2]){ + toss("Do not call the Stmt constructor directly. Use DB.prepare()."); + } + this.db = arguments[0]; + this.pStmt = arguments[1]; + this.columnCount = S.sqlite3_column_count(this.pStmt); + this._allocs = [/*list of alloc'd memory blocks for bind() values*/] + }; + + + /** Throws if the given DB has been closed, else it is returned. */ + const affirmDbOpen = function(db){ + if(!db.pDb) toss("DB has been closed."); + return db; + }; + + DB.prototype = { + /** + Expects to be given an sqlite3 API result code. If it is + falsy, this function returns this object, else it throws an + exception with an error message from sqlite3_errmsg(), + using this object's db handle. + */ + checkRc: function(sqliteResultCode){ + if(!sqliteResultCode) return this; + toss(S.sqlite3_errmsg(this.pDb) || "Unknown db error."); + }, + /** + Finalizes all open statements and closes this database + connection. This is a no-op if the db has already been + closed. + */ + close: function(){ + if(this.pDb){ + let s; + while(undefined!==(s = this._statements.pop())){ + if(s.pStmt) s.finalize(); + } + S.sqlite3_close_v2(this.pDb); + delete this.pDb; + } + }, + /** + Similar to this.filename but will return NULL for + special names like ":memory:". Not of much use until + we have filesystem support. Throws if the DB has + been closed. If passed an argument it then it will return + the filename of the ATTACHEd db with that name, else it assumes + a name of `main`. + */ + fileName: function(dbName){ + return S.sqlite3_db_filename(affirmDbOpen(this).pDb, dbName||"main"); + }, + + /** + Compiles the given SQL and returns a prepared Stmt. This is + the only way to create new Stmt objects. Throws on error. + */ + prepare: function(sql){ + affirmDbOpen(this); + setValue(pPtrArg,0,"i32"); + this.checkRc(S.sqlite3_prepare_v2(this.pDb, sql, -1, pPtrArg, null)); + const pStmt = getValue(pPtrArg, "i32"); + if(!pStmt) toss("Empty SQL is not permitted."); + const stmt = new Stmt(this, pStmt, dummyArg); + this._statements[pStmt] = stmt; + return stmt; + } + }; + + /** + Internal-use enum for mapping JS types to DB-bindable types. + These do not (and need not) line up with the SQLITE_type + values. All values in this enum must be truthy and distinct + but they need not be numbers. + */ + const BindTypes = { + null: 1, + number: 2, + string: 3, + boolean: 4, + blob: 5 + }; + BindTypes['undefined'] == BindTypes.null; + + /** Returns an opaque truthy value from the BindTypes + enum if v's type is a valid bindable type, else + returns a falsy value. */ + const isSupportedBindType = function(v){ + let t = BindTypes[null===v ? 'null' : typeof v]; + if(t) return t; + // TODO: handle buffer/blob types. + return undefined; + } + + /** + If isSupportedBindType(v) returns a truthy value, this + function returns that value, else it throws. + */ + const affirmSupportedBindType = function(v){ + const t = isSupportedBindType(v); + if(t) return t; + toss("Unsupport bind() argument type."); + }; + + /** + If key is a number and within range of stmt's bound parameter + count, key is returned. + + If key is not a number then it is checked against named + parameters. If a match is found, its index is returned. + + Else it throws. + */ + const indexOfParam = function(stmt,key){ + const n = ('number'===typeof key) + ? key : S.sqlite3_bind_parameter_index(stmt.pStmt, key); + if(0===n || (n===key && (n!==(n|0)/*floating point*/))){ + toss("Invalid bind() parameter name: "+key); + } + else if(n>=stmt.columnCount) toss("Bind index",key,"is out of range."); + return n; + }; + + /** + Binds a single bound parameter value on the given stmt at the + given index (numeric or named) using the given bindType (see + the BindTypes enum) and value. Throws on error. Returns stmt on + success. + */ + const bindOne = function(stmt,ndx,bindType,val){ + affirmSupportedBindType(val); + ndx = indexOfParam(stmt,ndx); + let rc = 0; + switch(bindType){ + case BindType.null: + rc = S.sqlite3_bind_null(stmt.pStmt, ndx); + break; + case BindType.string:{ + const bytes = intArrayFromString(string,false); + const pStr = allocate(bytes, ALLOC_NORMAL); + stmt._allocs.push(pStr); + rc = S.sqlite3_bind_text(stmt.pStmt, ndx, pStr, + bytes.length, 0); + break; + } + case BindType.number: { + const m = ((val === (val|0)) + ? (val>0xefffffff + ? S.sqlite3_bind_int64 + : S.sqlite3_bind_int) + : S.sqlite3_bind_double); + rc = m(stmt.pStmt, ndx, val); + break; + } + case BindType.boolean: + rc = S.sqlite3_bind_int(stmt.pStmt, ndx, val ? 1 : 0); + break; + case BindType.blob: + default: toss("Unsupported bind() argument type."); + } + if(rc) stmt.db.checkRc(rc); + return stmt; + }; + + /** Throws if the given Stmt has been finalized, else + it is returned. */ + const affirmStmtOpen = function(stmt){ + if(!stmt.pStmt) toss("Stmt has been closed."); + return stmt; + }; + + /** Frees any memory explicitly allocated for the given + Stmt object. Returns stmt. */ + const freeBindMemory = function(stmt){ + let m; + while(undefined !== (m = stmt._allocs.pop())){ + _free(m); + } + return stmt; + }; + + Stmt.prototype = { + /** + "Finalizes" this statement. This is a no-op if the + statement has already been finalizes. Returns + undefined. Most methods in this class will throw if called + after this is. + */ + finalize: function(){ + if(this.pStmt){ + freeBindMemory(this); + S.sqlite3_finalize(this.pStmt); + delete this.pStmt; + delete this.db; + } + }, + /** Clears all bound values. Returns this object. + Throws if this statement has been finalized. */ + clearBindings: function(){ + freeBindMemory(affirmStmtOpen(this)); + S.sqlite3_clear_bindings(this.pStmt); + return this; + }, + /** + Resets this statement so that it may be step()ed again + from the beginning. Returns this object. Throws if this + statement has been finalized. + + If passed a truthy argument then this.clearBindings() is + also called, otherwise any existing bindings, along with + any memory allocated for them, are retained. + */ + reset: function(alsoClearBinds){ + if(alsoClearBinds) this.clearBindings(); + S.sqlite3_reset(affirmStmtOpen(this).pStmt); + return this; + }, + /** + Binds one or more values to its bindable parameters. It + accepts 1 or 2 arguments: + + If passed a single argument, it must be either an array, an + object, or a value of a bindable type (see below). + + If passed 2 arguments, the first one is the 1-based bind + index or bindable parameter name and the second one must be + a value of a bindable type. + + Bindable value types: + + - null or undefined is bound as NULL. + + - Numbers are bound as either doubles or integers: int64 if + they are larger than 0xEFFFFFFF, else int32. Booleans are + bound as integer 0 or 1. Note that doubles with no + fractional part are bound as integers. It is not expected + that that distinction is significant for the majority of + clients due to sqlite3's data typing model. This API does + not currently support the BigInt type. + + - Strings are bound as strings (use bindAsBlob() to force + blob binding). + + - buffers (blobs) are currently TODO but will be bound as + blobs. + + If passed an array, each element of the array is bound at + the parameter index equal to the array index plus 1 + (because arrays are 0-based but binding is 1-based). + + If passed an object, each object key is treated as a + bindable parameter name. The object keys _must_ match any + bindable parameter names, including any `$`, `@`, or `:` + prefix. Because `$` is a legal identifier chararacter in + JavaScript, that is the suggested prefix for bindable + parameters. + + It returns this object on success and throws on + error. Errors include: + + - Any bind index is out of range or a named bind parameter + does not match. + + - Any value to bind is of an unsupported type. + + - Passed no arguments or more than two. + + - The statement has been finalized. + */ + bind: function(/*[ndx,] value*/){ + let ndx, arg; + switch(arguments.length){ + case 1: ndx = 1; arg = arguments[0]; break; + case 2: ndx = arguments[0]; arg = arguments[1]; break; + default: toss("Invalid bind() arguments."); + } + affirmStmtOpen(this); + if(null===arg || undefined===arg){ + /* bind NULL */ + return bindOne(this, ndx, BindType.null, arg); + } + else if(Array.isArray(arg)){ + /* bind each entry by index */ + if(1!==arguments.length){ + toss("When binding an array, an index argument is not permitted."); + } + arg.forEach((v,i)=>bindOne(this, i+1, affirmSupportedBindType(v), v)); + return this; + } + else if('object'===typeof arg/*null was checked above*/){ + /* bind by name */ + if(1!==arguments.length){ + toss("When binding an object, an index argument is not permitted."); + } + Object.keys(arg) + .forEach(k=>bindOne(this, k, + affirmSupportedBindType(arg[k]), + arg[k])); + return this; + }else{ + return bindOne(this, ndx, + affirmSupportedBindType(arg), arg); + } + toss("Should not reach this point."); + }, + /** + Special case of bind() which binds the given value + using the BLOB binding mechanism instead of the default + selected one for the value. The ndx may be a numbered + or named bind index. The value must be of type string, + buffer, or null/undefined (both treated as null). + + If passed a single argument, a bind index of 1 is assumed. + */ + bindAsBlob: function(ndx,arg){ + affirmStmtOpen(this); + if(1===arguments.length){ + ndx = 1; + arg = arguments[0]; + } + const t = affirmSupportedBindType(arg); + if(BindTypes.string !== t && BindTypes.blob !== t + && BindTypes.null !== t){ + toss("Invalid value type for bindAsBlob()"); + } + return bindOne(this, ndx, BindType.blob, arg); + } + }; + + const SQLite3 = { + version: { + lib: S.sqlite3_libversion(), + ooApi: "0.0.1" + }, + DB + }; + return SQLite3; +}; + +const mainTest1 = function(S/*sqlite3 module*/){ + console.log("Loaded module:",S.sqlite3_libversion(), + S.sqlite3_sourceid()); + const oo = setupAPI(S); + + const db = new oo.DB(); + console.log("DB:",db.filename); +}; + +self/*window or worker*/.Module.onRuntimeInitialized = function(){ + console.log("Loading sqlite3-api.js..."); + self.Module.loadSqliteAPI(mainTest1); +}; diff --git a/manifest b/manifest index 34fda5bf97..54f4e5cb51 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Build\srefactoring\sfor\sthe\sfiddle/wasm\sbits.\sSet\sup\swasm\sbinding\sof\sa\schunk\sof\sthe\score\sC\sAPI\sand\sadded\ssome\sinfastructure\sfor\screating\stest\spages\sfor\sit. -D 2022-05-22T00:27:19.296 +C WASM\sOO\swrapper\s#1:\sprepare()\sand\sbind()\sAPIs\sare\sin\splace\sbut\sare\suntested,\spending\sfetch/get\sAPIs. +D 2022-05-22T14:07:44.577 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -55,8 +55,8 @@ F ext/expert/expert1.test 3c642a4e7bbb14f21ddab595436fb465a4733f47a0fe5b2855e1d5 F ext/expert/sqlite3expert.c 6ca30d73b9ed75bd56d6e0d7f2c962d2affaa72c505458619d0ff5d9cdfac204 F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72 -F ext/fiddle/EXPORTED_FUNCTIONS.fiddle 487fc7c83d45c48326f731c89162ed17ab15767e5efede8999d7d6c6e2d04c0f w ext/fiddle/EXPORTED_FUNCTIONS -F ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 4b06e6c3ce8c8389274079ffb6b441ffff1a55e32a448cf21ce1da45a16c8a01 +F ext/fiddle/EXPORTED_FUNCTIONS.fiddle 487fc7c83d45c48326f731c89162ed17ab15767e5efede8999d7d6c6e2d04c0f +F ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 a3a2862941270ae5e2633d21cbf44979901c4b75efa42a452c15ef879b47ad2b F ext/fiddle/EXPORTED_RUNTIME_METHODS 91d5dcb0168ee056fa1a340cb8ab3c23d922622f8dad39d28919dd8af2b3ade0 F ext/fiddle/Makefile 9277c73e208b9c8093659256c9f07409c877e366480c7c22ec545ee345451d95 F ext/fiddle/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f @@ -64,10 +64,10 @@ F ext/fiddle/fiddle-worker.js c22557b641b47fa1473d3465a4e69fe06b8b09b924955805a4 F ext/fiddle/fiddle.html 657c6c3f860c322fba3c69fa4f7a1209e2d2ce44b4bc65a3e154e3a97c047a7c F ext/fiddle/fiddle.js f9c79164428e96a5909532f18a8bc8f8c8ec4f738bfc09ad3d2a532c2400f9f0 F ext/fiddle/index.md d9c1c308d8074341bc3b11d1d39073cd77754cb3ca9aeb949f23fdd8323d81cf -F ext/fiddle/sqlite3-api.js d3c6da99850e146e50dc42039ac027e5d9b08b9f24eb22b31d1982c49930ee7c +F ext/fiddle/sqlite3-api.js 5f256e3dc78ed0ac4f8556c0c77860812f9baf542b7a73b19b2abb72a6e13146 F ext/fiddle/testing-common.js 37b014758db7e5e74278e37dc712ced2fc9b40d0617f5ed0b8b64a6bd9c0a45d F ext/fiddle/testing1.html 68cec1b1c8646a071717e5979f22e4268e6d36d96ba13ad68333351acdbcf1d1 -F ext/fiddle/testing1.js 0fb900c768b06c2ec3922ab522f721a68b0756d200e3c66602461f45910bcd39 +F ext/fiddle/testing1.js 2e9aa40a17c97ab8e90a8ba942725ebf590ae5db3f0329583d7431e4524f5b11 F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b F ext/fts1/ft_hash.h 06df7bba40dadd19597aa400a875dbc2fed705ea @@ -1967,8 +1967,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P c7cfdd4c3682659352642461d3307bf8180703b121ec1802ba5881f8e1ef9809 -R d89e623e1614875df0e3a579152a2be9 +P dea098b64eb95c395b346ebcae687afe42b7d21df48833527808c02226300a66 +R d6777acddc9dd48a02f29eb36eccd673 U stephan -Z fd89698a5fe01334529b2fb407d595a1 +Z ec1032561dde0c5db030c66f88c029fe # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index a0a10eb4c2..8691610d23 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -dea098b64eb95c395b346ebcae687afe42b7d21df48833527808c02226300a66 \ No newline at end of file +84c8f63a1c446331a3afe52b0c8bdfa6980f24aa4cf600f576877fef5e650c39 \ No newline at end of file From 40b5b19a0ffaac4063df6fbf56c3854e3ce8ac72 Mon Sep 17 00:00:00 2001 From: stephan Date: Sun, 22 May 2022 16:25:43 +0000 Subject: [PATCH 067/108] WASM: added bindings for sqlite3_compileoption_get/used(), moved OO #1 into sqlite3-api.js since it can only be used from the same thread as that API and separating them complicates client-side use. Started adding test utilities and tests for the OO1 API. FossilOrigin-Name: f3bc0328c87cac7d50513b0f13576d8fe7b411396f19c08fbe7e7c657b33cfbf --- ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 | 3 + ext/fiddle/sqlite3-api.js | 494 +++++++++++++++++++++++++- ext/fiddle/testing-common.js | 63 +++- ext/fiddle/testing1.js | 394 ++------------------ manifest | 18 +- manifest.uuid | 2 +- 6 files changed, 575 insertions(+), 399 deletions(-) diff --git a/ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 b/ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 index 09f6e8ba79..e6b57420c2 100644 --- a/ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 +++ b/ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 @@ -3,6 +3,7 @@ _sqlite3_bind_double _sqlite3_bind_int _sqlite3_bind_int64 _sqlite3_bind_null +_sqlite3_bind_parameter_count _sqlite3_bind_parameter_index _sqlite3_bind_text _sqlite3_changes @@ -16,6 +17,8 @@ _sqlite3_column_double _sqlite3_column_name _sqlite3_column_text _sqlite3_column_type +_sqlite3_compileoption_get +_sqlite3_compileoption_used _sqlite3_create_function_v2 _sqlite3_data_count _sqlite3_db_filename diff --git a/ext/fiddle/sqlite3-api.js b/ext/fiddle/sqlite3-api.js index 83e46bbcaf..0c24085784 100644 --- a/ext/fiddle/sqlite3-api.js +++ b/ext/fiddle/sqlite3-api.js @@ -10,21 +10,31 @@ *********************************************************************** - This file is intended to be loaded after loading - sqlite3-module.wasm. It sets one of any number of potential - bindings using that API, this one as closely matching the C-native - API as is feasible. + This file is intended to be loaded after loading sqlite3.wasm. It + sets one of any number of potential bindings using that API, this + one as closely matching the C-native API as is feasible. Note that this file is not named sqlite3.js because that file gets generated by emscripten as the JS-glue counterpart of sqlite3.wasm. The API gets installed as self.sqlite3, where self is expected to be - either the global window or Worker object. + either the global window or Worker object. In addition, a higher-level + OO API is installed as self.SQLite3. - Because using this API properly requires some degree of WASM-related - magic, it is not recommended that this API be used as-is in - client-level code, but instead is intended to be used as a basis for - APIs more appropriate for high-level client code. + Potential TODO: instead of exporting 2 symbols, export only SQLite3 + as {api: sqlite3, oo1: SQLite3}. The way we export this module is + not _really_ modern-JS-friendly because it exports global symbols + (which is admittedly poor form). Exporting it "cleanly" requires + using a module loader in all client code. As there are several + different approaches, none of which this developer is currently + truly familiar with, the current approach will have to do for the + time being. + + Because using the low-level API properly requires some degree of + WASM-related magic, it is not recommended that that API be used + as-is in client-level code. Rather, client code should use the + higher-level OO API or write such a wrapper on top of the + lower-level API. This file installs namespace.sqlite3, where namespace is `self`, meaning either the global window or worker, depending on where this @@ -74,8 +84,23 @@ /* It is important that the following integer values match those from the C code. Ideally we could fetch them from the C API, e.g., in the form of a JSON object, but getting that - JSON string constructed within our current confised is - currently not worth the effort. */ + JSON string constructed within our current confines is + currently not worth the effort. + + Reminder to self: we could probably do so by adding the + proverbial level of indirection, calling in to C to get it, + and having that C func call an + emscripten-installed/JS-implemented library function which + builds the result object: + + const obj = {}; + sqlite3__get_enum(function(key,val){ + obj[key] = val; + }); + + but whether or not we can pass a function that way, via a + (void*) is as yet unknown. + */ /* Minimum subset of sqlite result codes we'll need. */ SQLITE_OK: 0, SQLITE_ROW: 100, @@ -108,6 +133,7 @@ ["sqlite3_bind_int","number",["number", "number", "number"]], ["sqlite3_bind_int64","number",["number", "number", "number"]], ["sqlite3_bind_null","void",["number"]], + ["sqlite3_bind_parameter_count", "number", ["number"]], ["sqlite3_bind_parameter_index","number",["number", "string"]], ["sqlite3_bind_text","number",["number", "number", "number", "number", "number"]], ["sqlite3_changes", "number", ["number"]], @@ -121,6 +147,8 @@ ["sqlite3_column_name","string",["number", "number"]], ["sqlite3_column_text","string",["number", "number"]], ["sqlite3_column_type","number",["number", "number"]], + ["sqlite3_compileoption_get", "string", ["number"]], + ["sqlite3_compileoption_used", "number", ["string"]], ["sqlite3_create_function_v2", "number", ["number", "string", "number", "number","number", "number", "number", "number", "number"]], @@ -162,5 +190,447 @@ api[k] = cwrap.apply(this, a); }); //console.debug("libversion =",api.sqlite3_libversion()); - namespace.sqlite3 = api; + + /* What follows is colloquially known as "OO API #1". It is a + binding of the sqlite3 API which is designed to be run within + the same thread (main or worker) as the one in which the + sqlite3 WASM binding was initialized. This wrapper cannot use + the sqlite3 binding if, e.g., the wrapper is in the main thread + and the sqlite3 API is in a worker. */ + /* memory for use in some pointer-passing routines */ + const pPtrArg = stackAlloc(4); + const toss = function(){ + throw new Error(Array.prototype.join.call(arguments, ' ')); + }; + + const sqlite3/*canonical name*/ = S/*convenience alias*/ = api; + + /** + The DB class wraps a sqlite3 db handle. + */ + const DB = function(name/*TODO: openMode flags*/){ + if(!name) name = ':memory:'; + else if('string'!==typeof name){ + toss("TODO: support blob image of db here."); + } + this.checkRc(S.sqlite3_open(name, pPtrArg)); + this.pDb = getValue(pPtrArg, "i32"); + this.filename = name; + this._statements = {/*map of open Stmt _pointers_*/}; + }; + + /** + Internal-use enum for mapping JS types to DB-bindable types. + These do not (and need not) line up with the SQLITE_type + values. All values in this enum must be truthy and distinct + but they need not be numbers. + */ + const BindTypes = { + null: 1, + number: 2, + string: 3, + boolean: 4, + blob: 5 + }; + BindTypes['undefined'] == BindTypes.null; + + /** + This class wraps sqlite3_stmt. Calling this constructor + directly will trigger an exception. Use DB.prepare() to create + new instances. + */ + const Stmt = function(){ + if(BindTypes!=arguments[2]){ + toss("Do not call the Stmt constructor directly. Use DB.prepare()."); + } + this.db = arguments[0]; + this.pStmt = arguments[1]; + this.columnCount = S.sqlite3_column_count(this.pStmt); + this.parameterCount = S.sqlite3_bind_parameter_count(this.pStmt); + this._allocs = [/*list of alloc'd memory blocks for bind() values*/] + }; + + /** Throws if the given DB has been closed, else it is returned. */ + const affirmDbOpen = function(db){ + if(!db.pDb) toss("DB has been closed."); + return db; + }; + + DB.prototype = { + /** + Expects to be given an sqlite3 API result code. If it is + falsy, this function returns this object, else it throws an + exception with an error message from sqlite3_errmsg(), + using this object's db handle. + */ + checkRc: function(sqliteResultCode){ + if(!sqliteResultCode) return this; + toss(S.sqlite3_errmsg(this.pDb) || "Unknown db error."); + }, + /** + Finalizes all open statements and closes this database + connection. This is a no-op if the db has already been + closed. + */ + close: function(){ + if(this.pDb){ + let s; + const that = this; + Object.keys(this._statements).forEach(function(k,s){ + delete that._statements[k]; + if(s && s.pStmt) s.finalize(); + }); + S.sqlite3_close_v2(this.pDb); + delete this.pDb; + } + }, + /** + Similar to this.filename but will return NULL for + special names like ":memory:". Not of much use until + we have filesystem support. Throws if the DB has + been closed. If passed an argument it then it will return + the filename of the ATTACHEd db with that name, else it assumes + a name of `main`. + */ + fileName: function(dbName){ + return S.sqlite3_db_filename(affirmDbOpen(this).pDb, dbName||"main"); + }, + /** + Compiles the given SQL and returns a prepared Stmt. This is + the only way to create new Stmt objects. Throws on error. + */ + prepare: function(sql){ + affirmDbOpen(this); + setValue(pPtrArg,0,"i32"); + this.checkRc(S.sqlite3_prepare_v2(this.pDb, sql, -1, pPtrArg, null)); + const pStmt = getValue(pPtrArg, "i32"); + if(!pStmt) toss("Empty SQL is not permitted."); + const stmt = new Stmt(this, pStmt, BindTypes); + this._statements[pStmt] = stmt; + return stmt; + } + }; + + /** Returns an opaque truthy value from the BindTypes + enum if v's type is a valid bindable type, else + returns a falsy value. */ + const isSupportedBindType = function(v){ + let t = BindTypes[null===v ? 'null' : typeof v]; + if(t) return t; + // TODO: handle buffer/blob types. + return undefined; + } + + /** + If isSupportedBindType(v) returns a truthy value, this + function returns that value, else it throws. + */ + const affirmSupportedBindType = function(v){ + const t = isSupportedBindType(v); + if(t) return t; + toss("Unsupport bind() argument type."); + }; + + /** + If key is a number and within range of stmt's bound parameter + count, key is returned. + + If key is not a number then it is checked against named + parameters. If a match is found, its index is returned. + + Else it throws. + */ + const indexOfParam = function(stmt,key){ + const n = ('number'===typeof key) + ? key : S.sqlite3_bind_parameter_index(stmt.pStmt, key); + if(0===n || (n===key && (n!==(n|0)/*floating point*/))){ + toss("Invalid bind() parameter name: "+key); + } + else if(n<1 || n>=stmt.parameterCount) toss("Bind index",key,"is out of range."); + return n; + }; + + /** + Binds a single bound parameter value on the given stmt at the + given index (numeric or named) using the given bindType (see + the BindTypes enum) and value. Throws on error. Returns stmt on + success. + */ + const bindOne = function(stmt,ndx,bindType,val){ + affirmSupportedBindType(val); + ndx = indexOfParam(stmt,ndx); + let rc = 0; + switch(bindType){ + case BindType.null: + rc = S.sqlite3_bind_null(stmt.pStmt, ndx); + break; + case BindType.string:{ + const bytes = intArrayFromString(string,false); + const pStr = allocate(bytes, ALLOC_NORMAL); + stmt._allocs.push(pStr); + rc = S.sqlite3_bind_text(stmt.pStmt, ndx, pStr, + bytes.length, 0); + break; + } + case BindType.number: { + const m = ((val === (val|0)) + ? (val>0xefffffff + ? S.sqlite3_bind_int64 + : S.sqlite3_bind_int) + : S.sqlite3_bind_double); + rc = m(stmt.pStmt, ndx, val); + break; + } + case BindType.boolean: + rc = S.sqlite3_bind_int(stmt.pStmt, ndx, val ? 1 : 0); + break; + case BindType.blob: + default: toss("Unsupported bind() argument type."); + } + if(rc) stmt.db.checkRc(rc); + return stmt; + }; + + /** Throws if the given Stmt has been finalized, else + it is returned. */ + const affirmStmtOpen = function(stmt){ + if(!stmt.pStmt) toss("Stmt has been closed."); + return stmt; + }; + + /** Frees any memory explicitly allocated for the given + Stmt object. Returns stmt. */ + const freeBindMemory = function(stmt){ + let m; + while(undefined !== (m = stmt._allocs.pop())){ + _free(m); + } + return stmt; + }; + + Stmt.prototype = { + /** + "Finalizes" this statement. This is a no-op if the + statement has already been finalizes. Returns + undefined. Most methods in this class will throw if called + after this is. + */ + finalize: function(){ + if(this.pStmt){ + freeBindMemory(this); + delete this.db._statements[this.pStmt]; + S.sqlite3_finalize(this.pStmt); + delete this.pStmt; + delete this.db; + } + }, + /** Clears all bound values. Returns this object. + Throws if this statement has been finalized. */ + clearBindings: function(){ + freeBindMemory(affirmStmtOpen(this)); + S.sqlite3_clear_bindings(this.pStmt); + return this; + }, + /** + Resets this statement so that it may be step()ed again + from the beginning. Returns this object. Throws if this + statement has been finalized. + + If passed a truthy argument then this.clearBindings() is + also called, otherwise any existing bindings, along with + any memory allocated for them, are retained. + */ + reset: function(alsoClearBinds){ + if(alsoClearBinds) this.clearBindings(); + S.sqlite3_reset(affirmStmtOpen(this).pStmt); + return this; + }, + /** + Binds one or more values to its bindable parameters. It + accepts 1 or 2 arguments: + + If passed a single argument, it must be either an array, an + object, or a value of a bindable type (see below). + + If passed 2 arguments, the first one is the 1-based bind + index or bindable parameter name and the second one must be + a value of a bindable type. + + Bindable value types: + + - null or undefined is bound as NULL. + + - Numbers are bound as either doubles or integers: int64 if + they are larger than 0xEFFFFFFF, else int32. Booleans are + bound as integer 0 or 1. Note that doubles with no + fractional part are bound as integers. It is not expected + that that distinction is significant for the majority of + clients due to sqlite3's data typing model. This API does + not currently support the BigInt type. + + - Strings are bound as strings (use bindAsBlob() to force + blob binding). + + - buffers (blobs) are currently TODO but will be bound as + blobs. + + If passed an array, each element of the array is bound at + the parameter index equal to the array index plus 1 + (because arrays are 0-based but binding is 1-based). + + If passed an object, each object key is treated as a + bindable parameter name. The object keys _must_ match any + bindable parameter names, including any `$`, `@`, or `:` + prefix. Because `$` is a legal identifier chararacter in + JavaScript, that is the suggested prefix for bindable + parameters. + + It returns this object on success and throws on + error. Errors include: + + - Any bind index is out of range, a named bind parameter + does not match, or this statement has no bindable + parameters. + + - Any value to bind is of an unsupported type. + + - Passed no arguments or more than two. + + - The statement has been finalized. + */ + bind: function(/*[ndx,] value*/){ + if(!this.parameterCount){ + toss("This statement has no bindable parameters."); + } + let ndx, arg; + switch(arguments.length){ + case 1: ndx = 1; arg = arguments[0]; break; + case 2: ndx = arguments[0]; arg = arguments[1]; break; + default: toss("Invalid bind() arguments."); + } + affirmStmtOpen(this); + if(null===arg || undefined===arg){ + /* bind NULL */ + return bindOne(this, ndx, BindType.null, arg); + } + else if(Array.isArray(arg)){ + /* bind each entry by index */ + if(1!==arguments.length){ + toss("When binding an array, an index argument is not permitted."); + } + arg.forEach((v,i)=>bindOne(this, i+1, affirmSupportedBindType(v), v)); + return this; + } + else if('object'===typeof arg/*null was checked above*/){ + /* bind by name */ + if(1!==arguments.length){ + toss("When binding an object, an index argument is not permitted."); + } + Object.keys(arg) + .forEach(k=>bindOne(this, k, + affirmSupportedBindType(arg[k]), + arg[k])); + return this; + }else{ + return bindOne(this, ndx, + affirmSupportedBindType(arg), arg); + } + toss("Should not reach this point."); + }, + /** + Special case of bind() which binds the given value + using the BLOB binding mechanism instead of the default + selected one for the value. The ndx may be a numbered + or named bind index. The value must be of type string, + buffer, or null/undefined (both treated as null). + + If passed a single argument, a bind index of 1 is assumed. + */ + bindAsBlob: function(ndx,arg){ + affirmStmtOpen(this); + if(1===arguments.length){ + ndx = 1; + arg = arguments[0]; + } + const t = affirmSupportedBindType(arg); + if(BindTypes.string !== t && BindTypes.blob !== t + && BindTypes.null !== t){ + toss("Invalid value type for bindAsBlob()"); + } + return bindOne(this, ndx, BindType.blob, arg); + } + }; + + /** OO binding's namespace. */ + const SQLite3 = { + version: { + lib: sqlite3.sqlite3_libversion(), + ooApi: "0.0.1" + }, + DB, + Stmt, + /** + Reports whether a given compile-time option, named by the + given argument. + + If optName is an array then it is expected to be a list of + compilation options and this function returns an object + which maps each such option to true or false. That object + is returned. + + If optName is an object, its keys are expected to be + compilation options and this function sets each entry to + true or false. That object is returned. + + If passed no arguments then it returns an object mapping + all known compilation options to their compile-time values, + or true if the are defined with no value. + + In all other cases it returns true if the option was active + when when compiling the sqlite3 module, else false. + + Compile-time option names may optionally include their + "SQLITE_" prefix. When it returns an object of all options, + the prefix is elided. + */ + compileOptionUsed: function f(optName){ + if(!arguments.length){ + if(!f._opt){ + f._rx = /^([^=]+)=(.+)/; + f._rxInt = /^-?\d+/; + f._opt = function(opt, rv){ + const m = f._rx.exec(opt); + rv[0] = (m ? m[1] : opt); + rv[1] = m ? (f._rxInt.test(m[2]) ? +m[2] : m[2]) : true; + }; + } + const rc = {}, ov = [0,0]; + let i = 0; + while((k = S.sqlite3_compileoption_get(i++))){ + f._opt(k,ov); + rc[ov[0]] = ov[1]; + } + return rc; + } + else if(Array.isArray(optName)){ + const rc = {}; + optName.forEach((v)=>{ + rc[v] = S.sqlite3_compileoption_used(v); + }); + return rc; + } + else if('object' === typeof optName){ + Object.keys(optName).forEach((k)=> { + optName[k] = S.sqlite3_compileoption_used(k); + }); + return optName; + } + return ( + 'string'===typeof optName + ) ? !!S.sqlite3_compileoption_used(optName) : false; + } + }; + + namespace.sqlite3 = sqlite3; + namespace.SQLite3 = SQLite3; })(self/*worker or window*/); diff --git a/ext/fiddle/testing-common.js b/ext/fiddle/testing-common.js index 2fe9a860ba..762ce58668 100644 --- a/ext/fiddle/testing-common.js +++ b/ext/fiddle/testing-common.js @@ -28,7 +28,6 @@ const statusElement = E('#module-status'); const progressElement = E('#module-progress'); const spinnerElement = E('#module-spinner'); - self.Module = { /* ^^^ cannot declare that const because fiddle-module.js (auto-generated) includes a decl for it and runs in this scope. */ @@ -71,9 +70,10 @@ : 'All downloads complete.'); }, /* Loads sqlite3-api.js and calls the given callback (if - provided), passing it the sqlite3 module. Whether this is - synchronous or async depends on whether it's run in the - main thread or a worker.*/ + provided), passing it an object which contains the sqlite3 + and SQLite3 modules. Whether this is synchronous or async + depends on whether it's run in the main thread or a + worker.*/ loadSqliteAPI: function(callback){ const theScript = 'sqlite3-api.js'; if(self.importScripts){/*worker*/ @@ -88,9 +88,62 @@ script.async = true; script.src = theScript; }).then(() => { - if(callback) callback(self.sqlite3); + if(callback) callback({sqlite3:self.sqlite3, + SQLite3:self.SQLite3}); }); } } }; + + const _expr = function(expr){ + return (expr instanceof Function) ? expr() : !!expr; + }; + + /** + Helpers for writing sqlite3-specific tests. + */ + self.SqliteTester = { + /** Running total of the number of tests run via + this API. */ + counter: 0, + /** abort() if expr is false. If expr is a function, it + is called and its result is evaluated. + */ + assert: function(expr, msg){ + ++this.counter; + if(!_expr(expr)) abort(msg || "Assertion failed."); + return this; + }, + /** Identical to assert() but throws instead of calling + abort(). */ + affirm: function(expr, msg){ + ++this.counter; + if(!_expr(expr)) throw new Error(msg || "Affirmation failed."); + return this; + }, + /** Calls f() and squelches any exception it throws. If it + does not throw, this function throws. */ + mustThrow: function(f, msg){ + ++this.counter; + let err; + try{ f(); } catch(e){err=e;} + if(!err) throw new Error(msg || "Expected exception."); + return this; + }, + /** Throws if expr is truthy or expr is a function and expr() + returns truthy. */ + throwIf: function(expr, msg){ + ++this.counter; + if(_expr(expr)) throw new Error(msg || "throwIf() failed"); + return this; + }, + /** Throws if expr is falsy or expr is a function and expr() + returns falsy. */ + throwUnless: function(expr, msg){ + ++this.counter; + if(!_expr(expr)) throw new Error(msg || "throwUnless() failed"); + return this; + } + }; + })(self/*window or worker*/); diff --git a/ext/fiddle/testing1.js b/ext/fiddle/testing1.js index a24d63f105..6e79be0257 100644 --- a/ext/fiddle/testing1.js +++ b/ext/fiddle/testing1.js @@ -12,382 +12,32 @@ A basic test script for sqlite3-api.js. */ -const setupAPI = function(S/*sqlite3 module*/){ - /* memory for use in some pointer-passing routines */ - const pPtrArg = stackAlloc(4); - const dummyArg = {/*for restricting Stmt constructor to internal use*/}; - const toss = function(){ - throw new Error(Array.prototype.join.apply(arguments, ' ')); - }; - - /** - The DB class wraps a sqlite3 db handle. - */ - const DB = function(name/*TODO: openMode flags*/){ - if(!name) name = ':memory:'; - else if('string'!==typeof name){ - toss("TODO: support blob image of db here."); - } - this.checkRc(S.sqlite3_open(name, pPtrArg)); - this.pDb = getValue(pPtrArg, "i32"); - this.filename = name; - this._statements = {/*array of open Stmt _pointers_*/}; - }; - - /** - This class wraps sqlite3_stmt. Calling this constructor - directly will trigger an exception. Use DB.prepare() to create - new instances. - */ - const Stmt = function(){ - if(dummyArg!=arguments[2]){ - toss("Do not call the Stmt constructor directly. Use DB.prepare()."); - } - this.db = arguments[0]; - this.pStmt = arguments[1]; - this.columnCount = S.sqlite3_column_count(this.pStmt); - this._allocs = [/*list of alloc'd memory blocks for bind() values*/] - }; - - - /** Throws if the given DB has been closed, else it is returned. */ - const affirmDbOpen = function(db){ - if(!db.pDb) toss("DB has been closed."); - return db; - }; - - DB.prototype = { - /** - Expects to be given an sqlite3 API result code. If it is - falsy, this function returns this object, else it throws an - exception with an error message from sqlite3_errmsg(), - using this object's db handle. - */ - checkRc: function(sqliteResultCode){ - if(!sqliteResultCode) return this; - toss(S.sqlite3_errmsg(this.pDb) || "Unknown db error."); - }, - /** - Finalizes all open statements and closes this database - connection. This is a no-op if the db has already been - closed. - */ - close: function(){ - if(this.pDb){ - let s; - while(undefined!==(s = this._statements.pop())){ - if(s.pStmt) s.finalize(); - } - S.sqlite3_close_v2(this.pDb); - delete this.pDb; - } - }, - /** - Similar to this.filename but will return NULL for - special names like ":memory:". Not of much use until - we have filesystem support. Throws if the DB has - been closed. If passed an argument it then it will return - the filename of the ATTACHEd db with that name, else it assumes - a name of `main`. - */ - fileName: function(dbName){ - return S.sqlite3_db_filename(affirmDbOpen(this).pDb, dbName||"main"); - }, - - /** - Compiles the given SQL and returns a prepared Stmt. This is - the only way to create new Stmt objects. Throws on error. - */ - prepare: function(sql){ - affirmDbOpen(this); - setValue(pPtrArg,0,"i32"); - this.checkRc(S.sqlite3_prepare_v2(this.pDb, sql, -1, pPtrArg, null)); - const pStmt = getValue(pPtrArg, "i32"); - if(!pStmt) toss("Empty SQL is not permitted."); - const stmt = new Stmt(this, pStmt, dummyArg); - this._statements[pStmt] = stmt; - return stmt; - } - }; - - /** - Internal-use enum for mapping JS types to DB-bindable types. - These do not (and need not) line up with the SQLITE_type - values. All values in this enum must be truthy and distinct - but they need not be numbers. - */ - const BindTypes = { - null: 1, - number: 2, - string: 3, - boolean: 4, - blob: 5 - }; - BindTypes['undefined'] == BindTypes.null; - - /** Returns an opaque truthy value from the BindTypes - enum if v's type is a valid bindable type, else - returns a falsy value. */ - const isSupportedBindType = function(v){ - let t = BindTypes[null===v ? 'null' : typeof v]; - if(t) return t; - // TODO: handle buffer/blob types. - return undefined; - } - - /** - If isSupportedBindType(v) returns a truthy value, this - function returns that value, else it throws. - */ - const affirmSupportedBindType = function(v){ - const t = isSupportedBindType(v); - if(t) return t; - toss("Unsupport bind() argument type."); - }; - - /** - If key is a number and within range of stmt's bound parameter - count, key is returned. - - If key is not a number then it is checked against named - parameters. If a match is found, its index is returned. - - Else it throws. - */ - const indexOfParam = function(stmt,key){ - const n = ('number'===typeof key) - ? key : S.sqlite3_bind_parameter_index(stmt.pStmt, key); - if(0===n || (n===key && (n!==(n|0)/*floating point*/))){ - toss("Invalid bind() parameter name: "+key); - } - else if(n>=stmt.columnCount) toss("Bind index",key,"is out of range."); - return n; - }; - - /** - Binds a single bound parameter value on the given stmt at the - given index (numeric or named) using the given bindType (see - the BindTypes enum) and value. Throws on error. Returns stmt on - success. - */ - const bindOne = function(stmt,ndx,bindType,val){ - affirmSupportedBindType(val); - ndx = indexOfParam(stmt,ndx); - let rc = 0; - switch(bindType){ - case BindType.null: - rc = S.sqlite3_bind_null(stmt.pStmt, ndx); - break; - case BindType.string:{ - const bytes = intArrayFromString(string,false); - const pStr = allocate(bytes, ALLOC_NORMAL); - stmt._allocs.push(pStr); - rc = S.sqlite3_bind_text(stmt.pStmt, ndx, pStr, - bytes.length, 0); - break; - } - case BindType.number: { - const m = ((val === (val|0)) - ? (val>0xefffffff - ? S.sqlite3_bind_int64 - : S.sqlite3_bind_int) - : S.sqlite3_bind_double); - rc = m(stmt.pStmt, ndx, val); - break; - } - case BindType.boolean: - rc = S.sqlite3_bind_int(stmt.pStmt, ndx, val ? 1 : 0); - break; - case BindType.blob: - default: toss("Unsupported bind() argument type."); - } - if(rc) stmt.db.checkRc(rc); - return stmt; - }; - - /** Throws if the given Stmt has been finalized, else - it is returned. */ - const affirmStmtOpen = function(stmt){ - if(!stmt.pStmt) toss("Stmt has been closed."); - return stmt; - }; - - /** Frees any memory explicitly allocated for the given - Stmt object. Returns stmt. */ - const freeBindMemory = function(stmt){ - let m; - while(undefined !== (m = stmt._allocs.pop())){ - _free(m); - } - return stmt; - }; - - Stmt.prototype = { - /** - "Finalizes" this statement. This is a no-op if the - statement has already been finalizes. Returns - undefined. Most methods in this class will throw if called - after this is. - */ - finalize: function(){ - if(this.pStmt){ - freeBindMemory(this); - S.sqlite3_finalize(this.pStmt); - delete this.pStmt; - delete this.db; - } - }, - /** Clears all bound values. Returns this object. - Throws if this statement has been finalized. */ - clearBindings: function(){ - freeBindMemory(affirmStmtOpen(this)); - S.sqlite3_clear_bindings(this.pStmt); - return this; - }, - /** - Resets this statement so that it may be step()ed again - from the beginning. Returns this object. Throws if this - statement has been finalized. - - If passed a truthy argument then this.clearBindings() is - also called, otherwise any existing bindings, along with - any memory allocated for them, are retained. - */ - reset: function(alsoClearBinds){ - if(alsoClearBinds) this.clearBindings(); - S.sqlite3_reset(affirmStmtOpen(this).pStmt); - return this; - }, - /** - Binds one or more values to its bindable parameters. It - accepts 1 or 2 arguments: - - If passed a single argument, it must be either an array, an - object, or a value of a bindable type (see below). - - If passed 2 arguments, the first one is the 1-based bind - index or bindable parameter name and the second one must be - a value of a bindable type. - - Bindable value types: - - - null or undefined is bound as NULL. - - - Numbers are bound as either doubles or integers: int64 if - they are larger than 0xEFFFFFFF, else int32. Booleans are - bound as integer 0 or 1. Note that doubles with no - fractional part are bound as integers. It is not expected - that that distinction is significant for the majority of - clients due to sqlite3's data typing model. This API does - not currently support the BigInt type. - - - Strings are bound as strings (use bindAsBlob() to force - blob binding). - - - buffers (blobs) are currently TODO but will be bound as - blobs. - - If passed an array, each element of the array is bound at - the parameter index equal to the array index plus 1 - (because arrays are 0-based but binding is 1-based). - - If passed an object, each object key is treated as a - bindable parameter name. The object keys _must_ match any - bindable parameter names, including any `$`, `@`, or `:` - prefix. Because `$` is a legal identifier chararacter in - JavaScript, that is the suggested prefix for bindable - parameters. - - It returns this object on success and throws on - error. Errors include: - - - Any bind index is out of range or a named bind parameter - does not match. - - - Any value to bind is of an unsupported type. - - - Passed no arguments or more than two. - - - The statement has been finalized. - */ - bind: function(/*[ndx,] value*/){ - let ndx, arg; - switch(arguments.length){ - case 1: ndx = 1; arg = arguments[0]; break; - case 2: ndx = arguments[0]; arg = arguments[1]; break; - default: toss("Invalid bind() arguments."); - } - affirmStmtOpen(this); - if(null===arg || undefined===arg){ - /* bind NULL */ - return bindOne(this, ndx, BindType.null, arg); - } - else if(Array.isArray(arg)){ - /* bind each entry by index */ - if(1!==arguments.length){ - toss("When binding an array, an index argument is not permitted."); - } - arg.forEach((v,i)=>bindOne(this, i+1, affirmSupportedBindType(v), v)); - return this; - } - else if('object'===typeof arg/*null was checked above*/){ - /* bind by name */ - if(1!==arguments.length){ - toss("When binding an object, an index argument is not permitted."); - } - Object.keys(arg) - .forEach(k=>bindOne(this, k, - affirmSupportedBindType(arg[k]), - arg[k])); - return this; - }else{ - return bindOne(this, ndx, - affirmSupportedBindType(arg), arg); - } - toss("Should not reach this point."); - }, - /** - Special case of bind() which binds the given value - using the BLOB binding mechanism instead of the default - selected one for the value. The ndx may be a numbered - or named bind index. The value must be of type string, - buffer, or null/undefined (both treated as null). - - If passed a single argument, a bind index of 1 is assumed. - */ - bindAsBlob: function(ndx,arg){ - affirmStmtOpen(this); - if(1===arguments.length){ - ndx = 1; - arg = arguments[0]; - } - const t = affirmSupportedBindType(arg); - if(BindTypes.string !== t && BindTypes.blob !== t - && BindTypes.null !== t){ - toss("Invalid value type for bindAsBlob()"); - } - return bindOne(this, ndx, BindType.blob, arg); - } - }; - - const SQLite3 = { - version: { - lib: S.sqlite3_libversion(), - ooApi: "0.0.1" - }, - DB - }; - return SQLite3; -}; - -const mainTest1 = function(S/*sqlite3 module*/){ +const mainTest1 = function(namespace){ + const S = namespace.sqlite3; + const oo = namespace.SQLite3; + const T = self.SqliteTester; console.log("Loaded module:",S.sqlite3_libversion(), S.sqlite3_sourceid()); - const oo = setupAPI(S); - const db = new oo.DB(); - console.log("DB:",db.filename); + const log = console.log.bind(console); + T.assert(db.pDb); + log("DB:",db.filename); + log("Build options:",oo.compileOptionUsed()); + + let st = db.prepare("select 1"); + T.assert(st.pStmt); + log("statement =",st); + T.assert(st === db._statements[st.pStmt]) + .assert(1===st.columnCount) + .assert(0===st.parameterCount) + .mustThrow(()=>st.bind(1,null)); + + let pId = st.pStmt; + st.finalize(); + T.assert(!st.pStmt) + .assert(!db._statements[pId]); + log("Test count:",T.counter); }; self/*window or worker*/.Module.onRuntimeInitialized = function(){ diff --git a/manifest b/manifest index 54f4e5cb51..36dce9f18d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C WASM\sOO\swrapper\s#1:\sprepare()\sand\sbind()\sAPIs\sare\sin\splace\sbut\sare\suntested,\spending\sfetch/get\sAPIs. -D 2022-05-22T14:07:44.577 +C WASM:\sadded\sbindings\sfor\ssqlite3_compileoption_get/used(),\smoved\sOO\s#1\sinto\ssqlite3-api.js\ssince\sit\scan\sonly\sbe\sused\sfrom\sthe\ssame\sthread\sas\sthat\sAPI\sand\sseparating\sthem\scomplicates\sclient-side\suse.\sStarted\sadding\stest\sutilities\sand\stests\sfor\sthe\sOO1\sAPI. +D 2022-05-22T16:25:43.076 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -56,7 +56,7 @@ F ext/expert/sqlite3expert.c 6ca30d73b9ed75bd56d6e0d7f2c962d2affaa72c505458619d0 F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72 F ext/fiddle/EXPORTED_FUNCTIONS.fiddle 487fc7c83d45c48326f731c89162ed17ab15767e5efede8999d7d6c6e2d04c0f -F ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 a3a2862941270ae5e2633d21cbf44979901c4b75efa42a452c15ef879b47ad2b +F ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 00553766051a038b1acd3992d04e50540d1284c3ea78bd11daa521383e57d653 F ext/fiddle/EXPORTED_RUNTIME_METHODS 91d5dcb0168ee056fa1a340cb8ab3c23d922622f8dad39d28919dd8af2b3ade0 F ext/fiddle/Makefile 9277c73e208b9c8093659256c9f07409c877e366480c7c22ec545ee345451d95 F ext/fiddle/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f @@ -64,10 +64,10 @@ F ext/fiddle/fiddle-worker.js c22557b641b47fa1473d3465a4e69fe06b8b09b924955805a4 F ext/fiddle/fiddle.html 657c6c3f860c322fba3c69fa4f7a1209e2d2ce44b4bc65a3e154e3a97c047a7c F ext/fiddle/fiddle.js f9c79164428e96a5909532f18a8bc8f8c8ec4f738bfc09ad3d2a532c2400f9f0 F ext/fiddle/index.md d9c1c308d8074341bc3b11d1d39073cd77754cb3ca9aeb949f23fdd8323d81cf -F ext/fiddle/sqlite3-api.js 5f256e3dc78ed0ac4f8556c0c77860812f9baf542b7a73b19b2abb72a6e13146 -F ext/fiddle/testing-common.js 37b014758db7e5e74278e37dc712ced2fc9b40d0617f5ed0b8b64a6bd9c0a45d +F ext/fiddle/sqlite3-api.js ab7e7ded7b3079ee7de43e8290f1942e757d90ebb47ae4654cfe03c980cd0cad +F ext/fiddle/testing-common.js 2b2826a1e7c8ca3e610dfa4255ff1077438b6570e08096cc139c226811e60dbb F ext/fiddle/testing1.html 68cec1b1c8646a071717e5979f22e4268e6d36d96ba13ad68333351acdbcf1d1 -F ext/fiddle/testing1.js 2e9aa40a17c97ab8e90a8ba942725ebf590ae5db3f0329583d7431e4524f5b11 +F ext/fiddle/testing1.js 6a314a10efc954bcd854af89d53ab768f48a42d3dcb80773b297f4ba0ac0236d F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b F ext/fts1/ft_hash.h 06df7bba40dadd19597aa400a875dbc2fed705ea @@ -1967,8 +1967,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P dea098b64eb95c395b346ebcae687afe42b7d21df48833527808c02226300a66 -R d6777acddc9dd48a02f29eb36eccd673 +P 84c8f63a1c446331a3afe52b0c8bdfa6980f24aa4cf600f576877fef5e650c39 +R d3343607f5b0d8f2cee2f7485f266550 U stephan -Z ec1032561dde0c5db030c66f88c029fe +Z 4ea03d4418e5522f96fc7a3cf30bf26a # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 8691610d23..47aa878ffb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -84c8f63a1c446331a3afe52b0c8bdfa6980f24aa4cf600f576877fef5e650c39 \ No newline at end of file +f3bc0328c87cac7d50513b0f13576d8fe7b411396f19c08fbe7e7c657b33cfbf \ No newline at end of file From f6868562ce6b5d8e3268aef991d385575f3a3262 Mon Sep 17 00:00:00 2001 From: stephan Date: Sun, 22 May 2022 19:09:59 +0000 Subject: [PATCH 068/108] Implemented Stmt.get() and friends for WASM OO #1 wrapper. Added basic tests for prepare/step/get. Restructured module init output to introduce only 1 global-scope symbol instead of 2. FossilOrigin-Name: 601dc3fa29c2ce2ede5a8320c79050305f3774b6d7bc759247c5021f3b74aaec --- ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 | 2 + ext/fiddle/sqlite3-api.js | 296 ++++++++++++++++++++------ ext/fiddle/testing-common.js | 28 ++- ext/fiddle/testing1.js | 41 +++- manifest | 18 +- manifest.uuid | 2 +- 6 files changed, 292 insertions(+), 95 deletions(-) diff --git a/ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 b/ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 index e6b57420c2..ae34ccdb19 100644 --- a/ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 +++ b/ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 @@ -14,6 +14,8 @@ _sqlite3_column_bytes _sqlite3_column_count _sqlite3_column_count _sqlite3_column_double +_sqlite3_column_int +_sqlite3_column_int64 _sqlite3_column_name _sqlite3_column_text _sqlite3_column_type diff --git a/ext/fiddle/sqlite3-api.js b/ext/fiddle/sqlite3-api.js index 0c24085784..d4423a2175 100644 --- a/ext/fiddle/sqlite3-api.js +++ b/ext/fiddle/sqlite3-api.js @@ -17,23 +17,26 @@ Note that this file is not named sqlite3.js because that file gets generated by emscripten as the JS-glue counterpart of sqlite3.wasm. - The API gets installed as self.sqlite3, where self is expected to be - either the global window or Worker object. In addition, a higher-level - OO API is installed as self.SQLite3. + This code installs an object named self.sqlite3, where self is + expected to be either the global window or Worker object: - Potential TODO: instead of exporting 2 symbols, export only SQLite3 - as {api: sqlite3, oo1: SQLite3}. The way we export this module is - not _really_ modern-JS-friendly because it exports global symbols - (which is admittedly poor form). Exporting it "cleanly" requires - using a module loader in all client code. As there are several - different approaches, none of which this developer is currently - truly familiar with, the current approach will have to do for the - time being. + self.sqlite3 = { + api: core WASM bindings of sqlite3 APIs, + SQLite3: high-level OO API wrapper + }; + + The way we export this module is not _really_ modern-JS-friendly + because it exports a global symbol (which is admittedly not + ideal). Exporting it "cleanly," without introducing any global-scope + symbols, requires using a module loader in all client code. As there + are several different approaches, none of which this developer is + currently truly familiar with, the current approach will have to do + for the time being. Because using the low-level API properly requires some degree of WASM-related magic, it is not recommended that that API be used as-is in client-level code. Rather, client code should use the - higher-level OO API or write such a wrapper on top of the + higher-level OO API or write a custom wrapper on top of the lower-level API. This file installs namespace.sqlite3, where namespace is `self`, @@ -131,7 +134,8 @@ ["sqlite3_bind_blob","number",["number", "number", "number", "number", "number"]], ["sqlite3_bind_double","number",["number", "number", "number"]], ["sqlite3_bind_int","number",["number", "number", "number"]], - ["sqlite3_bind_int64","number",["number", "number", "number"]], + [/*Noting that wasm does not currently support 64-bit integers:*/ + "sqlite3_bind_int64","number",["number", "number", "number"]], ["sqlite3_bind_null","void",["number"]], ["sqlite3_bind_parameter_count", "number", ["number"]], ["sqlite3_bind_parameter_index","number",["number", "string"]], @@ -144,6 +148,9 @@ ["sqlite3_column_count", "number", ["number"]], ["sqlite3_column_count","number",["number"]], ["sqlite3_column_double","number",["number", "number"]], + ["sqlite3_column_int","number",["number", "number"]], + [/*Noting that wasm does not currently support 64-bit integers:*/ + "sqlite3_column_int64","number",["number", "number"]], ["sqlite3_column_name","string",["number", "number"]], ["sqlite3_column_text","string",["number", "number"]], ["sqlite3_column_type","number",["number", "number"]], @@ -199,6 +206,8 @@ and the sqlite3 API is in a worker. */ /* memory for use in some pointer-passing routines */ const pPtrArg = stackAlloc(4); + /** Throws a new error, concatenating all args with a space between + each. */ const toss = function(){ throw new Error(Array.prototype.join.call(arguments, ' ')); }; @@ -214,7 +223,7 @@ toss("TODO: support blob image of db here."); } this.checkRc(S.sqlite3_open(name, pPtrArg)); - this.pDb = getValue(pPtrArg, "i32"); + this._pDb = getValue(pPtrArg, "i32"); this.filename = name; this._statements = {/*map of open Stmt _pointers_*/}; }; @@ -244,15 +253,15 @@ toss("Do not call the Stmt constructor directly. Use DB.prepare()."); } this.db = arguments[0]; - this.pStmt = arguments[1]; - this.columnCount = S.sqlite3_column_count(this.pStmt); - this.parameterCount = S.sqlite3_bind_parameter_count(this.pStmt); + this._pStmt = arguments[1]; + this.columnCount = S.sqlite3_column_count(this._pStmt); + this.parameterCount = S.sqlite3_bind_parameter_count(this._pStmt); this._allocs = [/*list of alloc'd memory blocks for bind() values*/] }; /** Throws if the given DB has been closed, else it is returned. */ const affirmDbOpen = function(db){ - if(!db.pDb) toss("DB has been closed."); + if(!db._pDb) toss("DB has been closed."); return db; }; @@ -265,7 +274,7 @@ */ checkRc: function(sqliteResultCode){ if(!sqliteResultCode) return this; - toss(S.sqlite3_errmsg(this.pDb) || "Unknown db error."); + toss(S.sqlite3_errmsg(this._pDb) || "Unknown db error."); }, /** Finalizes all open statements and closes this database @@ -273,15 +282,15 @@ closed. */ close: function(){ - if(this.pDb){ + if(this._pDb){ let s; const that = this; Object.keys(this._statements).forEach(function(k,s){ delete that._statements[k]; - if(s && s.pStmt) s.finalize(); + if(s && s._pStmt) s.finalize(); }); - S.sqlite3_close_v2(this.pDb); - delete this.pDb; + S.sqlite3_close_v2(this._pDb); + delete this._pDb; } }, /** @@ -293,7 +302,7 @@ a name of `main`. */ fileName: function(dbName){ - return S.sqlite3_db_filename(affirmDbOpen(this).pDb, dbName||"main"); + return S.sqlite3_db_filename(affirmDbOpen(this)._pDb, dbName||"main"); }, /** Compiles the given SQL and returns a prepared Stmt. This is @@ -302,7 +311,7 @@ prepare: function(sql){ affirmDbOpen(this); setValue(pPtrArg,0,"i32"); - this.checkRc(S.sqlite3_prepare_v2(this.pDb, sql, -1, pPtrArg, null)); + this.checkRc(S.sqlite3_prepare_v2(this._pDb, sql, -1, pPtrArg, null)); const pStmt = getValue(pPtrArg, "i32"); if(!pStmt) toss("Empty SQL is not permitted."); const stmt = new Stmt(this, pStmt, BindTypes); @@ -316,9 +325,16 @@ returns a falsy value. */ const isSupportedBindType = function(v){ let t = BindTypes[null===v ? 'null' : typeof v]; - if(t) return t; - // TODO: handle buffer/blob types. - return undefined; + switch(t){ + case BindTypes.boolean: + case BindTypes.null: + case BindTypes.number: + case BindTypes.string: + return t; + default: + if(v instanceof Uint8Array) return BindTypes.blob; + toss("Unhandled isSupportedBindType()",t); + } } /** @@ -326,9 +342,7 @@ function returns that value, else it throws. */ const affirmSupportedBindType = function(v){ - const t = isSupportedBindType(v); - if(t) return t; - toss("Unsupport bind() argument type."); + return isSupportedBindType(v) || toss("Unsupport bind() argument type."); }; /** @@ -340,9 +354,9 @@ Else it throws. */ - const indexOfParam = function(stmt,key){ + const affirmParamIndex = function(stmt,key){ const n = ('number'===typeof key) - ? key : S.sqlite3_bind_parameter_index(stmt.pStmt, key); + ? key : S.sqlite3_bind_parameter_index(stmt._pStmt, key); if(0===n || (n===key && (n!==(n|0)/*floating point*/))){ toss("Invalid bind() parameter name: "+key); } @@ -350,41 +364,78 @@ return n; }; + /** Throws if ndx is not an integer or if it is out of range + for stmt.columnCount, else returns stmt. */ + const affirmColIndex = function(stmt,ndx){ + if((ndx !== (ndx|0)) || ndx<0 || ndx>=stmt.columnCount){ + toss("Column index",ndx,"is out of range."); + } + return stmt; + }; + + /** If stmt._mayGet, returns stmt, else throws. */ + const affirmMayGet = function(stmt){ + if(!affirmStmtOpen(stmt)._mayGet){ + toss("Statement.step() has not (recently) returned true."); + } + return stmt; + }; + /** Binds a single bound parameter value on the given stmt at the given index (numeric or named) using the given bindType (see the BindTypes enum) and value. Throws on error. Returns stmt on success. */ - const bindOne = function(stmt,ndx,bindType,val){ + const bindOne = function f(stmt,ndx,bindType,val){ + if(!f._){ + f._ = { + string: function(stmt, ndx, val, asBlob){ + const bytes = intArrayFromString(val,true); + const pStr = allocate(bytes, ALLOC_NORMAL); + stmt._allocs.push(pStr); + const func = asBlob ? S.sqlite3_bind_blob : S.sqlite3_bind_text; + return func(stmt._pStmt, ndx, pStr, bytes.length, 0); + } + }; + } affirmSupportedBindType(val); - ndx = indexOfParam(stmt,ndx); + ndx = affirmParamIndex(stmt,ndx); let rc = 0; - switch(bindType){ + switch((null===val || undefined===val) ? BindTypes.null : bindType){ case BindType.null: - rc = S.sqlite3_bind_null(stmt.pStmt, ndx); + rc = S.sqlite3_bind_null(stmt._pStmt, ndx); break; case BindType.string:{ - const bytes = intArrayFromString(string,false); - const pStr = allocate(bytes, ALLOC_NORMAL); - stmt._allocs.push(pStr); - rc = S.sqlite3_bind_text(stmt.pStmt, ndx, pStr, - bytes.length, 0); + rc = f._.string(stmt, ndx, val, false); break; } case BindType.number: { const m = ((val === (val|0)) - ? (val>0xefffffff + ? ((val & 0x00000000/*>32 bits*/) ? S.sqlite3_bind_int64 : S.sqlite3_bind_int) : S.sqlite3_bind_double); - rc = m(stmt.pStmt, ndx, val); + rc = m(stmt._pStmt, ndx, val); break; } case BindType.boolean: - rc = S.sqlite3_bind_int(stmt.pStmt, ndx, val ? 1 : 0); + rc = S.sqlite3_bind_int(stmt._pStmt, ndx, val ? 1 : 0); break; - case BindType.blob: + case BindType.blob: { + if('string'===typeof val){ + rc = f._.string(stmt, ndx, val, true); + }else{ + const len = val.length; + if(undefined===len){ + toss("Binding a value as a blob requires", + "that it have a length member."); + } + const pBlob = allocate(val, ALLOC_NORMAL); + stmt._allocs.push(pBlob); + rc = S.sqlite3_bind_blob(stmt._pStmt, ndx, pBlob, len, 0); + } + } default: toss("Unsupported bind() argument type."); } if(rc) stmt.db.checkRc(rc); @@ -394,7 +445,7 @@ /** Throws if the given Stmt has been finalized, else it is returned. */ const affirmStmtOpen = function(stmt){ - if(!stmt.pStmt) toss("Stmt has been closed."); + if(!stmt._pStmt) toss("Stmt has been closed."); return stmt; }; @@ -416,11 +467,13 @@ after this is. */ finalize: function(){ - if(this.pStmt){ + if(this._pStmt){ freeBindMemory(this); - delete this.db._statements[this.pStmt]; - S.sqlite3_finalize(this.pStmt); - delete this.pStmt; + delete this.db._statements[this._pStmt]; + S.sqlite3_finalize(this._pStmt); + delete this.columnCount; + delete this.parameterCount; + delete this._pStmt; delete this.db; } }, @@ -428,7 +481,8 @@ Throws if this statement has been finalized. */ clearBindings: function(){ freeBindMemory(affirmStmtOpen(this)); - S.sqlite3_clear_bindings(this.pStmt); + S.sqlite3_clear_bindings(this._pStmt); + this._mayGet = false; return this; }, /** @@ -442,7 +496,8 @@ */ reset: function(alsoClearBinds){ if(alsoClearBinds) this.clearBindings(); - S.sqlite3_reset(affirmStmtOpen(this).pStmt); + S.sqlite3_reset(affirmStmtOpen(this)._pStmt); + this._mayGet = false; return this; }, /** @@ -471,8 +526,7 @@ - Strings are bound as strings (use bindAsBlob() to force blob binding). - - buffers (blobs) are currently TODO but will be bound as - blobs. + - Uint8Array instances are bound as blobs. If passed an array, each element of the array is bound at the parameter index equal to the array index plus 1 @@ -499,16 +553,16 @@ - The statement has been finalized. */ bind: function(/*[ndx,] value*/){ - if(!this.parameterCount){ + if(!affirmStmtOpen(this).parameterCount){ toss("This statement has no bindable parameters."); } + this._mayGet = false; let ndx, arg; switch(arguments.length){ case 1: ndx = 1; arg = arguments[0]; break; case 2: ndx = arguments[0]; arg = arguments[1]; break; default: toss("Invalid bind() arguments."); } - affirmStmtOpen(this); if(null===arg || undefined===arg){ /* bind NULL */ return bindOne(this, ndx, BindType.null, arg); @@ -542,12 +596,12 @@ using the BLOB binding mechanism instead of the default selected one for the value. The ndx may be a numbered or named bind index. The value must be of type string, - buffer, or null/undefined (both treated as null). + Uint8Array, or null/undefined (both treated as null). - If passed a single argument, a bind index of 1 is assumed. + If passed a single argument, a bind index of 1 is assumed. */ bindAsBlob: function(ndx,arg){ - affirmStmtOpen(this); + affirmStmtOpen(this)._mayGet = false; if(1===arguments.length){ ndx = 1; arg = arguments[0]; @@ -558,6 +612,120 @@ toss("Invalid value type for bindAsBlob()"); } return bindOne(this, ndx, BindType.blob, arg); + }, + /** + Steps the statement one time. If the result indicates that + a row of data is available, true is returned. If no row of + data is available, false is returned. Throws on error. + */ + step: function(){ + const rc = S.sqlite3_step(affirmStmtOpen(this)._pStmt); + this._mayGet = false; + switch(rc){ + case S.SQLITE_DONE: return false; + case S.SQLITE_ROW: return this._mayGet = true; + default: this.db.checkRc(rc); + }; + }, + /** + Fetches the value from the given 0-based column index of + the current data row, throwing if index is out of range. + + Requires that step() has just returned a truthy value, else + an exception is thrown. + + By default it will determine the data type of the result + automatically. If passed a second arugment, it must be one + of the enumeration values for sqlite3 types, which are + defined as members of the sqlite3 module: SQLITE_INTEGER, + SQLITE_FLOAT, SQLITE_TEXT, SQLITE_BLOB. Any other value, + except for undefined, will trigger an exception. Passing + undefined is the same as not passing a value. It is legal + to, e.g., fetch an integer value as a string, in which case + sqlite3 will convert the value to a string. + + If ndx is an array, this function behaves a differently: it + assigns the indexes of the array, from 0 to the number of + result columns, to the values of the corresponding column, + and returns that array. + + If ndx is a plain object, this function behaves even + differentlier: it assigns the properties of the object to + the values of their corresponding result columns. + + Blobs are returned as Uint8Array instances. + + Potential TODO: add type ID SQLITE_JSON, which fetches the + result as a string and passes it (if it's not null) to + JSON.parse(), returning the result of that. Until then, + getJSON() can be used for that. + */ + get: function(ndx,asType){ + affirmMayGet(this); + if(Array.isArray(ndx)){ + let i = 0; + while(i1 ? arguments[0] : document) .querySelector(arguments[arguments.length-1]); }; - + + /* emscripten-related bits... */ const statusElement = E('#module-status'); const progressElement = E('#module-progress'); const spinnerElement = E('#module-spinner'); self.Module = { - /* ^^^ cannot declare that const because fiddle-module.js - (auto-generated) includes a decl for it and runs in this scope. */ + /* ^^^ cannot declare that const because sqlite3.js + (auto-generated) includes a decl for it and runs in this + scope. */ preRun: [], postRun: [], //onRuntimeInitialized: function(){}, @@ -94,10 +96,6 @@ } } }; - - const _expr = function(expr){ - return (expr instanceof Function) ? expr() : !!expr; - }; /** Helpers for writing sqlite3-specific tests. @@ -106,19 +104,27 @@ /** Running total of the number of tests run via this API. */ counter: 0, + /** + If expr is a function, it is called and its result + is returned, coerced to a bool, else expr, coerced to + a bool, is returned. + */ + toBool: function(expr){ + return (expr instanceof Function) ? !!expr() : !!expr; + }, /** abort() if expr is false. If expr is a function, it is called and its result is evaluated. */ assert: function(expr, msg){ ++this.counter; - if(!_expr(expr)) abort(msg || "Assertion failed."); + if(!this.toBool(expr)) abort(msg || "Assertion failed."); return this; }, /** Identical to assert() but throws instead of calling abort(). */ affirm: function(expr, msg){ ++this.counter; - if(!_expr(expr)) throw new Error(msg || "Affirmation failed."); + if(!this.toBool(expr)) throw new Error(msg || "Affirmation failed."); return this; }, /** Calls f() and squelches any exception it throws. If it @@ -134,14 +140,14 @@ returns truthy. */ throwIf: function(expr, msg){ ++this.counter; - if(_expr(expr)) throw new Error(msg || "throwIf() failed"); + if(this.toBool(expr)) throw new Error(msg || "throwIf() failed"); return this; }, /** Throws if expr is falsy or expr is a function and expr() returns falsy. */ throwUnless: function(expr, msg){ ++this.counter; - if(!_expr(expr)) throw new Error(msg || "throwUnless() failed"); + if(!this.toBool(expr)) throw new Error(msg || "throwUnless() failed"); return this; } }; diff --git a/ext/fiddle/testing1.js b/ext/fiddle/testing1.js index 6e79be0257..d667a480c5 100644 --- a/ext/fiddle/testing1.js +++ b/ext/fiddle/testing1.js @@ -14,28 +14,47 @@ */ const mainTest1 = function(namespace){ - const S = namespace.sqlite3; - const oo = namespace.SQLite3; + const S = namespace.sqlite3.api; + const oo = namespace.sqlite3.SQLite3; const T = self.SqliteTester; console.log("Loaded module:",S.sqlite3_libversion(), S.sqlite3_sourceid()); const db = new oo.DB(); const log = console.log.bind(console); - T.assert(db.pDb); + T.assert(db._pDb); log("DB:",db.filename); log("Build options:",oo.compileOptionUsed()); - - let st = db.prepare("select 1"); - T.assert(st.pStmt); + let st = db.prepare("select 3 as a"); log("statement =",st); - T.assert(st === db._statements[st.pStmt]) + T.assert(st._pStmt) + .assert(!st._mayGet) + .assert('a' === st.getColumnName(0)) + .assert(st === db._statements[st._pStmt]) .assert(1===st.columnCount) .assert(0===st.parameterCount) - .mustThrow(()=>st.bind(1,null)); - - let pId = st.pStmt; + .mustThrow(()=>st.bind(1,null)) + .assert(true===st.step()) + .assert(3 === st.get(0)) + .mustThrow(()=>st.get(1)) + .mustThrow(()=>st.get(0,~S.SQLITE_INTEGER)) + .assert(3 === st.get(0,S.SQLITE_INTEGER)) + .assert(3 === st.getInt(0)) + .assert('3' === st.get(0,S.SQLITE_TEXT)) + .assert('3' === st.getString(0)) + .assert(3.0 === st.get(0,S.SQLITE_FLOAT)) + .assert(3.0 === st.getFloat(0)) + .assert(st.get(0,S.SQLITE_BLOB) instanceof Uint8Array) + .assert(st.getBlob(0) instanceof Uint8Array) + .assert(3 === st.get([])[0]) + .assert(3 === st.get({}).a) + .assert(3 === st.getJSON(0)) + .assert(st._mayGet) + .assert(false===st.step()) + .assert(!st._mayGet) + ; + let pId = st._pStmt; st.finalize(); - T.assert(!st.pStmt) + T.assert(!st._pStmt) .assert(!db._statements[pId]); log("Test count:",T.counter); }; diff --git a/manifest b/manifest index 36dce9f18d..da28b2bacd 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C WASM:\sadded\sbindings\sfor\ssqlite3_compileoption_get/used(),\smoved\sOO\s#1\sinto\ssqlite3-api.js\ssince\sit\scan\sonly\sbe\sused\sfrom\sthe\ssame\sthread\sas\sthat\sAPI\sand\sseparating\sthem\scomplicates\sclient-side\suse.\sStarted\sadding\stest\sutilities\sand\stests\sfor\sthe\sOO1\sAPI. -D 2022-05-22T16:25:43.076 +C Implemented\sStmt.get()\sand\sfriends\sfor\sWASM\sOO\s#1\swrapper.\sAdded\sbasic\stests\sfor\sprepare/step/get.\sRestructured\smodule\sinit\soutput\sto\sintroduce\sonly\s1\sglobal-scope\ssymbol\sinstead\sof\s2. +D 2022-05-22T19:09:59.198 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -56,7 +56,7 @@ F ext/expert/sqlite3expert.c 6ca30d73b9ed75bd56d6e0d7f2c962d2affaa72c505458619d0 F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72 F ext/fiddle/EXPORTED_FUNCTIONS.fiddle 487fc7c83d45c48326f731c89162ed17ab15767e5efede8999d7d6c6e2d04c0f -F ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 00553766051a038b1acd3992d04e50540d1284c3ea78bd11daa521383e57d653 +F ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 bba07bb2b81ce667df7916d4c942f0bfe6de6c77f5fe769d479f01250f92ca01 F ext/fiddle/EXPORTED_RUNTIME_METHODS 91d5dcb0168ee056fa1a340cb8ab3c23d922622f8dad39d28919dd8af2b3ade0 F ext/fiddle/Makefile 9277c73e208b9c8093659256c9f07409c877e366480c7c22ec545ee345451d95 F ext/fiddle/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f @@ -64,10 +64,10 @@ F ext/fiddle/fiddle-worker.js c22557b641b47fa1473d3465a4e69fe06b8b09b924955805a4 F ext/fiddle/fiddle.html 657c6c3f860c322fba3c69fa4f7a1209e2d2ce44b4bc65a3e154e3a97c047a7c F ext/fiddle/fiddle.js f9c79164428e96a5909532f18a8bc8f8c8ec4f738bfc09ad3d2a532c2400f9f0 F ext/fiddle/index.md d9c1c308d8074341bc3b11d1d39073cd77754cb3ca9aeb949f23fdd8323d81cf -F ext/fiddle/sqlite3-api.js ab7e7ded7b3079ee7de43e8290f1942e757d90ebb47ae4654cfe03c980cd0cad -F ext/fiddle/testing-common.js 2b2826a1e7c8ca3e610dfa4255ff1077438b6570e08096cc139c226811e60dbb +F ext/fiddle/sqlite3-api.js e205ccb758678bab7261f184e816d809a5031e1b4babd7738bed98de534787dd +F ext/fiddle/testing-common.js 53284264504821314f052017b54fa75ab065dcd9cbb754cc8060930498faeee8 F ext/fiddle/testing1.html 68cec1b1c8646a071717e5979f22e4268e6d36d96ba13ad68333351acdbcf1d1 -F ext/fiddle/testing1.js 6a314a10efc954bcd854af89d53ab768f48a42d3dcb80773b297f4ba0ac0236d +F ext/fiddle/testing1.js 8849eaee6d7b31a195b29f9532c16a87a03e1be780a48cbdec54760c39ebf66c F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b F ext/fts1/ft_hash.h 06df7bba40dadd19597aa400a875dbc2fed705ea @@ -1967,8 +1967,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 84c8f63a1c446331a3afe52b0c8bdfa6980f24aa4cf600f576877fef5e650c39 -R d3343607f5b0d8f2cee2f7485f266550 +P f3bc0328c87cac7d50513b0f13576d8fe7b411396f19c08fbe7e7c657b33cfbf +R e0afacc1df156a218ff63194b2d94770 U stephan -Z 4ea03d4418e5522f96fc7a3cf30bf26a +Z 8276de9ecbbfd692683c1010f2d924a3 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 47aa878ffb..826df84f44 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f3bc0328c87cac7d50513b0f13576d8fe7b411396f19c08fbe7e7c657b33cfbf \ No newline at end of file +601dc3fa29c2ce2ede5a8320c79050305f3774b6d7bc759247c5021f3b74aaec \ No newline at end of file From 744a65cf7d6cd849984a50253dd42365d1e9a563 Mon Sep 17 00:00:00 2001 From: stephan Date: Sun, 22 May 2022 22:00:39 +0000 Subject: [PATCH 069/108] WASM: added exec(), execMulti(), and several getters. Various touchups and fixes. FossilOrigin-Name: b790c91b85e9cf8eecce86ac1717e8ccd2c3b6b98a1ad6a5d64eefc94ee86f9d --- ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 | 1 + ext/fiddle/sqlite3-api.js | 361 +++++++++++++++++++++++--- ext/fiddle/testing1.js | 108 +++++--- manifest | 16 +- manifest.uuid | 2 +- 5 files changed, 402 insertions(+), 86 deletions(-) diff --git a/ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 b/ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 index ae34ccdb19..da14513415 100644 --- a/ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 +++ b/ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 @@ -40,6 +40,7 @@ _sqlite3_result_int _sqlite3_result_null _sqlite3_result_text _sqlite3_sourceid +_sqlite3_sql _sqlite3_step _sqlite3_value_blob _sqlite3_value_bytes diff --git a/ext/fiddle/sqlite3-api.js b/ext/fiddle/sqlite3-api.js index d4423a2175..52ea1f982c 100644 --- a/ext/fiddle/sqlite3-api.js +++ b/ext/fiddle/sqlite3-api.js @@ -42,6 +42,22 @@ This file installs namespace.sqlite3, where namespace is `self`, meaning either the global window or worker, depending on where this is loaded from. + + # Goals and Non-goals of this API + + Goals: + + - Except where noted in the non-goals, provide a more-or-less + complete wrapper to the sqlite3 C API, insofar as WASM feature + parity with C allows for. + + Non-goals: + + - As WASM is a web-based technology and UTF-8 is the King of + Encodings in that realm, there are no plans to support the + UTF16-related APIs will not be. They would add a complication to + the bindings for no appreciable benefit. + */ (function(namespace){ /* For reference: sql.js does essentially everything we want and @@ -184,13 +200,13 @@ ["sqlite3_result_null",null,["number"]], ["sqlite3_result_text",null,["number", "string", "number", "number"]], ["sqlite3_sourceid", "string", []], + ["sqlite3_sql", "string", ["number"]], ["sqlite3_step", "number", ["number"]], ["sqlite3_value_blob", "number", ["number"]], ["sqlite3_value_bytes","number",["number"]], ["sqlite3_value_double","number",["number"]], ["sqlite3_value_text", "string", ["number"]], ["sqlite3_value_type", "number", ["number"]] - //["sqlite3_sql", "string", ["number"]], //["sqlite3_normalized_sql", "string", ["number"]] ].forEach(function(a){ const k = (4==a.length) ? a.shift() : a[0]; @@ -201,10 +217,11 @@ /* What follows is colloquially known as "OO API #1". It is a binding of the sqlite3 API which is designed to be run within the same thread (main or worker) as the one in which the - sqlite3 WASM binding was initialized. This wrapper cannot use + sqlite3 WASM binding was initialized. This wrapper cannot use the sqlite3 binding if, e.g., the wrapper is in the main thread and the sqlite3 API is in a worker. */ - /* memory for use in some pointer-passing routines */ + + /** Memory for use in some pointer-to-pointer-passing routines. */ const pPtrArg = stackAlloc(4); /** Throws a new error, concatenating all args with a space between each. */ @@ -212,8 +229,8 @@ throw new Error(Array.prototype.join.call(arguments, ' ')); }; - const sqlite3/*canonical name*/ = S/*convenience alias*/ = api; - + const S/*convenience alias*/ = api; + /** The DB class wraps a sqlite3 db handle. */ @@ -222,6 +239,7 @@ else if('string'!==typeof name){ toss("TODO: support blob image of db here."); } + setValue(pPtrArg, 0, "i32"); this.checkRc(S.sqlite3_open(name, pPtrArg)); this._pDb = getValue(pPtrArg, "i32"); this.filename = name; @@ -249,7 +267,7 @@ new instances. */ const Stmt = function(){ - if(BindTypes!=arguments[2]){ + if(BindTypes!==arguments[2]){ toss("Do not call the Stmt constructor directly. Use DB.prepare()."); } this.db = arguments[0]; @@ -265,16 +283,64 @@ return db; }; + /** + Expects to be passed (arguments) from DB.exec() and + DB.execMulti(). Does the argument processing/validation, throws + on error, and returns a new object on success: + + { sql: the SQL, obt: optionsObj, cbArg: function} + + cbArg is only set if the opt.callback is set, in which case + it's a function which expects to be passed the current Stmt + and returns the callback argument of the type indicated by + the input arguments. + */ + const parseExecArgs = function(args){ + const out = {}; + switch(args.length){ + case 1: + if('string'===typeof args[0]){ + out.sql = args[0]; + out.opt = {}; + }else if(args[0] && 'object'===typeof args[0]){ + out.opt = args[0]; + out.sql = out.opt.sql; + } + break; + case 2: + out.sql = args[0]; + out.opt = args[1]; + break; + default: toss("Invalid argument count for exec()."); + }; + if('string'!==typeof out.sql) toss("Missing SQL argument."); + if(out.opt.callback){ + switch((undefined===out.opt.rowMode) + ? 'stmt' : out.opt.rowMode) { + case 'object': out.cbArg = (stmt)=>stmt.get({}); break; + case 'array': out.cbArg = (stmt)=>stmt.get([]); break; + case 'stmt': out.cbArg = (stmt)=>stmt; break; + default: toss("Invalid rowMode:",out.opt.rowMode); + } + } + return out; + }; + DB.prototype = { /** Expects to be given an sqlite3 API result code. If it is falsy, this function returns this object, else it throws an exception with an error message from sqlite3_errmsg(), - using this object's db handle. + using this object's db handle. Note that if it's passed a + non-error code like SQLITE_ROW or SQLITE_DONE, it will + still throw but the error string might be "Not an error." + The various non-0 non-error codes need to be checked for in + client code where they are expected. */ checkRc: function(sqliteResultCode){ if(!sqliteResultCode) return this; - toss(S.sqlite3_errmsg(this._pDb) || "Unknown db error."); + toss("sqlite result code",sqliteResultCode+":", + S.sqlite3_errmsg(this._pDb) || "Unknown db error."); }, /** Finalizes all open statements and closes this database @@ -317,7 +383,168 @@ const stmt = new Stmt(this, pStmt, BindTypes); this._statements[pStmt] = stmt; return stmt; - } + }, + /** + This function works like execMulti(), and takes the same + arguments, but is more efficient (performs much less work) + when the input SQL is only a single statement. If passed a + multi-statement SQL, it only processes the first one. + + This function supports one additional option not used by + execMulti(): + + - .multi: if true, this function acts as a proxy for + execMulti(). + */ + exec: function(/*(sql [,optionsObj]) or (optionsObj)*/){ + affirmDbOpen(this); + const arg = parseExecArgs(arguments); + if(!arg.sql) return this; + else if(arg.multi){ + return this.execMulti(arg, undefined, BindTypes); + } + const opt = arg.opt; + let stmt; + try { + stmt = this.prepare(arg.sql); + if(opt.bind) stmt.bind(bind); + if(opt.callback){ + while(stmt.step()){ + stmt._isLocked = true; + opt.callback(arg.cbArg(stmt), stmt); + stmt._isLocked = false; + } + }else{ + stmt.step(); + } + }finally{ + if(stmt){ + delete stmt._isLocked; + stmt.finalize(); + } + } + return this; + + }/*exec()*/, + /** + Executes one or more SQL statements. Its arguments + must be either (sql,optionsObject) or (optionsObject). + In the latter case, optionsObject.sql must contain the + SQL to execute. Returns this object. Throws on error. + + If no SQL is provided, or a non-string is provided, an + exception is triggered. Empty SQL, on the other hand, is + simply a no-op. + + The optional options object may contain any of the following + properties: + + - .sql = the SQL to run (unless it's provided as the first + argument). + + - .bind = a single value valid as an argument for + Stmt.bind(). This is ONLY applied to the FIRST non-empty + statement in the SQL which has any bindable + parameters. (Empty statements are skipped entirely.) + + - .callback = a function which gets called for each row of + the FIRST statement in the SQL (if it has any result + rows). The second argument passed to the callback is + always the current Stmt object (so that the caller + may collect column names, or similar). The first + argument passed to the callback defaults to the current + Stmt object but may be changed with ... + + - .rowMode = a string describing what type of argument + should be passed as the first argument to the callback. A + value of 'object' causes the results of `stmt.get({})` to + be passed to the object. A value of 'array' causes the + results of `stmt.get([])` to be passed to the callback. + A value of 'stmt' is equivalent to the default, passing + the current Stmt to the callback (noting that it's always + passed as the 2nd argument). Any other value triggers an + exception. + + - saveSql = an optional array. If set, the SQL of each + executed statement is appended to this array before the + statement is executed (but after it is prepared - we + don't have the string until after that). Empty SQL + statements are elided. + + ACHTUNG #1: The callback MUST NOT modify the Stmt + object. Calling any of the Stmt.get() variants, + Stmt.getColumnName(), or simililar, is legal, but calling + step() or finalize() is not. Routines which are illegal + in this context will trigger an exception. + + ACHTUNG #2: The semantics of the `bind` and `callback` + options may well change or those options may be removed + altogether for this function (but retained for exec()). + */ + execMulti: function(/*(sql [,obj]) || (obj)*/){ + affirmDbOpen(this); + const arg = (BindTypes===arguments[2] + /* ^^^ Being passed on from exec() */ + ? arguments[0] : parseExecArgs(arguments)); + if(!arg.sql) return this; + const opt = arg.opt; + const stack = stackSave(); + let stmt; + let bind = opt.bind; + let rowMode = ( + (opt.callback && opt.rowMode) + ? opt.rowMode : false); + try{ + let pSql = allocateUTF8OnStack(arg.sql) + const pzTail = stackAlloc(4); + while(getValue(pSql, "i8")){ + setValue(pPtrArg, 0, "i32"); + setValue(pzTail, 0, "i32"); + this.checkRc(S.sqlite3_prepare_v2_sqlptr( + this._pDb, pSql, -1, pPtrArg, pzTail + )); + const pStmt = getValue(pPtrArg, "i32"); + pSql = getValue(pzTail, "i32"); + if(!pStmt) continue; + if(opt.saveSql){ + opt.saveSql.push(S.sqlite3_sql(pStmt).trim()); + } + stmt = new Stmt(this, pStmt, BindTypes); + if(bind && stmt.parameterCount){ + stmt.bind(bind); + bind = null; + } + if(opt.callback && null!==rowMode){ + while(stmt.step()){ + stmt._isLocked = true; + callback(arg.cbArg(stmt), stmt); + stmt._isLocked = false; + } + rowMode = null; + }else{ + // Do we need to while(stmt.step()){} here? + stmt.step(); + } + stmt.finalize(); + stmt = null; + } + }finally{ + if(stmt){ + delete stmt._isLocked; + stmt.finalize(); + } + stackRestore(stack); + } + return this; + }/*execMulti()*/ + }/*DB.prototype*/; + + + /** Throws if the given Stmt has been finalized, else stmt is + returned. */ + const affirmStmtOpen = function(stmt){ + if(!stmt._pStmt) toss("Stmt has been closed."); + return stmt; }; /** Returns an opaque truthy value from the BindTypes @@ -360,12 +587,17 @@ if(0===n || (n===key && (n!==(n|0)/*floating point*/))){ toss("Invalid bind() parameter name: "+key); } - else if(n<1 || n>=stmt.parameterCount) toss("Bind index",key,"is out of range."); + else if(n<1 || n>stmt.parameterCount) toss("Bind index",key,"is out of range."); return n; }; /** Throws if ndx is not an integer or if it is out of range - for stmt.columnCount, else returns stmt. */ + for stmt.columnCount, else returns stmt. + + Reminder: this will also fail after the statement is finalized + but the resulting error will be about an out-of-bounds column + index. + */ const affirmColIndex = function(stmt,ndx){ if((ndx !== (ndx|0)) || ndx<0 || ndx>=stmt.columnCount){ toss("Column index",ndx,"is out of range."); @@ -380,7 +612,22 @@ } return stmt; }; - + + /** + If stmt._isLocked is truthy, this throws an exception + complaining that the 2nd argument (an operation name, + e.g. "bind()") is not legal while the statement is "locked". + Locking happens before an exec()-like callback is passed a + statement, to ensure that the callback does not mutate or + finalize the statement. If it does not throw, it returns stmt. + */ + const affirmUnlocked = function(stmt,currentOpName){ + if(stmt._isLocked){ + toss("Operation is illegal when statement is locked:",currentOpName); + } + return stmt; + }; + /** Binds a single bound parameter value on the given stmt at the given index (numeric or named) using the given bindType (see @@ -388,6 +635,7 @@ success. */ const bindOne = function f(stmt,ndx,bindType,val){ + affirmUnlocked(stmt, 'bind()'); if(!f._){ f._ = { string: function(stmt, ndx, val, asBlob){ @@ -403,14 +651,14 @@ ndx = affirmParamIndex(stmt,ndx); let rc = 0; switch((null===val || undefined===val) ? BindTypes.null : bindType){ - case BindType.null: + case BindTypes.null: rc = S.sqlite3_bind_null(stmt._pStmt, ndx); break; - case BindType.string:{ + case BindTypes.string:{ rc = f._.string(stmt, ndx, val, false); break; } - case BindType.number: { + case BindTypes.number: { const m = ((val === (val|0)) ? ((val & 0x00000000/*>32 bits*/) ? S.sqlite3_bind_int64 @@ -419,10 +667,10 @@ rc = m(stmt._pStmt, ndx, val); break; } - case BindType.boolean: + case BindTypes.boolean: rc = S.sqlite3_bind_int(stmt._pStmt, ndx, val ? 1 : 0); break; - case BindType.blob: { + case BindTypes.blob: { if('string'===typeof val){ rc = f._.string(stmt, ndx, val, true); }else{ @@ -442,13 +690,6 @@ return stmt; }; - /** Throws if the given Stmt has been finalized, else - it is returned. */ - const affirmStmtOpen = function(stmt){ - if(!stmt._pStmt) toss("Stmt has been closed."); - return stmt; - }; - /** Frees any memory explicitly allocated for the given Stmt object. Returns stmt. */ const freeBindMemory = function(stmt){ @@ -468,6 +709,7 @@ */ finalize: function(){ if(this._pStmt){ + affirmUnlocked(this,'finalize()'); freeBindMemory(this); delete this.db._statements[this._pStmt]; S.sqlite3_finalize(this._pStmt); @@ -475,12 +717,15 @@ delete this.parameterCount; delete this._pStmt; delete this.db; + delete this._isLocked; } }, /** Clears all bound values. Returns this object. Throws if this statement has been finalized. */ clearBindings: function(){ - freeBindMemory(affirmStmtOpen(this)); + freeBindMemory( + affirmUnlocked(affirmStmtOpen(this), 'clearBindings()') + ); S.sqlite3_clear_bindings(this._pStmt); this._mayGet = false; return this; @@ -495,6 +740,7 @@ any memory allocated for them, are retained. */ reset: function(alsoClearBinds){ + affirmUnlocked(this,'reset()'); if(alsoClearBinds) this.clearBindings(); S.sqlite3_reset(affirmStmtOpen(this)._pStmt); this._mayGet = false; @@ -565,7 +811,7 @@ } if(null===arg || undefined===arg){ /* bind NULL */ - return bindOne(this, ndx, BindType.null, arg); + return bindOne(this, ndx, BindTypes.null, arg); } else if(Array.isArray(arg)){ /* bind each entry by index */ @@ -611,7 +857,7 @@ && BindTypes.null !== t){ toss("Invalid value type for bindAsBlob()"); } - return bindOne(this, ndx, BindType.blob, arg); + return bindOne(this, ndx, BindTypes.blob, arg); }, /** Steps the statement one time. If the result indicates that @@ -619,12 +865,16 @@ data is available, false is returned. Throws on error. */ step: function(){ + affirmUnlocked(this, 'step()'); const rc = S.sqlite3_step(affirmStmtOpen(this)._pStmt); this._mayGet = false; switch(rc){ case S.SQLITE_DONE: return false; case S.SQLITE_ROW: return this._mayGet = true; - default: this.db.checkRc(rc); + default: + console.warn("sqlite3_step() rc=",rc,"SQL =", + S.sqlite3_sql(this._pStmt)); + this.db.checkRc(rc); }; }, /** @@ -713,7 +963,8 @@ A convenience wrapper around get() which fetches the value as a string and then, if it is not null, passes it to JSON.parse(), returning that result. Throws if parsing - fails. + fails. If the result is null, null is returned. An empty + string, on the other hand, will trigger an exception. */ getJSON: function(ndx){ const s = this.get(ndx, S.SQLITE_STRING); @@ -725,26 +976,56 @@ finalized. */ getColumnName: function(ndx){ - return S.sqlite3_column_name(affirmColIndex(this,ndx)._pStmt, ndx); + return S.sqlite3_column_name( + affirmColIndex(affirmStmtOpen(this),ndx)._pStmt, ndx + ); + }, + /** + If this statement potentially has result columns, this + function returns an array of all such names. If passed an + array, it is used as the target and all names are appended + to it. Returns the target array. Throws if this statement + cannot have result columns. This object's columnCount member + holds the number of columns. + */ + getColumnNames: function(tgt){ + affirmColIndex(affirmStmtOpen(this),0); + if(!tgt) tgt = []; + for(let i = 0; i < this.columnCount; ++i){ + tgt.push(S.sqlite3_column_name(this._pStmt, i)); + } + return tgt; + }, + /** + If this statement has named bindable parameters and the + given name matches one, its 1-based bind index is + returned. If no match is found, 0 is returned. If it has no + bindable parameters, the undefined value is returned. + */ + getParamIndex: function(name){ + return (affirmStmtOpen(this).parameterCount + ? S.sqlite3_bind_parameter_index(this._pStmt, name) + : undefined); } - }; + }/*Stmt.prototype*/; /** OO binding's namespace. */ const SQLite3 = { version: { - lib: sqlite3.sqlite3_libversion(), + lib: S.sqlite3_libversion(), ooApi: "0.0.1" }, DB, Stmt, /** Reports whether a given compile-time option, named by the - given argument. + given argument. It has several distinct uses: If optName is an array then it is expected to be a list of compilation options and this function returns an object - which maps each such option to true or false. That object - is returned. + which maps each such option to true or false, indicating + whether or not the given option was included in this + build. That object is returned. If optName is an object, its keys are expected to be compilation options and this function sets each entry to @@ -752,10 +1033,10 @@ If passed no arguments then it returns an object mapping all known compilation options to their compile-time values, - or true if the are defined with no value. + or boolean true if they are defined with no value. - In all other cases it returns true if the option was active - when when compiling the sqlite3 module, else false. + In all other cases it returns true if the given option was + active when when compiling the sqlite3 module, else false. Compile-time option names may optionally include their "SQLITE_" prefix. When it returns an object of all options, @@ -798,9 +1079,9 @@ ) ? !!S.sqlite3_compileoption_used(optName) : false; } }; - + namespace.sqlite3 = { - api:sqlite3, + api: api, SQLite3 }; })(self/*worker or window*/); diff --git a/ext/fiddle/testing1.js b/ext/fiddle/testing1.js index d667a480c5..b7dcfe6b00 100644 --- a/ext/fiddle/testing1.js +++ b/ext/fiddle/testing1.js @@ -20,43 +20,77 @@ const mainTest1 = function(namespace){ console.log("Loaded module:",S.sqlite3_libversion(), S.sqlite3_sourceid()); const db = new oo.DB(); - const log = console.log.bind(console); - T.assert(db._pDb); - log("DB:",db.filename); - log("Build options:",oo.compileOptionUsed()); - let st = db.prepare("select 3 as a"); - log("statement =",st); - T.assert(st._pStmt) - .assert(!st._mayGet) - .assert('a' === st.getColumnName(0)) - .assert(st === db._statements[st._pStmt]) - .assert(1===st.columnCount) - .assert(0===st.parameterCount) - .mustThrow(()=>st.bind(1,null)) - .assert(true===st.step()) - .assert(3 === st.get(0)) - .mustThrow(()=>st.get(1)) - .mustThrow(()=>st.get(0,~S.SQLITE_INTEGER)) - .assert(3 === st.get(0,S.SQLITE_INTEGER)) - .assert(3 === st.getInt(0)) - .assert('3' === st.get(0,S.SQLITE_TEXT)) - .assert('3' === st.getString(0)) - .assert(3.0 === st.get(0,S.SQLITE_FLOAT)) - .assert(3.0 === st.getFloat(0)) - .assert(st.get(0,S.SQLITE_BLOB) instanceof Uint8Array) - .assert(st.getBlob(0) instanceof Uint8Array) - .assert(3 === st.get([])[0]) - .assert(3 === st.get({}).a) - .assert(3 === st.getJSON(0)) - .assert(st._mayGet) - .assert(false===st.step()) - .assert(!st._mayGet) - ; - let pId = st._pStmt; - st.finalize(); - T.assert(!st._pStmt) - .assert(!db._statements[pId]); - log("Test count:",T.counter); + try { + const log = console.log.bind(console); + T.assert(db._pDb); + log("DB:",db.filename); + log("Build options:",oo.compileOptionUsed()); + let st = db.prepare("select 3 as a"); + log("statement =",st); + T.assert(st._pStmt) + .assert(!st._mayGet) + .assert('a' === st.getColumnName(0)) + .assert(st === db._statements[st._pStmt]) + .assert(1===st.columnCount) + .assert(0===st.parameterCount) + .mustThrow(()=>st.bind(1,null)) + .assert(true===st.step()) + .assert(3 === st.get(0)) + .mustThrow(()=>st.get(1)) + .mustThrow(()=>st.get(0,~S.SQLITE_INTEGER)) + .assert(3 === st.get(0,S.SQLITE_INTEGER)) + .assert(3 === st.getInt(0)) + .assert('3' === st.get(0,S.SQLITE_TEXT)) + .assert('3' === st.getString(0)) + .assert(3.0 === st.get(0,S.SQLITE_FLOAT)) + .assert(3.0 === st.getFloat(0)) + .assert(st.get(0,S.SQLITE_BLOB) instanceof Uint8Array) + .assert(st.getBlob(0) instanceof Uint8Array) + .assert(3 === st.get([])[0]) + .assert(3 === st.get({}).a) + .assert(3 === st.getJSON(0)) + .assert(st._mayGet) + .assert(false===st.step()) + .assert(!st._mayGet) + ; + let pId = st._pStmt; + st.finalize(); + T.assert(!st._pStmt) + .assert(!db._statements[pId]); + + let list = []; + db.execMulti({ + sql:`CREATE TABLE t(a,b); +INSERT INTO t(a,b) VALUES(1,2),(3,4),(?,?);`, + saveSql: list, + bind: [5,6] + }); + log("Exec'd SQL:", list); + let counter = 0, colNames = []; + db.exec("SELECT a a, b b FROM t",{ + rowMode: 'object', + callback: function(row,stmt){ + if(!counter) stmt.getColumnNames(colNames); + ++counter; + T.assert(row.a%2 && row.a<6); + } + }); + assert(2 === colNames.length); + assert('a' === colNames[0]); + T.assert(3 === counter); + db.exec("SELECT a a, b b FROM t",{ + rowMode: 'array', + callback: function(row,stmt){ + ++counter; + assert(Array.isArray(row)); + T.assert(0===row[1]%2 && row[1]<7); + } + }); + T.assert(6 === counter); + log("Test count:",T.counter); + }finally{ + db.close(); + } }; self/*window or worker*/.Module.onRuntimeInitialized = function(){ diff --git a/manifest b/manifest index da28b2bacd..885ccb9c86 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Implemented\sStmt.get()\sand\sfriends\sfor\sWASM\sOO\s#1\swrapper.\sAdded\sbasic\stests\sfor\sprepare/step/get.\sRestructured\smodule\sinit\soutput\sto\sintroduce\sonly\s1\sglobal-scope\ssymbol\sinstead\sof\s2. -D 2022-05-22T19:09:59.198 +C WASM:\sadded\sexec(),\sexecMulti(),\sand\sseveral\sgetters.\sVarious\stouchups\sand\sfixes. +D 2022-05-22T22:00:39.271 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -56,7 +56,7 @@ F ext/expert/sqlite3expert.c 6ca30d73b9ed75bd56d6e0d7f2c962d2affaa72c505458619d0 F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72 F ext/fiddle/EXPORTED_FUNCTIONS.fiddle 487fc7c83d45c48326f731c89162ed17ab15767e5efede8999d7d6c6e2d04c0f -F ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 bba07bb2b81ce667df7916d4c942f0bfe6de6c77f5fe769d479f01250f92ca01 +F ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 5816adc4d4715b410a9df971c70f55fca610d3a240bd85d2ec34e75483cb54bb F ext/fiddle/EXPORTED_RUNTIME_METHODS 91d5dcb0168ee056fa1a340cb8ab3c23d922622f8dad39d28919dd8af2b3ade0 F ext/fiddle/Makefile 9277c73e208b9c8093659256c9f07409c877e366480c7c22ec545ee345451d95 F ext/fiddle/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f @@ -64,10 +64,10 @@ F ext/fiddle/fiddle-worker.js c22557b641b47fa1473d3465a4e69fe06b8b09b924955805a4 F ext/fiddle/fiddle.html 657c6c3f860c322fba3c69fa4f7a1209e2d2ce44b4bc65a3e154e3a97c047a7c F ext/fiddle/fiddle.js f9c79164428e96a5909532f18a8bc8f8c8ec4f738bfc09ad3d2a532c2400f9f0 F ext/fiddle/index.md d9c1c308d8074341bc3b11d1d39073cd77754cb3ca9aeb949f23fdd8323d81cf -F ext/fiddle/sqlite3-api.js e205ccb758678bab7261f184e816d809a5031e1b4babd7738bed98de534787dd +F ext/fiddle/sqlite3-api.js 6d088e075fa2910dcad2584d2a518de33c7dd5ce4d94408691c0cdb1c9c4394b F ext/fiddle/testing-common.js 53284264504821314f052017b54fa75ab065dcd9cbb754cc8060930498faeee8 F ext/fiddle/testing1.html 68cec1b1c8646a071717e5979f22e4268e6d36d96ba13ad68333351acdbcf1d1 -F ext/fiddle/testing1.js 8849eaee6d7b31a195b29f9532c16a87a03e1be780a48cbdec54760c39ebf66c +F ext/fiddle/testing1.js 5e46c8850f826821cb24b13a21e4dabee8dac9ce76845149dac599ab643784ab F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b F ext/fts1/ft_hash.h 06df7bba40dadd19597aa400a875dbc2fed705ea @@ -1967,8 +1967,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P f3bc0328c87cac7d50513b0f13576d8fe7b411396f19c08fbe7e7c657b33cfbf -R e0afacc1df156a218ff63194b2d94770 +P 601dc3fa29c2ce2ede5a8320c79050305f3774b6d7bc759247c5021f3b74aaec +R e2842421067cb498614f974216c18719 U stephan -Z 8276de9ecbbfd692683c1010f2d924a3 +Z 9b9e03e3e05307544edc47fc1b8505b5 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 826df84f44..e601bd2321 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -601dc3fa29c2ce2ede5a8320c79050305f3774b6d7bc759247c5021f3b74aaec \ No newline at end of file +b790c91b85e9cf8eecce86ac1717e8ccd2c3b6b98a1ad6a5d64eefc94ee86f9d \ No newline at end of file From c21c0e2af9de95078a2358a3e090e0384e791966 Mon Sep 17 00:00:00 2001 From: stephan Date: Sun, 22 May 2022 22:10:38 +0000 Subject: [PATCH 070/108] WASM: an arg handling fix for DB.exec({multi:true...}). FossilOrigin-Name: 0d6332f706ec5c34cc6a9ff79878f4e10a9ad81b24cc7d743b52168586285811 --- ext/fiddle/sqlite3-api.js | 4 ++-- ext/fiddle/testing1.js | 4 +++- manifest | 14 +++++++------- manifest.uuid | 2 +- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/ext/fiddle/sqlite3-api.js b/ext/fiddle/sqlite3-api.js index 52ea1f982c..a8a697301f 100644 --- a/ext/fiddle/sqlite3-api.js +++ b/ext/fiddle/sqlite3-api.js @@ -400,14 +400,14 @@ affirmDbOpen(this); const arg = parseExecArgs(arguments); if(!arg.sql) return this; - else if(arg.multi){ + else if(arg.opt.multi){ return this.execMulti(arg, undefined, BindTypes); } const opt = arg.opt; let stmt; try { stmt = this.prepare(arg.sql); - if(opt.bind) stmt.bind(bind); + if(opt.bind) stmt.bind(opt.bind); if(opt.callback){ while(stmt.step()){ stmt._isLocked = true; diff --git a/ext/fiddle/testing1.js b/ext/fiddle/testing1.js index b7dcfe6b00..7f024bf032 100644 --- a/ext/fiddle/testing1.js +++ b/ext/fiddle/testing1.js @@ -59,12 +59,14 @@ const mainTest1 = function(namespace){ .assert(!db._statements[pId]); let list = []; - db.execMulti({ + db.exec({ sql:`CREATE TABLE t(a,b); INSERT INTO t(a,b) VALUES(1,2),(3,4),(?,?);`, + multi: true, saveSql: list, bind: [5,6] }); + T.assert(2 === list.length); log("Exec'd SQL:", list); let counter = 0, colNames = []; db.exec("SELECT a a, b b FROM t",{ diff --git a/manifest b/manifest index 885ccb9c86..aff1814a5b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C WASM:\sadded\sexec(),\sexecMulti(),\sand\sseveral\sgetters.\sVarious\stouchups\sand\sfixes. -D 2022-05-22T22:00:39.271 +C WASM:\san\sarg\shandling\sfix\sfor\sDB.exec({multi:true...}). +D 2022-05-22T22:10:38.293 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -64,10 +64,10 @@ F ext/fiddle/fiddle-worker.js c22557b641b47fa1473d3465a4e69fe06b8b09b924955805a4 F ext/fiddle/fiddle.html 657c6c3f860c322fba3c69fa4f7a1209e2d2ce44b4bc65a3e154e3a97c047a7c F ext/fiddle/fiddle.js f9c79164428e96a5909532f18a8bc8f8c8ec4f738bfc09ad3d2a532c2400f9f0 F ext/fiddle/index.md d9c1c308d8074341bc3b11d1d39073cd77754cb3ca9aeb949f23fdd8323d81cf -F ext/fiddle/sqlite3-api.js 6d088e075fa2910dcad2584d2a518de33c7dd5ce4d94408691c0cdb1c9c4394b +F ext/fiddle/sqlite3-api.js bf8d382e79ad0b2131734a823a84c530f8115a4265f00dc937a4daca6b20faa9 F ext/fiddle/testing-common.js 53284264504821314f052017b54fa75ab065dcd9cbb754cc8060930498faeee8 F ext/fiddle/testing1.html 68cec1b1c8646a071717e5979f22e4268e6d36d96ba13ad68333351acdbcf1d1 -F ext/fiddle/testing1.js 5e46c8850f826821cb24b13a21e4dabee8dac9ce76845149dac599ab643784ab +F ext/fiddle/testing1.js d28af2b33a9c1c47668bc74b3b7d4198012a4c62e25dd35550794fcc26be3057 F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b F ext/fts1/ft_hash.h 06df7bba40dadd19597aa400a875dbc2fed705ea @@ -1967,8 +1967,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 601dc3fa29c2ce2ede5a8320c79050305f3774b6d7bc759247c5021f3b74aaec -R e2842421067cb498614f974216c18719 +P b790c91b85e9cf8eecce86ac1717e8ccd2c3b6b98a1ad6a5d64eefc94ee86f9d +R d56953962e2ee4ada32fbd2e80f7b019 U stephan -Z 9b9e03e3e05307544edc47fc1b8505b5 +Z 371bcc2e2a7bddeb441dadf34f671698 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index e601bd2321..abb2f5111a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b790c91b85e9cf8eecce86ac1717e8ccd2c3b6b98a1ad6a5d64eefc94ee86f9d \ No newline at end of file +0d6332f706ec5c34cc6a9ff79878f4e10a9ad81b24cc7d743b52168586285811 \ No newline at end of file From 71eacead7644d5bcbc1abfbaa022852998b84ae5 Mon Sep 17 00:00:00 2001 From: stephan Date: Mon, 23 May 2022 01:11:49 +0000 Subject: [PATCH 071/108] WASM: removed the in64-related bindings, as MDN says that calling a wasm function which has an int64 type in its signature will currently throw because JS has no 64-bit integer support. Those bindings now use doubles and simply hope that the user doesn't exceed their integer precision (2^53-1, approx 9 quadrillion). FossilOrigin-Name: 392e84828275ec203bc713d3a5d4790852add57539add6b29b5f6de1da2dc97a --- ext/fiddle/sqlite3-api.js | 56 +++++++++++++++++++++++++++------------ manifest | 12 ++++----- manifest.uuid | 2 +- 3 files changed, 46 insertions(+), 24 deletions(-) diff --git a/ext/fiddle/sqlite3-api.js b/ext/fiddle/sqlite3-api.js index a8a697301f..1a07e6d544 100644 --- a/ext/fiddle/sqlite3-api.js +++ b/ext/fiddle/sqlite3-api.js @@ -11,8 +11,8 @@ *********************************************************************** This file is intended to be loaded after loading sqlite3.wasm. It - sets one of any number of potential bindings using that API, this - one as closely matching the C-native API as is feasible. + sets up one of any number of potential bindings using that API, this + one as closely matching the C-native API as is feasible in JS. Note that this file is not named sqlite3.js because that file gets generated by emscripten as the JS-glue counterpart of sqlite3.wasm. @@ -49,7 +49,17 @@ - Except where noted in the non-goals, provide a more-or-less complete wrapper to the sqlite3 C API, insofar as WASM feature - parity with C allows for. + parity with C allows for. In fact, provide at least 3... + + - (1) The aforementioned C-style API. (2) An OO-style API on + top of that, designed to run in the same thread (main window or + Web Worker) as the C API. (3) A less-capable wrapper which can + work across the main window/worker boundary, where the sqlite3 API + is one of those and this wrapper is in the other. That + constellation places some considerable limitations on how the API + can be interacted with, but keeping the DB operations out of the + UI thread is generally desirable. + Non-goals: @@ -58,6 +68,9 @@ UTF16-related APIs will not be. They would add a complication to the bindings for no appreciable benefit. + - Supporting old or niche-market platforms. WASM is built for a + modern web and requires modern platforms. + */ (function(namespace){ /* For reference: sql.js does essentially everything we want and @@ -150,8 +163,8 @@ ["sqlite3_bind_blob","number",["number", "number", "number", "number", "number"]], ["sqlite3_bind_double","number",["number", "number", "number"]], ["sqlite3_bind_int","number",["number", "number", "number"]], - [/*Noting that wasm does not currently support 64-bit integers:*/ - "sqlite3_bind_int64","number",["number", "number", "number"]], + /*Noting that JS/wasm combo does not currently support 64-bit integers: + ["sqlite3_bind_int64","number",["number", "number", "number"]],*/ ["sqlite3_bind_null","void",["number"]], ["sqlite3_bind_parameter_count", "number", ["number"]], ["sqlite3_bind_parameter_index","number",["number", "string"]], @@ -165,8 +178,8 @@ ["sqlite3_column_count","number",["number"]], ["sqlite3_column_double","number",["number", "number"]], ["sqlite3_column_int","number",["number", "number"]], - [/*Noting that wasm does not currently support 64-bit integers:*/ - "sqlite3_column_int64","number",["number", "number"]], + /*Noting that JS/wasm combo does not currently support 64-bit integers: + ["sqlite3_column_int64","number",["number", "number"]],*/ ["sqlite3_column_name","string",["number", "number"]], ["sqlite3_column_text","string",["number", "number"]], ["sqlite3_column_type","number",["number", "number"]], @@ -661,7 +674,9 @@ case BindTypes.number: { const m = ((val === (val|0)) ? ((val & 0x00000000/*>32 bits*/) - ? S.sqlite3_bind_int64 + ? S.sqlite3_bind_double + /*It's illegal to bind a 64-bit int + from here*/ : S.sqlite3_bind_int) : S.sqlite3_bind_double); rc = m(stmt._pStmt, ndx, val); @@ -761,13 +776,17 @@ - null or undefined is bound as NULL. - - Numbers are bound as either doubles or integers: int64 if - they are larger than 0xEFFFFFFF, else int32. Booleans are - bound as integer 0 or 1. Note that doubles with no - fractional part are bound as integers. It is not expected - that that distinction is significant for the majority of - clients due to sqlite3's data typing model. This API does - not currently support the BigInt type. + - Numbers are bound as either doubles or integers: doubles + if they are larger than 32 bits, else double or int32, + depending on whether they have a fractional part. (It is, + as of this writing, illegal to call (from JS) a WASM + function which either takes or returns an int64.) + Booleans are bound as integer 0 or 1. It is not expected + the distinction of binding doubles which have no + fractional parts is integers is significant for the + majority of clients due to sqlite3's data typing + model. This API does not currently support the BigInt + type. - Strings are bound as strings (use bindAsBlob() to force blob binding). @@ -929,8 +948,11 @@ switch(undefined===asType ? S.sqlite3_column_type(this._pStmt, ndx) : asType){ - case S.SQLITE_INTEGER: - return S.sqlite3_column_int64(this._pStmt, ndx); + case S.SQLITE_INTEGER:{ + return 0 | S.sqlite3_column_double(this._pStmt, ndx); + /* ^^^^^^^^ strips any fractional part and handles + handles >32bits */ + } case S.SQLITE_FLOAT: return S.sqlite3_column_double(this._pStmt, ndx); case S.SQLITE_TEXT: diff --git a/manifest b/manifest index aff1814a5b..6fcf363395 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C WASM:\san\sarg\shandling\sfix\sfor\sDB.exec({multi:true...}). -D 2022-05-22T22:10:38.293 +C WASM:\sremoved\sthe\sin64-related\sbindings,\sas\sMDN\ssays\sthat\scalling\sa\swasm\sfunction\swhich\shas\san\sint64\stype\sin\sits\ssignature\swill\scurrently\sthrow\sbecause\sJS\shas\sno\s64-bit\sinteger\ssupport.\sThose\sbindings\snow\suse\sdoubles\sand\ssimply\shope\sthat\sthe\suser\sdoesn't\sexceed\stheir\sinteger\sprecision\s(2^53-1,\sapprox\s9\squadrillion). +D 2022-05-23T01:11:49.315 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -64,7 +64,7 @@ F ext/fiddle/fiddle-worker.js c22557b641b47fa1473d3465a4e69fe06b8b09b924955805a4 F ext/fiddle/fiddle.html 657c6c3f860c322fba3c69fa4f7a1209e2d2ce44b4bc65a3e154e3a97c047a7c F ext/fiddle/fiddle.js f9c79164428e96a5909532f18a8bc8f8c8ec4f738bfc09ad3d2a532c2400f9f0 F ext/fiddle/index.md d9c1c308d8074341bc3b11d1d39073cd77754cb3ca9aeb949f23fdd8323d81cf -F ext/fiddle/sqlite3-api.js bf8d382e79ad0b2131734a823a84c530f8115a4265f00dc937a4daca6b20faa9 +F ext/fiddle/sqlite3-api.js afe0b37b579bcc4feaadb6a3a69ed8e9d0d51fd93b3214a00505492b8d1f5ace F ext/fiddle/testing-common.js 53284264504821314f052017b54fa75ab065dcd9cbb754cc8060930498faeee8 F ext/fiddle/testing1.html 68cec1b1c8646a071717e5979f22e4268e6d36d96ba13ad68333351acdbcf1d1 F ext/fiddle/testing1.js d28af2b33a9c1c47668bc74b3b7d4198012a4c62e25dd35550794fcc26be3057 @@ -1967,8 +1967,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P b790c91b85e9cf8eecce86ac1717e8ccd2c3b6b98a1ad6a5d64eefc94ee86f9d -R d56953962e2ee4ada32fbd2e80f7b019 +P 0d6332f706ec5c34cc6a9ff79878f4e10a9ad81b24cc7d743b52168586285811 +R 79562a6f4ad568e3ba19c4e1026944bf U stephan -Z 371bcc2e2a7bddeb441dadf34f671698 +Z 5fc9a3781b7c2550ee7ad879a95eb45a # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index abb2f5111a..7b8ebbf8bd 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0d6332f706ec5c34cc6a9ff79878f4e10a9ad81b24cc7d743b52168586285811 \ No newline at end of file +392e84828275ec203bc713d3a5d4790852add57539add6b29b5f6de1da2dc97a \ No newline at end of file From 51e5d447baebc8223e7b7817b993fcf27f2d82b8 Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 23 May 2022 11:51:10 +0000 Subject: [PATCH 072/108] Add an assert() to clear a harmless static-analyzer warning. FossilOrigin-Name: 919ba2f0472e12c2d1e82364c1481e778b24ea406615b08992964a4eb80abee7 --- manifest | 13 ++++++------- manifest.uuid | 2 +- src/where.c | 1 + 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 3760c04775..19008f7049 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Do\snot\srun\sthe\ssubroutine\sthat\smaterializes\sa\sview\sor\ssubquery\suntil\sjust\nbefore\sthe\smaterialization\sis\sactually\sneeded,\sso\sthat\sif\sthe\smaterialization\nturns\sout\sto\snever\sbeen\sneeded,\sunnecessary\swork\scan\sbe\savoided. -D 2022-05-23T10:57:20.868 +C Add\san\sassert()\sto\sclear\sa\sharmless\sstatic-analyzer\swarning. +D 2022-05-23T11:51:10.322 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -653,7 +653,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c 226b9b5485d101fe4f99db2a7a1ce3fc2ab5be270b539817fd7dcbefdbfd440a +F src/where.c 424b8696c379f57c5a23452e26fbf330f792e61fe096cffabefbf8b18a340385 F src/whereInt.h 8da918f392bf202ccc0ee61291455b33ad171d209445f1ff3eaf62e0b6f6b363 F src/wherecode.c 2a8a73bcf1886632f2b2247c79395f94852a4b74484d8aa70a005892ce73d339 F src/whereexpr.c efed370c684dce04eab949202c5452bbde993efb198de43c7a88f59411ad2a2c @@ -1967,9 +1967,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 392e84828275ec203bc713d3a5d4790852add57539add6b29b5f6de1da2dc97a 16bf350683fd6ac906dbd02b21fb8bf1b1014ed05594cacf108645acd383ae65 -R b08060ca43b78ebd2d297e7f5a17d817 -T +closed 16bf350683fd6ac906dbd02b21fb8bf1b1014ed05594cacf108645acd383ae65 +P d64ae49a1f2513171d678259928c67741d79b2ae595078299525641a676cc46b +R f4740518f2ef42e0c51e1c88bd493d42 U drh -Z be8900ebd686c65db6085318ddd46fbb +Z ea092fa8452c2e569b6fc162be055767 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 5a87c0c1e4..3af9056e34 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d64ae49a1f2513171d678259928c67741d79b2ae595078299525641a676cc46b \ No newline at end of file +919ba2f0472e12c2d1e82364c1481e778b24ea406615b08992964a4eb80abee7 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 3553cfb6cc..842af8e7ae 100644 --- a/src/where.c +++ b/src/where.c @@ -3664,6 +3664,7 @@ static int whereLoopAddVirtualOne( *pbIn = 1; assert( (mExclude & WO_IN)==0 ); } + assert( pbRetryLimit || !isLimitTerm(pTerm) ); if( isLimitTerm(pTerm) && *pbIn ){ /* If there is an IN(...) term handled as an == (separate call to ** xFilter for each value on the RHS of the IN) and a LIMIT or From ea488b1258cbc4289b10ce1726474ed6ab757339 Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 23 May 2022 12:37:54 +0000 Subject: [PATCH 073/108] New test cases to further demonstrate the difference in name matching rules for LEFT JOIN versus RIGHT JOIN that protect legacy behavior. [forum:/forumpost/e90a8e6e6fa652ac|Forum thread e90a8e6e6fa652ac]. FossilOrigin-Name: 2c586060a016f5481bad29bfb8f4ac4e1204075afdd0fa1851fbbcf2abda4893 --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/join8.test | 31 +++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 19008f7049..19de6f021a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\san\sassert()\sto\sclear\sa\sharmless\sstatic-analyzer\swarning. -D 2022-05-23T11:51:10.322 +C New\stest\scases\sto\sfurther\sdemonstrate\sthe\sdifference\sin\sname\smatching\srules\nfor\sLEFT\sJOIN\sversus\sRIGHT\sJOIN\sthat\sprotect\slegacy\sbehavior.\n[forum:/forumpost/e90a8e6e6fa652ac|Forum\sthread\se90a8e6e6fa652ac]. +D 2022-05-23T12:37:54.866 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -1161,7 +1161,7 @@ F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join5.test d22b6cba8fb59ab3f1c82701434c360705eb12d4ce200c449f37b018fc47681a F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c F test/join7.test 8e72de4b45e5e930d18c305c7efe86015fb2552731e4e03ea226353036b0dab0 -F test/join8.test adf30584c6d0cc61816b24fd6f3cc8386ce89f579da4b65a6c8e05c2f2dce08e +F test/join8.test e46de7f84611663b4ee2fab699d5735af8948386904b0f067263561ee05ae427 F test/join9.test 9056ddd3b0c0f4f9d658f4521038d9a37dc23ead8ca9a505d0b0db2b6a471e05 F test/joinA.test 7eab225dc1c1ab258a5e62513a4ed7cabbd3db971d59d5d92f4fb6fa14c12f6a F test/joinB.test 1b2ba3fc8568b49411787fccbf540570c148e9b6a53a30f80691cb6268098ded @@ -1967,8 +1967,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P d64ae49a1f2513171d678259928c67741d79b2ae595078299525641a676cc46b -R f4740518f2ef42e0c51e1c88bd493d42 +P 919ba2f0472e12c2d1e82364c1481e778b24ea406615b08992964a4eb80abee7 +R 6c059b818d3fd73ba4e722dfbe5f733e U drh -Z ea092fa8452c2e569b6fc162be055767 +Z 1b7fdd9547fd3e324ebf708a24bee8c4 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 3af9056e34..f5847da199 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -919ba2f0472e12c2d1e82364c1481e778b24ea406615b08992964a4eb80abee7 \ No newline at end of file +2c586060a016f5481bad29bfb8f4ac4e1204075afdd0fa1851fbbcf2abda4893 \ No newline at end of file diff --git a/test/join8.test b/test/join8.test index 6dee54b0ae..388df8fb55 100644 --- a/test/join8.test +++ b/test/join8.test @@ -375,4 +375,35 @@ do_execsql_test join8-11040 { SELECT b, d FROM t1 RIGHT JOIN t2 WHERE (b+0)=1 AND d!=4; } {1 not-4} +# 2022-05-23 +# NATURAL JOIN name resolution is more forgiving with LEFT JOIN +# https://sqlite.org/forum/forumpost/e90a8e6e6f +# +reset_db +db null - +do_execsql_test join8-12000 { + CREATE TABLE t1(a INT); INSERT INTO t1 VALUES(0),(1); + CREATE TABLE t2(a INT); INSERT INTO t2 VALUES(0),(2); + CREATE TABLE t3(a INT); INSERT INTO t3 VALUES(0),(3); +} {} +do_catchsql_test join8-12010 { + SELECT * FROM t1 RIGHT JOIN t2 ON t2.a<>0 NATURAL RIGHT JOIN t3; +} {1 {ambiguous reference to a in USING()}} +do_catchsql_test join8-12020 { + SELECT * FROM t1 RIGHT JOIN t2 ON t2.a<>0 NATURAL LEFT JOIN t3; +} {1 {ambiguous reference to a in USING()}} +do_catchsql_test join8-12030 { + SELECT * FROM t1 LEFT JOIN t2 ON t2.a<>0 NATURAL RIGHT JOIN t3; +} {1 {ambiguous reference to a in USING()}} + +# The following query should probably also return the same error as the +# previous three cases. However, historical versions of SQLite have always +# let it pass. We will not "fix" this, since to do so might break legacy +# applications. +# +do_catchsql_test join8-12040 { + SELECT * FROM t1 LEFT JOIN t2 ON t2.a<>0 NATURAL LEFT JOIN t3; +} {0 {0 2 1 2}} + + finish_test From 192201d2ed2cc6ef34e78263c7c30622181775ad Mon Sep 17 00:00:00 2001 From: stephan Date: Mon, 23 May 2022 13:52:36 +0000 Subject: [PATCH 074/108] wasm: corrected isSupportedBindType() to behave as documented. FossilOrigin-Name: 7e2d2e807272e98e9a3c9c9ba492b796a603f36b7cc12b16923cd8a9e6579851 --- ext/fiddle/sqlite3-api.js | 2 +- manifest | 14 +++++++------- manifest.uuid | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ext/fiddle/sqlite3-api.js b/ext/fiddle/sqlite3-api.js index 1a07e6d544..5d5ac03859 100644 --- a/ext/fiddle/sqlite3-api.js +++ b/ext/fiddle/sqlite3-api.js @@ -573,7 +573,7 @@ return t; default: if(v instanceof Uint8Array) return BindTypes.blob; - toss("Unhandled isSupportedBindType()",t); + return undefined; } } diff --git a/manifest b/manifest index 19de6f021a..4018ae52d9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C New\stest\scases\sto\sfurther\sdemonstrate\sthe\sdifference\sin\sname\smatching\srules\nfor\sLEFT\sJOIN\sversus\sRIGHT\sJOIN\sthat\sprotect\slegacy\sbehavior.\n[forum:/forumpost/e90a8e6e6fa652ac|Forum\sthread\se90a8e6e6fa652ac]. -D 2022-05-23T12:37:54.866 +C wasm:\scorrected\sisSupportedBindType()\sto\sbehave\sas\sdocumented. +D 2022-05-23T13:52:36.251 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -64,7 +64,7 @@ F ext/fiddle/fiddle-worker.js c22557b641b47fa1473d3465a4e69fe06b8b09b924955805a4 F ext/fiddle/fiddle.html 657c6c3f860c322fba3c69fa4f7a1209e2d2ce44b4bc65a3e154e3a97c047a7c F ext/fiddle/fiddle.js f9c79164428e96a5909532f18a8bc8f8c8ec4f738bfc09ad3d2a532c2400f9f0 F ext/fiddle/index.md d9c1c308d8074341bc3b11d1d39073cd77754cb3ca9aeb949f23fdd8323d81cf -F ext/fiddle/sqlite3-api.js afe0b37b579bcc4feaadb6a3a69ed8e9d0d51fd93b3214a00505492b8d1f5ace +F ext/fiddle/sqlite3-api.js a6f12bf5856c1188bd613cbe487ff4171ab082defd7f2938a824e6980b342019 F ext/fiddle/testing-common.js 53284264504821314f052017b54fa75ab065dcd9cbb754cc8060930498faeee8 F ext/fiddle/testing1.html 68cec1b1c8646a071717e5979f22e4268e6d36d96ba13ad68333351acdbcf1d1 F ext/fiddle/testing1.js d28af2b33a9c1c47668bc74b3b7d4198012a4c62e25dd35550794fcc26be3057 @@ -1967,8 +1967,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 919ba2f0472e12c2d1e82364c1481e778b24ea406615b08992964a4eb80abee7 -R 6c059b818d3fd73ba4e722dfbe5f733e -U drh -Z 1b7fdd9547fd3e324ebf708a24bee8c4 +P 2c586060a016f5481bad29bfb8f4ac4e1204075afdd0fa1851fbbcf2abda4893 +R a81e75e9c1b5698ee91cc4c29d610c0b +U stephan +Z 4d417b0369487b69af23b34dd8dfae9e # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index f5847da199..85bab69618 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2c586060a016f5481bad29bfb8f4ac4e1204075afdd0fa1851fbbcf2abda4893 \ No newline at end of file +7e2d2e807272e98e9a3c9c9ba492b796a603f36b7cc12b16923cd8a9e6579851 \ No newline at end of file From dc5888e04a2a07e52112a3b0a23520a95fdbba9e Mon Sep 17 00:00:00 2001 From: stephan Date: Mon, 23 May 2022 13:55:39 +0000 Subject: [PATCH 075/108] wasm: added missing 'use strict' and fixed an undeclared var use caught by that. FossilOrigin-Name: c16a7f4950d47c2f5177db7dc5d83f0f11eb0cafdce1ec688d6f1bd740d92733 --- ext/fiddle/sqlite3-api.js | 5 +++-- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/ext/fiddle/sqlite3-api.js b/ext/fiddle/sqlite3-api.js index 5d5ac03859..25ae514394 100644 --- a/ext/fiddle/sqlite3-api.js +++ b/ext/fiddle/sqlite3-api.js @@ -73,6 +73,7 @@ */ (function(namespace){ + 'use strict'; /* For reference: sql.js does essentially everything we want and it solves much of the wasm-related voodoo, but we'll need a different structure because we want the db connection to run in @@ -575,7 +576,7 @@ if(v instanceof Uint8Array) return BindTypes.blob; return undefined; } - } + }; /** If isSupportedBindType(v) returns a truthy value, this @@ -1076,7 +1077,7 @@ }; } const rc = {}, ov = [0,0]; - let i = 0; + let i = 0, k; while((k = S.sqlite3_compileoption_get(i++))){ f._opt(k,ov); rc[ov[0]] = ov[1]; diff --git a/manifest b/manifest index 4018ae52d9..4e15ac2067 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C wasm:\scorrected\sisSupportedBindType()\sto\sbehave\sas\sdocumented. -D 2022-05-23T13:52:36.251 +C wasm:\sadded\smissing\s'use\sstrict'\sand\sfixed\san\sundeclared\svar\suse\scaught\sby\sthat. +D 2022-05-23T13:55:39.347 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -64,7 +64,7 @@ F ext/fiddle/fiddle-worker.js c22557b641b47fa1473d3465a4e69fe06b8b09b924955805a4 F ext/fiddle/fiddle.html 657c6c3f860c322fba3c69fa4f7a1209e2d2ce44b4bc65a3e154e3a97c047a7c F ext/fiddle/fiddle.js f9c79164428e96a5909532f18a8bc8f8c8ec4f738bfc09ad3d2a532c2400f9f0 F ext/fiddle/index.md d9c1c308d8074341bc3b11d1d39073cd77754cb3ca9aeb949f23fdd8323d81cf -F ext/fiddle/sqlite3-api.js a6f12bf5856c1188bd613cbe487ff4171ab082defd7f2938a824e6980b342019 +F ext/fiddle/sqlite3-api.js c684fc5ce6b6c3e70f33699de2fc4bf9eaf045a217a30125a9da31737a9ca9e7 F ext/fiddle/testing-common.js 53284264504821314f052017b54fa75ab065dcd9cbb754cc8060930498faeee8 F ext/fiddle/testing1.html 68cec1b1c8646a071717e5979f22e4268e6d36d96ba13ad68333351acdbcf1d1 F ext/fiddle/testing1.js d28af2b33a9c1c47668bc74b3b7d4198012a4c62e25dd35550794fcc26be3057 @@ -1967,8 +1967,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 2c586060a016f5481bad29bfb8f4ac4e1204075afdd0fa1851fbbcf2abda4893 -R a81e75e9c1b5698ee91cc4c29d610c0b +P 7e2d2e807272e98e9a3c9c9ba492b796a603f36b7cc12b16923cd8a9e6579851 +R 775bb58b424cc12ca6c6f62d38938ce2 U stephan -Z 4d417b0369487b69af23b34dd8dfae9e +Z e5e8a91572b08fda7b97d6952202209e # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 85bab69618..bab01378f5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7e2d2e807272e98e9a3c9c9ba492b796a603f36b7cc12b16923cd8a9e6579851 \ No newline at end of file +c16a7f4950d47c2f5177db7dc5d83f0f11eb0cafdce1ec688d6f1bd740d92733 \ No newline at end of file From 325b56b5049460c04ccf675630d620494f0b1cea Mon Sep 17 00:00:00 2001 From: stephan Date: Mon, 23 May 2022 16:54:18 +0000 Subject: [PATCH 076/108] fiddle: cleaned up and documented the status-loading progress mechanism in prep for reusing it in the sqlite3-api worker. FossilOrigin-Name: 107e3497869d757265f2a4235082bf324ba1220075d1096c2a82021a5d348a6c --- ext/fiddle/fiddle-worker.js | 63 +++++++++++++++++++++++++++++++------ ext/fiddle/fiddle.js | 56 ++++++++++++++++++--------------- manifest | 14 ++++----- manifest.uuid | 2 +- 4 files changed, 92 insertions(+), 43 deletions(-) diff --git a/ext/fiddle/fiddle-worker.js b/ext/fiddle/fiddle-worker.js index e2297dbeb2..16da63606e 100644 --- a/ext/fiddle/fiddle-worker.js +++ b/ext/fiddle/fiddle-worker.js @@ -38,19 +38,30 @@ layer. The data property is the string of the output, noting that the emscripten binding emits these one line at a time. Thus, if a C-side puts() emits multiple lines in a single call, the JS - side will see that as multiple calls. + side will see that as multiple calls. Example: + + {type:'stdout', data: 'Hi, world.'} - module: Status text. This is intended to alert the main thread about module loading status so that, e.g., the main thread can update a progress widget and DTRT when the module is finished - loading and available for work. The status text is mostly in some - undocumented(?) format emited by the emscripten generated - module-loading code, encoding progress info within it. + loading and available for work. Status messages come in the form + + {type:'module', data:{ + type:'status', + data: {text:string|null, step:1-based-integer} + } + + with an incrementing step value for each subsequent message. When + the module loading is complete, a message with a text value of + null is posted. - working: data='start'|'end'. Indicates that work is about to be sent to the module or has just completed. This can be used, e.g., to disable UI elements which should not be activated while work - is pending. + is pending. Example: + + {type:'working', data:'start'} Main-to-Worker types: @@ -60,7 +71,9 @@ it starts and a 'working' event (data='end') when it finished. If called while work is currently being executed it emits stderr message instead of doing actual work, as the underlying db cannot - handle concurrent tasks. + handle concurrent tasks. Example: + + {type:'shellExec', data: 'select * from sqlite_master'} - More TBD as the higher-level db layer develops. */ @@ -102,7 +115,40 @@ self.Module = { //onRuntimeInitialized: function(){}, print: function(text){wMsg('stdout', Array.prototype.slice.call(arguments));}, printErr: function(text){wMsg('stderr', Array.prototype.slice.call(arguments));}, - setStatus: function f(text){wMsg('module',{type:'status',data:text});}, + /** + Intercepts status updates from the Module object and fires + worker events with a type of 'status' and a payload of: + + { + text: string | null, // null at end of load process + step: integer // starts at 1, increments 1 per call + } + + We have no way of knowing in advance how many steps will + be processed/posted, so creating a "percentage done" view is + not really practical. One can be approximated by giving it a + current value of message.step and max value of message.step+1, + though. + + When work is finished, a message with a text value of null is + submitted. + + After a message with text==null is posted, the module may later + post messages about fatal problems, e.g. an exit() being + triggered, so it is recommended that UI elements for posting + status messages not be outright removed from the DOM when + text==null, and that they instead be hidden until/unless + text!=null. + */ + setStatus: function f(text){ + if(!f.last) f.last = { step: 0, text: '' }; + else if(text === f.last.text) return; + f.last.text = text; + wMsg('module',{ + type:'status', + data:{step: ++f.last.step, text: text||null} + }); + }, totalDependencies: 0, monitorRunDependencies: function(left) { this.totalDependencies = Math.max(this.totalDependencies, left); @@ -147,6 +193,5 @@ importScripts('fiddle-module.js') is called _before_ the final call to Module.setStatus(). */; Module["onRuntimeInitialized"] = function onRuntimeInitialized() { - //console.log('onRuntimeInitialized'); - //wMsg('module','done'); + wMsg('fiddle-ready'); }; diff --git a/ext/fiddle/fiddle.js b/ext/fiddle/fiddle.js index 30c20a8102..2353509da7 100644 --- a/ext/fiddle/fiddle.js +++ b/ext/fiddle/fiddle.js @@ -17,6 +17,9 @@ (function(){ 'use strict'; + /* Recall that the 'self' symbol, except where locally + overwritten, refers to the global window or worker object. */ + /** The SqliteFiddle object is intended to be the primary app-level object for the main-thread side of the sqlite @@ -136,39 +139,40 @@ SF.addMsgHandler('module', function f(ev){ ev = ev.data; - //console.log("Module status:",ev); - if('status'!==ev.type) return; - /* This weird handling of the ev.data is simply how - emscripten's auto-generated code notifies the client of - load progress. */ - let text = ev.data; - if(!f.last) f.last = { time: Date.now(), text: '' }; - if(text === f.last.text) return; - const m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/); - const now = Date.now(); - if(m && now - f.last.time < 30) return; // if this is a progress update, skip it if too soon - f.last.time = now; - f.last.text = text; - if(m) { - text = m[1]; - progressElement.value = parseInt(m[2])*100; - progressElement.max = parseInt(m[4])*100; + if('status'!==ev.type){ + console.warn("Unexpected module-type message:",ev); + return; + } + const msg = ev.data; + progressElement.value = msg.step; + progressElement.max = msg.step + 1/*we don't know how many steps to expect*/; + if(1==msg.step){ progressElement.hidden = false; spinnerElement.hidden = false; - } else { - progressElement.remove(); - if(!text) spinnerElement.remove(); } - if(text){ - statusElement.innerText = text; + if(msg.text){ + statusElement.classList.remove('hidden'); + statusElement.innerText = msg.text; }else{ - console.log("Finalizing status."); - statusElement.remove(); - SF.clearMsgHandlers('module'); - self.onSFLoaded(); + progressElement.remove(); + spinnerElement.remove(); + statusElement.classList.add('hidden'); + /* The module can post messages about fatal problems, + e.g. an exit() being triggered or assertion failure, + after the last "load" message has arrived, so + leave the statusElement and message listener intact. */ } }); + /** + The 'fiddle-ready' event is fired (with no payload) when the + wasm module has finished loading. Interestingly, that happens + _before_ the final module:status event */ + SF.addMsgHandler('fiddle-ready', function(){ + SF.clearMsgHandlers('fiddle-ready'); + self.onSFLoaded(); + }); + /** Performs all app initialization which must wait until after the worker module is loaded. This function removes itself when it's diff --git a/manifest b/manifest index 4e15ac2067..3d192125d2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C wasm:\sadded\smissing\s'use\sstrict'\sand\sfixed\san\sundeclared\svar\suse\scaught\sby\sthat. -D 2022-05-23T13:55:39.347 +C fiddle:\scleaned\sup\sand\sdocumented\sthe\sstatus-loading\sprogress\smechanism\sin\sprep\sfor\sreusing\sit\sin\sthe\ssqlite3-api\sworker. +D 2022-05-23T16:54:18.777 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -60,9 +60,9 @@ F ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 5816adc4d4715b410a9df971c70f55fca610d3a2 F ext/fiddle/EXPORTED_RUNTIME_METHODS 91d5dcb0168ee056fa1a340cb8ab3c23d922622f8dad39d28919dd8af2b3ade0 F ext/fiddle/Makefile 9277c73e208b9c8093659256c9f07409c877e366480c7c22ec545ee345451d95 F ext/fiddle/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f -F ext/fiddle/fiddle-worker.js c22557b641b47fa1473d3465a4e69fe06b8b09b924955805a4202c8201ddc429 +F ext/fiddle/fiddle-worker.js e87c17070b979bd057a6849332f2a86660a4255ff7f1b6671e3e6026182ffd5a F ext/fiddle/fiddle.html 657c6c3f860c322fba3c69fa4f7a1209e2d2ce44b4bc65a3e154e3a97c047a7c -F ext/fiddle/fiddle.js f9c79164428e96a5909532f18a8bc8f8c8ec4f738bfc09ad3d2a532c2400f9f0 +F ext/fiddle/fiddle.js 68f5bb45fc1ae7f8ae3f6b85f465257db514d12bf50ec492259685178c452a88 F ext/fiddle/index.md d9c1c308d8074341bc3b11d1d39073cd77754cb3ca9aeb949f23fdd8323d81cf F ext/fiddle/sqlite3-api.js c684fc5ce6b6c3e70f33699de2fc4bf9eaf045a217a30125a9da31737a9ca9e7 F ext/fiddle/testing-common.js 53284264504821314f052017b54fa75ab065dcd9cbb754cc8060930498faeee8 @@ -1967,8 +1967,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 7e2d2e807272e98e9a3c9c9ba492b796a603f36b7cc12b16923cd8a9e6579851 -R 775bb58b424cc12ca6c6f62d38938ce2 +P c16a7f4950d47c2f5177db7dc5d83f0f11eb0cafdce1ec688d6f1bd740d92733 +R d12da4267c62c5adab320ccc656c0131 U stephan -Z e5e8a91572b08fda7b97d6952202209e +Z e5ea295f62c882bcf12e60eff235c6ea # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index bab01378f5..6b5e057ea1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c16a7f4950d47c2f5177db7dc5d83f0f11eb0cafdce1ec688d6f1bd740d92733 \ No newline at end of file +107e3497869d757265f2a4235082bf324ba1220075d1096c2a82021a5d348a6c \ No newline at end of file From e145136a4e2e0b76d3a64d3f47783dcf9c3143bb Mon Sep 17 00:00:00 2001 From: stephan Date: Mon, 23 May 2022 19:38:57 +0000 Subject: [PATCH 077/108] wasm: minor refactoring and doc updates. FossilOrigin-Name: 6044605b2a712da73600cabb967797a03ed1915dc0ab0b10edbd52525e548196 --- ext/fiddle/SqliteTestUtil.js | 54 +++++++++++++++++++++++++++++++ ext/fiddle/testing-common.js | 63 +++--------------------------------- ext/fiddle/testing1.html | 1 + ext/fiddle/testing1.js | 16 +++++---- manifest | 17 +++++----- manifest.uuid | 2 +- 6 files changed, 79 insertions(+), 74 deletions(-) create mode 100644 ext/fiddle/SqliteTestUtil.js diff --git a/ext/fiddle/SqliteTestUtil.js b/ext/fiddle/SqliteTestUtil.js new file mode 100644 index 0000000000..964e60b215 --- /dev/null +++ b/ext/fiddle/SqliteTestUtil.js @@ -0,0 +1,54 @@ +/** + Helpers for writing sqlite3-specific tests. +*/ +self/*window or worker*/.SqliteTestUtil = { + /** Running total of the number of tests run via + this API. */ + counter: 0, + /** + If expr is a function, it is called and its result + is returned, coerced to a bool, else expr, coerced to + a bool, is returned. + */ + toBool: function(expr){ + return (expr instanceof Function) ? !!expr() : !!expr; + }, + /** abort() if expr is false. If expr is a function, it + is called and its result is evaluated. + */ + assert: function(expr, msg){ + ++this.counter; + if(!this.toBool(expr)) abort(msg || "Assertion failed."); + return this; + }, + /** Identical to assert() but throws instead of calling + abort(). */ + affirm: function(expr, msg){ + ++this.counter; + if(!this.toBool(expr)) throw new Error(msg || "Affirmation failed."); + return this; + }, + /** Calls f() and squelches any exception it throws. If it + does not throw, this function throws. */ + mustThrow: function(f, msg){ + ++this.counter; + let err; + try{ f(); } catch(e){err=e;} + if(!err) throw new Error(msg || "Expected exception."); + return this; + }, + /** Throws if expr is truthy or expr is a function and expr() + returns truthy. */ + throwIf: function(expr, msg){ + ++this.counter; + if(this.toBool(expr)) throw new Error(msg || "throwIf() failed"); + return this; + }, + /** Throws if expr is falsy or expr is a function and expr() + returns falsy. */ + throwUnless: function(expr, msg){ + ++this.counter; + if(!this.toBool(expr)) throw new Error(msg || "throwUnless() failed"); + return this; + } +}; diff --git a/ext/fiddle/testing-common.js b/ext/fiddle/testing-common.js index 79bb0ba9d9..2701481289 100644 --- a/ext/fiddle/testing-common.js +++ b/ext/fiddle/testing-common.js @@ -37,10 +37,10 @@ postRun: [], //onRuntimeInitialized: function(){}, print: function(){ - console.log(Array.prototype.slice.call(arguments)); + console.log.apply(console, Array.prototype.slice.call(arguments)); }, printErr: function(){ - console.error(Array.prototype.slice.call(arguments)); + console.error.apply(console, Array.prototype.slice.call(arguments)); }, setStatus: function f(text){ if(!f.last) f.last = { time: Date.now(), text: '' }; @@ -74,8 +74,8 @@ /* Loads sqlite3-api.js and calls the given callback (if provided), passing it an object which contains the sqlite3 and SQLite3 modules. Whether this is synchronous or async - depends on whether it's run in the main thread or a - worker.*/ + depends on whether it's run in the main thread (async) or a + worker (synchronous). */ loadSqliteAPI: function(callback){ const theScript = 'sqlite3-api.js'; if(self.importScripts){/*worker*/ @@ -96,60 +96,5 @@ } } }; - - /** - Helpers for writing sqlite3-specific tests. - */ - self.SqliteTester = { - /** Running total of the number of tests run via - this API. */ - counter: 0, - /** - If expr is a function, it is called and its result - is returned, coerced to a bool, else expr, coerced to - a bool, is returned. - */ - toBool: function(expr){ - return (expr instanceof Function) ? !!expr() : !!expr; - }, - /** abort() if expr is false. If expr is a function, it - is called and its result is evaluated. - */ - assert: function(expr, msg){ - ++this.counter; - if(!this.toBool(expr)) abort(msg || "Assertion failed."); - return this; - }, - /** Identical to assert() but throws instead of calling - abort(). */ - affirm: function(expr, msg){ - ++this.counter; - if(!this.toBool(expr)) throw new Error(msg || "Affirmation failed."); - return this; - }, - /** Calls f() and squelches any exception it throws. If it - does not throw, this function throws. */ - mustThrow: function(f, msg){ - ++this.counter; - let err; - try{ f(); } catch(e){err=e;} - if(!err) throw new Error(msg || "Expected exception."); - return this; - }, - /** Throws if expr is truthy or expr is a function and expr() - returns truthy. */ - throwIf: function(expr, msg){ - ++this.counter; - if(this.toBool(expr)) throw new Error(msg || "throwIf() failed"); - return this; - }, - /** Throws if expr is falsy or expr is a function and expr() - returns falsy. */ - throwUnless: function(expr, msg){ - ++this.counter; - if(!this.toBool(expr)) throw new Error(msg || "throwUnless() failed"); - return this; - } - }; })(self/*window or worker*/); diff --git a/ext/fiddle/testing1.html b/ext/fiddle/testing1.html index 56d2cb53b3..d428f12f65 100644 --- a/ext/fiddle/testing1.html +++ b/ext/fiddle/testing1.html @@ -25,6 +25,7 @@
Everything on this page happens in the dev console.
+ diff --git a/ext/fiddle/testing1.js b/ext/fiddle/testing1.js index 7f024bf032..a59d2d2cc2 100644 --- a/ext/fiddle/testing1.js +++ b/ext/fiddle/testing1.js @@ -16,12 +16,12 @@ const mainTest1 = function(namespace){ const S = namespace.sqlite3.api; const oo = namespace.sqlite3.SQLite3; - const T = self.SqliteTester; + const T = self.SqliteTestUtil; console.log("Loaded module:",S.sqlite3_libversion(), S.sqlite3_sourceid()); const db = new oo.DB(); + const log = console.log.bind(console); try { - const log = console.log.bind(console); T.assert(db._pDb); log("DB:",db.filename); log("Build options:",oo.compileOptionUsed()); @@ -95,7 +95,11 @@ INSERT INTO t(a,b) VALUES(1,2),(3,4),(?,?);`, } }; -self/*window or worker*/.Module.onRuntimeInitialized = function(){ - console.log("Loading sqlite3-api.js..."); - self.Module.loadSqliteAPI(mainTest1); -}; +self/*window or worker*/.Module.postRun.push(function(theModule){ + /** Use a timeout so that we are (hopefully) out from under the + module init stack when our setup gets run. */ + + setTimeout(function(){ + theModule.loadSqliteAPI(mainTest1); + },0); +}); diff --git a/manifest b/manifest index 3d192125d2..f2a75f05f8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C fiddle:\scleaned\sup\sand\sdocumented\sthe\sstatus-loading\sprogress\smechanism\sin\sprep\sfor\sreusing\sit\sin\sthe\ssqlite3-api\sworker. -D 2022-05-23T16:54:18.777 +C wasm:\sminor\srefactoring\sand\sdoc\supdates. +D 2022-05-23T19:38:57.101 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -59,15 +59,16 @@ F ext/fiddle/EXPORTED_FUNCTIONS.fiddle 487fc7c83d45c48326f731c89162ed17ab15767e5 F ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 5816adc4d4715b410a9df971c70f55fca610d3a240bd85d2ec34e75483cb54bb F ext/fiddle/EXPORTED_RUNTIME_METHODS 91d5dcb0168ee056fa1a340cb8ab3c23d922622f8dad39d28919dd8af2b3ade0 F ext/fiddle/Makefile 9277c73e208b9c8093659256c9f07409c877e366480c7c22ec545ee345451d95 +F ext/fiddle/SqliteTestUtil.js e3094833660a6ddd40766b802901b5861b37f0b89c6c577ee0ce4c9d36399e61 F ext/fiddle/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f F ext/fiddle/fiddle-worker.js e87c17070b979bd057a6849332f2a86660a4255ff7f1b6671e3e6026182ffd5a F ext/fiddle/fiddle.html 657c6c3f860c322fba3c69fa4f7a1209e2d2ce44b4bc65a3e154e3a97c047a7c F ext/fiddle/fiddle.js 68f5bb45fc1ae7f8ae3f6b85f465257db514d12bf50ec492259685178c452a88 F ext/fiddle/index.md d9c1c308d8074341bc3b11d1d39073cd77754cb3ca9aeb949f23fdd8323d81cf F ext/fiddle/sqlite3-api.js c684fc5ce6b6c3e70f33699de2fc4bf9eaf045a217a30125a9da31737a9ca9e7 -F ext/fiddle/testing-common.js 53284264504821314f052017b54fa75ab065dcd9cbb754cc8060930498faeee8 -F ext/fiddle/testing1.html 68cec1b1c8646a071717e5979f22e4268e6d36d96ba13ad68333351acdbcf1d1 -F ext/fiddle/testing1.js d28af2b33a9c1c47668bc74b3b7d4198012a4c62e25dd35550794fcc26be3057 +F ext/fiddle/testing-common.js 723aada13d90a5ee3f0f8f5b5b88e46954becae5d2b04ded811d90106057f4ac +F ext/fiddle/testing1.html 026502e5d5e6a250e4101f8e8948708a1295ce831a094d741839ecaf788d8533 +F ext/fiddle/testing1.js c3d529379f901846907b00f62dffe752ff5724fb39791d47b421c4afdab0f58b F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b F ext/fts1/ft_hash.h 06df7bba40dadd19597aa400a875dbc2fed705ea @@ -1967,8 +1968,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P c16a7f4950d47c2f5177db7dc5d83f0f11eb0cafdce1ec688d6f1bd740d92733 -R d12da4267c62c5adab320ccc656c0131 +P 107e3497869d757265f2a4235082bf324ba1220075d1096c2a82021a5d348a6c +R e327ce077052e8c8f39099637b67690c U stephan -Z e5ea295f62c882bcf12e60eff235c6ea +Z 572c126f779e5a94cb3892ddd8508065 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 6b5e057ea1..b561a9295a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -107e3497869d757265f2a4235082bf324ba1220075d1096c2a82021a5d348a6c \ No newline at end of file +6044605b2a712da73600cabb967797a03ed1915dc0ab0b10edbd52525e548196 \ No newline at end of file From a240a24ad0b9d0e2023c5e77bcc4fc277db2e5cf Mon Sep 17 00:00:00 2001 From: stephan Date: Tue, 24 May 2022 00:22:10 +0000 Subject: [PATCH 078/108] wasm/JS: added support for scalar UDFs. Fixed a deallocation problem with bind()ed strings/blobs. FossilOrigin-Name: 325a9ee31ad7abae563c4da5cd8228e151b00aa9afcac7e9bca5efaa9d48e107 --- Makefile.in | 2 +- ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 | 1 + ext/fiddle/EXPORTED_RUNTIME_METHODS | 5 + ext/fiddle/sqlite3-api.js | 242 ++++++++++++++++++++++++-- ext/fiddle/testing1.js | 31 +++- manifest | 20 +-- manifest.uuid | 2 +- 7 files changed, 271 insertions(+), 32 deletions(-) diff --git a/Makefile.in b/Makefile.in index bd9bc366f1..8a6d04a1de 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1535,7 +1535,7 @@ clean: clean-wasm #emcc_opt = -O2 #emcc_opt = -O3 emcc_opt = -Oz -emcc_flags = $(emcc_opt) -I. $(SHELL_OPT) +emcc_flags = $(emcc_opt) -sALLOW_TABLE_GROWTH -I. $(SHELL_OPT) $(fiddle_module_js): Makefile sqlite3.c shell.c \ $(fiddle_dir)/EXPORTED_RUNTIME_METHODS $(fiddle_dir)/EXPORTED_FUNCTIONS.fiddle emcc -o $@ $(emcc_flags) \ diff --git a/ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 b/ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 index da14513415..45f9266a38 100644 --- a/ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 +++ b/ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 @@ -47,3 +47,4 @@ _sqlite3_value_bytes _sqlite3_value_double _sqlite3_value_text _sqlite3_value_type +_free diff --git a/ext/fiddle/EXPORTED_RUNTIME_METHODS b/ext/fiddle/EXPORTED_RUNTIME_METHODS index a5b33fb786..1bfcc97d40 100644 --- a/ext/fiddle/EXPORTED_RUNTIME_METHODS +++ b/ext/fiddle/EXPORTED_RUNTIME_METHODS @@ -4,3 +4,8 @@ stackAlloc stackSave stackRestore UTF8ToString +removeFunction +addFunction +setValue +getValue +allocate diff --git a/ext/fiddle/sqlite3-api.js b/ext/fiddle/sqlite3-api.js index 25ae514394..22773d8d7d 100644 --- a/ext/fiddle/sqlite3-api.js +++ b/ext/fiddle/sqlite3-api.js @@ -144,6 +144,10 @@ SQLITE_TEXT: 3, SQLITE_BLOB: 4, SQLITE_NULL: 5, + /* create_function() flags */ + SQLITE_DETERMINISTIC: 0x000000800, + SQLITE_DIRECTONLY: 0x000080000, + SQLITE_INNOCUOUS: 0x000200000, /* sqlite encodings, used for creating UDFs, noting that we will only support UTF8. */ SQLITE_UTF8: 1 @@ -257,7 +261,8 @@ this.checkRc(S.sqlite3_open(name, pPtrArg)); this._pDb = getValue(pPtrArg, "i32"); this.filename = name; - this._statements = {/*map of open Stmt _pointers_*/}; + this._statements = {/*map of open Stmt _pointers_ to Stmt*/}; + this._udfs = {/*map of UDF names to wasm function _pointers_*/}; }; /** @@ -297,6 +302,12 @@ return db; }; + /** Returns true if n is a 32-bit (signed) integer, + else false. */ + const isInt32 = function(n){ + return (n===n|0 && n<0xFFFFFFFF) ? true : undefined; + }; + /** Expects to be passed (arguments) from DB.exec() and DB.execMulti(). Does the argument processing/validation, throws @@ -340,6 +351,11 @@ return out; }; + /** If object opts has _its own_ property named p then that + property's value is returned, else dflt is returned. */ + const getOwnOption = (opts, p, dflt)=> + opts.hasOwnProperty(p) ? opts[p] : dflt; + DB.prototype = { /** Expects to be given an sqlite3 API result code. If it is @@ -369,6 +385,9 @@ delete that._statements[k]; if(s && s._pStmt) s.finalize(); }); + Object.values(this._udfs).forEach(Module.removeFunction); + delete this._udfs; + delete this._statements; S.sqlite3_close_v2(this._pDb); delete this._pDb; } @@ -550,7 +569,184 @@ stackRestore(stack); } return this; - }/*execMulti()*/ + }/*execMulti()*/, + /** + Creates a new scalar UDF (User-Defined Function) which is + accessible via SQL code. This function may be called in any + of the following forms: + + - (name, function) + - (name, function, optionsObject) + - (name, optionsObject) + - (optionsObject) + + In the final two cases, the function must be defined as the + 'callback' property of the options object. In the final + case, the function's name must be the 'name' property. + + This can only be used to create scalar functions, not + aggregate or window functions. UDFs cannot be removed from + a DB handle after they're added. + + On success, returns this object. Throws on error. + + When called from SQL, arguments to the UDF, and its result, + will be converted between JS and SQL with as much fidelity + as is feasible, triggering an exception if a type + conversion cannot be determined. Some freedom is afforded + to numeric conversions due to friction between the JS and C + worlds: integers which are larger than 32 bits will be + treated as doubles, as JS does not support 64-bit integers + and it is (as of this writing) illegal to use WASM + functions which take or return 64-bit integers from JS. + + The optional options object may contain flags to modify how + the function is defined: + + - .arity: the number of arguments which SQL calls to this + function expect or require. The default value is the + callback's length property. A value of -1 means that the + function is variadic and may accept any number of + arguments, up to sqlite3's compile-time limits. sqlite3 + will enforce the argument count if is zero or greater. + + The following properties correspond to flags documented at: + + https://sqlite.org/c3ref/create_function.html + + - .deterministic = SQLITE_DETERMINISTIC + - .directOnly = SQLITE_DIRECTONLY + - .innocuous = SQLITE_INNOCUOUS + + + Maintenance reminder: the ability to add new + WASM-accessible functions to the runtime requires that the + WASM build is compiled with emcc's `-sALLOW_TABLE_GROWTH` + flag. + */ + createFunction: function f(name, callback,opt){ + switch(arguments.length){ + case 1: /* (optionsObject) */ + opt = name; + name = opt.name; + callback = opt.callback; + break; + case 2: /* (name, callback|optionsObject) */ + if(!(callback instanceof Function)){ + opt = callback; + callback = opt.callback; + } + break; + default: break; + } + if(!opt) opt = {}; + if(!(callback instanceof Function)){ + toss("Invalid arguments: expecting a callback function."); + }else if('string' !== typeof name){ + toss("Invalid arguments: missing function name."); + } + if(!f._extractArgs){ + /* Static init */ + f._extractArgs = function(argc, pArgv){ + let i, pVal, valType, arg; + const tgt = []; + for(i = 0; i < argc; ++i){ + pVal = getValue(pArgv + (4 * i), "i32"); + valType = S.sqlite3_value_type(pVal); + switch(valType){ + case S.SQLITE_INTEGER: + case S.SQLITE_FLOAT: + arg = S.sqlite3_value_double(pVal); + break; + case SQLITE_TEXT: + arg = S.sqlite3_value_text(pVal); + break; + case SQLITE_BLOB:{ + const n = S.sqlite3_value_bytes(ptr); + const pBlob = S.sqlite3_value_blob(ptr); + arg = new Uint8Array(n); + let i; + for(i = 0; i < n; ++i) arg[i] = HEAP8[pBlob+i]; + break; + } + default: + arg = null; break; + } + tgt.push(arg); + } + return tgt; + }/*_extractArgs()*/; + f._setResult = function(pCx, val){ + switch(typeof val) { + case 'boolean': + S.sqlite3_result_int(pCx, val ? 1 : 0); + break; + case 'number': { + (isInt32(val) + ? S.sqlite3_result_int + : S.sqlite3_result_double)(pCx, val); + break; + } + case 'string': + S.sqlite3_result_text(pCx, val, -1, + -1/*==SQLITE_TRANSIENT*/); + break; + case 'object': + if(null===val) { + S.sqlite3_result_null(pCx); + break; + }else if(undefined!==val.length){ + const pBlob = Module.allocate(val, ALLOC_NORMAL); + S.sqlite3_result_blob(pCx, pBlob, val.length, -1/*==SQLITE_TRANSIENT*/); + Module._free(blobptr); + break; + } + // else fall through + default: + toss("Don't not how to handle this UDF result value:",val); + }; + }/*_setResult()*/; + }/*static init*/ + const wrapper = function(pCx, argc, pArgv){ + try{ + f._setResult(pCx, callback.apply(null, f._extractArgs(argc, pArgv))); + }catch(e){ + S.sqlite3_result_error(pCx, e.message, -1); + } + }; + const pUdf = Module.addFunction(wrapper, "viii"); + let fFlags = 0; + if(getOwnOption(opt, 'deterministic')) fFlags |= S.SQLITE_DETERMINISTIC; + if(getOwnOption(opt, 'directOnly')) fFlags |= S.SQLITE_DIRECTONLY; + if(getOwnOption(opt, 'innocuous')) fFlags |= S.SQLITE_INNOCUOUS; + name = name.toLowerCase(); + try { + this.checkRc(S.sqlite3_create_function_v2( + this._pDb, name, + (opt.hasOwnProperty('arity') ? +opt.arity : callback.length), + S.SQLITE_UTF8 | fFlags, null/*pApp*/, pUdf, + null/*xStep*/, null/*xFinal*/, null/*xDestroy*/)); + }catch(e){ + Module.removeFunction(pUdf); + throw e; + } + if(this._udfs.hasOwnProperty(name)){ + Module.removeFunction(this._udfs[name]); + } + this._udfs[name] = pUdf; + return this; + }/*createFunction()*/, + selectValue: function(sql,bind){ + let stmt, rc; + try { + stmt = this.prepare(sql); + stmt.bind(bind); + if(stmt.step()) rc = stmt.get(0); + }finally{ + if(stmt) stmt.finalize(); + } + return rc; + } }/*DB.prototype*/; @@ -654,7 +850,7 @@ f._ = { string: function(stmt, ndx, val, asBlob){ const bytes = intArrayFromString(val,true); - const pStr = allocate(bytes, ALLOC_NORMAL); + const pStr = Module.allocate(bytes, ALLOC_NORMAL); stmt._allocs.push(pStr); const func = asBlob ? S.sqlite3_bind_blob : S.sqlite3_bind_text; return func(stmt._pStmt, ndx, pStr, bytes.length, 0); @@ -673,12 +869,10 @@ break; } case BindTypes.number: { - const m = ((val === (val|0)) - ? ((val & 0x00000000/*>32 bits*/) - ? S.sqlite3_bind_double - /*It's illegal to bind a 64-bit int - from here*/ - : S.sqlite3_bind_int) + const m = (isInt32(val) + ? S.sqlite3_bind_int + /*It's illegal to bind a 64-bit int + from here*/ : S.sqlite3_bind_double); rc = m(stmt._pStmt, ndx, val); break; @@ -695,7 +889,7 @@ toss("Binding a value as a blob requires", "that it have a length member."); } - const pBlob = allocate(val, ALLOC_NORMAL); + const pBlob = Module.allocate(val, ALLOC_NORMAL); stmt._allocs.push(pBlob); rc = S.sqlite3_bind_blob(stmt._pStmt, ndx, pBlob, len, 0); } @@ -711,7 +905,7 @@ const freeBindMemory = function(stmt){ let m; while(undefined !== (m = stmt._allocs.pop())){ - _free(m); + Module._free(m); } return stmt; }; @@ -775,7 +969,13 @@ Bindable value types: - - null or undefined is bound as NULL. + - null is bound as NULL. + + - undefined as a standalone value is a no-op intended to + simplify certain client-side use cases: passing undefined + as a value to this function will not actually bind + anything. undefined as an array or object property when + binding an array/object is treated as null. - Numbers are bound as either doubles or integers: doubles if they are larger than 32 bits, else double or int32, @@ -818,18 +1018,24 @@ - The statement has been finalized. */ - bind: function(/*[ndx,] value*/){ - if(!affirmStmtOpen(this).parameterCount){ - toss("This statement has no bindable parameters."); - } - this._mayGet = false; + bind: function(/*[ndx,] arg*/){ + affirmStmtOpen(this); let ndx, arg; switch(arguments.length){ case 1: ndx = 1; arg = arguments[0]; break; case 2: ndx = arguments[0]; arg = arguments[1]; break; default: toss("Invalid bind() arguments."); } - if(null===arg || undefined===arg){ + this._mayGet = false; + if(undefined===arg){ + /* It might seem intuitive to bind undefined as NULL + but this approach simplifies certain client-side + uses when passing on arguments between 2+ levels of + functions. */ + return this; + }else if(!this.parameterCount){ + toss("This statement has no bindable parameters."); + }else if(null===arg){ /* bind NULL */ return bindOne(this, ndx, BindTypes.null, arg); } diff --git a/ext/fiddle/testing1.js b/ext/fiddle/testing1.js index a59d2d2cc2..5e8dd662d0 100644 --- a/ext/fiddle/testing1.js +++ b/ext/fiddle/testing1.js @@ -14,14 +14,20 @@ */ const mainTest1 = function(namespace){ + const T = self.SqliteTestUtil; + T.assert(Module._free instanceof Function). + assert(Module.allocate instanceof Function). + assert(Module.addFunction instanceof Function). + assert(Module.removeFunction instanceof Function); + const S = namespace.sqlite3.api; const oo = namespace.sqlite3.SQLite3; - const T = self.SqliteTestUtil; console.log("Loaded module:",S.sqlite3_libversion(), S.sqlite3_sourceid()); const db = new oo.DB(); const log = console.log.bind(console); try { + T.assert(db._pDb); log("DB:",db.filename); log("Build options:",oo.compileOptionUsed()); @@ -89,10 +95,31 @@ INSERT INTO t(a,b) VALUES(1,2),(3,4),(?,?);`, } }); T.assert(6 === counter); - log("Test count:",T.counter); + + log("Testing UDF..."); + db.createFunction("foo",function(a,b){return a+b}); + T.assert(7===db.selectValue("select foo(3,4)")). + assert(5===db.selectValue("select foo(3,?)",2)). + assert(5===db.selectValue("select foo(?,?)",[1,4])). + assert(5===db.selectValue("select foo($a,$b)",{$a:0,$b:5})); + db.createFunction("bar", { + arity: -1, + callback: function(){ + var rc = 0; + for(let i = 0; i < arguments.length; ++i) rc += arguments[i]; + return rc; + } + }); + T.assert(0===db.selectValue("select bar()")). + assert(1===db.selectValue("select bar(1)")). + assert(3===db.selectValue("select bar(1,2)")). + assert(-1===db.selectValue("select bar(1,2,-4)")); + + T.assert('hi' === db.selectValue("select ?",'hi')); }finally{ db.close(); } + log("Total Test count:",T.counter); }; self/*window or worker*/.Module.postRun.push(function(theModule){ diff --git a/manifest b/manifest index f2a75f05f8..98394a4ca7 100644 --- a/manifest +++ b/manifest @@ -1,9 +1,9 @@ -C wasm:\sminor\srefactoring\sand\sdoc\supdates. -D 2022-05-23T19:38:57.101 +C wasm/JS:\sadded\ssupport\sfor\sscalar\sUDFs.\sFixed\sa\sdeallocation\sproblem\swith\sbind()ed\sstrings/blobs. +D 2022-05-24T00:22:10.054 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 -F Makefile.in a192a8de35ba61e6d695a3bd430b021e7cbf7ea473497028540801fe7b659282 +F Makefile.in dd31c34eb86a7869660f9697694d52c8f1c9705fede9717c59559530b6f0cb87 F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241 F Makefile.msc b28a8a7a977e7312f6859f560348e1eb110c21bd6cf9fab0d16537c0a514eef3 F README.md 8b8df9ca852aeac4864eb1e400002633ee6db84065bd01b78c33817f97d31f5e @@ -56,8 +56,8 @@ F ext/expert/sqlite3expert.c 6ca30d73b9ed75bd56d6e0d7f2c962d2affaa72c505458619d0 F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72 F ext/fiddle/EXPORTED_FUNCTIONS.fiddle 487fc7c83d45c48326f731c89162ed17ab15767e5efede8999d7d6c6e2d04c0f -F ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 5816adc4d4715b410a9df971c70f55fca610d3a240bd85d2ec34e75483cb54bb -F ext/fiddle/EXPORTED_RUNTIME_METHODS 91d5dcb0168ee056fa1a340cb8ab3c23d922622f8dad39d28919dd8af2b3ade0 +F ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 07b573a1830cb2d38ed347cf2a4139ec3b9c0f69748da6a2d8356b426c807694 +F ext/fiddle/EXPORTED_RUNTIME_METHODS ff64aea52779b0d4a838268275fe02adf6f2fdf4d9ce21c22d104bf3d7597398 F ext/fiddle/Makefile 9277c73e208b9c8093659256c9f07409c877e366480c7c22ec545ee345451d95 F ext/fiddle/SqliteTestUtil.js e3094833660a6ddd40766b802901b5861b37f0b89c6c577ee0ce4c9d36399e61 F ext/fiddle/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f @@ -65,10 +65,10 @@ F ext/fiddle/fiddle-worker.js e87c17070b979bd057a6849332f2a86660a4255ff7f1b6671e F ext/fiddle/fiddle.html 657c6c3f860c322fba3c69fa4f7a1209e2d2ce44b4bc65a3e154e3a97c047a7c F ext/fiddle/fiddle.js 68f5bb45fc1ae7f8ae3f6b85f465257db514d12bf50ec492259685178c452a88 F ext/fiddle/index.md d9c1c308d8074341bc3b11d1d39073cd77754cb3ca9aeb949f23fdd8323d81cf -F ext/fiddle/sqlite3-api.js c684fc5ce6b6c3e70f33699de2fc4bf9eaf045a217a30125a9da31737a9ca9e7 +F ext/fiddle/sqlite3-api.js 43d750c13ca2426580a57c1f0c8b4e529a1d8af45eda92dcdde6b5d5e4031fcd F ext/fiddle/testing-common.js 723aada13d90a5ee3f0f8f5b5b88e46954becae5d2b04ded811d90106057f4ac F ext/fiddle/testing1.html 026502e5d5e6a250e4101f8e8948708a1295ce831a094d741839ecaf788d8533 -F ext/fiddle/testing1.js c3d529379f901846907b00f62dffe752ff5724fb39791d47b421c4afdab0f58b +F ext/fiddle/testing1.js 7365c6dac4f680f8ebd6ecfcf6475c5c0a0afd61cdaff5b5281e473b79c7424e F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b F ext/fts1/ft_hash.h 06df7bba40dadd19597aa400a875dbc2fed705ea @@ -1968,8 +1968,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 107e3497869d757265f2a4235082bf324ba1220075d1096c2a82021a5d348a6c -R e327ce077052e8c8f39099637b67690c +P 6044605b2a712da73600cabb967797a03ed1915dc0ab0b10edbd52525e548196 +R ceb272ebfbe3295f001f5fea9e36326e U stephan -Z 572c126f779e5a94cb3892ddd8508065 +Z 228a27040854e49e332f67b566615c59 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index b561a9295a..06b3868814 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6044605b2a712da73600cabb967797a03ed1915dc0ab0b10edbd52525e548196 \ No newline at end of file +325a9ee31ad7abae563c4da5cd8228e151b00aa9afcac7e9bca5efaa9d48e107 \ No newline at end of file From 64f0e9376b9dcd2cb0f930a1bb4d62c3ce16f2ab Mon Sep 17 00:00:00 2001 From: stephan Date: Tue, 24 May 2022 00:35:18 +0000 Subject: [PATCH 079/108] wasm/JS: documented DB.selectValue() and corrected the fetching of NULL columns via Stmt.get(). FossilOrigin-Name: 70f91fab825d365f505750acdb8d3ae532880c4cdb64d1e61bb21b24a115958b --- ext/fiddle/sqlite3-api.js | 12 ++++++++++-- ext/fiddle/testing1.js | 4 +++- manifest | 14 +++++++------- manifest.uuid | 2 +- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/ext/fiddle/sqlite3-api.js b/ext/fiddle/sqlite3-api.js index 22773d8d7d..7d30634f5e 100644 --- a/ext/fiddle/sqlite3-api.js +++ b/ext/fiddle/sqlite3-api.js @@ -736,11 +736,18 @@ this._udfs[name] = pUdf; return this; }/*createFunction()*/, + /** + Prepares the given SQL, step()s it one time and returns the + value of the first result column. If it has no results, + undefined is returned. If passed a second argument, it is + treated like an argument to Stmt.bind(), so may be any type + supported by that function. Throws on error (e.g. malformed + SQL). + */ selectValue: function(sql,bind){ let stmt, rc; try { - stmt = this.prepare(sql); - stmt.bind(bind); + stmt = this.prepare(sql).bind(bind); if(stmt.step()) rc = stmt.get(0); }finally{ if(stmt) stmt.finalize(); @@ -1155,6 +1162,7 @@ switch(undefined===asType ? S.sqlite3_column_type(this._pStmt, ndx) : asType){ + case S.SQLITE_NULL: return null; case S.SQLITE_INTEGER:{ return 0 | S.sqlite3_column_double(this._pStmt, ndx); /* ^^^^^^^^ strips any fractional part and handles diff --git a/ext/fiddle/testing1.js b/ext/fiddle/testing1.js index 5e8dd662d0..1c83b90e37 100644 --- a/ext/fiddle/testing1.js +++ b/ext/fiddle/testing1.js @@ -115,7 +115,9 @@ INSERT INTO t(a,b) VALUES(1,2),(3,4),(?,?);`, assert(3===db.selectValue("select bar(1,2)")). assert(-1===db.selectValue("select bar(1,2,-4)")); - T.assert('hi' === db.selectValue("select ?",'hi')); + T.assert('hi' === db.selectValue("select ?",'hi')). + assert(null===db.selectValue("select null")); + }finally{ db.close(); } diff --git a/manifest b/manifest index 98394a4ca7..4061294b7d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C wasm/JS:\sadded\ssupport\sfor\sscalar\sUDFs.\sFixed\sa\sdeallocation\sproblem\swith\sbind()ed\sstrings/blobs. -D 2022-05-24T00:22:10.054 +C wasm/JS:\sdocumented\sDB.selectValue()\sand\scorrected\sthe\sfetching\sof\sNULL\scolumns\svia\sStmt.get(). +D 2022-05-24T00:35:18.252 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -65,10 +65,10 @@ F ext/fiddle/fiddle-worker.js e87c17070b979bd057a6849332f2a86660a4255ff7f1b6671e F ext/fiddle/fiddle.html 657c6c3f860c322fba3c69fa4f7a1209e2d2ce44b4bc65a3e154e3a97c047a7c F ext/fiddle/fiddle.js 68f5bb45fc1ae7f8ae3f6b85f465257db514d12bf50ec492259685178c452a88 F ext/fiddle/index.md d9c1c308d8074341bc3b11d1d39073cd77754cb3ca9aeb949f23fdd8323d81cf -F ext/fiddle/sqlite3-api.js 43d750c13ca2426580a57c1f0c8b4e529a1d8af45eda92dcdde6b5d5e4031fcd +F ext/fiddle/sqlite3-api.js 2a0ba8c9a0778a6ea6720c6717540732a8eb36b7605b883a716db3da9d4a2aba F ext/fiddle/testing-common.js 723aada13d90a5ee3f0f8f5b5b88e46954becae5d2b04ded811d90106057f4ac F ext/fiddle/testing1.html 026502e5d5e6a250e4101f8e8948708a1295ce831a094d741839ecaf788d8533 -F ext/fiddle/testing1.js 7365c6dac4f680f8ebd6ecfcf6475c5c0a0afd61cdaff5b5281e473b79c7424e +F ext/fiddle/testing1.js 2f9910ff46bcd31ed2779b4bd2fcf09a57805c6073da6dd56dce6cd2e95a47b9 F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b F ext/fts1/ft_hash.h 06df7bba40dadd19597aa400a875dbc2fed705ea @@ -1968,8 +1968,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 6044605b2a712da73600cabb967797a03ed1915dc0ab0b10edbd52525e548196 -R ceb272ebfbe3295f001f5fea9e36326e +P 325a9ee31ad7abae563c4da5cd8228e151b00aa9afcac7e9bca5efaa9d48e107 +R ec73c1d66717375855af09a51e0d10ff U stephan -Z 228a27040854e49e332f67b566615c59 +Z 005deadcf1ed546088d3a014fe907d3d # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 06b3868814..554fc93691 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -325a9ee31ad7abae563c4da5cd8228e151b00aa9afcac7e9bca5efaa9d48e107 \ No newline at end of file +70f91fab825d365f505750acdb8d3ae532880c4cdb64d1e61bb21b24a115958b \ No newline at end of file From 2f6a729d551826888a31b61f9b0ebd107b53ff65 Mon Sep 17 00:00:00 2001 From: stephan Date: Tue, 24 May 2022 01:15:21 +0000 Subject: [PATCH 080/108] wasm/JS: minor doc updates, corrected bind()ing of the undefined value to behave as documented, removed some superfluous code. FossilOrigin-Name: 526c8c728019b317624a93f6f07840ca524bca84e7c03ce5e86e38953146236f --- ext/fiddle/sqlite3-api.js | 49 ++++++++++++++++++++------------------- ext/fiddle/testing1.js | 5 +++- manifest | 14 +++++------ manifest.uuid | 2 +- 4 files changed, 37 insertions(+), 33 deletions(-) diff --git a/ext/fiddle/sqlite3-api.js b/ext/fiddle/sqlite3-api.js index 7d30634f5e..90b8de798b 100644 --- a/ext/fiddle/sqlite3-api.js +++ b/ext/fiddle/sqlite3-api.js @@ -605,10 +605,11 @@ - .arity: the number of arguments which SQL calls to this function expect or require. The default value is the - callback's length property. A value of -1 means that the - function is variadic and may accept any number of - arguments, up to sqlite3's compile-time limits. sqlite3 - will enforce the argument count if is zero or greater. + callback's length property (i.e. the number of declared + parameters it has). A value of -1 means that the function + is variadic and may accept any number of arguments, up to + sqlite3's compile-time limits. sqlite3 will enforce the + argument count if is zero or greater. The following properties correspond to flags documented at: @@ -737,8 +738,8 @@ return this; }/*createFunction()*/, /** - Prepares the given SQL, step()s it one time and returns the - value of the first result column. If it has no results, + Prepares the given SQL, step()s it one time, and returns + the value of the first result column. If it has no results, undefined is returned. If passed a second argument, it is treated like an argument to Stmt.bind(), so may be any type supported by that function. Throws on error (e.g. malformed @@ -766,9 +767,10 @@ /** Returns an opaque truthy value from the BindTypes enum if v's type is a valid bindable type, else - returns a falsy value. */ + returns a falsy value. As a special case, a value of + undefined is treated as a bind type of null. */ const isSupportedBindType = function(v){ - let t = BindTypes[null===v ? 'null' : typeof v]; + let t = BindTypes[(null===v||undefined===v) ? 'null' : typeof v]; switch(t){ case BindTypes.boolean: case BindTypes.null: @@ -822,14 +824,6 @@ return stmt; }; - /** If stmt._mayGet, returns stmt, else throws. */ - const affirmMayGet = function(stmt){ - if(!affirmStmtOpen(stmt)._mayGet){ - toss("Statement.step() has not (recently) returned true."); - } - return stmt; - }; - /** If stmt._isLocked is truthy, this throws an exception complaining that the 2nd argument (an operation name, @@ -981,8 +975,11 @@ - undefined as a standalone value is a no-op intended to simplify certain client-side use cases: passing undefined as a value to this function will not actually bind - anything. undefined as an array or object property when - binding an array/object is treated as null. + anything and this function will skip confirmation that + binding is even legal. (Those semantics simplify certain + client-side uses.) Conversely, a value of undefined as an + array or object property when binding an array/object + (see below) is treated the same as null. - Numbers are bound as either doubles or integers: doubles if they are larger than 32 bits, else double or int32, @@ -1033,7 +1030,6 @@ case 2: ndx = arguments[0]; arg = arguments[1]; break; default: toss("Invalid bind() arguments."); } - this._mayGet = false; if(undefined===arg){ /* It might seem intuitive to bind undefined as NULL but this approach simplifies certain client-side @@ -1042,7 +1038,9 @@ return this; }else if(!this.parameterCount){ toss("This statement has no bindable parameters."); - }else if(null===arg){ + } + this._mayGet = false; + if(null===arg){ /* bind NULL */ return bindOne(this, ndx, BindTypes.null, arg); } @@ -1080,7 +1078,7 @@ If passed a single argument, a bind index of 1 is assumed. */ bindAsBlob: function(ndx,arg){ - affirmStmtOpen(this)._mayGet = false; + affirmStmtOpen(this); if(1===arguments.length){ ndx = 1; arg = arguments[0]; @@ -1090,6 +1088,7 @@ && BindTypes.null !== t){ toss("Invalid value type for bindAsBlob()"); } + this._mayGet = false; return bindOne(this, ndx, BindTypes.blob, arg); }, /** @@ -1100,11 +1099,11 @@ step: function(){ affirmUnlocked(this, 'step()'); const rc = S.sqlite3_step(affirmStmtOpen(this)._pStmt); - this._mayGet = false; switch(rc){ - case S.SQLITE_DONE: return false; + case S.SQLITE_DONE: return this._mayGet = false; case S.SQLITE_ROW: return this._mayGet = true; default: + this._mayGet = false; console.warn("sqlite3_step() rc=",rc,"SQL =", S.sqlite3_sql(this._pStmt)); this.db.checkRc(rc); @@ -1144,7 +1143,9 @@ getJSON() can be used for that. */ get: function(ndx,asType){ - affirmMayGet(this); + if(!affirmStmtOpen(this)._mayGet){ + toss("Stmt.step() has not (recently) returned true."); + } if(Array.isArray(ndx)){ let i = 0; while(i Date: Tue, 24 May 2022 14:36:45 +0000 Subject: [PATCH 081/108] fiddle: lots of generic refactoring, restructuring, and cleanup in the higher-level code. Added push-fiddle ext/fiddle/Makefile target to push the fiddle app to a remote server via rsync. FossilOrigin-Name: ed19fef3459499abb0a4a010f368b4576d6e068d930c8480446ea677ac87c1c1 --- ext/fiddle/Makefile | 29 +++++- ext/fiddle/fiddle.js | 56 ++++++---- ext/fiddle/sqlite3-api.js | 194 ++++++++++++++++++----------------- ext/fiddle/testing-common.js | 81 +++++++++------ ext/fiddle/testing.css | 31 ++++++ ext/fiddle/testing1.html | 1 + ext/fiddle/testing1.js | 80 ++++++++------- manifest | 23 +++-- manifest.uuid | 2 +- 9 files changed, 298 insertions(+), 199 deletions(-) create mode 100644 ext/fiddle/testing.css diff --git a/ext/fiddle/Makefile b/ext/fiddle/Makefile index 73107d3bde..16f68132ad 100644 --- a/ext/fiddle/Makefile +++ b/ext/fiddle/Makefile @@ -1,10 +1,31 @@ -# This makefile exists primarily to simplify/speed up development from -# emacs. It is not part of the canonical build process. +# This GNU makefile exists primarily to simplify/speed up development +# from emacs. It is not part of the canonical build process. default: make -C ../.. wasm -e emcc_opt=-O0 clean: make -C ../../ clean-wasm -push-demo: - rsync -va fiddle*.js fiddle*.wasm fiddle.html *.css wh2:www/wh/sqlite3/. +demo_files = emscripten.css fiddle.html \ + fiddle.js fiddle-module.js \ + fiddle-module.wasm fiddle-worker.js + +# demo_target is the remote destination for the fiddle app. It +# must be a [user@]HOST:/path for rsync. +# Note that the target "should probably" contain a symlink of +# index.html -> fiddle.html. +demo_target ?= +ifeq (,$(demo_target)) +ifneq (,$(wildcard /home/stephan)) + demo_target = wh2:www/wh/sqlite3/. +else ifneq (,$(wildcard /home/drh)) + #demo_target = if appropriate, add that user@host:/path here +endif +endif + +push-fiddle: $(demo_files) + @if [ x = "x$(demo_target)" ]; then \ + echo "demo_target must be a [user@]HOST:/path for rsync"; \ + exit 1; \ + fi + rsync -va $(demo_files) $(demo_target) diff --git a/ext/fiddle/fiddle.js b/ext/fiddle/fiddle.js index 2353509da7..5590279d0c 100644 --- a/ext/fiddle/fiddle.js +++ b/ext/fiddle/fiddle.js @@ -132,35 +132,45 @@ return (arguments.length>1 ? arguments[0] : document) .querySelector(arguments[arguments.length-1]); }; - - const statusElement = E('#module-status'); - const progressElement = E('#module-progress'); - const spinnerElement = E('#module-spinner'); + /** Handles status updates from the Module object. */ SF.addMsgHandler('module', function f(ev){ ev = ev.data; if('status'!==ev.type){ console.warn("Unexpected module-type message:",ev); return; } + if(!f.ui){ + f.ui = { + status: E('#module-status'), + progress: E('#module-progress'), + spinner: E('#module-spinner') + }; + } const msg = ev.data; - progressElement.value = msg.step; - progressElement.max = msg.step + 1/*we don't know how many steps to expect*/; + if(f.ui.progres){ + progress.value = msg.step; + progress.max = msg.step + 1/*we don't know how many steps to expect*/; + } if(1==msg.step){ - progressElement.hidden = false; - spinnerElement.hidden = false; + f.ui.progress.classList.remove('hidden'); + f.ui.spinner.classList.remove('hidden'); } if(msg.text){ - statusElement.classList.remove('hidden'); - statusElement.innerText = msg.text; + f.ui.status.classList.remove('hidden'); + f.ui.status.innerText = msg.text; }else{ - progressElement.remove(); - spinnerElement.remove(); - statusElement.classList.add('hidden'); + if(f.ui.progress){ + f.ui.progress.remove(); + f.ui.spinner.remove(); + delete f.ui.progress; + delete f.ui.spinner; + } + f.ui.status.classList.add('hidden'); /* The module can post messages about fatal problems, e.g. an exit() being triggered or assertion failure, after the last "load" message has arrived, so - leave the statusElement and message listener intact. */ + leave f.ui.status and message listener intact. */ } }); @@ -209,9 +219,9 @@ },false); /** To be called immediately before work is sent to the - worker. Updates some UI elements. The 'working'/'end' + worker. Updates some UI elements. The 'working'/'end' event will apply the inverse, undoing the bits this - function does. This impl is not in the 'working'/'start' + function does. This impl is not in the 'working'/'start' event handler because that event is given to us asynchronously _after_ we need to have performed this work. @@ -242,13 +252,15 @@ }; SF.addMsgHandler('working',function f(ev){ - if('start' === ev.data){ - /* See notes in preStartWork(). */ - }else if('end' === ev.data){ - preStartWork._.pageTitle.innerText = preStartWork._.pageTitleOrig; - btnShellExec.innerText = preStartWork._.btnLabel; - btnShellExec.removeAttribute('disabled'); + switch(ev.data){ + case 'start': /* See notes in preStartWork(). */; return; + case 'end': + preStartWork._.pageTitle.innerText = preStartWork._.pageTitleOrig; + btnShellExec.innerText = preStartWork._.btnLabel; + btnShellExec.removeAttribute('disabled'); + return; } + console.warn("Unhandled 'working' event:",ev.data); }); /* For each checkbox with data-csstgt, set up a handler which diff --git a/ext/fiddle/sqlite3-api.js b/ext/fiddle/sqlite3-api.js index 90b8de798b..e97e7c1837 100644 --- a/ext/fiddle/sqlite3-api.js +++ b/ext/fiddle/sqlite3-api.js @@ -17,31 +17,33 @@ Note that this file is not named sqlite3.js because that file gets generated by emscripten as the JS-glue counterpart of sqlite3.wasm. - This code installs an object named self.sqlite3, where self is - expected to be either the global window or Worker object: + This code installs an object named self.Module.sqlite3, where self + is expected to be either the global window or Worker object and + Module is the object set up by the emscripten infrastructure. The + sqlite3 object looks like: - self.sqlite3 = { - api: core WASM bindings of sqlite3 APIs, + { + api: bindings for much of the core sqlite3 APIs, SQLite3: high-level OO API wrapper - }; + } The way we export this module is not _really_ modern-JS-friendly - because it exports a global symbol (which is admittedly not - ideal). Exporting it "cleanly," without introducing any global-scope - symbols, requires using a module loader in all client code. As there - are several different approaches, none of which this developer is - currently truly familiar with, the current approach will have to do - for the time being. + because it exports/relies on a global symbol (which is admittedly + not ideal). Exporting it "cleanly," without introducing any + global-scope symbols, requires using a module loader in all client + code. As there are several different approaches, none of which this + developer is currently truly familiar with, the current approach + will have to do for the time being. - Because using the low-level API properly requires some degree of - WASM-related magic, it is not recommended that that API be used - as-is in client-level code. Rather, client code should use the - higher-level OO API or write a custom wrapper on top of the - lower-level API. - - This file installs namespace.sqlite3, where namespace is `self`, - meaning either the global window or worker, depending on where this - is loaded from. + Because using certain parts of the low-level API properly requires + some degree of WASM-related magic, it is not recommended that that + API be used as-is in client-level code. Rather, client code should + use the higher-level OO API or write a custom wrapper on top of the + lower-level API. In short, using any C-style APIs which take + pointers-to-pointer arguments require WASM-specific interfaces + installed by emcscripten-generated code. Those which take or return + only integers, doubles, strings, or "plain" pointers to db or + statement objects can be used in a straightforward manner. # Goals and Non-goals of this API @@ -60,13 +62,16 @@ can be interacted with, but keeping the DB operations out of the UI thread is generally desirable. + - Insofar as possible, support client-side storage using JS + filesystem APIs. As of this writing, such things are still very + much TODO. Non-goals: - - As WASM is a web-based technology and UTF-8 is the King of - Encodings in that realm, there are no plans to support the - UTF16-related APIs will not be. They would add a complication to - the bindings for no appreciable benefit. + - As WASM is a web-centric technology and UTF-8 is the King of + Encodings in that realm, there are no current plans to support the + UTF16-related APIs. They would add a complication to the bindings + for no appreciable benefit. - Supporting old or niche-market platforms. WASM is built for a modern web and requires modern platforms. @@ -247,8 +252,6 @@ throw new Error(Array.prototype.join.call(arguments, ' ')); }; - const S/*convenience alias*/ = api; - /** The DB class wraps a sqlite3 db handle. */ @@ -258,7 +261,7 @@ toss("TODO: support blob image of db here."); } setValue(pPtrArg, 0, "i32"); - this.checkRc(S.sqlite3_open(name, pPtrArg)); + this.checkRc(api.sqlite3_open(name, pPtrArg)); this._pDb = getValue(pPtrArg, "i32"); this.filename = name; this._statements = {/*map of open Stmt _pointers_ to Stmt*/}; @@ -291,8 +294,8 @@ } this.db = arguments[0]; this._pStmt = arguments[1]; - this.columnCount = S.sqlite3_column_count(this._pStmt); - this.parameterCount = S.sqlite3_bind_parameter_count(this._pStmt); + this.columnCount = api.sqlite3_column_count(this._pStmt); + this.parameterCount = api.sqlite3_bind_parameter_count(this._pStmt); this._allocs = [/*list of alloc'd memory blocks for bind() values*/] }; @@ -370,7 +373,7 @@ checkRc: function(sqliteResultCode){ if(!sqliteResultCode) return this; toss("sqlite result code",sqliteResultCode+":", - S.sqlite3_errmsg(this._pDb) || "Unknown db error."); + api.sqlite3_errmsg(this._pDb) || "Unknown db error."); }, /** Finalizes all open statements and closes this database @@ -388,7 +391,7 @@ Object.values(this._udfs).forEach(Module.removeFunction); delete this._udfs; delete this._statements; - S.sqlite3_close_v2(this._pDb); + api.sqlite3_close_v2(this._pDb); delete this._pDb; } }, @@ -401,7 +404,7 @@ a name of `main`. */ fileName: function(dbName){ - return S.sqlite3_db_filename(affirmDbOpen(this)._pDb, dbName||"main"); + return api.sqlite3_db_filename(affirmDbOpen(this)._pDb, dbName||"main"); }, /** Compiles the given SQL and returns a prepared Stmt. This is @@ -410,7 +413,7 @@ prepare: function(sql){ affirmDbOpen(this); setValue(pPtrArg,0,"i32"); - this.checkRc(S.sqlite3_prepare_v2(this._pDb, sql, -1, pPtrArg, null)); + this.checkRc(api.sqlite3_prepare_v2(this._pDb, sql, -1, pPtrArg, null)); const pStmt = getValue(pPtrArg, "i32"); if(!pStmt) toss("Empty SQL is not permitted."); const stmt = new Stmt(this, pStmt, BindTypes); @@ -533,14 +536,14 @@ while(getValue(pSql, "i8")){ setValue(pPtrArg, 0, "i32"); setValue(pzTail, 0, "i32"); - this.checkRc(S.sqlite3_prepare_v2_sqlptr( + this.checkRc(api.sqlite3_prepare_v2_sqlptr( this._pDb, pSql, -1, pPtrArg, pzTail )); const pStmt = getValue(pPtrArg, "i32"); pSql = getValue(pzTail, "i32"); if(!pStmt) continue; if(opt.saveSql){ - opt.saveSql.push(S.sqlite3_sql(pStmt).trim()); + opt.saveSql.push(api.sqlite3_sql(pStmt).trim()); } stmt = new Stmt(this, pStmt, BindTypes); if(bind && stmt.parameterCount){ @@ -653,18 +656,18 @@ const tgt = []; for(i = 0; i < argc; ++i){ pVal = getValue(pArgv + (4 * i), "i32"); - valType = S.sqlite3_value_type(pVal); + valType = api.sqlite3_value_type(pVal); switch(valType){ - case S.SQLITE_INTEGER: - case S.SQLITE_FLOAT: - arg = S.sqlite3_value_double(pVal); + case api.SQLITE_INTEGER: + case api.SQLITE_FLOAT: + arg = api.sqlite3_value_double(pVal); break; case SQLITE_TEXT: - arg = S.sqlite3_value_text(pVal); + arg = api.sqlite3_value_text(pVal); break; case SQLITE_BLOB:{ - const n = S.sqlite3_value_bytes(ptr); - const pBlob = S.sqlite3_value_blob(ptr); + const n = api.sqlite3_value_bytes(ptr); + const pBlob = api.sqlite3_value_blob(ptr); arg = new Uint8Array(n); let i; for(i = 0; i < n; ++i) arg[i] = HEAP8[pBlob+i]; @@ -680,25 +683,25 @@ f._setResult = function(pCx, val){ switch(typeof val) { case 'boolean': - S.sqlite3_result_int(pCx, val ? 1 : 0); + api.sqlite3_result_int(pCx, val ? 1 : 0); break; case 'number': { (isInt32(val) - ? S.sqlite3_result_int - : S.sqlite3_result_double)(pCx, val); + ? api.sqlite3_result_int + : api.sqlite3_result_double)(pCx, val); break; } case 'string': - S.sqlite3_result_text(pCx, val, -1, + api.sqlite3_result_text(pCx, val, -1, -1/*==SQLITE_TRANSIENT*/); break; case 'object': if(null===val) { - S.sqlite3_result_null(pCx); + api.sqlite3_result_null(pCx); break; }else if(undefined!==val.length){ const pBlob = Module.allocate(val, ALLOC_NORMAL); - S.sqlite3_result_blob(pCx, pBlob, val.length, -1/*==SQLITE_TRANSIENT*/); + api.sqlite3_result_blob(pCx, pBlob, val.length, -1/*==SQLITE_TRANSIENT*/); Module._free(blobptr); break; } @@ -712,20 +715,20 @@ try{ f._setResult(pCx, callback.apply(null, f._extractArgs(argc, pArgv))); }catch(e){ - S.sqlite3_result_error(pCx, e.message, -1); + api.sqlite3_result_error(pCx, e.message, -1); } }; const pUdf = Module.addFunction(wrapper, "viii"); let fFlags = 0; - if(getOwnOption(opt, 'deterministic')) fFlags |= S.SQLITE_DETERMINISTIC; - if(getOwnOption(opt, 'directOnly')) fFlags |= S.SQLITE_DIRECTONLY; - if(getOwnOption(opt, 'innocuous')) fFlags |= S.SQLITE_INNOCUOUS; + if(getOwnOption(opt, 'deterministic')) fFlags |= api.SQLITE_DETERMINISTIC; + if(getOwnOption(opt, 'directOnly')) fFlags |= api.SQLITE_DIRECTONLY; + if(getOwnOption(opt, 'innocuous')) fFlags |= api.SQLITE_INNOCUOUS; name = name.toLowerCase(); try { - this.checkRc(S.sqlite3_create_function_v2( + this.checkRc(api.sqlite3_create_function_v2( this._pDb, name, (opt.hasOwnProperty('arity') ? +opt.arity : callback.length), - S.SQLITE_UTF8 | fFlags, null/*pApp*/, pUdf, + api.SQLITE_UTF8 | fFlags, null/*pApp*/, pUdf, null/*xStep*/, null/*xFinal*/, null/*xDestroy*/)); }catch(e){ Module.removeFunction(pUdf); @@ -802,7 +805,7 @@ */ const affirmParamIndex = function(stmt,key){ const n = ('number'===typeof key) - ? key : S.sqlite3_bind_parameter_index(stmt._pStmt, key); + ? key : api.sqlite3_bind_parameter_index(stmt._pStmt, key); if(0===n || (n===key && (n!==(n|0)/*floating point*/))){ toss("Invalid bind() parameter name: "+key); } @@ -853,7 +856,7 @@ const bytes = intArrayFromString(val,true); const pStr = Module.allocate(bytes, ALLOC_NORMAL); stmt._allocs.push(pStr); - const func = asBlob ? S.sqlite3_bind_blob : S.sqlite3_bind_text; + const func = asBlob ? api.sqlite3_bind_blob : api.sqlite3_bind_text; return func(stmt._pStmt, ndx, pStr, bytes.length, 0); } }; @@ -863,7 +866,7 @@ let rc = 0; switch((null===val || undefined===val) ? BindTypes.null : bindType){ case BindTypes.null: - rc = S.sqlite3_bind_null(stmt._pStmt, ndx); + rc = api.sqlite3_bind_null(stmt._pStmt, ndx); break; case BindTypes.string:{ rc = f._.string(stmt, ndx, val, false); @@ -871,15 +874,15 @@ } case BindTypes.number: { const m = (isInt32(val) - ? S.sqlite3_bind_int + ? api.sqlite3_bind_int /*It's illegal to bind a 64-bit int from here*/ - : S.sqlite3_bind_double); + : api.sqlite3_bind_double); rc = m(stmt._pStmt, ndx, val); break; } case BindTypes.boolean: - rc = S.sqlite3_bind_int(stmt._pStmt, ndx, val ? 1 : 0); + rc = api.sqlite3_bind_int(stmt._pStmt, ndx, val ? 1 : 0); break; case BindTypes.blob: { if('string'===typeof val){ @@ -892,7 +895,7 @@ } const pBlob = Module.allocate(val, ALLOC_NORMAL); stmt._allocs.push(pBlob); - rc = S.sqlite3_bind_blob(stmt._pStmt, ndx, pBlob, len, 0); + rc = api.sqlite3_bind_blob(stmt._pStmt, ndx, pBlob, len, 0); } } default: toss("Unsupported bind() argument type."); @@ -923,7 +926,7 @@ affirmUnlocked(this,'finalize()'); freeBindMemory(this); delete this.db._statements[this._pStmt]; - S.sqlite3_finalize(this._pStmt); + api.sqlite3_finalize(this._pStmt); delete this.columnCount; delete this.parameterCount; delete this._pStmt; @@ -937,7 +940,7 @@ freeBindMemory( affirmUnlocked(affirmStmtOpen(this), 'clearBindings()') ); - S.sqlite3_clear_bindings(this._pStmt); + api.sqlite3_clear_bindings(this._pStmt); this._mayGet = false; return this; }, @@ -953,7 +956,7 @@ reset: function(alsoClearBinds){ affirmUnlocked(this,'reset()'); if(alsoClearBinds) this.clearBindings(); - S.sqlite3_reset(affirmStmtOpen(this)._pStmt); + api.sqlite3_reset(affirmStmtOpen(this)._pStmt); this._mayGet = false; return this; }, @@ -1098,14 +1101,14 @@ */ step: function(){ affirmUnlocked(this, 'step()'); - const rc = S.sqlite3_step(affirmStmtOpen(this)._pStmt); + const rc = api.sqlite3_step(affirmStmtOpen(this)._pStmt); switch(rc){ - case S.SQLITE_DONE: return this._mayGet = false; - case S.SQLITE_ROW: return this._mayGet = true; + case api.SQLITE_DONE: return this._mayGet = false; + case api.SQLITE_ROW: return this._mayGet = true; default: this._mayGet = false; console.warn("sqlite3_step() rc=",rc,"SQL =", - S.sqlite3_sql(this._pStmt)); + api.sqlite3_sql(this._pStmt)); this.db.checkRc(rc); }; }, @@ -1155,27 +1158,27 @@ }else if(ndx && 'object'===typeof ndx){ let i = 0; while(i32bits */ } - case S.SQLITE_FLOAT: - return S.sqlite3_column_double(this._pStmt, ndx); - case S.SQLITE_TEXT: - return S.sqlite3_column_text(this._pStmt, ndx); - case S.SQLITE_BLOB: { - const n = S.sqlite3_column_bytes(this._pStmt, ndx); - const ptr = S.sqlite3_column_blob(this._pStmt, ndx); + case api.SQLITE_FLOAT: + return api.sqlite3_column_double(this._pStmt, ndx); + case api.SQLITE_TEXT: + return api.sqlite3_column_text(this._pStmt, ndx); + case api.SQLITE_BLOB: { + const n = api.sqlite3_column_bytes(this._pStmt, ndx); + const ptr = api.sqlite3_column_blob(this._pStmt, ndx); const rc = new Uint8Array(n); for(let i = 0; i < n; ++i) rc[i] = HEAP8[ptr + i]; return rc; @@ -1187,16 +1190,16 @@ }, /** Equivalent to get(ndx) but coerces the result to an integer. */ - getInt: function(ndx){return this.get(ndx,S.SQLITE_INTEGER)}, + getInt: function(ndx){return this.get(ndx,api.SQLITE_INTEGER)}, /** Equivalent to get(ndx) but coerces the result to a float. */ - getFloat: function(ndx){return this.get(ndx,S.SQLITE_FLOAT)}, + getFloat: function(ndx){return this.get(ndx,api.SQLITE_FLOAT)}, /** Equivalent to get(ndx) but coerces the result to a string. */ - getString: function(ndx){return this.get(ndx,S.SQLITE_TEXT)}, + getString: function(ndx){return this.get(ndx,api.SQLITE_TEXT)}, /** Equivalent to get(ndx) but coerces the result to a Uint8Array. */ - getBlob: function(ndx){return this.get(ndx,S.SQLITE_BLOB)}, + getBlob: function(ndx){return this.get(ndx,api.SQLITE_BLOB)}, /** A convenience wrapper around get() which fetches the value as a string and then, if it is not null, passes it to @@ -1205,16 +1208,17 @@ string, on the other hand, will trigger an exception. */ getJSON: function(ndx){ - const s = this.get(ndx, S.SQLITE_STRING); + const s = this.get(ndx, api.SQLITE_STRING); return null===s ? s : JSON.parse(s); }, /** Returns the result column name of the given index, or throws if index is out of bounds or this statement has been - finalized. + finalized. This can be used without having run step() + first. */ getColumnName: function(ndx){ - return S.sqlite3_column_name( + return api.sqlite3_column_name( affirmColIndex(affirmStmtOpen(this),ndx)._pStmt, ndx ); }, @@ -1230,7 +1234,7 @@ affirmColIndex(affirmStmtOpen(this),0); if(!tgt) tgt = []; for(let i = 0; i < this.columnCount; ++i){ - tgt.push(S.sqlite3_column_name(this._pStmt, i)); + tgt.push(api.sqlite3_column_name(this._pStmt, i)); } return tgt; }, @@ -1242,7 +1246,7 @@ */ getParamIndex: function(name){ return (affirmStmtOpen(this).parameterCount - ? S.sqlite3_bind_parameter_index(this._pStmt, name) + ? api.sqlite3_bind_parameter_index(this._pStmt, name) : undefined); } }/*Stmt.prototype*/; @@ -1250,7 +1254,7 @@ /** OO binding's namespace. */ const SQLite3 = { version: { - lib: S.sqlite3_libversion(), + lib: api.sqlite3_libversion(), ooApi: "0.0.1" }, DB, @@ -1293,7 +1297,7 @@ } const rc = {}, ov = [0,0]; let i = 0, k; - while((k = S.sqlite3_compileoption_get(i++))){ + while((k = api.sqlite3_compileoption_get(i++))){ f._opt(k,ov); rc[ov[0]] = ov[1]; } @@ -1302,19 +1306,19 @@ else if(Array.isArray(optName)){ const rc = {}; optName.forEach((v)=>{ - rc[v] = S.sqlite3_compileoption_used(v); + rc[v] = api.sqlite3_compileoption_used(v); }); return rc; } else if('object' === typeof optName){ Object.keys(optName).forEach((k)=> { - optName[k] = S.sqlite3_compileoption_used(k); + optName[k] = api.sqlite3_compileoption_used(k); }); return optName; } return ( 'string'===typeof optName - ) ? !!S.sqlite3_compileoption_used(optName) : false; + ) ? !!api.sqlite3_compileoption_used(optName) : false; } }; @@ -1322,4 +1326,4 @@ api: api, SQLite3 }; -})(self/*worker or window*/); +})(self/*worker or window*/.Module); diff --git a/ext/fiddle/testing-common.js b/ext/fiddle/testing-common.js index 2701481289..9a51dfad41 100644 --- a/ext/fiddle/testing-common.js +++ b/ext/fiddle/testing-common.js @@ -26,9 +26,6 @@ }; /* emscripten-related bits... */ - const statusElement = E('#module-status'); - const progressElement = E('#module-progress'); - const spinnerElement = E('#module-spinner'); self.Module = { /* ^^^ cannot declare that const because sqlite3.js (auto-generated) includes a decl for it and runs in this @@ -43,25 +40,33 @@ console.error.apply(console, Array.prototype.slice.call(arguments)); }, setStatus: function f(text){ - if(!f.last) f.last = { time: Date.now(), text: '' }; - if(text === f.last.text) return; - const m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/); - const now = Date.now(); - if(m && now - f.last.time < 30) return; // if this is a progress update, skip it if too soon - f.last.time = now; - f.last.text = text; - if(m) { - text = m[1]; - progressElement.value = parseInt(m[2])*100; - progressElement.max = parseInt(m[4])*100; - progressElement.hidden = false; - spinnerElement.hidden = false; - } else { - progressElement.remove(); - if(!text) spinnerElement.remove(); + if(!f.last){ + f.last = { text: '', step: 0 }; + f.ui = { + status: E('#module-status'), + progress: E('#module-progress'), + spinner: E('#module-spinner') + }; + } + if(text === f.last.text) return; + f.last.text = text; + if(f.ui.progress){ + f.ui.progress.value = f.last.step; + f.ui.progress.max = f.last.step + 1; + } + ++f.last.step; + if(text) { + f.ui.status.classList.remove('hidden'); + f.ui.status.innerText = text; + }else{ + if(f.ui.progress){ + f.ui.progress.remove(); + f.ui.spinner.remove(); + delete f.ui.progress; + delete f.ui.spinner; + } + f.ui.status.classList.add('hidden'); } - if(text) statusElement.innerText = text; - else statusElement.remove(); }, totalDependencies: 0, monitorRunDependencies: function(left) { @@ -71,16 +76,33 @@ + '/' + this.totalDependencies + ')') : 'All downloads complete.'); }, - /* Loads sqlite3-api.js and calls the given callback (if - provided), passing it an object which contains the sqlite3 - and SQLite3 modules. Whether this is synchronous or async - depends on whether it's run in the main thread (async) or a - worker (synchronous). */ - loadSqliteAPI: function(callback){ + /** + Loads sqlite3-api.js and calls the given callback (if + provided), passing it an object: + + { + api:sqlite3_c-like API wrapper, + SQLite3: OO wrapper + } + + Whether this is synchronous or async depends on whether + it's run in the main thread (async) or a worker + (synchronous). + + If called after the module has been loaded, it uses a + cached reference, noting that multiple async calls may end + up loading it multiple times. + */ + loadSqliteAPI: function f(callback){ + const namespace = self.Module; + if(namespace.sqlite3){ + if(callback) callback(namespace.sqlite3); + return; + } const theScript = 'sqlite3-api.js'; if(self.importScripts){/*worker*/ importScripts(theScript); - if(callback) callback(self.sqlite3); + if(callback) callback(namespace.sqlite3); }else{/*main thread*/ new Promise((resolve, reject) => { const script = document.createElement('script'); @@ -90,8 +112,7 @@ script.async = true; script.src = theScript; }).then(() => { - if(callback) callback({sqlite3:self.sqlite3, - SQLite3:self.SQLite3}); + if(callback) callback(namespace.sqlite3); }); } } diff --git a/ext/fiddle/testing.css b/ext/fiddle/testing.css new file mode 100644 index 0000000000..f87dbd2cf1 --- /dev/null +++ b/ext/fiddle/testing.css @@ -0,0 +1,31 @@ +textarea { + font-family: monospace; +} +header { + font-size: 130%; + font-weight: bold; +} +.hidden, .initially-hidden { + position: absolute !important; + opacity: 0 !important; + pointer-events: none !important; + display: none !important; +} +fieldset.options { + font-size: 75%; +} +fieldset > legend { + padding: 0 0.5em; +} +span.labeled-input { + padding: 0.25em; + margin: 0.25em 0.5em; + border-radius: 0.25em; + white-space: nowrap; + background: #0002; +} +.center { text-align: center; } +.error { + color: red; + background-color: yellow; +} diff --git a/ext/fiddle/testing1.html b/ext/fiddle/testing1.html index d428f12f65..08a0009c60 100644 --- a/ext/fiddle/testing1.html +++ b/ext/fiddle/testing1.html @@ -4,6 +4,7 @@ + sqlite3-api.js tests diff --git a/ext/fiddle/testing1.js b/ext/fiddle/testing1.js index 5dfc9cd8e9..d35557865d 100644 --- a/ext/fiddle/testing1.js +++ b/ext/fiddle/testing1.js @@ -12,27 +12,15 @@ A basic test script for sqlite3-api.js. */ - -const mainTest1 = function(namespace){ +(function(){ const T = self.SqliteTestUtil; - T.assert(Module._free instanceof Function). - assert(Module.allocate instanceof Function). - assert(Module.addFunction instanceof Function). - assert(Module.removeFunction instanceof Function); - - const S = namespace.sqlite3.api; - const oo = namespace.sqlite3.SQLite3; - console.log("Loaded module:",S.sqlite3_libversion(), - S.sqlite3_sourceid()); - const db = new oo.DB(); const log = console.log.bind(console); - try { + const test1 = function(db,api){ + log("Basic sanity tests..."); T.assert(db._pDb); - log("DB:",db.filename); - log("Build options:",oo.compileOptionUsed()); let st = db.prepare("select 3 as a"); - log("statement =",st); + //log("statement =",st); T.assert(st._pStmt) .assert(!st._mayGet) .assert('a' === st.getColumnName(0)) @@ -43,14 +31,14 @@ const mainTest1 = function(namespace){ .assert(true===st.step()) .assert(3 === st.get(0)) .mustThrow(()=>st.get(1)) - .mustThrow(()=>st.get(0,~S.SQLITE_INTEGER)) - .assert(3 === st.get(0,S.SQLITE_INTEGER)) + .mustThrow(()=>st.get(0,~api.SQLITE_INTEGER)) + .assert(3 === st.get(0,api.SQLITE_INTEGER)) .assert(3 === st.getInt(0)) - .assert('3' === st.get(0,S.SQLITE_TEXT)) + .assert('3' === st.get(0,api.SQLITE_TEXT)) .assert('3' === st.getString(0)) - .assert(3.0 === st.get(0,S.SQLITE_FLOAT)) + .assert(3.0 === st.get(0,api.SQLITE_FLOAT)) .assert(3.0 === st.getFloat(0)) - .assert(st.get(0,S.SQLITE_BLOB) instanceof Uint8Array) + .assert(st.get(0,api.SQLITE_BLOB) instanceof Uint8Array) .assert(st.getBlob(0) instanceof Uint8Array) .assert(3 === st.get([])[0]) .assert(3 === st.get({}).a) @@ -73,7 +61,7 @@ INSERT INTO t(a,b) VALUES(1,2),(3,4),(?,?);`, bind: [5,6] }); T.assert(2 === list.length); - log("Exec'd SQL:", list); + //log("Exec'd SQL:", list); let counter = 0, colNames = []; db.exec("SELECT a a, b b FROM t",{ rowMode: 'object', @@ -95,7 +83,9 @@ INSERT INTO t(a,b) VALUES(1,2),(3,4),(?,?);`, } }); T.assert(6 === counter); + }; + const testUDF = function(db){ log("Testing UDF..."); db.createFunction("foo",function(a,b){return a+b}); T.assert(7===db.selectValue("select foo(3,4)")). @@ -110,6 +100,8 @@ INSERT INTO t(a,b) VALUES(1,2),(3,4),(?,?);`, return rc; } }); + + log("Testing DB::selectValue() w/ UDF..."); T.assert(0===db.selectValue("select bar()")). assert(1===db.selectValue("select bar(1)")). assert(3===db.selectValue("select bar(1,2)")). @@ -120,18 +112,34 @@ INSERT INTO t(a,b) VALUES(1,2),(3,4),(?,?);`, assert(null === db.selectValue("select ?",null)). assert(null === db.selectValue("select ?",[null])). assert(null === db.selectValue("select $a",{$a:null})); - - }finally{ - db.close(); - } - log("Total Test count:",T.counter); -}; + }; -self/*window or worker*/.Module.postRun.push(function(theModule){ - /** Use a timeout so that we are (hopefully) out from under the - module init stack when our setup gets run. */ - - setTimeout(function(){ - theModule.loadSqliteAPI(mainTest1); - },0); -}); + const runTests = function(namespace){ + T.assert(Module._free instanceof Function). + assert(Module.allocate instanceof Function). + assert(Module.addFunction instanceof Function). + assert(Module.removeFunction instanceof Function); + const api = namespace.api; + const oo = namespace.SQLite3; + console.log("Loaded module:",api.sqlite3_libversion(), + api.sqlite3_sourceid()); + log("Build options:",oo.compileOptionUsed()); + const db = new oo.DB(); + try { + log("DB:",db.filename); + [ + test1, testUDF + ].forEach((f)=>f(db, api)); + }finally{ + db.close(); + } + log("Total Test count:",T.counter); + }; + + self.Module.postRun.push(function(theModule){ + /** Use a timeout so that we are (hopefully) out from under the + module init stack when our setup gets run. Just on principle, + not because we _need_ to be. */ + setTimeout(()=>theModule.loadSqliteAPI(runTests), 0); + }); +})(self/*window or worker*/); diff --git a/manifest b/manifest index e9f9fc3988..04cee01095 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C wasm/JS:\sminor\sdoc\supdates,\scorrected\sbind()ing\sof\sthe\sundefined\svalue\sto\sbehave\sas\sdocumented,\sremoved\ssome\ssuperfluous\scode. -D 2022-05-24T01:15:21.052 +C fiddle:\slots\sof\sgeneric\srefactoring,\srestructuring,\sand\scleanup\sin\sthe\shigher-level\scode.\sAdded\spush-fiddle\sext/fiddle/Makefile\starget\sto\spush\sthe\sfiddle\sapp\sto\sa\sremote\sserver\svia\srsync. +D 2022-05-24T14:36:45.563 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -58,17 +58,18 @@ F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be F ext/fiddle/EXPORTED_FUNCTIONS.fiddle 487fc7c83d45c48326f731c89162ed17ab15767e5efede8999d7d6c6e2d04c0f F ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 07b573a1830cb2d38ed347cf2a4139ec3b9c0f69748da6a2d8356b426c807694 F ext/fiddle/EXPORTED_RUNTIME_METHODS ff64aea52779b0d4a838268275fe02adf6f2fdf4d9ce21c22d104bf3d7597398 -F ext/fiddle/Makefile 9277c73e208b9c8093659256c9f07409c877e366480c7c22ec545ee345451d95 +F ext/fiddle/Makefile 8eb51a07b4ff7e5684ca829906233c07d0dccb5d14a9d8b4ec737a2a6f3f0d7e F ext/fiddle/SqliteTestUtil.js e3094833660a6ddd40766b802901b5861b37f0b89c6c577ee0ce4c9d36399e61 F ext/fiddle/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f F ext/fiddle/fiddle-worker.js e87c17070b979bd057a6849332f2a86660a4255ff7f1b6671e3e6026182ffd5a F ext/fiddle/fiddle.html 657c6c3f860c322fba3c69fa4f7a1209e2d2ce44b4bc65a3e154e3a97c047a7c -F ext/fiddle/fiddle.js 68f5bb45fc1ae7f8ae3f6b85f465257db514d12bf50ec492259685178c452a88 +F ext/fiddle/fiddle.js 0263a1ebf7e09ecd8b37ff8e00b9ba27c543b65b6c3dbf2f9def90e6c71c4580 F ext/fiddle/index.md d9c1c308d8074341bc3b11d1d39073cd77754cb3ca9aeb949f23fdd8323d81cf -F ext/fiddle/sqlite3-api.js 3f41887a66d620ae506fea4a735d909c3dc0023045265736958de6d3016fbfc9 -F ext/fiddle/testing-common.js 723aada13d90a5ee3f0f8f5b5b88e46954becae5d2b04ded811d90106057f4ac -F ext/fiddle/testing1.html 026502e5d5e6a250e4101f8e8948708a1295ce831a094d741839ecaf788d8533 -F ext/fiddle/testing1.js b9dd06fd02fbcf947794ceb0bcca1a00e3440d80bf1d819a73bbcac25c87086e +F ext/fiddle/sqlite3-api.js 5492d48b4167179fd979fae99f0c21dc2d0f03460be9ff2d35e62225c58c4c9c +F ext/fiddle/testing-common.js a2527fd8dfb500bad9b434ae2645bb91489792115ee1e1b4b53cac4e9198992a +F ext/fiddle/testing.css 750572dded671d2cf142bbcb27af5542522ac08db128245d0b9fe410aa1d7f2a +F ext/fiddle/testing1.html c00236d71b7f7523b722ae2f79cb2b734e6ed4ff16102fa69974145f6e2bfc95 +F ext/fiddle/testing1.js a2cee7ee12c2e1756e775125b0f9950dc5e5faeeeb4979c6d9894626d90cb5d9 F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b F ext/fts1/ft_hash.h 06df7bba40dadd19597aa400a875dbc2fed705ea @@ -1968,8 +1969,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 70f91fab825d365f505750acdb8d3ae532880c4cdb64d1e61bb21b24a115958b -R aa6cc8d5c8c48a5dcba3187d74399b46 +P 526c8c728019b317624a93f6f07840ca524bca84e7c03ce5e86e38953146236f +R 8d308c6cc994c31188b8c779dc67218e U stephan -Z 0033b446f56e6779d5a11407c4e1444a +Z 3a03c1dbb04138d0aaacfe24b6f85ef3 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 7ae63bdd66..4f241efce6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -526c8c728019b317624a93f6f07840ca524bca84e7c03ce5e86e38953146236f \ No newline at end of file +ed19fef3459499abb0a4a010f368b4576d6e068d930c8480446ea677ac87c1c1 \ No newline at end of file From 73c6ad19203a5dc384a683169a5556bb56cd3547 Mon Sep 17 00:00:00 2001 From: stephan Date: Tue, 24 May 2022 14:45:16 +0000 Subject: [PATCH 082/108] MoUse re descriptive var names in ext/fiddle/Makefile. FossilOrigin-Name: 2f9a42fb141d386f6edd03a37da3b0cef63dcc9fbfd076076b5330a8aa7d45a8 --- ext/fiddle/Makefile | 22 ++++++++++++---------- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/ext/fiddle/Makefile b/ext/fiddle/Makefile index 16f68132ad..841a3febde 100644 --- a/ext/fiddle/Makefile +++ b/ext/fiddle/Makefile @@ -6,26 +6,28 @@ default: clean: make -C ../../ clean-wasm -demo_files = emscripten.css fiddle.html \ +fiddle_files = emscripten.css fiddle.html \ fiddle.js fiddle-module.js \ fiddle-module.wasm fiddle-worker.js -# demo_target is the remote destination for the fiddle app. It +# fiddle_remote is the remote destination for the fiddle app. It # must be a [user@]HOST:/path for rsync. # Note that the target "should probably" contain a symlink of # index.html -> fiddle.html. -demo_target ?= -ifeq (,$(demo_target)) +fiddle_remote ?= +ifeq (,$(fiddle_remote)) ifneq (,$(wildcard /home/stephan)) - demo_target = wh2:www/wh/sqlite3/. + fiddle_remote = wh2:www/wh/sqlite3/. else ifneq (,$(wildcard /home/drh)) - #demo_target = if appropriate, add that user@host:/path here + #fiddle_remote = if appropriate, add that user@host:/path here endif endif -push-fiddle: $(demo_files) - @if [ x = "x$(demo_target)" ]; then \ - echo "demo_target must be a [user@]HOST:/path for rsync"; \ +$(fiddle_files): default + +push-fiddle: $(fiddle_files) + @if [ x = "x$(fiddle_remote)" ]; then \ + echo "fiddle_remote must be a [user@]HOST:/path for rsync"; \ exit 1; \ fi - rsync -va $(demo_files) $(demo_target) + rsync -va $(fiddle_files) $(fiddle_remote) diff --git a/manifest b/manifest index 04cee01095..43d87e8706 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C fiddle:\slots\sof\sgeneric\srefactoring,\srestructuring,\sand\scleanup\sin\sthe\shigher-level\scode.\sAdded\spush-fiddle\sext/fiddle/Makefile\starget\sto\spush\sthe\sfiddle\sapp\sto\sa\sremote\sserver\svia\srsync. -D 2022-05-24T14:36:45.563 +C MoUse\sre\sdescriptive\svar\snames\sin\sext/fiddle/Makefile. +D 2022-05-24T14:45:16.972 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -58,7 +58,7 @@ F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be F ext/fiddle/EXPORTED_FUNCTIONS.fiddle 487fc7c83d45c48326f731c89162ed17ab15767e5efede8999d7d6c6e2d04c0f F ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 07b573a1830cb2d38ed347cf2a4139ec3b9c0f69748da6a2d8356b426c807694 F ext/fiddle/EXPORTED_RUNTIME_METHODS ff64aea52779b0d4a838268275fe02adf6f2fdf4d9ce21c22d104bf3d7597398 -F ext/fiddle/Makefile 8eb51a07b4ff7e5684ca829906233c07d0dccb5d14a9d8b4ec737a2a6f3f0d7e +F ext/fiddle/Makefile 2608fe0c56fa8f9cdf17e28d2be6def550a2fe987db5f7fc06d0210bfc868258 F ext/fiddle/SqliteTestUtil.js e3094833660a6ddd40766b802901b5861b37f0b89c6c577ee0ce4c9d36399e61 F ext/fiddle/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f F ext/fiddle/fiddle-worker.js e87c17070b979bd057a6849332f2a86660a4255ff7f1b6671e3e6026182ffd5a @@ -1969,8 +1969,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 526c8c728019b317624a93f6f07840ca524bca84e7c03ce5e86e38953146236f -R 8d308c6cc994c31188b8c779dc67218e +P ed19fef3459499abb0a4a010f368b4576d6e068d930c8480446ea677ac87c1c1 +R 2d139ba9f84cbb3e77d4faca8388b32a U stephan -Z 3a03c1dbb04138d0aaacfe24b6f85ef3 +Z 17627719ea8f66a25c6ef55c824d9ee0 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 4f241efce6..82be11205d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ed19fef3459499abb0a4a010f368b4576d6e068d930c8480446ea677ac87c1c1 \ No newline at end of file +2f9a42fb141d386f6edd03a37da3b0cef63dcc9fbfd076076b5330a8aa7d45a8 \ No newline at end of file From 6af03b469efdaf57480a4fad0ab35ae19ee8bec5 Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 24 May 2022 16:05:41 +0000 Subject: [PATCH 083/108] When an ON clause on an INNER JOIN references a table to the right of of the join, just convert the ON clause to an ordinary WHERE clause term, in order to be compatible with older versions of SQLite. See [forum:/forumpost/687b0bf563a1d4f1|forum thread 687b0bf563a1d4f1] for details. FossilOrigin-Name: 2b6ebba26d936ae7b9acf7d4bd15e82cbfabda22e1044b3dd838c7b07095100e --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/whereexpr.c | 22 +++++++++++++++------- test/join8.test | 12 ++++++++++++ 4 files changed, 36 insertions(+), 16 deletions(-) diff --git a/manifest b/manifest index 43d87e8706..a6f75bdb85 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C MoUse\sre\sdescriptive\svar\snames\sin\sext/fiddle/Makefile. -D 2022-05-24T14:45:16.972 +C When\san\sON\sclause\son\san\sINNER\sJOIN\sreferences\sa\stable\sto\sthe\sright\sof\nof\sthe\sjoin,\sjust\sconvert\sthe\sON\sclause\sto\san\sordinary\sWHERE\sclause\sterm,\nin\sorder\sto\sbe\scompatible\swith\solder\sversions\sof\sSQLite.\s\sSee\n[forum:/forumpost/687b0bf563a1d4f1|forum\sthread\s687b0bf563a1d4f1]\sfor\sdetails. +D 2022-05-24T16:05:41.137 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -658,7 +658,7 @@ F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b F src/where.c 424b8696c379f57c5a23452e26fbf330f792e61fe096cffabefbf8b18a340385 F src/whereInt.h 8da918f392bf202ccc0ee61291455b33ad171d209445f1ff3eaf62e0b6f6b363 F src/wherecode.c 2a8a73bcf1886632f2b2247c79395f94852a4b74484d8aa70a005892ce73d339 -F src/whereexpr.c efed370c684dce04eab949202c5452bbde993efb198de43c7a88f59411ad2a2c +F src/whereexpr.c 7c5ee52e1df81d6a43f39e6b6f35d540fd37254e2b6e953a4e2715c3abf26f46 F src/window.c fff1b51757438c664e471d5184634e48dcdf8ea34b640f3b1b0810b1e06de18c F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627 @@ -1163,7 +1163,7 @@ F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join5.test d22b6cba8fb59ab3f1c82701434c360705eb12d4ce200c449f37b018fc47681a F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c F test/join7.test 8e72de4b45e5e930d18c305c7efe86015fb2552731e4e03ea226353036b0dab0 -F test/join8.test e46de7f84611663b4ee2fab699d5735af8948386904b0f067263561ee05ae427 +F test/join8.test c73bc91bee9d5f6f5975986bfa29da466347cf2616076e7841d3f198f9361176 F test/join9.test 9056ddd3b0c0f4f9d658f4521038d9a37dc23ead8ca9a505d0b0db2b6a471e05 F test/joinA.test 7eab225dc1c1ab258a5e62513a4ed7cabbd3db971d59d5d92f4fb6fa14c12f6a F test/joinB.test 1b2ba3fc8568b49411787fccbf540570c148e9b6a53a30f80691cb6268098ded @@ -1969,8 +1969,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P ed19fef3459499abb0a4a010f368b4576d6e068d930c8480446ea677ac87c1c1 -R 2d139ba9f84cbb3e77d4faca8388b32a -U stephan -Z 17627719ea8f66a25c6ef55c824d9ee0 +P 2f9a42fb141d386f6edd03a37da3b0cef63dcc9fbfd076076b5330a8aa7d45a8 +R b23285aa9cad2fbb603a6d0b592197f4 +U drh +Z a3136607e1e2d962d7405d0d9fcd3d10 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 82be11205d..1cb0daf032 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2f9a42fb141d386f6edd03a37da3b0cef63dcc9fbfd076076b5330a8aa7d45a8 \ No newline at end of file +2b6ebba26d936ae7b9acf7d4bd15e82cbfabda22e1044b3dd838c7b07095100e \ No newline at end of file diff --git a/src/whereexpr.c b/src/whereexpr.c index 22dd730ef1..38e16b16b3 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -1109,14 +1109,22 @@ static void exprAnalyze( } #endif - if( ExprHasProperty(pExpr, EP_OuterON) ){ + if( ExprHasProperty(pExpr, EP_OuterON|EP_InnerON) ){ Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->w.iJoin); - prereqAll |= x; - extraRight = x-1; /* ON clause terms may not be used with an index - ** on left table of a LEFT JOIN. Ticket #3015 */ - if( (prereqAll>>1)>=x ){ - sqlite3ErrorMsg(pParse, "ON clause references tables to its right"); - return; + if( ExprHasProperty(pExpr, EP_OuterON) ){ + prereqAll |= x; + extraRight = x-1; /* ON clause terms may not be used with an index + ** on left table of a LEFT JOIN. Ticket #3015 */ + if( (prereqAll>>1)>=x ){ + sqlite3ErrorMsg(pParse, "ON clause references tables to its right"); + return; + } + }else if( (prereqAll>>1)>=x ){ + /* The ON clause of an INNER JOIN references a table to its right. + ** Most other SQL database engines raise an error. But all versions + ** of SQLite going back to 3.0.0 have just put the ON clause constraint + ** into the WHERE clause and carried on. */ + ExprClearProperty(pExpr, EP_InnerON); } } pTerm->prereqAll = prereqAll; diff --git a/test/join8.test b/test/join8.test index 388df8fb55..a3e306a05f 100644 --- a/test/join8.test +++ b/test/join8.test @@ -405,5 +405,17 @@ do_catchsql_test join8-12040 { SELECT * FROM t1 LEFT JOIN t2 ON t2.a<>0 NATURAL LEFT JOIN t3; } {0 {0 2 1 2}} +# 2022-05-24 +# https://sqlite.org/forum/forumpost/687b0bf563a1d4f1 +# +reset_db +do_execsql_test join8-13000 { + CREATE TABLE t0(t TEXT, u TEXT); INSERT INTO t0 VALUES('t', 'u'); + CREATE TABLE t1(v TEXT, w TEXT); INSERT INTO t1 VALUES('v', 'w'); + CREATE TABLE t2(x TEXT, y TEXT); INSERT INTO t2 VALUES('x', 'y'); + SELECT * FROM t0 JOIN t1 ON (t2.x NOTNULL) LEFT JOIN t2 ON false; + SELECT * FROM t0 JOIN t1 ON (t2.x NOTNULL) LEFT JOIN t2 ON false + WHERE t2.y ISNULL; +} {} finish_test From de1e02ee52ddcd909024bea66643415e2471416c Mon Sep 17 00:00:00 2001 From: stephan Date: Tue, 24 May 2022 19:01:21 +0000 Subject: [PATCH 084/108] fiddle: initial work on loading a client-side db file. Works but requires some cleanup. Export is not yet implemented. FossilOrigin-Name: 0fa8378c006fcf2311772d36cf2e3c2cd8e8648f671de89ee9832e2e1a06ef49 --- ext/fiddle/fiddle-worker.js | 77 +++++++++++++++++++++++++++++-------- ext/fiddle/fiddle.html | 15 +++++++- ext/fiddle/fiddle.js | 43 ++++++++++++++++++++- ext/fiddle/sqlite3-api.js | 34 +++++++++++++--- manifest | 25 ++++++------ manifest.uuid | 2 +- src/shell.c.in | 16 +++++++- 7 files changed, 173 insertions(+), 39 deletions(-) diff --git a/ext/fiddle/fiddle-worker.js b/ext/fiddle/fiddle-worker.js index 16da63606e..6a687e42cb 100644 --- a/ext/fiddle/fiddle-worker.js +++ b/ext/fiddle/fiddle-worker.js @@ -159,30 +159,73 @@ self.Module = { } }; -const shellExec = function f(sql){ - if(!f._) f._ = Module.cwrap('fiddle_exec', null, ['string']); - if(Module._isDead){ - wMsg('stderr', "shell module has exit()ed. Cannot run SQL."); - return; - } - wMsg('working','start'); - try { - if(f._running) wMsg('stderr','Cannot run multiple commands concurrently.'); - else{ - f._running = true; - f._(sql); +const Sqlite3Shell = { + exec: function f(sql){ + if(!f._) f._ = Module.cwrap('fiddle_exec', null, ['string']); + if(Module._isDead){ + wMsg('stderr', "shell module has exit()ed. Cannot run SQL."); + return; } - } finally { - wMsg('working','end'); - delete f._running; + wMsg('working','start'); + try { + if(f._running) wMsg('stderr','Cannot run multiple commands concurrently.'); + else{ + f._running = true; + f._(sql); + } + } finally { + wMsg('working','end'); + delete f._running; + } + }, + /* Interrupt can't work: this Worker is tied up working, so won't get the + interrupt event which would be needed to perform the interrupt. */ + interrupt: function f(){ + if(!f._) f._ = Module.cwrap('fiddle_interrupt', null); + wMsg('stdout',"Requesting interrupt."); + f._(); } }; -self.onmessage = function(ev){ +self.onmessage = function f(ev){ ev = ev.data; + if(!f.cache){ + f.cache = { + prevFilename: null + }; + } //console.debug("worker: onmessage.data",ev); switch(ev.type){ - case 'shellExec': shellExec(ev.data); return; + case 'shellExec': Sqlite3Shell.exec(ev.data); return; + case 'interrupt': Sqlite3Shell.interrupt(); return; + case 'open': { + /* Expects: { + buffer: ArrayBuffer | Uint8Array, + filename: for logging/informational purposes only + } */ + const opt = ev.data; + let buffer = opt.buffer; + if(buffer instanceof Uint8Array){ + }else if(buffer instanceof ArrayBuffer){ + buffer = new Uint8Array(buffer); + }else{ + wMsg('stderr',"'open' expects {buffer:Uint8Array} containing an uploaded db."); + return; + } + if(f.cache.prevFilename){ + FS.unlink(f.cache.prevFilename); + /* Noting that it might not actually be removed until + the current db handle closes it. */ + f.cache.prevFilename = null; + } + const fn = "db-"+((Math.random() * 10000000) | 0)+ + "-"+((Math.random() * 10000000) | 0)+".sqlite3"; + FS.createDataFile("/", fn, buffer, true, true); + f.cache.prevFilename = fn; + Sqlite3Shell.exec(".open /"+fn); + wMsg('stdout',"Replaced DB with "+(opt.filename || fn)+"."); + return; + } }; console.warn("Unknown fiddle-worker message type:",ev); }; diff --git a/ext/fiddle/fiddle.html b/ext/fiddle/fiddle.html index 52ae2467ec..8db780e4d7 100644 --- a/ext/fiddle/fiddle.html +++ b/ext/fiddle/fiddle.html @@ -76,6 +76,10 @@ fieldset > legend { padding: 0 0.5em; } + fieldset.options > div { + display: flex; + flex-wrap: wrap; + } span.labeled-input { padding: 0.25em; margin: 0.25em 0.5em; @@ -108,7 +112,7 @@ } #view-split { display: flex; - flex-direction: column; + flex-direction: column-reverse; } @@ -161,6 +165,10 @@ data-config='autoClearOutput'> + + + +
@@ -185,6 +193,11 @@ SELECT * FROM t; placeholder="Shell output.">
+ + @@ -71,7 +74,7 @@ display: none !important; } fieldset.options { - font-size: 75%; + font-size: 70%; } fieldset > legend { padding: 0 0.5em; @@ -172,6 +175,9 @@ + + +
@@ -188,7 +194,6 @@ SELECT * FROM t; -
diff --git a/ext/fiddle/fiddle.js b/ext/fiddle/fiddle.js index 54d2be99c3..95f57c15a7 100644 --- a/ext/fiddle/fiddle.js +++ b/ext/fiddle/fiddle.js @@ -79,7 +79,7 @@ f._.value = ''; } if(this.config.echoToConsole) console.log(text); - if(this.jqTerm) window.Module.jqTerm.echo(text); + if(this.jqTerm) this.jqTerm.echo(text); f._.value += text + "\n"; if(this.config.autoScrollOutput){ f._.scrollTop = f._.scrollHeight; @@ -527,7 +527,7 @@ SELECT group_concat(rtrim(t),x'0a') as Mandelbrot FROM a;`} if(window.jQuery && window.jQuery.terminal){ /* Set up the terminal-style view... */ const eTerm = window.jQuery('#view-terminal').empty(); - SF.jqTerm = eTerm.terminal(dbExec,{ + SF.jqTerm = eTerm.terminal(SF.dbExec.bind(SF),{ prompt: 'sqlite> ', greetings: false /* note that the docs incorrectly call this 'greeting' */ }); @@ -535,6 +535,7 @@ SELECT group_concat(rtrim(t),x'0a') as Mandelbrot FROM a;`} const head = E('header#titlebar'); const btnToggleView = document.createElement('button'); btnToggleView.appendChild(document.createTextNode("Toggle View")); + head.appendChild(btnToggleView); btnToggleView.addEventListener('click',function f(){ EAll('.app-view').forEach(e=>e.classList.toggle('hidden')); if(document.body.classList.toggle('terminal-mode')){ diff --git a/manifest b/manifest index 803bf329b9..1b66446908 100644 --- a/manifest +++ b/manifest @@ -1,9 +1,9 @@ -C fiddle:\sadded\ssupport\sfor\sexporting\s(downloading)\sthe\scurrent\sdb\sfile.\sTo\sdo\sthis\swe\shad\sto\sfall\sback\sto\snamed\sdbs,\sinstead\sof\sdefaulting\sto\san\sin-memory\sone,\sbut\sthe\svirtual\sfilesystem\sis\san\sin-memory\sFS,\sso\sthe\send\seffect\sis\sthe\ssame. -D 2022-05-24T22:16:12.220 +C fiddle:\srefactored\sso\sthat\sit\sno\slonger\sexposes\sany\sglobal\ssymbols.\sDoing\sso\swith\sthe\smain\ssqlite3.api\smodule\swill\sbe\smuch\stricker. +D 2022-05-25T03:08:22.772 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 -F Makefile.in dd31c34eb86a7869660f9697694d52c8f1c9705fede9717c59559530b6f0cb87 +F Makefile.in c2fc409d58889d2b4c6cfb28e28d9560d03b459edde2165863ca79742d4679e3 F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241 F Makefile.msc b28a8a7a977e7312f6859f560348e1eb110c21bd6cf9fab0d16537c0a514eef3 F README.md 8b8df9ca852aeac4864eb1e400002633ee6db84065bd01b78c33817f97d31f5e @@ -57,13 +57,13 @@ F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaed F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72 F ext/fiddle/EXPORTED_FUNCTIONS.fiddle 2f7c561af85e6d711fb42f395bc0074b6e6fcf16bc57d495ce4e1c3d0484c5d2 F ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 540b9dec63a3a62a256e2f030827848a92e9b9d9b6fa5c0188295a4a1c5382cd -F ext/fiddle/EXPORTED_RUNTIME_METHODS ff64aea52779b0d4a838268275fe02adf6f2fdf4d9ce21c22d104bf3d7597398 +F ext/fiddle/EXPORTED_RUNTIME_METHODS 4808171d24c601e31d2ea4eb131180e25194d8e78a4f5b24797320c610201e26 F ext/fiddle/Makefile 2608fe0c56fa8f9cdf17e28d2be6def550a2fe987db5f7fc06d0210bfc868258 F ext/fiddle/SqliteTestUtil.js e3094833660a6ddd40766b802901b5861b37f0b89c6c577ee0ce4c9d36399e61 F ext/fiddle/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f -F ext/fiddle/fiddle-worker.js 2c4e323ad5c94b863271d7779436a6e5291d3cc9dd2f5e5d067a22c2a539ff22 -F ext/fiddle/fiddle.html 468723b7a0bbdc92e24990c72e4b8bffdc1a8d605f91b595e36bcd8a6c840ff8 -F ext/fiddle/fiddle.js bc08897ceee8b4f32bb32dabab9c28d5aa1f252a88ac14b51933d6fa36e1c34c +F ext/fiddle/fiddle-worker.js ecfdf9d842f895046338469b30101f312866ca5dc3d3e002ae88b1256898094c +F ext/fiddle/fiddle.html 70796dc8a867448b41bc7e2c5fd6b1865ed8010b3abe22ba0678e8915c062e9a +F ext/fiddle/fiddle.js 931562304cf918b4b88c7095735e8b91896194c918a15afcfba0e5a31e273d63 F ext/fiddle/index.md d9c1c308d8074341bc3b11d1d39073cd77754cb3ca9aeb949f23fdd8323d81cf F ext/fiddle/sqlite3-api.js ce08520b8117e4fbbbeb02d8d047defd4e8507d687e76d20a39f12401bad0219 F ext/fiddle/testing-common.js a2527fd8dfb500bad9b434ae2645bb91489792115ee1e1b4b53cac4e9198992a @@ -1969,8 +1969,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 0fa8378c006fcf2311772d36cf2e3c2cd8e8648f671de89ee9832e2e1a06ef49 -R 39035a17b33485a10b3b4dd052e35f61 +P 7c7fd34c8a05832a3973aaffe696250cb4d2a0b1646c9bfbe83970daf33cd817 +R 51490a036ccbb69f6412426a9f5e3350 U stephan -Z 0fc30b16e829c9b67855feacd792a751 +Z 8dfdf2f1ba6221b5fdaef93177c62735 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index bb0697fefc..4f5e9539de 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7c7fd34c8a05832a3973aaffe696250cb4d2a0b1646c9bfbe83970daf33cd817 \ No newline at end of file +cd227be805d0cd4b6e3c72ed0992ad3aec3db9c366909d9d82c6d3a29009c6eb \ No newline at end of file From d0b22b81c89e1e79e544faf0f2ad9305f5d02bea Mon Sep 17 00:00:00 2001 From: stephan Date: Wed, 25 May 2022 04:20:08 +0000 Subject: [PATCH 088/108] Further minor cleanups and docs in the fiddle app and worker. FossilOrigin-Name: 199e01799dfa48e3fddafb7f2ae5360604150a44186d5c5a977e158ad8e7e657 --- ext/fiddle/fiddle-worker.js | 50 ++++++++++++------------------------- ext/fiddle/fiddle.js | 24 ++++++++++++------ ext/fiddle/testing1.html | 2 +- manifest | 16 ++++++------ manifest.uuid | 2 +- 5 files changed, 43 insertions(+), 51 deletions(-) diff --git a/ext/fiddle/fiddle-worker.js b/ext/fiddle/fiddle-worker.js index 3707e85a84..5c7f7e4fbf 100644 --- a/ext/fiddle/fiddle-worker.js +++ b/ext/fiddle/fiddle-worker.js @@ -102,14 +102,17 @@ }); }; + const stdout = function(){wMsg('stdout', Array.prototype.slice.call(arguments));}; + const stderr = function(){wMsg('stderr', Array.prototype.slice.call(arguments));}; + self.onerror = function(/*message, source, lineno, colno, error*/) { const err = arguments[4]; if(err && 'ExitStatus'==err.name){ /* This is relevant for the sqlite3 shell binding but not the lower-level binding. */ - fiddleModule._isDead = true; - fiddleModule.printErr("FATAL ERROR:", err.message); - fiddleModule.printErr("Restarting the app requires reloading the page."); + fiddleModule.isDead = true; + stderr("FATAL ERROR:", err.message); + stderr("Restarting the app requires reloading the page."); wMsg('error', err); } fiddleModule.setStatus('Exception thrown, see JavaScript console'); @@ -131,7 +134,7 @@ */ exec: function f(sql){ if(!f._) f._ = fiddleModule.cwrap('fiddle_exec', null, ['string']); - if(fiddleModule._isDead){ + if(fiddleModule.isDead){ wMsg('stderr', "shell module has exit()ed. Cannot run SQL."); return; } @@ -240,24 +243,12 @@ emscripten module for use with build mode -sMODULARIZE. */ const fiddleModule = { - /* ^^^ cannot declare that const because fiddle-module.js - (auto-generated) includes a decl for it and runs in this scope. */ - preRun: [], - postRun: [ - /*function(M) { - console.debug("FS=",M.FS); - wMsg('fiddle-ready'); - }*/ - ], - print: function(text){wMsg('stdout', Array.prototype.slice.call(arguments));}, - printErr: function(text){wMsg('stderr', Array.prototype.slice.call(arguments));}, - onRuntimeInitialized: function(M) { - //console.debug("M=",M); - wMsg('fiddle-ready'); - }, + print: stdout, + printErr: stderr, /** - Intercepts status updates from the Module object and fires - worker events with a type of 'status' and a payload of: + Intercepts status updates from the emscripting module init + and fires worker events with a type of 'status' and a + payload of: { text: string | null, // null at end of load process @@ -288,26 +279,17 @@ type:'status', data:{step: ++f.last.step, text: text||null} }); - }, - totalDependencies: 0, - monitorRunDependencies: function(left) { - this.totalDependencies = Math.max(this.totalDependencies, left); - this.setStatus(left - ? ('Preparing... (' + (this.totalDependencies-left) - + '/' + this.totalDependencies + ')') - : 'All downloads complete.'); } }; - - importScripts('fiddle-module.js') - /* loads the wasm module and installs our module init function, - initFiddleModule(). */; + importScripts('fiddle-module.js'); /** initFiddleModule() is installed via fiddle-module.js due to building with: emcc ... -sMODULARIZE=1 -sEXPORT_NAME=initFiddleModule */ - initFiddleModule(fiddleModule); + initFiddleModule(fiddleModule).then(function(thisModule){ + wMsg('fiddle-ready'); + }); })(); diff --git a/ext/fiddle/fiddle.js b/ext/fiddle/fiddle.js index 95f57c15a7..ec2cc4a8ef 100644 --- a/ext/fiddle/fiddle.js +++ b/ext/fiddle/fiddle.js @@ -86,6 +86,8 @@ } }, _msgMap: {}, + /** Adds a worker message handler for messages of the given + type. */ addMsgHandler: function f(type,callback){ if(Array.isArray(type)){ type.forEach((t)=>this.addMsgHandler(t, callback)); @@ -96,6 +98,7 @@ : (this._msgMap[type] = [])).push(callback); return this; }, + /** Given a worker message, runs all handlers for msg.type. */ runMsgHandlers: function(msg){ const list = (this._msgMap.hasOwnProperty(msg.type) ? this._msgMap[msg.type] : false); @@ -107,6 +110,7 @@ list.forEach((f)=>f(msg)); return true; }, + /** Removes all message handlers for the given message type. */ clearMsgHandlers: function(type){ delete this._msgMap[type]; return this; @@ -338,11 +342,14 @@ SF.echo("Exported (possibly auto-downloaded):",ev.filename); window.URL.revokeObjectURL(a.href); a.remove(); - },0); + },500); }); a.click(); }); + /** + Handle load/import of an external db file. + */ E('#load-db').addEventListener('change',function(){ const f = this.files[0]; const r = new FileReader(); @@ -365,7 +372,7 @@ }); r.addEventListener('error',function(){ that.removeAttribute('disabled'); - SF.echo("Loading",f.name,"failed for unknown reason."); + SF.echo("Loading",f.name,"failed for unknown reasons."); }); r.addEventListener('abort',function(){ that.removeAttribute('disabled'); @@ -440,11 +447,12 @@ debounce.$defaultDelay = 500 /*arbitrary*/; const ForceResizeKludge = (function(){ - /* Workaround for Safari mayhem regarding use of vh CSS units.... - We cannot use vh units to set the terminal area size because - Safari chokes on that, so we calculate that height here. Larger - than ~95% is too big for Firefox on Android, causing the input - area to move off-screen. */ + /* Workaround for Safari mayhem regarding use of vh CSS + units.... We cannot use vh units to set the main view + size because Safari chokes on that, so we calculate + that height here. Larger than ~95% is too big for + Firefox on Android, causing the input area to move + off-screen. */ const bcl = document.body.classList; const appViews = EAll('.app-view'); const resized = function f(){ @@ -453,6 +461,8 @@ var ht; var extra = 0; const elemsToCount = [ + /* Elements which we need to always count in the + visible body size. */ E('body > header'), E('body > footer') ]; diff --git a/ext/fiddle/testing1.html b/ext/fiddle/testing1.html index 08a0009c60..f29fb3ce2c 100644 --- a/ext/fiddle/testing1.html +++ b/ext/fiddle/testing1.html @@ -25,8 +25,8 @@
Everything on this page happens in the dev console.
- + diff --git a/manifest b/manifest index 1b66446908..ff64e20864 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C fiddle:\srefactored\sso\sthat\sit\sno\slonger\sexposes\sany\sglobal\ssymbols.\sDoing\sso\swith\sthe\smain\ssqlite3.api\smodule\swill\sbe\smuch\stricker. -D 2022-05-25T03:08:22.772 +C Further\sminor\scleanups\sand\sdocs\sin\sthe\sfiddle\sapp\sand\sworker. +D 2022-05-25T04:20:08.617 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -61,14 +61,14 @@ F ext/fiddle/EXPORTED_RUNTIME_METHODS 4808171d24c601e31d2ea4eb131180e25194d8e78a F ext/fiddle/Makefile 2608fe0c56fa8f9cdf17e28d2be6def550a2fe987db5f7fc06d0210bfc868258 F ext/fiddle/SqliteTestUtil.js e3094833660a6ddd40766b802901b5861b37f0b89c6c577ee0ce4c9d36399e61 F ext/fiddle/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f -F ext/fiddle/fiddle-worker.js ecfdf9d842f895046338469b30101f312866ca5dc3d3e002ae88b1256898094c +F ext/fiddle/fiddle-worker.js 6000da12965319bed53d546f87885a6717a0cd8de0b4832edde7a95e63d1f33e F ext/fiddle/fiddle.html 70796dc8a867448b41bc7e2c5fd6b1865ed8010b3abe22ba0678e8915c062e9a -F ext/fiddle/fiddle.js 931562304cf918b4b88c7095735e8b91896194c918a15afcfba0e5a31e273d63 +F ext/fiddle/fiddle.js 45f96ac7f7d6678503568dded46afaa741d841a2464519035636da0fd77aec50 F ext/fiddle/index.md d9c1c308d8074341bc3b11d1d39073cd77754cb3ca9aeb949f23fdd8323d81cf F ext/fiddle/sqlite3-api.js ce08520b8117e4fbbbeb02d8d047defd4e8507d687e76d20a39f12401bad0219 F ext/fiddle/testing-common.js a2527fd8dfb500bad9b434ae2645bb91489792115ee1e1b4b53cac4e9198992a F ext/fiddle/testing.css 750572dded671d2cf142bbcb27af5542522ac08db128245d0b9fe410aa1d7f2a -F ext/fiddle/testing1.html c00236d71b7f7523b722ae2f79cb2b734e6ed4ff16102fa69974145f6e2bfc95 +F ext/fiddle/testing1.html 6c9321f68d90f942bdf51bbbfa7497113b203b85e45ef65e31d7cca3ce460366 F ext/fiddle/testing1.js a2cee7ee12c2e1756e775125b0f9950dc5e5faeeeb4979c6d9894626d90cb5d9 F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b @@ -1969,8 +1969,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 7c7fd34c8a05832a3973aaffe696250cb4d2a0b1646c9bfbe83970daf33cd817 -R 51490a036ccbb69f6412426a9f5e3350 +P cd227be805d0cd4b6e3c72ed0992ad3aec3db9c366909d9d82c6d3a29009c6eb +R 89c5ae72ffcf082aa75015e7b32399c7 U stephan -Z 8dfdf2f1ba6221b5fdaef93177c62735 +Z 3072b7cf3dc542f70a2622c2abe8aee2 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 4f5e9539de..42e8b35117 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cd227be805d0cd4b6e3c72ed0992ad3aec3db9c366909d9d82c6d3a29009c6eb \ No newline at end of file +199e01799dfa48e3fddafb7f2ae5360604150a44186d5c5a977e158ad8e7e657 \ No newline at end of file From e599cc427f72c117d08e56387f7cd556a88829b8 Mon Sep 17 00:00:00 2001 From: stephan Date: Wed, 25 May 2022 04:38:35 +0000 Subject: [PATCH 089/108] Renamed EXPORTED_FUNCTIONS.sqlite3 to EXPORTED_FUNCTIONS.sqlite3-api to avoid any potential confusion about that file (not) being an sqlite3 database. FossilOrigin-Name: 3d6245c6f9f2ef4ca6746639d300cc5795598b119034439dfed671de3da638fb --- Makefile.in | 8 +++++--- ...ONS.sqlite3 => EXPORTED_FUNCTIONS.sqlite3-api} | 0 manifest | 15 +++++++-------- manifest.uuid | 2 +- 4 files changed, 13 insertions(+), 12 deletions(-) rename ext/fiddle/{EXPORTED_FUNCTIONS.sqlite3 => EXPORTED_FUNCTIONS.sqlite3-api} (100%) diff --git a/Makefile.in b/Makefile.in index b49c987bfe..895417f143 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1537,7 +1537,8 @@ clean: clean-wasm emcc_opt = -Oz emcc_flags = $(emcc_opt) -sALLOW_TABLE_GROWTH -I. $(SHELL_OPT) $(fiddle_module_js): Makefile sqlite3.c shell.c \ - $(fiddle_dir)/EXPORTED_RUNTIME_METHODS $(fiddle_dir)/EXPORTED_FUNCTIONS.fiddle + $(fiddle_dir)/EXPORTED_RUNTIME_METHODS \ + $(fiddle_dir)/EXPORTED_FUNCTIONS.fiddle emcc -o $@ $(emcc_flags) \ -sMODULARIZE \ -sEXPORT_NAME=initFiddleModule \ @@ -1546,10 +1547,11 @@ $(fiddle_module_js): Makefile sqlite3.c shell.c \ -sEXPORTED_FUNCTIONS=@$(fiddle_dir_abs)/EXPORTED_FUNCTIONS.fiddle \ sqlite3.c shell.c $(sqlite3_wasm_js): Makefile sqlite3.c \ - $(fiddle_dir)/EXPORTED_RUNTIME_METHODS $(fiddle_dir)/EXPORTED_FUNCTIONS.sqlite3 + $(fiddle_dir)/EXPORTED_RUNTIME_METHODS \ + $(fiddle_dir)/EXPORTED_FUNCTIONS.sqlite3-api emcc -o $@ $(emcc_flags) \ -sEXPORTED_RUNTIME_METHODS=@$(fiddle_dir_abs)/EXPORTED_RUNTIME_METHODS \ - -sEXPORTED_FUNCTIONS=@$(fiddle_dir_abs)/EXPORTED_FUNCTIONS.sqlite3 \ + -sEXPORTED_FUNCTIONS=@$(fiddle_dir_abs)/EXPORTED_FUNCTIONS.sqlite3-api \ --no-entry \ sqlite3.c fiddle: $(fiddle_module_js) diff --git a/ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 b/ext/fiddle/EXPORTED_FUNCTIONS.sqlite3-api similarity index 100% rename from ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 rename to ext/fiddle/EXPORTED_FUNCTIONS.sqlite3-api diff --git a/manifest b/manifest index 67dacef8b5..d36a612630 100644 --- a/manifest +++ b/manifest @@ -1,9 +1,9 @@ -C Add\sthe\sability\sto\simport/export\sdb\sfiles\sinto/from\sfiddle. -D 2022-05-25T04:35:22.243 +C Renamed\sEXPORTED_FUNCTIONS.sqlite3\sto\sEXPORTED_FUNCTIONS.sqlite3-api\sto\savoid\sany\spotential\sconfusion\sabout\sthat\sfile\s(not)\sbeing\san\ssqlite3\sdatabase. +D 2022-05-25T04:38:35.081 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 -F Makefile.in c2fc409d58889d2b4c6cfb28e28d9560d03b459edde2165863ca79742d4679e3 +F Makefile.in 335ac492dc602e7a7da3be3df020eac3b439a07cbdcf00a71b58304d7068257f F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241 F Makefile.msc b28a8a7a977e7312f6859f560348e1eb110c21bd6cf9fab0d16537c0a514eef3 F README.md 8b8df9ca852aeac4864eb1e400002633ee6db84065bd01b78c33817f97d31f5e @@ -56,7 +56,7 @@ F ext/expert/sqlite3expert.c 6ca30d73b9ed75bd56d6e0d7f2c962d2affaa72c505458619d0 F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72 F ext/fiddle/EXPORTED_FUNCTIONS.fiddle 2f7c561af85e6d711fb42f395bc0074b6e6fcf16bc57d495ce4e1c3d0484c5d2 -F ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 540b9dec63a3a62a256e2f030827848a92e9b9d9b6fa5c0188295a4a1c5382cd +F ext/fiddle/EXPORTED_FUNCTIONS.sqlite3-api 540b9dec63a3a62a256e2f030827848a92e9b9d9b6fa5c0188295a4a1c5382cd w ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 F ext/fiddle/EXPORTED_RUNTIME_METHODS b831017ba67ba993b34a27400cef2f6095bd6789c0fc4eba7e7a251c207be31c F ext/fiddle/Makefile 2608fe0c56fa8f9cdf17e28d2be6def550a2fe987db5f7fc06d0210bfc868258 F ext/fiddle/SqliteTestUtil.js e3094833660a6ddd40766b802901b5861b37f0b89c6c577ee0ce4c9d36399e61 @@ -1969,9 +1969,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 2b6ebba26d936ae7b9acf7d4bd15e82cbfabda22e1044b3dd838c7b07095100e 199e01799dfa48e3fddafb7f2ae5360604150a44186d5c5a977e158ad8e7e657 -R aee4bfef4ef9203a44b8e6cdf71dd6f9 -T +closed 199e01799dfa48e3fddafb7f2ae5360604150a44186d5c5a977e158ad8e7e657 Closed\sby\sintegrate-merge. +P e0c30438a4f1372afb93a0488bae17b3f85d535717b215f494a83ae909871d2c +R 9374645be385492e5cf981b1ed91722a U stephan -Z 2998fcf747653a641a36368e5e5a2641 +Z 0e306e7b329adee899bf0b24535c7b65 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index db33fc9940..85e8b2e4a1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e0c30438a4f1372afb93a0488bae17b3f85d535717b215f494a83ae909871d2c \ No newline at end of file +3d6245c6f9f2ef4ca6746639d300cc5795598b119034439dfed671de3da638fb \ No newline at end of file From 26542e722bcdd9511b75cbc8cbf4720c01780632 Mon Sep 17 00:00:00 2001 From: stephan Date: Wed, 25 May 2022 08:51:07 +0000 Subject: [PATCH 090/108] Got the sqlite3-api JS bits wrapped up in deferred-load module. Whether that's going to be easier to use, in practice, remains to be seen. Consolidated two of the test-related JS files. FossilOrigin-Name: dd83cc05f2522d221641807dd66b33df48ac9264f27e5b6f63f312084f109801 --- Makefile.in | 7 +- ext/fiddle/Makefile | 4 +- ext/fiddle/SqliteTestUtil.js | 190 ++++++++++++++++++++++++++--------- ext/fiddle/sqlite3-api.js | 82 ++++++++------- ext/fiddle/testing-common.js | 121 ---------------------- ext/fiddle/testing1.html | 5 +- ext/fiddle/testing1.js | 32 ++++-- manifest | 25 +++-- manifest.uuid | 2 +- 9 files changed, 230 insertions(+), 238 deletions(-) delete mode 100644 ext/fiddle/testing-common.js diff --git a/Makefile.in b/Makefile.in index 895417f143..31579970a5 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1540,18 +1540,23 @@ $(fiddle_module_js): Makefile sqlite3.c shell.c \ $(fiddle_dir)/EXPORTED_RUNTIME_METHODS \ $(fiddle_dir)/EXPORTED_FUNCTIONS.fiddle emcc -o $@ $(emcc_flags) \ + -sENVIRONMENT=web \ -sMODULARIZE \ -sEXPORT_NAME=initFiddleModule \ - -sENVIRONMENT=web \ -sEXPORTED_RUNTIME_METHODS=@$(fiddle_dir_abs)/EXPORTED_RUNTIME_METHODS \ -sEXPORTED_FUNCTIONS=@$(fiddle_dir_abs)/EXPORTED_FUNCTIONS.fiddle \ sqlite3.c shell.c $(sqlite3_wasm_js): Makefile sqlite3.c \ + $(fiddle_dir)/sqlite3-api.js \ $(fiddle_dir)/EXPORTED_RUNTIME_METHODS \ $(fiddle_dir)/EXPORTED_FUNCTIONS.sqlite3-api emcc -o $@ $(emcc_flags) \ + -sENVIRONMENT=web \ + -sMODULARIZE \ + -sEXPORT_NAME=initSqlite3Module \ -sEXPORTED_RUNTIME_METHODS=@$(fiddle_dir_abs)/EXPORTED_RUNTIME_METHODS \ -sEXPORTED_FUNCTIONS=@$(fiddle_dir_abs)/EXPORTED_FUNCTIONS.sqlite3-api \ + --post-js=$(fiddle_dir)/sqlite3-api.js \ --no-entry \ sqlite3.c fiddle: $(fiddle_module_js) diff --git a/ext/fiddle/Makefile b/ext/fiddle/Makefile index 841a3febde..6f3279b61a 100644 --- a/ext/fiddle/Makefile +++ b/ext/fiddle/Makefile @@ -1,10 +1,10 @@ # This GNU makefile exists primarily to simplify/speed up development # from emacs. It is not part of the canonical build process. default: - make -C ../.. wasm -e emcc_opt=-O0 + $(MAKE) -C ../.. wasm -e emcc_opt=-O0 clean: - make -C ../../ clean-wasm + $(MAKE) -C ../../ clean-wasm fiddle_files = emscripten.css fiddle.html \ fiddle.js fiddle-module.js \ diff --git a/ext/fiddle/SqliteTestUtil.js b/ext/fiddle/SqliteTestUtil.js index 964e60b215..cf78946dc7 100644 --- a/ext/fiddle/SqliteTestUtil.js +++ b/ext/fiddle/SqliteTestUtil.js @@ -1,54 +1,144 @@ -/** - Helpers for writing sqlite3-specific tests. +/* + 2022-05-22 + + The author disclaims copyright to this source code. In place of a + legal notice, here is a blessing: + + * May you do good and not evil. + * May you find forgiveness for yourself and forgive others. + * May you share freely, never taking more than you give. + + *********************************************************************** + + This file contains bootstrapping code used by various test scripts + which live in this file's directory. */ -self/*window or worker*/.SqliteTestUtil = { - /** Running total of the number of tests run via - this API. */ - counter: 0, +(function(){ + /* querySelectorAll() proxy */ + const EAll = function(/*[element=document,] cssSelector*/){ + return (arguments.length>1 ? arguments[0] : document) + .querySelectorAll(arguments[arguments.length-1]); + }; + /* querySelector() proxy */ + const E = function(/*[element=document,] cssSelector*/){ + return (arguments.length>1 ? arguments[0] : document) + .querySelector(arguments[arguments.length-1]); + }; + /** - If expr is a function, it is called and its result - is returned, coerced to a bool, else expr, coerced to - a bool, is returned. + Helpers for writing sqlite3-specific tests. */ - toBool: function(expr){ - return (expr instanceof Function) ? !!expr() : !!expr; - }, - /** abort() if expr is false. If expr is a function, it - is called and its result is evaluated. + self/*window or worker*/.SqliteTestUtil = { + /** Running total of the number of tests run via + this API. */ + counter: 0, + /** + If expr is a function, it is called and its result + is returned, coerced to a bool, else expr, coerced to + a bool, is returned. + */ + toBool: function(expr){ + return (expr instanceof Function) ? !!expr() : !!expr; + }, + /** abort() if expr is false. If expr is a function, it + is called and its result is evaluated. + */ + assert: function f(expr, msg){ + if(!f._){ + f._ = ('undefined'===typeof abort + ? (msg)=>{throw new Error(msg)} + : abort); + } + ++this.counter; + if(!this.toBool(expr)){ + f._(msg || "Assertion failed."); + } + return this; + }, + /** Identical to assert() but throws instead of calling + abort(). */ + affirm: function(expr, msg){ + ++this.counter; + if(!this.toBool(expr)) throw new Error(msg || "Affirmation failed."); + return this; + }, + /** Calls f() and squelches any exception it throws. If it + does not throw, this function throws. */ + mustThrow: function(f, msg){ + ++this.counter; + let err; + try{ f(); } catch(e){err=e;} + if(!err) throw new Error(msg || "Expected exception."); + return this; + }, + /** Throws if expr is truthy or expr is a function and expr() + returns truthy. */ + throwIf: function(expr, msg){ + ++this.counter; + if(this.toBool(expr)) throw new Error(msg || "throwIf() failed"); + return this; + }, + /** Throws if expr is falsy or expr is a function and expr() + returns falsy. */ + throwUnless: function(expr, msg){ + ++this.counter; + if(!this.toBool(expr)) throw new Error(msg || "throwUnless() failed"); + return this; + } + }; + + + /** + This is a module object for use with the emscripten-installed + initSqlite3Module() factory function. */ - assert: function(expr, msg){ - ++this.counter; - if(!this.toBool(expr)) abort(msg || "Assertion failed."); - return this; - }, - /** Identical to assert() but throws instead of calling - abort(). */ - affirm: function(expr, msg){ - ++this.counter; - if(!this.toBool(expr)) throw new Error(msg || "Affirmation failed."); - return this; - }, - /** Calls f() and squelches any exception it throws. If it - does not throw, this function throws. */ - mustThrow: function(f, msg){ - ++this.counter; - let err; - try{ f(); } catch(e){err=e;} - if(!err) throw new Error(msg || "Expected exception."); - return this; - }, - /** Throws if expr is truthy or expr is a function and expr() - returns truthy. */ - throwIf: function(expr, msg){ - ++this.counter; - if(this.toBool(expr)) throw new Error(msg || "throwIf() failed"); - return this; - }, - /** Throws if expr is falsy or expr is a function and expr() - returns falsy. */ - throwUnless: function(expr, msg){ - ++this.counter; - if(!this.toBool(expr)) throw new Error(msg || "throwUnless() failed"); - return this; - } -}; + self.sqlite3TestModule = { + postRun: [ + /* function(theModule){...} */ + ], + //onRuntimeInitialized: function(){}, + /* Proxy for C-side stdout output. */ + print: function(){ + console.log.apply(console, Array.prototype.slice.call(arguments)); + }, + /* Proxy for C-side stderr output. */ + printErr: function(){ + console.error.apply(console, Array.prototype.slice.call(arguments)); + }, + /** + Called by the module init bits to report loading + progress. It gets passed an empty argument when loading is + done (after onRuntimeInitialized() and any this.postRun + callbacks have been run). + */ + setStatus: function f(text){ + if(!f.last){ + f.last = { text: '', step: 0 }; + f.ui = { + status: E('#module-status'), + progress: E('#module-progress'), + spinner: E('#module-spinner') + }; + } + if(text === f.last.text) return; + f.last.text = text; + if(f.ui.progress){ + f.ui.progress.value = f.last.step; + f.ui.progress.max = f.last.step + 1; + } + ++f.last.step; + if(text) { + f.ui.status.classList.remove('hidden'); + f.ui.status.innerText = text; + }else{ + if(f.ui.progress){ + f.ui.progress.remove(); + f.ui.spinner.remove(); + delete f.ui.progress; + delete f.ui.spinner; + } + f.ui.status.classList.add('hidden'); + } + } + }; +})(self/*window or worker*/); diff --git a/ext/fiddle/sqlite3-api.js b/ext/fiddle/sqlite3-api.js index 7dff49980b..d88ec9a8b8 100644 --- a/ext/fiddle/sqlite3-api.js +++ b/ext/fiddle/sqlite3-api.js @@ -10,40 +10,45 @@ *********************************************************************** - This file is intended to be loaded after loading sqlite3.wasm. It - sets up one of any number of potential bindings using that API, this - one as closely matching the C-native API as is feasible in JS. + This file is intended to be appended to the emcc-generated + sqlite3.js via emcc: - Note that this file is not named sqlite3.js because that file gets - generated by emscripten as the JS-glue counterpart of sqlite3.wasm. + emcc ... -sMODULARIZE -sEXPORT_NAME=initSqlite3Module --post-js=THIS_FILE - This code installs an object named self.Module.sqlite3, where self - is expected to be either the global window or Worker object and - Module is the object set up by the emscripten infrastructure. The - sqlite3 object looks like: + It is loaded by importing the emcc-generated sqlite3.js, then: - { - api: bindings for much of the core sqlite3 APIs, - SQLite3: high-level OO API wrapper - } + initSqlite3Module({module object}).then( + function(theModule){ + theModule.sqlite3 == an object containing this file's + deliverables: + { + api: bindings for much of the core sqlite3 APIs, + SQLite3: high-level OO API wrapper + } + }); - The way we export this module is not _really_ modern-JS-friendly - because it exports/relies on a global symbol (which is admittedly - not ideal). Exporting it "cleanly," without introducing any - global-scope symbols, requires using a module loader in all client - code. As there are several different approaches, none of which this - developer is currently truly familiar with, the current approach - will have to do for the time being. + It is up to the caller to provide a module object compatible with + emcc, but it can be a plain empty object. The object passed to + initSqlite3Module() will get populated by the emscripten-generated + bits and, in part, by the code from this file. Specifically, this file + installs the `theModule.sqlite3` part shown above. + + The resulting sqlite3.api object wraps the standard sqlite3 C API in + a way as close to its native form as JS allows for. The + sqlite3.SQLite3 object provides a higher-level wrapper more + appropriate for general client-side use in JS. Because using certain parts of the low-level API properly requires some degree of WASM-related magic, it is not recommended that that API be used as-is in client-level code. Rather, client code should use the higher-level OO API or write a custom wrapper on top of the - lower-level API. In short, using any C-style APIs which take + lower-level API. In short, most of the C-style API is used in an + intuitive manner from JS but any C-style APIs which take pointers-to-pointer arguments require WASM-specific interfaces installed by emcscripten-generated code. Those which take or return only integers, doubles, strings, or "plain" pointers to db or - statement objects can be used in a straightforward manner. + statement objects can be used in "as normal," noting that "pointers" + in wasm are simply 32-bit integers. # Goals and Non-goals of this API @@ -77,7 +82,10 @@ modern web and requires modern platforms. */ -(function(namespace){ +if(!Module.postRun) Module.postRun = []; +/* ^^^^ the name Module is, in this setup, scope-local in the generated + file sqlite3.js, with which this file gets combined at build-time. */ +Module.postRun.push(function(namespace){ 'use strict'; /* For reference: sql.js does essentially everything we want and it solves much of the wasm-related voodoo, but we'll need a @@ -111,6 +119,8 @@ clear and much experimentation is pending. */ + const SQM = namespace/*the sqlite module object */; + /** Set up the main sqlite3 binding API here, mimicking the C API as closely as we can. @@ -157,7 +167,7 @@ will only support UTF8. */ SQLITE_UTF8: 1 }; - const cwrap = Module.cwrap; + const cwrap = SQM.cwrap; [/* C-side functions to bind. Each entry is an array with 3 or 4 elements: @@ -237,7 +247,6 @@ const k = (4==a.length) ? a.shift() : a[0]; api[k] = cwrap.apply(this, a); }); - //console.debug("libversion =",api.sqlite3_libversion()); /* What follows is colloquially known as "OO API #1". It is a binding of the sqlite3 API which is designed to be run within @@ -418,7 +427,7 @@ delete that._statements[k]; if(s && s._pStmt) s.finalize(); }); - Object.values(this._udfs).forEach(Module.removeFunction); + Object.values(this._udfs).forEach(SQM.removeFunction); delete this._udfs; delete this._statements; delete this.filename; @@ -562,7 +571,7 @@ (opt.callback && opt.rowMode) ? opt.rowMode : false); try{ - let pSql = allocateUTF8OnStack(arg.sql) + let pSql = SQM.allocateUTF8OnStack(arg.sql) const pzTail = stackAlloc(4); while(getValue(pSql, "i8")){ setValue(pPtrArg, 0, "i32"); @@ -731,9 +740,10 @@ api.sqlite3_result_null(pCx); break; }else if(undefined!==val.length){ - const pBlob = Module.allocate(val, ALLOC_NORMAL); + const pBlob = + SQM.allocate(val, SQM.ALLOC_NORMAL); api.sqlite3_result_blob(pCx, pBlob, val.length, -1/*==SQLITE_TRANSIENT*/); - Module._free(blobptr); + SQM._free(blobptr); break; } // else fall through @@ -749,7 +759,7 @@ api.sqlite3_result_error(pCx, e.message, -1); } }; - const pUdf = Module.addFunction(wrapper, "viii"); + const pUdf = SQM.addFunction(wrapper, "viii"); let fFlags = 0; if(getOwnOption(opt, 'deterministic')) fFlags |= api.SQLITE_DETERMINISTIC; if(getOwnOption(opt, 'directOnly')) fFlags |= api.SQLITE_DIRECTONLY; @@ -762,11 +772,11 @@ api.SQLITE_UTF8 | fFlags, null/*pApp*/, pUdf, null/*xStep*/, null/*xFinal*/, null/*xDestroy*/)); }catch(e){ - Module.removeFunction(pUdf); + SQM.removeFunction(pUdf); throw e; } if(this._udfs.hasOwnProperty(name)){ - Module.removeFunction(this._udfs[name]); + SQM.removeFunction(this._udfs[name]); } this._udfs[name] = pUdf; return this; @@ -911,7 +921,7 @@ f._ = { string: function(stmt, ndx, val, asBlob){ const bytes = intArrayFromString(val,true); - const pStr = Module.allocate(bytes, ALLOC_NORMAL); + const pStr = SQM.allocate(bytes, ALLOC_NORMAL); stmt._allocs.push(pStr); const func = asBlob ? api.sqlite3_bind_blob : api.sqlite3_bind_text; return func(stmt._pStmt, ndx, pStr, bytes.length, 0); @@ -950,7 +960,7 @@ toss("Binding a value as a blob requires", "that it have a length member."); } - const pBlob = Module.allocate(val, ALLOC_NORMAL); + const pBlob = SQM.allocate(val, ALLOC_NORMAL); stmt._allocs.push(pBlob); rc = api.sqlite3_bind_blob(stmt._pStmt, ndx, pBlob, len, 0); } @@ -966,7 +976,7 @@ const freeBindMemory = function(stmt){ let m; while(undefined !== (m = stmt._allocs.pop())){ - Module._free(m); + SQM._free(m); } return stmt; }; @@ -1383,4 +1393,4 @@ api: api, SQLite3 }; -})(self/*worker or window*/.Module); +}); diff --git a/ext/fiddle/testing-common.js b/ext/fiddle/testing-common.js deleted file mode 100644 index 9a51dfad41..0000000000 --- a/ext/fiddle/testing-common.js +++ /dev/null @@ -1,121 +0,0 @@ -/* - 2022-05-22 - - The author disclaims copyright to this source code. In place of a - legal notice, here is a blessing: - - * May you do good and not evil. - * May you find forgiveness for yourself and forgive others. - * May you share freely, never taking more than you give. - - *********************************************************************** - - This file contains bootstrapping code used by various test scripts - which live in this file's directory. -*/ -(function(){ - /* querySelectorAll() proxy */ - const EAll = function(/*[element=document,] cssSelector*/){ - return (arguments.length>1 ? arguments[0] : document) - .querySelectorAll(arguments[arguments.length-1]); - }; - /* querySelector() proxy */ - const E = function(/*[element=document,] cssSelector*/){ - return (arguments.length>1 ? arguments[0] : document) - .querySelector(arguments[arguments.length-1]); - }; - - /* emscripten-related bits... */ - self.Module = { - /* ^^^ cannot declare that const because sqlite3.js - (auto-generated) includes a decl for it and runs in this - scope. */ - preRun: [], - postRun: [], - //onRuntimeInitialized: function(){}, - print: function(){ - console.log.apply(console, Array.prototype.slice.call(arguments)); - }, - printErr: function(){ - console.error.apply(console, Array.prototype.slice.call(arguments)); - }, - setStatus: function f(text){ - if(!f.last){ - f.last = { text: '', step: 0 }; - f.ui = { - status: E('#module-status'), - progress: E('#module-progress'), - spinner: E('#module-spinner') - }; - } - if(text === f.last.text) return; - f.last.text = text; - if(f.ui.progress){ - f.ui.progress.value = f.last.step; - f.ui.progress.max = f.last.step + 1; - } - ++f.last.step; - if(text) { - f.ui.status.classList.remove('hidden'); - f.ui.status.innerText = text; - }else{ - if(f.ui.progress){ - f.ui.progress.remove(); - f.ui.spinner.remove(); - delete f.ui.progress; - delete f.ui.spinner; - } - f.ui.status.classList.add('hidden'); - } - }, - totalDependencies: 0, - monitorRunDependencies: function(left) { - this.totalDependencies = Math.max(this.totalDependencies, left); - this.setStatus(left - ? ('Preparing... (' + (this.totalDependencies-left) - + '/' + this.totalDependencies + ')') - : 'All downloads complete.'); - }, - /** - Loads sqlite3-api.js and calls the given callback (if - provided), passing it an object: - - { - api:sqlite3_c-like API wrapper, - SQLite3: OO wrapper - } - - Whether this is synchronous or async depends on whether - it's run in the main thread (async) or a worker - (synchronous). - - If called after the module has been loaded, it uses a - cached reference, noting that multiple async calls may end - up loading it multiple times. - */ - loadSqliteAPI: function f(callback){ - const namespace = self.Module; - if(namespace.sqlite3){ - if(callback) callback(namespace.sqlite3); - return; - } - const theScript = 'sqlite3-api.js'; - if(self.importScripts){/*worker*/ - importScripts(theScript); - if(callback) callback(namespace.sqlite3); - }else{/*main thread*/ - new Promise((resolve, reject) => { - const script = document.createElement('script'); - document.body.appendChild(script); - script.onload = resolve; - script.onerror = reject; - script.async = true; - script.src = theScript; - }).then(() => { - if(callback) callback(namespace.sqlite3); - }); - } - } - }; - -})(self/*window or worker*/); diff --git a/ext/fiddle/testing1.html b/ext/fiddle/testing1.html index ce0e4c8fd8..bf22f30ff3 100644 --- a/ext/fiddle/testing1.html +++ b/ext/fiddle/testing1.html @@ -26,9 +26,8 @@
Everything on this page happens in the dev console.
- - - + + diff --git a/ext/fiddle/testing1.js b/ext/fiddle/testing1.js index d35557865d..9216db1341 100644 --- a/ext/fiddle/testing1.js +++ b/ext/fiddle/testing1.js @@ -16,7 +16,14 @@ const T = self.SqliteTestUtil; const log = console.log.bind(console); - const test1 = function(db,api){ + const assert = function(condition, text) { + if (!condition) { + throw new Error('Assertion failed' + (text ? ': ' + text : '')); + } + }; + + const test1 = function(db,sqlite3){ + const api = sqlite3.api; log("Basic sanity tests..."); T.assert(db._pDb); let st = db.prepare("select 3 as a"); @@ -114,13 +121,14 @@ INSERT INTO t(a,b) VALUES(1,2),(3,4),(?,?);`, assert(null === db.selectValue("select $a",{$a:null})); }; - const runTests = function(namespace){ + const runTests = function(Module){ T.assert(Module._free instanceof Function). assert(Module.allocate instanceof Function). assert(Module.addFunction instanceof Function). assert(Module.removeFunction instanceof Function); - const api = namespace.api; - const oo = namespace.SQLite3; + const sqlite3 = Module.sqlite3; + const api = sqlite3.api; + const oo = sqlite3.SQLite3; console.log("Loaded module:",api.sqlite3_libversion(), api.sqlite3_sourceid()); log("Build options:",oo.compileOptionUsed()); @@ -129,17 +137,19 @@ INSERT INTO t(a,b) VALUES(1,2),(3,4),(?,?);`, log("DB:",db.filename); [ test1, testUDF - ].forEach((f)=>f(db, api)); + ].forEach((f)=>f(db, sqlite3)); }finally{ db.close(); } log("Total Test count:",T.counter); }; - self.Module.postRun.push(function(theModule){ - /** Use a timeout so that we are (hopefully) out from under the - module init stack when our setup gets run. Just on principle, - not because we _need_ to be. */ - setTimeout(()=>theModule.loadSqliteAPI(runTests), 0); + initSqlite3Module(self.sqlite3TestModule).then(function(theModule){ + /** Use a timeout so that we are (hopefully) out from + under the module init stack when our setup gets + run. Just on principle, not because we _need_ to + be. */ + //console.debug("theModule =",theModule); + setTimeout(()=>runTests(theModule), 0); }); -})(self/*window or worker*/); +})(); diff --git a/manifest b/manifest index d36a612630..447c8c5092 100644 --- a/manifest +++ b/manifest @@ -1,9 +1,9 @@ -C Renamed\sEXPORTED_FUNCTIONS.sqlite3\sto\sEXPORTED_FUNCTIONS.sqlite3-api\sto\savoid\sany\spotential\sconfusion\sabout\sthat\sfile\s(not)\sbeing\san\ssqlite3\sdatabase. -D 2022-05-25T04:38:35.081 +C Got\sthe\ssqlite3-api\sJS\sbits\swrapped\sup\sin\sdeferred-load\smodule.\sWhether\sthat's\sgoing\sto\sbe\seasier\sto\suse,\sin\spractice,\sremains\sto\sbe\sseen.\sConsolidated\stwo\sof\sthe\stest-related\sJS\sfiles. +D 2022-05-25T08:51:07.626 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 -F Makefile.in 335ac492dc602e7a7da3be3df020eac3b439a07cbdcf00a71b58304d7068257f +F Makefile.in 7ad689fdbe11297af09488b00c88b133b1505d6559bdad1f1829b6b7388c05be F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241 F Makefile.msc b28a8a7a977e7312f6859f560348e1eb110c21bd6cf9fab0d16537c0a514eef3 F README.md 8b8df9ca852aeac4864eb1e400002633ee6db84065bd01b78c33817f97d31f5e @@ -56,20 +56,19 @@ F ext/expert/sqlite3expert.c 6ca30d73b9ed75bd56d6e0d7f2c962d2affaa72c505458619d0 F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72 F ext/fiddle/EXPORTED_FUNCTIONS.fiddle 2f7c561af85e6d711fb42f395bc0074b6e6fcf16bc57d495ce4e1c3d0484c5d2 -F ext/fiddle/EXPORTED_FUNCTIONS.sqlite3-api 540b9dec63a3a62a256e2f030827848a92e9b9d9b6fa5c0188295a4a1c5382cd w ext/fiddle/EXPORTED_FUNCTIONS.sqlite3 +F ext/fiddle/EXPORTED_FUNCTIONS.sqlite3-api 540b9dec63a3a62a256e2f030827848a92e9b9d9b6fa5c0188295a4a1c5382cd F ext/fiddle/EXPORTED_RUNTIME_METHODS b831017ba67ba993b34a27400cef2f6095bd6789c0fc4eba7e7a251c207be31c -F ext/fiddle/Makefile 2608fe0c56fa8f9cdf17e28d2be6def550a2fe987db5f7fc06d0210bfc868258 -F ext/fiddle/SqliteTestUtil.js e3094833660a6ddd40766b802901b5861b37f0b89c6c577ee0ce4c9d36399e61 +F ext/fiddle/Makefile de65d04bfb312e94dbd7a0e7d99fb126f0abc1db62f920159c4124b5a42347d8 +F ext/fiddle/SqliteTestUtil.js 559731c3e8e0de330ec7d292e6c1846566408caee6637acc8a119ac338a8781c F ext/fiddle/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f F ext/fiddle/fiddle-worker.js 6000da12965319bed53d546f87885a6717a0cd8de0b4832edde7a95e63d1f33e F ext/fiddle/fiddle.html 70796dc8a867448b41bc7e2c5fd6b1865ed8010b3abe22ba0678e8915c062e9a F ext/fiddle/fiddle.js 45f96ac7f7d6678503568dded46afaa741d841a2464519035636da0fd77aec50 F ext/fiddle/index.md d9c1c308d8074341bc3b11d1d39073cd77754cb3ca9aeb949f23fdd8323d81cf -F ext/fiddle/sqlite3-api.js ce08520b8117e4fbbbeb02d8d047defd4e8507d687e76d20a39f12401bad0219 -F ext/fiddle/testing-common.js a2527fd8dfb500bad9b434ae2645bb91489792115ee1e1b4b53cac4e9198992a +F ext/fiddle/sqlite3-api.js 8500698d2163f4a25f8e5e6810ad826487342579d6a321d82b244dbc8e6f6db6 F ext/fiddle/testing.css 750572dded671d2cf142bbcb27af5542522ac08db128245d0b9fe410aa1d7f2a -F ext/fiddle/testing1.html 0a59d6cfb4cb16982c45ae3fabb1e090d122ca59285be97f3c01743eb75d6d73 -F ext/fiddle/testing1.js a2cee7ee12c2e1756e775125b0f9950dc5e5faeeeb4979c6d9894626d90cb5d9 +F ext/fiddle/testing1.html ea1f3be727f78e420007f823912c1a03b337ecbb8e79449abc2244ad4fe15d9a +F ext/fiddle/testing1.js 94a7597955c8fdbd15839a70d9b8279bc690205dda65ff175f688f13bf315745 F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b F ext/fts1/ft_hash.h 06df7bba40dadd19597aa400a875dbc2fed705ea @@ -1969,8 +1968,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P e0c30438a4f1372afb93a0488bae17b3f85d535717b215f494a83ae909871d2c -R 9374645be385492e5cf981b1ed91722a +P 3d6245c6f9f2ef4ca6746639d300cc5795598b119034439dfed671de3da638fb +R 0cd793b0df7e1a958b5a7fb6c581456e U stephan -Z 0e306e7b329adee899bf0b24535c7b65 +Z 24d1fc51d53037dbed19059815815fc9 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 85e8b2e4a1..1320ac63d0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3d6245c6f9f2ef4ca6746639d300cc5795598b119034439dfed671de3da638fb \ No newline at end of file +dd83cc05f2522d221641807dd66b33df48ac9264f27e5b6f63f312084f109801 \ No newline at end of file From 361e0ede47fab03b00904b6773e932bc566d10a9 Mon Sep 17 00:00:00 2001 From: drh <> Date: Wed, 25 May 2022 11:17:13 +0000 Subject: [PATCH 091/108] Add in a VdbeCoverage() macro accidentally omitted from [d64ae49a1f251317]. FossilOrigin-Name: 18b5cea0392a28f694b8931a80e93518f8d3d297d787fa44d1544e373f76838e --- manifest | 13 ++++++------- manifest.uuid | 2 +- src/where.c | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 0da905bbc1..93ec5996a0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sthe\sUPDATE-FROM\slogic\sso\sthat\sit\sworks\sthe\ssame\sas\sPostgreSQL\swhen\sthe\nFROM\sclause\scontains\san\souter\sjoin. -D 2022-05-25T11:09:07.638 +C Add\sin\sa\sVdbeCoverage()\smacro\saccidentally\somitted\sfrom\s[d64ae49a1f251317]. +D 2022-05-25T11:17:13.356 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -654,7 +654,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c 424b8696c379f57c5a23452e26fbf330f792e61fe096cffabefbf8b18a340385 +F src/where.c 01f87c783caf2d121617a1693aef9abdb6f71e316b2aa2852916512b0b9b2537 F src/whereInt.h 8da918f392bf202ccc0ee61291455b33ad171d209445f1ff3eaf62e0b6f6b363 F src/wherecode.c 2a8a73bcf1886632f2b2247c79395f94852a4b74484d8aa70a005892ce73d339 F src/whereexpr.c 7c5ee52e1df81d6a43f39e6b6f35d540fd37254e2b6e953a4e2715c3abf26f46 @@ -1969,9 +1969,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P dd83cc05f2522d221641807dd66b33df48ac9264f27e5b6f63f312084f109801 a124e4f96f883d8682ba7a253d33a9565ed0fc3580525225b95733bd3782a806 -R 0947292cf57b2d2b62677fbda585a4ec -T +closed a124e4f96f883d8682ba7a253d33a9565ed0fc3580525225b95733bd3782a806 +P 98b3816bbaf539ea745456e1c0064e47d2903d33ee0ceb029bdb97d56fcde937 +R 14446e7cde681b5e8cf26122c87ba0b0 U drh -Z 53acd9530f0c6264d60842c46e9a54be +Z 96b70b9e4542e2477014e495200cd320 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 69907f292a..13d88d8bf6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -98b3816bbaf539ea745456e1c0064e47d2903d33ee0ceb029bdb97d56fcde937 \ No newline at end of file +18b5cea0392a28f694b8931a80e93518f8d3d297d787fa44d1544e373f76838e \ No newline at end of file diff --git a/src/where.c b/src/where.c index 842af8e7ae..4615dd7e3b 100644 --- a/src/where.c +++ b/src/where.c @@ -5933,7 +5933,7 @@ WhereInfo *sqlite3WhereBegin( if( pSrc->fg.isCorrelated ){ sqlite3VdbeAddOp2(v, OP_Gosub, pSrc->regReturn, pSrc->addrFillSub); }else{ - int iOnce = sqlite3VdbeAddOp0(v, OP_Once); + int iOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Gosub, pSrc->regReturn, pSrc->addrFillSub); sqlite3VdbeJumpHere(v, iOnce); } From 7bfbd2508ca02adb7572a04b96f845a8f1fcef6d Mon Sep 17 00:00:00 2001 From: drh <> Date: Wed, 25 May 2022 12:49:59 +0000 Subject: [PATCH 092/108] Do not allow the right operand of a RIGHT JOIN to be reordered with other FROM clause terms that are even further to the right. Fix for the issue identified by [forum:/forumpost/5cfe08eed6|forum post 5cfe08eed6]. FossilOrigin-Name: 4be0c60e38edc5d5bfd72bb35a3c91c55240b4e6313a40614beb60f1ab9d9f4c --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/where.c | 11 ++++++++--- test/join8.test | 27 +++++++++++++++++++++++++++ 4 files changed, 43 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index 93ec5996a0..26b6ad579c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sin\sa\sVdbeCoverage()\smacro\saccidentally\somitted\sfrom\s[d64ae49a1f251317]. -D 2022-05-25T11:17:13.356 +C Do\snot\sallow\sthe\sright\soperand\sof\sa\sRIGHT\sJOIN\sto\sbe\sreordered\swith\sother\nFROM\sclause\sterms\sthat\sare\seven\sfurther\sto\sthe\sright.\s\sFix\sfor\sthe\sissue\nidentified\sby\s[forum:/forumpost/5cfe08eed6|forum\spost\s5cfe08eed6]. +D 2022-05-25T12:49:59.232 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -654,7 +654,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c 01f87c783caf2d121617a1693aef9abdb6f71e316b2aa2852916512b0b9b2537 +F src/where.c c4b64c6fa224e5b89ed547ec0ebdfd243c081509b195e71581164a2fbb8d4a80 F src/whereInt.h 8da918f392bf202ccc0ee61291455b33ad171d209445f1ff3eaf62e0b6f6b363 F src/wherecode.c 2a8a73bcf1886632f2b2247c79395f94852a4b74484d8aa70a005892ce73d339 F src/whereexpr.c 7c5ee52e1df81d6a43f39e6b6f35d540fd37254e2b6e953a4e2715c3abf26f46 @@ -1162,7 +1162,7 @@ F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join5.test d22b6cba8fb59ab3f1c82701434c360705eb12d4ce200c449f37b018fc47681a F test/join6.test f809c025fa253f9e150c0e9afd4cef8813257bceeb6f46e04041228c9403cc2c F test/join7.test 8e72de4b45e5e930d18c305c7efe86015fb2552731e4e03ea226353036b0dab0 -F test/join8.test c73bc91bee9d5f6f5975986bfa29da466347cf2616076e7841d3f198f9361176 +F test/join8.test 616eb7c2e4f2a54f2d730b914884d2205c8ada4757e89d08089255964a28e78e F test/join9.test 9056ddd3b0c0f4f9d658f4521038d9a37dc23ead8ca9a505d0b0db2b6a471e05 F test/joinA.test 7eab225dc1c1ab258a5e62513a4ed7cabbd3db971d59d5d92f4fb6fa14c12f6a F test/joinB.test 1b2ba3fc8568b49411787fccbf540570c148e9b6a53a30f80691cb6268098ded @@ -1969,8 +1969,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 98b3816bbaf539ea745456e1c0064e47d2903d33ee0ceb029bdb97d56fcde937 -R 14446e7cde681b5e8cf26122c87ba0b0 +P 18b5cea0392a28f694b8931a80e93518f8d3d297d787fa44d1544e373f76838e +R 8e650f107a80285980558729e468cb90 U drh -Z 96b70b9e4542e2477014e495200cd320 +Z 6af0bc21d075a0c1811a0f8f9fd1d30b # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 13d88d8bf6..61d553da9c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -18b5cea0392a28f694b8931a80e93518f8d3d297d787fa44d1544e373f76838e \ No newline at end of file +4be0c60e38edc5d5bfd72bb35a3c91c55240b4e6313a40614beb60f1ab9d9f4c \ No newline at end of file diff --git a/src/where.c b/src/where.c index 4615dd7e3b..d563f7b93b 100644 --- a/src/where.c +++ b/src/where.c @@ -4138,8 +4138,10 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ SrcItem *pEnd = &pTabList->a[pWInfo->nLevel]; sqlite3 *db = pWInfo->pParse->db; int rc = SQLITE_OK; + int bFirstPastRJ = 0; WhereLoop *pNew; + /* Loop over the tables in the join, from left to right */ pNew = pBuilder->pNew; whereLoopInit(pNew); @@ -4149,10 +4151,13 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ pNew->iTab = iTab; pBuilder->iPlanLimit += SQLITE_QUERY_PLANNER_LIMIT_INCR; pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor); - if( (pItem->fg.jointype & (JT_OUTER|JT_CROSS))!=0 ){ - /* This condition is true when pItem is the FROM clause term on the - ** right-hand-side of a OUTER or CROSS JOIN. */ + if( bFirstPastRJ || (pItem->fg.jointype & (JT_OUTER|JT_CROSS))!=0 ){ + /* Add prerequisites to prevent reordering of FROM clause terms + ** across CROSS joins and outer joins. The bFirstPastRJ boolean + ** prevents the right operand of a RIGHT JOIN from being swapped with + ** other elements even further to the right. */ mPrereq |= mPrior; + bFirstPastRJ = (pItem->fg.jointype & JT_RIGHT)!=0; } #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pItem->pTab) ){ diff --git a/test/join8.test b/test/join8.test index a3e306a05f..cccb167ac1 100644 --- a/test/join8.test +++ b/test/join8.test @@ -418,4 +418,31 @@ do_execsql_test join8-13000 { WHERE t2.y ISNULL; } {} +# 2022-05-25 +# https://sqlite.org/forum/forumpost/5cfe08eed6 +# +reset_db +do_execsql_test join8-14000 { + CREATE TABLE t0(a TEXT, b TEXT, c TEXT); + CREATE TABLE t1(a TEXT); + INSERT INTO t1 VALUES('1'); + CREATE VIEW v0 AS SELECT 'xyz' AS d; + SELECT * FROM v0 RIGHT JOIN t1 ON t1.a<>'' INNER JOIN t0 ON t0.c<>''; + SELECT * FROM v0 RIGHT JOIN t1 ON t1.a<>'' INNER JOIN t0 ON t0.c<>'' WHERE b ISNULL; +} {} +do_execsql_test join8-14010 { + CREATE TABLE y0(a INT); + CREATE TABLE y1(b INT); INSERT INTO y1 VALUES(1), (2); + CREATE TABLE y2(c INT); INSERT INTO y2 VALUES(3), (4); +} {} +db null - +do_execsql_test join8-14020 { + SELECT * FROM y0 RIGHT JOIN y1 ON true INNER JOIN y2 ON true WHERE y2.c!=99 AND y2.c!=98; +} { + - 1 3 + - 1 4 + - 2 3 + - 2 4 +} + finish_test From 724e298e9cefc13a3814178545aac6c58299620e Mon Sep 17 00:00:00 2001 From: drh <> Date: Wed, 25 May 2022 13:10:29 +0000 Subject: [PATCH 093/108] Slight increase in the accuracy of log10(). FossilOrigin-Name: c48a735bd4a1dbd541aed5937c25fc0c606c4263d8ee94cae30a06b1a7b26d9a --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/func.c | 4 ++-- test/func7.test | 6 ++++++ 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 26b6ad579c..a941e64120 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Do\snot\sallow\sthe\sright\soperand\sof\sa\sRIGHT\sJOIN\sto\sbe\sreordered\swith\sother\nFROM\sclause\sterms\sthat\sare\seven\sfurther\sto\sthe\sright.\s\sFix\sfor\sthe\sissue\nidentified\sby\s[forum:/forumpost/5cfe08eed6|forum\spost\s5cfe08eed6]. -D 2022-05-25T12:49:59.232 +C Slight\sincrease\sin\sthe\saccuracy\sof\slog10(). +D 2022-05-25T13:10:29.282 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -521,7 +521,7 @@ F src/delete.c a8e844af211a48b13b5b358be77a12c860c6a557c21990ad51a548e2536500ce F src/expr.c 19507ae3244402860cac2944be3b92bf9a8b50212fbfabaf7e9817127fec7c00 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c d965ede15d8360c09ed59348940649ee647b192e784466837d7aefa836d1d91e -F src/func.c a3407a6fbb0d4088d8d502e46f0ace63e0aeae7467ae23a9ca9815bbf9239761 +F src/func.c 41bf487f04d54e694baf84baacff7de621847fd7e89a35b776d5fb9ade772ff7 F src/global.c e83ee571b79ee3adc32e380cf554cf1254bc43763d23786c71721fbcdfbbb965 F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51 @@ -1072,7 +1072,7 @@ F test/func3.test 600a632c305a88f3946d38f9a51efe145c989b2e13bd2b2a488db47fe76bab F test/func4.test 2285fb5792d593fef442358763f0fd9de806eda47dbc7a5934df57ffdc484c31 F test/func5.test 863e6d1bd0013d09c17236f8a13ea34008dd857d87d85a13a673960e4c25d82a F test/func6.test 9cc9b1f43b435af34fe1416eb1e318c8920448ea7a6962f2121972f5215cb9b0 -F test/func7.test b9e2a1a30a8562b00841b4a21a5d2d81754fa3ab99275fd71fd5279287b44b1c +F test/func7.test adbfc910385a6ffd15dc47be3c619ef070c542fcb7488964badb17b2d9a4d080 F test/fuzz-oss1.test 514dcabb24687818ea949fa6760229eaacad74ca70157743ef36d35bbe01ffb0 F test/fuzz.test 4608c1310cff4c3014a84bcced6278139743e080046e5f6784b0de7b069371d8 F test/fuzz2.test 76dc35b32b6d6f965259508508abce75a6c4d7e1 @@ -1969,8 +1969,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 18b5cea0392a28f694b8931a80e93518f8d3d297d787fa44d1544e373f76838e -R 8e650f107a80285980558729e468cb90 +P 4be0c60e38edc5d5bfd72bb35a3c91c55240b4e6313a40614beb60f1ab9d9f4c +R 1c6e1432c4284eb2e687e5d9d74723a1 U drh -Z 6af0bc21d075a0c1811a0f8f9fd1d30b +Z 42ab2d62436fdafee99e49f2f11c2914 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 61d553da9c..88ea212996 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4be0c60e38edc5d5bfd72bb35a3c91c55240b4e6313a40614beb60f1ab9d9f4c \ No newline at end of file +c48a735bd4a1dbd541aed5937c25fc0c606c4263d8ee94cae30a06b1a7b26d9a \ No newline at end of file diff --git a/src/func.c b/src/func.c index 7ccb5118e8..6c831c74bc 100644 --- a/src/func.c +++ b/src/func.c @@ -2098,11 +2098,11 @@ static void logFunc( switch( SQLITE_PTR_TO_INT(sqlite3_user_data(context)) ){ case 1: /* Convert from natural logarithm to log base 10 */ - ans *= 1.0/M_LN10; + ans /= M_LN10; break; case 2: /* Convert from natural logarithm to log base 2 */ - ans *= 1.0/M_LN2; + ans /= M_LN2; break; default: break; diff --git a/test/func7.test b/test/func7.test index c8ae2931e1..bb4f80b325 100644 --- a/test/func7.test +++ b/test/func7.test @@ -60,6 +60,12 @@ do_execsql_test func7-pg-170 { do_execsql_test func7-pg-180 { SELECT log10(1000.0) } {3.0} +do_execsql_test func7-pg-181 { + SELECT format('%.30f', log10(100.0) ); +} {2.000000000000000000000000000000} +do_execsql_test func7-pg-182 { + SELECT format('%.30f', ln(exp(2.0)) ); +} {2.000000000000000000000000000000} do_execsql_test func7-pg-190 { SELECT log(2.0, 64.0) } {6.0} From c121e087f3614fd04d1f939dc26798e879be7863 Mon Sep 17 00:00:00 2001 From: stephan Date: Thu, 26 May 2022 05:08:25 +0000 Subject: [PATCH 094/108] Makefile.in: added explanations, intended for maintainers and hackers, of the various emcc flags used for building the wasm files. No code or build rule changes. FossilOrigin-Name: 1a159159094d6357b3cadbb8e5499cec4de35ef382c03fcc45c11daee906c3d6 --- Makefile.in | 45 +++++++++++++++++++++++++++++++++++++++++++++ manifest | 14 +++++++------- manifest.uuid | 2 +- 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/Makefile.in b/Makefile.in index 31579970a5..863eeb99cd 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1562,3 +1562,48 @@ $(sqlite3_wasm_js): Makefile sqlite3.c \ fiddle: $(fiddle_module_js) sqlite3-wasm: $(sqlite3_wasm_js) wasm: fiddle sqlite3-wasm +######################################################################## +# Explanation of the emcc build flags: +# +# -sENVIRONMENT=web: elides bootstrap code related to non-web JS +# environments like node.js. Removing this makes the output a tiny +# tick larger but hypothetically makes it more portable to +# non-browser JS environments. +# +# -sMODULARIZE: changes how the generated code is structured to avoid +# declaring a global Module object and instead installing a function +# which loads and initialized the module. The function is named... +# +# -sEXPORT_NAME=jsFunctionName (see -sMODULARIZE) +# +# -sEXPORTED_RUNTIME_METHODS=@/absolute/path/to/file: a file +# containing a list of emscripten-supplied APIs, one per line, which +# must be exported into the generated JS. +# +# -sEXPORTED_FUNCTIONS=@/absolute/path/to/file: a file containing a +# list of C functions, one per line, which must be exported via wasm +# so they're visible to JS. C symbols names in that file must all +# start with an underscore for reasons known only to the emcc +# developers. e.g., _sqlite3_open_v2 and _sqlite3_finalize. Must be +# an absolute path! +# +# --no-entry: for compiling library code with no main(). If this is +# not supplied and the code has a main(), it is called as part of the +# module init process. Note that main() is #if'd out of shell.c +# (renamed) when building in wasm mode. Must be an absolute path! +# +# --pre-js/--post-js=FILE relative or absolute paths to JS files to +# prepend/append to the emcc-generated bootstrapping JS. It's +# easier/faster to develop with separate JS files (reduces rebuilding +# requirements) but certain configurations, namely -sMODULARIZE, may +# require using at least a --pre-js file. They can be used +# individually and need not be paired. +# +# -O0..-O3 and -Oz: optimization levels affect not only C-style +# optimization but whether or not the resulting generated JS code +# gets minified. -O0 compiles _much_ more quickly than -O3 or -Oz, +# and doesn't minimize any JS code, so is recommended for +# development. -O3 or -Oz are recommended for deployment, but primarily +# because -Oz will shrink the wasm file notably. JS-side minification +# makes little difference in terms of overall distributable size. +######################################################################## diff --git a/manifest b/manifest index a941e64120..488b56f0ae 100644 --- a/manifest +++ b/manifest @@ -1,9 +1,9 @@ -C Slight\sincrease\sin\sthe\saccuracy\sof\slog10(). -D 2022-05-25T13:10:29.282 +C Makefile.in:\sadded\sexplanations,\sintended\sfor\smaintainers\sand\shackers,\sof\sthe\svarious\semcc\sflags\sused\sfor\sbuilding\sthe\swasm\sfiles.\sNo\scode\sor\sbuild\srule\schanges. +D 2022-05-26T05:08:25.641 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 -F Makefile.in 7ad689fdbe11297af09488b00c88b133b1505d6559bdad1f1829b6b7388c05be +F Makefile.in 80e7bb2f240fd2f17a0617501dc4ce41a05d36147587ec4cf6f8ae18edbdf6e9 F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241 F Makefile.msc b28a8a7a977e7312f6859f560348e1eb110c21bd6cf9fab0d16537c0a514eef3 F README.md 8b8df9ca852aeac4864eb1e400002633ee6db84065bd01b78c33817f97d31f5e @@ -1969,8 +1969,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 4be0c60e38edc5d5bfd72bb35a3c91c55240b4e6313a40614beb60f1ab9d9f4c -R 1c6e1432c4284eb2e687e5d9d74723a1 -U drh -Z 42ab2d62436fdafee99e49f2f11c2914 +P c48a735bd4a1dbd541aed5937c25fc0c606c4263d8ee94cae30a06b1a7b26d9a +R 6471d09ee21cb81c75dbefeb9f386ac7 +U stephan +Z a2d5db1738115b0671a1164b1988cd28 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 88ea212996..1aafe34518 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c48a735bd4a1dbd541aed5937c25fc0c606c4263d8ee94cae30a06b1a7b26d9a \ No newline at end of file +1a159159094d6357b3cadbb8e5499cec4de35ef382c03fcc45c11daee906c3d6 \ No newline at end of file From 78907bba3ec87c9c36aa045c46696d89feafe77c Mon Sep 17 00:00:00 2001 From: stephan Date: Thu, 26 May 2022 05:18:33 +0000 Subject: [PATCH 095/108] Fixed a minor cut/paste mistake in the previous checkin. Affects only internal docs. FossilOrigin-Name: 37e3764839b968456f576fad67d3d99007773f5c0689165ecbdc610fcabef1ca --- Makefile.in | 11 ++++++----- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Makefile.in b/Makefile.in index 863eeb99cd..0b0cbc8645 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1578,7 +1578,7 @@ wasm: fiddle sqlite3-wasm # # -sEXPORTED_RUNTIME_METHODS=@/absolute/path/to/file: a file # containing a list of emscripten-supplied APIs, one per line, which -# must be exported into the generated JS. +# must be exported into the generated JS. Must be an absolute path! # # -sEXPORTED_FUNCTIONS=@/absolute/path/to/file: a file containing a # list of C functions, one per line, which must be exported via wasm @@ -1590,7 +1590,7 @@ wasm: fiddle sqlite3-wasm # --no-entry: for compiling library code with no main(). If this is # not supplied and the code has a main(), it is called as part of the # module init process. Note that main() is #if'd out of shell.c -# (renamed) when building in wasm mode. Must be an absolute path! +# (renamed) when building in wasm mode. # # --pre-js/--post-js=FILE relative or absolute paths to JS files to # prepend/append to the emcc-generated bootstrapping JS. It's @@ -1603,7 +1603,8 @@ wasm: fiddle sqlite3-wasm # optimization but whether or not the resulting generated JS code # gets minified. -O0 compiles _much_ more quickly than -O3 or -Oz, # and doesn't minimize any JS code, so is recommended for -# development. -O3 or -Oz are recommended for deployment, but primarily -# because -Oz will shrink the wasm file notably. JS-side minification -# makes little difference in terms of overall distributable size. +# development. -O3 or -Oz are recommended for deployment, but +# primarily because -Oz will shrink the wasm file notably. JS-side +# minification makes little difference in terms of overall +# distributable size. ######################################################################## diff --git a/manifest b/manifest index 488b56f0ae..901616d096 100644 --- a/manifest +++ b/manifest @@ -1,9 +1,9 @@ -C Makefile.in:\sadded\sexplanations,\sintended\sfor\smaintainers\sand\shackers,\sof\sthe\svarious\semcc\sflags\sused\sfor\sbuilding\sthe\swasm\sfiles.\sNo\scode\sor\sbuild\srule\schanges. -D 2022-05-26T05:08:25.641 +C Fixed\sa\sminor\scut/paste\smistake\sin\sthe\sprevious\scheckin.\sAffects\sonly\sinternal\sdocs. +D 2022-05-26T05:18:33.887 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 -F Makefile.in 80e7bb2f240fd2f17a0617501dc4ce41a05d36147587ec4cf6f8ae18edbdf6e9 +F Makefile.in 038e29ac929fe8549e73cd92d1c360cdb0faa76ab80ca8fed29677b0ed814e2c F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241 F Makefile.msc b28a8a7a977e7312f6859f560348e1eb110c21bd6cf9fab0d16537c0a514eef3 F README.md 8b8df9ca852aeac4864eb1e400002633ee6db84065bd01b78c33817f97d31f5e @@ -1969,8 +1969,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P c48a735bd4a1dbd541aed5937c25fc0c606c4263d8ee94cae30a06b1a7b26d9a -R 6471d09ee21cb81c75dbefeb9f386ac7 +P 1a159159094d6357b3cadbb8e5499cec4de35ef382c03fcc45c11daee906c3d6 +R 70b4e1e5fdf8e461117e5a8beeef8ee6 U stephan -Z a2d5db1738115b0671a1164b1988cd28 +Z 5753ec80c3c37a802b11484d956a1c77 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 1aafe34518..528de1e251 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1a159159094d6357b3cadbb8e5499cec4de35ef382c03fcc45c11daee906c3d6 \ No newline at end of file +37e3764839b968456f576fad67d3d99007773f5c0689165ecbdc610fcabef1ca \ No newline at end of file From e91bde4655629a466fec624f832afe2554752044 Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 26 May 2022 14:46:09 +0000 Subject: [PATCH 096/108] Clarification of the meaning of the N parameter in sqlite3_db_name(). Documentation only. No changes to code. FossilOrigin-Name: f22f41d2c8a676b9a339e7f00c29c163bbb7079b1a4a76ee1a6a96aaf7de5f9e --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/sqlite.h.in | 4 +++- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 901616d096..db5cbba4e0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fixed\sa\sminor\scut/paste\smistake\sin\sthe\sprevious\scheckin.\sAffects\sonly\sinternal\sdocs. -D 2022-05-26T05:18:33.887 +C Clarification\sof\sthe\smeaning\sof\sthe\sN\sparameter\sin\ssqlite3_db_name().\nDocumentation\sonly.\s\sNo\schanges\sto\scode. +D 2022-05-26T14:46:09.766 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -569,7 +569,7 @@ F src/resolve.c a4eb3c617027fd049b07432f3b942ea7151fa793a332a11a7d0f58c9539e104f F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c a0dca0b4a328826d4713195a2fe305852cd8b1ed876311667b00c64b93a7fe23 F src/shell.c.in f3e0eb3e817f4d2edaeb12a06b2a0c8b5302fa223d87db68975313b9ce768e03 -F src/sqlite.h.in d15c307939039086adca159dd340a94b79b69827e74c6d661f343eeeaefba896 +F src/sqlite.h.in 172528c287399a34f188154017b7268bf82c6d5b780902e361958d2318c4e37c F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h a988810c9b21c0dc36dc7a62735012339dc76fc7ab448fb0792721d30eacb69d F src/sqliteInt.h 3064533677f135771e71843b5221482df18d6589afe65e6a7ef828ccb8879a5f @@ -1969,8 +1969,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 1a159159094d6357b3cadbb8e5499cec4de35ef382c03fcc45c11daee906c3d6 -R 70b4e1e5fdf8e461117e5a8beeef8ee6 -U stephan -Z 5753ec80c3c37a802b11484d956a1c77 +P 37e3764839b968456f576fad67d3d99007773f5c0689165ecbdc610fcabef1ca +R ad1c2600d93c5d6d7235db32fa9a048b +U drh +Z ca32a2eb387f9f8be5f39604dc123106 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 528de1e251..712a49a309 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -37e3764839b968456f576fad67d3d99007773f5c0689165ecbdc610fcabef1ca \ No newline at end of file +f22f41d2c8a676b9a339e7f00c29c163bbb7079b1a4a76ee1a6a96aaf7de5f9e \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 7c3664253d..ca56b8cb98 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -6282,7 +6282,9 @@ sqlite3 *sqlite3_db_handle(sqlite3_stmt*); ** ** ^The sqlite3_db_name(D,N) interface returns a pointer to the schema name ** for the N-th database on database connection D, or a NULL pointer of N is -** out of range. +** out of range. An N alue of 0 means the main database file. An N of 1 is +** the "temp" schema. Larger values of N correspond to various ATTACH-ed +** databases. ** ** Space to hold the string that is returned by sqlite3_db_name() is managed ** by SQLite itself. The string might be deallocated by any operation that From 26c4df0fb0da9baa37b797cdbaefd35df0a24693 Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 26 May 2022 17:33:42 +0000 Subject: [PATCH 097/108] Correct handling of outer joins in the FROM clause of an UPDATE statement that occurs inside of a trigger. Follow-on to [98b3816bbaf539ea]. FossilOrigin-Name: 664a49fa813144b6fa5a7ae3f65af5412f150dd5def261c4d581d706b39f7846 --- manifest | 14 ++++----- manifest.uuid | 2 +- src/trigger.c | 10 ++++++- test/upfrom4.test | 75 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 92 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index db5cbba4e0..2f209316a3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Clarification\sof\sthe\smeaning\sof\sthe\sN\sparameter\sin\ssqlite3_db_name().\nDocumentation\sonly.\s\sNo\schanges\sto\scode. -D 2022-05-26T14:46:09.766 +C Correct\shandling\sof\souter\sjoins\sin\sthe\sFROM\sclause\sof\san\sUPDATE\sstatement\nthat\soccurs\sinside\sof\sa\strigger.\s\sFollow-on\sto\s[98b3816bbaf539ea]. +D 2022-05-26T17:33:42.057 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -633,7 +633,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c a38f52058b517929e264094abd0b5fd1e8e145a1aa43bc6f6a72ae5218f96c98 F src/treeview.c 73facf395c8841653b9a54e789d8c80e15bc3d0d1cb9d16104c2d889c15e33cd -F src/trigger.c 4fe4c1ac811755aff49d669d2e52e414eb5dfa6e172e849ab7b6825e70a571c0 +F src/trigger.c adecf22bf1e869653a0637c2bb0c12b0b289e71fbb2c5cac70d596e11dbdf957 F src/update.c 2cfaded82ca80ff56afb8c3ae5e88284e0824bfd86119827cc22481959f96f92 F src/upsert.c 8789047a8f0a601ea42fa0256d1ba3190c13746b6ba940fe2d25643a7e991937 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 @@ -1706,7 +1706,7 @@ F test/upfrom1.tcl 8859d9d437f03b44174c4524a7a734a391fd4526fcff65be08285dafc9dc9 F test/upfrom1.test 8cb06689e99cd707d884faa16da0e8eb26ff658bb01c47ddf72fadade666e6e1 F test/upfrom2.test 66f3ebf721b3cebd922faee5c386bf244f816d416b57c000753ff51af62328a1 F test/upfrom3.test 6130f24ebf97f5ea865e5d2a14a2d543fe5428a62e87cc60f62d875e45c1f5f0 -F test/upfrom4.test 71d25e18c7d04e2930dcbd78e6aafb6931c80cb08f77039309b6095a12f1e62e +F test/upfrom4.test 1cd82e9423e02b1f63d069e8665c6c3932ec424fd0043d033cc0ba99abf33236 F test/upfromfault.test 3a10075a0043f0c4fad6614b2c371f88a8ba5a4acab68b907438413865d6a8d6 F test/upsert1.test b0ae2f58680c5205b4bc1cdeed3c3d444057c506f6c44494fa3eac60731d68a2 F test/upsert2.test 720e94d09f7362a282bc69b3c6b83d51daeaaf0440eb4920a08b86518b8c7496 @@ -1969,8 +1969,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 37e3764839b968456f576fad67d3d99007773f5c0689165ecbdc610fcabef1ca -R ad1c2600d93c5d6d7235db32fa9a048b +P f22f41d2c8a676b9a339e7f00c29c163bbb7079b1a4a76ee1a6a96aaf7de5f9e +R 96c2f1a4243ab0b57b68e0f3b4978a15 U drh -Z ca32a2eb387f9f8be5f39604dc123106 +Z 723fac70f8b090aa70201f7f985c54bc # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 712a49a309..04ae0302b2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f22f41d2c8a676b9a339e7f00c29c163bbb7079b1a4a76ee1a6a96aaf7de5f9e \ No newline at end of file +664a49fa813144b6fa5a7ae3f65af5412f150dd5def261c4d581d706b39f7846 \ No newline at end of file diff --git a/src/trigger.c b/src/trigger.c index 42c76bcd93..c4983bd92a 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -514,7 +514,7 @@ TriggerStep *sqlite3TriggerInsertStep( TriggerStep *sqlite3TriggerUpdateStep( Parse *pParse, /* Parser */ Token *pTableName, /* Name of the table to be updated */ - SrcList *pFrom, + SrcList *pFrom, /* FROM clause for an UPDATE-FROM, or NULL */ ExprList *pEList, /* The SET clause: list of column and new values */ Expr *pWhere, /* The WHERE clause */ u8 orconf, /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */ @@ -850,6 +850,14 @@ SrcList *sqlite3TriggerStepSrc( } if( pStep->pFrom ){ SrcList *pDup = sqlite3SrcListDup(db, pStep->pFrom, 0); + if( pDup && pDup->nSrc>1 ){ + Select *pSubquery; + Token as; + pSubquery = sqlite3SelectNew(pParse,0,pDup,0,0,0,0,SF_NestedFrom,0); + as.n = 0; + as.z = 0; + pDup = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&as,pSubquery,0); + } pSrc = sqlite3SrcListAppendList(pParse, pSrc, pDup); } }else{ diff --git a/test/upfrom4.test b/test/upfrom4.test index d0dcc953c9..b20e9638aa 100644 --- a/test/upfrom4.test +++ b/test/upfrom4.test @@ -52,4 +52,79 @@ do_execsql_test 120 { } {1 i I 2 ii {} 3 iii II 4 four FOUR} +reset_db +db null - +do_execsql_test 200 { + CREATE TABLE t1(a INT PRIMARY KEY, b INT, c INT); + INSERT INTO t1(a) VALUES(1),(2),(8),(19); + CREATE TABLE c1(x INTEGER PRIMARY KEY, b INT); + INSERT INTO c1(x,b) VALUES(1,1),(8,8),(17,17),(NULL,NULL); + CREATE TABLE c2(x INT,c INT); + INSERT INTO c2(x,c) VALUES(2,2),(8,8),(NULL,NULL); + CREATE TABLE dual(dummy TEXT); + INSERT INTO dual VALUES('X'); +} {} +do_execsql_test 210 { + BEGIN; + SELECT * FROM t1 ORDER BY a; + UPDATE t1 SET b=c1.b, c=c2.c + FROM dual, c1 NATURAL RIGHT JOIN c2 + WHERE x=a; + SELECT * FROM t1 ORDER BY a; + ROLLBACK; +} { + 1 - - + 2 - - + 8 - - + 19 - - + 1 - - + 2 - 2 + 8 8 8 + 19 - - +} +do_execsql_test 300 { + CREATE TABLE t2(x); + CREATE TRIGGER AFTER INSERT ON t2 BEGIN + UPDATE t1 SET b=c1.b, c=c2.c + FROM dual, c1 NATURAL RIGHT JOIN c2 + WHERE x=a; + END; +} {} +do_execsql_test 310 { + BEGIN; + SELECT * FROM t1 ORDER BY a; + INSERT INTO t2(x) VALUES(1); + SELECT * FROM t1 ORDER BY a; + ROLLBACK; +} { + 1 - - + 2 - - + 8 - - + 19 - - + 1 - - + 2 - 2 + 8 8 8 + 19 - - +} + +# 2022-05-26 dbsqlfuzz crash-9401d6ba699f1257d352a657de236286bf2b14da +# +reset_db +db null - +do_execsql_test 400 { + CREATE TABLE t2(x,y,z PRIMARY KEY) WITHOUT ROWID; + INSERT INTO t2 VALUES(89,-89,6); + CREATE TABLE t1(a INT,b TEXT,c TEXT,d REAL) STRICT; + INSERT INTO t1 VALUES(1,'xyz','def',4.5); + CREATE TRIGGER t1tr BEFORE UPDATE ON t1 BEGIN + INSERT INTO t1(a,b) VALUES(1000,'uvw'); + UPDATE t1 SET b=NULL FROM (SELECT CAST(a AS varchar) FROM t1 ORDER BY b) NATURAL LEFT FULL JOIN t1 AS text; + END; + UPDATE t1 SET b=b|100; + SELECT * FROM t1 ORDER BY a; +} { + 1 100 def 4.5 + 1000 - - - +} + finish_test From b8bbe3e2db8b0cd12a955de6c10a441301b60e55 Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 26 May 2022 19:10:11 +0000 Subject: [PATCH 098/108] Fix issues with ALTER TABLE and triggers containing "UPDATE...FROM" statements. FossilOrigin-Name: 2fba0d41b781d226915fa2bf888a7bc640c046ce22670ceb53f62a09f3975259 --- manifest | 15 ++--- manifest.uuid | 2 +- src/alter.c | 22 +++++++- test/altertrig.test | 130 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 159 insertions(+), 10 deletions(-) create mode 100644 test/altertrig.test diff --git a/manifest b/manifest index 2f209316a3..f83067ff4d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Correct\shandling\sof\souter\sjoins\sin\sthe\sFROM\sclause\sof\san\sUPDATE\sstatement\nthat\soccurs\sinside\sof\sa\strigger.\s\sFollow-on\sto\s[98b3816bbaf539ea]. -D 2022-05-26T17:33:42.057 +C Fix\sissues\swith\sALTER\sTABLE\sand\striggers\scontaining\s"UPDATE...FROM"\sstatements. +D 2022-05-26T19:10:11.700 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -500,7 +500,7 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a -F src/alter.c d8872f9d1863d8e31c37475e318de746e1b5ca57c0e477e35042a9ebbb6e0298 +F src/alter.c 379c644a32c64a18b592affac5ef173eb6024638b70ed4c593896e901702c78c F src/analyze.c aabdf3769c7fd9954a8ec508eb7041ae174b66f88d12c47199fabbea9a646467 F src/attach.c 4431f82f0247bf3aaf91589acafdff77d1882235c95407b36da1585c765fbbc8 F src/auth.c f4fa91b6a90bbc8e0d0f738aa284551739c9543a367071f55574681e0f24f8cf @@ -685,6 +685,7 @@ F test/alterqf.test ff6c6f881485c29ed699b8ef4774864ca1b0c01a6c08f5cdd624a008e4b4 F test/altertab.test 7273b8506eab46342be016af78028df49f3bd99037412f997a8f1011b37a6912 F test/altertab2.test 62597b6fd08feaba1b6bfe7d31dac6117c67e06dc9ce9c478a3abe75b5926de0 F test/altertab3.test 8af5c6eb4a7dd2fc73235b865b53561bf07428d1d6a9cd59a067abf51141891e +F test/altertrig.test f621cb3b209a2e72974e580840365b046537cd97b2df6b52088218a95dcbd58d F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f F test/analyze.test 547bb700f903107b38611b014ca645d6b5bb819f5210d7bf39c40802aafeb7d7 F test/analyze3.test 4440c4932247adb2b4e0c838f657c19dc7af4f56859255436dc4e855f39b9324 @@ -1969,8 +1970,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P f22f41d2c8a676b9a339e7f00c29c163bbb7079b1a4a76ee1a6a96aaf7de5f9e -R 96c2f1a4243ab0b57b68e0f3b4978a15 -U drh -Z 723fac70f8b090aa70201f7f985c54bc +P 664a49fa813144b6fa5a7ae3f65af5412f150dd5def261c4d581d706b39f7846 +R 4d839461e9af3d0a5ea1b8ddf72bf796 +U dan +Z 14299f1b8c4a8b0632845b66e1aabf6a # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 04ae0302b2..07e5cbd3c4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -664a49fa813144b6fa5a7ae3f65af5412f150dd5def261c4d581d706b39f7846 \ No newline at end of file +2fba0d41b781d226915fa2bf888a7bc640c046ce22670ceb53f62a09f3975259 \ No newline at end of file diff --git a/src/alter.c b/src/alter.c index 538ba7d9f8..8e19c0acea 100644 --- a/src/alter.c +++ b/src/alter.c @@ -1318,6 +1318,8 @@ static int renameResolveTrigger(Parse *pParse){ SrcList *pSrc = sqlite3TriggerStepSrc(pParse, pStep); if( pSrc ){ int i; + assert( pSrc->nSrc==1 || pSrc->nSrc==2 ); + assert( pSrc->a[0].pSelect==0 ); for(i=0; inSrc && rc==SQLITE_OK; i++){ SrcItem *p = &pSrc->a[i]; p->iCursor = pParse->nTab++; @@ -1325,8 +1327,6 @@ static int renameResolveTrigger(Parse *pParse){ sqlite3SelectPrep(pParse, p->pSelect, 0); sqlite3ExpandSubquery(pParse, p); assert( i>0 ); - assert( pStep->pFrom->a[i-1].pSelect ); - sqlite3SelectPrep(pParse, pStep->pFrom->a[i-1].pSelect, 0); }else{ p->pTab = sqlite3LocateTableItem(pParse, 0, p); if( p->pTab==0 ){ @@ -1337,6 +1337,15 @@ static int renameResolveTrigger(Parse *pParse){ } } } + if( pStep->pFrom ){ + for(i=0; ipFrom->nSrc && rc==SQLITE_OK; i++){ + SrcItem *p = &pStep->pFrom->a[i]; + if( p->pSelect ){ + sqlite3SelectPrep(pParse, p->pSelect, 0); + } + } + } + if( rc==SQLITE_OK && db->mallocFailed ){ rc = SQLITE_NOMEM; } @@ -1789,6 +1798,15 @@ static void renameTableFunc( if( pStep->zTarget && 0==sqlite3_stricmp(pStep->zTarget, zOld) ){ renameTokenFind(&sParse, &sCtx, pStep->zTarget); } + if( pStep->pFrom ){ + int i; + for(i=0; ipFrom->nSrc; i++){ + SrcItem *pItem = &pStep->pFrom->a[i]; + if( pItem->zName && 0==sqlite3_stricmp(pItem->zName, zOld) ){ + renameTokenFind(&sParse, &sCtx, pItem->zName); + } + } + } } } } diff --git a/test/altertrig.test b/test/altertrig.test new file mode 100644 index 0000000000..f418e58381 --- /dev/null +++ b/test/altertrig.test @@ -0,0 +1,130 @@ +# 2022 May 27 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#************************************************************************* +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix altertrig + +# If SQLITE_OMIT_ALTERTABLE is defined, omit this file. +ifcapable !altertable { + finish_test + return +} + +proc collapse_whitespace {in} { + regsub -all {[ \t\n]+} [string trim $in] { } +} + +proc do_whitespace_sql_test {tn sql res} { + set got [execsql $sql] + set wgot [list] + set wres [list] + foreach g $got { lappend wgot [collapse_whitespace $g] } + foreach r $res { lappend wres [collapse_whitespace $r] } + + uplevel [list do_test $tn [list set {} $wgot] $wres] +} + +do_execsql_test 1.0 { + CREATE TABLE t1(x); + CREATE TABLE t2(y); + CREATE TABLE t3(z); + CREATE TABLE t4(a); + + CREATE TRIGGER r1 INSERT ON t1 BEGIN + UPDATE t1 SET d='xyz' FROM t2, t3; + END; +} + +do_whitespace_sql_test 1.1 { + ALTER TABLE t3 RENAME TO t5; + SELECT sql FROM sqlite_schema WHERE type='trigger'; +} {{ + CREATE TRIGGER r1 INSERT ON t1 BEGIN + UPDATE t1 SET d='xyz' FROM t2, "t5"; + END +}} + +do_execsql_test 1.2 { + DROP TRIGGER r1; + CREATE TRIGGER r1 INSERT ON t1 BEGIN + UPDATE t1 SET d='xyz' FROM t2, (SELECT * FROM t5); + END; +} + +do_whitespace_sql_test 1.3 { + ALTER TABLE t5 RENAME TO t3; + SELECT sql FROM sqlite_schema WHERE type='trigger'; +} {{ + CREATE TRIGGER r1 INSERT ON t1 BEGIN + UPDATE t1 SET d='xyz' FROM t2, (SELECT * FROM "t3"); + END +}} + +foreach {tn alter update final} { + 1 { + ALTER TABLE t3 RENAME TO t10 + } { + UPDATE t1 SET d='xyz' FROM t2, (SELECT * FROM t3) + } { + UPDATE t1 SET d='xyz' FROM t2, (SELECT * FROM "t10") + } + + 2 { + ALTER TABLE t3 RENAME TO t10 + } { + UPDATE t1 SET d='xyz' FROM t3, (SELECT * FROM (SELECT e FROM t3)) + } { + UPDATE t1 SET d='xyz' FROM "t10", (SELECT * FROM (SELECT e FROM "t10")) + } + + 3 { + ALTER TABLE t3 RENAME e TO abc + } { + UPDATE t1 SET d='xyz' FROM t3, (SELECT * FROM (SELECT e FROM t3)) + } { + UPDATE t1 SET d='xyz' FROM t3, (SELECT * FROM (SELECT abc FROM t3)) + } + + 4 { + ALTER TABLE t2 RENAME c TO abc + } { + UPDATE t1 SET d='xyz' FROM t3, (SELECT 1 FROM t2 WHERE c) + } { + UPDATE t1 SET d='xyz' FROM t3, (SELECT 1 FROM t2 WHERE abc) + } + +} { + reset_db + do_execsql_test 2.$tn.1 { + CREATE TABLE t1(a,b); + CREATE TABLE t2(c,d); + CREATE TABLE t3(e,f); + } + do_execsql_test 2.$tn.2 " + CREATE TRIGGER r1 INSERT ON t1 BEGIN + $update; + END + " + do_execsql_test 2.$tn.3 $alter + + do_whitespace_sql_test 2.$tn.4 { + SELECT sqL FROM sqlite_schema WHERE type='trigger' + } "{ + CREATE TRIGGER r1 INSERT ON t1 BEGIN + $final; + END + }" +} + +finish_test + From cd697846468afe1728b0864b3d4c5e4c3da14eb5 Mon Sep 17 00:00:00 2001 From: stephan Date: Fri, 27 May 2022 03:27:10 +0000 Subject: [PATCH 099/108] fiddle: added an option to completely wipe/reset the db. The Options area can now be toggled on/off via tapping the label at its top. Running the input SQL is now limited to the selected area if any text is currently selected, per suggestion in the forum. FossilOrigin-Name: d100283e378f2d8e353399848184a4ab8ccf6316218fffc28b90a656cf81c279 --- ext/fiddle/EXPORTED_FUNCTIONS.fiddle | 1 + ext/fiddle/fiddle-worker.js | 25 +++++++---- ext/fiddle/fiddle.html | 66 +++++++++++++++++++++++----- ext/fiddle/fiddle.js | 46 ++++++++++++++----- manifest | 22 +++++----- manifest.uuid | 2 +- src/shell.c.in | 26 ++++++++++- 7 files changed, 143 insertions(+), 45 deletions(-) diff --git a/ext/fiddle/EXPORTED_FUNCTIONS.fiddle b/ext/fiddle/EXPORTED_FUNCTIONS.fiddle index 6356910f3b..b96ce4e67c 100644 --- a/ext/fiddle/EXPORTED_FUNCTIONS.fiddle +++ b/ext/fiddle/EXPORTED_FUNCTIONS.fiddle @@ -4,3 +4,4 @@ _fiddle_experiment _fiddle_the_db _fiddle_db_arg _fiddle_db_filename +_fiddle_reset_db diff --git a/ext/fiddle/fiddle-worker.js b/ext/fiddle/fiddle-worker.js index 5c7f7e4fbf..302452f1c3 100644 --- a/ext/fiddle/fiddle-worker.js +++ b/ext/fiddle/fiddle-worker.js @@ -115,10 +115,10 @@ stderr("Restarting the app requires reloading the page."); wMsg('error', err); } - fiddleModule.setStatus('Exception thrown, see JavaScript console'); - fiddleModule.setStatus = function(text) { + fiddleModule.setStatus('Exception thrown, see JavaScript console:',text); + /*fiddleModule.setStatus = function(text) { console.error('[post-exception status]', text); - }; + };*/ }; const Sqlite3Shell = { @@ -135,13 +135,13 @@ exec: function f(sql){ if(!f._) f._ = fiddleModule.cwrap('fiddle_exec', null, ['string']); if(fiddleModule.isDead){ - wMsg('stderr', "shell module has exit()ed. Cannot run SQL."); + stderr("shell module has exit()ed. Cannot run SQL."); return; } wMsg('working','start'); try { if(f._running){ - wMsg('stderr','Cannot run multiple commands concurrently.'); + stderr('Cannot run multiple commands concurrently.'); }else{ f._running = true; f._(sql); @@ -151,11 +151,17 @@ wMsg('working','end'); } }, + resetDb: function f(){ + if(!f._) f._ = fiddleModule.cwrap('fiddle_reset_db', null); + stdout("Resetting database."); + f._(); + stdout("Reset",this.dbFilename()); + }, /* Interrupt can't work: this Worker is tied up working, so won't get the interrupt event which would be needed to perform the interrupt. */ interrupt: function f(){ if(!f._) f._ = fiddleModule.cwrap('fiddle_interrupt', null); - wMsg('stdout',"Requesting interrupt."); + stdout("Requesting interrupt."); f._(); } }; @@ -170,6 +176,7 @@ //console.debug("worker: onmessage.data",ev); switch(ev.type){ case 'shellExec': Sqlite3Shell.exec(ev.data); return; + case 'db-reset': Sqlite3Shell.resetDb(); return; case 'interrupt': Sqlite3Shell.interrupt(); return; /** Triggers the export of the current db. Fires an event in the form: @@ -184,7 +191,7 @@ */ case 'db-export': { const fn = Sqlite3Shell.dbFilename(); - wMsg('stdout',"Exporting",fn+"."); + stdout("Exporting",fn+"."); const fn2 = fn ? fn.split(/[/\\]/).pop() : null; try{ if(!fn2) throw new Error("DB appears to be closed."); @@ -213,7 +220,7 @@ }else if(buffer instanceof ArrayBuffer){ buffer = new Uint8Array(buffer); }else{ - wMsg('stderr',"'open' expects {buffer:Uint8Array} containing an uploaded db."); + stderr("'open' expects {buffer:Uint8Array} containing an uploaded db."); return; } const fn = ( @@ -232,7 +239,7 @@ if(oldName !== fn){ fiddleModule.FS.unlink(oldName); } - wMsg('stdout',"Replaced DB with",fn+"."); + stdout("Replaced DB with",fn+"."); return; } }; diff --git a/ext/fiddle/fiddle.html b/ext/fiddle/fiddle.html index d8625cbf64..0bdb22e6f5 100644 --- a/ext/fiddle/fiddle.html +++ b/ext/fiddle/fiddle.html @@ -60,9 +60,6 @@ label[for] { cursor: pointer; } - fieldset { - border-radius: 0.5em; - } .error { color: red; background-color: yellow; @@ -73,15 +70,55 @@ pointer-events: none !important; display: none !important; } - fieldset.options { - font-size: 70%; + /* Safari supports neither styling of nor event handling on a + fieldset legend, so we emulate a fieldset-like widget. */ + .fieldset { + border-radius: 0.5em; + border: 1px inset; + display: flex; + flex-direction: column; } - fieldset > legend { + .fieldset > .legend { + position: relative; + top: -1.5ex; padding: 0 0.5em; + font-size: 85%; + margin-left: 0.5em; + flex: 0 1 auto; + align-self: self-start; + cursor: pointer; } - fieldset.options > div { + .fieldset.options > div { display: flex; flex-wrap: wrap; + font-size: 70%; + margin: 0 0.5em 0.5em 0.5em; + } + .fieldset > .legend > span { + position: relative; + } + .fieldset > .legend::before { + /* Hide the parent element's top border where this + element intersects it. */ + content: ' '; + width: 100%; + height: 100%; + background-color: white + /* REALLY want to 'inherit' the color from the fieldset's + parent, but inherit leads to a transparent bg, which is + exactly what we're trying to avoid here. */; + opacity: 1; + position: absolute; + top: 0; + left: 0; + } + .fieldset > .legend::after { + content: " [hide]"; + position: relative; + } + .fieldset.collapsed > .legend::after { + content: " [show]"; + position: relative; } span.labeled-input { padding: 0.25em; @@ -117,6 +154,9 @@ display: flex; flex-direction: column-reverse; } + #view-split > .fieldset.options { + margin-top: 0.5em; + } @@ -141,8 +181,8 @@
-
- Options +
+ Options
+ + +
-
+
diff --git a/manifest b/manifest index f033407924..15f7127c15 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sanother\sproblem\swith\sALTER\sTABLE\sand\sUPDATE...FROM\sin\striggers. -D 2022-05-27T15:33:51.795 +C Corrected\sa\sbroken\sHTML\scomment\s(was\susing\sa\sC-style\scomment\scloser). +D 2022-05-27T17:13:56.268 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -62,7 +62,7 @@ F ext/fiddle/Makefile de65d04bfb312e94dbd7a0e7d99fb126f0abc1db62f920159c4124b5a4 F ext/fiddle/SqliteTestUtil.js 559731c3e8e0de330ec7d292e6c1846566408caee6637acc8a119ac338a8781c F ext/fiddle/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f F ext/fiddle/fiddle-worker.js e3e8c7af2d6d10d915c8d6b5c88bd48587afbfdab7cb76858829c3b83e83a810 -F ext/fiddle/fiddle.html 2d63f820b8b5001ebd0ec0045beef0fed7cbef8e02fd6717b79e9b35050ce2e0 +F ext/fiddle/fiddle.html 724f1cd4126616bc87f5871f78d3f7aaaf41e45c9728724627baab87e6af35f0 F ext/fiddle/fiddle.js 700df283e8c6e87519aba6839e1aa99d040b39ea545253cbe79da18e24af256a F ext/fiddle/index.md d9c1c308d8074341bc3b11d1d39073cd77754cb3ca9aeb949f23fdd8323d81cf F ext/fiddle/sqlite3-api.js 8500698d2163f4a25f8e5e6810ad826487342579d6a321d82b244dbc8e6f6db6 @@ -1970,8 +1970,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 53fbc269ddbabc4a97d297e881e5f9cd2bfbcd24af4af1b7cf9db412a3a51813 -R 782c6ab6608c09278d06be6bd8fb58f8 -U dan -Z 229c3e01bc73b34742f015169bd23836 +P 33cf12235e6469ba17cfb72cef0e480dfd0dea81ed412fb1fb24b05dbeb8dc02 +R 0185d9a66db4bbbf377e87a775a5273a +U stephan +Z e1db3e85707eb265e716816de954de27 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 88e3da28af..242c16a9f6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -33cf12235e6469ba17cfb72cef0e480dfd0dea81ed412fb1fb24b05dbeb8dc02 \ No newline at end of file +db742e3e7d1caeff8d9df1d86abf54fcb2f2263db7a433ffacf3cd3777e533c5 \ No newline at end of file From abe1ff38dd9bf840bd43b45b2b842642484ee8d7 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 27 May 2022 17:36:21 +0000 Subject: [PATCH 104/108] Minor simplification to ALTER TABLE logic. FossilOrigin-Name: 01beb0365c529481605f1864b1b6760e2484fad08d56a72e00e34acff37e23f8 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/alter.c | 3 +-- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 15f7127c15..b288ab3fe6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Corrected\sa\sbroken\sHTML\scomment\s(was\susing\sa\sC-style\scomment\scloser). -D 2022-05-27T17:13:56.268 +C Minor\ssimplification\sto\sALTER\sTABLE\slogic. +D 2022-05-27T17:36:21.337 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -500,7 +500,7 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a -F src/alter.c d8671d56a89123dfeb517efbd580043a67b5859a615c31745f533567fd42e69b +F src/alter.c 0390ca1d69ec3626cfa9f153114b7ab233e6b2bada6a9eb91361ed385fe90deb F src/analyze.c aabdf3769c7fd9954a8ec508eb7041ae174b66f88d12c47199fabbea9a646467 F src/attach.c 4431f82f0247bf3aaf91589acafdff77d1882235c95407b36da1585c765fbbc8 F src/auth.c f4fa91b6a90bbc8e0d0f738aa284551739c9543a367071f55574681e0f24f8cf @@ -1970,8 +1970,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 33cf12235e6469ba17cfb72cef0e480dfd0dea81ed412fb1fb24b05dbeb8dc02 -R 0185d9a66db4bbbf377e87a775a5273a -U stephan -Z e1db3e85707eb265e716816de954de27 +P db742e3e7d1caeff8d9df1d86abf54fcb2f2263db7a433ffacf3cd3777e533c5 +R 9f5bbbd598c3c632a4687a11d52f0b0c +U drh +Z bcb40d0c984d7fab2c03d3331d81ea89 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 242c16a9f6..0fa9a0e804 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -db742e3e7d1caeff8d9df1d86abf54fcb2f2263db7a433ffacf3cd3777e533c5 \ No newline at end of file +01beb0365c529481605f1864b1b6760e2484fad08d56a72e00e34acff37e23f8 \ No newline at end of file diff --git a/src/alter.c b/src/alter.c index 9ccab37c78..d8a9982873 100644 --- a/src/alter.c +++ b/src/alter.c @@ -1333,7 +1333,6 @@ static int renameResolveTrigger(Parse *pParse){ pSel->pSrc = 0; sqlite3SelectDelete(db, pSel); } - if( pStep->pFrom ){ int i; for(i=0; ipFrom->nSrc && rc==SQLITE_OK; i++){ @@ -1344,7 +1343,7 @@ static int renameResolveTrigger(Parse *pParse){ } } - if( rc==SQLITE_OK && db->mallocFailed ){ + if( db->mallocFailed ){ rc = SQLITE_NOMEM; } sNC.pSrcList = pSrc; From 5af8a86d6280559fcecc4b5e65be4f8cadcb1888 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 27 May 2022 18:06:49 +0000 Subject: [PATCH 105/108] Mark an always-true conditional as ALWAYS(). FossilOrigin-Name: 3492fe8a212cbe02b9016866e2499b99c3b566a4b0bc91fba267e6e1fe1b8943 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/select.c | 3 ++- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index b288ab3fe6..f69de28b39 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Minor\ssimplification\sto\sALTER\sTABLE\slogic. -D 2022-05-27T17:36:21.337 +C Mark\san\salways-true\sconditional\sas\sALWAYS(). +D 2022-05-27T18:06:49.146 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -567,7 +567,7 @@ F src/printf.c 6166a30417b05c5b2f82e1f183f75faa2926ad60531c0b688a57dbc951441a20 F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c a4eb3c617027fd049b07432f3b942ea7151fa793a332a11a7d0f58c9539e104f F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 -F src/select.c a0dca0b4a328826d4713195a2fe305852cd8b1ed876311667b00c64b93a7fe23 +F src/select.c 7a4c5023d6c3bcd243546dbe9bbf5b280a60ca565658d037b8c0ec8dd77e1136 F src/shell.c.in b76e681f9e441928d574f21f9473ef615158bbeab1ae49f05ecab9d81730a51d F src/sqlite.h.in 172528c287399a34f188154017b7268bf82c6d5b780902e361958d2318c4e37c F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 @@ -1970,8 +1970,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P db742e3e7d1caeff8d9df1d86abf54fcb2f2263db7a433ffacf3cd3777e533c5 -R 9f5bbbd598c3c632a4687a11d52f0b0c +P 01beb0365c529481605f1864b1b6760e2484fad08d56a72e00e34acff37e23f8 +R 01dd885cb493be38067a73be4179a0ab U drh -Z bcb40d0c984d7fab2c03d3331d81ea89 +Z 416cd8c7c7dc19c9e93e8237f3081073 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 0fa9a0e804..d26e133969 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -01beb0365c529481605f1864b1b6760e2484fad08d56a72e00e34acff37e23f8 \ No newline at end of file +3492fe8a212cbe02b9016866e2499b99c3b566a4b0bc91fba267e6e1fe1b8943 \ No newline at end of file diff --git a/src/select.c b/src/select.c index 57f1b45957..cc5e4df8db 100644 --- a/src/select.c +++ b/src/select.c @@ -2193,10 +2193,11 @@ int sqlite3ColumnsFromExprList( } if( pColExpr->op==TK_COLUMN && ALWAYS( ExprUseYTab(pColExpr) ) - && (pTab = pColExpr->y.pTab)!=0 + && ALWAYS( pColExpr->y.pTab!=0 ) ){ /* For columns use the column name name */ int iCol = pColExpr->iColumn; + pTab = pColExpr->y.pTab; if( iCol<0 ) iCol = pTab->iPKey; zName = iCol>=0 ? pTab->aCol[iCol].zCnName : "rowid"; }else if( pColExpr->op==TK_ID ){ From e9ab04a4469e96d3b4cce233972487d3a9a11490 Mon Sep 17 00:00:00 2001 From: stephan Date: Sat, 28 May 2022 11:29:00 +0000 Subject: [PATCH 106/108] fiddle: corrected a piece of far-corner-case error handling and made the various checkbox config options persistent. FossilOrigin-Name: 2ba429a4f8300b981b23d54c2bdb54bd4863522c1c18bf9a67a82e3dce845b10 --- ext/fiddle/fiddle-worker.js | 6 +- ext/fiddle/fiddle.js | 195 +++++++++++++++++++++++++++++++++++- manifest | 16 +-- manifest.uuid | 2 +- 4 files changed, 205 insertions(+), 14 deletions(-) diff --git a/ext/fiddle/fiddle-worker.js b/ext/fiddle/fiddle-worker.js index 302452f1c3..e71955a8a8 100644 --- a/ext/fiddle/fiddle-worker.js +++ b/ext/fiddle/fiddle-worker.js @@ -115,10 +115,8 @@ stderr("Restarting the app requires reloading the page."); wMsg('error', err); } - fiddleModule.setStatus('Exception thrown, see JavaScript console:',text); - /*fiddleModule.setStatus = function(text) { - console.error('[post-exception status]', text); - };*/ + console.error(err); + fiddleModule.setStatus('Exception thrown, see JavaScript console: '+err); }; const Sqlite3Shell = { diff --git a/ext/fiddle/fiddle.js b/ext/fiddle/fiddle.js index d2ad7091cd..98caa6b3c2 100644 --- a/ext/fiddle/fiddle.js +++ b/ext/fiddle/fiddle.js @@ -16,10 +16,184 @@ */ (function(){ 'use strict'; - /* Recall that the 'self' symbol, except where locally overwritten, refers to the global window or worker object. */ + const storage = (function(NS/*namespace object in which to store this module*/){ + /* Pedantic licensing note: this code originated in the Fossil SCM + source tree, where it has a different license, but the person who + ported it into sqlite is the same one who wrote it for fossil. */ + 'use strict'; + NS = NS||{}; + + /** + This module provides a basic wrapper around localStorage + or sessionStorage or a dummy proxy object if neither + of those are available. + */ + const tryStorage = function f(obj){ + if(!f.key) f.key = 'storage.access.check'; + try{ + obj.setItem(f.key, 'f'); + const x = obj.getItem(f.key); + obj.removeItem(f.key); + if(x!=='f') throw new Error(f.key+" failed") + return obj; + }catch(e){ + return undefined; + } + }; + + /** Internal storage impl for this module. */ + const $storage = + tryStorage(window.localStorage) + || tryStorage(window.sessionStorage) + || tryStorage({ + // A basic dummy xyzStorage stand-in + $$$:{}, + setItem: function(k,v){this.$$$[k]=v}, + getItem: function(k){ + return this.$$$.hasOwnProperty(k) ? this.$$$[k] : undefined; + }, + removeItem: function(k){delete this.$$$[k]}, + clear: function(){this.$$$={}} + }); + + /** + For the dummy storage we need to differentiate between + $storage and its real property storage for hasOwnProperty() + to work properly... + */ + const $storageHolder = $storage.hasOwnProperty('$$$') ? $storage.$$$ : $storage; + + /** + A prefix which gets internally applied to all storage module + property keys so that localStorage and sessionStorage across the + same browser profile instance do not "leak" across multiple apps + being hosted by the same origin server. Such cross-polination is + still there but, with this key prefix applied, it won't be + immediately visible via the storage API. + + With this in place we can justify using localStorage instead of + sessionStorage. + + One implication of using localStorage and sessionStorage is that + their scope (the same "origin" and client application/profile) + allows multiple apps on the same origin to use the same + storage. Thus /appA/foo could then see changes made via + /appB/foo. The data do not cross user- or browser boundaries, + though, so it "might" arguably be called a + feature. storageKeyPrefix was added so that we can sandbox that + state for each separate app which shares an origin. + + See: https://fossil-scm.org/forum/forumpost/4afc4d34de + + Sidebar: it might seem odd to provide a key prefix and stick all + properties in the topmost level of the storage object. We do that + because adding a layer of object to sandbox each app would mean + (de)serializing that whole tree on every storage property change. + e.g. instead of storageObject.projectName.foo we have + storageObject[storageKeyPrefix+'foo']. That's soley for + efficiency's sake (in terms of battery life and + environment-internal storage-level effort). + */ + const storageKeyPrefix = ( + $storageHolder===$storage/*localStorage or sessionStorage*/ + ? ( + (NS.config ? + (NS.config.projectCode || NS.config.projectName + || NS.config.shortProjectName) + : false) + || window.location.pathname + )+'::' : ( + '' /* transient storage */ + ) + ); + + /** + A proxy for localStorage or sessionStorage or a + page-instance-local proxy, if neither one is availble. + + Which exact storage implementation is uses is unspecified, and + apps must not rely on it. + */ + NS.storage = { + storageKeyPrefix: storageKeyPrefix, + /** Sets the storage key k to value v, implicitly converting + it to a string. */ + set: (k,v)=>$storage.setItem(storageKeyPrefix+k,v), + /** Sets storage key k to JSON.stringify(v). */ + setJSON: (k,v)=>$storage.setItem(storageKeyPrefix+k,JSON.stringify(v)), + /** Returns the value for the given storage key, or + dflt if the key is not found in the storage. */ + get: (k,dflt)=>$storageHolder.hasOwnProperty( + storageKeyPrefix+k + ) ? $storage.getItem(storageKeyPrefix+k) : dflt, + /** Returns true if the given key has a value of "true". If the + key is not found, it returns true if the boolean value of dflt + is "true". (Remember that JS persistent storage values are all + strings.) */ + getBool: function(k,dflt){ + return 'true'===this.get(k,''+(!!dflt)); + }, + /** Returns the JSON.parse()'d value of the given + storage key's value, or dflt is the key is not + found or JSON.parse() fails. */ + getJSON: function f(k,dflt){ + try { + const x = this.get(k,f); + return x===f ? dflt : JSON.parse(x); + } + catch(e){return dflt} + }, + /** Returns true if the storage contains the given key, + else false. */ + contains: (k)=>$storageHolder.hasOwnProperty(storageKeyPrefix+k), + /** Removes the given key from the storage. Returns this. */ + remove: function(k){ + $storage.removeItem(storageKeyPrefix+k); + return this; + }, + /** Clears ALL keys from the storage. Returns this. */ + clear: function(){ + this.keys().forEach((k)=>$storage.removeItem(/*w/o prefix*/k)); + return this; + }, + /** Returns an array of all keys currently in the storage. */ + keys: ()=>Object.keys($storageHolder).filter((v)=>(v||'').startsWith(storageKeyPrefix)), + /** Returns true if this storage is transient (only available + until the page is reloaded), indicating that fileStorage + and sessionStorage are unavailable. */ + isTransient: ()=>$storageHolder!==$storage, + /** Returns a symbolic name for the current storage mechanism. */ + storageImplName: function(){ + if($storage===window.localStorage) return 'localStorage'; + else if($storage===window.sessionStorage) return 'sessionStorage'; + else return 'transient'; + }, + + /** + Returns a brief help text string for the currently-selected + storage type. + */ + storageHelpDescription: function(){ + return { + localStorage: "Browser-local persistent storage with an "+ + "unspecified long-term lifetime (survives closing the browser, "+ + "but maybe not a browser upgrade).", + sessionStorage: "Storage local to this browser tab, "+ + "lost if this tab is closed.", + "transient": "Transient storage local to this invocation of this page." + }[this.storageImplName()]; + } + }; + return NS.storage; + })({})/*storage API setup*/; + + + /** Name of the stored copy of SqliteFiddle.config. */ + const configStorageKey = 'fiddle-config'; + /** The SqliteFiddle object is intended to be the primary app-level object for the main-thread side of the sqlite @@ -130,9 +304,27 @@ this.wMsg('db-reset'); } return this; + }, + storeConfig: function(){ + storage.setJSON(configStorageKey,this.config); } }; + if(1){ /* set up SF.config */ + const storedConfig = storage.getJSON(configStorageKey); + if(storedConfig){ + /* Copy all properties to SF.config which are currently in + storedConfig. We don't bother copying any other + properties: those have been removed from the app in the + meantime. */ + Object.keys(SF.config).forEach(function(k){ + if(storedConfig.hasOwnProperty(k)){ + SF.config[k] = storedConfig[k]; + } + }); + } + } + SF.worker = new Worker('fiddle-worker.js'); SF.worker.onmessage = (ev)=>SF.runMsgHandlers(ev.data); SF.addMsgHandler(['stdout', 'stderr'], (ev)=>SF.echo(ev.data)); @@ -316,6 +508,7 @@ } e.addEventListener('change', function(){ SF.config[this.dataset.config] = this.checked; + SF.storeConfig(); }, false); }); /* For each button with data-cmd=X, map a click handler which diff --git a/manifest b/manifest index f69de28b39..f2d22cea59 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Mark\san\salways-true\sconditional\sas\sALWAYS(). -D 2022-05-27T18:06:49.146 +C fiddle:\scorrected\sa\spiece\sof\sfar-corner-case\serror\shandling\sand\smade\sthe\svarious\scheckbox\sconfig\soptions\spersistent. +D 2022-05-28T11:29:00.497 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -61,9 +61,9 @@ F ext/fiddle/EXPORTED_RUNTIME_METHODS b831017ba67ba993b34a27400cef2f6095bd6789c0 F ext/fiddle/Makefile de65d04bfb312e94dbd7a0e7d99fb126f0abc1db62f920159c4124b5a42347d8 F ext/fiddle/SqliteTestUtil.js 559731c3e8e0de330ec7d292e6c1846566408caee6637acc8a119ac338a8781c F ext/fiddle/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f -F ext/fiddle/fiddle-worker.js e3e8c7af2d6d10d915c8d6b5c88bd48587afbfdab7cb76858829c3b83e83a810 +F ext/fiddle/fiddle-worker.js 3a19253dc026d1ad9064ee853f3c4da3385223ce4434dab1838837525d817371 F ext/fiddle/fiddle.html 724f1cd4126616bc87f5871f78d3f7aaaf41e45c9728724627baab87e6af35f0 -F ext/fiddle/fiddle.js 700df283e8c6e87519aba6839e1aa99d040b39ea545253cbe79da18e24af256a +F ext/fiddle/fiddle.js 503524eb132716c6c4777a1a2352a9bfc6d391b38de8d050f22f73a5df5993b1 F ext/fiddle/index.md d9c1c308d8074341bc3b11d1d39073cd77754cb3ca9aeb949f23fdd8323d81cf F ext/fiddle/sqlite3-api.js 8500698d2163f4a25f8e5e6810ad826487342579d6a321d82b244dbc8e6f6db6 F ext/fiddle/testing.css 750572dded671d2cf142bbcb27af5542522ac08db128245d0b9fe410aa1d7f2a @@ -1970,8 +1970,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 01beb0365c529481605f1864b1b6760e2484fad08d56a72e00e34acff37e23f8 -R 01dd885cb493be38067a73be4179a0ab -U drh -Z 416cd8c7c7dc19c9e93e8237f3081073 +P 3492fe8a212cbe02b9016866e2499b99c3b566a4b0bc91fba267e6e1fe1b8943 +R a18f2e003119227b8304b945c745c3c1 +U stephan +Z aed9dc05a3c9ef7bf20957969efcb8af # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index d26e133969..3cb0668914 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3492fe8a212cbe02b9016866e2499b99c3b566a4b0bc91fba267e6e1fe1b8943 \ No newline at end of file +2ba429a4f8300b981b23d54c2bdb54bd4863522c1c18bf9a67a82e3dce845b10 \ No newline at end of file From 1a66ff359f769656e8adaaf83e8a3973dd5a6911 Mon Sep 17 00:00:00 2001 From: stephan Date: Sat, 28 May 2022 11:59:46 +0000 Subject: [PATCH 107/108] fiddle: changed the internal key of the session/local storage to avoid conflicts with the pikchr fiddle app (which is derived from this one) when running from the same HTTP origin as an instance of that app in a dev environment. FossilOrigin-Name: fd668da5ccf037c2ad8e61e381dd1eb398a8deab42a00593e551c30bd176890d --- ext/fiddle/fiddle.js | 5 +++-- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/ext/fiddle/fiddle.js b/ext/fiddle/fiddle.js index 98caa6b3c2..c03a09af11 100644 --- a/ext/fiddle/fiddle.js +++ b/ext/fiddle/fiddle.js @@ -192,7 +192,7 @@ /** Name of the stored copy of SqliteFiddle.config. */ - const configStorageKey = 'fiddle-config'; + const configStorageKey = 'sqlite3-fiddle-config'; /** The SqliteFiddle object is intended to be the primary @@ -305,12 +305,13 @@ } return this; }, + /** Stores this object's config in the browser's storage. */ storeConfig: function(){ storage.setJSON(configStorageKey,this.config); } }; - if(1){ /* set up SF.config */ + if(1){ /* Restore SF.config */ const storedConfig = storage.getJSON(configStorageKey); if(storedConfig){ /* Copy all properties to SF.config which are currently in diff --git a/manifest b/manifest index f2d22cea59..6702b91ddd 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C fiddle:\scorrected\sa\spiece\sof\sfar-corner-case\serror\shandling\sand\smade\sthe\svarious\scheckbox\sconfig\soptions\spersistent. -D 2022-05-28T11:29:00.497 +C fiddle:\schanged\sthe\sinternal\skey\sof\sthe\ssession/local\sstorage\sto\savoid\sconflicts\swith\sthe\spikchr\sfiddle\sapp\s(which\sis\sderived\sfrom\sthis\sone)\swhen\srunning\sfrom\sthe\ssame\sHTTP\sorigin\sas\san\sinstance\sof\sthat\sapp\sin\sa\sdev\senvironment. +D 2022-05-28T11:59:46.787 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -63,7 +63,7 @@ F ext/fiddle/SqliteTestUtil.js 559731c3e8e0de330ec7d292e6c1846566408caee6637acc8 F ext/fiddle/emscripten.css 3d253a6fdb8983a2ac983855bfbdd4b6fa1ff267c28d69513dd6ef1f289ada3f F ext/fiddle/fiddle-worker.js 3a19253dc026d1ad9064ee853f3c4da3385223ce4434dab1838837525d817371 F ext/fiddle/fiddle.html 724f1cd4126616bc87f5871f78d3f7aaaf41e45c9728724627baab87e6af35f0 -F ext/fiddle/fiddle.js 503524eb132716c6c4777a1a2352a9bfc6d391b38de8d050f22f73a5df5993b1 +F ext/fiddle/fiddle.js 5b456ed7085830cda2fc75a0801476174a978521949335f24bc4154d076dcd4d F ext/fiddle/index.md d9c1c308d8074341bc3b11d1d39073cd77754cb3ca9aeb949f23fdd8323d81cf F ext/fiddle/sqlite3-api.js 8500698d2163f4a25f8e5e6810ad826487342579d6a321d82b244dbc8e6f6db6 F ext/fiddle/testing.css 750572dded671d2cf142bbcb27af5542522ac08db128245d0b9fe410aa1d7f2a @@ -1970,8 +1970,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 3492fe8a212cbe02b9016866e2499b99c3b566a4b0bc91fba267e6e1fe1b8943 -R a18f2e003119227b8304b945c745c3c1 +P 2ba429a4f8300b981b23d54c2bdb54bd4863522c1c18bf9a67a82e3dce845b10 +R 5eae1a2cd35849ef58a6f996836c910f U stephan -Z aed9dc05a3c9ef7bf20957969efcb8af +Z 2e6b37323598d8726fccb322e129ee85 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 3cb0668914..3fc3330fe9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2ba429a4f8300b981b23d54c2bdb54bd4863522c1c18bf9a67a82e3dce845b10 \ No newline at end of file +fd668da5ccf037c2ad8e61e381dd1eb398a8deab42a00593e551c30bd176890d \ No newline at end of file From 1943005f626fbefa1fb32f77fc671ee07c52b11f Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 28 May 2022 14:03:23 +0000 Subject: [PATCH 108/108] Apply the UPDATE-FROM file from check-in [98b3816bbaf539ea] to update-delete-limit builds. FossilOrigin-Name: 7e87892c249f023ee9ed1d5f75a9ad8db10fb38f14dd9e6954b12b9b28400b07 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/parse.y | 13 ++++++++++++- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 6702b91ddd..e804cf0c3a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C fiddle:\schanged\sthe\sinternal\skey\sof\sthe\ssession/local\sstorage\sto\savoid\sconflicts\swith\sthe\spikchr\sfiddle\sapp\s(which\sis\sderived\sfrom\sthis\sone)\swhen\srunning\sfrom\sthe\ssame\sHTTP\sorigin\sas\san\sinstance\sof\sthat\sapp\sin\sa\sdev\senvironment. -D 2022-05-28T11:59:46.787 +C Apply\sthe\sUPDATE-FROM\sfile\sfrom\scheck-in\s[98b3816bbaf539ea]\sto\nupdate-delete-limit\sbuilds. +D 2022-05-28T14:03:23.844 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -556,7 +556,7 @@ F src/os_win.c a8ea80037e81127ca01959daa87387cc135f325c88dc745376c4f760de852a10 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a F src/pager.c 42120492784fc9bcd9082b5c9b5e329b7318c357f9f3574a1bbfcf7418910356 F src/pager.h f82e9844166e1585f5786837ddc7709966138ced17f568c16af7ccf946c2baa3 -F src/parse.y b58ad9fadf31e26e45214a4d8be4351ec2910bbd914caa2e172d616057f67ddc +F src/parse.y 8e67d820030d2655b9942ffe61c1e7e6b96cea2f2f72183533299393907d0564 F src/pcache.c 084e638432c610f95aea72b8509f0845d2791293f39d1b82f0c0a7e089c3bb6b F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 F src/pcache1.c 54881292a9a5db202b2c0ac541c5e3ef9a5e8c4f1c1383adb2601d5499a60e65 @@ -1970,8 +1970,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 2ba429a4f8300b981b23d54c2bdb54bd4863522c1c18bf9a67a82e3dce845b10 -R 5eae1a2cd35849ef58a6f996836c910f -U stephan -Z 2e6b37323598d8726fccb322e129ee85 +P fd668da5ccf037c2ad8e61e381dd1eb398a8deab42a00593e551c30bd176890d +R e62d67531970b1619ea2f47c2f8c0901 +U drh +Z 2f27046509ba92f24780e3263d6632b0 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 3fc3330fe9..a331df2c16 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -fd668da5ccf037c2ad8e61e381dd1eb398a8deab42a00593e551c30bd176890d \ No newline at end of file +7e87892c249f023ee9ed1d5f75a9ad8db10fb38f14dd9e6954b12b9b28400b07 \ No newline at end of file diff --git a/src/parse.y b/src/parse.y index 44a14e2585..d627f22ba2 100644 --- a/src/parse.y +++ b/src/parse.y @@ -924,7 +924,18 @@ where_opt_ret(A) ::= WHERE expr(X) RETURNING selcollist(Y). cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y) from(F) where_opt_ret(W) orderby_opt(O) limit_opt(L). { sqlite3SrcListIndexedBy(pParse, X, &I); - X = sqlite3SrcListAppendList(pParse, X, F); + if( F ){ + SrcList *pFromClause = F; + if( pFromClause->nSrc>1 ){ + Select *pSubquery; + Token as; + pSubquery = sqlite3SelectNew(pParse,0,pFromClause,0,0,0,0,SF_NestedFrom,0); + as.n = 0; + as.z = 0; + pFromClause = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&as,pSubquery,0); + } + X = sqlite3SrcListAppendList(pParse, X, pFromClause); + } sqlite3ExprListCheckLength(pParse,Y,"set list"); #ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT if( O || L ){