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