]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Do not pre-allocate sqlite3_aggregate_context() for Java UDFs, as it unduly complicat...
authorstephan <stephan@noemail.net>
Thu, 24 Aug 2023 21:31:56 +0000 (21:31 +0000)
committerstephan <stephan@noemail.net>
Thu, 24 Aug 2023 21:31:56 +0000 (21:31 +0000)
FossilOrigin-Name: e8308f0c6ec2d8999c8a2502fb130cb3501ba326f23f71f2cd8d452debae79b5

ext/jni/GNUmakefile
ext/jni/src/c/sqlite3-jni.c
ext/jni/src/c/sqlite3-jni.h
ext/jni/src/org/sqlite/jni/SQLFunction.java
ext/jni/src/org/sqlite/jni/SQLite3Jni.java
ext/jni/src/org/sqlite/jni/Tester1.java
ext/jni/src/org/sqlite/jni/sqlite3_context.java
manifest
manifest.uuid

index a6711043fc4c02cf276efcfb58185fecd99ec37f..c4fa4b5c06a253629a007bee5790b43c53f957c0 100644 (file)
@@ -288,7 +288,7 @@ jar: $(package.jar)
 
 dir.doc := $(dir.jni)/doc
 doc: $(JAVA_FILES.main)
-       $(bin.javadoc) -cp $(classpath) -d $(dir.doc) org.sqlite.jni
+       $(bin.javadoc) -cp $(classpath) -d $(dir.doc) -quiet org.sqlite.jni
 
 ########################################################################
 # Clean up...
index c62aa1765a699a22252567741c6c734acd036f8b..13ccc4ec3f9fc605b5dcca9435a25837faf5a4a2 100644 (file)
@@ -1164,49 +1164,6 @@ static int S3JniAutoExtension_init(JNIEnv *const env,
   return 0;
 }
 
