mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
Add oo1.DB.exec() 'returnValue' option, which specifies what exec() should return. Defaults to the db object and enables direct return of the result rows array or a list of the individual SQL statements. Other code-adjacent internal cleanups.
FossilOrigin-Name: 69d36a6aa5e2cd79d26c0fd3e0d20fe8838fd1be97db07725233bfff1dfe6643
This commit is contained in:
@ -365,7 +365,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
current Stmt and returns the callback argument of the type
|
current Stmt and returns the callback argument of the type
|
||||||
indicated by the input arguments.
|
indicated by the input arguments.
|
||||||
*/
|
*/
|
||||||
const parseExecArgs = function(args){
|
const parseExecArgs = function(db, args){
|
||||||
const out = Object.create(null);
|
const out = Object.create(null);
|
||||||
out.opt = Object.create(null);
|
out.opt = Object.create(null);
|
||||||
switch(args.length){
|
switch(args.length){
|
||||||
@ -385,20 +385,34 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
break;
|
break;
|
||||||
default: toss3("Invalid argument count for exec().");
|
default: toss3("Invalid argument count for exec().");
|
||||||
};
|
};
|
||||||
if(util.isSQLableTypedArray(out.sql)){
|
out.sql = util.flexibleString(out.sql);
|
||||||
out.sql = util.typedArrayToString(out.sql);
|
if('string'!==typeof out.sql){
|
||||||
}else if(Array.isArray(out.sql)){
|
|
||||||
out.sql = out.sql.join('');
|
|
||||||
}else if('string'!==typeof out.sql){
|
|
||||||
toss3("Missing SQL argument or unsupported SQL value type.");
|
toss3("Missing SQL argument or unsupported SQL value type.");
|
||||||
}
|
}
|
||||||
if(out.opt.callback || out.opt.resultRows){
|
const opt = out.opt;
|
||||||
switch((undefined===out.opt.rowMode)
|
switch(opt.returnValue){
|
||||||
? 'array' : out.opt.rowMode) {
|
case 'resultRows':
|
||||||
|
if(!opt.resultRows) opt.resultRows = [];
|
||||||
|
out.returnVal = ()=>opt.resultRows;
|
||||||
|
break;
|
||||||
|
case 'saveSql':
|
||||||
|
if(!opt.saveSql) opt.saveSql = [];
|
||||||
|
out.returnVal = ()=>opt.saveSql;
|
||||||
|
break;
|
||||||
|
case undefined:
|
||||||
|
case 'this':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
toss3("Invalid returnValue value:",opt.returnValue);
|
||||||
|
}
|
||||||
|
if(!out.returnVal) out.returnVal = ()=>db;
|
||||||
|
if(opt.callback || opt.resultRows){
|
||||||
|
switch((undefined===opt.rowMode)
|
||||||
|
? 'array' : opt.rowMode) {
|
||||||
case 'object': out.cbArg = (stmt)=>stmt.get(Object.create(null)); break;
|
case 'object': out.cbArg = (stmt)=>stmt.get(Object.create(null)); break;
|
||||||
case 'array': out.cbArg = (stmt)=>stmt.get([]); break;
|
case 'array': out.cbArg = (stmt)=>stmt.get([]); break;
|
||||||
case 'stmt':
|
case 'stmt':
|
||||||
if(Array.isArray(out.opt.resultRows)){
|
if(Array.isArray(opt.resultRows)){
|
||||||
toss3("exec(): invalid rowMode for a resultRows array: must",
|
toss3("exec(): invalid rowMode for a resultRows array: must",
|
||||||
"be one of 'array', 'object',",
|
"be one of 'array', 'object',",
|
||||||
"a result column number, or column name reference.");
|
"a result column number, or column name reference.");
|
||||||
@ -406,32 +420,32 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
out.cbArg = (stmt)=>stmt;
|
out.cbArg = (stmt)=>stmt;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if(util.isInt32(out.opt.rowMode)){
|
if(util.isInt32(opt.rowMode)){
|
||||||
out.cbArg = (stmt)=>stmt.get(out.opt.rowMode);
|
out.cbArg = (stmt)=>stmt.get(opt.rowMode);
|
||||||
break;
|
break;
|
||||||
}else if('string'===typeof out.opt.rowMode && out.opt.rowMode.length>1){
|
}else if('string'===typeof opt.rowMode && opt.rowMode.length>1){
|
||||||
/* "$X", ":X", and "@X" fetch column named "X" (case-sensitive!) */
|
/* "$X", ":X", and "@X" fetch column named "X" (case-sensitive!) */
|
||||||
const prefix = out.opt.rowMode[0];
|
const prefix = opt.rowMode[0];
|
||||||
if(':'===prefix || '@'===prefix || '$'===prefix){
|
if(':'===prefix || '@'===prefix || '$'===prefix){
|
||||||
out.cbArg = function(stmt){
|
out.cbArg = function(stmt){
|
||||||
const rc = stmt.get(this.obj)[this.colName];
|
const rc = stmt.get(this.obj)[this.colName];
|
||||||
return (undefined===rc) ? toss3("exec(): unknown result column:",this.colName) : rc;
|
return (undefined===rc) ? toss3("exec(): unknown result column:",this.colName) : rc;
|
||||||
}.bind({
|
}.bind({
|
||||||
obj:Object.create(null),
|
obj:Object.create(null),
|
||||||
colName: out.opt.rowMode.substr(1)
|
colName: opt.rowMode.substr(1)
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
toss3("Invalid rowMode:",out.opt.rowMode);
|
toss3("Invalid rowMode:",opt.rowMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Internal impl of the DB.selectRowArray() and
|
Internal impl of the DB.selectArray() and
|
||||||
selectRowObject() methods.
|
selectObject() methods.
|
||||||
*/
|
*/
|
||||||
const __selectFirstRow = (db, sql, bind, getArg)=>{
|
const __selectFirstRow = (db, sql, bind, getArg)=>{
|
||||||
let stmt, rc;
|
let stmt, rc;
|
||||||
@ -588,9 +602,10 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
/**
|
/**
|
||||||
Executes one or more SQL statements in the form of a single
|
Executes one or more SQL statements in the form of a single
|
||||||
string. Its arguments must be either (sql,optionsObject) or
|
string. Its arguments must be either (sql,optionsObject) or
|
||||||
(optionsObject). In the latter case, optionsObject.sql
|
(optionsObject). In the latter case, optionsObject.sql must
|
||||||
must contain the SQL to execute. Returns this
|
contain the SQL to execute. By default it returns this object
|
||||||
object. Throws on error.
|
but that can be changed via the `returnValue` option as
|
||||||
|
described below. Throws on error.
|
||||||
|
|
||||||
If no SQL is provided, or a non-string is provided, an
|
If no SQL is provided, or a non-string is provided, an
|
||||||
exception is triggered. Empty SQL, on the other hand, is
|
exception is triggered. Empty SQL, on the other hand, is
|
||||||
@ -599,21 +614,25 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
The optional options object may contain any of the following
|
The optional options object may contain any of the following
|
||||||
properties:
|
properties:
|
||||||
|
|
||||||
- `.sql` = the SQL to run (unless it's provided as the first
|
- `sql` = the SQL to run (unless it's provided as the first
|
||||||
argument). This must be of type string, Uint8Array, or an array
|
argument). This must be of type string, Uint8Array, or an array
|
||||||
of strings. In the latter case they're concatenated together
|
of strings. In the latter case they're concatenated together
|
||||||
as-is, _with no separator_ between elements, before evaluation.
|
as-is, _with no separator_ between elements, before evaluation.
|
||||||
The array form is often simpler for long hand-written queries.
|
The array form is often simpler for long hand-written queries.
|
||||||
|
|
||||||
- `.bind` = a single value valid as an argument for
|
- `bind` = a single value valid as an argument for
|
||||||
Stmt.bind(). This is _only_ applied to the _first_ non-empty
|
Stmt.bind(). This is _only_ applied to the _first_ non-empty
|
||||||
statement in the SQL which has any bindable parameters. (Empty
|
statement in the SQL which has any bindable parameters. (Empty
|
||||||
statements are skipped entirely.)
|
statements are skipped entirely.)
|
||||||
|
|
||||||
- `.saveSql` = an optional array. If set, the SQL of each
|
- `saveSql` = an optional array. If set, the SQL of each
|
||||||
executed statement is appended to this array before the
|
executed statement is appended to this array before the
|
||||||
statement is executed (but after it is prepared - we don't have
|
statement is executed (but after it is prepared - we don't have
|
||||||
the string until after that). Empty SQL statements are elided.
|
the string until after that). Empty SQL statements are elided
|
||||||
|
but can have odd effects in the output. e.g. SQL of: `"select
|
||||||
|
1; -- empty\n; select 2"` will result in an array containing
|
||||||
|
`["select 1;", "--empty \n; select 2"]`. That's simply how
|
||||||
|
sqlite3 records the SQL for the 2nd statement.
|
||||||
|
|
||||||
==================================================================
|
==================================================================
|
||||||
The following options apply _only_ to the _first_ statement
|
The following options apply _only_ to the _first_ statement
|
||||||
@ -621,14 +640,14 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
the statement actually produces any result rows.
|
the statement actually produces any result rows.
|
||||||
==================================================================
|
==================================================================
|
||||||
|
|
||||||
- `.columnNames`: if this is an array, the column names of the
|
- `columnNames`: if this is an array, the column names of the
|
||||||
result set are stored in this array before the callback (if
|
result set are stored in this array before the callback (if
|
||||||
any) is triggered (regardless of whether the query produces any
|
any) is triggered (regardless of whether the query produces any
|
||||||
result rows). If no statement has result columns, this value is
|
result rows). If no statement has result columns, this value is
|
||||||
unchanged. Achtung: an SQL result may have multiple columns
|
unchanged. Achtung: an SQL result may have multiple columns
|
||||||
with identical names.
|
with identical names.
|
||||||
|
|
||||||
- `.callback` = a function which gets called for each row of
|
- `callback` = a function which gets called for each row of
|
||||||
the result set, but only if that statement has any result
|
the result set, but only if that statement has any result
|
||||||
_rows_. The callback's "this" is the options object, noting
|
_rows_. The callback's "this" is the options object, noting
|
||||||
that this function synthesizes one if the caller does not pass
|
that this function synthesizes one if the caller does not pass
|
||||||
@ -647,7 +666,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
The first argument passed to the callback defaults to an array of
|
The first argument passed to the callback defaults to an array of
|
||||||
values from the current result row but may be changed with ...
|
values from the current result row but may be changed with ...
|
||||||
|
|
||||||
- `.rowMode` = specifies the type of he callback's first argument.
|
- `rowMode` = specifies the type of he callback's first argument.
|
||||||
It may be any of...
|
It may be any of...
|
||||||
|
|
||||||
A) A string describing what type of argument should be passed
|
A) A string describing what type of argument should be passed
|
||||||
@ -655,7 +674,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
|
|
||||||
A.1) `'array'` (the default) causes the results of
|
A.1) `'array'` (the default) causes the results of
|
||||||
`stmt.get([])` to be passed to the `callback` and/or appended
|
`stmt.get([])` to be passed to the `callback` and/or appended
|
||||||
to `resultRows`.
|
to `resultRows`
|
||||||
|
|
||||||
A.2) `'object'` causes the results of
|
A.2) `'object'` causes the results of
|
||||||
`stmt.get(Object.create(null))` to be passed to the
|
`stmt.get(Object.create(null))` to be passed to the
|
||||||
@ -687,7 +706,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
|
|
||||||
Any other `rowMode` value triggers an exception.
|
Any other `rowMode` value triggers an exception.
|
||||||
|
|
||||||
- `.resultRows`: if this is an array, it functions similarly to
|
- `resultRows`: if this is an array, it functions similarly to
|
||||||
the `callback` option: each row of the result set (if any),
|
the `callback` option: each row of the result set (if any),
|
||||||
with the exception that the `rowMode` 'stmt' is not legal. It
|
with the exception that the `rowMode` 'stmt' is not legal. It
|
||||||
is legal to use both `resultRows` and `callback`, but
|
is legal to use both `resultRows` and `callback`, but
|
||||||
@ -695,28 +714,44 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
and can be used over a WebWorker-style message interface.
|
and can be used over a WebWorker-style message interface.
|
||||||
exec() throws if `resultRows` is set and `rowMode` is 'stmt'.
|
exec() throws if `resultRows` is set and `rowMode` is 'stmt'.
|
||||||
|
|
||||||
|
- `returnValue`: is a string specifying what this function
|
||||||
|
should return:
|
||||||
|
|
||||||
|
A) The default value is `"this"`, meaning that the
|
||||||
|
DB object itself should be returned.
|
||||||
|
|
||||||
|
B) `"resultRows"` means to return the value of the
|
||||||
|
`resultRows` option. If `resultRows` is not set, this
|
||||||
|
function behaves as if it were set to an empty array.
|
||||||
|
|
||||||
|
C) `"saveSql"` means to return the value of the
|
||||||
|
`saveSql` option. If `saveSql` is not set, this
|
||||||
|
function behaves as if it were set to an empty array.
|
||||||
|
|
||||||
Potential TODOs:
|
Potential TODOs:
|
||||||
|
|
||||||
- `.bind`: permit an array of arrays/objects to bind. The first
|
- `bind`: permit an array of arrays/objects to bind. The first
|
||||||
sub-array would act on the first statement which has bindable
|
sub-array would act on the first statement which has bindable
|
||||||
parameters (as it does now). The 2nd would act on the next such
|
parameters (as it does now). The 2nd would act on the next such
|
||||||
statement, etc.
|
statement, etc.
|
||||||
|
|
||||||
- `.callback` and `.resultRows`: permit an array entries with
|
- `callback` and `resultRows`: permit an array entries with
|
||||||
semantics similar to those described for `.bind` above.
|
semantics similar to those described for `bind` above.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
exec: function(/*(sql [,obj]) || (obj)*/){
|
exec: function(/*(sql [,obj]) || (obj)*/){
|
||||||
affirmDbOpen(this);
|
affirmDbOpen(this);
|
||||||
const arg = parseExecArgs(arguments);
|
const arg = parseExecArgs(this, arguments);
|
||||||
if(!arg.sql){
|
if(!arg.sql){
|
||||||
return (''===arg.sql) ? this : toss3("exec() requires an SQL string.");
|
return (''===arg.sql) ? this : toss3("exec() requires an SQL string.");
|
||||||
}
|
}
|
||||||
const opt = arg.opt;
|
const opt = arg.opt;
|
||||||
const callback = opt.callback;
|
const callback = opt.callback;
|
||||||
let resultRows = (Array.isArray(opt.resultRows)
|
const returnValue = opt.returnValue || 'this';
|
||||||
? opt.resultRows : undefined);
|
const resultRows = (Array.isArray(opt.resultRows)
|
||||||
|
? opt.resultRows : (
|
||||||
|
'resultRows'===returnValue ? [] : undefined
|
||||||
|
));
|
||||||
let stmt;
|
let stmt;
|
||||||
let bind = opt.bind;
|
let bind = opt.bind;
|
||||||
let evalFirstResult = !!(arg.cbArg || opt.columnNames) /* true to evaluate the first result-returning query */;
|
let evalFirstResult = !!(arg.cbArg || opt.columnNames) /* true to evaluate the first result-returning query */;
|
||||||
@ -774,7 +809,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
stmt._isLocked = true;
|
stmt._isLocked = true;
|
||||||
const row = arg.cbArg(stmt);
|
const row = arg.cbArg(stmt);
|
||||||
if(resultRows) resultRows.push(row);
|
if(resultRows) resultRows.push(row);
|
||||||
if(callback) callback.apply(opt,[row,stmt]);
|
if(callback) callback.call(opt, row, stmt);
|
||||||
stmt._isLocked = false;
|
stmt._isLocked = false;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
@ -793,7 +828,7 @@ self.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
|||||||
}
|
}
|
||||||
wasm.scopedAllocPop(stack);
|
wasm.scopedAllocPop(stack);
|
||||||
}
|
}
|
||||||
return this;
|
return arg.returnVal();
|
||||||
}/*exec()*/,
|
}/*exec()*/,
|
||||||
/**
|
/**
|
||||||
Creates a new scalar UDF (User-Defined Function) which is
|
Creates a new scalar UDF (User-Defined Function) which is
|
||||||
|
@ -162,12 +162,64 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/** Throws a new Error, the message of which is the concatenation
|
/**
|
||||||
all args with a space between each. */
|
An Error subclass specifically for reporting DB-level errors and
|
||||||
const toss = (...args)=>{throw new Error(args.join(' '))};
|
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. As a special case,
|
||||||
|
if it's passed only a single integer argument, the string form
|
||||||
|
of that argument is the result of
|
||||||
|
sqlite3.capi.sqlite3_js_rc_str() or (if that returns falsy), a
|
||||||
|
synthesized string which contains that integer.
|
||||||
|
*/
|
||||||
|
constructor(...args){
|
||||||
|
if(1===args.length && 'number'===typeof args[0] && args[0]===(args[0] | 0)){
|
||||||
|
super((capi.sqlite3_js_rc_str && capi.sqlite3_js_rc_str(args[0]))
|
||||||
|
|| ("Unknown result code #"+args[0]));
|
||||||
|
}else{
|
||||||
|
super(args.join(' '));
|
||||||
|
}
|
||||||
|
this.name = 'SQLite3Error';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
The main sqlite3 binding API gets installed into this object,
|
||||||
|
mimicking the C API as closely as we can. The numerous members
|
||||||
|
names with prefixes 'sqlite3_' and 'SQLITE_' behave, insofar as
|
||||||
|
possible, identically to the C-native counterparts, as documented at:
|
||||||
|
|
||||||
|
https://www.sqlite.org/c3ref/intro.html
|
||||||
|
|
||||||
|
A very few exceptions require an additional level of proxy
|
||||||
|
function or may otherwise require special attention in the WASM
|
||||||
|
environment, and all such cases are document here. Those not
|
||||||
|
documented otherwise are installed as 1-to-1 proxies for their
|
||||||
|
C-side counterparts.
|
||||||
|
*/
|
||||||
|
const capi = Object.create(null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Functionally equivalent to the SQLite3Error constructor but may
|
||||||
|
be used as part of an expression, e.g.:
|
||||||
|
|
||||||
|
```
|
||||||
|
return someFunction(x) || SQLite3Error.toss(...);
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
SQLite3Error.toss = (...args)=>{
|
||||||
|
throw new SQLite3Error(...args);
|
||||||
|
};
|
||||||
|
const toss3 = SQLite3Error.toss;
|
||||||
|
|
||||||
if(config.wasmfsOpfsDir && !/^\/[^/]+$/.test(config.wasmfsOpfsDir)){
|
if(config.wasmfsOpfsDir && !/^\/[^/]+$/.test(config.wasmfsOpfsDir)){
|
||||||
toss("config.wasmfsOpfsDir must be falsy or in the form '/dir-name'.");
|
toss3("config.wasmfsOpfsDir must be falsy or in the form '/dir-name'.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -267,7 +319,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
|||||||
that v is not a supported TypedArray value. */
|
that v is not a supported TypedArray value. */
|
||||||
const affirmBindableTypedArray = (v)=>{
|
const affirmBindableTypedArray = (v)=>{
|
||||||
return isBindableTypedArray(v)
|
return isBindableTypedArray(v)
|
||||||
|| toss("Value is not of a supported TypedArray type.");
|
|| toss3("Value is not of a supported TypedArray type.");
|
||||||
};
|
};
|
||||||
|
|
||||||
const utf8Decoder = new TextDecoder('utf-8');
|
const utf8Decoder = new TextDecoder('utf-8');
|
||||||
@ -318,21 +370,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
|||||||
throw new WasmAllocError(...args);
|
throw new WasmAllocError(...args);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
Object.assign(capi, {
|
||||||
The main sqlite3 binding API gets installed into this object,
|
|
||||||
mimicking the C API as closely as we can. The numerous members
|
|
||||||
names with prefixes 'sqlite3_' and 'SQLITE_' behave, insofar as
|
|
||||||
possible, identically to the C-native counterparts, as documented at:
|
|
||||||
|
|
||||||
https://www.sqlite.org/c3ref/intro.html
|
|
||||||
|
|
||||||
A very few exceptions require an additional level of proxy
|
|
||||||
function or may otherwise require special attention in the WASM
|
|
||||||
environment, and all such cases are document here. Those not
|
|
||||||
documented here are installed as 1-to-1 proxies for their C-side
|
|
||||||
counterparts.
|
|
||||||
*/
|
|
||||||
const capi = {
|
|
||||||
/**
|
/**
|
||||||
sqlite3_create_function_v2() differs from its native
|
sqlite3_create_function_v2() differs from its native
|
||||||
counterpart only in the following ways:
|
counterpart only in the following ways:
|
||||||
@ -557,7 +595,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
|||||||
values.
|
values.
|
||||||
*/
|
*/
|
||||||
sqlite3_randomness: (n, outPtr)=>{/*installed later*/},
|
sqlite3_randomness: (n, outPtr)=>{/*installed later*/},
|
||||||
}/*capi*/;
|
}/*capi*/);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Various internal-use utilities are added here as needed. They
|
Various internal-use utilities are added here as needed. They
|
||||||
@ -617,7 +655,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
|||||||
The symbols exported by the WASM environment.
|
The symbols exported by the WASM environment.
|
||||||
*/
|
*/
|
||||||
exports: config.exports
|
exports: config.exports
|
||||||
|| toss("Missing API config.exports (WASM module exports)."),
|
|| toss3("Missing API config.exports (WASM module exports)."),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
When Emscripten compiles with `-sIMPORT_MEMORY`, it
|
When Emscripten compiles with `-sIMPORT_MEMORY`, it
|
||||||
@ -626,7 +664,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
|||||||
available via this.exports.memory.
|
available via this.exports.memory.
|
||||||
*/
|
*/
|
||||||
memory: config.memory || config.exports['memory']
|
memory: config.memory || config.exports['memory']
|
||||||
|| toss("API config object requires a WebAssembly.Memory object",
|
|| toss3("API config object requires a WebAssembly.Memory object",
|
||||||
"in either config.exports.memory (exported)",
|
"in either config.exports.memory (exported)",
|
||||||
"or config.memory (imported)."),
|
"or config.memory (imported)."),
|
||||||
|
|
||||||
@ -688,7 +726,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
|||||||
keyDealloc = config.deallocExportName || 'free';
|
keyDealloc = config.deallocExportName || 'free';
|
||||||
for(const key of [keyAlloc, keyDealloc]){
|
for(const key of [keyAlloc, keyDealloc]){
|
||||||
const f = wasm.exports[key];
|
const f = wasm.exports[key];
|
||||||
if(!(f instanceof Function)) toss("Missing required exports[",key,"] function.");
|
if(!(f instanceof Function)) toss3("Missing required exports[",key,"] function.");
|
||||||
}
|
}
|
||||||
|
|
||||||
wasm.alloc = function(n){
|
wasm.alloc = function(n){
|
||||||
@ -1057,43 +1095,6 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
|||||||
}
|
}
|
||||||
})/*wasm.pstack properties*/;
|
})/*wasm.pstack properties*/;
|
||||||
|
|
||||||
/**
|
|
||||||
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. As a special case,
|
|
||||||
if it's passed only a single integer argument, the string form
|
|
||||||
of that argument is the result of
|
|
||||||
sqlite3.capi.sqlite3_js_rc_str() or (if that returns falsy), a
|
|
||||||
synthesized string which contains that integer.
|
|
||||||
*/
|
|
||||||
constructor(...args){
|
|
||||||
if(1===args.length && 'number'===typeof args[0] && args[0]===(args[0] | 0)){
|
|
||||||
super(capi.sqlite3_js_rc_str(args[0]) || ("Unknown result code #"+args[0]));
|
|
||||||
}else{
|
|
||||||
super(args.join(' '));
|
|
||||||
}
|
|
||||||
this.name = 'SQLite3Error';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
Functionally equivalent to the SQLite3Error constructor but may
|
|
||||||
be used as part of an expression, e.g.:
|
|
||||||
|
|
||||||
```
|
|
||||||
return someFunction(x) || SQLite3Error.toss(...);
|
|
||||||
```
|
|
||||||
*/
|
|
||||||
SQLite3Error.toss = (...args)=>{
|
|
||||||
throw new SQLite3Error(...args);
|
|
||||||
};
|
|
||||||
|
|
||||||
capi.sqlite3_randomness = (...args)=>{
|
capi.sqlite3_randomness = (...args)=>{
|
||||||
if(1===args.length && util.isTypedArray(args[0])
|
if(1===args.length && util.isTypedArray(args[0])
|
||||||
&& 1===args[0].BYTES_PER_ELEMENT){
|
&& 1===args[0].BYTES_PER_ELEMENT){
|
||||||
@ -1245,8 +1246,8 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
|||||||
error it throws with a description of the problem.
|
error it throws with a description of the problem.
|
||||||
*/
|
*/
|
||||||
capi.sqlite3_js_db_export = function(pDb){
|
capi.sqlite3_js_db_export = function(pDb){
|
||||||
if(!pDb) toss('Invalid sqlite3* argument.');
|
if(!pDb) toss3('Invalid sqlite3* argument.');
|
||||||
if(!wasm.bigIntEnabled) toss('BigInt64 support is not enabled.');
|
if(!wasm.bigIntEnabled) toss3('BigInt64 support is not enabled.');
|
||||||
const stack = wasm.pstack.pointer;
|
const stack = wasm.pstack.pointer;
|
||||||
let pOut;
|
let pOut;
|
||||||
try{
|
try{
|
||||||
@ -1263,7 +1264,7 @@ self.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
|||||||
pDb, ppOut, pSize, 0
|
pDb, ppOut, pSize, 0
|
||||||
);
|
);
|
||||||
if(rc){
|
if(rc){
|
||||||
toss("Database serialization failed with code",
|
toss3("Database serialization failed with code",
|
||||||
sqlite3.capi.sqlite3_js_rc_str(rc));
|
sqlite3.capi.sqlite3_js_rc_str(rc));
|
||||||
}
|
}
|
||||||
pOut = wasm.getPtrValue(ppOut);
|
pOut = wasm.getPtrValue(ppOut);
|
||||||
|
@ -1220,8 +1220,9 @@
|
|||||||
.t('Table t', function(sqlite3){
|
.t('Table t', function(sqlite3){
|
||||||
const db = this.db;
|
const db = this.db;
|
||||||
let list = [];
|
let list = [];
|
||||||
db.exec({
|
let rc = db.exec({
|
||||||
sql:['CREATE TABLE t(a,b);',
|
sql:['CREATE TABLE t(a,b);',
|
||||||
|
// ^^^ using TEMP TABLE breaks the db export test
|
||||||
"INSERT INTO t(a,b) VALUES(1,2),(3,4),",
|
"INSERT INTO t(a,b) VALUES(1,2),(3,4),",
|
||||||
"(?,?),('blob',X'6869')"/*intentionally missing semicolon to test for
|
"(?,?),('blob',X'6869')"/*intentionally missing semicolon to test for
|
||||||
off-by-one bug in string-to-WASM conversion*/],
|
off-by-one bug in string-to-WASM conversion*/],
|
||||||
@ -1229,7 +1230,8 @@
|
|||||||
bind: [5,6]
|
bind: [5,6]
|
||||||
});
|
});
|
||||||
//debug("Exec'd SQL:", list);
|
//debug("Exec'd SQL:", list);
|
||||||
T.assert(2 === list.length)
|
T.assert(rc === db)
|
||||||
|
.assert(2 === list.length)
|
||||||
.assert('string'===typeof list[1])
|
.assert('string'===typeof list[1])
|
||||||
.assert(4===db.changes());
|
.assert(4===db.changes());
|
||||||
if(wasm.bigIntEnabled){
|
if(wasm.bigIntEnabled){
|
||||||
@ -1502,30 +1504,61 @@
|
|||||||
xValue: xValueFinal
|
xValue: xValueFinal
|
||||||
});
|
});
|
||||||
db.exec([
|
db.exec([
|
||||||
"CREATE TABLE twin(x, y); INSERT INTO twin VALUES",
|
"CREATE TEMP TABLE twin(x, y); INSERT INTO twin VALUES",
|
||||||
"('a', 4),('b', 5),('c', 3),('d', 8),('e', 1)"
|
"('a', 4),('b', 5),('c', 3),('d', 8),('e', 1)"
|
||||||
]);
|
]);
|
||||||
let count = 0;
|
let rc = db.exec({
|
||||||
db.exec({
|
returnValue: 'resultRows',
|
||||||
sql:[
|
sql:[
|
||||||
"SELECT x, winsumint(y) OVER (",
|
"SELECT x, winsumint(y) OVER (",
|
||||||
"ORDER BY x ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING",
|
"ORDER BY x ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING",
|
||||||
") AS sum_y ",
|
") AS sum_y ",
|
||||||
"FROM twin ORDER BY x;",
|
"FROM twin ORDER BY x;"
|
||||||
"DROP TABLE twin;"
|
]
|
||||||
],
|
|
||||||
callback: function(row){
|
|
||||||
switch(++count){
|
|
||||||
case 1: T.assert('a'===row[0] && 9===row[1]); break;
|
|
||||||
case 2: T.assert('b'===row[0] && 12===row[1]); break;
|
|
||||||
case 3: T.assert('c'===row[0] && 16===row[1]); break;
|
|
||||||
case 4: T.assert('d'===row[0] && 12===row[1]); break;
|
|
||||||
case 5: T.assert('e'===row[0] && 9===row[1]); break;
|
|
||||||
default: toss("Too many rows to window function.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
T.assert(5 === count);
|
T.assert(Array.isArray(rc))
|
||||||
|
.assert(5 === rc.length);
|
||||||
|
let count = 0;
|
||||||
|
for(const row of rc){
|
||||||
|
switch(++count){
|
||||||
|
case 1: T.assert('a'===row[0] && 9===row[1]); break;
|
||||||
|
case 2: T.assert('b'===row[0] && 12===row[1]); break;
|
||||||
|
case 3: T.assert('c'===row[0] && 16===row[1]); break;
|
||||||
|
case 4: T.assert('d'===row[0] && 12===row[1]); break;
|
||||||
|
case 5: T.assert('e'===row[0] && 9===row[1]); break;
|
||||||
|
default: toss("Too many rows to window function.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const resultRows = [];
|
||||||
|
rc = db.exec({
|
||||||
|
resultRows,
|
||||||
|
returnValue: 'resultRows',
|
||||||
|
sql:[
|
||||||
|
"SELECT x, winsumint(y) OVER (",
|
||||||
|
"ORDER BY x ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING",
|
||||||
|
") AS sum_y ",
|
||||||
|
"FROM twin ORDER BY x;"
|
||||||
|
]
|
||||||
|
});
|
||||||
|
T.assert(rc === resultRows)
|
||||||
|
.assert(5 === rc.length);
|
||||||
|
|
||||||
|
rc = db.exec({
|
||||||
|
returnValue: 'saveSql',
|
||||||
|
sql: "select 1; select 2; -- empty\n; select 3"
|
||||||
|
});
|
||||||
|
T.assert(Array.isArray(rc))
|
||||||
|
.assert(3===rc.length)
|
||||||
|
.assert('select 1;' === rc[0])
|
||||||
|
.assert('select 2;' === rc[1])
|
||||||
|
.assert('-- empty\n; select 3' === rc[2]
|
||||||
|
/* Strange but true. */);
|
||||||
|
|
||||||
|
T.mustThrowMatching(()=>{
|
||||||
|
db.exec({sql:'', returnValue: 'nope'});
|
||||||
|
}, /^Invalid returnValue/);
|
||||||
|
|
||||||
|
db.exec("DROP TABLE twin");
|
||||||
}
|
}
|
||||||
}/*window UDFs*/)
|
}/*window UDFs*/)
|
||||||
|
|
||||||
@ -1536,7 +1569,7 @@
|
|||||||
db.exec({
|
db.exec({
|
||||||
sql:new TextEncoder('utf-8').encode([
|
sql:new TextEncoder('utf-8').encode([
|
||||||
// ^^^ testing string-vs-typedarray handling in exec()
|
// ^^^ testing string-vs-typedarray handling in exec()
|
||||||
"attach 'session' as foo;" /* name 'session' is magic for kvvfs! */,
|
"attach 'session' as foo;",
|
||||||
"create table foo.bar(a);",
|
"create table foo.bar(a);",
|
||||||
"insert into foo.bar(a) values(1),(2),(3);",
|
"insert into foo.bar(a) values(1),(2),(3);",
|
||||||
"select a from foo.bar order by a;"
|
"select a from foo.bar order by a;"
|
||||||
@ -1665,27 +1698,24 @@
|
|||||||
;/* end of oo1 checks */
|
;/* end of oo1 checks */
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
T.g('kvvfs (Worker thread only)', isWorker)
|
T.g('kvvfs')
|
||||||
.t({
|
.t('kvvfs sanity checks', function(sqlite3){
|
||||||
name: 'kvvfs is disabled',
|
if(isWorker()){
|
||||||
test: ()=>{
|
|
||||||
T.assert(
|
T.assert(
|
||||||
!capi.sqlite3_vfs_find('kvvfs'),
|
!capi.sqlite3_vfs_find('kvvfs'),
|
||||||
"Expecting kvvfs to be unregistered."
|
"Expecting kvvfs to be unregistered."
|
||||||
);
|
);
|
||||||
|
log("kvvfs is (correctly) unavailable in a Worker.");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
});
|
const filename = 'session';
|
||||||
T.g('kvvfs (UI thread only)', isUIThread)
|
const pVfs = capi.sqlite3_vfs_find('kvvfs');
|
||||||
.t({
|
T.assert(pVfs);
|
||||||
name: 'kvvfs sanity checks',
|
const JDb = sqlite3.oo1.JsStorageDb;
|
||||||
test: function(sqlite3){
|
const unlink = ()=>JDb.clearStorage(filename);
|
||||||
const filename = 'session';
|
unlink();
|
||||||
const pVfs = capi.sqlite3_vfs_find('kvvfs');
|
let db = new JDb(filename);
|
||||||
T.assert(pVfs);
|
try {
|
||||||
const JDb = sqlite3.oo1.JsStorageDb;
|
|
||||||
const unlink = ()=>JDb.clearStorage(filename);
|
|
||||||
unlink();
|
|
||||||
let db = new JDb(filename);
|
|
||||||
db.exec([
|
db.exec([
|
||||||
'create table kvvfs(a);',
|
'create table kvvfs(a);',
|
||||||
'insert into kvvfs(a) values(1),(2),(3)'
|
'insert into kvvfs(a) values(1),(2),(3)'
|
||||||
@ -1695,6 +1725,7 @@
|
|||||||
db = new JDb(filename);
|
db = new JDb(filename);
|
||||||
db.exec('insert into kvvfs(a) values(4),(5),(6)');
|
db.exec('insert into kvvfs(a) values(4),(5),(6)');
|
||||||
T.assert(6 === db.selectValue('select count(*) from kvvfs'));
|
T.assert(6 === db.selectValue('select count(*) from kvvfs'));
|
||||||
|
}finally{
|
||||||
db.close();
|
db.close();
|
||||||
unlink();
|
unlink();
|
||||||
}
|
}
|
||||||
@ -1713,17 +1744,20 @@
|
|||||||
const unlink = (fn=filename)=>wasm.sqlite3_wasm_vfs_unlink(pVfs,fn);
|
const unlink = (fn=filename)=>wasm.sqlite3_wasm_vfs_unlink(pVfs,fn);
|
||||||
unlink();
|
unlink();
|
||||||
let db = new sqlite3.opfs.OpfsDb(filename);
|
let db = new sqlite3.opfs.OpfsDb(filename);
|
||||||
db.exec([
|
try {
|
||||||
'create table p(a);',
|
db.exec([
|
||||||
'insert into p(a) values(1),(2),(3)'
|
'create table p(a);',
|
||||||
]);
|
'insert into p(a) values(1),(2),(3)'
|
||||||
T.assert(3 === db.selectValue('select count(*) from p'));
|
]);
|
||||||
db.close();
|
T.assert(3 === db.selectValue('select count(*) from p'));
|
||||||
db = new sqlite3.opfs.OpfsDb(filename);
|
db.close();
|
||||||
db.exec('insert into p(a) values(4),(5),(6)');
|
db = new sqlite3.opfs.OpfsDb(filename);
|
||||||
T.assert(6 === db.selectValue('select count(*) from p'));
|
db.exec('insert into p(a) values(4),(5),(6)');
|
||||||
db.close();
|
T.assert(6 === db.selectValue('select count(*) from p'));
|
||||||
unlink();
|
}finally{
|
||||||
|
db.close();
|
||||||
|
unlink();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}/*OPFS sanity checks*/)
|
}/*OPFS sanity checks*/)
|
||||||
;/* end OPFS tests */
|
;/* end OPFS tests */
|
||||||
|
18
manifest
18
manifest
@ -1,5 +1,5 @@
|
|||||||
C Avoid\sa\ssegfault\sthat\scould\soccur\swhen\srunning\sthe\srecover\sAPI\son\sa\sdatabase\shandle\swith\smemory-mapping\senabled.
|
C Add\soo1.DB.exec()\s'returnValue'\soption,\swhich\sspecifies\swhat\sexec()\sshould\sreturn.\sDefaults\sto\sthe\sdb\sobject\sand\senables\sdirect\sreturn\sof\sthe\sresult\srows\sarray\sor\sa\slist\sof\sthe\sindividual\sSQL\sstatements.\sOther\scode-adjacent\sinternal\scleanups.
|
||||||
D 2022-10-31T10:53:23.735
|
D 2022-10-31T11:09:14.111
|
||||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||||
@ -500,9 +500,9 @@ F ext/wasm/api/post-js-header.js d6ab3dfef4a06960d28a7eaa338d4e2a1a5981e9b387181
|
|||||||
F ext/wasm/api/pre-js.js 287e462f969342b032c03900e668099fa1471d852df7a472de5bc349161d9c04
|
F ext/wasm/api/pre-js.js 287e462f969342b032c03900e668099fa1471d852df7a472de5bc349161d9c04
|
||||||
F ext/wasm/api/sqlite3-api-cleanup.js ecdc69dbfccfe26146f04799fcfd4a6f5790d46e7e3b9b6e9b0491f92ed8ae34
|
F ext/wasm/api/sqlite3-api-cleanup.js ecdc69dbfccfe26146f04799fcfd4a6f5790d46e7e3b9b6e9b0491f92ed8ae34
|
||||||
F ext/wasm/api/sqlite3-api-glue.js b87543534821ecfa56fc0d0cd153a115fa974e70d6217964baf6e93ef8d25fb1
|
F ext/wasm/api/sqlite3-api-glue.js b87543534821ecfa56fc0d0cd153a115fa974e70d6217964baf6e93ef8d25fb1
|
||||||
F ext/wasm/api/sqlite3-api-oo1.js a17e2624967073f86cc50f4c1e30f8822ef631dc20dfc73b1143847b9e9723fe
|
F ext/wasm/api/sqlite3-api-oo1.js 4028bc2bac7e3ae2d23b7c99828155b4a06da006b51dc2a929bc0db26337370d
|
||||||
F ext/wasm/api/sqlite3-api-opfs.js c67cbe0b1451ec43bc6b3199e13453e1ca56d718a75c0498253b0d479c336256
|
F ext/wasm/api/sqlite3-api-opfs.js c67cbe0b1451ec43bc6b3199e13453e1ca56d718a75c0498253b0d479c336256
|
||||||
F ext/wasm/api/sqlite3-api-prologue.js a218dda5e5ced8894f65760131371e4cabd31062af58803af8952cc00ea778d2
|
F ext/wasm/api/sqlite3-api-prologue.js 873986ca150c79510f647b910f8349bc71b14db21e444cab3b9fad9c4f39ffc7
|
||||||
F ext/wasm/api/sqlite3-api-worker1.js efdca1b42299d80b54f366d15a8fc5343f3b3e9e3647e5c1fd6f3ee1015e501b
|
F ext/wasm/api/sqlite3-api-worker1.js efdca1b42299d80b54f366d15a8fc5343f3b3e9e3647e5c1fd6f3ee1015e501b
|
||||||
F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3
|
F ext/wasm/api/sqlite3-license-version-header.js a661182fc93fc2cf212dfd0b987f8e138a3ac98f850b1112e29b5fbdaecc87c3
|
||||||
F ext/wasm/api/sqlite3-opfs-async-proxy.js 29f6f5c314c2956e77573c6ab975c2455a0839721ed44f38004382c2a1463ab5
|
F ext/wasm/api/sqlite3-opfs-async-proxy.js 29f6f5c314c2956e77573c6ab975c2455a0839721ed44f38004382c2a1463ab5
|
||||||
@ -549,7 +549,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555
|
|||||||
F ext/wasm/test-opfs-vfs.js 48fc59110e8775bb43c9be25b6d634fc07ebadab7da8fbd44889e8129c6e2548
|
F ext/wasm/test-opfs-vfs.js 48fc59110e8775bb43c9be25b6d634fc07ebadab7da8fbd44889e8129c6e2548
|
||||||
F ext/wasm/tester1-worker.html d02b9d38876b023854cf8955e77a40912f7e516956b4dbe1ec7f215faac273ee
|
F ext/wasm/tester1-worker.html d02b9d38876b023854cf8955e77a40912f7e516956b4dbe1ec7f215faac273ee
|
||||||
F ext/wasm/tester1.html c6c47e5a8071eb09cb1301104435c8e44fbb5719c92411f5b2384a461f9793c5
|
F ext/wasm/tester1.html c6c47e5a8071eb09cb1301104435c8e44fbb5719c92411f5b2384a461f9793c5
|
||||||
F ext/wasm/tester1.js 08ccc16972562ff604b7bda387b56d6eea380aaf968697fc8e2a9bb3c6ba2dda
|
F ext/wasm/tester1.js 2427ac48e255f658ad81163b5dc6372a8609ab6ab60e295e371d1e5fe9a495ab
|
||||||
F ext/wasm/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd72273503ae7d5
|
F ext/wasm/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd72273503ae7d5
|
||||||
F ext/wasm/wasmfs.make fb2d3c4a298b12cf1ec994ad1d0f1d027ae297449b364cde43d2eb807d68048f
|
F ext/wasm/wasmfs.make fb2d3c4a298b12cf1ec994ad1d0f1d027ae297449b364cde43d2eb807d68048f
|
||||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||||
@ -2054,8 +2054,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P cb12ac5de17e677f089d7b0b46803efbd9a9178972ffb0454a8b557b06633658
|
P e02c697281a777c33070168af784b2d291397e488244a217620897f40aed7158
|
||||||
R 46019e96ebee7f43e27063daa1a45bd1
|
R 26339704ab975fcc1e6818338a87c2a1
|
||||||
U dan
|
U stephan
|
||||||
Z 31c01b86489219dc9c143f294c0c509f
|
Z 2aa3561d4216c084633673f53cc5adc1
|
||||||
# Remove this line to create a well-formed Fossil manifest.
|
# Remove this line to create a well-formed Fossil manifest.
|
||||||
|
@ -1 +1 @@
|
|||||||
e02c697281a777c33070168af784b2d291397e488244a217620897f40aed7158
|
69d36a6aa5e2cd79d26c0fd3e0d20fe8838fd1be97db07725233bfff1dfe6643
|
Reference in New Issue
Block a user