+
+
+
+ {{{ 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 */