From: stephan Date: Mon, 16 Oct 2023 16:04:23 +0000 (+0000) Subject: JNI: add aggregate function support to the wrapper1 API. X-Git-Tag: version-3.44.0~102 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=08747d44a27c47735c050bca68193677ef39b5ec;p=thirdparty%2Fsqlite.git JNI: add aggregate function support to the wrapper1 API. FossilOrigin-Name: 15b28b340a5c5efdbfe3fbed16ee0b699561edaeebb77446addf2374bdf9357e --- diff --git a/ext/jni/GNUmakefile b/ext/jni/GNUmakefile index e7f083a756..19a5080471 100644 --- a/ext/jni/GNUmakefile +++ b/ext/jni/GNUmakefile @@ -106,6 +106,7 @@ JAVA_FILES.main := $(patsubst %,$(dir.src.jni)/annotation/%,\ TableColumnMetadata.java \ TraceV2Callback.java \ UpdateHookCallback.java \ + ValueHolder.java \ WindowFunction.java \ XDestroyCallback.java \ sqlite3.java \ @@ -113,9 +114,12 @@ JAVA_FILES.main := $(patsubst %,$(dir.src.jni)/annotation/%,\ sqlite3_stmt.java \ sqlite3_value.java \ ) $(patsubst %,$(dir.src.jni)/wrapper1/%,\ + AggregateFunction.java \ + ScalarFunction.java \ SqlFunction.java \ Sqlite.java \ SqliteException.java \ + ValueHolder.java \ ) JAVA_FILES.unittest := $(patsubst %,$(dir.src.jni)/%,\ diff --git a/ext/jni/src/org/sqlite/jni/capi/Tester1.java b/ext/jni/src/org/sqlite/jni/capi/Tester1.java index 5c982ea5ed..6fb28e65b9 100644 --- a/ext/jni/src/org/sqlite/jni/capi/Tester1.java +++ b/ext/jni/src/org/sqlite/jni/capi/Tester1.java @@ -38,17 +38,6 @@ import java.util.concurrent.Future; @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD}) @interface SingleThreadOnly{} -/** - A helper class which simply holds a single value. Its current use - is for communicating values out of anonymous classes, as doing so - requires a "final" reference. -*/ -class ValueHolder { - public T value; - public ValueHolder(){} - public ValueHolder(T v){value = v;} -} - public class Tester1 implements Runnable { //! True when running in multi-threaded mode. private static boolean mtMode = false; diff --git a/ext/jni/src/org/sqlite/jni/capi/ValueHolder.java b/ext/jni/src/org/sqlite/jni/capi/ValueHolder.java new file mode 100644 index 0000000000..b3f03ac867 --- /dev/null +++ b/ext/jni/src/org/sqlite/jni/capi/ValueHolder.java @@ -0,0 +1,25 @@ +/* +** 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 contains a set of tests for the sqlite3 JNI bindings. +*/ +package org.sqlite.jni.capi; + +/** + A helper class which simply holds a single value. Its primary use + is for communicating values out of anonymous classes, as doing so + requires a "final" reference. +*/ +public class ValueHolder { + public T value; + public ValueHolder(){} + public ValueHolder(T v){value = v;} +} diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java b/ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java new file mode 100644 index 0000000000..173d775e62 --- /dev/null +++ b/ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java @@ -0,0 +1,82 @@ +/* +** 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 + + A SqlFunction implementation for aggregate functions. The T type + represents the type of data accumulated by this aggregate while it + works. e.g. a SUM()-like UDF might use Integer or Long and a + CONCAT()-like UDF might use a StringBuilder or a List. +*/ +public abstract class AggregateFunction implements SqlFunction { + + /** + As for the xStep() argument of the C API's + sqlite3_create_function(). If this function throws, the + exception is reported via sqlite3_result_error(). + */ + public abstract void xStep(SqlFunction.Arguments args); + + /** + As for the xFinal() argument of the C API's + sqlite3_create_function(). If this function throws, it is + translated into sqlite3_result_error(). + + Note that the passed-in object will not actually contain any + arguments for xFinal() but will contain the context object needed + for setting the call's result or error state. + */ + public abstract void xFinal(SqlFunction.Arguments args); + + /** + Optionally override to be notified when the UDF is finalized by + SQLite. + */ + public void xDestroy() {} + + /** Per-invocation state for the UDF. */ + private final SqlFunction.PerContextState map = + new SqlFunction.PerContextState<>(); + + /** + To be called from the implementation's xStep() method, as well + as the xValue() and xInverse() methods of the {@link WindowFunction} + subclass, to fetch the current per-call UDF state. On the + first call to this method for any given sqlite3_context + argument, the context is set to the given initial value. On all other + calls, the 2nd argument is ignored. + + @see SQLFunction.PerContextState#getAggregateState + */ + protected final ValueHolder getAggregateState(SqlFunction.Arguments args, T initialValue){ + return map.getAggregateState(args, initialValue); + } + + /** + To be called from the implementation's xFinal() method to fetch + the final state of the UDF and remove its mapping. + + see SQLFunction.PerContextState#takeAggregateState + */ + protected final T takeAggregateState(SqlFunction.Arguments args){ + return map.takeAggregateState(args); + } + +} diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java b/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java index 6851bf8379..d6acda5aa5 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java @@ -13,22 +13,20 @@ */ 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 + Base marker interface for SQLite's three types of User-Defined SQL + Functions (UDFs): Scalar, Aggregate, and Window functions. */ 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. + The Arguments type is an abstraction on top of the lower-level + UDF function argument types. It provides _most_ of the functionality + of the lower-level interface, insofar as possible without "leaking" + those types into this API. */ public final static class Arguments implements Iterable{ private final sqlite3_context cx; @@ -37,29 +35,34 @@ public interface SqlFunction { /** Must be passed the context and arguments for the UDF call this - object is wrapping. + object is wrapping. Intended to be used by internal proxy + classes which "convert" the lower-level interface into this + package's higher-level interface, e.g. ScalarAdapter and + AggregateAdapter. + + Passing null for the args is equivalent to passing a length-0 + array. */ - Arguments(@NotNull sqlite3_context cx, @NotNull sqlite3_value args[]){ + Arguments(sqlite3_context cx, sqlite3_value args[]){ this.cx = cx; - this.args = args; - this.length = args.length; + this.args = args==null ? new sqlite3_value[0] : args;; + this.length = this.args.length; } /** Wrapper for a single SqlFunction argument. Primarily intended - for eventual use with the Arguments class's Iterable interface. + for 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){ + private Arg(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);} @@ -75,10 +78,9 @@ public interface SqlFunction { public void setAuxData(Object o){a.setAuxData(ndx, o);} } - //! Untested! @Override public java.util.Iterator iterator(){ - Arg[] proxies = new Arg[args.length]; + final Arg[] proxies = new Arg[args.length]; for( int i = 0; i < args.length; ++i ){ proxies[i] = new Arg(this, i); } @@ -98,6 +100,8 @@ public interface SqlFunction { return args[ndx]; } + sqlite3_context getContext(){return cx;} + public int getArgCount(){ return args.length; } public int getInt(int arg){return CApi.sqlite3_value_int(valueAt(arg));} @@ -159,6 +163,73 @@ public interface SqlFunction { } } + /** + PerContextState assists aggregate and window functions in + managing their accumulator state across calls to the UDF's + callbacks. + +

T must be of a type which can be legally stored as a value in + java.util.HashMap. + +

If a given aggregate or window function is called multiple times + in a single SQL statement, e.g. SELECT MYFUNC(A), MYFUNC(B)..., + then the clients need some way of knowing which call is which so + that they can map their state between their various UDF callbacks + and reset it via xFinal(). This class takes care of such + mappings. + +

This class works by mapping + sqlite3_context.getAggregateContext() to a single piece of + state, of a client-defined type (the T part of this class), which + persists across a "matching set" of the UDF's callbacks. + +

This class is a helper providing commonly-needed functionality + - it is not required for use with aggregate or window functions. + Client UDFs are free to perform such mappings using custom + approaches. The provided {@link AggregateFunction} and {@link + WindowFunction} classes use this. + */ + public static final class PerContextState { + private final java.util.Map> map + = new java.util.HashMap<>(); + + /** + Should be called from a UDF's xStep(), xValue(), and xInverse() + methods, passing it that method's first argument and an initial + value for the persistent state. If there is currently no + mapping for the given context within the map, one is created + using the given initial value, else the existing one is used + and the 2nd argument is ignored. It returns a ValueHolder + which can be used to modify that state directly without + requiring that the client update the underlying map's entry. + +

The caller is obligated to eventually call + takeAggregateState() to clear the mapping. + */ + public ValueHolder getAggregateState(SqlFunction.Arguments args, T initialValue){ + final Long key = args.getContext().getAggregateContext(true); + ValueHolder rc = null==key ? null : map.get(key); + if( null==rc ){ + map.put(key, rc = new ValueHolder<>(initialValue)); + } + return rc; + } + + /** + Should be called from a UDF's xFinal() method and passed that + method's first argument. This function removes the value + associated with with the arguments' aggregate context from the + map and returns it, returning null if no other UDF method has + been called to set up such a mapping. The latter condition will + be the case if a UDF is used in a statement which has no result + rows. + */ + public T takeAggregateState(SqlFunction.Arguments args){ + final ValueHolder h = map.remove(args.getContext().getAggregateContext(false)); + return null==h ? null : h.value; + } + } + /** Internal-use adapter for wrapping this package's ScalarFunction for use with the org.sqlite.jni.capi.ScalarFunction interface. @@ -169,11 +240,57 @@ public interface SqlFunction { this.impl = impl; } /** - Proxies this.f.xFunc(), adapting the call arguments to that - function's signature. + Proxies this.impl.xFunc(), adapting the call arguments to that + function's signature. If the proxy throws, it's translated to + sqlite_result_error() with the exception's message. */ public void xFunc(sqlite3_context cx, sqlite3_value[] args){ - impl.xFunc( new SqlFunction.Arguments(cx, args) ); + try{ + impl.xFunc( new SqlFunction.Arguments(cx, args) ); + }catch(Exception e){ + CApi.sqlite3_result_error(cx, e); + } + } + + public void xDestroy(){ + impl.xDestroy(); + } + } + + /** + Internal-use adapter for wrapping this package's AggregateFunction + for use with the org.sqlite.jni.capi.AggregateFunction interface. + */ + static final class AggregateAdapter extends org.sqlite.jni.capi.AggregateFunction { + final AggregateFunction impl; + AggregateAdapter(AggregateFunction impl){ + this.impl = impl; + } + + /** + Proxies this.impl.xStep(), adapting the call arguments to that + function's signature. If the proxied function throws, it is + translated to sqlite_result_error() with the exception's + message. + */ + public void xStep(sqlite3_context cx, sqlite3_value[] args){ + try{ + impl.xStep( new SqlFunction.Arguments(cx, args) ); + }catch(Exception e){ + CApi.sqlite3_result_error(cx, e); + } + } + + /** + As for the xFinal() argument of the C API's sqlite3_create_function(). + If the proxied function throws, it is translated into a sqlite3_result_error(). + */ + public void xFinal(sqlite3_context cx){ + try{ + impl.xFinal( new SqlFunction.Arguments(cx, null) ); + }catch(Exception e){ + CApi.sqlite3_result_error(cx, e); + } } public void xDestroy(){ diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java index 7321d7bb36..bcf97b2394 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java @@ -195,7 +195,6 @@ public final class Sqlite implements AutoCloseable { return prepare(sql, 0); } - public void createFunction(String name, int nArg, int eTextRep, ScalarFunction f ){ int rc = CApi.sqlite3_create_function(affirmOpen(), name, nArg, eTextRep, new SqlFunction.ScalarAdapter(f)); @@ -206,4 +205,14 @@ public final class Sqlite implements AutoCloseable { this.createFunction(name, nArg, CApi.SQLITE_UTF8, f); } + public void createFunction(String name, int nArg, int eTextRep, AggregateFunction f ){ + int rc = CApi.sqlite3_create_function(affirmOpen(), name, nArg, eTextRep, + new SqlFunction.AggregateAdapter(f)); + if( 0!=rc ) throw new SqliteException(db); + } + + public void createFunction(String name, int nArg, AggregateFunction f){ + this.createFunction(name, nArg, CApi.SQLITE_UTF8, f); + } + } diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java index 07a43b63dd..f5fd5f84e6 100644 --- a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java +++ b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java @@ -38,17 +38,6 @@ import org.sqlite.jni.capi.*; @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD}) @interface SingleThreadOnly{} -/** - A helper class which simply holds a single value. Its current use - is for communicating values out of anonymous classes, as doing so - requires a "final" reference. -*/ -class ValueHolder { - public T value; - public ValueHolder(){} - public ValueHolder(T v){value = v;} -} - public class Tester2 implements Runnable { //! True when running in multi-threaded mode. private static boolean mtMode = false; @@ -279,6 +268,36 @@ public class Tester2 implements Runnable { affirm( 1 == xDestroyCalled.value ); } + void testUdfAggregate(){ + final ValueHolder xDestroyCalled = new ValueHolder<>(0); + final ValueHolder vh = new ValueHolder<>(0); + try (Sqlite db = openDb()) { + execSql(db, "create table t(a); insert into t(a) values(1),(2),(3)"); + final AggregateFunction f = new AggregateFunction(){ + public void xStep(SqlFunction.Arguments args){ + final ValueHolder agg = this.getAggregateState(args, 0); + for( SqlFunction.Arguments.Arg arg : args ){ + agg.value += arg.getInt(); + } + } + public void xFinal(SqlFunction.Arguments args){ + final Integer v = this.takeAggregateState(args); + if( null==v ) args.resultNull(); + else args.resultInt(v); + vh.value = v; + } + public void xDestroy(){ + ++xDestroyCalled.value; + } + }; + db.createFunction("myagg", -1, f); + execSql(db, "select myagg(a) from t"); + affirm( 6 == vh.value ); + affirm( 0 == xDestroyCalled.value ); + } + affirm( 1 == xDestroyCalled.value ); + } + private void runTests(boolean fromThread) throws Exception { List mlist = testMethods; affirm( null!=mlist ); diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java b/ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java new file mode 100644 index 0000000000..009936a43e --- /dev/null +++ b/ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java @@ -0,0 +1,25 @@ +/* +** 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 contains a set of tests for the sqlite3 JNI bindings. +*/ +package org.sqlite.jni.wrapper1; + +/** + A helper class which simply holds a single value. Its primary use + is for communicating values out of anonymous classes, as doing so + requires a "final" reference. +*/ +public class ValueHolder { + public T value; + public ValueHolder(){} + public ValueHolder(T v){value = v;} +} diff --git a/manifest b/manifest index 1fb9230659..ed6c5f7f8a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C JNI:\sadd\sscalar\sUDF\ssupport\sto\sthe\swrapper1\sAPI. -D 2023-10-16T14:31:13.824 +C JNI:\sadd\saggregate\sfunction\ssupport\sto\sthe\swrapper1\sAPI. +D 2023-10-16T16:04:23.203 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 069399d471af948a4293e79135907a8d58daa09e59b4cc1b9cc1a5124c87f589 +F ext/jni/GNUmakefile 5c3ac326bf3853486ebe0d70819abc790cc65c412182ce4ebd5012b008d9b059 F ext/jni/README.md ef9ac115e97704ea995d743b4a8334e23c659e5534c3b64065a5405256d5f2f4 F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa F ext/jni/src/c/sqlite3-jni.c 8d32ca0598a11370a9e92a6d111f38934c225056b42b13512175acf6e37eed4c @@ -266,9 +266,10 @@ F ext/jni/src/org/sqlite/jni/capi/SQLFunction.java fef556adbc3624292423083a648bd F ext/jni/src/org/sqlite/jni/capi/SQLTester.java 09bee15aa0eedac68d767ae21d9a6a62a31ade59182a3ccbf036d6463d9e30b1 F ext/jni/src/org/sqlite/jni/capi/ScalarFunction.java 93b9700fca4c68075ccab12fe0fbbc76c91cafc9f368e835b9bd7cd7732c8615 F ext/jni/src/org/sqlite/jni/capi/TableColumnMetadata.java addf120e0e76e5be1ff2260daa7ce305ff9b5fafd64153a7a28e9d8f000a815f -F ext/jni/src/org/sqlite/jni/capi/Tester1.java 8aacea90b0eed6e4e801cfba2515a66b5d602e124f1ba68fe3d2f0aa98f0f443 +F ext/jni/src/org/sqlite/jni/capi/Tester1.java ca195521b6bda3e0cd00e76bb71ec8060d1fab76a2f13b1af9feea40789f44bb F ext/jni/src/org/sqlite/jni/capi/TraceV2Callback.java 0a25e117a0daae3394a77f24713e36d7b44c67d6e6d30e9e1d56a63442eef723 F ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java 2766b8526bbffc4f1045f70e79f1bc1b1efe1c3e95ca06cdb8a7391032dda3b4 +F ext/jni/src/org/sqlite/jni/capi/ValueHolder.java 9f9e151f1da017b706c0ee5f40f4c86b54e773d6ae4339723e0cc85a456251ab F ext/jni/src/org/sqlite/jni/capi/WindowFunction.java caf4396f91b2567904cf94bc538a069fd62260d975bd037d15a02a890ed1ef9e F ext/jni/src/org/sqlite/jni/capi/XDestroyCallback.java f3abb8dd7381f53ebba909437090caf68200f06717b8a7d6aa96fa3e8133117d F ext/jni/src/org/sqlite/jni/capi/package-info.java 08ff986a65d2be9162442c82d28a65ce431d826f188520717c2ecb1484d0a50e @@ -289,10 +290,12 @@ 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/SqlFunction.java 8b422ec8a2e922c1c21db549e68e0eb93078d2c4d341354043975e111a43b10d -F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 7826de9bea3102d8a2ecaef3cc84480d8d6f6bc617c531d2078b419913c866fd +F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java 5ad99bd74c85f56bbef324d9ec29b4048f4620547c9a80093d8586c3557f9f9a +F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 004394eeb944baa56e36cd7ae69ba6d4a52b52db3c49439db16e98270b861421 +F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java a9ddc6a9e8c113168cc67592ae24c0e56d30dd06226eeab012f2761a0889d7bb F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 1386f7b753134fc12253ce2fbbc448ba8c970567fac01a3356cb672e14408d73 -F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 3dccdb259bd1d737c6d104bdf488fb489063b40a113c03b311284e0287d0d5b7 +F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java c24b510ebe801c30533cc62efdf69a4a5e2da9ec4b49f8d403f2060693f060a0 +F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java 7b89a7391f771692c5b83b0a5b86266abe8d59f1c77d7a0eccc9b79f259d79af F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43443408f3000139478c4dc745 F ext/jni/src/tests/000-001-ignored.test e17e874c6ab3c437f1293d88093cf06286083b65bf162317f91bbfd92f961b70 F ext/jni/src/tests/900-001-fts.test bf0ce17a8d082773450e91f2388f5bbb2dfa316d0b676c313c637a91198090f0 @@ -2129,8 +2132,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 43b10a5cf9cb8be53d62914f340d533e60a70bf4caa8b9b91c0f867fa0f70493 -R b476ec63940a46ee7b1e2c0e07bbcf7b +P a850535766d2243d9475e1523c753615875a2da9c9d82a41a9fb61b141c6334a +R 41c1c0a2430694da022548afb899150c U stephan -Z a39099e216c3c59927f5c5a18a7e93ef +Z b40ce65d6c09198a38c3804feb9178c7 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 0ec7f3375d..0973dce9e0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a850535766d2243d9475e1523c753615875a2da9c9d82a41a9fb61b141c6334a \ No newline at end of file +15b28b340a5c5efdbfe3fbed16ee0b699561edaeebb77446addf2374bdf9357e \ No newline at end of file