sqlite3-api-glue.c-pp.js 78 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963
  1. /*
  2. 2022-07-22
  3. The author disclaims copyright to this source code. In place of a
  4. legal notice, here is a blessing:
  5. * May you do good and not evil.
  6. * May you find forgiveness for yourself and forgive others.
  7. * May you share freely, never taking more than you give.
  8. ***********************************************************************
  9. This file glues together disparate pieces of JS which are loaded in
  10. previous steps of the sqlite3-api.js bootstrapping process:
  11. sqlite3-api-prologue.js, whwasmutil.js, and jaccwabyt.js. It
  12. initializes the main API pieces so that the downstream components
  13. (e.g. sqlite3-api-oo1.js) have all of the infrastructure that they
  14. need.
  15. */
  16. globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
  17. 'use strict';
  18. const toss = (...args)=>{throw new Error(args.join(' '))};
  19. const toss3 = sqlite3.SQLite3Error.toss;
  20. const capi = sqlite3.capi, wasm = sqlite3.wasm, util = sqlite3.util;
  21. globalThis.WhWasmUtilInstaller(wasm);
  22. delete globalThis.WhWasmUtilInstaller;
  23. if(0){
  24. /**
  25. Please keep this block around as a maintenance reminder
  26. that we cannot rely on this type of check.
  27. This block fails on Safari, per a report at
  28. https://sqlite.org/forum/forumpost/e5b20e1feb.
  29. It turns out that what Safari serves from the indirect function
  30. table (e.g. wasm.functionEntry(X)) is anonymous functions which
  31. wrap the WASM functions, rather than returning the WASM
  32. functions themselves. That means comparison of such functions
  33. is useless for determining whether or not we have a specific
  34. function from wasm.exports. i.e. if function X is indirection
  35. function table entry N then wasm.exports.X is not equal to
  36. wasm.functionEntry(N) in Safari, despite being so in the other
  37. browsers.
  38. */
  39. /**
  40. Find a mapping for SQLITE_WASM_DEALLOC, which the API
  41. guarantees is a WASM pointer to the same underlying function as
  42. wasm.dealloc() (noting that wasm.dealloc() is permitted to be a
  43. JS wrapper around the WASM function). There is unfortunately no
  44. O(1) algorithm for finding this pointer: we have to walk the
  45. WASM indirect function table to find it. However, experience
  46. indicates that that particular function is always very close to
  47. the front of the table (it's been entry #3 in all relevant
  48. tests).
  49. */
  50. const dealloc = wasm.exports[sqlite3.config.deallocExportName];
  51. const nFunc = wasm.functionTable().length;
  52. let i;
  53. for(i = 0; i < nFunc; ++i){
  54. const e = wasm.functionEntry(i);
  55. if(dealloc === e){
  56. capi.SQLITE_WASM_DEALLOC = i;
  57. break;
  58. }
  59. }
  60. if(dealloc !== wasm.functionEntry(capi.SQLITE_WASM_DEALLOC)){
  61. toss("Internal error: cannot find function pointer for SQLITE_WASM_DEALLOC.");
  62. }
  63. }
  64. /**
  65. Signatures for the WASM-exported C-side functions. Each entry
  66. is an array with 2+ elements:
  67. [ "c-side name",
  68. "result type" (wasm.xWrap() syntax),
  69. [arg types in xWrap() syntax]
  70. // ^^^ this needn't strictly be an array: it can be subsequent
  71. // elements instead: [x,y,z] is equivalent to x,y,z
  72. ]
  73. Note that support for the API-specific data types in the
  74. result/argument type strings gets plugged in at a later phase in
  75. the API initialization process.
  76. */
  77. wasm.bindingSignatures = [
  78. // Please keep these sorted by function name!
  79. ["sqlite3_aggregate_context","void*", "sqlite3_context*", "int"],
  80. /* sqlite3_auto_extension() has a hand-written binding. */
  81. /* sqlite3_bind_blob() and sqlite3_bind_text() have hand-written
  82. bindings to permit more flexible inputs. */
  83. ["sqlite3_bind_double","int", "sqlite3_stmt*", "int", "f64"],
  84. ["sqlite3_bind_int","int", "sqlite3_stmt*", "int", "int"],
  85. ["sqlite3_bind_null",undefined, "sqlite3_stmt*", "int"],
  86. ["sqlite3_bind_parameter_count", "int", "sqlite3_stmt*"],
  87. ["sqlite3_bind_parameter_index","int", "sqlite3_stmt*", "string"],
  88. ["sqlite3_bind_parameter_name", "string", "sqlite3_stmt*", "int"],
  89. ["sqlite3_bind_pointer", "int",
  90. "sqlite3_stmt*", "int", "*", "string:static", "*"],
  91. ["sqlite3_busy_handler","int", [
  92. "sqlite3*",
  93. new wasm.xWrap.FuncPtrAdapter({
  94. signature: 'i(pi)',
  95. contextKey: (argv,argIndex)=>argv[0/* sqlite3* */]
  96. }),
  97. "*"
  98. ]],
  99. ["sqlite3_busy_timeout","int", "sqlite3*", "int"],
  100. /* sqlite3_cancel_auto_extension() has a hand-written binding. */
  101. /* sqlite3_close_v2() is implemented by hand to perform some
  102. extra work. */
  103. ["sqlite3_changes", "int", "sqlite3*"],
  104. ["sqlite3_clear_bindings","int", "sqlite3_stmt*"],
  105. ["sqlite3_collation_needed", "int", "sqlite3*", "*", "*"/*=>v(ppis)*/],
  106. ["sqlite3_column_blob","*", "sqlite3_stmt*", "int"],
  107. ["sqlite3_column_bytes","int", "sqlite3_stmt*", "int"],
  108. ["sqlite3_column_count", "int", "sqlite3_stmt*"],
  109. ["sqlite3_column_decltype", "string", "sqlite3_stmt*", "int"],
  110. ["sqlite3_column_double","f64", "sqlite3_stmt*", "int"],
  111. ["sqlite3_column_int","int", "sqlite3_stmt*", "int"],
  112. ["sqlite3_column_name","string", "sqlite3_stmt*", "int"],
  113. ["sqlite3_column_text","string", "sqlite3_stmt*", "int"],
  114. ["sqlite3_column_type","int", "sqlite3_stmt*", "int"],
  115. ["sqlite3_column_value","sqlite3_value*", "sqlite3_stmt*", "int"],
  116. ["sqlite3_commit_hook", "void*", [
  117. "sqlite3*",
  118. new wasm.xWrap.FuncPtrAdapter({
  119. name: 'sqlite3_commit_hook',
  120. signature: 'i(p)',
  121. contextKey: (argv)=>argv[0/* sqlite3* */]
  122. }),
  123. '*'
  124. ]],
  125. ["sqlite3_compileoption_get", "string", "int"],
  126. ["sqlite3_compileoption_used", "int", "string"],
  127. ["sqlite3_complete", "int", "string:flexible"],
  128. ["sqlite3_context_db_handle", "sqlite3*", "sqlite3_context*"],
  129. /* sqlite3_create_collation() and sqlite3_create_collation_v2()
  130. use hand-written bindings to simplify passing of the callback
  131. function. */
  132. /* sqlite3_create_function(), sqlite3_create_function_v2(), and
  133. sqlite3_create_window_function() use hand-written bindings to
  134. simplify handling of their function-type arguments. */
  135. ["sqlite3_data_count", "int", "sqlite3_stmt*"],
  136. ["sqlite3_db_filename", "string", "sqlite3*", "string"],
  137. ["sqlite3_db_handle", "sqlite3*", "sqlite3_stmt*"],
  138. ["sqlite3_db_name", "string", "sqlite3*", "int"],
  139. ["sqlite3_db_readonly", "int", "sqlite3*", "string"],
  140. ["sqlite3_db_status", "int", "sqlite3*", "int", "*", "*", "int"],
  141. ["sqlite3_errcode", "int", "sqlite3*"],
  142. ["sqlite3_errmsg", "string", "sqlite3*"],
  143. ["sqlite3_error_offset", "int", "sqlite3*"],
  144. ["sqlite3_errstr", "string", "int"],
  145. ["sqlite3_exec", "int", [
  146. "sqlite3*", "string:flexible",
  147. new wasm.xWrap.FuncPtrAdapter({
  148. signature: 'i(pipp)',
  149. bindScope: 'transient',
  150. callProxy: (callback)=>{
  151. let aNames;
  152. return (pVoid, nCols, pColVals, pColNames)=>{
  153. try {
  154. const aVals = wasm.cArgvToJs(nCols, pColVals);
  155. if(!aNames) aNames = wasm.cArgvToJs(nCols, pColNames);
  156. return callback(aVals, aNames) | 0;
  157. }catch(e){
  158. /* If we set the db error state here, the higher-level
  159. exec() call replaces it with its own, so we have no way
  160. of reporting the exception message except the console. We
  161. must not propagate exceptions through the C API. Though
  162. we make an effort to report OOM here, sqlite3_exec()
  163. translates that into SQLITE_ABORT as well. */
  164. return e.resultCode || capi.SQLITE_ERROR;
  165. }
  166. }
  167. }
  168. }),
  169. "*", "**"
  170. ]],
  171. ["sqlite3_expanded_sql", "string", "sqlite3_stmt*"],
  172. ["sqlite3_extended_errcode", "int", "sqlite3*"],
  173. ["sqlite3_extended_result_codes", "int", "sqlite3*", "int"],
  174. ["sqlite3_file_control", "int", "sqlite3*", "string", "int", "*"],
  175. ["sqlite3_finalize", "int", "sqlite3_stmt*"],
  176. ["sqlite3_free", undefined,"*"],
  177. ["sqlite3_get_autocommit", "int", "sqlite3*"],
  178. ["sqlite3_get_auxdata", "*", "sqlite3_context*", "int"],
  179. ["sqlite3_initialize", undefined],
  180. ["sqlite3_interrupt", undefined, "sqlite3*"],
  181. ["sqlite3_is_interrupted", "int", "sqlite3*"],
  182. ["sqlite3_keyword_count", "int"],
  183. ["sqlite3_keyword_name", "int", ["int", "**", "*"]],
  184. ["sqlite3_keyword_check", "int", ["string", "int"]],
  185. ["sqlite3_libversion", "string"],
  186. ["sqlite3_libversion_number", "int"],
  187. ["sqlite3_limit", "int", ["sqlite3*", "int", "int"]],
  188. ["sqlite3_malloc", "*","int"],
  189. ["sqlite3_open", "int", "string", "*"],
  190. ["sqlite3_open_v2", "int", "string", "*", "int", "string"],
  191. /* sqlite3_prepare_v2() and sqlite3_prepare_v3() are handled
  192. separately due to us requiring two different sets of semantics
  193. for those, depending on how their SQL argument is provided. */
  194. /* sqlite3_randomness() uses a hand-written wrapper to extend
  195. the range of supported argument types. */
  196. ["sqlite3_realloc", "*","*","int"],
  197. ["sqlite3_reset", "int", "sqlite3_stmt*"],
  198. /* sqlite3_reset_auto_extension() has a hand-written binding. */
  199. ["sqlite3_result_blob", undefined, "sqlite3_context*", "*", "int", "*"],
  200. ["sqlite3_result_double", undefined, "sqlite3_context*", "f64"],
  201. ["sqlite3_result_error", undefined, "sqlite3_context*", "string", "int"],
  202. ["sqlite3_result_error_code", undefined, "sqlite3_context*", "int"],
  203. ["sqlite3_result_error_nomem", undefined, "sqlite3_context*"],
  204. ["sqlite3_result_error_toobig", undefined, "sqlite3_context*"],
  205. ["sqlite3_result_int", undefined, "sqlite3_context*", "int"],
  206. ["sqlite3_result_null", undefined, "sqlite3_context*"],
  207. ["sqlite3_result_pointer", undefined,
  208. "sqlite3_context*", "*", "string:static", "*"],
  209. ["sqlite3_result_subtype", undefined, "sqlite3_value*", "int"],
  210. ["sqlite3_result_text", undefined, "sqlite3_context*", "string", "int", "*"],
  211. ["sqlite3_result_zeroblob", undefined, "sqlite3_context*", "int"],
  212. ["sqlite3_rollback_hook", "void*", [
  213. "sqlite3*",
  214. new wasm.xWrap.FuncPtrAdapter({
  215. name: 'sqlite3_rollback_hook',
  216. signature: 'v(p)',
  217. contextKey: (argv)=>argv[0/* sqlite3* */]
  218. }),
  219. '*'
  220. ]],
  221. /**
  222. We do not have a way to automatically clean up destructors
  223. which are automatically converted from JS functions via the
  224. final argument to sqlite3_set_auxdata(). Because of that,
  225. automatic function conversion is not supported for this
  226. function. Clients should use wasm.installFunction() to create
  227. such callbacks, then pass that pointer to
  228. sqlite3_set_auxdata(). Relying on automated conversions here
  229. would lead to leaks of JS/WASM proxy functions because
  230. sqlite3_set_auxdata() is frequently called in UDFs.
  231. The sqlite3.oo1.DB class's onclose handlers can be used for this
  232. purpose. For example:
  233. const pAuxDtor = wasm.installFunction('v(p)', function(ptr){
  234. //free ptr
  235. });
  236. myDb.onclose = {
  237. after: ()=>{
  238. wasm.uninstallFunction(pAuxDtor);
  239. }
  240. };
  241. Then pass pAuxDtor as the final argument to appropriate
  242. sqlite3_set_auxdata() calls.
  243. Note that versions prior to 3.49.0 ostensibly had automatic
  244. function conversion here but a typo prevented it from
  245. working. Rather than fix it, it was removed because testing the
  246. fix brought the huge potential for memory leaks to the
  247. forefront.
  248. */
  249. ["sqlite3_set_auxdata", undefined, [
  250. "sqlite3_context*", "int", "*",
  251. true
  252. ? "*"
  253. : new wasm.xWrap.FuncPtrAdapter({
  254. /* If we can find a way to automate their cleanup, JS functions can
  255. be auto-converted with this. */
  256. name: 'xDestroyAuxData',
  257. signature: 'v(p)',
  258. contextKey: (argv, argIndex)=>argv[0/* sqlite3_context* */]
  259. })
  260. ]],
  261. ["sqlite3_shutdown", undefined],
  262. ["sqlite3_sourceid", "string"],
  263. ["sqlite3_sql", "string", "sqlite3_stmt*"],
  264. ["sqlite3_status", "int", "int", "*", "*", "int"],
  265. ["sqlite3_step", "int", "sqlite3_stmt*"],
  266. ["sqlite3_stmt_busy", "int", "sqlite3_stmt*"],
  267. ["sqlite3_stmt_readonly", "int", "sqlite3_stmt*"],
  268. ["sqlite3_stmt_status", "int", "sqlite3_stmt*", "int", "int"],
  269. ["sqlite3_strglob", "int", "string","string"],
  270. ["sqlite3_stricmp", "int", "string", "string"],
  271. ["sqlite3_strlike", "int", "string", "string","int"],
  272. ["sqlite3_strnicmp", "int", "string", "string", "int"],
  273. ["sqlite3_table_column_metadata", "int",
  274. "sqlite3*", "string", "string", "string",
  275. "**", "**", "*", "*", "*"],
  276. ["sqlite3_total_changes", "int", "sqlite3*"],
  277. ["sqlite3_trace_v2", "int", [
  278. "sqlite3*", "int",
  279. new wasm.xWrap.FuncPtrAdapter({
  280. name: 'sqlite3_trace_v2::callback',
  281. signature: 'i(ippp)',
  282. contextKey: (argv,argIndex)=>argv[0/* sqlite3* */]
  283. }),
  284. "*"
  285. ]],
  286. ["sqlite3_txn_state", "int", ["sqlite3*","string"]],
  287. /* Note that sqlite3_uri_...() have very specific requirements for
  288. their first C-string arguments, so we cannot perform any value
  289. conversion on those. */
  290. ["sqlite3_uri_boolean", "int", "sqlite3_filename", "string", "int"],
  291. ["sqlite3_uri_key", "string", "sqlite3_filename", "int"],
  292. ["sqlite3_uri_parameter", "string", "sqlite3_filename", "string"],
  293. ["sqlite3_user_data","void*", "sqlite3_context*"],
  294. ["sqlite3_value_blob", "*", "sqlite3_value*"],
  295. ["sqlite3_value_bytes","int", "sqlite3_value*"],
  296. ["sqlite3_value_double","f64", "sqlite3_value*"],
  297. ["sqlite3_value_dup", "sqlite3_value*", "sqlite3_value*"],
  298. ["sqlite3_value_free", undefined, "sqlite3_value*"],
  299. ["sqlite3_value_frombind", "int", "sqlite3_value*"],
  300. ["sqlite3_value_int","int", "sqlite3_value*"],
  301. ["sqlite3_value_nochange", "int", "sqlite3_value*"],
  302. ["sqlite3_value_numeric_type", "int", "sqlite3_value*"],
  303. ["sqlite3_value_pointer", "*", "sqlite3_value*", "string:static"],
  304. ["sqlite3_value_subtype", "int", "sqlite3_value*"],
  305. ["sqlite3_value_text", "string", "sqlite3_value*"],
  306. ["sqlite3_value_type", "int", "sqlite3_value*"],
  307. ["sqlite3_vfs_find", "*", "string"],
  308. ["sqlite3_vfs_register", "int", "sqlite3_vfs*", "int"],
  309. ["sqlite3_vfs_unregister", "int", "sqlite3_vfs*"]
  310. ]/*wasm.bindingSignatures*/;
  311. if( !!wasm.exports.sqlite3_progress_handler ){
  312. wasm.bindingSignatures.push(
  313. ["sqlite3_progress_handler", undefined, [
  314. "sqlite3*", "int", new wasm.xWrap.FuncPtrAdapter({
  315. name: 'xProgressHandler',
  316. signature: 'i(p)',
  317. bindScope: 'context',
  318. contextKey: (argv,argIndex)=>argv[0/* sqlite3* */]
  319. }), "*"
  320. ]]
  321. );
  322. }
  323. if( !!wasm.exports.sqlite3_stmt_explain ){
  324. wasm.bindingSignatures.push(
  325. ["sqlite3_stmt_explain", "int", "sqlite3_stmt*", "int"],
  326. ["sqlite3_stmt_isexplain", "int", "sqlite3_stmt*"]
  327. );
  328. }
  329. if( !!wasm.exports.sqlite3_set_authorizer ){
  330. wasm.bindingSignatures.push(
  331. ["sqlite3_set_authorizer", "int", [
  332. "sqlite3*",
  333. new wasm.xWrap.FuncPtrAdapter({
  334. name: "sqlite3_set_authorizer::xAuth",
  335. signature: "i(pi"+"ssss)",
  336. contextKey: (argv, argIndex)=>argv[0/*(sqlite3*)*/],
  337. callProxy: (callback)=>{
  338. return (pV, iCode, s0, s1, s2, s3)=>{
  339. try{
  340. s0 = s0 && wasm.cstrToJs(s0); s1 = s1 && wasm.cstrToJs(s1);
  341. s2 = s2 && wasm.cstrToJs(s2); s3 = s3 && wasm.cstrToJs(s3);
  342. return callback(pV, iCode, s0, s1, s2, s3) || 0;
  343. }catch(e){
  344. return e.resultCode || capi.SQLITE_ERROR;
  345. }
  346. }
  347. }
  348. }),
  349. "*"/*pUserData*/
  350. ]]
  351. );
  352. }/* sqlite3_set_authorizer() */
  353. if(false && wasm.compileOptionUsed('SQLITE_ENABLE_NORMALIZE')){
  354. /* ^^^ "the problem" is that this is an optional feature and the
  355. build-time function-export list does not currently take
  356. optional features into account. */
  357. wasm.bindingSignatures.push(["sqlite3_normalized_sql", "string", "sqlite3_stmt*"]);
  358. }
  359. //#if enable-see
  360. if(wasm.exports.sqlite3_key_v2 instanceof Function){
  361. /**
  362. This code is capable of using an SEE build but note that an SEE
  363. WASM build is generally incompatible with SEE's license
  364. conditions. It is permitted for use internally in organizations
  365. which have licensed SEE, but not for public sites because
  366. exposing an SEE build of sqlite3.wasm effectively provides all
  367. clients with a working copy of the commercial SEE code.
  368. */
  369. wasm.bindingSignatures.push(
  370. ["sqlite3_key", "int", "sqlite3*", "string", "int"],
  371. ["sqlite3_key_v2","int","sqlite3*","string","*","int"],
  372. ["sqlite3_rekey", "int", "sqlite3*", "string", "int"],
  373. ["sqlite3_rekey_v2", "int", "sqlite3*", "string", "*", "int"],
  374. ["sqlite3_activate_see", undefined, "string"]
  375. );
  376. }
  377. //#endif enable-see
  378. /**
  379. Functions which require BigInt (int64) support are separated from
  380. the others because we need to conditionally bind them or apply
  381. dummy impls, depending on the capabilities of the environment.
  382. (That said: we never actually build without BigInt support,
  383. and such builds are untested.)
  384. Note that not all of these functions directly require int64
  385. but are only for use with APIs which require int64. For example,
  386. the vtab-related functions.
  387. */
  388. wasm.bindingSignatures.int64 = [
  389. ["sqlite3_bind_int64","int", ["sqlite3_stmt*", "int", "i64"]],
  390. ["sqlite3_changes64","i64", ["sqlite3*"]],
  391. ["sqlite3_column_int64","i64", ["sqlite3_stmt*", "int"]],
  392. ["sqlite3_deserialize", "int", "sqlite3*", "string", "*", "i64", "i64", "int"]
  393. /* Careful! Short version: de/serialize() are problematic because they
  394. might use a different allocator than the user for managing the
  395. deserialized block. de/serialize() are ONLY safe to use with
  396. sqlite3_malloc(), sqlite3_free(), and its 64-bit variants. Because
  397. of this, the canonical builds of sqlite3.wasm/js guarantee that
  398. sqlite3.wasm.alloc() and friends use those allocators. Custom builds
  399. may not guarantee that, however. */,
  400. ["sqlite3_last_insert_rowid", "i64", ["sqlite3*"]],
  401. ["sqlite3_malloc64", "*","i64"],
  402. ["sqlite3_msize", "i64", "*"],
  403. ["sqlite3_overload_function", "int", ["sqlite3*","string","int"]],
  404. ["sqlite3_realloc64", "*","*", "i64"],
  405. ["sqlite3_result_int64", undefined, "*", "i64"],
  406. ["sqlite3_result_zeroblob64", "int", "*", "i64"],
  407. ["sqlite3_serialize","*", "sqlite3*", "string", "*", "int"],
  408. ["sqlite3_set_last_insert_rowid", undefined, ["sqlite3*", "i64"]],
  409. ["sqlite3_status64", "int", "int", "*", "*", "int"],
  410. ["sqlite3_total_changes64", "i64", ["sqlite3*"]],
  411. ["sqlite3_update_hook", "*", [
  412. "sqlite3*",
  413. new wasm.xWrap.FuncPtrAdapter({
  414. name: 'sqlite3_update_hook',
  415. signature: "v(iippj)",
  416. contextKey: (argv)=>argv[0/* sqlite3* */],
  417. callProxy: (callback)=>{
  418. return (p,op,z0,z1,rowid)=>{
  419. callback(p, op, wasm.cstrToJs(z0), wasm.cstrToJs(z1), rowid);
  420. };
  421. }
  422. }),
  423. "*"
  424. ]],
  425. ["sqlite3_uri_int64", "i64", ["sqlite3_filename", "string", "i64"]],
  426. ["sqlite3_value_int64","i64", "sqlite3_value*"]
  427. ];
  428. if( wasm.bigIntEnabled && !!wasm.exports.sqlite3_declare_vtab ){
  429. wasm.bindingSignatures.int64.push(
  430. ["sqlite3_create_module", "int",
  431. ["sqlite3*","string","sqlite3_module*","*"]],
  432. ["sqlite3_create_module_v2", "int",
  433. ["sqlite3*","string","sqlite3_module*","*","*"]],
  434. ["sqlite3_declare_vtab", "int", ["sqlite3*", "string:flexible"]],
  435. ["sqlite3_drop_modules", "int", ["sqlite3*", "**"]],
  436. ["sqlite3_vtab_collation","string","sqlite3_index_info*","int"],
  437. ["sqlite3_vtab_distinct","int", "sqlite3_index_info*"],
  438. ["sqlite3_vtab_in","int", "sqlite3_index_info*", "int", "int"],
  439. ["sqlite3_vtab_in_first", "int", "sqlite3_value*", "**"],
  440. ["sqlite3_vtab_in_next", "int", "sqlite3_value*", "**"],
  441. /*["sqlite3_vtab_config" is variadic and requires a hand-written
  442. proxy.] */
  443. ["sqlite3_vtab_nochange","int", "sqlite3_context*"],
  444. ["sqlite3_vtab_on_conflict","int", "sqlite3*"],
  445. ["sqlite3_vtab_rhs_value","int", "sqlite3_index_info*", "int", "**"]
  446. );
  447. }/* virtual table APIs */
  448. if(wasm.bigIntEnabled && !!wasm.exports.sqlite3_preupdate_hook){
  449. wasm.bindingSignatures.int64.push(
  450. ["sqlite3_preupdate_blobwrite", "int", "sqlite3*"],
  451. ["sqlite3_preupdate_count", "int", "sqlite3*"],
  452. ["sqlite3_preupdate_depth", "int", "sqlite3*"],
  453. ["sqlite3_preupdate_hook", "*", [
  454. "sqlite3*",
  455. new wasm.xWrap.FuncPtrAdapter({
  456. name: 'sqlite3_preupdate_hook',
  457. signature: "v(ppippjj)",
  458. contextKey: (argv)=>argv[0/* sqlite3* */],
  459. callProxy: (callback)=>{
  460. return (p,db,op,zDb,zTbl,iKey1,iKey2)=>{
  461. callback(p, db, op, wasm.cstrToJs(zDb), wasm.cstrToJs(zTbl),
  462. iKey1, iKey2);
  463. };
  464. }
  465. }),
  466. "*"
  467. ]],
  468. ["sqlite3_preupdate_new", "int", ["sqlite3*", "int", "**"]],
  469. ["sqlite3_preupdate_old", "int", ["sqlite3*", "int", "**"]]
  470. );
  471. } /* preupdate API */
  472. // Add session/changeset APIs...
  473. if(wasm.bigIntEnabled
  474. && !!wasm.exports.sqlite3changegroup_add
  475. && !!wasm.exports.sqlite3session_create
  476. && !!wasm.exports.sqlite3_preupdate_hook /* required by the session API */){
  477. /**
  478. FuncPtrAdapter options for session-related callbacks with the
  479. native signature "i(ps)". This proxy converts the 2nd argument
  480. from a C string to a JS string before passing the arguments on
  481. to the client-provided JS callback.
  482. */
  483. const __ipsProxy = {
  484. signature: 'i(ps)',
  485. callProxy:(callback)=>{
  486. return (p,s)=>{
  487. try{return callback(p, wasm.cstrToJs(s)) | 0}
  488. catch(e){return e.resultCode || capi.SQLITE_ERROR}
  489. }
  490. }
  491. };
  492. wasm.bindingSignatures.int64.push(...[
  493. ['sqlite3changegroup_add', 'int', ['sqlite3_changegroup*', 'int', 'void*']],
  494. ['sqlite3changegroup_add_strm', 'int', [
  495. 'sqlite3_changegroup*',
  496. new wasm.xWrap.FuncPtrAdapter({
  497. name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
  498. }),
  499. 'void*'
  500. ]],
  501. ['sqlite3changegroup_delete', undefined, ['sqlite3_changegroup*']],
  502. ['sqlite3changegroup_new', 'int', ['**']],
  503. ['sqlite3changegroup_output', 'int', ['sqlite3_changegroup*', 'int*', '**']],
  504. ['sqlite3changegroup_output_strm', 'int', [
  505. 'sqlite3_changegroup*',
  506. new wasm.xWrap.FuncPtrAdapter({
  507. name: 'xOutput', signature: 'i(ppi)', bindScope: 'transient'
  508. }),
  509. 'void*'
  510. ]],
  511. ['sqlite3changeset_apply', 'int', [
  512. 'sqlite3*', 'int', 'void*',
  513. new wasm.xWrap.FuncPtrAdapter({
  514. name: 'xFilter', bindScope: 'transient', ...__ipsProxy
  515. }),
  516. new wasm.xWrap.FuncPtrAdapter({
  517. name: 'xConflict', signature: 'i(pip)', bindScope: 'transient'
  518. }),
  519. 'void*'
  520. ]],
  521. ['sqlite3changeset_apply_strm', 'int', [
  522. 'sqlite3*',
  523. new wasm.xWrap.FuncPtrAdapter({
  524. name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
  525. }),
  526. 'void*',
  527. new wasm.xWrap.FuncPtrAdapter({
  528. name: 'xFilter', bindScope: 'transient', ...__ipsProxy
  529. }),
  530. new wasm.xWrap.FuncPtrAdapter({
  531. name: 'xConflict', signature: 'i(pip)', bindScope: 'transient'
  532. }),
  533. 'void*'
  534. ]],
  535. ['sqlite3changeset_apply_v2', 'int', [
  536. 'sqlite3*', 'int', 'void*',
  537. new wasm.xWrap.FuncPtrAdapter({
  538. name: 'xFilter', bindScope: 'transient', ...__ipsProxy
  539. }),
  540. new wasm.xWrap.FuncPtrAdapter({
  541. name: 'xConflict', signature: 'i(pip)', bindScope: 'transient'
  542. }),
  543. 'void*', '**', 'int*', 'int'
  544. ]],
  545. ['sqlite3changeset_apply_v2_strm', 'int', [
  546. 'sqlite3*',
  547. new wasm.xWrap.FuncPtrAdapter({
  548. name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
  549. }),
  550. 'void*',
  551. new wasm.xWrap.FuncPtrAdapter({
  552. name: 'xFilter', bindScope: 'transient', ...__ipsProxy
  553. }),
  554. new wasm.xWrap.FuncPtrAdapter({
  555. name: 'xConflict', signature: 'i(pip)', bindScope: 'transient'
  556. }),
  557. 'void*', '**', 'int*', 'int'
  558. ]],
  559. ['sqlite3changeset_concat', 'int', ['int','void*', 'int', 'void*', 'int*', '**']],
  560. ['sqlite3changeset_concat_strm', 'int', [
  561. new wasm.xWrap.FuncPtrAdapter({
  562. name: 'xInputA', signature: 'i(ppp)', bindScope: 'transient'
  563. }),
  564. 'void*',
  565. new wasm.xWrap.FuncPtrAdapter({
  566. name: 'xInputB', signature: 'i(ppp)', bindScope: 'transient'
  567. }),
  568. 'void*',
  569. new wasm.xWrap.FuncPtrAdapter({
  570. name: 'xOutput', signature: 'i(ppi)', bindScope: 'transient'
  571. }),
  572. 'void*'
  573. ]],
  574. ['sqlite3changeset_conflict', 'int', ['sqlite3_changeset_iter*', 'int', '**']],
  575. ['sqlite3changeset_finalize', 'int', ['sqlite3_changeset_iter*']],
  576. ['sqlite3changeset_fk_conflicts', 'int', ['sqlite3_changeset_iter*', 'int*']],
  577. ['sqlite3changeset_invert', 'int', ['int', 'void*', 'int*', '**']],
  578. ['sqlite3changeset_invert_strm', 'int', [
  579. new wasm.xWrap.FuncPtrAdapter({
  580. name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
  581. }),
  582. 'void*',
  583. new wasm.xWrap.FuncPtrAdapter({
  584. name: 'xOutput', signature: 'i(ppi)', bindScope: 'transient'
  585. }),
  586. 'void*'
  587. ]],
  588. ['sqlite3changeset_new', 'int', ['sqlite3_changeset_iter*', 'int', '**']],
  589. ['sqlite3changeset_next', 'int', ['sqlite3_changeset_iter*']],
  590. ['sqlite3changeset_old', 'int', ['sqlite3_changeset_iter*', 'int', '**']],
  591. ['sqlite3changeset_op', 'int', [
  592. 'sqlite3_changeset_iter*', '**', 'int*', 'int*','int*'
  593. ]],
  594. ['sqlite3changeset_pk', 'int', ['sqlite3_changeset_iter*', '**', 'int*']],
  595. ['sqlite3changeset_start', 'int', ['**', 'int', '*']],
  596. ['sqlite3changeset_start_strm', 'int', [
  597. '**',
  598. new wasm.xWrap.FuncPtrAdapter({
  599. name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
  600. }),
  601. 'void*'
  602. ]],
  603. ['sqlite3changeset_start_v2', 'int', ['**', 'int', '*', 'int']],
  604. ['sqlite3changeset_start_v2_strm', 'int', [
  605. '**',
  606. new wasm.xWrap.FuncPtrAdapter({
  607. name: 'xInput', signature: 'i(ppp)', bindScope: 'transient'
  608. }),
  609. 'void*', 'int'
  610. ]],
  611. ['sqlite3session_attach', 'int', ['sqlite3_session*', 'string']],
  612. ['sqlite3session_changeset', 'int', ['sqlite3_session*', 'int*', '**']],
  613. ['sqlite3session_changeset_size', 'i64', ['sqlite3_session*']],
  614. ['sqlite3session_changeset_strm', 'int', [
  615. 'sqlite3_session*',
  616. new wasm.xWrap.FuncPtrAdapter({
  617. name: 'xOutput', signature: 'i(ppp)', bindScope: 'transient'
  618. }),
  619. 'void*'
  620. ]],
  621. ['sqlite3session_config', 'int', ['int', 'void*']],
  622. ['sqlite3session_create', 'int', ['sqlite3*', 'string', '**']],
  623. //sqlite3session_delete() is bound manually
  624. ['sqlite3session_diff', 'int', ['sqlite3_session*', 'string', 'string', '**']],
  625. ['sqlite3session_enable', 'int', ['sqlite3_session*', 'int']],
  626. ['sqlite3session_indirect', 'int', ['sqlite3_session*', 'int']],
  627. ['sqlite3session_isempty', 'int', ['sqlite3_session*']],
  628. ['sqlite3session_memory_used', 'i64', ['sqlite3_session*']],
  629. ['sqlite3session_object_config', 'int', ['sqlite3_session*', 'int', 'void*']],
  630. ['sqlite3session_patchset', 'int', ['sqlite3_session*', '*', '**']],
  631. ['sqlite3session_patchset_strm', 'int', [
  632. 'sqlite3_session*',
  633. new wasm.xWrap.FuncPtrAdapter({
  634. name: 'xOutput', signature: 'i(ppp)', bindScope: 'transient'
  635. }),
  636. 'void*'
  637. ]],
  638. ['sqlite3session_table_filter', undefined, [
  639. 'sqlite3_session*',
  640. new wasm.xWrap.FuncPtrAdapter({
  641. name: 'xFilter', ...__ipsProxy,
  642. contextKey: (argv,argIndex)=>argv[0/* (sqlite3_session*) */]
  643. }),
  644. '*'
  645. ]]
  646. ]);
  647. }/*session/changeset APIs*/
  648. /**
  649. Functions which are intended solely for API-internal use by the
  650. WASM components, not client code. These get installed into
  651. sqlite3.util. Some of them get exposed to clients via variants
  652. in sqlite3_js_...().
  653. 2024-01-11: these were renamed, with two underscores in the
  654. prefix, to ensure that clients do not accidentally depend on
  655. them. They have always been documented as internal-use-only, so
  656. no clients "should" be depending on the old names.
  657. */
  658. wasm.bindingSignatures.wasmInternal = [
  659. ["sqlite3__wasm_db_reset", "int", "sqlite3*"],
  660. ["sqlite3__wasm_db_vfs", "sqlite3_vfs*", "sqlite3*","string"],
  661. [/* DO NOT USE. This is deprecated since 2023-08-11 because it can
  662. trigger assert() in debug builds when used with file sizes
  663. which are not sizes to a multiple of a valid db page size. */
  664. "sqlite3__wasm_vfs_create_file", "int", "sqlite3_vfs*","string","*", "int"
  665. ],
  666. ["sqlite3__wasm_posix_create_file", "int", "string","*", "int"],
  667. ["sqlite3__wasm_vfs_unlink", "int", "sqlite3_vfs*","string"],
  668. ["sqlite3__wasm_qfmt_token","string:dealloc", "string","int"]
  669. ];
  670. /**
  671. Install JS<->C struct bindings for the non-opaque struct types we
  672. need... */
  673. sqlite3.StructBinder = globalThis.Jaccwabyt({
  674. heap: 0 ? wasm.memory : wasm.heap8u,
  675. alloc: wasm.alloc,
  676. dealloc: wasm.dealloc,
  677. bigIntEnabled: wasm.bigIntEnabled,
  678. memberPrefix: /* Never change this: this prefix is baked into any
  679. amount of code and client-facing docs. */ '$'
  680. });
  681. delete globalThis.Jaccwabyt;
  682. {// wasm.xWrap() bindings...
  683. /* Convert Arrays and certain TypedArrays to strings for
  684. 'string:flexible'-type arguments */
  685. const __xString = wasm.xWrap.argAdapter('string');
  686. wasm.xWrap.argAdapter(
  687. 'string:flexible', (v)=>__xString(util.flexibleString(v))
  688. );
  689. /**
  690. The 'string:static' argument adapter treats its argument as
  691. either...
  692. - WASM pointer: assumed to be a long-lived C-string which gets
  693. returned as-is.
  694. - Anything else: gets coerced to a JS string for use as a map
  695. key. If a matching entry is found (as described next), it is
  696. returned, else wasm.allocCString() is used to create a a new
  697. string, map its pointer to (''+v) for the remainder of the
  698. application's life, and returns that pointer value for this
  699. call and all future calls which are passed a
  700. string-equivalent argument.
  701. Use case: sqlite3_bind_pointer() and sqlite3_result_pointer()
  702. call for "a static string and preferably a string
  703. literal." This converter is used to ensure that the string
  704. value seen by those functions is long-lived and behaves as they
  705. need it to.
  706. */
  707. wasm.xWrap.argAdapter(
  708. 'string:static',
  709. function(v){
  710. if(wasm.isPtr(v)) return v;
  711. v = ''+v;
  712. let rc = this[v];
  713. return rc || (this[v] = wasm.allocCString(v));
  714. }.bind(Object.create(null))
  715. );
  716. /**
  717. Add some descriptive xWrap() aliases for '*' intended to (A)
  718. initially improve readability/correctness of
  719. wasm.bindingSignatures and (B) provide automatic conversion
  720. from higher-level representations, e.g. capi.sqlite3_vfs to
  721. `sqlite3_vfs*` via capi.sqlite3_vfs.pointer.
  722. */
  723. const __xArgPtr = wasm.xWrap.argAdapter('*');
  724. const nilType = function(){
  725. /*a class which no value can ever be an instance of*/
  726. };
  727. wasm.xWrap.argAdapter('sqlite3_filename', __xArgPtr)
  728. ('sqlite3_context*', __xArgPtr)
  729. ('sqlite3_value*', __xArgPtr)
  730. ('void*', __xArgPtr)
  731. ('sqlite3_changegroup*', __xArgPtr)
  732. ('sqlite3_changeset_iter*', __xArgPtr)
  733. ('sqlite3_session*', __xArgPtr)
  734. ('sqlite3_stmt*', (v)=>
  735. __xArgPtr((v instanceof (sqlite3?.oo1?.Stmt || nilType))
  736. ? v.pointer : v))
  737. ('sqlite3*', (v)=>
  738. __xArgPtr((v instanceof (sqlite3?.oo1?.DB || nilType))
  739. ? v.pointer : v))
  740. /**
  741. `sqlite3_vfs*`:
  742. - v is-a string: use the result of sqlite3_vfs_find(v) but
  743. throw if it returns 0.
  744. - v is-a capi.sqlite3_vfs: use v.pointer.
  745. - Else return the same as the `'*'` argument conversion.
  746. */
  747. ('sqlite3_vfs*', (v)=>{
  748. if('string'===typeof v){
  749. /* A NULL sqlite3_vfs pointer will be treated as the default
  750. VFS in many contexts. We specifically do not want that
  751. behavior here. */
  752. return capi.sqlite3_vfs_find(v)
  753. || sqlite3.SQLite3Error.toss(
  754. capi.SQLITE_NOTFOUND,
  755. "Unknown sqlite3_vfs name:", v
  756. );
  757. }
  758. return __xArgPtr((v instanceof (capi.sqlite3_vfs || nilType))
  759. ? v.pointer : v);
  760. });
  761. if( wasm.exports.sqlite3_declare_vtab ){
  762. wasm.xWrap.argAdapter('sqlite3_index_info*', (v)=>
  763. __xArgPtr((v instanceof (capi.sqlite3_index_info || nilType))
  764. ? v.pointer : v))
  765. ('sqlite3_module*', (v)=>
  766. __xArgPtr((v instanceof (capi.sqlite3_module || nilType))
  767. ? v.pointer : v)
  768. );
  769. }
  770. const __xRcPtr = wasm.xWrap.resultAdapter('*');
  771. wasm.xWrap.resultAdapter('sqlite3*', __xRcPtr)
  772. ('sqlite3_context*', __xRcPtr)
  773. ('sqlite3_stmt*', __xRcPtr)
  774. ('sqlite3_value*', __xRcPtr)
  775. ('sqlite3_vfs*', __xRcPtr)
  776. ('void*', __xRcPtr);
  777. /**
  778. Populate api object with sqlite3_...() by binding the "raw" wasm
  779. exports into type-converting proxies using wasm.xWrap().
  780. */
  781. if(0 === wasm.exports.sqlite3_step.length){
  782. /* This environment wraps exports in nullary functions, which means
  783. we must disable the arg-count validation we otherwise perform
  784. on the wrappers. */
  785. wasm.xWrap.doArgcCheck = false;
  786. sqlite3.config.warn(
  787. "Disabling sqlite3.wasm.xWrap.doArgcCheck due to environmental quirks."
  788. );
  789. }
  790. for(const e of wasm.bindingSignatures){
  791. capi[e[0]] = wasm.xWrap.apply(null, e);
  792. }
  793. for(const e of wasm.bindingSignatures.wasmInternal){
  794. util[e[0]] = wasm.xWrap.apply(null, e);
  795. }
  796. /* For C API functions which cannot work properly unless
  797. wasm.bigIntEnabled is true, install a bogus impl which throws
  798. if called when bigIntEnabled is false. The alternative would be
  799. to elide these functions altogether, which seems likely to
  800. cause more confusion. */
  801. const fI64Disabled = function(fname){
  802. return ()=>toss(fname+"() is unavailable due to lack",
  803. "of BigInt support in this build.");
  804. };
  805. for(const e of wasm.bindingSignatures.int64){
  806. capi[e[0]] = wasm.bigIntEnabled
  807. ? wasm.xWrap.apply(null, e)
  808. : fI64Disabled(e[0]);
  809. }
  810. /* There's no need to expose bindingSignatures to clients,
  811. implicitly making it part of the public interface. */
  812. delete wasm.bindingSignatures;
  813. if(wasm.exports.sqlite3__wasm_db_error){
  814. const __db_err = wasm.xWrap(
  815. 'sqlite3__wasm_db_error', 'int', 'sqlite3*', 'int', 'string'
  816. );
  817. /**
  818. Sets the given db's error state. Accepts:
  819. - (sqlite3*, int code, string msg)
  820. - (sqlite3*, Error e [,string msg = ''+e])
  821. If passed a WasmAllocError, the message is ignored and the
  822. result code is SQLITE_NOMEM. If passed any other Error type,
  823. the result code defaults to SQLITE_ERROR unless the Error
  824. object has a resultCode property, in which case that is used
  825. (e.g. SQLite3Error has that). If passed a non-WasmAllocError
  826. exception, the message string defaults to theError.message.
  827. Returns the resulting code. Pass (pDb,0,0) to clear the error
  828. state.
  829. */
  830. util.sqlite3__wasm_db_error = function(pDb, resultCode, message){
  831. if(resultCode instanceof sqlite3.WasmAllocError){
  832. resultCode = capi.SQLITE_NOMEM;
  833. message = 0 /*avoid allocating message string*/;
  834. }else if(resultCode instanceof Error){
  835. message = message || ''+resultCode;
  836. resultCode = (resultCode.resultCode || capi.SQLITE_ERROR);
  837. }
  838. return pDb ? __db_err(pDb, resultCode, message) : resultCode;
  839. };
  840. }else{
  841. util.sqlite3__wasm_db_error = function(pDb,errCode,msg){
  842. console.warn("sqlite3__wasm_db_error() is not exported.",arguments);
  843. return errCode;
  844. };
  845. }
  846. }/*xWrap() bindings*/
  847. {/* Import C-level constants and structs... */
  848. const cJson = wasm.xCall('sqlite3__wasm_enum_json');
  849. if(!cJson){
  850. toss("Maintenance required: increase sqlite3__wasm_enum_json()'s",
  851. "static buffer size!");
  852. }
  853. //console.debug('wasm.ctype length =',wasm.cstrlen(cJson));
  854. wasm.ctype = JSON.parse(wasm.cstrToJs(cJson));
  855. // Groups of SQLITE_xyz macros...
  856. const defineGroups = ['access', 'authorizer',
  857. 'blobFinalizers', 'changeset',
  858. 'config', 'dataTypes',
  859. 'dbConfig', 'dbStatus',
  860. 'encodings', 'fcntl', 'flock', 'ioCap',
  861. 'limits', 'openFlags',
  862. 'prepareFlags', 'resultCodes',
  863. 'sqlite3Status',
  864. 'stmtStatus', 'syncFlags',
  865. 'trace', 'txnState', 'udfFlags',
  866. 'version' ];
  867. if(wasm.bigIntEnabled){
  868. defineGroups.push('serialize', 'session', 'vtab');
  869. }
  870. for(const t of defineGroups){
  871. for(const e of Object.entries(wasm.ctype[t])){
  872. // ^^^ [k,v] there triggers a buggy code transformation via
  873. // one of the Emscripten-driven optimizers.
  874. capi[e[0]] = e[1];
  875. }
  876. }
  877. if(!wasm.functionEntry(capi.SQLITE_WASM_DEALLOC)){
  878. toss("Internal error: cannot resolve exported function",
  879. "entry SQLITE_WASM_DEALLOC (=="+capi.SQLITE_WASM_DEALLOC+").");
  880. }
  881. const __rcMap = Object.create(null);
  882. for(const t of ['resultCodes']){
  883. for(const e of Object.entries(wasm.ctype[t])){
  884. __rcMap[e[1]] = e[0];
  885. }
  886. }
  887. /**
  888. For the given integer, returns the SQLITE_xxx result code as a
  889. string, or undefined if no such mapping is found.
  890. */
  891. capi.sqlite3_js_rc_str = (rc)=>__rcMap[rc];
  892. /* Bind all registered C-side structs... */
  893. const notThese = Object.assign(Object.create(null),{
  894. // For each struct to NOT register, map its name to true:
  895. WasmTestStruct: true,
  896. /* We unregister the kvvfs VFS from Worker threads below. */
  897. sqlite3_kvvfs_methods: !util.isUIThread(),
  898. /* sqlite3_index_info and friends require int64: */
  899. sqlite3_index_info: !wasm.bigIntEnabled,
  900. sqlite3_index_constraint: !wasm.bigIntEnabled,
  901. sqlite3_index_orderby: !wasm.bigIntEnabled,
  902. sqlite3_index_constraint_usage: !wasm.bigIntEnabled
  903. });
  904. for(const s of wasm.ctype.structs){
  905. if(!notThese[s.name]){
  906. capi[s.name] = sqlite3.StructBinder(s);
  907. }
  908. }
  909. if(capi.sqlite3_index_info){
  910. /* Move these inner structs into sqlite3_index_info. Binding
  911. ** them to WASM requires that we create global-scope structs to
  912. ** model them with, but those are no longer needed after we've
  913. ** passed them to StructBinder. */
  914. for(const k of ['sqlite3_index_constraint',
  915. 'sqlite3_index_orderby',
  916. 'sqlite3_index_constraint_usage']){
  917. capi.sqlite3_index_info[k] = capi[k];
  918. delete capi[k];
  919. }
  920. capi.sqlite3_vtab_config = wasm.xWrap(
  921. 'sqlite3__wasm_vtab_config','int',[
  922. 'sqlite3*', 'int', 'int']
  923. );
  924. }/* end vtab-related setup */
  925. }/*end C constant and struct imports*/
  926. /**
  927. Internal helper to assist in validating call argument counts in
  928. the hand-written sqlite3_xyz() wrappers. We do this only for
  929. consistency with non-special-case wrappings.
  930. */
  931. const __dbArgcMismatch = (pDb,f,n)=>{
  932. return util.sqlite3__wasm_db_error(pDb, capi.SQLITE_MISUSE,
  933. f+"() requires "+n+" argument"+
  934. (1===n?"":'s')+".");
  935. };
  936. /** Code duplication reducer for functions which take an encoding
  937. argument and require SQLITE_UTF8. Sets the db error code to
  938. SQLITE_FORMAT, installs a descriptive error message,
  939. and returns SQLITE_FORMAT. */
  940. const __errEncoding = (pDb)=>{
  941. return util.sqlite3__wasm_db_error(
  942. pDb, capi.SQLITE_FORMAT, "SQLITE_UTF8 is the only supported encoding."
  943. );
  944. };
  945. /**
  946. __dbCleanupMap is infrastructure for recording registration of
  947. UDFs and collations so that sqlite3_close_v2() can clean up any
  948. automated JS-to-WASM function conversions installed by those.
  949. */
  950. const __argPDb = (pDb)=>wasm.xWrap.argAdapter('sqlite3*')(pDb);
  951. const __argStr = (str)=>wasm.isPtr(str) ? wasm.cstrToJs(str) : str;
  952. const __dbCleanupMap = function(
  953. pDb, mode/*0=remove, >0=create if needed, <0=do not create if missing*/
  954. ){
  955. pDb = __argPDb(pDb);
  956. let m = this.dbMap.get(pDb);
  957. if(!mode){
  958. this.dbMap.delete(pDb);
  959. return m;
  960. }else if(!m && mode>0){
  961. this.dbMap.set(pDb, (m = Object.create(null)));
  962. }
  963. return m;
  964. }.bind(Object.assign(Object.create(null),{
  965. dbMap: new Map
  966. }));
  967. __dbCleanupMap.addCollation = function(pDb, name){
  968. const m = __dbCleanupMap(pDb, 1);
  969. if(!m.collation) m.collation = new Set;
  970. m.collation.add(__argStr(name).toLowerCase());
  971. };
  972. __dbCleanupMap._addUDF = function(pDb, name, arity, map){
  973. /* Map UDF name to a Set of arity values */
  974. name = __argStr(name).toLowerCase();
  975. let u = map.get(name);
  976. if(!u) map.set(name, (u = new Set));
  977. u.add((arity<0) ? -1 : arity);
  978. };
  979. __dbCleanupMap.addFunction = function(pDb, name, arity){
  980. const m = __dbCleanupMap(pDb, 1);
  981. if(!m.udf) m.udf = new Map;
  982. this._addUDF(pDb, name, arity, m.udf);
  983. };
  984. if( wasm.exports.sqlite3_create_window_function ){
  985. __dbCleanupMap.addWindowFunc = function(pDb, name, arity){
  986. const m = __dbCleanupMap(pDb, 1);
  987. if(!m.wudf) m.wudf = new Map;
  988. this._addUDF(pDb, name, arity, m.wudf);
  989. };
  990. }
  991. /**
  992. Intended to be called _only_ from sqlite3_close_v2(),
  993. passed its non-0 db argument.
  994. This function frees up certain automatically-installed WASM
  995. function bindings which were installed on behalf of the given db,
  996. as those may otherwise leak.
  997. Notable caveat: this is only ever run via
  998. sqlite3.capi.sqlite3_close_v2(). If a client, for whatever
  999. reason, uses sqlite3.wasm.exports.sqlite3_close_v2() (the
  1000. function directly exported from WASM), this cleanup will not
  1001. happen.
  1002. This is not a silver bullet for avoiding automation-related
  1003. leaks but represents "an honest effort."
  1004. The issue being addressed here is covered at:
  1005. https://sqlite.org/wasm/doc/trunk/api-c-style.md#convert-func-ptr
  1006. */
  1007. __dbCleanupMap.cleanup = function(pDb){
  1008. pDb = __argPDb(pDb);
  1009. //wasm.xWrap.FuncPtrAdapter.debugFuncInstall = false;
  1010. /**
  1011. Installing NULL functions in the C API will remove those
  1012. bindings. The FuncPtrAdapter which sits between us and the C
  1013. API will also treat that as an opportunity to
  1014. wasm.uninstallFunction() any WASM function bindings it has
  1015. installed for pDb.
  1016. */
  1017. const closeArgs = [pDb];
  1018. for(const name of [
  1019. 'sqlite3_busy_handler',
  1020. 'sqlite3_commit_hook',
  1021. 'sqlite3_preupdate_hook',
  1022. 'sqlite3_progress_handler',
  1023. 'sqlite3_rollback_hook',
  1024. 'sqlite3_set_authorizer',
  1025. 'sqlite3_trace_v2',
  1026. 'sqlite3_update_hook'
  1027. /*
  1028. We do not yet have a way to clean up automatically-converted
  1029. sqlite3_set_auxdata() finalizers.
  1030. */
  1031. ]) {
  1032. const x = wasm.exports[name];
  1033. if( !x ){
  1034. /* assume it was built without this API */
  1035. continue;
  1036. }
  1037. closeArgs.length = x.length/*==argument count*/
  1038. /* recall that undefined entries translate to 0 when passed to
  1039. WASM. */;
  1040. try{ capi[name](...closeArgs) }
  1041. catch(e){
  1042. sqlite3.config.warn("close-time call of",name+"(",closeArgs,") threw:",e);
  1043. }
  1044. }
  1045. const m = __dbCleanupMap(pDb, 0);
  1046. if(!m) return;
  1047. if(m.collation){
  1048. for(const name of m.collation){
  1049. try{
  1050. capi.sqlite3_create_collation_v2(
  1051. pDb, name, capi.SQLITE_UTF8, 0, 0, 0
  1052. );
  1053. }catch(e){
  1054. /*ignored*/
  1055. }
  1056. }
  1057. delete m.collation;
  1058. }
  1059. let i;
  1060. for(i = 0; i < 2; ++i){ /* Clean up UDFs... */
  1061. const fmap = i ? m.wudf : m.udf;
  1062. if(!fmap) continue;
  1063. const func = i
  1064. ? capi.sqlite3_create_window_function
  1065. : capi.sqlite3_create_function_v2;
  1066. for(const e of fmap){
  1067. const name = e[0], arities = e[1];
  1068. const fargs = [pDb, name, 0/*arity*/, capi.SQLITE_UTF8, 0, 0, 0, 0, 0];
  1069. if(i) fargs.push(0);
  1070. for(const arity of arities){
  1071. try{ fargs[2] = arity; func.apply(null, fargs); }
  1072. catch(e){/*ignored*/}
  1073. }
  1074. arities.clear();
  1075. }
  1076. fmap.clear();
  1077. }
  1078. delete m.udf;
  1079. delete m.wudf;
  1080. }/*__dbCleanupMap.cleanup()*/;
  1081. {/* Binding of sqlite3_close_v2() */
  1082. const __sqlite3CloseV2 = wasm.xWrap("sqlite3_close_v2", "int", "sqlite3*");
  1083. capi.sqlite3_close_v2 = function(pDb){
  1084. if(1!==arguments.length) return __dbArgcMismatch(pDb, 'sqlite3_close_v2', 1);
  1085. if(pDb){
  1086. try{__dbCleanupMap.cleanup(pDb)} catch(e){/*ignored*/}
  1087. }
  1088. return __sqlite3CloseV2(pDb);
  1089. };
  1090. }/*sqlite3_close_v2()*/
  1091. if(capi.sqlite3session_create){
  1092. const __sqlite3SessionDelete = wasm.xWrap(
  1093. 'sqlite3session_delete', undefined, ['sqlite3_session*']
  1094. );
  1095. capi.sqlite3session_delete = function(pSession){
  1096. if(1!==arguments.length){
  1097. return __dbArgcMismatch(pDb, 'sqlite3session_delete', 1);
  1098. /* Yes, we're returning a value from a void function. That seems
  1099. like the lesser evil compared to not maintaining arg-count
  1100. consistency as we do with other similar bindings. */
  1101. }
  1102. else if(pSession){
  1103. //wasm.xWrap.FuncPtrAdapter.debugFuncInstall = true;
  1104. capi.sqlite3session_table_filter(pSession, 0, 0);
  1105. }
  1106. __sqlite3SessionDelete(pSession);
  1107. };
  1108. }
  1109. {/* Bindings for sqlite3_create_collation[_v2]() */
  1110. // contextKey() impl for wasm.xWrap.FuncPtrAdapter
  1111. const contextKey = (argv,argIndex)=>{
  1112. return 'argv['+argIndex+']:'+argv[0/* sqlite3* */]+
  1113. ':'+wasm.cstrToJs(argv[1/* collation name */]).toLowerCase()
  1114. };
  1115. const __sqlite3CreateCollationV2 = wasm.xWrap(
  1116. 'sqlite3_create_collation_v2', 'int', [
  1117. 'sqlite3*', 'string', 'int', '*',
  1118. new wasm.xWrap.FuncPtrAdapter({
  1119. /* int(*xCompare)(void*,int,const void*,int,const void*) */
  1120. name: 'xCompare', signature: 'i(pipip)', contextKey
  1121. }),
  1122. new wasm.xWrap.FuncPtrAdapter({
  1123. /* void(*xDestroy(void*) */
  1124. name: 'xDestroy', signature: 'v(p)', contextKey
  1125. })
  1126. ]
  1127. );
  1128. /**
  1129. Works exactly like C's sqlite3_create_collation_v2() except that:
  1130. 1) It returns capi.SQLITE_FORMAT if the 3rd argument contains
  1131. any encoding-related value other than capi.SQLITE_UTF8. No
  1132. other encodings are supported. As a special case, if the
  1133. bottom 4 bits of that argument are 0, SQLITE_UTF8 is
  1134. assumed.
  1135. 2) It accepts JS functions for its function-pointer arguments,
  1136. for which it will install WASM-bound proxies. The bindings
  1137. are "permanent," in that they will stay in the WASM environment
  1138. until it shuts down unless the client calls this again with the
  1139. same collation name and a value of 0 or null for the
  1140. the function pointer(s).
  1141. For consistency with the C API, it requires the same number of
  1142. arguments. It returns capi.SQLITE_MISUSE if passed any other
  1143. argument count.
  1144. Returns 0 on success, non-0 on error, in which case the error
  1145. state of pDb (of type `sqlite3*` or argument-convertible to it)
  1146. may contain more information.
  1147. */
  1148. capi.sqlite3_create_collation_v2 = function(pDb,zName,eTextRep,pArg,xCompare,xDestroy){
  1149. if(6!==arguments.length) return __dbArgcMismatch(pDb, 'sqlite3_create_collation_v2', 6);
  1150. else if( 0 === (eTextRep & 0xf) ){
  1151. eTextRep |= capi.SQLITE_UTF8;
  1152. }else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){
  1153. return __errEncoding(pDb);
  1154. }
  1155. try{
  1156. const rc = __sqlite3CreateCollationV2(pDb, zName, eTextRep, pArg, xCompare, xDestroy);
  1157. if(0===rc && xCompare instanceof Function){
  1158. __dbCleanupMap.addCollation(pDb, zName);
  1159. }
  1160. return rc;
  1161. }catch(e){
  1162. return util.sqlite3__wasm_db_error(pDb, e);
  1163. }
  1164. };
  1165. capi.sqlite3_create_collation = (pDb,zName,eTextRep,pArg,xCompare)=>{
  1166. return (5===arguments.length)
  1167. ? capi.sqlite3_create_collation_v2(pDb,zName,eTextRep,pArg,xCompare,0)
  1168. : __dbArgcMismatch(pDb, 'sqlite3_create_collation', 5);
  1169. };
  1170. }/*sqlite3_create_collation() and friends*/
  1171. {/* Special-case handling of sqlite3_create_function_v2()
  1172. and sqlite3_create_window_function(). */
  1173. /** FuncPtrAdapter for contextKey() for sqlite3_create_function()
  1174. and friends. */
  1175. const contextKey = function(argv,argIndex){
  1176. return (
  1177. argv[0/* sqlite3* */]
  1178. +':'+(argv[2/*number of UDF args*/] < 0 ? -1 : argv[2])
  1179. +':'+argIndex/*distinct for each xAbc callback type*/
  1180. +':'+wasm.cstrToJs(argv[1]).toLowerCase()
  1181. )
  1182. };
  1183. /**
  1184. JS proxies for the various sqlite3_create[_window]_function()
  1185. callbacks, structured in a form usable by wasm.xWrap.FuncPtrAdapter.
  1186. */
  1187. const __cfProxy = Object.assign(Object.create(null), {
  1188. xInverseAndStep: {
  1189. signature:'v(pip)', contextKey,
  1190. callProxy: (callback)=>{
  1191. return (pCtx, argc, pArgv)=>{
  1192. try{ callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv)) }
  1193. catch(e){ capi.sqlite3_result_error_js(pCtx, e) }
  1194. };
  1195. }
  1196. },
  1197. xFinalAndValue: {
  1198. signature:'v(p)', contextKey,
  1199. callProxy: (callback)=>{
  1200. return (pCtx)=>{
  1201. try{ capi.sqlite3_result_js(pCtx, callback(pCtx)) }
  1202. catch(e){ capi.sqlite3_result_error_js(pCtx, e) }
  1203. };
  1204. }
  1205. },
  1206. xFunc: {
  1207. signature:'v(pip)', contextKey,
  1208. callProxy: (callback)=>{
  1209. return (pCtx, argc, pArgv)=>{
  1210. try{
  1211. capi.sqlite3_result_js(
  1212. pCtx,
  1213. callback(pCtx, ...capi.sqlite3_values_to_js(argc, pArgv))
  1214. );
  1215. }catch(e){
  1216. //console.error('xFunc() caught:',e);
  1217. capi.sqlite3_result_error_js(pCtx, e);
  1218. }
  1219. };
  1220. }
  1221. },
  1222. xDestroy: {
  1223. signature:'v(p)', contextKey,
  1224. //Arguable: a well-behaved destructor doesn't require a proxy.
  1225. callProxy: (callback)=>{
  1226. return (pVoid)=>{
  1227. try{ callback(pVoid) }
  1228. catch(e){ console.error("UDF xDestroy method threw:",e) }
  1229. };
  1230. }
  1231. }
  1232. })/*__cfProxy*/;
  1233. const __sqlite3CreateFunction = wasm.xWrap(
  1234. "sqlite3_create_function_v2", "int", [
  1235. "sqlite3*", "string"/*funcName*/, "int"/*nArg*/,
  1236. "int"/*eTextRep*/, "*"/*pApp*/,
  1237. new wasm.xWrap.FuncPtrAdapter({name: 'xFunc', ...__cfProxy.xFunc}),
  1238. new wasm.xWrap.FuncPtrAdapter({name: 'xStep', ...__cfProxy.xInverseAndStep}),
  1239. new wasm.xWrap.FuncPtrAdapter({name: 'xFinal', ...__cfProxy.xFinalAndValue}),
  1240. new wasm.xWrap.FuncPtrAdapter({name: 'xDestroy', ...__cfProxy.xDestroy})
  1241. ]
  1242. );
  1243. const __sqlite3CreateWindowFunction =
  1244. wasm.exports.sqlite3_create_window_function
  1245. ? wasm.xWrap(
  1246. "sqlite3_create_window_function", "int", [
  1247. "sqlite3*", "string"/*funcName*/, "int"/*nArg*/,
  1248. "int"/*eTextRep*/, "*"/*pApp*/,
  1249. new wasm.xWrap.FuncPtrAdapter({name: 'xStep', ...__cfProxy.xInverseAndStep}),
  1250. new wasm.xWrap.FuncPtrAdapter({name: 'xFinal', ...__cfProxy.xFinalAndValue}),
  1251. new wasm.xWrap.FuncPtrAdapter({name: 'xValue', ...__cfProxy.xFinalAndValue}),
  1252. new wasm.xWrap.FuncPtrAdapter({name: 'xInverse', ...__cfProxy.xInverseAndStep}),
  1253. new wasm.xWrap.FuncPtrAdapter({name: 'xDestroy', ...__cfProxy.xDestroy})
  1254. ]
  1255. )
  1256. : undefined;
  1257. /* Documented in the api object's initializer. */
  1258. capi.sqlite3_create_function_v2 = function f(
  1259. pDb, funcName, nArg, eTextRep, pApp,
  1260. xFunc, //void (*xFunc)(sqlite3_context*,int,sqlite3_value**)
  1261. xStep, //void (*xStep)(sqlite3_context*,int,sqlite3_value**)
  1262. xFinal, //void (*xFinal)(sqlite3_context*)
  1263. xDestroy //void (*xDestroy)(void*)
  1264. ){
  1265. if( f.length!==arguments.length ){
  1266. return __dbArgcMismatch(pDb,"sqlite3_create_function_v2",f.length);
  1267. }else if( 0 === (eTextRep & 0xf) ){
  1268. eTextRep |= capi.SQLITE_UTF8;
  1269. }else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){
  1270. return __errEncoding(pDb);
  1271. }
  1272. try{
  1273. const rc = __sqlite3CreateFunction(pDb, funcName, nArg, eTextRep,
  1274. pApp, xFunc, xStep, xFinal, xDestroy);
  1275. if(0===rc && (xFunc instanceof Function
  1276. || xStep instanceof Function
  1277. || xFinal instanceof Function
  1278. || xDestroy instanceof Function)){
  1279. __dbCleanupMap.addFunction(pDb, funcName, nArg);
  1280. }
  1281. return rc;
  1282. }catch(e){
  1283. console.error("sqlite3_create_function_v2() setup threw:",e);
  1284. return util.sqlite3__wasm_db_error(pDb, e, "Creation of UDF threw: "+e);
  1285. }
  1286. };
  1287. /* Documented in the api object's initializer. */
  1288. capi.sqlite3_create_function = function f(
  1289. pDb, funcName, nArg, eTextRep, pApp,
  1290. xFunc, xStep, xFinal
  1291. ){
  1292. return (f.length===arguments.length)
  1293. ? capi.sqlite3_create_function_v2(pDb, funcName, nArg, eTextRep,
  1294. pApp, xFunc, xStep, xFinal, 0)
  1295. : __dbArgcMismatch(pDb,"sqlite3_create_function",f.length);
  1296. };
  1297. /* Documented in the api object's initializer. */
  1298. if( __sqlite3CreateWindowFunction ){
  1299. capi.sqlite3_create_window_function = function f(
  1300. pDb, funcName, nArg, eTextRep, pApp,
  1301. xStep, //void (*xStep)(sqlite3_context*,int,sqlite3_value**)
  1302. xFinal, //void (*xFinal)(sqlite3_context*)
  1303. xValue, //void (*xValue)(sqlite3_context*)
  1304. xInverse,//void (*xInverse)(sqlite3_context*,int,sqlite3_value**)
  1305. xDestroy //void (*xDestroy)(void*)
  1306. ){
  1307. if( f.length!==arguments.length ){
  1308. return __dbArgcMismatch(pDb,"sqlite3_create_window_function",f.length);
  1309. }else if( 0 === (eTextRep & 0xf) ){
  1310. eTextRep |= capi.SQLITE_UTF8;
  1311. }else if( capi.SQLITE_UTF8 !== (eTextRep & 0xf) ){
  1312. return __errEncoding(pDb);
  1313. }
  1314. try{
  1315. const rc = __sqlite3CreateWindowFunction(pDb, funcName, nArg, eTextRep,
  1316. pApp, xStep, xFinal, xValue,
  1317. xInverse, xDestroy);
  1318. if(0===rc && (xStep instanceof Function
  1319. || xFinal instanceof Function
  1320. || xValue instanceof Function
  1321. || xInverse instanceof Function
  1322. || xDestroy instanceof Function)){
  1323. __dbCleanupMap.addWindowFunc(pDb, funcName, nArg);
  1324. }
  1325. return rc;
  1326. }catch(e){
  1327. console.error("sqlite3_create_window_function() setup threw:",e);
  1328. return util.sqlite3__wasm_db_error(pDb, e, "Creation of UDF threw: "+e);
  1329. }
  1330. };
  1331. }else{
  1332. delete capi.sqlite3_create_window_function;
  1333. }
  1334. /**
  1335. A _deprecated_ alias for capi.sqlite3_result_js() which
  1336. predates the addition of that function in the public API.
  1337. */
  1338. capi.sqlite3_create_function_v2.udfSetResult =
  1339. capi.sqlite3_create_function.udfSetResult = capi.sqlite3_result_js;
  1340. if(capi.sqlite3_create_window_function){
  1341. capi.sqlite3_create_window_function.udfSetResult = capi.sqlite3_result_js;
  1342. }
  1343. /**
  1344. A _deprecated_ alias for capi.sqlite3_values_to_js() which
  1345. predates the addition of that function in the public API.
  1346. */
  1347. capi.sqlite3_create_function_v2.udfConvertArgs =
  1348. capi.sqlite3_create_function.udfConvertArgs = capi.sqlite3_values_to_js;
  1349. if(capi.sqlite3_create_window_function){
  1350. capi.sqlite3_create_window_function.udfConvertArgs = capi.sqlite3_values_to_js;
  1351. }
  1352. /**
  1353. A _deprecated_ alias for capi.sqlite3_result_error_js() which
  1354. predates the addition of that function in the public API.
  1355. */
  1356. capi.sqlite3_create_function_v2.udfSetError =
  1357. capi.sqlite3_create_function.udfSetError = capi.sqlite3_result_error_js;
  1358. if(capi.sqlite3_create_window_function){
  1359. capi.sqlite3_create_window_function.udfSetError = capi.sqlite3_result_error_js;
  1360. }
  1361. }/*sqlite3_create_function_v2() and sqlite3_create_window_function() proxies*/;
  1362. {/* Special-case handling of sqlite3_prepare_v2() and
  1363. sqlite3_prepare_v3() */
  1364. /**
  1365. Helper for string:flexible conversions which require a
  1366. byte-length counterpart argument. Passed a value and its
  1367. ostensible length, this function returns [V,N], where V is
  1368. either v or a transformed copy of v and N is either n, -1, or
  1369. the byte length of v (if it's a byte array or ArrayBuffer).
  1370. */
  1371. const __flexiString = (v,n)=>{
  1372. if('string'===typeof v){
  1373. n = -1;
  1374. }else if(util.isSQLableTypedArray(v)){
  1375. n = v.byteLength;
  1376. v = util.typedArrayToString(
  1377. (v instanceof ArrayBuffer) ? new Uint8Array(v) : v
  1378. );
  1379. }else if(Array.isArray(v)){
  1380. v = v.join("");
  1381. n = -1;
  1382. }
  1383. return [v, n];
  1384. };
  1385. /**
  1386. Scope-local holder of the two impls of sqlite3_prepare_v2/v3().
  1387. */
  1388. const __prepare = {
  1389. /**
  1390. This binding expects a JS string as its 2nd argument and
  1391. null as its final argument. In order to compile multiple
  1392. statements from a single string, the "full" impl (see
  1393. below) must be used.
  1394. */
  1395. basic: wasm.xWrap('sqlite3_prepare_v3',
  1396. "int", ["sqlite3*", "string",
  1397. "int"/*ignored for this impl!*/,
  1398. "int", "**",
  1399. "**"/*MUST be 0 or null or undefined!*/]),
  1400. /**
  1401. Impl which requires that the 2nd argument be a pointer
  1402. to the SQL string, instead of being converted to a
  1403. string. This variant is necessary for cases where we
  1404. require a non-NULL value for the final argument
  1405. (exec()'ing multiple statements from one input
  1406. string). For simpler cases, where only the first
  1407. statement in the SQL string is required, the wrapper
  1408. named sqlite3_prepare_v2() is sufficient and easier to
  1409. use because it doesn't require dealing with pointers.
  1410. */
  1411. full: wasm.xWrap('sqlite3_prepare_v3',
  1412. "int", ["sqlite3*", "*", "int", "int",
  1413. "**", "**"])
  1414. };
  1415. /* Documented in the capi object's initializer. */
  1416. capi.sqlite3_prepare_v3 = function f(pDb, sql, sqlLen, prepFlags, ppStmt, pzTail){
  1417. if(f.length!==arguments.length){
  1418. return __dbArgcMismatch(pDb,"sqlite3_prepare_v3",f.length);
  1419. }
  1420. const [xSql, xSqlLen] = __flexiString(sql, sqlLen);
  1421. switch(typeof xSql){
  1422. case 'string': return __prepare.basic(pDb, xSql, xSqlLen, prepFlags, ppStmt, null);
  1423. case 'number': return __prepare.full(pDb, xSql, xSqlLen, prepFlags, ppStmt, pzTail);
  1424. default:
  1425. return util.sqlite3__wasm_db_error(
  1426. pDb, capi.SQLITE_MISUSE,
  1427. "Invalid SQL argument type for sqlite3_prepare_v2/v3()."
  1428. );
  1429. }
  1430. };
  1431. /* Documented in the capi object's initializer. */
  1432. capi.sqlite3_prepare_v2 = function f(pDb, sql, sqlLen, ppStmt, pzTail){
  1433. return (f.length===arguments.length)
  1434. ? capi.sqlite3_prepare_v3(pDb, sql, sqlLen, 0, ppStmt, pzTail)
  1435. : __dbArgcMismatch(pDb,"sqlite3_prepare_v2",f.length);
  1436. };
  1437. }/*sqlite3_prepare_v2/v3()*/
  1438. {/*sqlite3_bind_text/blob()*/
  1439. const __bindText = wasm.xWrap("sqlite3_bind_text", "int", [
  1440. "sqlite3_stmt*", "int", "string", "int", "*"
  1441. ]);
  1442. const __bindBlob = wasm.xWrap("sqlite3_bind_blob", "int", [
  1443. "sqlite3_stmt*", "int", "*", "int", "*"
  1444. ]);
  1445. /** Documented in the capi object's initializer. */
  1446. capi.sqlite3_bind_text = function f(pStmt, iCol, text, nText, xDestroy){
  1447. if(f.length!==arguments.length){
  1448. return __dbArgcMismatch(capi.sqlite3_db_handle(pStmt),
  1449. "sqlite3_bind_text", f.length);
  1450. }else if(wasm.isPtr(text) || null===text){
  1451. return __bindText(pStmt, iCol, text, nText, xDestroy);
  1452. }else if(text instanceof ArrayBuffer){
  1453. text = new Uint8Array(text);
  1454. }else if(Array.isArray(pMem)){
  1455. text = pMem.join('');
  1456. }
  1457. let p, n;
  1458. try{
  1459. if(util.isSQLableTypedArray(text)){
  1460. p = wasm.allocFromTypedArray(text);
  1461. n = text.byteLength;
  1462. }else if('string'===typeof text){
  1463. [p, n] = wasm.allocCString(text);
  1464. }else{
  1465. return util.sqlite3__wasm_db_error(
  1466. capi.sqlite3_db_handle(pStmt), capi.SQLITE_MISUSE,
  1467. "Invalid 3rd argument type for sqlite3_bind_text()."
  1468. );
  1469. }
  1470. return __bindText(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC);
  1471. }catch(e){
  1472. wasm.dealloc(p);
  1473. return util.sqlite3__wasm_db_error(
  1474. capi.sqlite3_db_handle(pStmt), e
  1475. );
  1476. }
  1477. }/*sqlite3_bind_text()*/;
  1478. /** Documented in the capi object's initializer. */
  1479. capi.sqlite3_bind_blob = function f(pStmt, iCol, pMem, nMem, xDestroy){
  1480. if(f.length!==arguments.length){
  1481. return __dbArgcMismatch(capi.sqlite3_db_handle(pStmt),
  1482. "sqlite3_bind_blob", f.length);
  1483. }else if(wasm.isPtr(pMem) || null===pMem){
  1484. return __bindBlob(pStmt, iCol, pMem, nMem, xDestroy);
  1485. }else if(pMem instanceof ArrayBuffer){
  1486. pMem = new Uint8Array(pMem);
  1487. }else if(Array.isArray(pMem)){
  1488. pMem = pMem.join('');
  1489. }
  1490. let p, n;
  1491. try{
  1492. if(util.isBindableTypedArray(pMem)){
  1493. p = wasm.allocFromTypedArray(pMem);
  1494. n = nMem>=0 ? nMem : pMem.byteLength;
  1495. }else if('string'===typeof pMem){
  1496. [p, n] = wasm.allocCString(pMem);
  1497. }else{
  1498. return util.sqlite3__wasm_db_error(
  1499. capi.sqlite3_db_handle(pStmt), capi.SQLITE_MISUSE,
  1500. "Invalid 3rd argument type for sqlite3_bind_blob()."
  1501. );
  1502. }
  1503. return __bindBlob(pStmt, iCol, p, n, capi.SQLITE_WASM_DEALLOC);
  1504. }catch(e){
  1505. wasm.dealloc(p);
  1506. return util.sqlite3__wasm_db_error(
  1507. capi.sqlite3_db_handle(pStmt), e
  1508. );
  1509. }
  1510. }/*sqlite3_bind_blob()*/;
  1511. }/*sqlite3_bind_text/blob()*/
  1512. {/* sqlite3_config() */
  1513. /**
  1514. Wraps a small subset of the C API's sqlite3_config() options.
  1515. Unsupported options trigger the return of capi.SQLITE_NOTFOUND.
  1516. Passing fewer than 2 arguments triggers return of
  1517. capi.SQLITE_MISUSE.
  1518. */
  1519. capi.sqlite3_config = function(op, ...args){
  1520. if(arguments.length<2) return capi.SQLITE_MISUSE;
  1521. switch(op){
  1522. case capi.SQLITE_CONFIG_COVERING_INDEX_SCAN: // 20 /* int */
  1523. case capi.SQLITE_CONFIG_MEMSTATUS:// 9 /* boolean */
  1524. case capi.SQLITE_CONFIG_SMALL_MALLOC: // 27 /* boolean */
  1525. case capi.SQLITE_CONFIG_SORTERREF_SIZE: // 28 /* int nByte */
  1526. case capi.SQLITE_CONFIG_STMTJRNL_SPILL: // 26 /* int nByte */
  1527. case capi.SQLITE_CONFIG_URI:// 17 /* int */
  1528. return wasm.exports.sqlite3__wasm_config_i(op, args[0]);
  1529. case capi.SQLITE_CONFIG_LOOKASIDE: // 13 /* int int */
  1530. return wasm.exports.sqlite3__wasm_config_ii(op, args[0], args[1]);
  1531. case capi.SQLITE_CONFIG_MEMDB_MAXSIZE: // 29 /* sqlite3_int64 */
  1532. return wasm.exports.sqlite3__wasm_config_j(op, args[0]);
  1533. case capi.SQLITE_CONFIG_GETMALLOC: // 5 /* sqlite3_mem_methods* */
  1534. case capi.SQLITE_CONFIG_GETMUTEX: // 11 /* sqlite3_mutex_methods* */
  1535. case capi.SQLITE_CONFIG_GETPCACHE2: // 19 /* sqlite3_pcache_methods2* */
  1536. case capi.SQLITE_CONFIG_GETPCACHE: // 15 /* no-op */
  1537. case capi.SQLITE_CONFIG_HEAP: // 8 /* void*, int nByte, int min */
  1538. case capi.SQLITE_CONFIG_LOG: // 16 /* xFunc, void* */
  1539. case capi.SQLITE_CONFIG_MALLOC:// 4 /* sqlite3_mem_methods* */
  1540. case capi.SQLITE_CONFIG_MMAP_SIZE: // 22 /* sqlite3_int64, sqlite3_int64 */
  1541. case capi.SQLITE_CONFIG_MULTITHREAD: // 2 /* nil */
  1542. case capi.SQLITE_CONFIG_MUTEX: // 10 /* sqlite3_mutex_methods* */
  1543. case capi.SQLITE_CONFIG_PAGECACHE: // 7 /* void*, int sz, int N */
  1544. case capi.SQLITE_CONFIG_PCACHE2: // 18 /* sqlite3_pcache_methods2* */
  1545. case capi.SQLITE_CONFIG_PCACHE: // 14 /* no-op */
  1546. case capi.SQLITE_CONFIG_PCACHE_HDRSZ: // 24 /* int *psz */
  1547. case capi.SQLITE_CONFIG_PMASZ: // 25 /* unsigned int szPma */
  1548. case capi.SQLITE_CONFIG_SERIALIZED: // 3 /* nil */
  1549. case capi.SQLITE_CONFIG_SINGLETHREAD: // 1 /* nil */:
  1550. case capi.SQLITE_CONFIG_SQLLOG: // 21 /* xSqllog, void* */
  1551. case capi.SQLITE_CONFIG_WIN32_HEAPSIZE: // 23 /* int nByte */
  1552. default:
  1553. /* maintenance note: we specifically do not include
  1554. SQLITE_CONFIG_ROWID_IN_VIEW here, on the grounds that
  1555. it's only for legacy support and no apps written with
  1556. this API require that. */
  1557. return capi.SQLITE_NOTFOUND;
  1558. }
  1559. };
  1560. }/* sqlite3_config() */
  1561. {/*auto-extension bindings.*/
  1562. const __autoExtFptr = new Set;
  1563. capi.sqlite3_auto_extension = function(fPtr){
  1564. if( fPtr instanceof Function ){
  1565. fPtr = wasm.installFunction('i(ppp)', fPtr);
  1566. }else if( 1!==arguments.length || !wasm.isPtr(fPtr) ){
  1567. return capi.SQLITE_MISUSE;
  1568. }
  1569. const rc = wasm.exports.sqlite3_auto_extension(fPtr);
  1570. if( fPtr!==arguments[0] ){
  1571. if(0===rc) __autoExtFptr.add(fPtr);
  1572. else wasm.uninstallFunction(fPtr);
  1573. }
  1574. return rc;
  1575. };
  1576. capi.sqlite3_cancel_auto_extension = function(fPtr){
  1577. /* We do not do an automatic JS-to-WASM function conversion here
  1578. because it would be senseless: the converted pointer would
  1579. never possibly match an already-installed one. */;
  1580. if(!fPtr || 1!==arguments.length || !wasm.isPtr(fPtr)) return 0;
  1581. return wasm.exports.sqlite3_cancel_auto_extension(fPtr);
  1582. /* Note that it "cannot happen" that a client passes a pointer which
  1583. is in __autoExtFptr because __autoExtFptr only contains automatic
  1584. conversions created inside sqlite3_auto_extension() and
  1585. never exposed to the client. */
  1586. };
  1587. capi.sqlite3_reset_auto_extension = function(){
  1588. wasm.exports.sqlite3_reset_auto_extension();
  1589. for(const fp of __autoExtFptr) wasm.uninstallFunction(fp);
  1590. __autoExtFptr.clear();
  1591. };
  1592. }/* auto-extension */
  1593. const pKvvfs = capi.sqlite3_vfs_find("kvvfs");
  1594. if( pKvvfs ){/* kvvfs-specific glue */
  1595. if(util.isUIThread()){
  1596. const kvvfsMethods = new capi.sqlite3_kvvfs_methods(
  1597. wasm.exports.sqlite3__wasm_kvvfs_methods()
  1598. );
  1599. delete capi.sqlite3_kvvfs_methods;
  1600. const kvvfsMakeKey = wasm.exports.sqlite3__wasm_kvvfsMakeKeyOnPstack,
  1601. pstack = wasm.pstack;
  1602. const kvvfsStorage = (zClass)=>
  1603. ((115/*=='s'*/===wasm.peek(zClass))
  1604. ? sessionStorage : localStorage);
  1605. /**
  1606. Implementations for members of the object referred to by
  1607. sqlite3__wasm_kvvfs_methods(). We swap out the native
  1608. implementations with these, which use localStorage or
  1609. sessionStorage for their backing store.
  1610. */
  1611. const kvvfsImpls = {
  1612. xRead: (zClass, zKey, zBuf, nBuf)=>{
  1613. const stack = pstack.pointer,
  1614. astack = wasm.scopedAllocPush();
  1615. try {
  1616. const zXKey = kvvfsMakeKey(zClass,zKey);
  1617. if(!zXKey) return -3/*OOM*/;
  1618. const jKey = wasm.cstrToJs(zXKey);
  1619. const jV = kvvfsStorage(zClass).getItem(jKey);
  1620. if(!jV) return -1;
  1621. const nV = jV.length /* Note that we are relying 100% on v being
  1622. ASCII so that jV.length is equal to the
  1623. C-string's byte length. */;
  1624. if(nBuf<=0) return nV;
  1625. else if(1===nBuf){
  1626. wasm.poke(zBuf, 0);
  1627. return nV;
  1628. }
  1629. const zV = wasm.scopedAllocCString(jV);
  1630. if(nBuf > nV + 1) nBuf = nV + 1;
  1631. wasm.heap8u().copyWithin(zBuf, zV, zV + nBuf - 1);
  1632. wasm.poke(zBuf + nBuf - 1, 0);
  1633. return nBuf - 1;
  1634. }catch(e){
  1635. console.error("kvstorageRead()",e);
  1636. return -2;
  1637. }finally{
  1638. pstack.restore(stack);
  1639. wasm.scopedAllocPop(astack);
  1640. }
  1641. },
  1642. xWrite: (zClass, zKey, zData)=>{
  1643. const stack = pstack.pointer;
  1644. try {
  1645. const zXKey = kvvfsMakeKey(zClass,zKey);
  1646. if(!zXKey) return 1/*OOM*/;
  1647. const jKey = wasm.cstrToJs(zXKey);
  1648. kvvfsStorage(zClass).setItem(jKey, wasm.cstrToJs(zData));
  1649. return 0;
  1650. }catch(e){
  1651. console.error("kvstorageWrite()",e);
  1652. return capi.SQLITE_IOERR;
  1653. }finally{
  1654. pstack.restore(stack);
  1655. }
  1656. },
  1657. xDelete: (zClass, zKey)=>{
  1658. const stack = pstack.pointer;
  1659. try {
  1660. const zXKey = kvvfsMakeKey(zClass,zKey);
  1661. if(!zXKey) return 1/*OOM*/;
  1662. kvvfsStorage(zClass).removeItem(wasm.cstrToJs(zXKey));
  1663. return 0;
  1664. }catch(e){
  1665. console.error("kvstorageDelete()",e);
  1666. return capi.SQLITE_IOERR;
  1667. }finally{
  1668. pstack.restore(stack);
  1669. }
  1670. }
  1671. }/*kvvfsImpls*/;
  1672. for(const k of Object.keys(kvvfsImpls)){
  1673. kvvfsMethods[kvvfsMethods.memberKey(k)] =
  1674. wasm.installFunction(
  1675. kvvfsMethods.memberSignature(k),
  1676. kvvfsImpls[k]
  1677. );
  1678. }
  1679. }else{
  1680. /* Worker thread: unregister kvvfs to avoid it being used
  1681. for anything other than local/sessionStorage. It "can"
  1682. be used that way but it's not really intended to be. */
  1683. capi.sqlite3_vfs_unregister(pKvvfs);
  1684. }
  1685. }/*pKvvfs*/
  1686. /* Warn if client-level code makes use of FuncPtrAdapter. */
  1687. wasm.xWrap.FuncPtrAdapter.warnOnUse = true;
  1688. const StructBinder = sqlite3.StructBinder
  1689. /* we require a local alias b/c StructBinder is removed from the sqlite3
  1690. object during the final steps of the API cleanup. */;
  1691. /**
  1692. Installs a StructBinder-bound function pointer member of the
  1693. given name and function in the given StructBinder.StructType
  1694. target object.
  1695. It creates a WASM proxy for the given function and arranges for
  1696. that proxy to be cleaned up when tgt.dispose() is called. Throws
  1697. on the slightest hint of error, e.g. tgt is-not-a StructType,
  1698. name does not map to a struct-bound member, etc.
  1699. As a special case, if the given function is a pointer, then
  1700. `wasm.functionEntry()` is used to validate that it is a known
  1701. function. If so, it is used as-is with no extra level of proxying
  1702. or cleanup, else an exception is thrown. It is legal to pass a
  1703. value of 0, indicating a NULL pointer, with the caveat that 0
  1704. _is_ a legal function pointer in WASM but it will not be accepted
  1705. as such _here_. (Justification: the function at address zero must
  1706. be one which initially came from the WASM module, not a method we
  1707. want to bind to a virtual table or VFS.)
  1708. This function returns a proxy for itself which is bound to tgt
  1709. and takes 2 args (name,func). That function returns the same
  1710. thing as this one, permitting calls to be chained.
  1711. If called with only 1 arg, it has no side effects but returns a
  1712. func with the same signature as described above.
  1713. ACHTUNG: because we cannot generically know how to transform JS
  1714. exceptions into result codes, the installed functions do no
  1715. automatic catching of exceptions. It is critical, to avoid
  1716. undefined behavior in the C layer, that methods mapped via
  1717. this function do not throw. The exception, as it were, to that
  1718. rule is...
  1719. If applyArgcCheck is true then each JS function (as opposed to
  1720. function pointers) gets wrapped in a proxy which asserts that it
  1721. is passed the expected number of arguments, throwing if the
  1722. argument count does not match expectations. That is only intended
  1723. for dev-time usage for sanity checking, and may leave the C
  1724. environment in an undefined state.
  1725. */
  1726. const installMethod = function callee(
  1727. tgt, name, func, applyArgcCheck = callee.installMethodArgcCheck
  1728. ){
  1729. if(!(tgt instanceof StructBinder.StructType)){
  1730. toss("Usage error: target object is-not-a StructType.");
  1731. }else if(!(func instanceof Function) && !wasm.isPtr(func)){
  1732. toss("Usage errror: expecting a Function or WASM pointer to one.");
  1733. }
  1734. if(1===arguments.length){
  1735. return (n,f)=>callee(tgt, n, f, applyArgcCheck);
  1736. }
  1737. if(!callee.argcProxy){
  1738. callee.argcProxy = function(tgt, funcName, func,sig){
  1739. return function(...args){
  1740. if(func.length!==arguments.length){
  1741. toss("Argument mismatch for",
  1742. tgt.structInfo.name+"::"+funcName
  1743. +": Native signature is:",sig);
  1744. }
  1745. return func.apply(this, args);
  1746. }
  1747. };
  1748. /* An ondispose() callback for use with
  1749. StructBinder-created types. */
  1750. callee.removeFuncList = function(){
  1751. if(this.ondispose.__removeFuncList){
  1752. this.ondispose.__removeFuncList.forEach(
  1753. (v,ndx)=>{
  1754. if('number'===typeof v){
  1755. try{wasm.uninstallFunction(v)}
  1756. catch(e){/*ignore*/}
  1757. }
  1758. /* else it's a descriptive label for the next number in
  1759. the list. */
  1760. }
  1761. );
  1762. delete this.ondispose.__removeFuncList;
  1763. }
  1764. };
  1765. }/*static init*/
  1766. const sigN = tgt.memberSignature(name);
  1767. if(sigN.length<2){
  1768. toss("Member",name,"does not have a function pointer signature:",sigN);
  1769. }
  1770. const memKey = tgt.memberKey(name);
  1771. const fProxy = (applyArgcCheck && !wasm.isPtr(func))
  1772. /** This middle-man proxy is only for use during development, to
  1773. confirm that we always pass the proper number of
  1774. arguments. We know that the C-level code will always use the
  1775. correct argument count. */
  1776. ? callee.argcProxy(tgt, memKey, func, sigN)
  1777. : func;
  1778. if(wasm.isPtr(fProxy)){
  1779. if(fProxy && !wasm.functionEntry(fProxy)){
  1780. toss("Pointer",fProxy,"is not a WASM function table entry.");
  1781. }
  1782. tgt[memKey] = fProxy;
  1783. }else{
  1784. const pFunc = wasm.installFunction(fProxy, tgt.memberSignature(name, true));
  1785. tgt[memKey] = pFunc;
  1786. if(!tgt.ondispose || !tgt.ondispose.__removeFuncList){
  1787. tgt.addOnDispose('ondispose.__removeFuncList handler',
  1788. callee.removeFuncList);
  1789. tgt.ondispose.__removeFuncList = [];
  1790. }
  1791. tgt.ondispose.__removeFuncList.push(memKey, pFunc);
  1792. }
  1793. return (n,f)=>callee(tgt, n, f, applyArgcCheck);
  1794. }/*installMethod*/;
  1795. installMethod.installMethodArgcCheck = false;
  1796. /**
  1797. Installs methods into the given StructBinder.StructType-type
  1798. instance. Each entry in the given methods object must map to a
  1799. known member of the given StructType, else an exception will be
  1800. triggered. See installMethod() for more details, including the
  1801. semantics of the 3rd argument.
  1802. As an exception to the above, if any two or more methods in the
  1803. 2nd argument are the exact same function, installMethod() is
  1804. _not_ called for the 2nd and subsequent instances, and instead
  1805. those instances get assigned the same method pointer which is
  1806. created for the first instance. This optimization is primarily to
  1807. accommodate special handling of sqlite3_module::xConnect and
  1808. xCreate methods.
  1809. On success, returns its first argument. Throws on error.
  1810. */
  1811. const installMethods = function(
  1812. structInstance, methods, applyArgcCheck = installMethod.installMethodArgcCheck
  1813. ){
  1814. const seen = new Map /* map of <Function, memberName> */;
  1815. for(const k of Object.keys(methods)){
  1816. const m = methods[k];
  1817. const prior = seen.get(m);
  1818. if(prior){
  1819. const mkey = structInstance.memberKey(k);
  1820. structInstance[mkey] = structInstance[structInstance.memberKey(prior)];
  1821. }else{
  1822. installMethod(structInstance, k, m, applyArgcCheck);
  1823. seen.set(m, k);
  1824. }
  1825. }
  1826. return structInstance;
  1827. };
  1828. /**
  1829. Equivalent to calling installMethod(this,...arguments) with a
  1830. first argument of this object. If called with 1 or 2 arguments
  1831. and the first is an object, it's instead equivalent to calling
  1832. installMethods(this,...arguments).
  1833. */
  1834. StructBinder.StructType.prototype.installMethod = function callee(
  1835. name, func, applyArgcCheck = installMethod.installMethodArgcCheck
  1836. ){
  1837. return (arguments.length < 3 && name && 'object'===typeof name)
  1838. ? installMethods(this, ...arguments)
  1839. : installMethod(this, ...arguments);
  1840. };
  1841. /**
  1842. Equivalent to calling installMethods() with a first argument
  1843. of this object.
  1844. */
  1845. StructBinder.StructType.prototype.installMethods = function(
  1846. methods, applyArgcCheck = installMethod.installMethodArgcCheck
  1847. ){
  1848. return installMethods(this, methods, applyArgcCheck);
  1849. };
  1850. });