From: stephan Date: Tue, 8 Aug 2023 14:40:47 +0000 (+0000) Subject: A number of baby steps for SQLTester.java. It can now handle basic --result cases. X-Git-Tag: version-3.43.0~47^2~64 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=671757f4d4daca431f1f67aca70e3b8ac8904a36;p=thirdparty%2Fsqlite.git A number of baby steps for SQLTester.java. It can now handle basic --result cases. FossilOrigin-Name: 0404f688f6a22b6bbe009de1bee3341ca00e19e2cc32081265cf151876dc032f --- diff --git a/ext/jni/GNUmakefile b/ext/jni/GNUmakefile index 66df526225..d6fc2e6d38 100644 --- a/ext/jni/GNUmakefile +++ b/ext/jni/GNUmakefile @@ -54,6 +54,7 @@ JAVA_FILES.main := $(patsubst %,$(dir.src.jni)/%,\ NativePointerHolder.java \ OutputPointer.java \ ProgressHandler.java \ + ResultCode.java \ RollbackHook.java \ SQLFunction.java \ sqlite3_context.java \ diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c index 50676c3519..66c62d6053 100644 --- a/ext/jni/src/c/sqlite3-jni.c +++ b/ext/jni/src/c/sqlite3-jni.c @@ -2728,6 +2728,11 @@ end: UNREF_L(jStmt); jStmt = 0; } +#if 0 + if( 0!=rc ){ + MARKER(("prepare rc = %d\n", rc)); + } +#endif OutputPointer_set_sqlite3_stmt(env, jOutStmt, jStmt); (void)stmt_set_current(jc, pOldStmt); return (jint)rc; diff --git a/ext/jni/src/org/sqlite/jni/ResultCode.java b/ext/jni/src/org/sqlite/jni/ResultCode.java new file mode 100644 index 0000000000..30626f7564 --- /dev/null +++ b/ext/jni/src/org/sqlite/jni/ResultCode.java @@ -0,0 +1,151 @@ +/* +** 2023-07-21 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This file is part of the JNI bindings for the sqlite3 C API. +*/ +package org.sqlite.jni; + +//! Internal level of indirection requires because we cannot reference +// static enum members from an enum constructor. +class ResultCodeMap { + private static final java.util.Map i2e + = new java.util.HashMap<>(); + + public static void set(int i, ResultCode src){ + i2e.put(i, src); + } + public static ResultCode get(int i){ + return i2e.get(i); + } +} + +/** + This enum of sqlite3 result codes is provided not for use with the + C-style API (with which it won't work) but for higher-level code which + may find it useful to map codes to human-readable names. +*/ +public enum ResultCode { + SQLITE_OK(SQLite3Jni.SQLITE_OK), + SQLITE_ERROR(SQLite3Jni.SQLITE_ERROR), + SQLITE_INTERNAL(SQLite3Jni.SQLITE_INTERNAL), + SQLITE_PERM(SQLite3Jni.SQLITE_PERM), + SQLITE_ABORT(SQLite3Jni.SQLITE_ABORT), + SQLITE_BUSY(SQLite3Jni.SQLITE_BUSY), + SQLITE_LOCKED(SQLite3Jni.SQLITE_LOCKED), + SQLITE_NOMEM(SQLite3Jni.SQLITE_NOMEM), + SQLITE_READONLY(SQLite3Jni.SQLITE_READONLY), + SQLITE_INTERRUPT(SQLite3Jni.SQLITE_INTERRUPT), + SQLITE_IOERR(SQLite3Jni.SQLITE_IOERR), + SQLITE_CORRUPT(SQLite3Jni.SQLITE_CORRUPT), + SQLITE_NOTFOUND(SQLite3Jni.SQLITE_NOTFOUND), + SQLITE_FULL(SQLite3Jni.SQLITE_FULL), + SQLITE_CANTOPEN(SQLite3Jni.SQLITE_CANTOPEN), + SQLITE_PROTOCOL(SQLite3Jni.SQLITE_PROTOCOL), + SQLITE_EMPTY(SQLite3Jni.SQLITE_EMPTY), + SQLITE_SCHEMA(SQLite3Jni.SQLITE_SCHEMA), + SQLITE_TOOBIG(SQLite3Jni.SQLITE_TOOBIG), + SQLITE_CONSTRAINT(SQLite3Jni.SQLITE_CONSTRAINT), + SQLITE_MISMATCH(SQLite3Jni.SQLITE_MISMATCH), + SQLITE_MISUSE(SQLite3Jni.SQLITE_MISUSE), + SQLITE_NOLFS(SQLite3Jni.SQLITE_NOLFS), + SQLITE_AUTH(SQLite3Jni.SQLITE_AUTH), + SQLITE_FORMAT(SQLite3Jni.SQLITE_FORMAT), + SQLITE_RANGE(SQLite3Jni.SQLITE_RANGE), + SQLITE_NOTADB(SQLite3Jni.SQLITE_NOTADB), + SQLITE_NOTICE(SQLite3Jni.SQLITE_NOTICE), + SQLITE_WARNING(SQLite3Jni.SQLITE_WARNING), + SQLITE_ROW(SQLite3Jni.SQLITE_ROW), + SQLITE_DONE(SQLite3Jni.SQLITE_DONE), + SQLITE_ERROR_MISSING_COLLSEQ(SQLite3Jni.SQLITE_ERROR_MISSING_COLLSEQ), + SQLITE_ERROR_RETRY(SQLite3Jni.SQLITE_ERROR_RETRY), + SQLITE_ERROR_SNAPSHOT(SQLite3Jni.SQLITE_ERROR_SNAPSHOT), + SQLITE_IOERR_READ(SQLite3Jni.SQLITE_IOERR_READ), + SQLITE_IOERR_SHORT_READ(SQLite3Jni.SQLITE_IOERR_SHORT_READ), + SQLITE_IOERR_WRITE(SQLite3Jni.SQLITE_IOERR_WRITE), + SQLITE_IOERR_FSYNC(SQLite3Jni.SQLITE_IOERR_FSYNC), + SQLITE_IOERR_DIR_FSYNC(SQLite3Jni.SQLITE_IOERR_DIR_FSYNC), + SQLITE_IOERR_TRUNCATE(SQLite3Jni.SQLITE_IOERR_TRUNCATE), + SQLITE_IOERR_FSTAT(SQLite3Jni.SQLITE_IOERR_FSTAT), + SQLITE_IOERR_UNLOCK(SQLite3Jni.SQLITE_IOERR_UNLOCK), + SQLITE_IOERR_RDLOCK(SQLite3Jni.SQLITE_IOERR_RDLOCK), + SQLITE_IOERR_DELETE(SQLite3Jni.SQLITE_IOERR_DELETE), + SQLITE_IOERR_BLOCKED(SQLite3Jni.SQLITE_IOERR_BLOCKED), + SQLITE_IOERR_NOMEM(SQLite3Jni.SQLITE_IOERR_NOMEM), + SQLITE_IOERR_ACCESS(SQLite3Jni.SQLITE_IOERR_ACCESS), + SQLITE_IOERR_CHECKRESERVEDLOCK(SQLite3Jni.SQLITE_IOERR_CHECKRESERVEDLOCK), + SQLITE_IOERR_LOCK(SQLite3Jni.SQLITE_IOERR_LOCK), + SQLITE_IOERR_CLOSE(SQLite3Jni.SQLITE_IOERR_CLOSE), + SQLITE_IOERR_DIR_CLOSE(SQLite3Jni.SQLITE_IOERR_DIR_CLOSE), + SQLITE_IOERR_SHMOPEN(SQLite3Jni.SQLITE_IOERR_SHMOPEN), + SQLITE_IOERR_SHMSIZE(SQLite3Jni.SQLITE_IOERR_SHMSIZE), + SQLITE_IOERR_SHMLOCK(SQLite3Jni.SQLITE_IOERR_SHMLOCK), + SQLITE_IOERR_SHMMAP(SQLite3Jni.SQLITE_IOERR_SHMMAP), + SQLITE_IOERR_SEEK(SQLite3Jni.SQLITE_IOERR_SEEK), + SQLITE_IOERR_DELETE_NOENT(SQLite3Jni.SQLITE_IOERR_DELETE_NOENT), + SQLITE_IOERR_MMAP(SQLite3Jni.SQLITE_IOERR_MMAP), + SQLITE_IOERR_GETTEMPPATH(SQLite3Jni.SQLITE_IOERR_GETTEMPPATH), + SQLITE_IOERR_CONVPATH(SQLite3Jni.SQLITE_IOERR_CONVPATH), + SQLITE_IOERR_VNODE(SQLite3Jni.SQLITE_IOERR_VNODE), + SQLITE_IOERR_AUTH(SQLite3Jni.SQLITE_IOERR_AUTH), + SQLITE_IOERR_BEGIN_ATOMIC(SQLite3Jni.SQLITE_IOERR_BEGIN_ATOMIC), + SQLITE_IOERR_COMMIT_ATOMIC(SQLite3Jni.SQLITE_IOERR_COMMIT_ATOMIC), + SQLITE_IOERR_ROLLBACK_ATOMIC(SQLite3Jni.SQLITE_IOERR_ROLLBACK_ATOMIC), + SQLITE_IOERR_DATA(SQLite3Jni.SQLITE_IOERR_DATA), + SQLITE_IOERR_CORRUPTFS(SQLite3Jni.SQLITE_IOERR_CORRUPTFS), + SQLITE_LOCKED_SHAREDCACHE(SQLite3Jni.SQLITE_LOCKED_SHAREDCACHE), + SQLITE_LOCKED_VTAB(SQLite3Jni.SQLITE_LOCKED_VTAB), + SQLITE_BUSY_RECOVERY(SQLite3Jni.SQLITE_BUSY_RECOVERY), + SQLITE_BUSY_SNAPSHOT(SQLite3Jni.SQLITE_BUSY_SNAPSHOT), + SQLITE_BUSY_TIMEOUT(SQLite3Jni.SQLITE_BUSY_TIMEOUT), + SQLITE_CANTOPEN_NOTEMPDIR(SQLite3Jni.SQLITE_CANTOPEN_NOTEMPDIR), + SQLITE_CANTOPEN_ISDIR(SQLite3Jni.SQLITE_CANTOPEN_ISDIR), + SQLITE_CANTOPEN_FULLPATH(SQLite3Jni.SQLITE_CANTOPEN_FULLPATH), + SQLITE_CANTOPEN_CONVPATH(SQLite3Jni.SQLITE_CANTOPEN_CONVPATH), + SQLITE_CANTOPEN_SYMLINK(SQLite3Jni.SQLITE_CANTOPEN_SYMLINK), + SQLITE_CORRUPT_VTAB(SQLite3Jni.SQLITE_CORRUPT_VTAB), + SQLITE_CORRUPT_SEQUENCE(SQLite3Jni.SQLITE_CORRUPT_SEQUENCE), + SQLITE_CORRUPT_INDEX(SQLite3Jni.SQLITE_CORRUPT_INDEX), + SQLITE_READONLY_RECOVERY(SQLite3Jni.SQLITE_READONLY_RECOVERY), + SQLITE_READONLY_CANTLOCK(SQLite3Jni.SQLITE_READONLY_CANTLOCK), + SQLITE_READONLY_ROLLBACK(SQLite3Jni.SQLITE_READONLY_ROLLBACK), + SQLITE_READONLY_DBMOVED(SQLite3Jni.SQLITE_READONLY_DBMOVED), + SQLITE_READONLY_CANTINIT(SQLite3Jni.SQLITE_READONLY_CANTINIT), + SQLITE_READONLY_DIRECTORY(SQLite3Jni.SQLITE_READONLY_DIRECTORY), + SQLITE_ABORT_ROLLBACK(SQLite3Jni.SQLITE_ABORT_ROLLBACK), + SQLITE_CONSTRAINT_CHECK(SQLite3Jni.SQLITE_CONSTRAINT_CHECK), + SQLITE_CONSTRAINT_COMMITHOOK(SQLite3Jni.SQLITE_CONSTRAINT_COMMITHOOK), + SQLITE_CONSTRAINT_FOREIGNKEY(SQLite3Jni.SQLITE_CONSTRAINT_FOREIGNKEY), + SQLITE_CONSTRAINT_FUNCTION(SQLite3Jni.SQLITE_CONSTRAINT_FUNCTION), + SQLITE_CONSTRAINT_NOTNULL(SQLite3Jni.SQLITE_CONSTRAINT_NOTNULL), + SQLITE_CONSTRAINT_PRIMARYKEY(SQLite3Jni.SQLITE_CONSTRAINT_PRIMARYKEY), + SQLITE_CONSTRAINT_TRIGGER(SQLite3Jni.SQLITE_CONSTRAINT_TRIGGER), + SQLITE_CONSTRAINT_UNIQUE(SQLite3Jni.SQLITE_CONSTRAINT_UNIQUE), + SQLITE_CONSTRAINT_VTAB(SQLite3Jni.SQLITE_CONSTRAINT_VTAB), + SQLITE_CONSTRAINT_ROWID(SQLite3Jni.SQLITE_CONSTRAINT_ROWID), + SQLITE_CONSTRAINT_PINNED(SQLite3Jni.SQLITE_CONSTRAINT_PINNED), + SQLITE_CONSTRAINT_DATATYPE(SQLite3Jni.SQLITE_CONSTRAINT_DATATYPE), + SQLITE_NOTICE_RECOVER_WAL(SQLite3Jni.SQLITE_NOTICE_RECOVER_WAL), + SQLITE_NOTICE_RECOVER_ROLLBACK(SQLite3Jni.SQLITE_NOTICE_RECOVER_ROLLBACK), + SQLITE_WARNING_AUTOINDEX(SQLite3Jni.SQLITE_WARNING_AUTOINDEX), + SQLITE_AUTH_USER(SQLite3Jni.SQLITE_AUTH_USER), + SQLITE_OK_LOAD_PERMANENTLY(SQLite3Jni.SQLITE_OK_LOAD_PERMANENTLY); + + public final int value; + + ResultCode(int v){ + value = v; + ResultCodeMap.set(v, this); + } + + public static ResultCode getEntryForInt(int rc){ + return ResultCodeMap.get(rc); + } +} diff --git a/ext/jni/src/org/sqlite/jni/Tester1.java b/ext/jni/src/org/sqlite/jni/Tester1.java index 57df78e9f6..3c67076469 100644 --- a/ext/jni/src/org/sqlite/jni/Tester1.java +++ b/ext/jni/src/org/sqlite/jni/Tester1.java @@ -102,23 +102,27 @@ public class Tester1 { rc = sqlite3_prepare_v2(db, sqlChunk, outStmt, oTail); if(throwOnError) affirm(0 == rc); else if( 0!=rc ) break; - stmt = outStmt.getValue(); pos = oTail.getValue(); + stmt = outStmt.getValue(); + if( null == stmt ){ + // empty statement was parsed. + continue; + } affirm(0 != stmt.getNativePointer()); while( SQLITE_ROW == (rc = sqlite3_step(stmt)) ){ } sqlite3_finalize(stmt); affirm(0 == stmt.getNativePointer()); if(0!=rc && SQLITE_ROW!=rc && SQLITE_DONE!=rc){ - if(throwOnError){ - throw new RuntimeException("db op failed with rc="+rc); - }else{ - break; - } + break; } } sqlite3_finalize(stmt); if(SQLITE_ROW==rc || SQLITE_DONE==rc) rc = 0; + if( 0!=rc && throwOnError){ + throw new RuntimeException("db op failed with rc=" + +rc+": "+sqlite3_errmsg(db)); + } return rc; } diff --git a/ext/jni/src/org/sqlite/jni/tester/Outer.java b/ext/jni/src/org/sqlite/jni/tester/Outer.java index f86277d14d..e4ea783490 100644 --- a/ext/jni/src/org/sqlite/jni/tester/Outer.java +++ b/ext/jni/src/org/sqlite/jni/tester/Outer.java @@ -29,8 +29,7 @@ class Outer { @SuppressWarnings("unchecked") public static void out(Object... vals){ - int n = 0; - for(Object v : vals) out((n++>0 ? " " : "")+v); + for(Object v : vals) out(v); } @SuppressWarnings("unchecked") @@ -41,7 +40,10 @@ class Outer { @SuppressWarnings("unchecked") public Outer verbose(Object... vals){ - if(verbose) outln(vals); + if(verbose){ + out("VERBOSE: "); + outln(vals); + } return this; } diff --git a/ext/jni/src/org/sqlite/jni/tester/SQLTester.java b/ext/jni/src/org/sqlite/jni/tester/SQLTester.java index 5fad8a6c0b..626e33a523 100644 --- a/ext/jni/src/org/sqlite/jni/tester/SQLTester.java +++ b/ext/jni/src/org/sqlite/jni/tester/SQLTester.java @@ -15,9 +15,16 @@ package org.sqlite.jni.tester; import java.util.List; import java.util.ArrayList; +import java.util.Arrays; +import java.nio.charset.StandardCharsets; import org.sqlite.jni.*; import static org.sqlite.jni.SQLite3Jni.*; +class TestFailure extends RuntimeException { + public TestFailure(String msg){ + super(msg); + } +} /** This class provides an application which aims to implement the rudimentary SQL-driven test tool described in the accompanying @@ -40,6 +47,7 @@ public class SQLTester { private int nTest; private final sqlite3[] aDb = new sqlite3[7]; private int iCurrentDb = 0; + private final String initialDbName = "test.db"; public SQLTester(){ reset(); @@ -48,6 +56,9 @@ public class SQLTester { public void setVerbose(boolean b){ this.outer.setVerbose(b); } + public boolean isVerbose(){ + return this.outer.isVerbose(); + } @SuppressWarnings("unchecked") public void verbose(Object... vals){ @@ -67,42 +78,51 @@ public class SQLTester { //! Adds the given test script to the to-test list. public void addTestScript(String filename){ listInFiles.add(filename); - verbose("Added file",filename); + verbose("Added file ",filename); + } + + public void setupInitialDb() throws Exception { + Util.unlink(initialDbName); + openDb(0, initialDbName, true); } public void runTests() throws Exception { // process each input file - outln("Verbose =",outer.isVerbose()); + outln("Verbose = ",outer.isVerbose()); for(String f : listInFiles){ reset(); + setupInitialDb(); ++nTestFile; final TestScript ts = new TestScript(f); - outln("---------> Test",ts.getName(),"..."); + outln("---------> Test ",ts.getName()," ..."); ts.run(this); - outln("<---------",nTest,"test(s) in",f); + outln("<--------- ",nTest," test(s) in ",f); } + Util.unlink(initialDbName); } - private StringBuilder resetBuffer(StringBuilder b){ + private StringBuilder clearBuffer(StringBuilder b){ b.delete(0, b.length()); return b; } - StringBuilder resetInputBuffer(){ - return resetBuffer(inputBuffer); + StringBuilder clearInputBuffer(){ + return clearBuffer(inputBuffer); } - StringBuilder resetResultBuffer(){ - return resetBuffer(resultBuffer); + StringBuilder clearResultBuffer(){ + return clearBuffer(resultBuffer); } StringBuilder getInputBuffer(){ return inputBuffer; } String getInputBufferText(){ return inputBuffer.toString(); } + String getResultBufferText(){ return resultBuffer.toString(); } + private String takeBuffer(StringBuilder b){ final String rc = b.toString(); - resetBuffer(b); + clearBuffer(b); return rc; } @@ -152,11 +172,18 @@ public class SQLTester { if( 0!=rc ){ final String msg = sqlite3_errmsg(db); sqlite3_close(db); - Util.toss("db open failed with code",rc,"and message:",msg); + Util.toss(TestFailure.class, "db open failed with code", + rc,"and message:",msg); } return aDb[iCurrentDb] = db; } + sqlite3 openDb(int slot, String name, boolean createIfNeeded) throws Exception { + affirmDbId(slot); + iCurrentDb = slot; + return openDb(name, createIfNeeded); + } + /** Resets all tester context state except for that related to tracking running totals. @@ -164,7 +191,7 @@ public class SQLTester { void reset(){ nTest = 0; nullView = "nil"; - resetInputBuffer(); + clearInputBuffer(); closeAllDbs(); } @@ -172,6 +199,89 @@ public class SQLTester { void incrementTestCounter(){ ++nTest; ++nTotalTest; } + String escapeSqlValue(String v){ + // TODO: implement the escaping rules + return v; + } + + private void appendDbErr(sqlite3 db, StringBuilder sb, int rc){ + sb.append(org.sqlite.jni.ResultCode.getEntryForInt(rc)) + .append(' ') + .append(escapeSqlValue(sqlite3_errmsg(db))); + } + + public int execSql(sqlite3 db, boolean throwOnError, + boolean appendToResult, String sql) throws Exception { + final OutputPointer.Int32 oTail = new OutputPointer.Int32(); + final OutputPointer.sqlite3_stmt outStmt = new OutputPointer.sqlite3_stmt(); + final byte[] sqlUtf8 = sql.getBytes(StandardCharsets.UTF_8); + if( null==db ) db = getCurrentDb(); + int pos = 0, n = 1; + byte[] sqlChunk = sqlUtf8; + int rc = 0; + sqlite3_stmt stmt = null; + final StringBuilder sb = appendToResult ? resultBuffer : null; + //outln("sqlChunk len= = ",sqlChunk.length); + while(pos < sqlChunk.length){ + if(pos > 0){ + sqlChunk = Arrays.copyOfRange(sqlChunk, pos, + sqlChunk.length); + } + if( 0==sqlChunk.length ) break; + rc = sqlite3_prepare_v2(db, sqlChunk, outStmt, oTail); + /*outln("PREPARE rc ",rc," oTail=",oTail.getValue(),": ", + new String(sqlChunk,StandardCharsets.UTF_8),"\n");*/ + if( 0!=rc ){ + if(throwOnError){ + Util.toss(RuntimeException.class, "db op failed with rc=" + +rc+": "+sqlite3_errmsg(db)); + }else if( null!=sb ){ + appendDbErr(db, sb, rc); + } + break; + } + pos = oTail.getValue(); + stmt = outStmt.getValue(); + if( null == stmt ){ + // empty statement was parsed. + continue; + } + if( null!=sb ){ + // Add the output to the result buffer... + final int nCol = sqlite3_column_count(stmt); + int spacing = 0; + while( SQLITE_ROW == (rc = sqlite3_step(stmt)) ){ + for(int i = 0; i < nCol; ++i){ + if( spacing++ > 0 ) sb.append(' '); + String val = sqlite3_column_text16(stmt, i); + if( null==val ){ + sb.append( nullView ); + continue; + } + sb.append( escapeSqlValue(val) ); + } + //sb.append('\n'); + } + }else{ + while( SQLITE_ROW == (rc = sqlite3_step(stmt)) ){} + } + sqlite3_finalize(stmt); + if(SQLITE_ROW==rc || SQLITE_DONE==rc) rc = 0; + else if( rc!=0 ){ + if( null!=sb ){ + appendDbErr(db, sb, rc); + } + break; + } + } + sqlite3_finalize(stmt); + if( 0!=rc && throwOnError ){ + Util.toss(RuntimeException.class, "db op failed with rc=" + +rc+": "+sqlite3_errmsg(db)); + } + return rc; + } + public static void main(String[] argv) throws Exception{ final SQLTester t = new SQLTester(); for(String a : argv){ @@ -189,7 +299,7 @@ public class SQLTester { t.addTestScript(a); } t.runTests(); - t.outer.outln("Processed",t.nTotalTest,"test(s) in",t.nTestFile,"file(s)."); + t.outer.outln("Processed ",t.nTotalTest," test(s) in ",t.nTestFile," file(s)."); } } @@ -221,6 +331,7 @@ class Command { protected final void argcCheck(String[] argv, int min, int max) throws Exception{ int argc = argv.length-1; + if(max<0) max = 99999999; if(argcmax){ if( min==max ) Util.badArg(argv[0],"requires exactly",min,"argument(s)"); else Util.badArg(argv[0],"requires",min,"-",max,"arguments."); @@ -254,7 +365,7 @@ class CloseDbCommand extends Command { if(argv.length>1){ String arg = argv[1]; if("all".equals(arg)){ - t.verbose(argv[0],"all dbs"); + t.verbose(argv[0]," all dbs"); t.closeAllDbs(); return; } @@ -265,7 +376,7 @@ class CloseDbCommand extends Command { id = t.getCurrentDbId(); } t.closeDb(id); - t.verbose(argv[0],"db",id); + t.verbose(argv[0]," db ",id); } } @@ -274,7 +385,7 @@ class DbCommand extends Command { argcCheck(argv,1); affirmNoContent(content); final sqlite3 db = t.setCurrentDb( Integer.parseInt(argv[1]) ); - t.verbose(argv[0],"set db to",db); + t.verbose(argv[0]," set db to ",db); } } @@ -284,7 +395,7 @@ class GlobCommand extends Command { argcCheck(argv,1); affirmNoContent(content); final String glob = argv[1].replace("#","[0-9]"); - t.verbose(argv[0],"is TODO. Pattern =",glob); + t.verbose(argv[0]," is TODO. Pattern = ",glob); } public GlobCommand(SQLTester t, String[] argv, String content) throws Exception{ this(false, t, argv, content); @@ -298,7 +409,7 @@ class NewDbCommand extends Command { String fname = argv[1]; Util.unlink(fname); final sqlite3 db = t.openDb(fname, true); - t.verbose(argv[0],"db",db); + t.verbose(argv[0]," db ",db); } } @@ -318,7 +429,7 @@ class NullCommand extends Command { argcCheck(argv,1); affirmNoContent(content); t.setNullValue(argv[1]); - //t.verbose(argv[0],argv[1]); + //t.verbose(argv[0]," ",argv[1]); } } @@ -327,9 +438,8 @@ class OpenDbCommand extends Command { argcCheck(argv,1); affirmNoContent(content); String fname = argv[1]; - Util.unlink(fname); final sqlite3 db = t.openDb(fname, false); - t.verbose(argv[0],"db",db); + t.verbose(argv[0]," db ",db); } } @@ -343,9 +453,37 @@ class PrintCommand extends Command { class ResultCommand extends Command { public ResultCommand(SQLTester t, String[] argv, String content) throws Exception{ - argcCheck(argv,0); - //t.verbose(argv[0],"command is TODO"); + argcCheck(argv,1,-1); + affirmNoContent(content); t.incrementTestCounter(); + final String sql = t.takeInputBuffer(); + //t.verbose(argv[0]," SQL =\n",sql); + int rc = t.execSql(null, true, true, sql); + final String result = t.getResultBufferText().trim(); + StringBuilder sbExpect = new StringBuilder(); + for(int i = 1; i < argv.length; ++i ){ + if( i>1 ) sbExpect.append(" "); + sbExpect.append( argv[i] ); + } + final String sArgs = sbExpect.toString(); + //t.verbose(argv[0]," rc = ",rc," result buffer:\n", result,"\nargs:\n",sArgs); + if( !result.equals(sArgs) ){ + Util.toss(TestFailure.class, argv[0]," comparison failed."); + } + } +} + +class RunCommand extends Command { + public RunCommand(SQLTester t, String[] argv, String content) throws Exception{ + argcCheck(argv,0); + affirmHasContent(content); + int rc = t.execSql(null, false, false, content); + if( 0!=rc ){ + sqlite3 db = t.getCurrentDb(); + String msg = sqlite3_errmsg(db); + t.verbose(argv[0]," non-fatal command error #",rc,": ", + msg,"\nfor SQL:\n",content); + } } } @@ -353,9 +491,10 @@ class TestCaseCommand extends Command { public TestCaseCommand(SQLTester t, String[] argv, String content) throws Exception{ argcCheck(argv,1); affirmHasContent(content); - t.resetInputBuffer(); - t.resetResultBuffer().append(content); - t.verbose(argv[0],"result buffer:",content); + // TODO: do something with the test name + t.clearResultBuffer(); + t.clearInputBuffer().append(content); + //t.verbose(argv[0]," input buffer: ",content); } } @@ -373,6 +512,7 @@ class CommandDispatcher { case "open": return OpenDbCommand.class; case "print": return PrintCommand.class; case "result": return ResultCommand.class; + case "run": return RunCommand.class; case "testcase": return TestCaseCommand.class; default: return null; } @@ -382,14 +522,17 @@ class CommandDispatcher { static void dispatch(SQLTester tester, String[] argv, String content) throws Exception{ final Class cmdClass = getCommandByName(argv[0]); if(null == cmdClass){ - throw new IllegalArgumentException( - "No command handler found for '"+argv[0]+"'" - ); + Util.toss(IllegalArgumentException.class, + "No command handler found for '"+argv[0]+"'"); } final java.lang.reflect.Constructor ctor = cmdClass.getConstructor(SQLTester.class, String[].class, String.class); - //tester.verbose("Running",argv[0],"..."); - ctor.newInstance(tester, argv, content); + try{ + //tester.verbose("Running ",argv[0]," with:\n", content); + ctor.newInstance(tester, argv, content); + }catch(java.lang.reflect.InvocationTargetException e){ + throw (Exception)e.getCause(); + } } } @@ -419,5 +562,4 @@ final class Util { /* ignore */ } } - } diff --git a/ext/jni/src/org/sqlite/jni/tester/TestScript.java b/ext/jni/src/org/sqlite/jni/tester/TestScript.java index c1e26e7a0a..d5af694faa 100644 --- a/ext/jni/src/org/sqlite/jni/tester/TestScript.java +++ b/ext/jni/src/org/sqlite/jni/tester/TestScript.java @@ -84,7 +84,7 @@ class TestScript { (because it contains certain content which indicates such). */ public static boolean shouldBeIgnored(String content){ - return content.indexOf("SCRIPT_MODULE_NAME")>=0 + return content.indexOf("SCRIPT_MODULE_NAME")<0 || content.indexOf("\n|")>=0; } @@ -123,16 +123,16 @@ class TestScript { s, Pattern.MULTILINE ); final Matcher m = p.matcher(tmp); - /*verbose("Pattern {{{",p.pattern(),"}}} with flags", - ""+p.flags(),"matches:" + /*verbose("Pattern {{{ ",p.pattern()," }}} with flags ", + p.flags()," matches:" );*/ int n = 0; - //while( m.find() ) verbose("#"+(++n)+"\t",m.group(0).trim()); + //while( m.find() ) verbose("#",(++n),"\t",m.group(0).trim()); tmp = m.replaceAll(""); } // Chunk the newly-cleaned text into individual commands and their input... final List rc = new ArrayList<>(); - final Pattern p = Pattern.compile("^--", Pattern.MULTILINE); + final Pattern p = Pattern.compile("^--[a-z]", Pattern.MULTILINE); final Matcher m = p.matcher(tmp); int ndxPrev = 0, pos = 0, i = 0; String chunk; @@ -147,7 +147,7 @@ class TestScript { } if( !chunk.isEmpty() ){ ++i; - //verbose("CHUNK #"+i,""+ndxPrev,"..",""+pos,chunk); + //verbose("CHUNK #",i," ",+ndxPrev,"..",pos,chunk); rc.add( chunk ); } ndxPrev = pos + 2; @@ -157,7 +157,7 @@ class TestScript { chunk = tmp.substring(ndxPrev, tmp.length()).trim(); if( !chunk.isEmpty() ){ ++i; - //verbose("CHUNK #"+(++i),chunk); + //verbose("CHUNK #",(++i)," ",chunk); rc.add( chunk ); } } @@ -168,13 +168,14 @@ class TestScript { Runs this test script in the context of the given tester object. */ public void run(SQLTester tester) throws Exception { + this.setVerbose(tester.isVerbose()); if( null==chunks ){ - verbose("This contains content which forces it to be ignored."); + outer.outln("This test contains content which forces it to be skipped."); }else{ int n = 0; for(String chunk : chunks){ ++n; - //verbose("#"+n,c).verbose(""); + //outer.verbose("CHUNK #",n," ",chunk,""); final String[] parts = chunk.split("\\n", 2); final String[] argv = parts[0].split("\\s+"); CommandDispatcher.dispatch( diff --git a/ext/jni/src/org/sqlite/jni/tester/test-script-interpreter.md b/ext/jni/src/org/sqlite/jni/tester/test-script-interpreter.md index 345210b1dd..ffaec1b132 100644 --- a/ext/jni/src/org/sqlite/jni/tester/test-script-interpreter.md +++ b/ext/jni/src/org/sqlite/jni/tester/test-script-interpreter.md @@ -76,11 +76,11 @@ commands: ### The --testcase command -Every test case starts with a --testcase command. The --testcase command -resets both the "input buffer" and the "result buffer". -The argument to the --testcase command is the -name of the test case. That test case name is used for logging and debugging -and when printing errors. +Every test case starts with a --testcase command. The --testcase +command resets both the "input buffer" and the "result buffer". The +argument to the --testcase command is the name of the test case. That +test case name is used for logging and debugging and when printing +errors. The input buffer is set to the body of the test case. ### The --result command diff --git a/ext/jni/src/tests/000_first.test b/ext/jni/src/tests/000_first.test index 9321576245..c838582145 100644 --- a/ext/jni/src/tests/000_first.test +++ b/ext/jni/src/tests/000_first.test @@ -1,4 +1,8 @@ -/* A script for testing the org.sqlite.jni.tester infrastructure */ +/* A script for testing the org.sqlite.jni.tester infrastructure +** +** SCRIPT_MODULE_NAME: 000_first +** +*/ # this line is ignored @@ -6,15 +10,19 @@ junk --new SQLTester.db --null zilch +--run +select 1; +select 2; +-- comment +intentional syntax error --oom --print This is from the print command. --- also ignored --testcase first -input for the first -command; ---result -hello world +select 'a', 'b'; +select 'a', 'b'; +--result a b a b --testcase second select 1 --glob # /* ignored */ @@ -22,3 +30,6 @@ select 1 select 'a' --notglob # --close +--open SQLTester.db +--print +Re-opened db. diff --git a/manifest b/manifest index 1616f77eaf..e879603840 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sa\sfew\swords\sof\sclarification\son\show\sthe\sSQLite\sTest\sScript\sInterpreter\nshould\sbe\sinitialized\sto\sstart\seach\stest\sscript. -D 2023-08-08T14:25:47.658 +C A\snumber\sof\sbaby\ssteps\sfor\sSQLTester.java.\sIt\scan\snow\shandle\sbasic\s--result\scases. +D 2023-08-08T14:40:47.725 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -230,9 +230,9 @@ F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c F ext/icu/README.txt 7ab7ced8ae78e3a645b57e78570ff589d4c672b71370f5aa9e1cd7024f400fc9 F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282 F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8 -F ext/jni/GNUmakefile 0d071597509ef4a9ac4b7712dac9ef29ded0db4819721c3b3c15e24d534827f6 +F ext/jni/GNUmakefile ce9587e2a4be50babc2ef4600e5c1016340a1187b9e5770c78000acdd02996bd F ext/jni/README.md e965674505e105626127ad45e628e4d19fcd379cdafc4d23c814c1ac2c55681d -F ext/jni/src/c/sqlite3-jni.c d51d930573dc4b13a02a66da9281b3ef814aeabd4c294bf3d7fc499093237224 +F ext/jni/src/c/sqlite3-jni.c ae704d2486e1213ecdc78bbf62d00573d41409d375cc7a3b8e4720f8a764d0cd F ext/jni/src/c/sqlite3-jni.h bc3ecd3f6e479fd45b80214f6256584cc599336ae222822fa1e603c22ff1fb19 F ext/jni/src/org/sqlite/jni/Authorizer.java 1308988f7f40579ea0e4deeaec3c6be971630566bd021c31367fe3f5140db892 F ext/jni/src/org/sqlite/jni/AutoExtension.java 3409ad8954d6466bf772e6be9379e0e337312b446b668287062845755a16844d @@ -249,10 +249,11 @@ F ext/jni/src/org/sqlite/jni/Fts5Tokenizer.java 91489893596b6528c0df5cd7180bd5b5 F ext/jni/src/org/sqlite/jni/NativePointerHolder.java 9c5d901cce4f7e57c3d623f4e2476f9f79a8eed6e51b2a603f37866018e040ee F ext/jni/src/org/sqlite/jni/OutputPointer.java ebdd33d48064c3302d0d4a6dd345562a967f8420edad7c7509403be277d076a0 F ext/jni/src/org/sqlite/jni/ProgressHandler.java 6f62053a828a572de809828b1ee495380677e87daa29a1c57a0e2c06b0a131dc +F ext/jni/src/org/sqlite/jni/ResultCode.java 7cdf993f2037ab7bd244c9a34dbaef2ace3beb5da5d7e7fda5c6f67634ceb647 F ext/jni/src/org/sqlite/jni/RollbackHook.java b04c8abcc6ade44a8a57129e33765793f69df0ba909e49ba18d73f4268d92564 F ext/jni/src/org/sqlite/jni/SQLFunction.java 09ce81c1c637e31c3a830d4c859cce95d65f5e02ff45f8bd1985b3479381bc46 F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 3681e6ea94973ce1f7facd6887853a4ae5657a9274dd06279b586dbf77f36c2d -F ext/jni/src/org/sqlite/jni/Tester1.java 57404879fbea78f0b405b7643abb03dad0a6ce6cea9ec0c4ef55ea40267be565 +F ext/jni/src/org/sqlite/jni/Tester1.java 22dca3ab0d93951382230f71e3cfb65898b80f12704a018c8ab9062df609b4fe F ext/jni/src/org/sqlite/jni/TesterFts5.java cf2d687baafffdeba219b77cf611fd47a0556248820ea794ae3e8259bfbdc5ee F ext/jni/src/org/sqlite/jni/Tracer.java a5cece9f947b0af27669b8baec300b6dd7ff859c3e6a6e4a1bd8b50f9714775d F ext/jni/src/org/sqlite/jni/UpdateHook.java e58645a1727f8a9bbe72dc072ec5b40d9f9362cb0aa24acfe93f49ff56a9016d @@ -264,11 +265,11 @@ F ext/jni/src/org/sqlite/jni/sqlite3.java 62b1b81935ccf3393472d17cb883dc5ff39c38 F ext/jni/src/org/sqlite/jni/sqlite3_context.java d26573fc7b309228cb49786e9078597d96232257defa955a3425d10897bca810 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/Outer.java 07b5d68bdc4a01173f2515954a250dce6affcc4efb85b1ac50d24ad05b166bf4 -F ext/jni/src/org/sqlite/jni/tester/SQLTester.java 2261be136c31a432a7416fa86810b97a28a2ad8012463ae68f0975ceac38b42f -F ext/jni/src/org/sqlite/jni/tester/TestScript.java 38652e01cab9c07b20741829f54ef2f4a5c25a73b2c77213dd9198d4268acc51 -F ext/jni/src/org/sqlite/jni/tester/test-script-interpreter.md a37dd71d1bd24773699b6efaa7ee37e616ae6c2e6554e7d46e0f759dde71f3e3 -F ext/jni/src/tests/000_first.test f58d5f22e2db31b20c6e744a247d14222508c88ed876b03a723c89f540948518 +F ext/jni/src/org/sqlite/jni/tester/Outer.java 3d9c40f8ed58ec0df05ca160986ea06ec84ec1f338b069cfba9604bbba467a01 +F ext/jni/src/org/sqlite/jni/tester/SQLTester.java f16d95e0eb89723010de955197164ea5da58a83852499004ec510f778681a8da +F ext/jni/src/org/sqlite/jni/tester/TestScript.java 52350fb458d7d2816377a824c18c498c4a97f0026b64278f62ff1c382a92a070 +F ext/jni/src/org/sqlite/jni/tester/test-script-interpreter.md e66ee0de4f6b805afe7486f6826d4e1f26b449066c2ec6550b314950369a4ea2 +F ext/jni/src/tests/000_first.test 752aca36279f9b0ceedaf15a4ce6bc9e0b7f9ca2749287e204d81ca2f7e41e6f F ext/jni/src/tests/010_ignored.test ce2de6742ff1bf98d8976fda0f260ff3d280e8f8c0a99309fb59fcfef2556fcd F ext/lsm1/Makefile a553b728bba6c11201b795188c5708915cc4290f02b7df6ba7e8c4c943fd5cd9 F ext/lsm1/Makefile.msc f8c878b467232226de288da320e1ac71c131f5ec91e08b21f502303347260013 @@ -2089,8 +2090,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 94628f88b5cc82832f0ca2b00fd5346bfe99323097c6e659c5ac818c4e31d3e9 -R 9b39d488601a6f92f9f4935ca5c0b938 -U drh -Z 2b5a8bdcd64c73cfaa2188a49297111d +P 3aa2b5a5cadb214dc64a3db412b7dfdd805abd8681b61da857b886cba3b937b5 +R 879a6e39ab778945869b54b1f498f7c6 +U stephan +Z d614dd3e6aa20cfdef1208a3dc72efbf # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 13b058113a..19673fabb6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3aa2b5a5cadb214dc64a3db412b7dfdd805abd8681b61da857b886cba3b937b5 \ No newline at end of file +0404f688f6a22b6bbe009de1bee3341ca00e19e2cc32081265cf151876dc032f \ No newline at end of file