From: stephan Date: Mon, 16 Oct 2023 13:04:42 +0000 (+0000) Subject: JNI: initial draft (untested - requires more infrastructure first) of a UDF argument... X-Git-Tag: version-3.44.0~104 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f2d7e961d9f8f67e183328ca40262e1a7c115f8d;p=thirdparty%2Fsqlite.git JNI: initial draft (untested - requires more infrastructure first) of a UDF argument/result-handling interface which completely hides the C-style API from the client. FossilOrigin-Name: 43b10a5cf9cb8be53d62914f340d533e60a70bf4caa8b9b91c0f867fa0f70493 --- diff --git a/ext/jni/GNUmakefile b/ext/jni/GNUmakefile index cc53cf8d15..e7f083a756 100644 --- a/ext/jni/GNUmakefile +++ b/ext/jni/GNUmakefile @@ -113,6 +113,7 @@ JAVA_FILES.main := $(patsubst %,$(dir.src.jni)/annotation/%,\ sqlite3_stmt.java \ sqlite3_value.java \ ) $(patsubst %,$(dir.src.jni)/wrapper1/%,\ + SqlFunction.java \ Sqlite.java \ SqliteException.java \ ) diff --git a/ext/jni/src/org/sqlite/jni/capi/CApi.java b/ext/jni/src/org/sqlite/jni/capi/CApi.java index 051e28a899..a721844744 100644 --- a/ext/jni/src/org/sqlite/jni/capi/CApi.java +++ b/ext/jni/src/org/sqlite/jni/capi/CApi.java @@ -1635,7 +1635,8 @@ public final class CApi { public static void sqlite3_result_text16( @NotNull sqlite3_context cx, @Nullable byte[] utf16 ){ - sqlite3_result_text64(cx, utf16, utf16.length, SQLITE_UTF16); + if(null == utf16) sqlite3_result_null(cx); + else sqlite3_result_text64(cx, utf16, utf16.length, SQLITE_UTF16); } public static void sqlite3_result_text16( diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java b/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java new file mode 100644 index 0000000000..4be6dcbe23 --- /dev/null +++ b/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java @@ -0,0 +1,153 @@ +/* +** 2023-10-16 +** +** 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 wrapper1 interface for sqlite3. +*/ +package org.sqlite.jni.wrapper1; +import org.sqlite.jni.capi.CApi; +import org.sqlite.jni.annotation.*; +import org.sqlite.jni.capi.sqlite3_context; +import org.sqlite.jni.capi.sqlite3_value; + +/** + EXPERIMENTAL/INCOMPLETE/UNTESTED +*/ +public interface SqlFunction { + + /** + EXPERIMENTAL/INCOMPLETE/UNTESTED. An attempt at hiding UDF-side + uses of the sqlite3_context and sqlite3_value classes from a + high-level wrapper. This level of indirection requires more than + twice as much Java code (in this API, not client-side) as using + the lower-level API. Client-side it's roughly the same amount of + code. + */ + public final static class Arguments implements Iterable{ + private final sqlite3_context cx; + private final sqlite3_value args[]; + + /** + Must be passed the context and arguments for the UDF call this + object is wrapping. + */ + Arguments(@NotNull sqlite3_context cx, @NotNull sqlite3_value args[]){ + this.cx = cx; + this.args = args; + } + + /** + Wrapper for a single SqlFunction argument. Primarily intended + for eventual use with the Arguments class's Iterable interface. + */ + public final static class Arg { + private final Arguments a; + private final int ndx; + /* Only for use by the Arguments class. */ + private Arg(@NotNull Arguments a, int ndx){ + this.a = a; + this.ndx = ndx; + } + /** Returns this argument's index in its parent argument list. */ + public int getIndex(){return ndx;} + + public int getInt(){return a.getInt(ndx);} + public long getInt64(){return a.getInt64(ndx);} + public double getDouble(){return a.getDouble(ndx);} + public byte[] getBlob(){return a.getBlob(ndx);} + public byte[] getText(){return a.getText(ndx);} + public String getText16(){return a.getText16(ndx);} + public int getBytes(){return a.getBytes(ndx);} + public int getBytes16(){return a.getBytes16(ndx);} + public Object getObject(){return a.getObject(ndx);} + public T getObjectCasted(Class type){ return a.getObjectCasted(ndx, type); } + public int getType(){return a.getType(ndx);} + public Object getAuxData(){return a.getAuxData(ndx);} + public void setAuxData(Object o){a.setAuxData(ndx, o);} + } + + //! Untested! + @Override + public java.util.Iterator iterator(){ + Arg[] proxies = new Arg[args.length]; + for( int i = 0; i < args.length; ++i ){ + proxies[i] = new Arg(this, i); + } + return java.util.Arrays.stream(proxies).iterator(); + } + + /** + Returns the sqlite3_value at the given argument index or throws + an IllegalArgumentException exception if ndx is out of range. + */ + private sqlite3_value valueAt(int ndx){ + if(ndx<0 || ndx>=args.length){ + throw new IllegalArgumentException( + "SQL function argument index "+ndx+" is out of range." + ); + } + return args[ndx]; + } + + public int getArgCount(){ return args.length; } + + public int getInt(int arg){return CApi.sqlite3_value_int(valueAt(arg));} + public long getInt64(int arg){return CApi.sqlite3_value_int64(valueAt(arg));} + public double getDouble(int arg){return CApi.sqlite3_value_double(valueAt(arg));} + public byte[] getBlob(int arg){return CApi.sqlite3_value_blob(valueAt(arg));} + public byte[] getText(int arg){return CApi.sqlite3_value_text(valueAt(arg));} + public String getText16(int arg){return CApi.sqlite3_value_text16(valueAt(arg));} + public int getBytes(int arg){return CApi.sqlite3_value_bytes(valueAt(arg));} + public int getBytes16(int arg){return CApi.sqlite3_value_bytes16(valueAt(arg));} + public Object getObject(int arg){return CApi.sqlite3_value_java_object(valueAt(arg));} + public T getObjectCasted(int arg, Class type){ + return CApi.sqlite3_value_java_casted(valueAt(arg), type); + } + + public int getType(int arg){return CApi.sqlite3_value_type(valueAt(arg));} + + public void resultInt(int v){ CApi.sqlite3_result_int(cx, v); } + public void resultInt64(long v){ CApi.sqlite3_result_int64(cx, v); } + public void resultDouble(double v){ CApi.sqlite3_result_double(cx, v); } + public void resultError(String msg){CApi.sqlite3_result_error(cx, msg);} + public void resultError(Exception e){CApi.sqlite3_result_error(cx, e);} + public void resultErrorTooBig(){CApi.sqlite3_result_error_toobig(cx);} + public void resultErrorCode(int rc){CApi.sqlite3_result_error_code(cx, rc);} + public void resultObject(Object o){CApi.sqlite3_result_java_object(cx, o);} + public void resultArg(int argNdx){CApi.sqlite3_result_value(cx, valueAt(argNdx));} + public void resultZeroBlob(long n){ + // Throw on error? If n is too big, + // sqlite3_result_error_toobig() is automatically called. + CApi.sqlite3_result_zeroblob64(cx, n); + } + + public void resultBlob(byte[] blob){CApi.sqlite3_result_blob(cx, blob);} + public void resultText(byte[] utf8){CApi.sqlite3_result_text(cx, utf8);} + public void resultText(String txt){CApi.sqlite3_result_text(cx, txt);} + public void resultText16(byte[] utf16){CApi.sqlite3_result_text16(cx, utf16);} + public void resultText16(String txt){CApi.sqlite3_result_text16(cx, txt);} + + public void setAuxData(int arg, Object o){ + /* From the API docs: https://www.sqlite.org/c3ref/get_auxdata.html + + The value of the N parameter to these interfaces should be + non-negative. Future enhancements may make use of negative N + values to define new kinds of function caching behavior. + */ + valueAt(arg); + CApi.sqlite3_set_auxdata(cx, arg, o); + } + + public Object getAuxData(int arg){ + valueAt(arg); + return CApi.sqlite3_get_auxdata(cx, arg); + } + } +} diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java index aaa1fe67fc..b6a4bda108 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** This file is part of the JNI bindings for the sqlite3 C API. +** This file is part of the wrapper1 interface for sqlite3. */ package org.sqlite.jni.wrapper1; import java.nio.charset.StandardCharsets; diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java b/ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java index 87b0d3737f..111f004db4 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** This file is part of the JNI bindings for the sqlite3 C API. +** This file is part of the wrapper1 interface for sqlite3. */ package org.sqlite.jni.wrapper1; import static org.sqlite.jni.capi.CApi.*; @@ -54,7 +54,7 @@ public final class SqliteException extends java.lang.RuntimeException { a failed db-open operation, and the place(s) where that can happen are inside this library, not client-level code. */ - public SqliteException(sqlite3 db){ + SqliteException(sqlite3 db){ super(sqlite3_errmsg(db)); errCode = sqlite3_errcode(db); xerrCode = sqlite3_extended_errcode(db); @@ -63,8 +63,8 @@ public final class SqliteException extends java.lang.RuntimeException { } /** - Records the current error state of db (which must not be null and must - refer to an open database) then closes it. + Records the current error state of db (which must not be null and + must refer to an open database). */ public SqliteException(Sqlite db){ this(db.nativeHandle()); diff --git a/manifest b/manifest index 891a5e2aef..978dd1cded 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C JNI:\scleanups\sin\sTester2\sand\supdate\sthe\sjar\smakefile\starget\sto\saccount\sfor\s[9fcdf96adca2]. -D 2023-10-16T10:38:34.125 +C JNI:\sinitial\sdraft\s(untested\s-\srequires\smore\sinfrastructure\sfirst)\sof\sa\sUDF\sargument/result-handling\sinterface\swhich\scompletely\shides\sthe\sC-style\sAPI\sfrom\sthe\sclient. +D 2023-10-16T13:04:42.394 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -235,7 +235,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 bf7dbc177903a180aaa45540483d49185abb5e032c08773a36eb7983281b7ab0 +F ext/jni/GNUmakefile 069399d471af948a4293e79135907a8d58daa09e59b4cc1b9cc1a5124c87f589 F ext/jni/README.md ef9ac115e97704ea995d743b4a8334e23c659e5534c3b64065a5405256d5f2f4 F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa F ext/jni/src/c/sqlite3-jni.c 8d32ca0598a11370a9e92a6d111f38934c225056b42b13512175acf6e37eed4c @@ -248,7 +248,7 @@ F ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java bc29e986c866c2ddbbb9f93 F ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java 7ed409d5449684616cc924534e22ff6b07d361f12ad904b69ecb10e0568a8013 F ext/jni/src/org/sqlite/jni/capi/AutoExtensionCallback.java 74cc4998a73d6563542ecb90804a3c4f4e828cb4bd69e61226d1a51f4646e759 F ext/jni/src/org/sqlite/jni/capi/BusyHandlerCallback.java 7b8e19810c42b0ad21a04b5d8c804b32ee5905d137148703f16a75b612c380ca -F ext/jni/src/org/sqlite/jni/capi/CApi.java 82993492793fd946e2b9b9a244fe5ac39647292b449cac7453ea49031c00f517 +F ext/jni/src/org/sqlite/jni/capi/CApi.java 5d754b4bb57852d006ad046b2860eb23ba406f800846460b26beee5172df4fc3 F ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java 0bfd6e56e8265c2f05c9207665707285534d78f8466ef0e0430c65677f00943d F ext/jni/src/org/sqlite/jni/capi/CollationCallback.java e29bcfc540fdd343e2f5cca4d27235113f2886acb13380686756d5cabdfd065a F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java f81cf10b79c52f9b2e9247d523d29ae48863935f60420eae35f257c38c80ce95 @@ -289,8 +289,9 @@ F ext/jni/src/org/sqlite/jni/fts5/fts5_api.java a8e88c3783d21cec51b0748568a96653 F ext/jni/src/org/sqlite/jni/fts5/fts5_extension_function.java 9e2b954d210d572552b28aca523b272fae14bd41e318921b22f65b728d5bf978 F ext/jni/src/org/sqlite/jni/fts5/fts5_tokenizer.java 92bdaa3893bd684533004d64ade23d329843f809cd0d0f4f1a2856da6e6b4d90 F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe59004a1485311c50a13edbf18c79a6ff9160030e -F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java f05ee6c52b039bb5b65e49ac90710f58cbfc95e13e5a8d46a7fe5106d5819dad -F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 039f6f858cd6a0f59a41f0823d638959d8f47e7098dd469c486988494d651896 +F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 40a9f4f8a7a72b90b12baa82d26ba16376a5758009739b069c1863201770e816 +F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 2bc90edc4c25225e018ed600b5eff43ba0485be85db08f8b6b35246372fdac20 +F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 1386f7b753134fc12253ce2fbbc448ba8c970567fac01a3356cb672e14408d73 F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java aee8301f92256ab8572043cf5de2a35afda057d2a6ff09970a2f84a90305471e F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43443408f3000139478c4dc745 F ext/jni/src/tests/000-001-ignored.test e17e874c6ab3c437f1293d88093cf06286083b65bf162317f91bbfd92f961b70 @@ -2128,8 +2129,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 9fcdf96adca25cc2d2f4b75ec4eea94254fb9671c5ba63b88213d7f62dedff1b -R 376c33c5d6d18c40ea3627a195e8192d +P abc82bf4b800dde1b6e6172c7be816edb391fdbed5dbd2749f54623fdf3bf8e6 +R 287c21329f3772a974832101be3bffee U stephan -Z 0f3f56205e0babb2af321d2f9efdae5a +Z a4e77b564ffa0b3970c5e65a1253c53d # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 11d064f42b..2eac8e0f45 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -abc82bf4b800dde1b6e6172c7be816edb391fdbed5dbd2749f54623fdf3bf8e6 \ No newline at end of file +43b10a5cf9cb8be53d62914f340d533e60a70bf4caa8b9b91c0f867fa0f70493 \ No newline at end of file