General internal cleanups in the oo1 API.

FossilOrigin-Name: f9db664f756f3707afcb5dce87f6d946625848f27ea84337af68de72d4ad6c6b
This commit is contained in:
stephan 2022-10-02 00:09:40 +00:00
parent f064a3bbe4
commit 193ee11fe1
5 changed files with 84 additions and 68 deletions

View File

@ -16,6 +16,7 @@
*/
self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
const toss = (...args)=>{throw new Error(args.join(' '))};
const toss3 = (...args)=>{throw new sqlite3.SQLite3Error(...args)};
const capi = sqlite3.capi, util = capi.util;
/* What follows is colloquially known as "OO API #1". It is a
@ -53,28 +54,11 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
const getOwnOption = (opts, p, dflt)=>
opts.hasOwnProperty(p) ? opts[p] : dflt;
/**
An Error subclass specifically for reporting DB-level errors and
enabling clients to unambiguously identify such exceptions.
*/
class SQLite3Error extends Error {
/**
Constructs this object with a message equal to all arguments
concatenated with a space between each one.
*/
constructor(...args){
super(args.join(' '));
this.name = 'SQLite3Error';
}
};
const toss3 = (...args)=>{throw new SQLite3Error(...args)};
sqlite3.SQLite3Error = SQLite3Error;
// Documented in DB.checkRc()
const checkSqlite3Rc = function(dbPtr, sqliteResultCode){
if(sqliteResultCode){
if(dbPtr instanceof DB) dbPtr = dbPtr.pointer;
throw new SQLite3Error(
toss3(
"sqlite result code",sqliteResultCode+":",
(dbPtr
? capi.sqlite3_errmsg(dbPtr)
@ -183,13 +167,14 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
If passed an object, any additional properties it has are copied
as-is into the new object.
*/
dbCtorHelper.normalizeArgs = function(filename,flags = 'c',vfs = null){
dbCtorHelper.normalizeArgs = function(filename=':memory:',flags = 'c',vfs = null){
const arg = {};
if(1===arguments.length && 'object'===typeof arguments[0]){
const x = arguments[0];
Object.keys(x).forEach((k)=>arg[k] = x[k]);
if(undefined===arg.flags) arg.flags = 'c';
if(undefined===arg.vfs) arg.vfs = null;
if(undefined===arg.filename) arg.filename = ':memory:';
}else{
arg.filename = filename;
arg.flags = flags;
@ -232,7 +217,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
The final argument is analogous to the final argument of
sqlite3_open_v2(): the name of an sqlite3 VFS. Pass a falsy value,
or not at all, to use the default. If passed a value, it must
or none at all, to use the default. If passed a value, it must
be the string name of a VFS
The constructor optionally (and preferably) takes its arguments
@ -554,15 +539,16 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
*/
prepare: function(sql){
affirmDbOpen(this);
if(Array.isArray(sql)) sql = sql.join('');
const stack = capi.wasm.scopedAllocPush();
const stack = capi.wasm.pstack.pointer;
let ppStmt, pStmt;
try{
ppStmt = capi.wasm.scopedAllocPtr()/* output (sqlite3_stmt**) arg */;
ppStmt = capi.wasm.pstack.alloc(8)/* output (sqlite3_stmt**) arg */;
DB.checkRc(this, capi.sqlite3_prepare_v2(this.pointer, sql, -1, ppStmt, null));
pStmt = capi.wasm.getPtrValue(ppStmt);
}
finally {capi.wasm.scopedAllocPop(stack)}
finally {
capi.wasm.pstack.restore(stack);
}
if(!pStmt) toss3("Cannot prepare empty SQL.");
const stmt = new Stmt(this, pStmt, BindTypes);
__stmtMap.get(this)[pStmt] = stmt;
@ -977,7 +963,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
SQLITE_{typename} constants. Passing the undefined value is
the same as not passing a value.
Throws on error (e.g. malformedSQL).
Throws on error (e.g. malformed SQL).
*/
selectValue: function(sql,bind,asType){
let stmt, rc;
@ -1157,7 +1143,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
}
}
};
}
}/* static init */
affirmSupportedBindType(val);
ndx = affirmParamIndex(stmt,ndx);
let rc = 0;
@ -1171,15 +1157,24 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
case BindTypes.number: {
let m;
if(util.isInt32(val)) m = capi.sqlite3_bind_int;
else if(capi.wasm.bigIntEnabled && ('bigint'===typeof val)){
else if('bigint'===typeof val){
if(val<f._minInt || val>f._maxInt){
toss3("BigInt value is out of range for int64: "+val);
toss3("BigInt value is out of range for storing as int64: "+val);
}else if(capi.wasm.bigIntEnabled){
m = capi.sqlite3_bind_int64;
}else if(val >= Number.MIN_SAFE_INTEGER && val <= Number.MAX_SAFE_INTEGER){
val = Number(val);
m = capi.sqlite3_bind_double;
}else{
toss3("BigInt value is out of range for storing as double: "+val);
}
}else{ // !int32, !bigint
val = Number(val);
if(capi.wasm.bigIntEnabled && Number.isInteger(val)){
m = capi.sqlite3_bind_int64;
}else{
m = capi.sqlite3_bind_double;
}
m = capi.sqlite3_bind_int64;
}else if(Number.isInteger(val)){
m = capi.sqlite3_bind_int64;
}else{
m = capi.sqlite3_bind_double;
}
rc = m(stmt.pointer, ndx, val);
break;
@ -1283,31 +1278,32 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
- null is bound as NULL.
- undefined as a standalone value is a no-op intended to
simplify certain client-side use cases: passing undefined
as a value to this function will not actually bind
anything and this function will skip confirmation that
binding is even legal. (Those semantics simplify certain
client-side uses.) Conversely, a value of undefined as an
array or object property when binding an array/object
(see below) is treated the same as null.
simplify certain client-side use cases: passing undefined as
a value to this function will not actually bind anything and
this function will skip confirmation that binding is even
legal. (Those semantics simplify certain client-side uses.)
Conversely, a value of undefined as an array or object
property when binding an array/object (see below) is treated
the same as null.
- Numbers are bound as either doubles or integers: doubles
if they are larger than 32 bits, else double or int32,
depending on whether they have a fractional part. (It is,
as of this writing, illegal to call (from JS) a WASM
function which either takes or returns an int64.)
Booleans are bound as integer 0 or 1. It is not expected
the distinction of binding doubles which have no
fractional parts is integers is significant for the
majority of clients due to sqlite3's data typing
model. If capi.wasm.bigIntEnabled is true then this
routine will bind BigInt values as 64-bit integers.
- Numbers are bound as either doubles or integers: doubles if
they are larger than 32 bits, else double or int32, depending
on whether they have a fractional part. Booleans are bound as
integer 0 or 1. It is not expected the distinction of binding
doubles which have no fractional parts is integers is
significant for the majority of clients due to sqlite3's data
typing model. If [BigInt] support is enabled then this
routine will bind BigInt values as 64-bit integers if they'll
fit in 64 bits. If that support disabled, it will store the
BigInt as an int32 or a double if it can do so without loss
of precision. If the BigInt is _too BigInt_ then it will
throw.
- Strings are bound as strings (use bindAsBlob() to force
blob binding).
blob binding).
- Uint8Array and Int8Array instances are bound as blobs.
(TODO: binding the other TypedArray types.)
(TODO: binding the other TypedArray types.)
If passed an array, each element of the array is bound at
the parameter index equal to the array index plus 1
@ -1458,7 +1454,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
This is intended to simplify use cases such as:
```
aDb.prepare("insert in foo(a) values(?)").bind(123).stepFinalize();
aDb.prepare("insert into foo(a) values(?)").bind(123).stepFinalize();
```
*/
stepFinalize: function(){
@ -1595,7 +1591,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
},
// Design note: the only reason most of these getters have a 'get'
// prefix is for consistency with getVALUE_TYPE(). The latter
// arguablly really need that prefix for API readability and the
// arguably really need that prefix for API readability and the
// rest arguably don't, but consistency is a powerful thing.
/**
Returns the result column name of the given index, or
@ -1616,9 +1612,8 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
cannot have result columns. This object's columnCount member
holds the number of columns.
*/
getColumnNames: function(tgt){
getColumnNames: function(tgt=[]){
affirmColIndex(affirmStmtOpen(this),0);
if(!tgt) tgt = [];
for(let i = 0; i < this.columnCount; ++i){
tgt.push(capi.sqlite3_column_name(this.pointer, i));
}

View File

@ -785,7 +785,9 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
be released using restore().
This method always adjusts the given value to be a multiple
of 8 in order to keep alignment guarantees.
of 8 bytes because failing to do so can lead to incorrect
results when reading and writing 64-bit values from/to the WASM
heap.
*/
alloc: capi.wasm.exports.sqlite3_wasm_pstack_alloc
});
@ -809,6 +811,24 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
get: capi.wasm.exports.sqlite3_wasm_pstack_remaining
});
/**
An Error subclass specifically for reporting DB-level errors and
enabling clients to unambiguously identify such exceptions.
The C-level APIs never throw, but some of the higher-level
C-style APIs do and the object-oriented APIs use exceptions
exclusively to report errors.
*/
class SQLite3Error extends Error {
/**
Constructs this object with a message equal to all arguments
concatenated with a space between each one.
*/
constructor(...args){
super(args.join(' '));
this.name = 'SQLite3Error';
}
};
/** State for sqlite3_wasmfs_opfs_dir(). */
let __persistentDir = undefined;
@ -1059,6 +1079,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
/* The remainder of the API will be set up in later steps. */
const sqlite3 = {
WasmAllocError: WasmAllocError,
SQLite3Error: SQLite3Error,
capi,
config,
/**

View File

@ -354,7 +354,7 @@
T.assert(g64(pMin) === minMaxI64[0]).
assert(minMaxI64[0] === db.selectValue("select ?",g64(pMin))).
assert(minMaxI64[1] === db.selectValue("select ?",g64(pMax)));
const rxRange = /out of range for int64/;
const rxRange = /out of range for storing as int64/;
T.mustThrowMatching(()=>{db.prepare("select ?").bind(minMaxI64[0] - BigInt(1))},
rxRange).
mustThrowMatching(()=>{db.prepare("select ?").bind(minMaxI64[1] + BigInt(1))},

View File

@ -1,5 +1,5 @@
C Correct\sfiddle\sdb\sexport\sbreakage\scaused\sby\sa\spost-testing\sAPI\schange\smade\sin\s[1fa019c88dea].
D 2022-10-01T19:21:52.215
C General\sinternal\scleanups\sin\sthe\soo1\sAPI.
D 2022-10-02T00:09:40.160
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -486,9 +486,9 @@ F ext/wasm/api/post-js-header.js 2e5c886398013ba2af88028ecbced1e4b22dc96a86467f1
F ext/wasm/api/pre-js.js 2db711eb637991b383fc6b5c0f3df65ec48a7201e5730e304beba8de2d3f9b0b
F ext/wasm/api/sqlite3-api-cleanup.js 5d22d1d3818ecacb23bfa223d5970cd0617d8cdbb48c8bc4bbd463f05b021a99
F ext/wasm/api/sqlite3-api-glue.js b15a51b88aaa472d36bf82d5123dbfdafe8ddf6ca75fba934510e4a20bbe4adb
F ext/wasm/api/sqlite3-api-oo1.js 9caed0757a5e039ed92467e827fd3ca347fa08f19fe086fcbdd14a4ebe9c2f01
F ext/wasm/api/sqlite3-api-oo1.js 7667d320f6b9fb5252050a2f9c0b1769e11b84dbc0763b999baf65b451b14369
F ext/wasm/api/sqlite3-api-opfs.js 1b097808b7b081b0f0700cf97d49ef19760e401706168edff9cd45cf9169f541
F ext/wasm/api/sqlite3-api-prologue.js 8692571345efc0f6844092e5ffa86cbd72af0fa23696599c04cc28d64c5d1d11
F ext/wasm/api/sqlite3-api-prologue.js a93bd69969eb8b8f9c4cb34e5d86dcbbe5adbeeea39c1cce57194256c5f28434
F ext/wasm/api/sqlite3-api-worker1.js 7f4f46cb6b512a48572d7567233896e6a9c46570c44bdc3d13419730c7c221c8
F ext/wasm/api/sqlite3-wasi.h 25356084cfe0d40458a902afb465df8c21fc4152c1d0a59b563a3fba59a068f9
F ext/wasm/api/sqlite3-wasm.c d72aecf0e50a4403402095ef4e8d6a814fdc2256589944c1dc974c70d2f65b7e
@ -530,7 +530,7 @@ F ext/wasm/test-opfs-vfs.js a59ff9210b17d46b0c6fbf6a0ba60143c033327865f2e556e14f
F ext/wasm/testing-worker1-promiser.html 6eaec6e04a56cf24cf4fa8ef49d78ce8905dde1354235c9125dca6885f7ce893
F ext/wasm/testing-worker1-promiser.js bd788e33c1807e0a6dda9c9a9d784bd3350ca49c9dd8ae2cc8719b506b6e013e
F ext/wasm/testing1.html 50575755e43232dbe4c2f97c9086b3118eb91ec2ee1fae931e6d7669fb17fcae
F ext/wasm/testing1.js 419e029ee4ae3cf98dd4c20aebdb111afe743b54ed8856e5f59775c3241fd21f
F ext/wasm/testing1.js 51ef1ced0669f804787ce96f19dcf64367550a7923a998514be56076326988d7
F ext/wasm/testing2.html a66951c38137ff1d687df79466351f3c734fa9c6d9cce71d3cf97c291b2167e3
F ext/wasm/testing2.js 88f40ef3cd8201bdadd120a711c36bbf0ce56cc0eab1d5e7debb71fed7822494
F ext/wasm/wasmfs.make 3cce1820006196de140f90f2da4b4ea657083fb5bfee7d125be43f7a85748c8f
@ -2029,8 +2029,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P c8a173cf16d2567bf9b13f52904077a2e7209776c76613c7bff59cd66e24bf11
R d4bf3165ea62de5a9f288d66d4a2cd95
P e73cc44ec36c7585ebb914bdeed5b39480fca7c7a8d3c4426bfe769c87b98d17
R 4b53a976c2062b810a77639258e8be02
U stephan
Z a03f054bd345e55a260c4a080b874912
Z f0b55570286779c7113ac4ef57233011
# Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
e73cc44ec36c7585ebb914bdeed5b39480fca7c7a8d3c4426bfe769c87b98d17
f9db664f756f3707afcb5dce87f6d946625848f27ea84337af68de72d4ad6c6b