From 6a61a19f9aa906ac7620ad08ae60c4380e1a46e8 Mon Sep 17 00:00:00 2001 From: stephan Date: Thu, 10 Aug 2023 05:14:22 +0000 Subject: [PATCH] Initial version of REQUIRED_PROPERTIES support for SQLTester, with TEMPSTORE_(FILE/MEM) and RECURSIVE_TRIGGERS options. FossilOrigin-Name: 48d16c9d2fe5f54b09004b4f09759c4e2ad247ae84130feb557951e32f48976a --- ext/jni/GNUmakefile | 2 + .../src/org/sqlite/jni/tester/SQLTester.java | 108 ++++++++++++------ ext/jni/src/tests/000-000-sanity.test | 7 +- manifest | 16 +-- manifest.uuid | 2 +- 5 files changed, 90 insertions(+), 45 deletions(-) diff --git a/ext/jni/GNUmakefile b/ext/jni/GNUmakefile index d081616364..0c522ec8b0 100644 --- a/ext/jni/GNUmakefile +++ b/ext/jni/GNUmakefile @@ -236,6 +236,8 @@ tester: @echo "SQLTester support is disabled. Build with enable.tester=1 to enable it." endif +tests: test tester + $(package.jar): $(CLASS_FILES) $(MAKEFILE) rm -f $(dir.src)/c/*~ $(dir.src.jni)/*~ $(bin.jar) -cfe $@ org.sqlite.Tester1 -C src org -C src c diff --git a/ext/jni/src/org/sqlite/jni/tester/SQLTester.java b/ext/jni/src/org/sqlite/jni/tester/SQLTester.java index 276104d4df..34b8cd5adc 100644 --- a/ext/jni/src/org/sqlite/jni/tester/SQLTester.java +++ b/ext/jni/src/org/sqlite/jni/tester/SQLTester.java @@ -69,6 +69,12 @@ class SQLTesterException extends RuntimeException { final boolean isFatal(){ return bFatal; } } +class DbException extends SQLTesterException { + protected DbException(sqlite3 db, int rc){ + super("DB error #"+rc+": "+sqlite3_errmsg(db),true); + } +} + /** Generic test-failed exception. */ @@ -110,27 +116,19 @@ class Outer { System.out.print(val); } - static void outln(Object val){ - System.out.println(val); - } - - @SuppressWarnings("unchecked") Outer out(Object... vals){ for(Object v : vals) out(v); return this; } - @SuppressWarnings("unchecked") Outer outln(Object... vals){ out(vals).out("\n"); return this; } - @SuppressWarnings("unchecked") Outer verbose(Object... vals){ if(verbosity>0){ - out("VERBOSE",(verbosity>1 ? "+: " : ": ")); - outln(vals); + out("VERBOSE",(verbosity>1 ? "+: " : ": ")).outln(vals); } return this; } @@ -169,6 +167,8 @@ public class SQLTester { private final StringBuilder inputBuffer = new StringBuilder(); //! Test result buffer. private final StringBuilder resultBuffer = new StringBuilder(); + //! Buffer for REQUIRED_PROPERTIES pragmas. + private final StringBuilder dbInitSql = new StringBuilder(); //! Output representation of SQL NULL. private String nullView = "nil"; //! Total tests run. @@ -205,17 +205,14 @@ public class SQLTester { void outputColumnNames(boolean b){ emitColNames = b; } - @SuppressWarnings("unchecked") void verbose(Object... vals){ outer.verbose(vals); } - @SuppressWarnings("unchecked") void outln(Object... vals){ outer.outln(vals); } - @SuppressWarnings("unchecked") void out(Object... vals){ outer.out(vals); } @@ -276,6 +273,14 @@ public class SQLTester { if(addNL) resultBuffer.append('\n'); } + void appendDbInitSql(String n) throws SQLTesterException { + dbInitSql.append(n).append('\n'); + if( null!=getCurrentDb() ){ + //outln("RUNNING DB INIT CODE: ",n); + execSql(null, true, ResultBufferMode.NONE, null, n); + } + } + String getInputText(){ return inputBuffer.toString(); } String getResultText(){ return resultBuffer.toString(); } @@ -333,11 +338,16 @@ public class SQLTester { final OutputPointer.sqlite3 out = new OutputPointer.sqlite3(); int rc = sqlite3_open_v2(name, out, flags, null); final sqlite3 db = out.getValue(); + if( 0==rc && dbInitSql.length() > 0){ + //outln("RUNNING DB INIT CODE: ",dbInitSql.toString()); + rc = execSql(db, false, ResultBufferMode.NONE, + null, dbInitSql.toString()); + } if( 0!=rc ){ final String msg = sqlite3_errmsg(db); sqlite3_close(db); - Util.toss(SQLTesterException.class, "db open failed with code ", - rc," and message: ",msg); + throw new SQLTesterException("db open failed with code "+ + rc+" and message: "+msg); } return aDb[iCurrentDb] = db; } @@ -355,6 +365,7 @@ public class SQLTester { void reset(){ clearInputBuffer(); clearResultBuffer(); + clearBuffer(dbInitSql); closeAllDbs(); nTest = 0; nullView = "nil"; @@ -440,7 +451,7 @@ public class SQLTester { public int execSql(sqlite3 db, boolean throwOnError, ResultBufferMode appendMode, ResultRowMode lineMode, - String sql) throws Exception { + String sql) throws SQLTesterException { final OutputPointer.Int32 oTail = new OutputPointer.Int32(); final OutputPointer.sqlite3_stmt outStmt = new OutputPointer.sqlite3_stmt(); final byte[] sqlUtf8 = sql.getBytes(StandardCharsets.UTF_8); @@ -465,8 +476,7 @@ public class SQLTester { 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)); + throw new DbException(db, rc); }else if( null!=sb ){ appendDbErr(db, sb, rc); } @@ -495,7 +505,7 @@ public class SQLTester { sb.append( escapeSqlValue(colName) ); break; default: - Util.toss(RuntimeException.class, "Unhandled ResultBufferMode."); + throw new SQLTesterException("Unhandled ResultBufferMode: "+appendMode); } sb.append(' '); } @@ -512,7 +522,7 @@ public class SQLTester { sb.append( escapeSqlValue(val) ); break; default: - Util.toss(RuntimeException.class, "Unhandled ResultBufferMode."); + throw new SQLTesterException("Unhandled ResultBufferMode: "+appendMode); } } if( ResultRowMode.NEWLINE == lineMode ){ @@ -537,8 +547,7 @@ public class SQLTester { sqlite3_finalize(stmt); } if( 0!=rc && throwOnError ){ - Util.toss(RuntimeException.class, "db op failed with rc=" - +rc+": "+sqlite3_errmsg(db)); + throw new DbException(db, rc); } return rc; } @@ -875,7 +884,7 @@ class TableResultCommand extends Command { public void process(SQLTester t, TestScript ts, String[] argv) throws Exception{ argcCheck(ts,argv,0); t.incrementTestCounter(); - String body = ts.fetchCommandBody(); + String body = ts.fetchCommandBody(t); if( null==body ) ts.toss("Missing ",argv[0]," body."); body = body.trim(); if( !body.endsWith("\n--end") ){ @@ -1031,13 +1040,12 @@ class TestScript { return "["+(moduleName==null ? filename : moduleName)+"] line "+ cur.lineNo; } - @SuppressWarnings("unchecked") private TestScript verboseN(int level, Object... vals){ final int verbosity = outer.getVerbosity(); if(verbosity>=level){ - outer.out("VERBOSE",(verbosity>1 ? "+ " : " "), - getOutputPrefix(),": ") - .outln(vals); + outer.out( + "VERBOSE", (verbosity>1 ? "+ " : " "), getOutputPrefix(), ": " + ).outln(vals); } return this; } @@ -1045,10 +1053,8 @@ class TestScript { private TestScript verbose1(Object... vals){return verboseN(1,vals);} private TestScript verbose2(Object... vals){return verboseN(2,vals);} - @SuppressWarnings("unchecked") public TestScript warn(Object... vals){ - outer.out("WARNING ", getOutputPrefix(),": ") - .outln(vals); + outer.out("WARNING ", getOutputPrefix(),": ").outln(vals); return this; } @@ -1173,6 +1179,34 @@ class TestScript { cur.lineNo = cur.putbackLineNo; } + private boolean checkRequiredProperties(SQLTester t, String[] props) throws SQLTesterException{ + int nOk = 0; + for(String rp : props){ + verbose1("REQUIRED_PROPERTIES: ",rp); + switch(rp){ + case "RECURSIVE_TRIGGERS": + t.appendDbInitSql("pragma recursive_triggers=on;"); + ++nOk; + break; + case "TEMPSTORE_FILE": + /* This _assumes_ that the lib is built with SQLITE_TEMP_STORE=1 or 2, + which we just happen to know is the case */ + t.appendDbInitSql("pragma temp_store=1;"); + ++nOk; + break; + case "TEMPSTORE_MEM": + /* This _assumes_ that the lib is built with SQLITE_TEMP_STORE=1 or 2, + which we just happen to know is the case */ + t.appendDbInitSql("pragma temp_store=0;"); + ++nOk; + break; + default: + break; + } + } + return props.length == nOk; + } + private static final Pattern patternRequiredProperties = Pattern.compile(" REQUIRED_PROPERTIES:[ \\t]*(\\S.*)\\s*$"); private static final Pattern patternScriptModuleName = @@ -1188,7 +1222,9 @@ class TestScript { a description of it is returned and processing of the test must end immediately. */ - private void checkForDirective(String line) throws IncompatibleDirective { + private void checkForDirective( + SQLTester tester, String line + ) throws IncompatibleDirective { if(line.startsWith("#")){ throw new IncompatibleDirective(this, "C-preprocessor input: "+line); }else if(line.startsWith("---")){ @@ -1201,7 +1237,10 @@ class TestScript { } m = patternRequiredProperties.matcher(line); if( m.find() ){ - throw new IncompatibleDirective(this, "REQUIRED_PROPERTIES: "+m.group(1)); + final String rp = m.group(1); + if( ! checkRequiredProperties( tester, rp.split("\\s+") ) ){ + throw new IncompatibleDirective(this, "REQUIRED_PROPERTIES: "+rp); + } } m = patternMixedModuleName.matcher(line); if( m.find() ){ @@ -1240,11 +1279,11 @@ class TestScript { which do not match a known command name are considered to be content, not commands. */ - String fetchCommandBody(){ + String fetchCommandBody(SQLTester tester){ final StringBuilder sb = new StringBuilder(); String line; while( (null != (line = peekLine())) ){ - checkForDirective(line); + checkForDirective(tester, line); if( !isCommandLine(line, true) ){ sb.append(line).append("\n"); consumePeeked(); @@ -1274,7 +1313,6 @@ class TestScript { /** Runs this test script in the context of the given tester object. */ - @SuppressWarnings("unchecked") public boolean run(SQLTester tester) throws Exception { reset(); setVerbosity(tester.getVerbosity()); @@ -1282,7 +1320,7 @@ class TestScript { String[] argv; while( null != (line = getLine()) ){ //verbose(line); - checkForDirective(line); + checkForDirective(tester, line); argv = getCommandArgv(line); if( null!=argv ){ processCommand(tester, argv); diff --git a/ext/jni/src/tests/000-000-sanity.test b/ext/jni/src/tests/000-000-sanity.test index 905882dc3b..aa37ae79ee 100644 --- a/ext/jni/src/tests/000-000-sanity.test +++ b/ext/jni/src/tests/000-000-sanity.test @@ -5,10 +5,15 @@ ** xMIXED_MODULE_NAME: mixed-module ** xMODULE_NAME: module-name ** xREQUIRED_PROPERTIES: small fast reliable -** REQUIRED_PROPERTIES: +** REQUIRED_PROPERTIES: RECURSIVE_TRIGGERS +** REQUIRED_PROPERTIES: TEMPSTORE_MEM TEMPSTORE_FILE ** */ --print starting up 😃 +--testcase required-props +PRAGMA recursive_triggers; +PRAGMA temp_store; +--result 1 1 --close all --oom --db 0 diff --git a/manifest b/manifest index 61d721bb1d..58fe6d30f1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Generic\scleanups\sand\sfixes\sin\sSQLTester. -D 2023-08-10T04:24:12.767 +C Initial\sversion\sof\sREQUIRED_PROPERTIES\ssupport\sfor\sSQLTester,\swith\sTEMPSTORE_(FILE/MEM)\sand\sRECURSIVE_TRIGGERS\soptions. +D 2023-08-10T05:14:22.157 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -231,7 +231,7 @@ 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 ce6c7af0a6f0d9ab1502606d191ea7025969b37bc6de67ae93e294ac2ac5d736 +F ext/jni/GNUmakefile d69b26fb294b7a86a2f838012f4161311c06d607680b86ecdb1334f6f78c165c F ext/jni/README.md e965674505e105626127ad45e628e4d19fcd379cdafc4d23c814c1ac2c55681d F ext/jni/src/c/sqlite3-jni.c 3fda1e271054835adec606b4dbaaa6db5ae120b59a72308e4b906739c0a27a87 F ext/jni/src/c/sqlite3-jni.h b19a104e0566440af566366cea72188bd994a96ba85c3f196acaa6f4a4609a55 @@ -266,9 +266,9 @@ 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/SQLTester.java 5b940aec0939ef766d11f5123b899248e0a3c05f2dc2bd0df26d07b0964c11c0 +F ext/jni/src/org/sqlite/jni/tester/SQLTester.java 6eb2db0465cb3d69f59aadab6d2be0aa8aba3181d1f28aa7e1ca21eb840b554e F ext/jni/src/org/sqlite/jni/tester/test-script-interpreter.md ab7169b08566a082ef55c9ef8a553827f99958ed3e076f31eef757563fae51ba -F ext/jni/src/tests/000-000-sanity.test de89692155bee1bb35120aced6871dd6562014d0cd7c1dcf173297d8bbc03002 +F ext/jni/src/tests/000-000-sanity.test 35817746f1909cc9af5d3e890ee94a43c47ce47127da9cca7d39b0e132d36c84 F ext/jni/src/tests/000-001-ignored.test e17e874c6ab3c437f1293d88093cf06286083b65bf162317f91bbfd92f961b70 F ext/lsm1/Makefile a553b728bba6c11201b795188c5708915cc4290f02b7df6ba7e8c4c943fd5cd9 F ext/lsm1/Makefile.msc f8c878b467232226de288da320e1ac71c131f5ec91e08b21f502303347260013 @@ -2089,8 +2089,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 3c3fea6bf284721ac376e2ab5a757cf30245dd39264aaf98a8d6cd5575484275 -R e0dcea60ec5219f4cbd640eec233c812 +P fc5d3cc30d2b96da42ea10dfb39f1631ff93b8384514fffd641b343df51da2a6 +R 9fb1e3deddfffb0e48b6c7087aa53315 U stephan -Z df3f8d652fff3c111483e31409cde9e4 +Z 7f9ad93c32ab9294dee15aaecfd30d3b # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index a95933c56d..44eb2be827 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -fc5d3cc30d2b96da42ea10dfb39f1631ff93b8384514fffd641b343df51da2a6 \ No newline at end of file +48d16c9d2fe5f54b09004b4f09759c4e2ad247ae84130feb557951e32f48976a \ No newline at end of file