]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add JNI Sqlite and SqliteException classes. Add Tester2.java as the main test app...
authorstephan <stephan@noemail.net>
Mon, 9 Oct 2023 11:46:32 +0000 (11:46 +0000)
committerstephan <stephan@noemail.net>
Mon, 9 Oct 2023 11:46:32 +0000 (11:46 +0000)
FossilOrigin-Name: 6acf52be7abce8dcf434c5ebf0d5e88859b033e6418077846247ecf00ccf9381

ext/jni/GNUmakefile
ext/jni/src/org/sqlite/jni/Sqlite.java [new file with mode: 0644]
ext/jni/src/org/sqlite/jni/SqliteException.java [new file with mode: 0644]
ext/jni/src/org/sqlite/jni/Tester1.java
ext/jni/src/org/sqlite/jni/Tester2.java [new file with mode: 0644]
ext/jni/src/org/sqlite/jni/fts5/Fts5ExtensionApi.java
ext/jni/src/org/sqlite/jni/fts5/fts5_api.java
ext/jni/src/org/sqlite/jni/sqlite3.java
ext/jni/src/org/sqlite/jni/sqlite3_stmt.java
manifest
manifest.uuid

index 661685b3f74b40afcd824aaaa4c4d996985b35cd..1b78d97ae113a7f5220c52f6c439481b2ac88da0 100644 (file)
@@ -98,6 +98,8 @@ JAVA_FILES.main := $(patsubst %,$(dir.src.jni)/%,\
   ResultCode.java \
   RollbackHookCallback.java \
   ScalarFunction.java \
+  Sqlite.java \
+  SqliteException.java \
   SQLFunction.java \
   CallbackProxy.java \
   CApi.java \
@@ -113,6 +115,7 @@ JAVA_FILES.main := $(patsubst %,$(dir.src.jni)/%,\
 )
 JAVA_FILES.unittest := $(patsubst %,$(dir.src.jni)/%,\
   Tester1.java \
+  Tester2.java \
 )
 ifeq (1,$(enable.fts5))
   JAVA_FILES.unittest += $(patsubst %,$(dir.src.jni)/%,\
@@ -294,19 +297,23 @@ $(package.dll): $(sqlite3-jni.c) $(MAKEFILE)
 all: $(package.dll)
 
 .PHONY: test test-one
-test.flags ?=
-test.main.flags = -ea -Djava.library.path=$(dir.bld.c) \
-                  $(java.flags) -cp $(classpath) \
-                  org.sqlite.jni.Tester1
+Tester1.flags ?=
+Tester2.flags ?=
+test.flags.jvm = -ea -Djava.library.path=$(dir.bld.c) \
+                  $(java.flags) -cp $(classpath)
 test.deps := $(CLASS_FILES) $(package.dll)
 test-one: $(test.deps)
-       $(bin.java) $(test.main.flags) $(test.flags)
+       $(bin.java) $(test.flags.jvm) org.sqlite.jni.Tester1 $(Tester1.flags)
+#      $(bin.java) $(test.flags.jvm) org.sqlite.jni.Tester2 $(Tester2.flags)
 test-sqllog: $(test.deps)
        @echo "Testing with -sqllog..."
-       $(bin.java) $(test.main.flags) -sqllog
+       $(bin.java) $(test.flags.jvm) -sqllog
 test-mt: $(test.deps)
        @echo "Testing in multi-threaded mode:";
-       $(bin.java) $(test.main.flags) -t 7 -r 50 -shuffle $(test.flags)
+       $(bin.java) $(test.flags.jvm) org.sqlite.jni.Tester1 \
+    -t 7 -r 50 -shuffle $(Tester1.flags)
+       $(bin.java) $(test.flags.jvm) org.sqlite.jni.Tester2 \
+    -t 7 -r 50 -shuffle $(Tester2.flags)
 
 test: test-one test-mt
 tests: test test-sqllog
diff --git a/ext/jni/src/org/sqlite/jni/Sqlite.java b/ext/jni/src/org/sqlite/jni/Sqlite.java
new file mode 100644 (file)
index 0000000..541c6c7
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+** 2023-10-09
+**
+** 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;
+import static org.sqlite.jni.CApi.*;
+
+/**
+   This class represents a database connection, analog to the C-side
+   sqlite3 class but with added argument validation, exceptions, and
+   similar "smoothing of sharp edges" to make the API safe to use from
+   Java. It also acts as a namespace for other types for which
+   individual instances are tied to a specific database connection.
+*/
+public final class Sqlite implements AutoCloseable  {
+  private sqlite3 db = null;
+
+  //! Used only by the open() factory functions.
+  private Sqlite(sqlite3 db){
+    this.db = db;
+  }
+
+  public static Sqlite open(String filename, int flags, String zVfs){
+    final OutputPointer.sqlite3 out = new OutputPointer.sqlite3();
+    final int rc = sqlite3_open_v2(filename, out, flags, zVfs);
+    final sqlite3 n = out.take();
+    if( 0!=rc ){
+      if( null==n ) throw new SqliteException(rc);
+      else throw new SqliteException(n);
+    }
+    return new Sqlite(n);
+  }
+
+  public static Sqlite open(String filename, int flags){
+    return open(filename, flags, null);
+  }
+
+  public static Sqlite open(String filename){
+    return open(filename, 0, null);
+  }
+
+  @Override public void close(){
+    if(null!=this.db){
+      this.db.close();
+      this.db = null;
+    }
+  }
+
+  sqlite3 dbHandle(){ return this.db; }
+
+}
diff --git a/ext/jni/src/org/sqlite/jni/SqliteException.java b/ext/jni/src/org/sqlite/jni/SqliteException.java
new file mode 100644 (file)
index 0000000..6eaf825
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+** 2023-10-09
+**
+** 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;
+import static org.sqlite.jni.CApi.*;
+
+/**
+   A wrapper for communicating C-level (sqlite3*) instances with
+   Java. These wrappers do not own their associated pointer, they
+   simply provide a type-safe way to communicate it between Java
+   and C via JNI.
+*/
+public final class SqliteException extends java.lang.RuntimeException {
+
+  public SqliteException(String msg){
+    super(msg);
+  }
+
+  public SqliteException(int sqlite3ResultCode){
+    super(sqlite3_errstr(sqlite3ResultCode));
+  }
+
+  public SqliteException(sqlite3 db){
+    super(sqlite3_errmsg(db));
+    db.close();
+  }
+
+  public SqliteException(Sqlite db){
+    this(db.dbHandle());
+  }
+
+}
index 70609bc7f7534c88e3f6e38467c4b26414bc1b53..0ff1c98dbe7f74a516f23c462d7e0a50247ffbd5 100644 (file)
@@ -1925,7 +1925,6 @@ public class Tester1 implements Runnable {
     sqlite3_shutdown();
     int nMethods = 0;
     int nNatives = 0;
-    int nCanonical = 0;
     final java.lang.reflect.Method[] declaredMethods =
       CApi.class.getDeclaredMethods();
     for(java.lang.reflect.Method m : declaredMethods){
@@ -1934,20 +1933,16 @@ public class Tester1 implements Runnable {
         final String name = m.getName();
         if(name.startsWith("sqlite3_")){
           ++nMethods;
-          if( m.isAnnotationPresent( org.sqlite.jni.annotation.Canonical.class ) ){
-            ++nCanonical;
-          }
           if( 0!=(mod & java.lang.reflect.Modifier.NATIVE) ){
             ++nNatives;
           }
         }
       }
     }
-    outln("\tSQLite3Jni.sqlite3_*() methods: "+
+    outln("\tCApi.sqlite3_*() methods: "+
           nMethods+" total, with "+
           nNatives+" native, "+
-          (nMethods - nNatives)+" Java, ",
-          nCanonical," @Canonical"
+          (nMethods - nNatives)+" Java"
     );
     outln("\tTotal test time = "
           +(timeEnd - timeStart)+"ms");
diff --git a/ext/jni/src/org/sqlite/jni/Tester2.java b/ext/jni/src/org/sqlite/jni/Tester2.java
new file mode 100644 (file)
index 0000000..a150eec
--- /dev/null
@@ -0,0 +1,417 @@
+/*
+** 2023-10-09
+**
+** 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;
+import static org.sqlite.jni.CApi.*;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+public class Tester2 implements Runnable {
+  //! True when running in multi-threaded mode.
+  private static boolean mtMode = false;
+  //! True to sleep briefly between tests.
+  private static boolean takeNaps = false;
+  //! True to shuffle the order of the tests.
+  private static boolean shuffle = false;
+  //! True to dump the list of to-run tests to stdout.
+  private static boolean listRunTests = false;
+  //! True to squelch all out() and outln() output.
+  private static boolean quietMode = false;
+  //! Total number of runTests() calls.
+  private static int nTestRuns = 0;
+  //! List of test*() methods to run.
+  private static List<java.lang.reflect.Method> testMethods = null;
+  //! List of exceptions collected by run()
+  private static List<Exception> listErrors = new ArrayList<>();
+  private static final class Metrics {
+    //! Number of times createNewDb() (or equivalent) is invoked.
+    volatile int dbOpen = 0;
+  }
+
+  //! Instance ID.
+  private Integer tId;
+
+  Tester2(Integer id){
+    tId = id;
+  }
+
+  static final Metrics metrics = new Metrics();
+
+  public static synchronized void outln(){
+    if( !quietMode ){
+      System.out.println("");
+    }
+  }
+
+  public static synchronized void outPrefix(){
+    if( !quietMode ){
+      System.out.print(Thread.currentThread().getName()+": ");
+    }
+  }
+
+  public static synchronized void outln(Object val){
+    if( !quietMode ){
+      outPrefix();
+      System.out.println(val);
+    }
+  }
+
+  public static synchronized void out(Object val){
+    if( !quietMode ){
+      System.out.print(val);
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  public static synchronized void out(Object... vals){
+    if( !quietMode ){
+      outPrefix();
+      for(Object v : vals) out(v);
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  public static synchronized void outln(Object... vals){
+    if( !quietMode ){
+      out(vals); out("\n");
+    }
+  }
+
+  static volatile int affirmCount = 0;
+  public static synchronized int affirm(Boolean v, String comment){
+    ++affirmCount;
+    if( false ) assert( v /* prefer assert over exception if it's enabled because
+                 the JNI layer sometimes has to suppress exceptions,
+                 so they might be squelched on their way back to the
+                 top. */);
+    if( !v ) throw new RuntimeException(comment);
+    return affirmCount;
+  }
+
+  public static void affirm(Boolean v){
+    affirm(v, "Affirmation failed.");
+  }
+
+  @SingleThreadOnly /* because it's thread-agnostic */
+  private void test1(){
+    affirm(sqlite3_libversion_number() == SQLITE_VERSION_NUMBER);
+  }
+
+  /* Copy/paste/rename this to add new tests. */
+  private void _testTemplate(){
+    //final sqlite3 db = createNewDb();
+    //sqlite3_stmt stmt = prepare(db,"SELECT 1");
+    //sqlite3_finalize(stmt);
+    //sqlite3_close_v2(db);
+  }
+
+  private void nap() throws InterruptedException {
+    if( takeNaps ){
+      Thread.sleep(java.util.concurrent.ThreadLocalRandom.current().nextInt(3, 17), 0);
+    }
+  }
+
+  @ManualTest /* because we only want to run this test on demand */
+  private void testFail(){
+    affirm( false, "Intentional failure." );
+  }
+
+  private void runTests(boolean fromThread) throws Exception {
+    List<java.lang.reflect.Method> mlist = testMethods;
+    affirm( null!=mlist );
+    if( shuffle ){
+      mlist = new ArrayList<>( testMethods.subList(0, testMethods.size()) );
+      java.util.Collections.shuffle(mlist);
+    }
+    if( listRunTests ){
+      synchronized(this.getClass()){
+        if( !fromThread ){
+          out("Initial test"," list: ");
+          for(java.lang.reflect.Method m : testMethods){
+            out(m.getName()+" ");
+          }
+          outln();
+          outln("(That list excludes some which are hard-coded to run.)");
+        }
+        out("Running"," tests: ");
+        for(java.lang.reflect.Method m : mlist){
+          out(m.getName()+" ");
+        }
+        outln();
+      }
+    }
+    for(java.lang.reflect.Method m : mlist){
+      nap();
+      try{
+        m.invoke(this);
+      }catch(java.lang.reflect.InvocationTargetException e){
+        outln("FAILURE: ",m.getName(),"(): ", e.getCause());
+        throw e;
+      }
+    }
+    synchronized( this.getClass() ){
+      ++nTestRuns;
+    }
+  }
+
+  public void run() {
+    try {
+      runTests(0!=this.tId);
+    }catch(Exception e){
+      synchronized( listErrors ){
+        listErrors.add(e);
+      }
+    }finally{
+      affirm( sqlite3_java_uncache_thread() );
+      affirm( !sqlite3_java_uncache_thread() );
+    }
+  }
+
+  /**
+     Runs the basic sqlite3 JNI binding sanity-check suite.
+
+     CLI flags:
+
+     -q|-quiet: disables most test output.
+
+     -t|-thread N: runs the tests in N threads
+      concurrently. Default=1.
+
+     -r|-repeat N: repeats the tests in a loop N times, each one
+      consisting of the -thread value's threads.
+
+     -shuffle: randomizes the order of most of the test functions.
+
+     -naps: sleep small random intervals between tests in order to add
+     some chaos for cross-thread contention.
+
+     -list-tests: outputs the list of tests being run, minus some
+      which are hard-coded. This is noisy in multi-threaded mode.
+
+     -fail: forces an exception to be thrown during the test run.  Use
+     with -shuffle to make its appearance unpredictable.
+
+     -v: emit some developer-mode info at the end.
+  */
+  public static void main(String[] args) throws Exception {
+    Integer nThread = 1;
+    boolean doSomethingForDev = false;
+    Integer nRepeat = 1;
+    boolean forceFail = false;
+    boolean sqlLog = false;
+    boolean configLog = false;
+    boolean squelchTestOutput = false;
+    for( int i = 0; i < args.length; ){
+      String arg = args[i++];
+      if(arg.startsWith("-")){
+        arg = arg.replaceFirst("-+","");
+        if(arg.equals("v")){
+          doSomethingForDev = true;
+          //listBoundMethods();
+        }else if(arg.equals("t") || arg.equals("thread")){
+          nThread = Integer.parseInt(args[i++]);
+        }else if(arg.equals("r") || arg.equals("repeat")){
+          nRepeat = Integer.parseInt(args[i++]);
+        }else if(arg.equals("shuffle")){
+          shuffle = true;
+        }else if(arg.equals("list-tests")){
+          listRunTests = true;
+        }else if(arg.equals("fail")){
+          forceFail = true;
+        }else if(arg.equals("sqllog")){
+          sqlLog = true;
+        }else if(arg.equals("configlog")){
+          configLog = true;
+        }else if(arg.equals("naps")){
+          takeNaps = true;
+        }else if(arg.equals("q") || arg.equals("quiet")){
+          squelchTestOutput = true;
+        }else{
+          throw new IllegalArgumentException("Unhandled flag:"+arg);
+        }
+      }
+    }
+
+    if( sqlLog ){
+      if( sqlite3_compileoption_used("ENABLE_SQLLOG") ){
+        final ConfigSqllogCallback log = new ConfigSqllogCallback() {
+            @Override public void call(sqlite3 db, String msg, int op){
+              switch(op){
+                case 0: outln("Opening db: ",db); break;
+                case 1: outln("SQL ",db,": ",msg); break;
+                case 2: outln("Closing db: ",db); break;
+              }
+            }
+          };
+        int rc = sqlite3_config( log );
+        affirm( 0==rc );
+        rc = sqlite3_config( (ConfigSqllogCallback)null );
+        affirm( 0==rc );
+        rc = sqlite3_config( log );
+        affirm( 0==rc );
+      }else{
+        outln("WARNING: -sqllog is not active because library was built ",
+              "without SQLITE_ENABLE_SQLLOG.");
+      }
+    }
+    if( configLog ){
+      final ConfigLogCallback log = new ConfigLogCallback() {
+          @Override public void call(int code, String msg){
+            outln("ConfigLogCallback: ",ResultCode.getEntryForInt(code),": ", msg);
+          };
+        };
+      int rc = sqlite3_config( log );
+      affirm( 0==rc );
+      rc = sqlite3_config( (ConfigLogCallback)null );
+      affirm( 0==rc );
+      rc = sqlite3_config( log );
+      affirm( 0==rc );
+    }
+
+    quietMode = squelchTestOutput;
+    outln("If you just saw warning messages regarding CallStaticObjectMethod, ",
+          "you are very likely seeing the side effects of a known openjdk8 ",
+          "bug. It is unsightly but does not affect the library.");
+
+    {
+      // Build list of tests to run from the methods named test*().
+      testMethods = new ArrayList<>();
+      int nSkipped = 0;
+      for(final java.lang.reflect.Method m : Tester2.class.getDeclaredMethods()){
+        final String name = m.getName();
+        if( name.equals("testFail") ){
+          if( forceFail ){
+            testMethods.add(m);
+          }
+        }else if( !m.isAnnotationPresent( ManualTest.class ) ){
+          if( nThread>1 && m.isAnnotationPresent( SingleThreadOnly.class ) ){
+            if( 0==nSkipped++ ){
+              out("Skipping tests in multi-thread mode:");
+            }
+            out(" "+name+"()");
+          }else if( name.startsWith("test") ){
+            testMethods.add(m);
+          }
+        }
+      }
+      if( nSkipped>0 ) out("\n");
+    }
+
+    final long timeStart = System.currentTimeMillis();
+    int nLoop = 0;
+    switch( sqlite3_threadsafe() ){ /* Sanity checking */
+      case 0:
+        affirm( SQLITE_ERROR==sqlite3_config( SQLITE_CONFIG_SINGLETHREAD ),
+                "Could not switch to single-thread mode." );
+        affirm( SQLITE_ERROR==sqlite3_config( SQLITE_CONFIG_MULTITHREAD ),
+                "Could switch to multithread mode."  );
+        affirm( SQLITE_ERROR==sqlite3_config( SQLITE_CONFIG_SERIALIZED ),
+                "Could not switch to serialized threading mode."  );
+        outln("This is a single-threaded build. Not using threads.");
+        nThread = 1;
+        break;
+      case 1:
+      case 2:
+        affirm( 0==sqlite3_config( SQLITE_CONFIG_SINGLETHREAD ),
+                "Could not switch to single-thread mode." );
+        affirm( 0==sqlite3_config( SQLITE_CONFIG_MULTITHREAD ),
+                "Could not switch to multithread mode."  );
+        affirm( 0==sqlite3_config( SQLITE_CONFIG_SERIALIZED ),
+                "Could not switch to serialized threading mode."  );
+        break;
+      default:
+        affirm( false, "Unhandled SQLITE_THREADSAFE value." );
+    }
+    outln("libversion_number: ",
+          sqlite3_libversion_number(),"\n",
+          sqlite3_libversion(),"\n",SQLITE_SOURCE_ID,"\n",
+          "SQLITE_THREADSAFE=",sqlite3_threadsafe());
+    final boolean showLoopCount = (nRepeat>1 && nThread>1);
+    if( showLoopCount ){
+      outln("Running ",nRepeat," loop(s) with ",nThread," thread(s) each.");
+    }
+    if( takeNaps ) outln("Napping between tests is enabled.");
+    for( int n = 0; n < nRepeat; ++n ){
+      ++nLoop;
+      if( showLoopCount ) out((1==nLoop ? "" : " ")+nLoop);
+      if( nThread<=1 ){
+        new Tester2(0).runTests(false);
+        continue;
+      }
+      Tester2.mtMode = true;
+      final ExecutorService ex = Executors.newFixedThreadPool( nThread );
+      for( int i = 0; i < nThread; ++i ){
+        ex.submit( new Tester2(i), i );
+      }
+      ex.shutdown();
+      try{
+        ex.awaitTermination(nThread*200, java.util.concurrent.TimeUnit.MILLISECONDS);
+        ex.shutdownNow();
+      }catch (InterruptedException ie){
+        ex.shutdownNow();
+        Thread.currentThread().interrupt();
+      }
+      if( !listErrors.isEmpty() ){
+        quietMode = false;
+        outln("TEST ERRORS:");
+        Exception err = null;
+        for( Exception e : listErrors ){
+          e.printStackTrace();
+          if( null==err ) err = e;
+        }
+        if( null!=err ) throw err;
+      }
+    }
+    if( showLoopCount ) outln();
+    quietMode = false;
+
+    final long timeEnd = System.currentTimeMillis();
+    outln("Tests done. Metrics across ",nTestRuns," total iteration(s):");
+    outln("\tAssertions checked: ",affirmCount);
+    outln("\tDatabases opened: ",metrics.dbOpen);
+    if( doSomethingForDev ){
+      sqlite3_jni_internal_details();
+    }
+    affirm( 0==sqlite3_release_memory(1) );
+    sqlite3_shutdown();
+    int nMethods = 0;
+    int nNatives = 0;
+    int nCanonical = 0;
+    final java.lang.reflect.Method[] declaredMethods =
+      CApi.class.getDeclaredMethods();
+    for(java.lang.reflect.Method m : declaredMethods){
+      final int mod = m.getModifiers();
+      if( 0!=(mod & java.lang.reflect.Modifier.STATIC) ){
+        final String name = m.getName();
+        if(name.startsWith("sqlite3_")){
+          ++nMethods;
+          if( 0!=(mod & java.lang.reflect.Modifier.NATIVE) ){
+            ++nNatives;
+          }
+        }
+      }
+    }
+    outln("\tCApi.sqlite3_*() methods: "+
+          nMethods+" total, with "+
+          nNatives+" native, "+
+          (nMethods - nNatives)+" Java"
+    );
+    outln("\tTotal test time = "
+          +(timeEnd - timeStart)+"ms");
+  }
+}
index 79de05ff3d40987ed153e96297852479e550ad00..7829104cd9a7a80b3da1648cdd79542e77fd1ad2 100644 (file)
@@ -33,67 +33,51 @@ public final class Fts5ExtensionApi extends NativePointerHolder<Fts5ExtensionApi
   */
   public static native Fts5ExtensionApi getInstance();
 
-  @Canonical
   public native int xColumnCount(@NotNull Fts5Context fcx);
 
-  @Canonical
   public native int xColumnSize(@NotNull Fts5Context cx, int iCol,
                                 @NotNull OutputPointer.Int32 pnToken);
 
-  @Canonical
   public native int xColumnText(@NotNull Fts5Context cx, int iCol,
                                 @NotNull OutputPointer.String txt);
 
-  @Canonical
   public native int xColumnTotalSize(@NotNull Fts5Context fcx, int iCol,
                                      @NotNull OutputPointer.Int64 pnToken);
 
-  @Canonical
   public native Object xGetAuxdata(@NotNull Fts5Context cx, boolean clearIt);
 
-  @Canonical
   public native int xInst(@NotNull Fts5Context cx, int iIdx,
                           @NotNull OutputPointer.Int32 piPhrase,
                           @NotNull OutputPointer.Int32 piCol,
                           @NotNull OutputPointer.Int32 piOff);
 
-  @Canonical
   public native int xInstCount(@NotNull Fts5Context fcx,
                                @NotNull OutputPointer.Int32 pnInst);
 
-  @Canonical
   public native int xPhraseCount(@NotNull Fts5Context fcx);
 
-  @Canonical
   public native int xPhraseFirst(@NotNull Fts5Context cx, int iPhrase,
                                  @NotNull Fts5PhraseIter iter,
                                  @NotNull OutputPointer.Int32 iCol,
                                  @NotNull OutputPointer.Int32 iOff);
 
-  @Canonical
   public native int xPhraseFirstColumn(@NotNull Fts5Context cx, int iPhrase,
                                        @NotNull Fts5PhraseIter iter,
                                        @NotNull OutputPointer.Int32 iCol);
-  @Canonical
   public native void xPhraseNext(@NotNull Fts5Context cx,
                                  @NotNull Fts5PhraseIter iter,
                                  @NotNull OutputPointer.Int32 iCol,
                                  @NotNull OutputPointer.Int32 iOff);
-  @Canonical
   public native void xPhraseNextColumn(@NotNull Fts5Context cx,
                                        @NotNull Fts5PhraseIter iter,
                                        @NotNull OutputPointer.Int32 iCol);
-  @Canonical
   public native int xPhraseSize(@NotNull Fts5Context fcx, int iPhrase);
 
-  @Canonical
   public native int xQueryPhrase(@NotNull Fts5Context cx, int iPhrase,
                                  @NotNull XQueryPhraseCallback callback);
-  @Canonical
   public native int xRowCount(@NotNull Fts5Context fcx,
                               @NotNull OutputPointer.Int64 nRow);
 
-  @Canonical
   public native long xRowid(@NotNull Fts5Context cx);
   /* Note that the JNI binding lacks the C version's xDelete()
      callback argument. Instead, if pAux has an xDestroy() method, it
@@ -102,14 +86,11 @@ public final class Fts5ExtensionApi extends NativePointerHolder<Fts5ExtensionApi
      pAux held by the JNI layer will be relinquished regardless of
      whether pAux has an xDestroy() method. */
 
-  @Canonical
   public native int xSetAuxdata(@NotNull Fts5Context cx, @Nullable Object pAux);
 
-  @Canonical
   public native int xTokenize(@NotNull Fts5Context cx, @NotNull byte[] pText,
                               @NotNull XTokenizeCallback callback);
 
-  @Canonical
   public native Object xUserData(Fts5Context cx);
   //^^^ returns the pointer passed as the 3rd arg to the C-level
   // fts5_api::xCreateFunction().
index d32a3d63d265fd87f7ea5882021bbf4aee34b094..3172dc83061b6648f064b45940b496755dcdf43e 100644 (file)
@@ -33,7 +33,6 @@ public final class fts5_api extends NativePointerHolder<fts5_api> {
   */
   public static synchronized native fts5_api getInstanceForDb(@NotNull sqlite3 db);
 
-  @Canonical
   public synchronized native int xCreateFunction(@NotNull String name,
                                                  @Nullable Object userData,
                                                  @NotNull fts5_extension_function xFunction);
index 27a6f9f1581b33d12d47bb8e5a200a10cc007d70..c358e91c8f510a8d7ec7877a0fcd5ec0eee8012b 100644 (file)
@@ -37,11 +37,6 @@ public final class sqlite3 extends NativePointerHolder<sqlite3>
       ;
   }
 
-  @Override protected void finalize(){
-    //System.out.println(this+".finalize()");
-    CApi.sqlite3_close_v2(this.clearNativePointer());
-  }
-
   @Override public void close(){
     CApi.sqlite3_close_v2(this.clearNativePointer());
   }
index 21e4bef03d4ef344be7a9636e2fb3a289b1c2838..e773b736310ca1a65ac1dbba65252886ad27d506 100644 (file)
@@ -24,11 +24,6 @@ public final class sqlite3_stmt extends NativePointerHolder<sqlite3_stmt>
   // Only invoked from JNI.
   private sqlite3_stmt(){}
 
-  //For as-yet-unknown reasons, this triggers a JVM crash.
-  //@Override protected void finalize(){
-  //  CApi.sqlite3_finalize(this.clearNativePointer());
-  //}
-
   @Override public void close(){
     CApi.sqlite3_finalize(this.clearNativePointer());
   }
index cc9a595b879f80a5f727c4e277ba862b536cfae1..cd5140dc7a9054da7aa6984d46524a0b910c980a 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Minor\sJNI\sdoc\sand\spublic/private\scleanups.
-D 2023-10-09T10:44:10.717
+C Add\sJNI\sSqlite\sand\sSqliteException\sclasses.\sAdd\sTester2.java\sas\sthe\smain\stest\sapp\sfor\sthe\shigh-level\sAPI.
+D 2023-10-09T11:46:32.020
 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 8c942ede995d4e42f79c838c03b913dde62f573b443fe8f308dae547bcf04d0b
+F ext/jni/GNUmakefile 8c44e22bad18ecc266dd8c521f215e95dc3741d9e337c51b175029abaedcfb35
 F ext/jni/README.md ef9ac115e97704ea995d743b4a8334e23c659e5534c3b64065a5405256d5f2f4
 F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa
 F ext/jni/src/c/sqlite3-jni.c fb8f178d27df828e3c797b4427a0a20545b44f5147ce38d09ce9b465be5a840b
@@ -262,8 +262,11 @@ F ext/jni/src/org/sqlite/jni/RollbackHookCallback.java ec6cd96bff5d3bc5af079cbf1
 F ext/jni/src/org/sqlite/jni/SQLFunction.java 544a875d33fd160467d82e2397ac33157b29971d715a821a4fad3c899113ee8c
 F ext/jni/src/org/sqlite/jni/SQLTester.java d246c67f93e2fa2603bd106dbb3246ea725c987dffd6e5d42214ae262f750c68
 F ext/jni/src/org/sqlite/jni/ScalarFunction.java 6d387bb499fbe3bc13c53315335233dbf6a0c711e8fa7c521683219b041c614c
+F ext/jni/src/org/sqlite/jni/Sqlite.java 04c1efa37eda02e5695a890479f2de5cc54abdbec61042611419f0141e05f83b
+F ext/jni/src/org/sqlite/jni/SqliteException.java cabf37b09f519b6b8aebecd100e7f66fffc1d244d3e46f62c2b12120b9e2a33c
 F ext/jni/src/org/sqlite/jni/TableColumnMetadata.java 54511b4297fa28dcb3f49b24035e34ced10e3fd44fd0e458e784f4d6b0096dab
-F ext/jni/src/org/sqlite/jni/Tester1.java 9326bf645accee7b4a509b7a4db1fa2ba46efaf131e0d53816a6ad109056cd97
+F ext/jni/src/org/sqlite/jni/Tester1.java f7b85fe24cf6c3e43bdf7e390617657e8137359f804d76921829c2a8c41b6df1
+F ext/jni/src/org/sqlite/jni/Tester2.java 75aa079e2baf8f73d95299da092e611656be0f6e12fe2fa051fdd984657857e2
 F ext/jni/src/org/sqlite/jni/TesterFts5.java d60fe9944a81156b3b5325dd1b0e8e92a1547468f39fd1266d06f7bb6a95fa70
 F ext/jni/src/org/sqlite/jni/TraceV2Callback.java f157edd9c72e7d2243c169061487cd7bb51a0d50f3ac976dbcbbacf748ab1fc2
 F ext/jni/src/org/sqlite/jni/UpdateHookCallback.java 959d4677a857c9079c6e96ddd10918b946d68359af6252b6f284379069ea3d27
@@ -274,19 +277,19 @@ F ext/jni/src/org/sqlite/jni/annotation/Nullable.java 0b1879852707f752512d4db9d7
 F ext/jni/src/org/sqlite/jni/annotation/package-info.java 977b374aed9d5853cbf3438ba3b0940abfa2ea4574f702a2448ee143b98ac3ca
 F ext/jni/src/org/sqlite/jni/fts5/Fts5.java e94681023785f1eff5399f0ddc82f46b035977d350f14838db659236ebdf6b41
 F ext/jni/src/org/sqlite/jni/fts5/Fts5Context.java 7058da97059b8e156c17561a47ecd7faa0fc3e2d8c2588b9a28dbff8d06202dd
-F ext/jni/src/org/sqlite/jni/fts5/Fts5ExtensionApi.java e2680721bd83129d0d650ba845b44d7634a9489a90a56c5ce3c54508bf470743
+F ext/jni/src/org/sqlite/jni/fts5/Fts5ExtensionApi.java c8e06475a6172a7cd61b2bad9cfb18b6f059ffdd2935e62856f95785a14fe0e5
 F ext/jni/src/org/sqlite/jni/fts5/Fts5PhraseIter.java 2a7f3d76a1206e6a43d4c4ed9609b294d5431cc7d8fb875d8419f76efa6e56dc
 F ext/jni/src/org/sqlite/jni/fts5/Fts5Tokenizer.java cc9a53846a168a215238af224c31cef0e8379780e36e8a5e743b00c08145cf19
 F ext/jni/src/org/sqlite/jni/fts5/XTokenizeCallback.java 1efd1220ea328a32f2d2a1b16c735864159e929480f71daad4de9d5944839167
-F ext/jni/src/org/sqlite/jni/fts5/fts5_api.java e2ad9bc06a9d307e0a6221c11645783898906455a92b1f7d5ec9b9ff1af1b8ea
+F ext/jni/src/org/sqlite/jni/fts5/fts5_api.java 90f09477331c371a8abe0a6504cfe094bc075b29a800be9d72a2c92a7bb49db1
 F ext/jni/src/org/sqlite/jni/fts5/fts5_extension_function.java 1fe0f5692c1d67475d12b067f0469949073446f18c56eba5ee5da6ddd06db9b9
 F ext/jni/src/org/sqlite/jni/fts5/fts5_tokenizer.java ea993738b851038c16d98576abd0db3d6028a231f075a394fb8a78c7834d0f6c
 F ext/jni/src/org/sqlite/jni/package-info.java 7d465cbdf9050761db0db6d0c542afaaad7dc67f61510860592159c48bfc40e8
-F ext/jni/src/org/sqlite/jni/sqlite3.java 3247101956b66c0a59333d3ddd3550eadf24b37c1ab15c322efbed5b221d0f08
+F ext/jni/src/org/sqlite/jni/sqlite3.java 4fa76f9c618264ed17ab613570076002c0b78717261b263350cd92d6d6b01242
 F ext/jni/src/org/sqlite/jni/sqlite3_backup.java 42db8b2f9cd8e9e16217273890e5d4afbb102603d7130a2cb1651f1c69c1cfa4
 F ext/jni/src/org/sqlite/jni/sqlite3_blob.java 7c341bca1856475fc3bf3697251e0cf1d737ddcb099c65d90afdc164aaddcc51
 F ext/jni/src/org/sqlite/jni/sqlite3_context.java ba8da75eaaeb557c986af3fb4dbc69501cf2b083ca33497f2c0c70dbc0a53f2c
-F ext/jni/src/org/sqlite/jni/sqlite3_stmt.java 38e5e88e79cde51a1dbeacfdbe7857b93ca105972f47c1198a51f0eaa48886f5
+F ext/jni/src/org/sqlite/jni/sqlite3_stmt.java fa0703004721c49d6d08a0c1e99439fadb8cebaebf42b81ee3f427d7f950d1eb
 F ext/jni/src/org/sqlite/jni/sqlite3_value.java 3d1d4903e267bc0bc81d57d21f5e85978eff389a1a6ed46726dbe75f85e6914a
 F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe59004a1485311c50a13edbf18c79a6ff9160030e
 F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43443408f3000139478c4dc745
@@ -2124,8 +2127,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 ca216b4486aff7d206ebfc3a5e84d48919c282425d4313396bc19313ffca8a0e
-R af6221100b1b0f5eb240f10a6b3978ab
+P c49d36ece283274963ce2e5a4db1e8f586dffa22e47f4adb93c625f918c3fd5d
+R fe6b079fd83fb48b0f0881df379b853e
 U stephan
-Z ff4bc4025115006080a68d26c19680b4
+Z 8f2bcd17cd435607663eb211630fda5f
 # Remove this line to create a well-formed Fossil manifest.
index 6ee1c62b7d0efbc7c01b4ebb766736f9d9688ba9..d42a4747b62dd0bba141b88748bebb6229cda93d 100644 (file)
@@ -1 +1 @@
-c49d36ece283274963ce2e5a4db1e8f586dffa22e47f4adb93c625f918c3fd5d
\ No newline at end of file
+6acf52be7abce8dcf434c5ebf0d5e88859b033e6418077846247ecf00ccf9381
\ No newline at end of file