1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-27 20:41:58 +03:00

JS SQLTestRunner can now run the Java impl's core-most sanity tests, missing only support for directives.

FossilOrigin-Name: 5e798369375ce1b0c9cdf831f835d931fbd562ff7b4db09a06d1bdca2ac1b975
This commit is contained in:
stephan
2023-08-29 20:01:01 +00:00
parent 69a55ca17d
commit aa15047796
7 changed files with 503 additions and 79 deletions

View File

@ -181,7 +181,7 @@ public class SQLTester {
private int nTestFile = 0;
//! Number of scripts which were aborted.
private int nAbortedScript = 0;
//! Per-script test counter.
//! Incremented by test case handlers
private int nTest = 0;
//! True to enable column name output from execSql()
private boolean emitColNames;
@ -582,6 +582,10 @@ public class SQLTester {
}
}
}finally{
sqlite3_reset(stmt
/* In order to trigger an exception in the
INSERT...RETURNING locking scenario:
https://sqlite.org/forum/forumpost/36f7a2e7494897df */);
sqlite3_finalize(stmt);
}
if( 0!=rc && throwOnError ){
@ -926,8 +930,8 @@ class RunCommand extends Command {
final sqlite3 db = (1==argv.length)
? t.getCurrentDb() : t.getDbById( Integer.parseInt(argv[1]) );
final String sql = t.takeInputBuffer();
int rc = t.execSql(db, false, ResultBufferMode.NONE,
ResultRowMode.ONELINE, sql);
final int rc = t.execSql(db, false, ResultBufferMode.NONE,
ResultRowMode.ONELINE, sql);
if( 0!=rc && t.isVerbose() ){
String msg = sqlite3_errmsg(db);
ts.verbose1(argv[0]," non-fatal command error #",rc,": ",
@ -950,8 +954,7 @@ class TableResultCommand extends Command {
if( !body.endsWith("\n--end") ){
ts.toss(argv[0], " must be terminated with --end.");
}else{
int n = body.length();
body = body.substring(0, n-6);
body = body.substring(0, body.length()-6);
}
final String[] globs = body.split("\\s*\\n\\s*");
if( globs.length < 1 ){
@ -1240,14 +1243,15 @@ class TestScript {
final int oldPB = cur.putbackPos;
final int oldPBL = cur.putbackLineNo;
final int oldLine = cur.lineNo;
final String rc = getLine();
cur.peekedPos = cur.pos;
cur.peekedLineNo = cur.lineNo;
cur.pos = oldPos;
cur.lineNo = oldLine;
cur.putbackPos = oldPB;
cur.putbackLineNo = oldPBL;
return rc;
try{ return getLine(); }
finally{
cur.peekedPos = cur.pos;
cur.peekedLineNo = cur.lineNo;
cur.pos = oldPos;
cur.lineNo = oldLine;
cur.putbackPos = oldPB;
cur.putbackLineNo = oldPBL;
}
}
/**
@ -1374,11 +1378,10 @@ class TestScript {
String line;
while( (null != (line = peekLine())) ){
checkForDirective(tester, line);
if( !isCommandLine(line, true) ){
if( isCommandLine(line, true) ) break;
else {
sb.append(line).append("\n");
consumePeeked();
}else{
break;
}
}
line = sb.toString();

View File

@ -73,7 +73,7 @@ class DbException extends SQLTesterException {
class TestScriptFailed extends SQLTesterException {
constructor(testScript, ...args){
super(testScript.getPutputPrefix(),': ',...args);
super(testScript.getOutputPrefix(),': ',...args);
}
isFatal() { return true; }
}
@ -103,6 +103,18 @@ const __utf8Encoder = new TextEncoder('utf-8');
const __SAB = ('undefined'===typeof globalThis.SharedArrayBuffer)
? function(){} : globalThis.SharedArrayBuffer;
const Rx = newObj({
requiredProperties: / REQUIRED_PROPERTIES:[ \t]*(\S.*)\s*$/,
scriptModuleName: / SCRIPT_MODULE_NAME:[ \t]*(\S+)\s*$/,
mixedModuleName: / ((MIXED_)?MODULE_NAME):[ \t]*(\S+)\s*$/,
command: /^--(([a-z-]+)( .*)?)$/,
//! "Special" characters - we have to escape output if it contains any.
special: /[\x00-\x20\x22\x5c\x7b\x7d]/,
//! Either of '{' or '}'.
squiggly: /[{}]/
});
const Util = newObj({
toss,
@ -110,7 +122,11 @@ const Util = newObj({
return 0==sqlite3.wasm.sqlite3_wasm_vfs_unlink(0,fn);
},
argvToString: (list)=>list.join(" "),
argvToString: (list)=>{
const m = [...list];
m.shift();
return m.join(" ")
},
utf8Decode: function(arrayBuffer, begin, end){
return __utf8Decoder.decode(
@ -120,7 +136,10 @@ const Util = newObj({
);
},
utf8Encode: (str)=>__utf8Encoder.encode(str)
utf8Encode: (str)=>__utf8Encoder.encode(str),
strglob: sqlite3.wasm.xWrap('sqlite3_wasm_SQLTester_strglob','int',
['string','string'])
})/*Util*/;
class Outer {
@ -182,21 +201,39 @@ class Outer {
class SQLTester {
//! Console output utility.
#outer = new Outer().outputPrefix( ()=>'SQLTester: ' );
//! List of input script files.
#aFiles = [];
//! Test input buffer.
#inputBuffer = [];
//! Test result buffer.
#resultBuffer = [];
//! Output representation of SQL NULL.
#nullView = "nil";
#metrics = newObj({
nTotalTest: 0, nTestFile: 0, nAbortedScript: 0
metrics = newObj({
//! Total tests run
nTotalTest: 0,
//! Total test script files run
nTestFile: 0,
//! Number of scripts which were aborted
nAbortedScript: 0,
//! Incremented by test case handlers
nTest: 0
});
#emitColNames = false;
//! True to keep going regardless of how a test fails.
#keepGoing = false;
#db = newObj({
//! The list of available db handles.
list: new Array(7),
//! Index into this.list of the current db.
iCurrentDb: 0,
//! Name of the default db, re-created for each script.
initialDbName: "test.db",
//! Buffer for REQUIRED_PROPERTIES pragmas.
initSql: ['select 1;'],
//! (sqlite3*) to the current db.
currentDb: function(){
return this.list[this.iCurrentDb];
}
@ -208,12 +245,17 @@ class SQLTester {
outln(...args){ return this.#outer.outln(...args); }
out(...args){ return this.#outer.out(...args); }
incrementTestCounter(){
++this.metrics.nTotalTest;
++this.metrics.nTest;
}
reset(){
this.clearInputBuffer();
this.clearResultBuffer();
this.#clearBuffer(this.#db.initSql);
this.closeAllDbs();
this.nTest = 0;
this.metrics.nTest = 0;
this.nullView = "nil";
this.emitColNames = false;
this.#db.iCurrentDb = 0;
@ -365,7 +407,7 @@ class SQLTester {
Util.unlink(this.#db.initialDbName);
this.openDb(0, this.#db.initialDbName, true);
}else{
this.#outer.outln("WARNING: setupInitialDb() unexpectedly ",
this.#outer.outln("WARNING: setupInitialDb() was unexpectedly ",
"triggered while it is opened.");
}
}
@ -405,17 +447,107 @@ class SQLTester {
#appendDbErr(pDb, sb, rc){
sb.push(sqlite3.capi.sqlite3_js_rc_str(rc), ' ');
const msg = this.#escapeSqlValue(sqlite3.capi.sqlite3_errmsg(pDb));
if( '{' == msg.charAt(0) ){
if( '{' === msg.charAt(0) ){
sb.push(msg);
}else{
sb.push('{', msg, '}');
}
}
#checkDbRc(pDb,rc){
sqlite3.oo1.DB.checkRc(pDb, rc);
}
execSql(pDb, throwOnError, appendMode, lineMode, sql){
sql = sqlite3.capi.sqlite3_js_sql_to_string(sql);
this.#outer.outln("execSql() is TODO. ",sql);
return 0;
if( !pDb && !this.#db.list[0] ){
this.#setupInitialDb();
}
if( !pDb ) pDb = this.#db.currentDb();
const wasm = sqlite3.wasm, capi = sqlite3.capi;
sql = (sql instanceof Uint8Array)
? sql
: new TextEncoder("utf-8").encode(capi.sqlite3_js_sql_to_string(sql));
const self = this;
const sb = (ResultBufferMode.NONE===appendMode) ? null : this.#resultBuffer;
let rc = 0;
wasm.scopedAllocCall(function(){
let sqlByteLen = sql.byteLength;
const ppStmt = wasm.scopedAlloc(
/* output (sqlite3_stmt**) arg and pzTail */
(2 * wasm.ptrSizeof) + (sqlByteLen + 1/* SQL + NUL */)
);
const pzTail = ppStmt + wasm.ptrSizeof /* final arg to sqlite3_prepare_v2() */;
let pSql = pzTail + wasm.ptrSizeof;
const pSqlEnd = pSql + sqlByteLen;
wasm.heap8().set(sql, pSql);
wasm.poke8(pSql + sqlByteLen, 0/*NUL terminator*/);
let pos = 0, n = 1, spacing = 0;
while( pSql && wasm.peek8(pSql) ){
wasm.pokePtr([ppStmt, pzTail], 0);
rc = capi.sqlite3_prepare_v3(
pDb, pSql, sqlByteLen, 0, ppStmt, pzTail
);
if( 0!==rc ){
if(throwOnError){
throw new DbException(pDb, rc);
}else if( sb ){
self.#appendDbErr(db, sb, rc);
}
break;
}
const pStmt = wasm.peekPtr(ppStmt);
pSql = wasm.peekPtr(pzTail);
sqlByteLen = pSqlEnd - pSql;
if(!pStmt) continue /* only whitespace or comments */;
if( sb ){
const nCol = capi.sqlite3_column_count(pStmt);
let colName, val;
while( capi.SQLITE_ROW === (rc = capi.sqlite3_step(pStmt)) ) {
for( let i=0; i < nCol; ++i ){
if( spacing++ > 0 ) sb.push(' ');
if( self.#emitColNames ){
colName = capi.sqlite3_column_name(pStmt, i);
switch(appendMode){
case ResultBufferMode.ASIS: sb.push( colName ); break;
case ResultBufferMode.ESCAPED:
sb.push( self.#escapeSqlValue(colName) );
break;
default:
self.toss("Unhandled ResultBufferMode.");
}
sb.push(' ');
}
val = capi.sqlite3_column_text(pStmt, i);
if( null===val ){
sb.push( self.#nullView );
continue;
}
switch(appendMode){
case ResultBufferMode.ASIS: sb.push( val ); break;
case ResultBufferMode.ESCAPED:
sb.push( self.#escapeSqlValue(val) );
break;
}
}/* column loop */
}/* row loop */
if( ResultRowMode.NEWLINE === lineMode ){
spacing = 0;
sb.push('\n');
}
}else{ // no output but possibly other side effects
while( capi.SQLITE_ROW === (rc = capi.sqlite3_step(pStmt)) ) {}
}
capi.sqlite3_finalize(pStmt);
if( capi.SQLITE_ROW===rc || capi.SQLITE_DONE===rc) rc = 0;
else if( rc!=0 ){
if( sb ){
self.#appendDbErr(db, sb, rc);
}
break;
}
}/* SQL script loop */;
})/*scopedAllocCall()*/;
return rc;
}
}/*SQLTester*/
@ -469,17 +601,6 @@ class Cursor {
}
}
const Rx = newObj({
requiredProperties: / REQUIRED_PROPERTIES:[ \t]*(\S.*)\s*$/,
scriptModuleName: / SCRIPT_MODULE_NAME:[ \t]*(\S+)\s*$/,
mixedModuleName: / ((MIXED_)?MODULE_NAME):[ \t]*(\S+)\s*$/,
command: /^--(([a-z-]+)( .*)?)$/,
//! "Special" characters - we have to escape output if it contains any.
special: /[\x00-\x20\x22\x5c\x7b\x7d]/,
//! Either of '{' or '}'.
squiggly: /[{}]/
});
class TestScript {
#cursor = new Cursor();
#moduleName = null;
@ -529,6 +650,28 @@ class TestScript {
return m ? m[1].trim().split(/\s+/) : null;
}
#isCommandLine(line, checkForImpl){
let m = Rx.command.exec(line);
if( m && checkForImpl ){
m = !!CommandDispatcher.getCommandByName(m[2]);
}
return !!m;
}
fetchCommandBody(tester){
const sb = [];
let line;
while( (null !== (line = this.peekLine())) ){
this.#checkForDirective(tester, line);
if( this.#isCommandLine(line, true) ) break;
sb.push(line,"\n");
this.consumePeeked();
}
line = sb.join('');
return !!line.trim() ? line : null;
}
run(tester){
this.reset();
this.#outer.verbosity(tester.verbosity());
@ -621,14 +764,16 @@ class TestScript {
const oldPB = cur.putbackPos;
const oldPBL = cur.putbackLineNo;
const oldLine = cur.lineNo;
const rc = this.getLine();
cur.peekedPos = cur.pos;
cur.peekedLineNo = cur.lineNo;
cur.pos = oldPos;
cur.lineNo = oldLine;
cur.putbackPos = oldPB;
cur.putbackLineNo = oldPBL;
return rc;
try {
return this.getLine();
}finally{
cur.peekedPos = cur.pos;
cur.peekedLineNo = cur.lineNo;
cur.pos = oldPos;
cur.lineNo = oldLine;
cur.putbackPos = oldPB;
cur.putbackLineNo = oldPBL;
}
}
@ -667,7 +812,7 @@ class CloseDbCommand extends Command {
let id;
if(argv.length>1){
const arg = argv[1];
if("all".equals(arg)){
if( "all" === arg ){
t.closeAllDbs();
return;
}
@ -697,6 +842,36 @@ class DbCommand extends Command {
}
}
//! --glob command
class GlobCommand extends Command {
#negate = false;
constructor(negate=false){
super();
this.#negate = negate;
}
process(t, ts, argv){
this.argcCheck(ts,argv,1,-1);
t.incrementTestCounter();
const sql = t.takeInputBuffer();
let rc = t.execSql(null, true, ResultBufferMode.ESCAPED,
ResultRowMode.ONELINE, sql);
const result = t.getResultText();
const sArgs = Util.argvToString(argv);
//t2.verbose2(argv[0]," rc = ",rc," result buffer:\n", result,"\nargs:\n",sArgs);
const glob = Util.argvToString(argv);
rc = Util.strglob(glob, result);
if( (this.#negate && 0===rc) || (!this.#negate && 0!==rc) ){
ts.toss(argv[0], " mismatch: ", glob," vs input: ",result);
}
}
}
//! --notglob command
class NotGlobCommand extends GlobCommand {
constructor(){super(true);}
}
//! --open command
class OpenDbCommand extends Command {
#createIfNeeded = false;
@ -740,6 +915,107 @@ class PrintCommand extends Command {
}
}
//! --result command
class ResultCommand extends Command {
#bufferMode;
constructor(resultBufferMode = ResultBufferMode.ESCAPED){
super();
this.#bufferMode = resultBufferMode;
}
process(t, ts, argv){
this.argcCheck(ts,argv,0,-1);
t.incrementTestCounter();
const sql = t.takeInputBuffer();
//ts.verbose2(argv[0]," SQL =\n",sql);
t.execSql(null, false, this.#bufferMode, ResultRowMode.ONELINE, sql);
const result = t.getResultText().trim();
const sArgs = argv.length>1 ? Util.argvToString(argv) : "";
if( result !== sArgs ){
t.outln(argv[0]," FAILED comparison. Result buffer:\n",
result,"\nExpected result:\n",sArgs);
ts.toss(argv[0]+" comparison failed.");
}
}
}
//! --json command
class JsonCommand extends ResultCommand {
constructor(){ super(ResultBufferMode.ASIS); }
}
//! --run command
class RunCommand extends Command {
process(t, ts, argv){
this.argcCheck(ts,argv,0,1);
const pDb = (1==argv.length)
? t.currentDb() : t.getDbById( parseInt(argv[1]) );
const sql = t.takeInputBuffer();
const rc = t.execSql(pDb, false, ResultBufferMode.NONE,
ResultRowMode.ONELINE, sql);
if( 0!==rc && t.verbosity()>0 ){
const msg = sqlite3.capi.sqlite3_errmsg(pDb);
ts.verbose1(argv[0]," non-fatal command error #",rc,": ",
msg,"\nfor SQL:\n",sql);
}
}
}
//! --tableresult command
class TableResultCommand extends Command {
#jsonMode;
constructor(jsonMode=false){
super();
this.#jsonMode = jsonMode;
}
process(t, ts, argv){
this.argcCheck(ts,argv,0);
t.incrementTestCounter();
let body = ts.fetchCommandBody(t);
log("TRC fetchCommandBody: ",body);
if( null===body ) ts.toss("Missing ",argv[0]," body.");
body = body.trim();
if( !body.endsWith("\n--end") ){
ts.toss(argv[0], " must be terminated with --end\\n");
}else{
body = body.substring(0, body.length-6);
log("TRC fetchCommandBody reshaped:",body);
}
const globs = body.split(/\s*\n\s*/);
if( globs.length < 1 ){
ts.toss(argv[0], " requires 1 or more ",
(this.#jsonMode ? "json snippets" : "globs"),".");
}
log("TRC fetchCommandBody globs:",globs);
const sql = t.takeInputBuffer();
t.execSql(null, true,
this.#jsonMode ? ResultBufferMode.ASIS : ResultBufferMode.ESCAPED,
ResultRowMode.NEWLINE, sql);
const rbuf = t.getResultText().trim();
const res = rbuf.split(/\r?\n/);
log("TRC fetchCommandBody rbuf, res:",rbuf, res);
if( res.length !== globs.length ){
ts.toss(argv[0], " failure: input has ", res.length,
" row(s) but expecting ",globs.length);
}
for(let i = 0; i < res.length; ++i){
const glob = globs[i].replaceAll(/\s+/g," ").trim();
//ts.verbose2(argv[0]," <<",glob,">> vs <<",res[i],">>");
if( this.#jsonMode ){
if( glob!==res[i] ){
ts.toss(argv[0], " json <<",glob, ">> does not match: <<",
res[i],">>");
}
}else if( 0!=Util.strglob(glob, res[i]) ){
ts.toss(argv[0], " glob <<",glob,">> does not match: <<",res[i],">>");
}
}
}
}
//! --json-block command
class JsonBlockCommand extends TableResultCommand {
constructor(){ super(true); }
}
//! --testcase command
class TestCaseCommand extends Command {
@ -770,18 +1046,18 @@ class CommandDispatcher {
case "close": rv = new CloseDbCommand(); break;
case "column-names": rv = new ColumnNamesCommand(); break;
case "db": rv = new DbCommand(); break;
//case "glob": rv = new GlobCommand(); break;
//case "json": rv = new JsonCommand(); break;
//case "json-block": rv = new JsonBlockCommand(); break;
case "glob": rv = new GlobCommand(); break;
case "json": rv = new JsonCommand(); break;
case "json-block": rv = new JsonBlockCommand(); break;
case "new": rv = new NewDbCommand(); break;
//case "notglob": rv = new NotGlobCommand(); break;
case "notglob": rv = new NotGlobCommand(); break;
case "null": rv = new NullCommand(); break;
case "oom": rv = new NoopCommand(); break;
case "open": rv = new OpenDbCommand(); break;
case "print": rv = new PrintCommand(); break;
//case "result": rv = new ResultCommand(); break;
//case "run": rv = new RunCommand(); break;
//case "tableresult": rv = new TableResultCommand(); break;
case "result": rv = new ResultCommand(); break;
case "run": rv = new RunCommand(); break;
case "tableresult": rv = new TableResultCommand(); break;
case "testcase": rv = new TestCaseCommand(); break;
case "verbosity": rv = new VerbosityCommand(); break;
}

View File

@ -25,14 +25,46 @@ log("ns =",ns);
out("Hi there. ").outln("SQLTester is ostensibly ready.");
let ts = new ns.TestScript('/foo.test', ns.Util.utf8Encode(
`# comment line
--print Starting up...
--null NIL
--new :memory:
--testcase 0.0.1
select '0.0.1';
#--result 0.0.1
--print done
`
--close all
--oom
--db 0
--new my.db
--null zilch
--testcase 1.0
SELECT 1, null;
--result 1 zilch
--glob *zil*
--notglob *ZIL*
SELECT 1, 2;
intentional error;
--run
--testcase json-1
SELECT json_array(1,2,3)
--json [1,2,3]
--testcase tableresult-1
select 1, 'a';
select 2, 'b';
--tableresult
# [a-z]
2 b
--end
--testcase json-block-1
select json_array(1,2,3);
select json_object('a',1,'b',2);
--json-block
[1,2,3]
{"a":1,"b":2}
--end
--testcase col-names-on
--column-names 1
select 1 as 'a', 2 as 'b';
--result a 1 b 2
--testcase col-names-off
--column-names 0
select 1 as 'a', 2 as 'b';
--result 1 2
--close
`));
const sqt = new ns.SQLTester();
@ -41,11 +73,12 @@ try{
sqt.openDb('/foo.db', true);
log( 'sqt.getCurrentDb()', sqt.getCurrentDb() );
sqt.verbosity(0);
affirm( 'NIL' !== sqt.nullValue() );
affirm( 'zilch' !== sqt.nullValue() );
ts.run(sqt);
affirm( 'NIL' === sqt.nullValue() );
affirm( 'zilch' === sqt.nullValue() );
}finally{
sqt.reset();
}
log( 'sqt.getCurrentDb()', sqt.getCurrentDb() );
log( "Metrics:", sqt.metrics );

View File

@ -1139,15 +1139,15 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
/**
Records the current pstack position, calls the given function,
and restores the pstack regardless of whether the function
throws. Returns the result of the call or propagates an
exception on error.
passing it the sqlite3 object, then restores the pstack
regardless of whether the function throws. Returns the result
of the call or propagates an exception on error.
Added in 3.44.
*/
call: function(f){
const stackPos = wasm.pstack.pointer;
try{ return f() }finally{
try{ return f(sqlite3) } finally{
wasm.pstack.restore(stackPos);
}
}

View File

@ -1801,6 +1801,118 @@ char * sqlite3_wasm_test_str_hello(int fail){
}
return s;
}
/*
** For testing using SQLTester scripts.
**
** Return non-zero if string z matches glob pattern zGlob and zero if the
** pattern does not match.
**
** To repeat:
**
** zero == no match
** non-zero == match
**
** Globbing rules:
**
** '*' Matches any sequence of zero or more characters.
**
** '?' Matches exactly one character.
**
** [...] Matches one character from the enclosed list of
** characters.
**
** [^...] Matches one character not in the enclosed list.
**
** '#' Matches any sequence of one or more digits with an
** optional + or - sign in front, or a hexadecimal
** literal of the form 0x...
*/
static int sqlite3_wasm_SQLTester_strnotglob(const char *zGlob, const char *z){
int c, c2;
int invert;
int seen;
typedef int (*recurse_f)(const char *,const char *);
static const recurse_f recurse = sqlite3_wasm_SQLTester_strnotglob;
while( (c = (*(zGlob++)))!=0 ){
if( c=='*' ){
while( (c=(*(zGlob++))) == '*' || c=='?' ){
if( c=='?' && (*(z++))==0 ) return 0;
}
if( c==0 ){
return 1;
}else if( c=='[' ){
while( *z && recurse(zGlob-1,z)==0 ){
z++;
}
return (*z)!=0;
}
while( (c2 = (*(z++)))!=0 ){
while( c2!=c ){
c2 = *(z++);
if( c2==0 ) return 0;
}
if( recurse(zGlob,z) ) return 1;
}
return 0;
}else if( c=='?' ){
if( (*(z++))==0 ) return 0;
}else if( c=='[' ){
int prior_c = 0;
seen = 0;
invert = 0;
c = *(z++);
if( c==0 ) return 0;
c2 = *(zGlob++);
if( c2=='^' ){
invert = 1;
c2 = *(zGlob++);
}
if( c2==']' ){
if( c==']' ) seen = 1;
c2 = *(zGlob++);
}
while( c2 && c2!=']' ){
if( c2=='-' && zGlob[0]!=']' && zGlob[0]!=0 && prior_c>0 ){
c2 = *(zGlob++);
if( c>=prior_c && c<=c2 ) seen = 1;
prior_c = 0;
}else{
if( c==c2 ){
seen = 1;
}
prior_c = c2;
}
c2 = *(zGlob++);
}
if( c2==0 || (seen ^ invert)==0 ) return 0;
}else if( c=='#' ){
if( z[0]=='0'
&& (z[1]=='x' || z[1]=='X')
&& sqlite3Isxdigit(z[2])
){
z += 3;
while( sqlite3Isxdigit(z[0]) ){ z++; }
}else{
if( (z[0]=='-' || z[0]=='+') && sqlite3Isdigit(z[1]) ) z++;
if( !sqlite3Isdigit(z[0]) ) return 0;
z++;
while( sqlite3Isdigit(z[0]) ){ z++; }
}
}else{
if( c!=(*(z++)) ) return 0;
}
}
return *z==0;
}
SQLITE_WASM_EXPORT
int sqlite3_wasm_SQLTester_strglob(const char *zGlob, const char *z){
return !sqlite3_wasm_SQLTester_strnotglob(zGlob, z);
}
#endif /* SQLITE_WASM_TESTS */
#undef SQLITE_WASM_EXPORT

View File

@ -1,5 +1,5 @@
C Get\sthe\sJS\sSQLTester\scommand\shandlers\sin\splace\ssans\sthose\swhich\shave\sto\srun\sSQL.
D 2023-08-29T15:39:57.155
C JS\sSQLTestRunner\scan\snow\srun\sthe\sJava\simpl's\score-most\ssanity\stests,\smissing\sonly\ssupport\sfor\sdirectives.
D 2023-08-29T20:01:01.586
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -283,7 +283,7 @@ F ext/jni/src/org/sqlite/jni/sqlite3.java 62b1b81935ccf3393472d17cb883dc5ff39c38
F ext/jni/src/org/sqlite/jni/sqlite3_context.java 66ca95ce904044263a4aff684abe262d56f73e6b06bca6cf650761d79d7779ad
F ext/jni/src/org/sqlite/jni/sqlite3_stmt.java 78e6d1b95ac600a9475e9db4623f69449322b0c93d1bd4e1616e76ed547ed9fc
F ext/jni/src/org/sqlite/jni/sqlite3_value.java 3d1d4903e267bc0bc81d57d21f5e85978eff389a1a6ed46726dbe75f85e6914a
F ext/jni/src/org/sqlite/jni/tester/SQLTester.java c8a9f20694e66f4d7ed677cd6d1f0d829f802c347a1f413ac2446c62e4cba23d
F ext/jni/src/org/sqlite/jni/tester/SQLTester.java a9f4b9e12109645b21fef15807973706dd958aad9fe1c835693fcb8e95abe949
F ext/jni/src/org/sqlite/jni/tester/test-script-interpreter.md f9f25126127045d051e918fe59004a1485311c50a13edbf18c79a6ff9160030e
F ext/jni/src/tests/000-000-sanity.test cfe6dc1b950751d6096e3f5695becaadcdaa048bfe9567209d6eb676e693366d
F ext/jni/src/tests/000-001-ignored.test e17e874c6ab3c437f1293d88093cf06286083b65bf162317f91bbfd92f961b70
@ -548,8 +548,8 @@ F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34ce
F ext/wasm/GNUmakefile 0e362f3fc04eab6628cbe4f1e35f4ab4a200881f6b5f753b27fb45eabeddd9d2
F ext/wasm/README-dist.txt 6382cb9548076fca472fb3330bbdba3a55c1ea0b180ff9253f084f07ff383576
F ext/wasm/README.md a8a2962c3aebdf8d2104a9102e336c5554e78fc6072746e5daf9c61514e7d193
F ext/wasm/SQLTester/SQLTester.mjs 90fc3d2eb831afed237c18b78c22b8871d8f855a742715ebee571a60b9fcd98e
F ext/wasm/SQLTester/SQLTester.run.mjs 30a459ec400495cc52f1d693703f1629e141947a19eaf868a8e4c1fd3ef2a114
F ext/wasm/SQLTester/SQLTester.mjs 345736d970dc56e2c1041f8583fc602eedd8a64d455864f312db7d3208e640ea
F ext/wasm/SQLTester/SQLTester.run.mjs 2dfa1407f5f188dadafe6f21f7a6740b4f07d59c594781a01eedadec16b2ddfe
F ext/wasm/SQLTester/index.html 88d87e3ccbc33e7ab3773a8e48c1172e876951c4be31d1307c3700671262cddf
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api d6a5078f48a5301ed17b9a30331075d9b2506e1360c1f0dee0c7816c10acd9ab
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-see fb29e62082a658f0d81102488414d422c393c4b20cc2f685b216bc566237957b
@ -563,14 +563,14 @@ F ext/wasm/api/pre-js.c-pp.js ad906703f7429590f2fbf5e6498513bf727a1a4f0ebfa057af
F ext/wasm/api/sqlite3-api-cleanup.js d235ad237df6954145404305040991c72ef8b1881715d2a650dda7b3c2576d0e
F ext/wasm/api/sqlite3-api-glue.js b65e546568f1dfb35205b9792feb5146a6323d71b55cda58e2ed30def6dd52f3
F ext/wasm/api/sqlite3-api-oo1.js 9678dc4d9a5d39632b6ffe6ea94a023119260815bf32f265bf5f6c36c9516db8
F ext/wasm/api/sqlite3-api-prologue.js 7fe51f06cd855634cb3765f830393f544fb532ead1cf95b5de3dd0befc81b92d
F ext/wasm/api/sqlite3-api-prologue.js 723908946bd624d367e4df7093e9a6c9725606dc526953ea601cad8d7ce88538
F ext/wasm/api/sqlite3-api-worker1.js 9f32af64df1a031071912eea7a201557fe39b1738645c0134562bb84e88e2fec
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
F ext/wasm/api/sqlite3-opfs-async-proxy.js 8cf8a897726f14071fae6be6648125162b256dfb4f96555b865dbb7a6b65e379
F ext/wasm/api/sqlite3-v-helper.js 7daa0eab0a513a25b05e9abae7b5beaaa39209b3ed12f86aeae9ef8d2719ed25
F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js 561463ac5380e4ccf1839a1922e6d7a5585660f32e3b9701a270b78cd35566cf
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js d9e62d42b86f7bb3143eb071628b24e2ba7dcc749e41a0e9d3e2451bfea1a6b6
F ext/wasm/api/sqlite3-wasm.c 6773e949034369ddd2a1efdedc39b2808a10b7274b0769188905432e561feebe
F ext/wasm/api/sqlite3-wasm.c 65d60439671e24d50d9119ca805ac1c68fb36129e164377eb46f8d037bd88b07
F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js bc06df0d599e625bde6a10a394e326dc68da9ff07fa5404354580f81566e591f
F ext/wasm/api/sqlite3-worker1.c-pp.js da509469755035e919c015deea41b4514b5e84c12a1332e6cc8d42cb2cc1fb75
F ext/wasm/batch-runner.html 4deeed44fe41496dc6898d9fb17938ea3291f40f4bfb977e29d0cef96fbbe4c8
@ -2111,8 +2111,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 8fcc2a553c1e26734902bbdee0c38183ee22b7b5c75f07405529bb79db34145a
R 8ed29d2cdb1f79e88ba5ccad29a3151d
P d21b1217964a53f33b7ba3958b34aa8560dff8ede33e66f54aa0afbab7099ec3
R 7266768b4057594984eb0965145c2068
U stephan
Z 988ed72426998a455381761a89d498de
Z 703bcb5450951150eb9347fe40faa521
# Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
d21b1217964a53f33b7ba3958b34aa8560dff8ede33e66f54aa0afbab7099ec3
5e798369375ce1b0c9cdf831f835d931fbd562ff7b4db09a06d1bdca2ac1b975