mirror of
				https://github.com/sqlite/sqlite.git
				synced 2025-10-30 07:05:46 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			1670 lines
		
	
	
		
			66 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			1670 lines
		
	
	
		
			66 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /*
 | |
|   2022-07-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 glues together disparate pieces of JS which are loaded in
 | |
|   previous steps of the sqlite3-api.js bootstrapping process:
 | |
|   sqlite3-api-prologue.js, whwasmutil.js, and jaccwabyt.js. It
 | |
|   initializes the main API pieces so that the downstream components
 | |
|   (e.g. sqlite3-api-oo1.js) have all that they need.
 | |
| */
 | |
| globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
 | |
|   'use strict';
 | |
|   const toss = (...args)=>{throw new Error(args.join(' '))};
 | |
|   const toss3 = sqlite3.SQLite3Error.toss;
 | |
|   const capi = sqlite3.capi, wasm = sqlite3.wasm, util = sqlite3.util;
 | |
|   globalThis.WhWasmUtilInstaller(wasm);
 | |
|   delete globalThis.WhWasmUtilInstaller;
 | |
| 
 | |
|   if(0){
 | |
|     /**
 | |
|        Please keep this block around as a maintenance reminder
 | |
|        that we cannot rely on this type of check.
 | |
| 
 | |
|        This block fails on Safari, per a report at
 | |
|        https://sqlite.org/forum/forumpost/e5b20e1feb.
 | |
| 
 | |
|        It turns out that what Safari serves from the indirect function
 | |
|        table (e.g. wasm.functionEntry(X)) is anonymous functions which
 | |
|        wrap the WASM functions, rather than returning the WASM
 | |
|        functions themselves. That means comparison of such functions
 | |
|        is useless for determining whether or not we have a specific
 | |
|        function from wasm.exports. i.e. if function X is indirection
 | |
|        function table entry N then wasm.exports.X is not equal to
 | |
|        wasm.functionEntry(N) in Safari, despite being so in the other
 | |
|        browsers.
 | |
|     */
 | |
|     /**
 | |
|        Find a mapping for SQLITE_WASM_DEALLOC, which the API
 | |
|        guarantees is a WASM pointer to the same underlying function as
 | |
|        wasm.dealloc() (noting that wasm.dealloc() is permitted to be a
 | |
|        JS wrapper around the WASM function). There is unfortunately no
 | |
|        O(1) algorithm for finding this pointer: we have to walk the
 | |
|        WASM indirect function table to find it. However, experience
 | |
|        indicates that that particular function is always very close to
 | |
|        the front of the table (it's been entry #3 in all relevant
 | |
|        tests).
 | |
|     */
 | |
|     const dealloc = wasm.exports[sqlite3.config.deallocExportName];
 | |
|     const nFunc = wasm.functionTable().length;
 | |
|     let i;
 | |
|     for(i = 0; i < nFunc; ++i){
 | |
|       const e = wasm.functionEntry(i);
 | |
|       if(dealloc === e){
 | |
|         capi.SQLITE_WASM_DEALLOC = i;
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|     if(dealloc !== wasm.functionEntry(capi.SQLITE_WASM_DEALLOC)){
 | |
|       toss("Internal error: cannot find function pointer for SQLITE_WASM_DEALLOC.");
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|      Signatures for the WASM-exported C-side functions. Each entry
 | |
|      is an array with 2+ elements:
 | |
| 
 | |
|      [ "c-side name",
 | |
|        "result type" (wasm.xWrap() syntax),
 | |
|        [arg types in xWrap() syntax]
 | |
|        // ^^^ this needn't strictly be an array: it can be subsequent
 | |
|        // elements instead: [x,y,z] is equivalent to x,y,z
 | |
|      ]
 | |
| 
 | |
|      Note that support for the API-specific data types in the
 | |
|      result/argument type strings gets plugged in at a later phase in
 | |
|      the API initialization process.
 | |
|   */
 | |
|   wasm.bindingSignatures = [
 | |
|     // Please keep these sorted by function name!
 | |
|     ["sqlite3_aggregate_context","void*", "sqlite3_context*", "int"],
 | |
|     /* sqlite3_auto_extension() has a hand-written binding. */
 | |
|     /* sqlite3_bind_blob() and sqlite3_bind_text() have hand-written
 | |
|        bindings to permit more flexible inputs. */
 | |
|     ["sqlite3_bind_double","int", "sqlite3_stmt*", "int", "f64"],
 | |
|     ["sqlite3_bind_int","int", "sqlite3_stmt*", "int", "int"],
 | |
|     ["sqlite3_bind_null",undefined, "sqlite3_stmt*", "int"],
 | |
|     ["sqlite3_bind_parameter_count", "int", "sqlite3_stmt*"],
 | |
|     ["sqlite3_bind_parameter_index","int", "sqlite3_stmt*", "string"],
 | |
|     ["sqlite3_bind_pointer", "int",
 | |
|      "sqlite3_stmt*", "int", "*", "string:static", "*"],
 | |
|     ["sqlite3_busy_handler","int", [
 | |
|       "sqlite3*",
 | |
|       new wasm.xWrap.FuncPtrAdapter({
 | |
|         signature: 'i(pi)',
 | |
|         contextKey: (argv,argIndex)=>argv[0/* sqlite3* */]
 | |
|       }),
 | |
|       "*"
 | |
|     ]],
 | |
|     ["sqlite3_busy_timeout","int", "sqlite3*", "int"],
 | |
|     /* sqlite3_cancel_auto_extension() has a hand-written binding. */
 | |
|     /* sqlite3_close_v2() is implemented by hand to perform some
 | |
|        extra work. */
 | |
|     ["sqlite3_changes", "int", "sqlite3*"],
 | |
|     ["sqlite3_clear_bindings","int", "sqlite3_stmt*"],
 | |
|     ["sqlite3_collation_needed", "int", "sqlite3*", "*", "*"/*=>v(ppis)*/],
 | |
|     ["sqlite3_column_blob","*", "sqlite3_stmt*", "int"],
 | |
|     ["sqlite3_column_bytes","int", "sqlite3_stmt*", "int"],
 | |
|     ["sqlite3_column_count", "int", "sqlite3_stmt*"],
 | |
|     ["sqlite3_column_double","f64", "sqlite3_stmt*", "int"],
 | |
|     ["sqlite3_column_int","int", "sqlite3_stmt*", "int"],
 | |
|     ["sqlite3_column_name","string", "sqlite3_stmt*", "int"],
 | |
|     ["sqlite3_column_text","string", "sqlite3_stmt*", "int"],
 | |
|     ["sqlite3_column_type","int", "sqlite3_stmt*", "int"],
 | |
|     ["sqlite3_column_value","sqlite3_value*", "sqlite3_stmt*", "int"],
 | |
|     ["sqlite3_commit_hook", "void*", [
 | |
|       "sqlite3*",
 | |
|       new wasm.xWrap.FuncPtrAdapter({
 | |
|         name: 'sqlite3_commit_hook',
 | |
|         signature: 'i(p)',
 | |
|         contextKey: (argv)=>argv[0/* sqlite3* */]
 | |
|       }),
 | |
|       '*'
 | |
|     ]],
 | |
|     ["sqlite3_compileoption_get", "string", "int"],
 | |
|     ["sqlite3_compileoption_used", "int", "string"],
 | |
|     ["sqlite3_complete", "int", "string:flexible"],
 | |
|     ["sqlite3_context_db_handle", "sqlite3*", "sqlite3_context*"],
 | |
| 
 | |
|     /* sqlite3_create_function(), sqlite3_create_function_v2(), and
 | |
|        sqlite3_create_window_function() use hand-written bindings to
 | |
|        simplify handling of their function-type arguments. */
 | |
|     /* sqlite3_create_collation() and sqlite3_create_collation_v2()
 | |
|        use hand-written bindings to simplify passing of the callback
 | |
|        function.
 | |
|       ["sqlite3_create_collation", "int",
 | |
|      "sqlite3*", "string", "int",//SQLITE_UTF8 is the only legal value
 | |
|      "*", "*"],
 | |
|     ["sqlite3_create_collation_v2", "int",
 | |
|      "sqlite3*", "string", "int",//SQLITE_UTF8 is the only legal value
 | |
|      "*", "*", "*"],
 | |
|     */
 | |
|     ["sqlite3_data_count", "int", "sqlite3_stmt*"],
 | |
|     ["sqlite3_db_filename", "string", "sqlite3*", "string"],
 | |
|     ["sqlite3_db_handle", "sqlite3*", "sqlite3_stmt*"],
 | |
|     ["sqlite3_db_name", "string", "sqlite3*", "int"],
 | |
|     ["sqlite3_db_status", "int", "sqlite3*", "int", "*", "*", "int"],
 | |
|     ["sqlite3_errcode", "int", "sqlite3*"],
 | |
|     ["sqlite3_errmsg", "string", "sqlite3*"],
 | |
|     ["sqlite3_error_offset", "int", "sqlite3*"],
 | |
|     ["sqlite3_errstr", "string", "int"],
 | |
|     ["sqlite3_exec", "int", [
 | |
|       "sqlite3*", "string:flexible",
 | |
|       new wasm.xWrap.FuncPtrAdapter({
 | |
|         signature: 'i(pipp)',
 | |
|         bindScope: 'transient',
 | |
|         callProxy: (callback)=>{
 | |
|           let aNames;
 | |
|           return (pVoid, nCols, pColVals, pColNames)=>{
 | |
|             try {
 | |
|               const aVals = wasm.cArgvToJs(nCols, pColVals);
 | |
|               if(!aNames) aNames = wasm.cArgvToJs(nCols, pColNames);
 | |
|               return callback(aVals, aNames) | 0;
 | |
|             }catch(e){
 | |
|               /* If we set the db error state here, the higher-level
 | |
|                  exec() call replaces it with its own, so we have no way
 | |
|                  of reporting the exception message except the console. We
 | |
|                  must not propagate exceptions through the C API. Though
 | |
|                  we make an effort to report OOM here, sqlite3_exec()
 | |
|                  translates that into SQLITE_ABORT as well. */
 | |
|               return e.resultCode || capi.SQLITE_ERROR;
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }),
 | |
|       "*", "**"
 | |
|     ]],
 | |
|     ["sqlite3_expanded_sql", "string", "sqlite3_stmt*"],
 | |
|     ["sqlite3_extended_errcode", "int", "sqlite3*"],
 | |
|     ["sqlite3_extended_result_codes", "int", "sqlite3*", "int"],
 | |
|     ["sqlite3_file_control", "int", "sqlite3*", "string", "int", "*"],
 | |
|     ["sqlite3_finalize", "int", "sqlite3_stmt*"],
 | |
|     ["sqlite3_free", undefined,"*"],
 | |
|     ["sqlite3_get_auxdata", "*", "sqlite3_context*", "int"],
 | |
|     ["sqlite3_initialize", undefined],
 | |
|     /*["sqlite3_interrupt", undefined, "sqlite3*"
 | |
|        ^^^ we cannot actually currently support this because JS is
 | |
|         single-threaded and we don't have a portable way to access a DB
 | |
|         from 2 SharedWorkers concurrently. ],*/
 | |
|     ["sqlite3_keyword_count", "int"],
 | |
|     ["sqlite3_keyword_name", "int", ["int", "**", "*"]],
 | |
|     ["sqlite3_keyword_check", "int", ["string", "int"]],
 | |
|     ["sqlite3_libversion", "string"],
 | |
|     ["sqlite3_libversion_number", "int"],
 | |
|     ["sqlite3_limit", "int", ["sqlite3*", "int", "int"]],
 | |
|     ["sqlite3_malloc", "*","int"],
 | |
|     ["sqlite3_open", "int", "string", "*"],
 | |
|     ["sqlite3_open_v2", "int", "string", "*", "int", "string"],
 | |
|     /* sqlite3_prepare_v2() and sqlite3_prepare_v3() are handled
 | |
|        separately due to us requiring two different sets of semantics
 | |
|        for those, depending on how their SQL argument is provided. */
 | |
|     /* sqlite3_randomness() uses a hand-written wrapper to extend
 | |
|        the range of supported argument types. */
 | |
|     ["sqlite3_progress_handler", undefined, [
 | |
|       "sqlite3*", "int", new wasm.xWrap.FuncPtrAdapter({
 | |
|         name: 'xProgressHandler',
 | |
|         signature: 'i(p)',
 | |
|         bindScope: 'context',
 | |
|         contextKey: (argv,argIndex)=>argv[0/* sqlite3* */]
 | |
|       }), "*"
 | |
|     ]],
 | |
|     ["sqlite3_realloc", "*","*","int"],
 | |
|     ["sqlite3_reset", "int", "sqlite3_stmt*"],
 | |
|     /* sqlite3_reset_auto_extension() has a hand-written binding. */
 | |
|     ["sqlite3_result_blob", undefined, "sqlite3_context*", "*", "int", "*"],
 | |
|     ["sqlite3_result_double", undefined, "sqlite3_context*", "f64"],
 | |
|     ["sqlite3_result_error", undefined, "sqlite3_context*", "string", "int"],
 | |
|     ["sqlite3_result_error_code", undefined, "sqlite3_context*", "int"],
 | |
|     ["sqlite3_result_error_nomem", undefined, "sqlite3_context*"],
 | |
|     ["sqlite3_result_error_toobig", undefined, "sqlite3_context*"],
 | |
|     ["sqlite3_result_int", undefined, "sqlite3_context*", "int"],
 | |
|     ["sqlite3_result_null", undefined, "sqlite3_context*"],
 | |
|     ["sqlite3_result_pointer", undefined,
 | |
|      "sqlite3_context*", "*", "string:static", "*"],
 | |
|     ["sqlite3_result_subtype", undefined, "sqlite3_value*", "int"],
 | |
|     ["sqlite3_result_text", undefined, "sqlite3_context*", "string", "int", "*"],
 | |
|     ["sqlite3_result_zeroblob", undefined, "sqlite3_context*", "int"],
 | |
|     ["sqlite3_rollback_hook", "void*", [
 | |
|       "sqlite3*",
 | |
|       new wasm.xWrap.FuncPtrAdapter({
 | |
|         name: 'sqlite3_rollback_hook',
 | |
|         signature: 'v(p)',
 | |
|         contextKey: (argv)=>argv[0/* sqlite3* */]
 | |
|       }),
 | |
|       '*'
 | |
|     ]],
 | |
|     ["sqlite3_set_authorizer", "int", [
 | |
|       "sqlite3*",
 | |
|       new wasm.xWrap.FuncPtrAdapter({
 | |
|         name: "sqlite3_set_authorizer::xAuth",
 | |
|         signature: "i(pi"+"ssss)",
 | |
|         contextKey: (argv, argIndex)=>argv[0/*(sqlite3*)*/],
 | |
|         callProxy: (callback)=>{
 | |
|           return (pV, iCode, s0, s1, s2, s3)=>{
 | |
|             try{
 | |
|               s0 = s0 && wasm.cstrToJs(s0); s1 = s1 && wasm.cstrToJs(s1);
 | |
|               s2 = s2 && wasm.cstrToJs(s2); s3 = s3 && wasm.cstrToJs(s3);
 | |
|               return callback(pV, iCode, s0, s1, s2, s3) || 0;
 | |
|             }catch(e){
 | |
|               return e.resultCode || capi.SQLITE_ERROR;
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }),
 | |
|       "*"/*pUserData*/
 | |
|     ]],
 | |
|     ["sqlite3_set_auxdata", undefined, [
 | |
|       "sqlite3_context*", "int", "*",
 | |
|       new wasm.xWrap.FuncPtrAdapter({
 | |
|         name: 'xDestroyAuxData',
 | |
|         signature: 'v(*)',
 | |
|         contextKey: (argv, argIndex)=>argv[0/* sqlite3_context* */]
 | |
|       })
 | |
|     ]],
 | |
|     ["sqlite3_shutdown", undefined],
 | |
|     ["sqlite3_sourceid", "string"],
 | |
|     ["sqlite3_sql", "string", "sqlite3_stmt*"],
 | |
|     ["sqlite3_status", "int", "int", "*", "*", "int"],
 | |
|     ["sqlite3_step", "int", "sqlite3_stmt*"],
 | |
|     ["sqlite3_stmt_isexplain", "int", ["sqlite3_stmt*"]],
 | |
|     ["sqlite3_stmt_readonly", "int", ["sqlite3_stmt*"]],
 | |
|     ["sqlite3_stmt_status", "int", "sqlite3_stmt*", "int", "int"],
 | |
|     ["sqlite3_strglob", "int", "string","string"],
 | |
|     ["sqlite3_stricmp", "int", "string", "string"],
 | |
|     ["sqlite3_strlike", "int", "string", "string","int"],
 | |
|     ["sqlite3_strnicmp", "int", "string", "string", "int"],
 | |
|     ["sqlite3_table_column_metadata", "int",
 | |
|      "sqlite3*", "string", "string", "string",
 | |
|      "**", "**", "*", "*", "*"],
 | |
|     ["sqlite3_total_changes", "int", "sqlite3*"],
 | |
|     ["sqlite3_trace_v2", "int", [
 | |
|       "sqlite3*", "int",
 | |
|       new wasm.xWrap.FuncPtrAdapter({
 | |
|         name: 'sqlite3_trace_v2::callback',
 | |
|         signature: 'i(ippp)',
 | |
|         contextKey: (argv,argIndex)=>argv[0/* sqlite3* */]
 | |
|       }),
 | |
|       "*"
 | |
|     ]],
 | |
|     ["sqlite3_txn_state", "int", ["sqlite3*","string"]],
 | |
|     /* Note that sqlite3_uri_...() have very specific requirements for
 | |
|        their first C-string arguments, so we cannot perform any value
 | |
|        conversion on those. */
 | |
|     ["sqlite3_uri_boolean", "int", "sqlite3_filename", "string", "int"],
 | |
|     ["sqlite3_uri_key", "string", "sqlite3_filename", "int"],
 | |
|     ["sqlite3_uri_parameter", "string", "sqlite3_filename", "string"],
 | |
|     ["sqlite3_user_data","void*", "sqlite3_context*"],
 | |
|     ["sqlite3_value_blob", "*", "sqlite3_value*"],
 | |
|     ["sqlite3_value_bytes","int", "sqlite3_value*"],
 | |
|     ["sqlite3_value_double","f64", "sqlite3_value*"],
 | |
|     ["sqlite3_value_dup", "sqlite3_value*", "sqlite3_value*"],
 | |
|     ["sqlite3_value_free", undefined, "sqlite3_value*"],
 | |
|     ["sqlite3_value_frombind", "int", "sqlite3_value*"],
 | |
|     ["sqlite3_value_int","int", "sqlite3_value*"],
 | |
|     ["sqlite3_value_nochange", "int", "sqlite3_value*"],
 | |
|     ["sqlite3_value_numeric_type", "int", "sqlite3_value*"],
 | |
|     ["sqlite3_value_pointer", "*", "sqlite3_value*", "string:static"],
 | |
|     ["sqlite3_value_subtype", "int", "sqlite3_value*"],
 | |
|     ["sqlite3_value_text", "string", "sqlite3_value*"],
 | |
|     ["sqlite3_value_type", "int", "sqlite3_value*"],
 | |
|     ["sqlite3_vfs_find", "*", "string"],
 | |
|     ["sqlite3_vfs_register", "int", "sqlite3_vfs*", "int"],
 | |
|     ["sqlite3_vfs_unregister", "int", "sqlite3_vfs*"]
 | |
|   ]/*wasm.bindingSignatures*/;
 | |
| 
 | |
|   if(false && wasm.compileOptionUsed('SQLITE_ENABLE_NORMALIZE')){
 | |
|     /* ^^^ "the problem" is that this is an option feature and the
 | |
|        build-time function-export list does not currently take
 | |
|        optional features into account. */
 | |
|     wasm.bindingSignatures.push(["sqlite3_normalized_sql", "string", "sqlite3_stmt*"]);
 | |
|   }
 | |
| 
 | |
|   if(wasm.exports.sqlite3_activate_see instanceof Function){
 | |
|     wasm.bindingSignatures.push(
 | |
|       ["sqlite3_key", "int", "sqlite3*", "string", "int"],
 | |
|       ["sqlite3_key_v2","int","sqlite3*","string","*","int"],
 | |
|       ["sqlite3_rekey", "int", "sqlite3*", "string", "int"],
 | |
|       ["sqlite3_rekey_v2", "int", "sqlite3*", "string", "*", "int"],
 | |
|       ["sqlite3_activate_see", undefined, "string"]
 | |
|     );
 | |
|   }
 | |
|   /**
 | |
|      Functions which require BigInt (int64) support are separated from
 | |
|      the others because we need to conditionally bind them or apply
 | |
|      dummy impls, depending on the capabilities of the environment.
 | |
| 
 | |
|      Note that not all of these functions directly require int64
 | |
|      but are only for use with APIs which require int64. For example,
 | |
|      the vtab-related functions.
 | |
|   */
 | |
|   wasm.bindingSignatures.int64 = [
 | |
|     ["sqlite3_bind_int64","int", ["sqlite3_stmt*", "int", "i64"]],
 | |
|     ["sqlite3_changes64","i64", ["sqlite3*"]],
 | |
|     ["sqlite3_column_int64","i64", ["sqlite3_stmt*", "int"]],
 | |
|     ["sqlite3_create_module", "int",
 | |
|      ["sqlite3*","string","sqlite3_module*","*"]],
 | |
|     ["sqlite3_create_module_v2", "int",
 | |
|      ["sqlite3*","string","sqlite3_module*","*","*"]],
 | |
|     ["sqlite3_declare_vtab", "int", ["sqlite3*", "string:flexible"]],
 | |
|     ["sqlite3_deserialize", "int", "sqlite3*", "string", "*", "i64", "i64", "int"]
 | |
|     /* Careful! Short version: de/serialize() are problematic because they
 | |
|        might use a different allocator than the user for managing the
 | |
|        deserialized block. de/serialize() are ONLY safe to use with
 | |
|        sqlite3_malloc(), sqlite3_free(), and its 64-bit variants. */,
 | |
|     ["sqlite3_drop_modules", "int", ["sqlite3*", "**"]],
 | |
|     ["sqlite3_last_insert_rowid", "i64", ["sqlite3*"]],
 | |
|     ["sqlite3_malloc64", "*","i64"],
 | |
|     ["sqlite3_msize", "i64", "*"],
 | |
|     ["sqlite3_overload_function", "int", ["sqlite3*","string","int"]],
 | |
|     ["sqlite3_preupdate_blobwrite", "int", "sqlite3*"],
 | |
|     ["sqlite3_preupdate_count", "int", "sqlite3*"],
 | |
|     ["sqlite3_preupdate_depth", "int", "sqlite3*"],
 | |
|     ["sqlite3_preupdate_hook", "*", [
 | |
|       "sqlite3*",
 | |
|       new wasm.xWrap.FuncPtrAdapter({
 | |
|         name: 'sqlite3_preupdate_hook',
 | |
|         signature: "v(ppippjj)",
 | |
|         contextKey: (argv)=>argv[0/* sqlite3* */],
 | |
|         callProxy: (callback)=>{
 | |
|           return (p,db,op,zDb,zTbl,iKey1,iKey2)=>{
 | |
|             callback(p, db, op, wasm.cstrToJs(zDb), wasm.cstrToJs(zTbl),
 | |
|                      iKey1, iKey2);
 | |
|           };
 | |
|         }
 | |
|       }),
 | |
|       "*"
 | |
|     ]],
 | |
|     ["sqlite3_preupdate_new", "int", ["sqlite3*", "int", "**"]],
 | |
|     ["sqlite3_preupdate_old", "int", ["sqlite3*", "int", "**"]],
 | |
|     ["sqlite3_realloc64", "*","*", "i64"],
 | |
|     ["sqlite3_result_int64", undefined, "*", "i64"],
 | |
|     ["sqlite3_result_zeroblob64", "int", "*", "i64"],
 | |
|     ["sqlite3_serialize","*", "sqlite3*", "string", "*", "int"],
 | |
|     ["sqlite3_set_last_insert_rowid", undefined, ["sqlite3*", "i64"]],
 | |
|     ["sqlite3_status64", "int", "int", "*", "*", "int"],
 | |
|     ["sqlite3_total_changes64", "i64", ["sqlite3*"]],
 | |
|     ["sqlite3_update_hook", "*", [
 | |
|       "sqlite3*",
 | |
|       new wasm.xWrap.FuncPtrAdapter({
 | |
|         name: 'sqlite3_update_hook',
 | |
|         signature: "v(iippj)",
 | |
|         contextKey: (argv)=>argv[0/* sqlite3* */],
 | |
|         callProxy: (callback)=>{
 | |
|           return (p,op,z0,z1,rowid)=>{
 | |
|             callback(p, op, wasm.cstrToJs(z0), wasm.cstrToJs(z1), rowid);
 | |
|           };
 | |
|         }
 | |
|       }),
 | |
|       "*"
 | |
|     ]],
 | |
|     ["sqlite3_uri_int64", "i64", ["sqlite3_filename", "string", "i64"]],
 | |
|     ["sqlite3_value_int64","i64", "sqlite3_value*"],
 | |
|     ["sqlite3_vtab_collation","string","sqlite3_index_info*","int"],
 | |
|     ["sqlite3_vtab_distinct","int", "sqlite3_index_info*"],
 | |
|     ["sqlite3_vtab_in","int", "sqlite3_index_info*", "int", "int"],
 | |
|     ["sqlite3_vtab_in_first", "int", "sqlite3_value*", "**"],
 | |
|     ["sqlite3_vtab_in_next", "int", "sqlite3_value*", "**"],
 | |
|     /*["sqlite3_vtab_config" is variadic and requires a hand-written
 | |
|       proxy.] */
 | |
|     ["sqlite3_vtab_nochange","int", "sqlite3_context*"],
 | |
|     ["sqlite3_vtab_on_conflict","int", "sqlite3*"],
 | |
|     ["sqlite3_vtab_rhs_value","int", "sqlite3_index_info*", "int", "**"]
 | |
|   ];
 | |
| 
 | |
|   // Add session/changeset APIs...
 | |
|   if(wasm.bigIntEnabled && !!wasm.exports.sqlite3changegroup_add){
 | |
|     /* ACHTUNG: 2022-12-23: the session/changeset API bindings are
 | |
|        COMPLETELY UNTESTED. */
 | |
|     /**
 | |
|        FuncPtrAdapter options for session-related callbacks with the
 | |
|        native signature "i(ps)". This proxy converts the 2nd argument
 | |
|        from a C string to a JS string before passing the arguments on
 | |
|        to the client-provided JS callback.
 | |
|     */
 | |
|     const __ipsProxy = {
 | |
|       signature: 'i(ps)',
 | |
|       callProxy:(callback)=>{
 | |
|         return (p,s)=>{
 | |
|           try{return callback(p, wasm.cstrToJs(s)) | 0}
 | |
|           catch(e){return e.resultCode || capi.SQLITE_ERROR}
 | |
|         }
 | |
|       }
 | |
|     };
 | |
| 
 | |
|     wasm.bindingSignatures.int64.push(...[
 | |
|       ['sqlite3changegroup_add', 'int', ['sqlite3_changegroup*', 'int', 'void*']],
 | |
|       ['sqlite3changegroup_add_strm', 'int', [
 | |
|         'sqlite3_changegroup*',
 | |
|         new wasm.xWrap.FuncPtrAdapter({
 | |
|           name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
 | |
|         }),
 | |
|         'void*'
 | |
|       ]],
 | |
|       ['sqlite3changegroup_delete', undefined, ['sqlite3_changegroup*']],
 | |
|       ['sqlite3changegroup_new', 'int', ['**']],
 | |
|       ['sqlite3changegroup_output', 'int', ['sqlite3_changegroup*', 'int*', '**']],
 | |
|       ['sqlite3changegroup_output_strm', 'int', [
 | |
|         'sqlite3_changegroup*',
 | |
|         new wasm.xWrap.FuncPtrAdapter({
 | |
|           name: 'xOutput', signature: 'i(ppi)', bindScope: 'transient'
 | |
|         }),
 | |
|         'void*'
 | |
|       ]],
 | |
|       ['sqlite3changeset_apply', 'int', [
 | |
|         'sqlite3*', 'int', 'void*',
 | |
|         new wasm.xWrap.FuncPtrAdapter({
 | |
|           name: 'xFilter', bindScope: 'transient', ...__ipsProxy
 | |
|         }),
 | |
|         new wasm.xWrap.FuncPtrAdapter({
 | |
|           name: 'xConflict', signature: 'i(pip)', bindScope: 'transient'
 | |
|         }),
 | |
|         'void*'
 | |
|       ]],
 | |
|       ['sqlite3changeset_apply_strm', 'int', [
 | |
|         'sqlite3*',
 | |
|         new wasm.xWrap.FuncPtrAdapter({
 | |
|           name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
 | |
|         }),
 | |
|         'void*',
 | |
|         new wasm.xWrap.FuncPtrAdapter({
 | |
|           name: 'xFilter', bindScope: 'transient', ...__ipsProxy
 | |
|         }),
 | |
|         new wasm.xWrap.FuncPtrAdapter({
 | |
|           name: 'xConflict', signature: 'i(pip)', bindScope: 'transient'
 | |
|         }),
 | |
|         'void*'
 | |
|       ]],
 | |
|       ['sqlite3changeset_apply_v2', 'int', [
 | |
|         'sqlite3*', 'int', 'void*',
 | |
|         new wasm.xWrap.FuncPtrAdapter({
 | |
|           name: 'xFilter', bindScope: 'transient', ...__ipsProxy
 | |
|         }),
 | |
|         new wasm.xWrap.FuncPtrAdapter({
 | |
|           name: 'xConflict', signature: 'i(pip)', bindScope: 'transient'
 | |
|         }),
 | |
|         'void*', '**', 'int*', 'int'
 | |
| 
 | |
|       ]],
 | |
|       ['sqlite3changeset_apply_v2_strm', 'int', [
 | |
|         'sqlite3*',
 | |
|         new wasm.xWrap.FuncPtrAdapter({
 | |
|           name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
 | |
|         }),
 | |
|         'void*',
 | |
|         new wasm.xWrap.FuncPtrAdapter({
 | |
|           name: 'xFilter', bindScope: 'transient', ...__ipsProxy
 | |
|         }),
 | |
|         new wasm.xWrap.FuncPtrAdapter({
 | |
|           name: 'xConflict', signature: 'i(pip)', bindScope: 'transient'
 | |
|         }),
 | |
|         'void*', '**', 'int*', 'int'
 | |
|       ]],
 | |
|       ['sqlite3changeset_concat', 'int', ['int','void*', 'int', 'void*', 'int*', '**']],
 | |
|       ['sqlite3changeset_concat_strm', 'int', [
 | |
|         new wasm.xWrap.FuncPtrAdapter({
 | |
|           name: 'xInputA', signature: 'i(ppp)', bindScope: 'transient'
 | |
|         }),
 | |
|         'void*',
 | |
|         new wasm.xWrap.FuncPtrAdapter({
 | |
|           name: 'xInputB', signature: 'i(ppp)', bindScope: 'transient'
 | |
|         }),
 | |
|         'void*',
 | |
|         new wasm.xWrap.FuncPtrAdapter({
 | |
|           name: 'xOutput', signature: 'i(ppi)', bindScope: 'transient'
 | |
|         }),
 | |
|         'void*'
 | |
|       ]],
 | |
|       ['sqlite3changeset_conflict', 'int', ['sqlite3_changeset_iter*', 'int', '**']],
 | |
|       ['sqlite3changeset_finalize', 'int', ['sqlite3_changeset_iter*']],
 | |
|       ['sqlite3changeset_fk_conflicts', 'int', ['sqlite3_changeset_iter*', 'int*']],
 | |
|       ['sqlite3changeset_invert', 'int', ['int', 'void*', 'int*', '**']],
 | |
|       ['sqlite3changeset_invert_strm', 'int', [
 | |
|         new wasm.xWrap.FuncPtrAdapter({
 | |
|           name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
 | |
|         }),
 | |
|         'void*',
 | |
|         new wasm.xWrap.FuncPtrAdapter({
 | |
|           name: 'xOutput', signature: 'i(ppi)', bindScope: 'transient'
 | |
|         }),
 | |
|         'void*'
 | |
|       ]],
 | |
|       ['sqlite3changeset_new', 'int', ['sqlite3_changeset_iter*', 'int', '**']],
 | |
|       ['sqlite3changeset_next', 'int', ['sqlite3_changeset_iter*']],
 | |
|       ['sqlite3changeset_old', 'int', ['sqlite3_changeset_iter*', 'int', '**']],
 | |
|       ['sqlite3changeset_op', 'int', [
 | |
|         'sqlite3_changeset_iter*', '**', 'int*', 'int*','int*'
 | |
|       ]],
 | |
|       ['sqlite3changeset_pk', 'int', ['sqlite3_changeset_iter*', '**', 'int*']],
 | |
|       ['sqlite3changeset_start', 'int', ['**', 'int', '*']],
 | |
|       ['sqlite3changeset_start_strm', 'int', [
 | |
|         '**',
 | |
|         new wasm.xWrap.FuncPtrAdapter({
 | |
|           name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
 | |
|         }),
 | |
|         'void*'
 | |
|       ]],
 | |
|       ['sqlite3changeset_start_v2', 'int', ['**', 'int', '*', 'int']],
 | |
|       ['sqlite3changeset_start_v2_strm', 'int', [
 | |
|         '**',
 | |
|         new wasm.xWrap.FuncPtrAdapter({
 | |
|           name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
 | |
|         }),
 | |
|         'void*', 'int'
 | |
|       ]],
 | |
|       ['sqlite3session_attach', 'int', ['sqlite3_session*', 'string']],
 | |
|       ['sqlite3session_changeset', 'int', ['sqlite3_session*', 'int*', '**']],
 | |
|       ['sqlite3session_changeset_size', 'i64', ['sqlite3_session*']],
 | |
|       ['sqlite3session_changeset_strm', 'int', [
 | |
|         'sqlite3_session*',
 | |
|         new wasm.xWrap.FuncPtrAdapter({
 | |
|           name: 'xOutput', signature: 'i(ppp)', bindScope: 'transient'
 | |
|         }),
 | |
|         'void*'
 | |
|       ]],
 | |
|       ['sqlite3session_config', 'int', ['int', 'void*']],
 | |
|       ['sqlite3session_create', 'int', ['sqlite3*', 'string', '**']],
 | |
|       //sqlite3session_delete() is bound manually
 | |
|       ['sqlite3session_diff', 'int', ['sqlite3_session*', 'string', 'string', '**']],
 | |
|       ['sqlite3session_enable', 'int', ['sqlite3_session*', 'int']],
 | |
|       ['sqlite3session_indirect', 'int', ['sqlite3_session*', 'int']],
 | |
|       ['sqlite3session_isempty', 'int', ['sqlite3_session*']],
 | |
|       ['sqlite3session_memory_used', 'i64', ['sqlite3_session*']],
 | |
|       ['sqlite3session_object_config', 'int', ['sqlite3_session*', 'int', 'void*']],
 | |
|       ['sqlite3session_patchset', 'int', ['sqlite3_session*', '*', '**']],
 | |
|       ['sqlite3session_patchset_strm', 'int', [
 | |
|         'sqlite3_session*',
 | |
|         new wasm.xWrap.FuncPtrAdapter({
 | |
|           name: 'xOutput', signature: 'i(ppp)', bindScope: 'transient'
 | |
|         }),
 | |
|         'void*'
 | |
|       ]],
 | |
|       ['sqlite3session_table_filter', undefined, [
 | |
|         'sqlite3_session*',
 | |
|         new wasm.xWrap.FuncPtrAdapter({
 | |
|           name: 'xFilter', ...__ipsProxy,
 | |
|           contextKey: (argv,argIndex)=>argv[0/* (sqlite3_session*) */]
 | |
|         }),
 | |
|         '*'
 | |
|       ]]
 | |
|     ]);
 | |
|   }/*session/changeset APIs*/
 | |
| 
 | |
|   /**
 | |
|      Functions which are intended solely for API-internal use by the
 | |
|      WASM components, not client code. These get installed into
 | |
|      sqlite3.wasm. Some of them get exposed to clients via variants
 | |
|      named sqlite3_js_...().
 | |
|   */
 | |
|   wasm.bindingSignatures.wasm = [
 | |
|     ["sqlite3_wasm_db_reset", "int", "sqlite3*"],
 | |
|     ["sqlite3_wasm_db_vfs", "sqlite3_vfs*", "sqlite3*","string"],
 | |
|     ["sqlite3_wasm_vfs_create_file", "int",
 | |
|      "sqlite3_vfs*","string","*", "int"],
 | |
|     ["sqlite3_wasm_vfs_unlink", "int", "sqlite3_vfs*","string"]
 | |
|   ];
 | |
| 
 | |
|   /**
 | |
|      Install JS<->C struct bindings for the non-opaque struct types we
 | |
|      need... */
 | |
|   sqlite3.StructBinder = globalThis.Jaccwabyt({
 | |
|     heap: 0 ? wasm.memory : wasm.heap8u,
 | |
|     alloc: wasm.alloc,
 | |
|     dealloc: wasm.dealloc,
 | |
|     bigIntEnabled: wasm.bigIntEnabled,
 | |
|     memberPrefix: /* Never change this: this prefix is baked into any
 | |
|                      amount of code and client-facing docs. */ '$'
 | |
|   });
 | |
|   delete globalThis.Jaccwabyt;
 | |
| 
 | |
|   {// wasm.xWrap() bindings...
 | |
| 
 | |
|     /* Convert Arrays and certain TypedArrays to strings for
 | |
|        'string:flexible'-type arguments */
 | |
|     const __xString = wasm.xWrap.argAdapter('string');
 | |
|     wasm.xWrap.argAdapter(
 | |
|       'string:flexible', (v)=>__xString(util.flexibleString(v))
 | |
|     );
 | |
| 
 | |
|     /**
 | |
|        The 'string:static' argument adapter treats its argument as
 | |
|        either...
 | |
| 
 | |
|        - WASM pointer: assumed to be a long-lived C-string which gets
 | |
|          returned as-is.
 | |
| 
 | |
|        - Anything else: gets coerced to a JS string for use as a map
 | |
|          key. If a matching entry is found (as described next), it is
 | |
|          returned, else wasm.allocCString() is used to create a a new
 | |
|          string, map its pointer to (''+v) for the remainder of the
 | |
|          application's life, and returns that pointer value for this
 | |
|          call and all future calls which are passed a
 | |
|          string-equivalent argument.
 | |
| 
 | |
|        Use case: sqlite3_bind_pointer() and sqlite3_result_pointer()
 | |
|        call for "a static string and preferably a string
 | |
|        literal". This converter is used to ensure that the string
 | |
|        value seen by those functions is long-lived and behaves as they
 | |
|        need it to.
 | |
|     */
 | |
|     wasm.xWrap.argAdapter(
 | |
|       'string:static',
 | |
|       function(v){
 | |
|         if(wasm.isPtr(v)) return v;
 | |
|         v = ''+v;
 | |
|         let rc = this[v];
 | |
|         return rc || (this[v] = wasm.allocCString(v));
 | |
|       }.bind(Object.create(null))
 | |
|     );
 | |
| 
 | |
|     /**
 | |
|        Add some descriptive xWrap() aliases for '*' intended to (A)
 | |
|        initially improve readability/correctness of
 | |
|        wasm.bindingSignatures and (B) provide automatic conversion
 | |
|        from higher-level representations, e.g. capi.sqlite3_vfs to
 | |
|        `sqlite3_vfs*` via capi.sqlite3_vfs.pointer.
 | |
|     */
 | |
|     const __xArgPtr = wasm.xWrap.argAdapter('*');
 | |
|     const nilType = function(){}/*a class no value can ever be an instance of*/;
 | |
|     wasm.xWrap.argAdapter('sqlite3_filename', __xArgPtr)
 | |
|     ('sqlite3_context*', __xArgPtr)
 | |
|     ('sqlite3_value*', __xArgPtr)
 | |
|     ('void*', __xArgPtr)
 | |
|     ('sqlite3_changegroup*', __xArgPtr)
 | |
|     ('sqlite3_changeset_iter*', __xArgPtr)
 | |
|     //('sqlite3_rebaser*', __xArgPtr)
 | |
|     ('sqlite3_session*', __xArgPtr)
 | |
|     ('sqlite3_stmt*', (v)=>
 | |
|       __xArgPtr((v instanceof (sqlite3?.oo1?.Stmt || nilType))
 | |
|            ? v.pointer : v))
 | |
|     ('sqlite3*', (v)=>
 | |
|       __xArgPtr((v instanceof (sqlite3?.oo1?.DB || nilType))
 | |
|            ? v.pointer : v))
 | |
|     ('sqlite3_index_info*', (v)=>
 | |
|       __xArgPtr((v instanceof (capi.sqlite3_index_info || nilType))
 | |
|            ? v.pointer : v))
 | |
|     ('sqlite3_module*', (v)=>
 | |
|       __xArgPtr((v instanceof (capi.sqlite3_module || nilType))
 | |
|            ? v.pointer : v))
 | |
|     /**
 | |
|        `sqlite3_vfs*`:
 | |
| 
 | |
|        - v is-a string: use the result of sqlite3_vfs_find(v) but
 | |
|          throw if it returns 0.
 | |
|        - v is-a capi.sqlite3_vfs: use v.pointer.
 | |
|        - Else return the same as the `'*'` argument conversion.
 | |
|     */
 | |
|     ('sqlite3_vfs*', (v)=>{
 | |
|       if('string'===typeof v){
 | |
|         /* A NULL sqlite3_vfs pointer will be treated as the default
 | |
|            VFS in many contexts. We specifically do not want that
 | |
|            behavior here. */
 | |
|         return capi.sqlite3_vfs_find(v)
 | |
|           || sqlite3.SQLite3Error.toss(
 | |
|             capi.SQLITE_NOTFOUND,
 | |
|             "Unknown sqlite3_vfs name:", v
 | |
|           );
 | |
|       }
 | |
|       return __xArgPtr((v instanceof (capi.sqlite3_vfs || nilType))
 | |
|                        ? v.pointer : v);
 | |
|     });
 | |
| 
 | |
|     const __xRcPtr = wasm.xWrap.resultAdapter('*');
 | |
|     wasm.xWrap.resultAdapter('sqlite3*', __xRcPtr)
 | |
|     ('sqlite3_context*', __xRcPtr)
 | |
|     ('sqlite3_stmt*', __xRcPtr)
 | |
|     ('sqlite3_value*', __xRcPtr)
 | |
|     ('sqlite3_vfs*', __xRcPtr)
 | |
|     ('void*', __xRcPtr);
 | |
| 
 | |
|     /**
 | |
|        Populate api object with sqlite3_...() by binding the "raw" wasm
 | |
|        exports into type-converting proxies using wasm.xWrap().
 | |
|     */
 | |
|     if(0 === wasm.exports.sqlite3_step.length){
 | |
|       /* This environment wraps exports in nullary functions, which means
 | |
|          we must disable the arg-count validation we otherwise perform
 | |
|          on the wrappers. */
 | |
|       wasm.xWrap.doArgcCheck = false;
 | |
|       sqlite3.config.warn(
 | |
|         "Disabling sqlite3.wasm.xWrap.doArgcCheck due to environmental quirks."
 | |
|       );
 | |
|     }
 | |
|     for(const e of wasm.bindingSignatures){
 | |
|       capi[e[0]] = wasm.xWrap.apply(null, e);
 | |
|     }
 | |
|     for(const e of wasm.bindingSignatures.wasm){
 | |
|       wasm[e[0]] = wasm.xWrap.apply(null, e);
 | |
|     }
 | |
| 
 | |
|     /* For C API functions which cannot work properly unless
 | |
|        wasm.bigIntEnabled is true, install a bogus impl which throws
 | |
|        if called when bigIntEnabled is false. The alternative would be
 | |
|        to elide these functions altogether, which seems likely to
 | |
|        cause more confusion. */
 | |
|     const fI64Disabled = function(fname){
 | |
|       return ()=>toss(fname+"() is unavailable due to lack",
 | |
|                       "of BigInt support in this build.");
 | |
|     };
 | |
|     for(const e of wasm.bindingSignatures.int64){
 | |
|       capi[e[0]] = wasm.bigIntEnabled
 | |
|         ? wasm.xWrap.apply(null, e)
 | |
|         : fI64Disabled(e[0]);
 | |
|     }
 | |
| 
 | |
|     /* There's no need to expose bindingSignatures to clients,
 | |
|        implicitly making it part of the public interface. */
 | |
|     delete wasm.bindingSignatures;
 | |
| 
 | |
|     if(wasm.exports.sqlite3_wasm_db_error){
 | |
|       const __db_err = wasm.xWrap(
 | |
|         'sqlite3_wasm_db_error', 'int', 'sqlite3*', 'int', 'string'
 | |
|       );
 | |
|       /**
 | |
|          Sets the given db's error state. Accepts:
 | |
| 
 | |
|          - (sqlite3*, int code, string msg)
 | |
|          - (sqlite3*, Error e [,string msg = ''+e])
 | |
| 
 | |
|          If passed a WasmAllocError, the message is ignored and the
 | |
|          result code is SQLITE_NOMEM. If passed any other Error type,
 | |
|          the result code defaults to SQLITE_ERROR unless the Error
 | |
|          object has a resultCode property, in which case that is used
 | |
|          (e.g. SQLite3Error has that). If passed a non-WasmAllocError
 | |
|          exception, the message string defaults to theError.message.
 | |
| 
 | |
|          Returns the resulting code. Pass (pDb,0,0) to clear the error
 | |
|          state.
 | |
|        */
 | |
|       util.sqlite3_wasm_db_error = function(pDb, resultCode, message){
 | |
|         if(resultCode instanceof sqlite3.WasmAllocError){
 | |
|           resultCode = capi.SQLITE_NOMEM;
 | |
|           message = 0 /*avoid allocating message string*/;
 | |
|         }else if(resultCode instanceof Error){
 | |
|           message = message || ''+resultCode;
 | |
|           resultCode = (resultCode.resultCode || capi.SQLITE_ERROR);
 | |
|         }
 | |
|         return pDb ? __db_err(pDb, resultCode, message) : resultCode;
 | |
|       };
 | |
|     }else{
 | |
|       util.sqlite3_wasm_db_error = function(pDb,errCode,msg){
 | |
|         console.warn("sqlite3_wasm_db_error() is not exported.",arguments);
 | |
|         return errCode;
 | |
|       };
 | |
|     }
 | |
|   }/*xWrap() bindings*/
 | |
| 
 | |
|   {/* Import C-level constants and structs... */
 | |
|     const cJson = wasm.xCall('sqlite3_wasm_enum_json');
 | |
|     if(!cJson){
 | |
|       toss("Maintenance required: increase sqlite3_wasm_enum_json()'s",
 | |
|            "static buffer size!");
 | |
|     }
 | |
|     //console.debug('wasm.ctype length =',wasm.cstrlen(cJson));
 | |
|     wasm.ctype = JSON.parse(wasm.cstrToJs(cJson));
 | |
|     // Groups of SQLITE_xyz macros...
 | |
|     const defineGroups = ['access', 'authorizer',
 | |
|                           'blobFinalizers', 'changeset',
 | |
|                           'config', 'dataTypes',
 | |
|                           'dbConfig', 'dbStatus',
 | |
|                           'encodings', 'fcntl', 'flock', 'ioCap',
 | |
|                           'limits', 'openFlags',
 | |
|                           'prepareFlags', 'resultCodes',
 | |
|                           'sqlite3Status',
 | |
|                           'stmtStatus', 'syncFlags',
 | |
|                           'trace', 'txnState', 'udfFlags',
 | |
|                           'version' ];
 | |
|     if(wasm.bigIntEnabled){
 | |
|       defineGroups.push('serialize', 'session', 'vtab');
 | |
|     }
 | |
|     for(const t of defineGroups){
 | |
|       for(const e of Object.entries(wasm.ctype[t])){
 | |
|         // ^^^ [k,v] there triggers a buggy code transformation via
 | |
|         // one of the Emscripten-driven optimizers.
 | |
|         capi[e[0]] = e[1];
 | |
|       }
 | |
|     }
 | |
|     if(!wasm.functionEntry(capi.SQLITE_WASM_DEALLOC)){
 | |
|       toss("Internal error: cannot resolve exported function",
 | |
|            "entry SQLITE_WASM_DEALLOC (=="+capi.SQLITE_WASM_DEALLOC+").");
 | |
|     }
 | |
|     const __rcMap = Object.create(null);
 | |
|     for(const t of ['resultCodes']){
 | |
|       for(const e of Object.entries(wasm.ctype[t])){
 | |
|         __rcMap[e[1]] = e[0];
 | |
|       }
 | |
|     }
 | |
|     /**
 | |
|        For the given integer, returns the SQLITE_xxx result code as a
 | |
|        string, or undefined if no such mapping is found.
 | |
|     */
 | |
|     capi.sqlite3_js_rc_str = (rc)=>__rcMap[rc];
 | |
|     /* Bind all registered C-side structs... */
 | |
|     const notThese = Object.assign(Object.create(null),{
 | |
|       // For each struct to NOT register, map its name to true:
 | |
|       WasmTestStruct: true,
 | |
|       /* We unregister the kvvfs VFS from Worker threads below. */
 | |
|       sqlite3_kvvfs_methods: !util.isUIThread(),
 | |
|       /* sqlite3_index_info and friends require int64: */
 | |
|       sqlite3_index_info: !wasm.bigIntEnabled,
 | |
|       sqlite3_index_constraint: !wasm.bigIntEnabled,
 | |
|       sqlite3_index_orderby: !wasm.bigIntEnabled,
 | |
|       sqlite3_index_constraint_usage: !wasm.bigIntEnabled
 | |
|     });
 | |
|     for(const s of wasm.ctype.structs){
 | |
|       if(!notThese[s.name]){
 | |
|         capi[s.name] = sqlite3.StructBinder(s);
 | |
|       }
 | |
|     }
 | |
|     if(capi.sqlite3_index_info){
 | |
|       /* Move these inner structs into sqlite3_index_info.  Binding
 | |
|       ** them to WASM requires that we create global-scope structs to
 | |
|       ** model them with, but those are no longer needed after we've
 | |
|       ** passed them to StructBinder. */
 | |
|       for(const k of ['sqlite3_index_constraint',
 | |
|                       'sqlite3_index_orderby',
 | |
|                       'sqlite3_index_constraint_usage']){
 | |
|         capi.sqlite3_index_info[k] = capi[k];
 | |
|         delete capi[k];
 | |
|       }
 | |
|       capi.sqlite3_vtab_config = wasm.xWrap(
 | |
|         'sqlite3_wasm_vtab_config','int',[
 | |
|           'sqlite3*', 'int', 'int']
 | |
|       );
 | |
|     }/* end vtab-related setup */
 | |
|   }/*end C constant and struct imports*/
 | |
| 
 | |
|   /**
 | |
|      Internal helper to assist in validating call argument counts in
 | |
|      the hand-written sqlite3_xyz() wrappers. We do this only for
 | |
|      consistency with non-special-case wrappings.
 | |
|   */
 | |
|   const __dbArgcMismatch = (pDb,f,n)=>{
 | |
|     return sqlite3.util.sqlite3_wasm_db_error(pDb, capi.SQLITE_MISUSE,
 | |
|                                               f+"() requires "+n+" argument"+
 | |
|                                               (1===n?"":'s')+".");
 | |
|   };
 | |
| 
 | |
|   /** Code duplication reducer for functions which take an encoding
 | |
|       argument and require SQLITE_UTF8.  Sets the db error code to
 | |
|       SQLITE_FORMAT and returns that code. */
 | |
|   const __errEncoding = (pDb)=>{
 | |
|     return util.sqlite3_wasm_db_error(
 | |
|       pDb, capi.SQLITE_FORMAT, "SQLITE_UTF8 is the only supported encoding."
 | |
|     );
 | |
|   };
 | |
| 
 | |
|   /**
 | |
|      __dbCleanupMap is infrastructure for recording registration of
 | |
|      UDFs and collations so that sqlite3_close_v2() can clean up any
 | |
|      automated JS-to-WASM function conversions installed by those.
 | |
|   */
 | |
|   const __argPDb = (pDb)=>wasm.xWrap.argAdapter('sqlite3*')(pDb);
 | |
|   const __argStr = (str)=>wasm.isPtr(str) ? wasm.cstrToJs(str) : str;
 | |
|   const __dbCleanupMap = function(
 | |
|     pDb, mode/*0=remove, >0=create if needed, <0=do not create if missing*/
 | |
|   ){
 | |
|     pDb = __argPDb(pDb);
 | |
|     let m = this.dbMap.get(pDb);
 | |
|     if(!mode){
 | |
|       this.dbMap.delete(pDb);
 | |
|       return m;
 | |
|     }else if(!m && mode>0){
 | |
|       this.dbMap.set(pDb, (m = Object.create(null)));
 | |
|     }
 | |
|     return m;
 | |
|   }.bind(Object.assign(Object.create(null),{
 | |
|     dbMap: new Map
 | |
|   }));
 | |
| 
 | |
|   __dbCleanupMap.addCollation = function(pDb, name){
 | |
|     const m = __dbCleanupMap(pDb, 1);
 | |
|     if(!m.collation) m.collation = new Set;
 | |
|     m.collation.add(__argStr(name).toLowerCase());
 | |
|   };
 | |
| 
 | |
|   __dbCleanupMap._addUDF = function(pDb, name, arity, map){
 | |
|     /* Map UDF name to a Set of arity values */
 | |
|     name = __argStr(name).toLowerCase();
 | |
|     let u = map.get(name);
 | |
|     if(!u) map.set(name, (u = new Set));
 | |
|     u.add((arity<0) ? -1 : arity);
 | |
|   };
 | |
| 
 | |
|   __dbCleanupMap.addFunction = function(pDb, name, arity){
 | |
|     const m = __dbCleanupMap(pDb, 1);
 | |
|     if(!m.udf) m.udf = new Map;
 | |
|     this._addUDF(pDb, name, arity, m.udf);
 | |
|   };
 | |
| 
 | |
|   __dbCleanupMap.addWindowFunc = function(pDb, name, arity){
 | |
|     const m = __dbCleanupMap(pDb, 1);
 | |
|     if(!m.wudf) m.wudf = new Map;
 | |
|     this._addUDF(pDb, name, arity, m.wudf);
 | |
|   };
 | |
| 
 | |
|   /**
 | |
|      Intended to be called _only_ from sqlite3_close_v2(),
 | |
|      passed its non-0 db argument.
 | |
| 
 | |
|      This function frees up certain automatically-installed WASM
 | |
|      function bindings which were installed on behalf of the given db,
 | |
|      as those may otherwise leak.
 | |
| 
 | |
|      Notable caveat: this is only ever run via
 | |
|      sqlite3.capi.sqlite3_close_v2(). If a client, for whatever
 | |
|      reason, uses sqlite3.wasm.exports.sqlite3_close_v2() (the
 | |
|      function directly exported from WASM), this cleanup will not
 | |
|      happen.
 | |
| 
 | |
|      This is not a silver bullet for avoiding automation-related
 | |
|      leaks but represents "an honest effort."
 | |
| 
 | |
|      The issue being addressed here is covered at:
 | |
| 
 | |
|      https://sqlite.org/wasm/doc/trunk/api-c-style.md#convert-func-ptr
 | |
|   */
 | |
|   __dbCleanupMap.cleanup = function(pDb){
 | |
|     pDb = __argPDb(pDb);
 | |
|     //wasm.xWrap.FuncPtrAdapter.debugFuncInstall = false;
 | |
|     /**
 | |
|        Installing NULL functions in the C API will remove those
 | |
|        bindings. The FuncPtrAdapter which sits between us and the C
 | |
|        API will also treat that as an opportunity to
 | |
|        wasm.uninstallFunction() any WASM function bindings it has
 | |
|        installed for pDb.
 | |
|     */
 | |
|     const closeArgs = [pDb];
 | |
|     for(const name of [
 | |
|       'sqlite3_busy_handler',
 | |
|       'sqlite3_commit_hook',
 | |
|       'sqlite3_preupdate_hook',
 | |
|       'sqlite3_progress_handler',
 | |
|       'sqlite3_rollback_hook',
 | |
|       'sqlite3_set_authorizer',
 | |
|       'sqlite3_trace_v2',
 | |
|       'sqlite3_update_hook'
 | |
|     ]) {
 | |
|       const x = wasm.exports[name];
 | |
|       closeArgs.length = x.length/*==argument count*/
 | |
|       /* recall that undefined entries translate to 0 when passed to
 | |
|          WASM. */;
 | |
|       try{ capi[name](...closeArgs) }
 | |
|       catch(e){
 | |
|         console.warn("close-time call of",name+"(",closeArgs,") threw:",e);
 | |
|       }
 | |
|     }
 | |
|     const m = __dbCleanupMap(pDb, 0);
 | |
|     if(!m) return;
 | |
|     if(m.collation){
 | |
|       for(const name of m.collation){
 | |
|         try{
 | |
|           capi.sqlite3_create_collation_v2(
 | |
|             pDb, name, capi.SQLITE_UTF8, 0, 0, 0
 | |
|           );
 | |
|         }catch(e){
 | |
|           /*ignored*/
 | |
|         }
 | |
|       }
 | |
|       delete m.collation;
 | |
|     }
 | |
|     let i;
 | |
|     for(i = 0; i < 2; ++i){ /* Clean up UDFs... */
 | |
|       const fmap = i ? m.wudf : m.udf;
 | |
|       if(!fmap) continue;
 | |
|       const func = i
 | |
|             ? capi.sqlite3_create_window_function
 | |
|             : capi.sqlite3_create_function_v2;
 | |
|       for(const e of fmap){
 | |
|         const name = e[0], arities = e[1];
 | |
|         const fargs = [pDb, name, 0/*arity*/, capi.SQLITE_UTF8, 0, 0, 0, 0, 0];
 | |
|         if(i) fargs.push(0);
 | |
|         for(const arity of arities){
 | |
|           try{ fargs[2] = arity; func.apply(null, fargs); }
 | |
|           catch(e){/*ignored*/}
 | |
|         }
 | |
|         arities.clear();
 | |
|       }
 | |
|       fmap.clear();
 | |
|     }
 | |
|     delete m.udf;
 | |
|     delete m.wudf;
 | |
|   }/*__dbCleanupMap.cleanup()*/;
 | |
| 
 | |
|   {/* Binding of sqlite3_close_v2() */
 | |
|     const __sqlite3CloseV2 = wasm.xWrap("sqlite3_close_v2", "int", "sqlite3*");
 | |
|     capi.sqlite3_close_v2 = function(pDb){
 | |
|       if(1!==arguments.length) return __dbArgcMismatch(pDb, 'sqlite3_close_v2', 1);
 | |
|       if(pDb){
 | |
|         try{__dbCleanupMap.cleanup(pDb)} catch(e){/*ignored*/}
 | |
|       }
 | |
|       return __sqlite3CloseV2(pDb);
 | |
|     };
 | |
|   }/*sqlite3_close_v2()*/
 | |
| 
 | |
|   if(capi.sqlite3session_table_filter){
 | |
|     const __sqlite3SessionDelete = wasm.xWrap(
 | |
|       'sqlite3session_delete', undefined, ['sqlite3_session*']
 | |
|     );
 | |
|     capi.sqlite3session_delete = function(pSession){
 | |
|       if(1!==arguments.length){
 | |
|         return __dbArgcMismatch(pDb, 'sqlite3session_delete', 1);
 | |
|         /* Yes, we're returning a value from a void function. That seems
 | |
|            like the lesser evil compared to not maintaining arg-count
 | |
|            consistency as we do with other similar bindings. */
 | |
|       }
 | |
|       else if(pSession){
 | |
|         //wasm.xWrap.FuncPtrAdapter.debugFuncInstall = true;
 | |
|         capi.sqlite3session_table_filter(pSession, 0, 0);
 | |
|       }
 | |
|       __sqlite3SessionDelete(pSession);
 | |
|     };
 | |
|   }
 | |
| 
 | |
|   {/* Bindings for sqlite3_create_collation[_v2]() */
 | |
|     // contextKey() impl for wasm.xWrap.FuncPtrAdapter
 | |
|     const contextKey = (argv,argIndex)=>{
 | |
|       return 'argv['+argIndex+']:'+argv[0/* sqlite3* */]+
 | |
|         ':'+wasm.cstrToJs(argv[1/* collation name */]).toLowerCase()
 | |
|     };
 | |
|     const __sqlite3CreateCollationV2 = wasm.xWrap(
 | |
|       'sqlite3_create_collation_v2', 'int', [
 | |
|         'sqlite3*', 'string', 'int', '*',
 | |
|         new wasm.xWrap.FuncPtrAdapter({
 | |
|           /* int(*xCompare)(void*,int,const void*,int,const void*) */
 | |
|           name: 'xCompare', signature: 'i(pipip)', contextKey
 | |
|         }),
 | |
|         new wasm.xWrap.FuncPtrAdapter({
 | |
|           /* void(*xDestroy(void*) */
 | |
|           name: 'xDestroy', signature: 'v(p)', contextKey
 | |
|         })
 | |
|       ]
 | |
|     );
 | |
| 
 | |
|     /**
 | |
|        Works exactly like C's sqlite3_create_collation_v2() except that:
 | |
| 
 | |
|        1) It returns capi.SQLITE_FORMAT if the 3rd argument contains
 | |
|           any encoding-related value other than capi.SQLITE_UTF8.  No
 | |
|           other encodings are supported. As a special case, if the
 | |
|           bottom 4 bits of that argument are 0, SQLITE_UTF8 is
 | |
|           assumed.
 | |
| 
 | |
|        2) It accepts JS functions for its function-pointer arguments,
 | |
|           for which it will install WASM-bound proxies. The bindings
 | |
|           are "permanent," in that they will stay in the WASM environment
 | |
|           until it shuts down unless the client calls this again with the
 | |
|           same collation name and a value of 0 or null for the
 | |
|           the function pointer(s).
 | |
| 
 | |
|        For consistency with the C API, it requires the same number of
 | |
|        arguments. It returns capi.SQLITE_MISUSE if passed any other
 | |
|        argument count.
 | |
| 
 | |
|        Returns 0 on success, non-0 on error, in which case the error
 | |
|        state of pDb (of type `sqlite3*` or argument-convertible to it)
 | |
|        may contain more information.
 | |
|     */
 | |
|     capi.sqlite3_create_collation_v2 = function(pDb,zName,eTextRep,pArg,xCompare,xDestroy){
 | |
|       if(6!==arguments.length) return __dbArgcMismatch(pDb, 'sqlite3_create_collation_v2', 6);
 | |
|       else if( 0 === (eTextRep & 0xf) ){
 | |
|         eTextRep |= capi.SQLITE_UTF8;
 | |
|       }else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){
 | |
|         return __errEncoding(pDb);
 | |
|       }
 | |
|       try{
 | |
|         const rc = __sqlite3CreateCollationV2(pDb, zName, eTextRep, pArg, xCompare, xDestroy);
 | |
|         if(0===rc && xCompare instanceof Function){
 | |
|           __dbCleanupMap.addCollation(pDb, zName);
 | |
|         }
 | |
|         return rc;
 | |
|       }catch(e){
 | |
|         return util.sqlite3_wasm_db_error(pDb, e);
 | |
|       }
 | |
|     };
 | |
| 
 | |
|     capi.sqlite3_create_collation = (pDb,zName,eTextRep,pArg,xCompare)=>{
 | |
|       return (5===arguments.length)
 | |
|         ? capi.sqlite3_create_collation_v2(pDb,zName,eTextRep,pArg,xCompare,0)
 | |
|         : __dbArgcMismatch(pDb, 'sqlite3_create_collation', 5);
 | |
|     };
 | |
| 
 | |
|   }/*sqlite3_create_collation() and friends*/
 | |
| 
 | |
|   {/* Special-case handling of sqlite3_create_function_v2()
 | |
|       and sqlite3_create_window_function(). */
 | |
|     /** FuncPtrAdapter for contextKey() for sqlite3_create_function()
 | |
|         and friends. */
 | |
|     const contextKey = function(argv,argIndex){
 | |
|       return (
 | |
|         argv[0/* sqlite3* */]
 | |
|           +':'+(argv[2/*number of UDF args*/] < 0 ? -1 : argv[2])
 | |
|           +':'+argIndex/*distinct for each xAbc callback type*/
 | |
|           +':'+wasm.cstrToJs(argv[1]).toLowerCase()
 | |
|       )
 | |
|     };
 | |
| 
 | |
|     /**
 | |
|        JS proxies for the various sqlite3_create[_window]_function()
 | |
|        callbacks, structured in a form usable by wasm.xWrap.FuncPtrAdapter.
 | |
|     */
 | |
|     const __cfProxy = Object.assign(Object.create(null), {
 | |
|       xInverseAndStep: {
 | |
|         signature:'v(pip)', contextKey,
 | |
|         callProxy: (callback)=>{
 | |
|           return (pCtx, argc, pArgv)=>{
 | |
|             try{ callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv)) }
 | |
|             catch(e){ capi.sqlite3_result_error_js(pCtx, e) }
 | |
|           };
 | |
|         }
 | |
|       },
 | |
|       xFinalAndValue: {
 | |
|         signature:'v(p)', contextKey,
 | |
|         callProxy: (callback)=>{
 | |
|           return (pCtx)=>{
 | |
|             try{ capi.sqlite3_result_js(pCtx, callback(pCtx)) }
 | |
|             catch(e){ capi.sqlite3_result_error_js(pCtx, e) }
 | |
|           };
 | |
|         }
 | |
|       },
 | |
|       xFunc: {
 | |
|         signature:'v(pip)', contextKey,
 | |
|         callProxy: (callback)=>{
 | |
|           return (pCtx, argc, pArgv)=>{
 | |
|             try{
 | |
|               capi.sqlite3_result_js(
 | |
|                 pCtx,
 | |
|                 callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv))
 | |
|               );
 | |
|             }catch(e){
 | |
|               //console.error('xFunc() caught:',e);
 | |
|               capi.sqlite3_result_error_js(pCtx, e);
 | |
|             }
 | |
|           };
 | |
|         }
 | |
|       },
 | |
|       xDestroy: {
 | |
|         signature:'v(p)', contextKey,
 | |
|         //Arguable: a well-behaved destructor doesn't require a proxy.
 | |
|         callProxy: (callback)=>{
 | |
|           return (pVoid)=>{
 | |
|             try{ callback(pVoid) }
 | |
|             catch(e){ console.error("UDF xDestroy method threw:",e) }
 | |
|           };
 | |
|         }
 | |
|       }
 | |
|     })/*__cfProxy*/;
 | |
| 
 | |
|     const __sqlite3CreateFunction = wasm.xWrap(
 | |
|       "sqlite3_create_function_v2", "int", [
 | |
|         "sqlite3*", "string"/*funcName*/, "int"/*nArg*/,
 | |
|         "int"/*eTextRep*/, "*"/*pApp*/,
 | |
|         new wasm.xWrap.FuncPtrAdapter({name: 'xFunc', ...__cfProxy.xFunc}),
 | |
|         new wasm.xWrap.FuncPtrAdapter({name: 'xStep', ...__cfProxy.xInverseAndStep}),
 | |
|         new wasm.xWrap.FuncPtrAdapter({name: 'xFinal', ...__cfProxy.xFinalAndValue}),
 | |
|         new wasm.xWrap.FuncPtrAdapter({name: 'xDestroy', ...__cfProxy.xDestroy})
 | |
|       ]
 | |
|     );
 | |
| 
 | |
|     const __sqlite3CreateWindowFunction = wasm.xWrap(
 | |
|       "sqlite3_create_window_function", "int", [
 | |
|         "sqlite3*", "string"/*funcName*/, "int"/*nArg*/,
 | |
|         "int"/*eTextRep*/, "*"/*pApp*/,
 | |
|         new wasm.xWrap.FuncPtrAdapter({name: 'xStep', ...__cfProxy.xInverseAndStep}),
 | |
|         new wasm.xWrap.FuncPtrAdapter({name: 'xFinal', ...__cfProxy.xFinalAndValue}),
 | |
|         new wasm.xWrap.FuncPtrAdapter({name: 'xValue', ...__cfProxy.xFinalAndValue}),
 | |
|         new wasm.xWrap.FuncPtrAdapter({name: 'xInverse', ...__cfProxy.xInverseAndStep}),
 | |
|         new wasm.xWrap.FuncPtrAdapter({name: 'xDestroy', ...__cfProxy.xDestroy})
 | |
|       ]
 | |
|     );
 | |
| 
 | |
|     /* Documented in the api object's initializer. */
 | |
|     capi.sqlite3_create_function_v2 = function f(
 | |
|       pDb, funcName, nArg, eTextRep, pApp,
 | |
|       xFunc,   //void (*xFunc)(sqlite3_context*,int,sqlite3_value**)
 | |
|       xStep,   //void (*xStep)(sqlite3_context*,int,sqlite3_value**)
 | |
|       xFinal,  //void (*xFinal)(sqlite3_context*)
 | |
|       xDestroy //void (*xDestroy)(void*)
 | |
|     ){
 | |
|       if( f.length!==arguments.length ){
 | |
|         return __dbArgcMismatch(pDb,"sqlite3_create_function_v2",f.length);
 | |
|       }else if( 0 === (eTextRep & 0xf) ){
 | |
|         eTextRep |= capi.SQLITE_UTF8;
 | |
|       }else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){
 | |
|         return __errEncoding(pDb);
 | |
|       }
 | |
|       try{
 | |
|         const rc = __sqlite3CreateFunction(pDb, funcName, nArg, eTextRep,
 | |
|                                            pApp, xFunc, xStep, xFinal, xDestroy);
 | |
|         if(0===rc && (xFunc instanceof Function
 | |
|                       || xStep instanceof Function
 | |
|                       || xFinal instanceof Function
 | |
|                       || xDestroy instanceof Function)){
 | |
|           __dbCleanupMap.addFunction(pDb, funcName, nArg);
 | |
|         }
 | |
|         return rc;
 | |
|       }catch(e){
 | |
|         console.error("sqlite3_create_function_v2() setup threw:",e);
 | |
|         return util.sqlite3_wasm_db_error(pDb, e, "Creation of UDF threw: "+e);
 | |
|       }
 | |
|     };
 | |
| 
 | |
|     /* Documented in the api object's initializer. */
 | |
|     capi.sqlite3_create_function = function f(
 | |
|       pDb, funcName, nArg, eTextRep, pApp,
 | |
|       xFunc, xStep, xFinal
 | |
|     ){
 | |
|       return (f.length===arguments.length)
 | |
|         ? capi.sqlite3_create_function_v2(pDb, funcName, nArg, eTextRep,
 | |
|                                           pApp, xFunc, xStep, xFinal, 0)
 | |
|         : __dbArgcMismatch(pDb,"sqlite3_create_function",f.length);
 | |
|     };
 | |
| 
 | |
|     /* Documented in the api object's initializer. */
 | |
|     capi.sqlite3_create_window_function = function f(
 | |
|       pDb, funcName, nArg, eTextRep, pApp,
 | |
|       xStep,   //void (*xStep)(sqlite3_context*,int,sqlite3_value**)
 | |
|       xFinal,  //void (*xFinal)(sqlite3_context*)
 | |
|       xValue,  //void (*xValue)(sqlite3_context*)
 | |
|       xInverse,//void (*xInverse)(sqlite3_context*,int,sqlite3_value**)
 | |
|       xDestroy //void (*xDestroy)(void*)
 | |
|     ){
 | |
|       if( f.length!==arguments.length ){
 | |
|         return __dbArgcMismatch(pDb,"sqlite3_create_window_function",f.length);
 | |
|       }else if( 0 === (eTextRep & 0xf) ){
 | |
|         eTextRep |= capi.SQLITE_UTF8;
 | |
|       }else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){
 | |
|         return __errEncoding(pDb);
 | |
|       }
 | |
|       try{
 | |
|         const rc = __sqlite3CreateWindowFunction(pDb, funcName, nArg, eTextRep,
 | |
|                                                  pApp, xStep, xFinal, xValue,
 | |
|                                                  xInverse, xDestroy);
 | |
|         if(0===rc && (xStep instanceof Function
 | |
|                       || xFinal instanceof Function
 | |
|                       || xValue instanceof Function
 | |
|                       || xInverse instanceof Function
 | |
|                       || xDestroy instanceof Function)){
 | |
|           __dbCleanupMap.addWindowFunc(pDb, funcName, nArg);
 | |
|         }
 | |
|         return rc;
 | |
|       }catch(e){
 | |
|         console.error("sqlite3_create_window_function() setup threw:",e);
 | |
|         return util.sqlite3_wasm_db_error(pDb, e, "Creation of UDF threw: "+e);
 | |
|       }
 | |
|     };
 | |
|     /**
 | |
|        A _deprecated_ alias for capi.sqlite3_result_js() which
 | |
|        predates the addition of that function in the public API.
 | |
|     */
 | |
|     capi.sqlite3_create_function_v2.udfSetResult =
 | |
|       capi.sqlite3_create_function.udfSetResult =
 | |
|       capi.sqlite3_create_window_function.udfSetResult = capi.sqlite3_result_js;
 | |
| 
 | |
|     /**
 | |
|        A _deprecated_ alias for capi.sqlite3_values_to_js() which
 | |
|        predates the addition of that function in the public API.
 | |
|     */
 | |
|     capi.sqlite3_create_function_v2.udfConvertArgs =
 | |
|       capi.sqlite3_create_function.udfConvertArgs =
 | |
|       capi.sqlite3_create_window_function.udfConvertArgs = capi.sqlite3_values_to_js;
 | |
| 
 | |
|     /**
 | |
|        A _deprecated_ alias for capi.sqlite3_result_error_js() which
 | |
|        predates the addition of that function in the public API.
 | |
|     */
 | |
|     capi.sqlite3_create_function_v2.udfSetError =
 | |
|       capi.sqlite3_create_function.udfSetError =
 | |
|       capi.sqlite3_create_window_function.udfSetError = capi.sqlite3_result_error_js;
 | |
| 
 | |
|   }/*sqlite3_create_function_v2() and sqlite3_create_window_function() proxies*/;
 | |
| 
 | |
|   {/* Special-case handling of sqlite3_prepare_v2() and
 | |
|       sqlite3_prepare_v3() */
 | |
| 
 | |
|     /**
 | |
|        Helper for string:flexible conversions which require a
 | |
|        byte-length counterpart argument. Passed a value and its
 | |
|        ostensible length, this function returns [V,N], where V is
 | |
|        either v or a transformed copy of v and N is either n, -1, or
 | |
|        the byte length of v (if it's a byte array or ArrayBuffer).
 | |
|     */
 | |
|     const __flexiString = (v,n)=>{
 | |
|       if('string'===typeof v){
 | |
|         n = -1;
 | |
|       }else if(util.isSQLableTypedArray(v)){
 | |
|         n = v.byteLength;
 | |
|         v = util.typedArrayToString(
 | |
|           (v instanceof ArrayBuffer) ? new Uint8Array(v) : v
 | |
|         );
 | |
|       }else if(Array.isArray(v)){
 | |
|         v = v.join("");
 | |
|         n = -1;
 | |
|       }
 | |
|       return [v, n];
 | |
|     };
 | |
| 
 | |
|     /**
 | |
|        Scope-local holder of the two impls of sqlite3_prepare_v2/v3().
 | |
|     */
 | |
|     const __prepare = {
 | |
|       /**
 | |
|          This binding expects a JS string as its 2nd argument and
 | |
|          null as its final argument. In order to compile multiple
 | |
|          statements from a single string, the "full" impl (see
 | |
|          below) must be used.
 | |
|       */
 | |
|       basic: wasm.xWrap('sqlite3_prepare_v3',
 | |
|                         "int", ["sqlite3*", "string",
 | |
|                                 "int"/*ignored for this impl!*/,
 | |
|                                 "int", "**",
 | |
|                                 "**"/*MUST be 0 or null or undefined!*/]),
 | |
|       /**
 | |
|          Impl which requires that the 2nd argument be a pointer
 | |
|          to the SQL string, instead of being converted to a
 | |
|          string. This variant is necessary for cases where we
 | |
|          require a non-NULL value for the final argument
 | |
|          (exec()'ing multiple statements from one input
 | |
|          string). For simpler cases, where only the first
 | |
|          statement in the SQL string is required, the wrapper
 | |
|          named sqlite3_prepare_v2() is sufficient and easier to
 | |
|          use because it doesn't require dealing with pointers.
 | |
|       */
 | |
|       full: wasm.xWrap('sqlite3_prepare_v3',
 | |
|                        "int", ["sqlite3*", "*", "int", "int",
 | |
|                                "**", "**"])
 | |
|     };
 | |
| 
 | |
|     /* Documented in the capi object's initializer. */
 | |
|     capi.sqlite3_prepare_v3 = function f(pDb, sql, sqlLen, prepFlags, ppStmt, pzTail){
 | |
|       if(f.length!==arguments.length){
 | |
|         return __dbArgcMismatch(pDb,"sqlite3_prepare_v3",f.length);
 | |
|       }
 | |
|       const [xSql, xSqlLen] = __flexiString(sql, sqlLen);
 | |
|       switch(typeof xSql){
 | |
|           case 'string': return __prepare.basic(pDb, xSql, xSqlLen, prepFlags, ppStmt, null);
 | |
|           case 'number': return __prepare.full(pDb, xSql, xSqlLen, prepFlags, ppStmt, pzTail);
 | |
|           default:
 | |
|             return util.sqlite3_wasm_db_error(
 | |
|               pDb, capi.SQLITE_MISUSE,
 | |
|               "Invalid SQL argument type for sqlite3_prepare_v2/v3()."
 | |
|             );
 | |
|       }
 | |
|     };
 | |
| 
 | |
|     /* Documented in the capi object's initializer. */
 | |
|     capi.sqlite3_prepare_v2 = function f(pDb, sql, sqlLen, ppStmt, pzTail){
 | |
|       return (f.length===arguments.length)
 | |
|         ? capi.sqlite3_prepare_v3(pDb, sql, sqlLen, 0, ppStmt, pzTail)
 | |
|         : __dbArgcMismatch(pDb,"sqlite3_prepare_v2",f.length);
 | |
|     };
 | |
| 
 | |
|   }/*sqlite3_prepare_v2/v3()*/
 | |
| 
 | |
|   {/*sqlite3_bind_text/blob()*/
 | |
|     const __bindText = wasm.xWrap("sqlite3_bind_text", "int", [
 | |
|       "sqlite3_stmt*", "int", "string", "int", "*"
 | |
|     ]);
 | |
|     const __bindBlob = wasm.xWrap("sqlite3_bind_blob", "int", [
 | |
|       "sqlite3_stmt*", "int", "*", "int", "*"
 | |
|     ]);
 | |
| 
 | |
|     /** Documented in the capi object's initializer. */
 | |
|     capi.sqlite3_bind_text = function f(pStmt, iCol, text, nText, xDestroy){
 | |
|       if(f.length!==arguments.length){
 | |
|         return __dbArgcMismatch(capi.sqlite3_db_handle(pStmt),
 | |
|                                 "sqlite3_bind_text", f.length);
 | |
|       }else if(wasm.isPtr(text) || null===text){
 | |
|         return __bindText(pStmt, iCol, text, nText, xDestroy);
 | |
|       }else if(text instanceof ArrayBuffer){
 | |
|         text = new Uint8Array(text);
 | |
|       }else if(Array.isArray(pMem)){
 | |
|         text = pMem.join('');
 | |
|       }
 | |
|       let p, n;
 | |
|       try{
 | |
|         if(util.isSQLableTypedArray(text)){
 | |
|           p = wasm.allocFromTypedArray(text);
 | |
|           n = text.byteLength;
 | |
|         }else if('string'===typeof text){
 | |
|           [p, n] = wasm.allocCString(text);
 | |
|         }else{
 | |
|           return util.sqlite3_wasm_db_error(
 | |
|             capi.sqlite3_db_handle(pStmt), capi.SQLITE_MISUSE,
 | |
|             "Invalid 3rd argument type for sqlite3_bind_text()."
 | |
|           );
 | |
|         }
 | |
|         return __bindText(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC);
 | |
|       }catch(e){
 | |
|         wasm.dealloc(p);
 | |
|         return util.sqlite3_wasm_db_error(
 | |
|           capi.sqlite3_db_handle(pStmt), e
 | |
|         );
 | |
|       }
 | |
|     }/*sqlite3_bind_text()*/;
 | |
| 
 | |
|     /** Documented in the capi object's initializer. */
 | |
|     capi.sqlite3_bind_blob = function f(pStmt, iCol, pMem, nMem, xDestroy){
 | |
|       if(f.length!==arguments.length){
 | |
|         return __dbArgcMismatch(capi.sqlite3_db_handle(pStmt),
 | |
|                                 "sqlite3_bind_blob", f.length);
 | |
|       }else if(wasm.isPtr(pMem) || null===pMem){
 | |
|         return __bindBlob(pStmt, iCol, pMem, nMem, xDestroy);
 | |
|       }else if(pMem instanceof ArrayBuffer){
 | |
|         pMem = new Uint8Array(pMem);
 | |
|       }else if(Array.isArray(pMem)){
 | |
|         pMem = pMem.join('');
 | |
|       }
 | |
|       let p, n;
 | |
|       try{
 | |
|         if(util.isBindableTypedArray(pMem)){
 | |
|           p = wasm.allocFromTypedArray(pMem);
 | |
|           n = nMem>=0 ? nMem : pMem.byteLength;
 | |
|         }else if('string'===typeof pMem){
 | |
|           [p, n] = wasm.allocCString(pMem);
 | |
|         }else{
 | |
|           return util.sqlite3_wasm_db_error(
 | |
|             capi.sqlite3_db_handle(pStmt), capi.SQLITE_MISUSE,
 | |
|             "Invalid 3rd argument type for sqlite3_bind_blob()."
 | |
|           );
 | |
|         }
 | |
|         return __bindBlob(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC);
 | |
|       }catch(e){
 | |
|         wasm.dealloc(p);
 | |
|         return util.sqlite3_wasm_db_error(
 | |
|           capi.sqlite3_db_handle(pStmt), e
 | |
|         );
 | |
|       }
 | |
|     }/*sqlite3_bind_blob()*/;
 | |
| 
 | |
|   }/*sqlite3_bind_text/blob()*/
 | |
| 
 | |
|   {/* sqlite3_config() */
 | |
|     /**
 | |
|        Wraps a small subset of the C API's sqlite3_config() options.
 | |
|        Unsupported options trigger the return of capi.SQLITE_NOTFOUND.
 | |
|        Passing fewer than 2 arguments triggers return of
 | |
|        capi.SQLITE_MISUSE.
 | |
|     */
 | |
|     capi.sqlite3_config = function(op, ...args){
 | |
|       if(arguments.length<2) return capi.SQLITE_MISUSE;
 | |
|       switch(op){
 | |
|           case capi.SQLITE_CONFIG_COVERING_INDEX_SCAN: // 20  /* int */
 | |
|           case capi.SQLITE_CONFIG_MEMSTATUS:// 9  /* boolean */
 | |
|           case capi.SQLITE_CONFIG_SMALL_MALLOC: // 27  /* boolean */
 | |
|           case capi.SQLITE_CONFIG_SORTERREF_SIZE: // 28  /* int nByte */
 | |
|           case capi.SQLITE_CONFIG_STMTJRNL_SPILL: // 26  /* int nByte */
 | |
|           case capi.SQLITE_CONFIG_URI:// 17  /* int */
 | |
|             return wasm.exports.sqlite3_wasm_config_i(op, args[0]);
 | |
|           case capi.SQLITE_CONFIG_LOOKASIDE: // 13  /* int int */
 | |
|             return wasm.exports.sqlite3_wasm_config_ii(op, args[0], args[1]);
 | |
|           case capi.SQLITE_CONFIG_MEMDB_MAXSIZE: // 29  /* sqlite3_int64 */
 | |
|             return wasm.exports.sqlite3_wasm_config_j(op, args[0]);
 | |
|           case capi.SQLITE_CONFIG_GETMALLOC: // 5 /* sqlite3_mem_methods* */
 | |
|           case capi.SQLITE_CONFIG_GETMUTEX: // 11  /* sqlite3_mutex_methods* */
 | |
|           case capi.SQLITE_CONFIG_GETPCACHE2: // 19  /* sqlite3_pcache_methods2* */
 | |
|           case capi.SQLITE_CONFIG_GETPCACHE: // 15  /* no-op */
 | |
|           case capi.SQLITE_CONFIG_HEAP: // 8  /* void*, int nByte, int min */
 | |
|           case capi.SQLITE_CONFIG_LOG: // 16  /* xFunc, void* */
 | |
|           case capi.SQLITE_CONFIG_MALLOC:// 4  /* sqlite3_mem_methods* */
 | |
|           case capi.SQLITE_CONFIG_MMAP_SIZE: // 22  /* sqlite3_int64, sqlite3_int64 */
 | |
|           case capi.SQLITE_CONFIG_MULTITHREAD: // 2 /* nil */
 | |
|           case capi.SQLITE_CONFIG_MUTEX: // 10  /* sqlite3_mutex_methods* */
 | |
|           case capi.SQLITE_CONFIG_PAGECACHE: // 7  /* void*, int sz, int N */
 | |
|           case capi.SQLITE_CONFIG_PCACHE2: // 18  /* sqlite3_pcache_methods2* */
 | |
|           case capi.SQLITE_CONFIG_PCACHE: // 14  /* no-op */
 | |
|           case capi.SQLITE_CONFIG_PCACHE_HDRSZ: // 24  /* int *psz */
 | |
|           case capi.SQLITE_CONFIG_PMASZ: // 25  /* unsigned int szPma */
 | |
|           case capi.SQLITE_CONFIG_SERIALIZED: // 3 /* nil */
 | |
|           case capi.SQLITE_CONFIG_SINGLETHREAD: // 1 /* nil */:
 | |
|           case capi.SQLITE_CONFIG_SQLLOG: // 21  /* xSqllog, void* */
 | |
|           case capi.SQLITE_CONFIG_WIN32_HEAPSIZE: // 23  /* int nByte */
 | |
|           default:
 | |
|             return capi.SQLITE_NOTFOUND;
 | |
|       }
 | |
|     };
 | |
|   }/* sqlite3_config() */
 | |
| 
 | |
|   {/*auto-extension bindings.*/
 | |
|     const __autoExtFptr = new Set;
 | |
| 
 | |
|     capi.sqlite3_auto_extension = function(fPtr){
 | |
|       if( fPtr instanceof Function ){
 | |
|         fPtr = wasm.installFunction('i(ppp)', fPtr);
 | |
|       }else if( 1!==arguments.length || !wasm.isPtr(fPtr) ){
 | |
|         return capi.SQLITE_MISUSE;
 | |
|       }
 | |
|       const rc = wasm.exports.sqlite3_auto_extension(fPtr);
 | |
|       if( fPtr!==arguments[0] ){
 | |
|         if(0===rc) __autoExtFptr.add(fPtr);
 | |
|         else wasm.uninstallFunction(fPtr);
 | |
|       }
 | |
|       return rc;
 | |
|     };
 | |
| 
 | |
|     capi.sqlite3_cancel_auto_extension = function(fPtr){
 | |
|      /* We do not do an automatic JS-to-WASM function conversion here
 | |
|         because it would be senseless: the converted pointer would
 | |
|         never possibly match an already-installed one. */;
 | |
|       if(!fPtr || 1!==arguments.length || !wasm.isPtr(fPtr)) return 0;
 | |
|       return wasm.exports.sqlite3_cancel_auto_extension(fPtr);
 | |
|       /* Note that it "cannot happen" that a client passes a pointer which
 | |
|          is in __autoExtFptr because __autoExtFptr only contains automatic
 | |
|          conversions created inside sqlite3_auto_extension() and
 | |
|          never exposed to the client. */
 | |
|     };
 | |
| 
 | |
|     capi.sqlite3_reset_auto_extension = function(){
 | |
|       wasm.exports.sqlite3_reset_auto_extension();
 | |
|       for(const fp of __autoExtFptr) wasm.uninstallFunction(fp);
 | |
|       __autoExtFptr.clear();
 | |
|     };
 | |
|   }/* auto-extension */
 | |
| 
 | |
|   const pKvvfs = capi.sqlite3_vfs_find("kvvfs");
 | |
|   if( pKvvfs ){/* kvvfs-specific glue */
 | |
|     if(util.isUIThread()){
 | |
|       const kvvfsMethods = new capi.sqlite3_kvvfs_methods(
 | |
|         wasm.exports.sqlite3_wasm_kvvfs_methods()
 | |
|       );
 | |
|       delete capi.sqlite3_kvvfs_methods;
 | |
| 
 | |
|       const kvvfsMakeKey = wasm.exports.sqlite3_wasm_kvvfsMakeKeyOnPstack,
 | |
|             pstack = wasm.pstack;
 | |
| 
 | |
|       const kvvfsStorage = (zClass)=>
 | |
|             ((115/*=='s'*/===wasm.peek(zClass))
 | |
|              ? sessionStorage : localStorage);
 | |
| 
 | |
|       /**
 | |
|          Implementations for members of the object referred to by
 | |
|          sqlite3_wasm_kvvfs_methods(). We swap out the native
 | |
|          implementations with these, which use localStorage or
 | |
|          sessionStorage for their backing store.
 | |
|       */
 | |
|       const kvvfsImpls = {
 | |
|         xRead: (zClass, zKey, zBuf, nBuf)=>{
 | |
|           const stack = pstack.pointer,
 | |
|                 astack = wasm.scopedAllocPush();
 | |
|           try {
 | |
|             const zXKey = kvvfsMakeKey(zClass,zKey);
 | |
|             if(!zXKey) return -3/*OOM*/;
 | |
|             const jKey = wasm.cstrToJs(zXKey);
 | |
|             const jV = kvvfsStorage(zClass).getItem(jKey);
 | |
|             if(!jV) return -1;
 | |
|             const nV = jV.length /* Note that we are relying 100% on v being
 | |
|                                     ASCII so that jV.length is equal to the
 | |
|                                     C-string's byte length. */;
 | |
|             if(nBuf<=0) return nV;
 | |
|             else if(1===nBuf){
 | |
|               wasm.poke(zBuf, 0);
 | |
|               return nV;
 | |
|             }
 | |
|             const zV = wasm.scopedAllocCString(jV);
 | |
|             if(nBuf > nV + 1) nBuf = nV + 1;
 | |
|             wasm.heap8u().copyWithin(zBuf, zV, zV + nBuf - 1);
 | |
|             wasm.poke(zBuf + nBuf - 1, 0);
 | |
|             return nBuf - 1;
 | |
|           }catch(e){
 | |
|             console.error("kvstorageRead()",e);
 | |
|             return -2;
 | |
|           }finally{
 | |
|             pstack.restore(stack);
 | |
|             wasm.scopedAllocPop(astack);
 | |
|           }
 | |
|         },
 | |
|         xWrite: (zClass, zKey, zData)=>{
 | |
|           const stack = pstack.pointer;
 | |
|           try {
 | |
|             const zXKey = kvvfsMakeKey(zClass,zKey);
 | |
|             if(!zXKey) return 1/*OOM*/;
 | |
|             const jKey = wasm.cstrToJs(zXKey);
 | |
|             kvvfsStorage(zClass).setItem(jKey, wasm.cstrToJs(zData));
 | |
|             return 0;
 | |
|           }catch(e){
 | |
|             console.error("kvstorageWrite()",e);
 | |
|             return capi.SQLITE_IOERR;
 | |
|           }finally{
 | |
|             pstack.restore(stack);
 | |
|           }
 | |
|         },
 | |
|         xDelete: (zClass, zKey)=>{
 | |
|           const stack = pstack.pointer;
 | |
|           try {
 | |
|             const zXKey = kvvfsMakeKey(zClass,zKey);
 | |
|             if(!zXKey) return 1/*OOM*/;
 | |
|             kvvfsStorage(zClass).removeItem(wasm.cstrToJs(zXKey));
 | |
|             return 0;
 | |
|           }catch(e){
 | |
|             console.error("kvstorageDelete()",e);
 | |
|             return capi.SQLITE_IOERR;
 | |
|           }finally{
 | |
|             pstack.restore(stack);
 | |
|           }
 | |
|         }
 | |
|       }/*kvvfsImpls*/;
 | |
|       for(const k of Object.keys(kvvfsImpls)){
 | |
|         kvvfsMethods[kvvfsMethods.memberKey(k)] =
 | |
|           wasm.installFunction(
 | |
|             kvvfsMethods.memberSignature(k),
 | |
|             kvvfsImpls[k]
 | |
|           );
 | |
|       }
 | |
|     }else{
 | |
|       /* Worker thread: unregister kvvfs to avoid it being used
 | |
|          for anything other than local/sessionStorage. It "can"
 | |
|          be used that way but it's not really intended to be. */
 | |
|       capi.sqlite3_vfs_unregister(pKvvfs);
 | |
|     }
 | |
|   }/*pKvvfs*/
 | |
| 
 | |
|   wasm.xWrap.FuncPtrAdapter.warnOnUse = true;
 | |
| });
 |