-/*
-** Requires that jCx be a Java-side sqlite3_context wrapper for pCx.
-** This function calls sqlite3_aggregate_context() to allocate a tiny
-** sliver of memory, the address of which is set in
-** jCx->aggregateContext.  The memory is only used as a key for
-** mapping client-side results of aggregate result sets across
-** calls to the UDF's callbacks.
-**
-** isFinal must be 1 for xFinal() calls and 0 for all others, the
-** difference being that the xFinal() invocation will not allocate
-** new memory if it was not already, resulting in a value of 0
-** for jCx->aggregateContext.
-**
-** Returns 0 on success. Returns SQLITE_NOMEM on allocation error,
-** noting that it will not allocate when isFinal is true. It returns
-** SQLITE_ERROR if there's a serious internal error in dealing with
-** the JNI state.
-*/
-static int udf_setAggregateContext(JNIEnv * env, jobject jCx,
-                                   sqlite3_context * pCx,
-                                   int isFinal){
-  void * pAgg;
-  int rc = 0;
-  S3JniNphClass * const pNC =
-    S3JniGlobal_nph_cache(env, &S3NphRefs.sqlite3_context);
-  if( !pNC->fidAggCtx ){
-    S3JniMutex_Nph_enter;
-    if( !pNC->fidAggCtx ){
-      pNC->fidAggCtx = (*env)->GetFieldID(env, pNC->klazz, "aggregateContext", "J");
-      EXCEPTION_IS_FATAL("Cannot get sqlite3_contex.aggregateContext member.");
-    }
-    S3JniMutex_Nph_leave;
-  }
-  pAgg = sqlite3_aggregate_context(pCx, isFinal ? 0 : sizeof(void*));
-  if( pAgg || isFinal ){
-    (*env)->SetLongField(env, jCx, pNC->fidAggCtx, (jlong)pAgg);
-  }else{
-    assert(!pAgg);
-    rc = SQLITE_NOMEM;
-  }
-  return rc;
-}
-
 /*
 ** Common init for OutputPointer_set_Int32() and friends. pRef must be
 ** a pointer from S3NphRefs. jOut must be an instance of that
@@ -1628,6 +1585,7 @@ static int udf_report_exception(JNIEnv * const env, int translateToErr,
     (*env)->ExceptionDescribe( env );
     S3JniExceptionClear;
   }
+  UNREF_L(ex);
   return rc;
 }
 
@@ -1645,10 +1603,6 @@ static int udf_xFSI(sqlite3_context* const pCx, int argc,
   int rc = udf_args(env, pCx, argc, argv, &args.jcx, &args.jargv);
 
   //MARKER(("UDF::%s.%s()\n", s->zFuncName, zFuncType));
-  if( rc ) return rc;
-  if( UDF_SCALAR != s->type ){
-    rc = udf_setAggregateContext(env, args.jcx, pCx, 0);
-  }
   if( 0 == rc ){
     (*env)->CallVoidMethod(env, s->jObj, xMethodID, args.jcx, args.jargv);
     S3JniIfThrew{
@@ -1678,15 +1632,10 @@ static int udf_xFV(sqlite3_context* cx, S3JniUdf * s,
     return SQLITE_NOMEM;
   }
   //MARKER(("UDF::%s.%s()\n", s->zFuncName, zFuncType));
-  if( UDF_SCALAR != s->type ){
-    rc = udf_setAggregateContext(env, jcx, cx, isFinal);
-  }
-  if( 0 == rc ){
-    (*env)->CallVoidMethod(env, s->jObj, xMethodID, jcx);
-    S3JniIfThrew{
-      rc = udf_report_exception(env, isFinal, cx, s->zFuncName,
-                                zFuncType);
-    }
+  (*env)->CallVoidMethod(env, s->jObj, xMethodID, jcx);
+  S3JniIfThrew{
+    rc = udf_report_exception(env, isFinal, cx, s->zFuncName,
+                              zFuncType);
   }
   UNREF_L(jcx);
   return rc;
@@ -1834,6 +1783,20 @@ WRAP_INT_SVALUE(1value_1type,          sqlite3_value_type)
 #undef WRAP_MUTF8_VOID
 #undef WRAP_STR_STMT_INT
 
+
+S3JniApi(sqlite3_aggregate_context(),jlong,1aggregate_1context)(
+  JniArgsEnvClass, jobject jCx, jboolean initialize
+){
+  sqlite3_context * const pCx = PtrGet_sqlite3_context(jCx);
+  void * const p = pCx
+    ? sqlite3_aggregate_context(pCx, (int)(initialize
+                                           ? (int)sizeof(void*)
+                                           : 0))
+    : 0;
+  return (jlong)p / sizeof(void*);
+}
+
+
 /* Central auto-extension handler. */
 static int s3jni_run_java_auto_extensions(sqlite3 *pDb, const char **pzErr,
                                           const struct sqlite3_api_routines *ignored){
index b9f03983a316a86183fff68a7787ad3dcbf70733..e642241921ff527c560d4d71c1cd7ae9157196d1 100644 (file)
@@ -771,6 +771,14 @@ JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_init
 JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_SQLite3Jni_uncacheJniEnv
   (JNIEnv *, jclass);
 
+/*
+ * Class:     org_sqlite_jni_SQLite3Jni
+ * Method:    sqlite3_aggregate_context
+ * Signature: (Lorg/sqlite/jni/sqlite3_context;Z)J
+ */
+JNIEXPORT jlong JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1aggregate_1context
+  (JNIEnv *, jclass, jobject, jboolean);
+
 /*
  * Class:     org_sqlite_jni_SQLite3Jni
  * Method:    sqlite3_auto_extension
index bc6f608736ef7f524162bdbb010dd0ec95f0b881..97a3f65a4690412e1433697344aa23d91b684d75 100644 (file)
@@ -55,6 +55,9 @@ public abstract class SQLFunction {
      Client UDFs are free to perform such mappings using custom
      approaches. The provided Aggregate<T> and Window<T> classes
      use this.
+
+     <p>T must be of a type which can be legally stored as a value in
+     java.util.HashMap<KeyType,T>.
   */
   public static final class PerContextState<T> {
     private final java.util.Map<Long,ValueHolder<T>> map
@@ -64,20 +67,20 @@ public abstract class SQLFunction {
        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 cx.getAggregateContext() 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<T> which can be used to modify that state directly
-       without requiring that the client update the underlying map's
-       entry.
-
-       <p>T must be of a type which can be legally stored as a value in
-       java.util.HashMap<KeyType,T>.
+       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<T>
+       which can be used to modify that state directly without
+       requiring that the client update the underlying map's entry.
+
+       <p>The caller is obligated to eventually call
+       takeAggregateState() to clear the mapping.
     */
     public ValueHolder<T> getAggregateState(sqlite3_context cx, T initialValue){
-      ValueHolder<T> rc = map.get(cx.getAggregateContext());
-      if(null == rc){
-        map.put(cx.getAggregateContext(), rc = new ValueHolder<>(initialValue));
+      final Long key = cx.getAggregateContext(true);
+      ValueHolder<T> rc = null==key ? null : map.get(key);
+      if( null==rc ){
+        map.put(key, rc = new ValueHolder<>(initialValue));
       }
       return rc;
     }
@@ -92,7 +95,7 @@ public abstract class SQLFunction {
        rows.
     */
     public T takeAggregateState(sqlite3_context cx){
-      final ValueHolder<T> h = map.remove(cx.getAggregateContext());
+      final ValueHolder<T> h = map.remove(cx.getAggregateContext(false));
       return null==h ? null : h.value;
     }
   }
index e5a8b6e2438f1d66ff6f402dc1a400e60f3d246d..9a00fa86e5807dc08a7617d49a39bd37b5956858 100644 (file)
@@ -126,19 +126,19 @@ public final class SQLite3Jni {
      This will clean up any cached per-JNIEnv info. Calling into the
      library will re-initialize the cache on demand.
 
-     This process does not close any databases or finalize
+     <p>This process does not close any databases or finalize
      any prepared statements because their ownership does not depend on
      a given thread.  For proper library behavior, and to
      avoid C-side leaks, be sure to finalize all statements and close
      all databases before calling this function.
 
-     Calling this from the main application thread is not strictly
+     <p>Calling this from the main application thread is not strictly
      required but is "polite." Additional threads must call this
      before ending or they will leak cache entries in the C heap,
      which in turn may keep numerous Java-side global references
      active.
 
-     This routine returns false without side effects if the current
+     <p>This routine returns false without side effects if the current
      JNIEnv is not cached, else returns true, but this information is
      primarily for testing of the JNI bindings and is not information
      which client-level code should use to make any informed
@@ -151,22 +151,42 @@ public final class SQLite3Jni {
   // alphabetized.  The SQLITE_... values. on the other hand, are
   // grouped by category.
 
+  /**
+     Functions exactly like the native form except that (A) the
+     returned value is only intended for use as a lookup key in a
+     higher-level data structure and (B) the 2nd argument is a boolean
+     instead of an int. If passed true, it will attempt to allocate
+     enough memory to use as a UDF-call-local context key. If passed
+     false it will not allocate any memory.
+
+     <p>It is only valid for the life of the current UDF method call
+     and must not be retained for later use. The return value 0
+     indicates an allocation error unless initialize is false, in
+     which case it means that the given context was never passed to
+     this function with a true second argument so never had to
+     allocate.
+
+     <p>For the JNI wrapping, the value of sz is provided for API
+     consistency but it is ignored unless it's 0. Results are
+     undefined if the value is negative.
+  */
+  public static native long sqlite3_aggregate_context(sqlite3_context cx, boolean initialize);
 
   /**
      Functions almost as documented for the C API, with these
      exceptions:
 
-     - The callback interface is is shorter because of cross-language
-       differences. Specifically, 3rd argument to the C auto-extension
-       callback interface is unnecessary here.
+     <p>- The callback interface is is shorter because of
+     cross-language differences. Specifically, 3rd argument to the C
+     auto-extension callback interface is unnecessary here.
 
 
-     The C API docs do not specifically say so, if the list of
+     <p>The C API docs do not specifically say so, but if the list of
      auto-extensions is manipulated from an auto-extension, it is
      undefined which, if any, auto-extensions will subsequently
      execute for the current database.
 
-     See the AutoExtension class docs for more information.
+     <p>See the AutoExtension class docs for more information.
   */
   public static native int sqlite3_auto_extension(@NotNull AutoExtension callback);
 
index eb383fe8d27131be6c88873f2ed89b5d7af156f9..89fa022cf50adcccb576a06d7e2909e3bc8d284e 100644 (file)
@@ -723,7 +723,9 @@ public class Tester1 implements Runnable {
     SQLFunction func = new SQLFunction.Aggregate<Integer>(){
         @Override
         public void xStep(sqlite3_context cx, sqlite3_value[] args){
-          this.getAggregateState(cx, 0).value += sqlite3_value_int(args[0]);
+          final ValueHolder<Integer> agg = this.getAggregateState(cx, 0);
+          agg.value += sqlite3_value_int(args[0]);
+          affirm( agg == this.getAggregateState(cx, 0) );
         }
         @Override
         public void xFinal(sqlite3_context cx){
@@ -740,15 +742,19 @@ public class Tester1 implements Runnable {
     int rc = sqlite3_create_function(db, "myfunc", 1, SQLITE_UTF8, func);
     affirm(0 == rc);
     sqlite3_stmt stmt = prepare(db, "select myfunc(a), myfunc(a+10) from t");
+    affirm( null != stmt );
     int n = 0;
     if( SQLITE_ROW == sqlite3_step(stmt) ){
-      final int v = sqlite3_column_int(stmt, 0);
+      int v = sqlite3_column_int(stmt, 0);
       affirm( 6 == v );
+      int v2 = sqlite3_column_int(stmt, 1);
+      affirm( 30+v == v2 );
       ++n;
     }
+    affirm( 1==n );
     affirm(!xFinalNull.value);
     sqlite3_reset(stmt);
-    // Ensure that the accumulator is reset...
+    // Ensure that the accumulator is reset on subsequent calls...
     n = 0;
     if( SQLITE_ROW == sqlite3_step(stmt) ){
       final int v = sqlite3_column_int(stmt, 0);
@@ -767,9 +773,9 @@ public class Tester1 implements Runnable {
       affirm( 6 == c0 );
       affirm( 12 == c1 );
     }
+    sqlite3_finalize(stmt);
     affirm( 1 == n );
     affirm(!xFinalNull.value);
-    sqlite3_finalize(stmt);
 
     execSql(db, "SELECT myfunc(1) WHERE 0");
     affirm(xFinalNull.value);
index d582df7838366c6c0907243f956298c1c16a8f05..ead3f372ea69f84eb1244384756e7210c4414d5b 100644 (file)
@@ -18,10 +18,7 @@ package org.sqlite.jni;
    SQL functions (a.k.a. UDFs).
 */
 public final class sqlite3_context extends NativePointerHolder<sqlite3_context> {
-  /**
-     Only set by the JNI layer.
-  */
-  private long aggregateContext = 0;
+  private Long aggregateContext = null;
 
   /**
      getAggregateContext() corresponds to C's
@@ -32,19 +29,29 @@ public final class sqlite3_context extends NativePointerHolder<sqlite3_context>
      such that all calls into those callbacks can determine which "set"
      of those calls they belong to.
 
-     If this object is being used in the context of an aggregate or
+     <p>If the argument is true and the aggregate context has not yet
+     been set up, it will be initialized fetched on demand, else it
+     won't. The intent is that xStep(), xValue(), and xInverse()
+     methods pass true and xFinal() methods pass false.
+
+     <p>This function treats numeric 0 as null, always returning null instead
+     of 0.
+
+     <p>If this object is being used in the context of an aggregate or
      window UDF, this function returns a non-0 value which is distinct
      for each set of UDF callbacks from a single invocation of the
      UDF, otherwise it returns 0. The returned value is only only
      valid within the context of execution of a single SQL statement,
-     and may be re-used by future invocations of the UDF in different
-     SQL statements.
+     and must not be re-used by future invocations of the UDF in
+     different SQL statements.
 
-     Consider this SQL, where MYFUNC is a user-defined aggregate function:
+     <p>Consider this SQL, where MYFUNC is a user-defined aggregate function:
 
+     {code
      SELECT MYFUNC(A), MYFUNC(B) FROM T;
+     }
 
-     The xStep() and xFinal() methods of the callback need to be able
+     <p>The xStep() and xFinal() methods of the callback need to be able
      to differentiate between those two invocations in order to
      perform their work properly. The value returned by
      getAggregateContext() will be distinct for each of those
@@ -52,14 +59,18 @@ public final class sqlite3_context extends NativePointerHolder<sqlite3_context>
      key for mapping callback invocations to whatever client-defined
      state is needed by the UDF.
 
-     There is one case where this will return 0 in the context of an
+     <p>There is one case where this will return 0 in the context of an
      aggregate or window function: if the result set has no rows,
      the UDF's xFinal() will be called without any other x...() members
      having been called. In that one case, no aggregate context key will
      have been generated. xFinal() implementations need to be prepared to
      accept that condition as legal.
   */
-  public long getAggregateContext(){
-    return aggregateContext;
+  public synchronized Long getAggregateContext(boolean initIfNeeded){
+      if( aggregateContext==null ){
+        aggregateContext = SQLite3Jni.sqlite3_aggregate_context(this, initIfNeeded);
+        if( !initIfNeeded && null==aggregateContext ) aggregateContext = 0L;
+      }
+      return (null==aggregateContext || 0!=aggregateContext) ? aggregateContext : null;
   }
 }
index 3d557c1b5832c4db295e2ceabaf2cae94b16c564..59c1110aa4b82aa38481a6a049023d55aacba312 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sdoc/testrunner.md,\sfor\sdocumenting\sthe\stestrunner.tcl\sscript.
-D 2023-08-24T19:08:50.024
+C Do\snot\spre-allocate\ssqlite3_aggregate_context()\sfor\sJava\sUDFs,\sas\sit\sunduly\scomplicates\sUDF\sinitialization.
+D 2023-08-24T21:31:56.676
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -233,11 +233,11 @@ 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 6b3c0fd8d055c129735702d0b288589d25544dd404a00d46d9eb43770fe7f78f
+F ext/jni/GNUmakefile 6aeafa0ebcf0f0d834c814ae8b450b54135ea11a2a7868f90b6286ec1bf6020f
 F ext/jni/README.md 9d3caa2e038bfe5e8356a9e8ff66f93ca0647ac278339eeea296f10017f5cf35
 F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa
-F ext/jni/src/c/sqlite3-jni.c 8db2fcc05dd7749f9f4175e2654344feccac6abfd19fd9db0d116c6350e3b625
-F ext/jni/src/c/sqlite3-jni.h 2b81cfb83933cb18e5f690487f4556591d3329538809c847d00190aa4d69aa1d
+F ext/jni/src/c/sqlite3-jni.c 0d98ab3b117893904a06f0f8a350d68d4e911939b6aee4f0eb1ef707502ac23c
+F ext/jni/src/c/sqlite3-jni.h 7e9f36434b919cd8b6aa66c61e3910e9f112e252f52d1ac8a9811c52710aefcb
 F ext/jni/src/org/sqlite/jni/Authorizer.java 1308988f7f40579ea0e4deeaec3c6be971630566bd021c31367fe3f5140db892
 F ext/jni/src/org/sqlite/jni/AutoExtension.java bcc1849b2fccbe5e2d7ac9e9ac7f8d05a6d7088a8fedbaad90e39569745a61e6
 F ext/jni/src/org/sqlite/jni/BusyHandler.java 1b1d3e5c86cd796a0580c81b6af6550ad943baa25e47ada0dcca3aff3ebe978c
@@ -256,10 +256,10 @@ F ext/jni/src/org/sqlite/jni/PreUpdateHook.java dec00a706b58c67989f0ff56c4f0a703
 F ext/jni/src/org/sqlite/jni/ProgressHandler.java 6f62053a828a572de809828b1ee495380677e87daa29a1c57a0e2c06b0a131dc
 F ext/jni/src/org/sqlite/jni/ResultCode.java ba701f20213a5f259e94cfbfdd36eb7ac7ce7797f2c6c7fca2004ff12ce20f86
 F ext/jni/src/org/sqlite/jni/RollbackHook.java b04c8abcc6ade44a8a57129e33765793f69df0ba909e49ba18d73f4268d92564
-F ext/jni/src/org/sqlite/jni/SQLFunction.java 5851698d96ee29171d68930ad758d0f5a253f7575f1feb890d82b2557a8d3ef5
+F ext/jni/src/org/sqlite/jni/SQLFunction.java 4d6291fa14fcca1a040609378f9f00a193145d79c3abbda98ba32c340904cbeb
 F ext/jni/src/org/sqlite/jni/SQLLog.java c60610b35208416940822e834d61f08fbbe5d6e06b374b541b49e41fd56c9798
-F ext/jni/src/org/sqlite/jni/SQLite3Jni.java d96f10a097c1d614b44353e85a65368d9aca565d5ae57fae0104811594fbdfba
-F ext/jni/src/org/sqlite/jni/Tester1.java 76f308ad9bf0bd74374561c30c65564ed24583a465264b751d9e2333980149f1
+F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 866b320e6cb089ebe96c14763575df9e2e0d5e52a0ec87a52119ff17ec59ffbf
+F ext/jni/src/org/sqlite/jni/Tester1.java 239eb0133547d4a23317a6dd5bc456172cfb1f2547fd15ba8408871c2776a721
 F ext/jni/src/org/sqlite/jni/TesterFts5.java 6f135c60e24c89e8eecb9fe61dde0f3bb2906de668ca6c9186bcf34bdaf94629
 F ext/jni/src/org/sqlite/jni/Tracer.java a5cece9f947b0af27669b8baec300b6dd7ff859c3e6a6e4a1bd8b50f9714775d
 F ext/jni/src/org/sqlite/jni/UpdateHook.java e58645a1727f8a9bbe72dc072ec5b40d9f9362cb0aa24acfe93f49ff56a9016d
@@ -269,7 +269,7 @@ F ext/jni/src/org/sqlite/jni/fts5_extension_function.java ac825035d7d83fc7fd9603
 F ext/jni/src/org/sqlite/jni/fts5_tokenizer.java e530b36e6437fcc500e95d5d75fbffe272bdea20d2fac6be2e1336c578fba98b
 F ext/jni/src/org/sqlite/jni/package-info.java 1a547913d681411d65c5fe0bca840f049abe5612740154a125545ea9e2481747
 F ext/jni/src/org/sqlite/jni/sqlite3.java 62b1b81935ccf3393472d17cb883dc5ff39c388ec3bc1de547f098a0217158fc
-F ext/jni/src/org/sqlite/jni/sqlite3_context.java fe7797a696978f057528a57b7a11e7797ed41fd7afcf100c5ebb67055d9f706f
+F ext/jni/src/org/sqlite/jni/sqlite3_context.java 42df6769ab9c8de40d24f39f49152cdaa6e0c06d1468660a95dfee9ecaeb9a63
 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 bc3d6797a2f6cb7d443a0b72af84e5a45e0416b96af52e432d28e123db1970c3
@@ -2096,8 +2096,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 62b404d62fd62f4d220838b59c9f38a71afa2d4a8c3af0a5c9495fa7020972cf
-R a33be9d18a7bfec02bf745dca74a3ae4
-U dan
-Z b231c489ac6e506e7affd58c17184d19
+P 9c69a28401c7273823f2c2b291fd417febeb278afb9ce085a4b944505ca13d23
+R 1c78bd3d04007fccae2264dff957535e
+U stephan
+Z 6a74bde3490bcf9bf06f9dd5ecb09697
 # Remove this line to create a well-formed Fossil manifest.
index 8eee5cd0272d455fc8aa857ce51a75f400d58275..d99911cac2bdb60e4f5eb158b8fd26fc23a9fd58 100644 (file)
@@ -1 +1 @@
-9c69a28401c7273823f2c2b291fd417febeb278afb9ce085a4b944505ca13d23
\ No newline at end of file
+e8308f0c6ec2d8999c8a2502fb130cb3501ba326f23f71f2cd8d452debae79b5
\ No newline at end of file