SQLite

Check-in [cefb6614e6]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Bind sqlite3_status(64)() to JNI.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | jni
Files: files | file ages | folders
SHA3-256: cefb6614e65ca1764ec72702f92f801382e63aa9b221fc9c68719d497e7499fd
User & Date: stephan 2023-08-12 10:06:59.356
Context
2023-08-12
10:27
Bind sqlite3_db_status() to JNI. (check-in: b79477a0af user: stephan tags: jni)
10:06
Bind sqlite3_status(64)() to JNI. (check-in: cefb6614e6 user: stephan tags: jni)
2023-08-11
21:25
Add timing info to SQLTester. (check-in: b69b5facbf user: stephan tags: jni)
Changes
Unified Diff Ignore Whitespace Patch
Changes to ext/jni/src/c/sqlite3-jni.c.
306
307
308
309
310
311
312
313


314
315
316
317
318
319
320

/* Helpers for jstring and jbyteArray. */
#define JSTR_TOC(ARG) (*env)->GetStringUTFChars(env, ARG, NULL)
#define JSTR_RELEASE(ARG,VAR) if(VAR) (*env)->ReleaseStringUTFChars(env, ARG, VAR)
#define JBA_TOC(ARG) (*env)->GetByteArrayElements(env,ARG, NULL)
#define JBA_RELEASE(ARG,VAR) if(VAR) (*env)->ReleaseByteArrayElements(env, ARG, VAR, JNI_ABORT)

/* Marker for code which needs(?) to be made thread-safe. */


#define FIXME_THREADING(REASON)

enum {
  /**
     Size of the NativePointerHolder cache.  Need enough space for
     (only) the library's NativePointerHolder types, a fixed count
     known at build-time. If we add more than this a fatal error will







|
>
>







306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322

/* Helpers for jstring and jbyteArray. */
#define JSTR_TOC(ARG) (*env)->GetStringUTFChars(env, ARG, NULL)
#define JSTR_RELEASE(ARG,VAR) if(VAR) (*env)->ReleaseStringUTFChars(env, ARG, VAR)
#define JBA_TOC(ARG) (*env)->GetByteArrayElements(env,ARG, NULL)
#define JBA_RELEASE(ARG,VAR) if(VAR) (*env)->ReleaseByteArrayElements(env, ARG, VAR, JNI_ABORT)

/* Marker for code which needs(?) to be made thread-safe.  REASON is a
   terse reminder about why that function requires a mutex.
*/
#define FIXME_THREADING(REASON)

enum {
  /**
     Size of the NativePointerHolder cache.  Need enough space for
     (only) the library's NativePointerHolder types, a fixed count
     known at build-time. If we add more than this a fatal error will
1384
1385
1386
1387
1388
1389
1390









1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
   to v. */
static void OutputPointer_set_Int32(JNIEnv * const env, jobject const jOut, int v){
  jfieldID setter = 0;
  setupOutputPointer(env, S3JniClassNames.OutputPointer_Int32, "I", jOut, &setter);
  (*env)->SetIntField(env, jOut, setter, (jint)v);
  EXCEPTION_IS_FATAL("Cannot set OutputPointer.Int32.value");
}










static void OutputPointer_set_sqlite3(JNIEnv * const env, jobject const jOut,
                              jobject jDb){
  jfieldID setter = 0;
  setupOutputPointer(env, S3JniClassNames.OutputPointer_sqlite3,
                     "Lorg/sqlite/jni/sqlite3;", jOut, &setter);
  (*env)->SetObjectField(env, jOut, setter, jDb);
  EXCEPTION_IS_FATAL("Cannot set OutputPointer.sqlite3.value");
}

static void OutputPointer_set_sqlite3_stmt(JNIEnv * const env, jobject const jOut,
                                   jobject jStmt){
  jfieldID setter = 0;
  setupOutputPointer(env, S3JniClassNames.OutputPointer_sqlite3_stmt,
                     "Lorg/sqlite/jni/sqlite3_stmt;", jOut, &setter);
  (*env)->SetObjectField(env, jOut, setter, jStmt);
  EXCEPTION_IS_FATAL("Cannot set OutputPointer.sqlite3_stmt.value");
}

#ifdef SQLITE_ENABLE_FTS5
/* Sets the value property of the OutputPointer.Int64 jOut object
   to v. */
static void OutputPointer_set_Int64(JNIEnv * const env, jobject const jOut, jlong v){
  jfieldID setter = 0;
  setupOutputPointer(env, S3JniClassNames.OutputPointer_Int64, "J", jOut, &setter);
  (*env)->SetLongField(env, jOut, setter, v);
  EXCEPTION_IS_FATAL("Cannot set OutputPointer.Int64.value");
}
#if 0
/* Sets the value property of the OutputPointer.ByteArray jOut object
   to v. */
static void OutputPointer_set_ByteArray(JNIEnv * const env, jobject const jOut,
                               jbyteArray const v){
  jfieldID setter = 0;
  setupOutputPointer(env, S3JniClassNames.OutputPointer_ByteArray, "[B",







>
>
>
>
>
>
>
>
>




















<
<
<
<
<
<
<
<







1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421








1422
1423
1424
1425
1426
1427
1428
   to v. */
static void OutputPointer_set_Int32(JNIEnv * const env, jobject const jOut, int v){
  jfieldID setter = 0;
  setupOutputPointer(env, S3JniClassNames.OutputPointer_Int32, "I", jOut, &setter);
  (*env)->SetIntField(env, jOut, setter, (jint)v);
  EXCEPTION_IS_FATAL("Cannot set OutputPointer.Int32.value");
}

/* Sets the value property of the OutputPointer.Int64 jOut object
   to v. */
static void OutputPointer_set_Int64(JNIEnv * const env, jobject const jOut, jlong v){
  jfieldID setter = 0;
  setupOutputPointer(env, S3JniClassNames.OutputPointer_Int64, "J", jOut, &setter);
  (*env)->SetLongField(env, jOut, setter, v);
  EXCEPTION_IS_FATAL("Cannot set OutputPointer.Int64.value");
}

static void OutputPointer_set_sqlite3(JNIEnv * const env, jobject const jOut,
                              jobject jDb){
  jfieldID setter = 0;
  setupOutputPointer(env, S3JniClassNames.OutputPointer_sqlite3,
                     "Lorg/sqlite/jni/sqlite3;", jOut, &setter);
  (*env)->SetObjectField(env, jOut, setter, jDb);
  EXCEPTION_IS_FATAL("Cannot set OutputPointer.sqlite3.value");
}

static void OutputPointer_set_sqlite3_stmt(JNIEnv * const env, jobject const jOut,
                                   jobject jStmt){
  jfieldID setter = 0;
  setupOutputPointer(env, S3JniClassNames.OutputPointer_sqlite3_stmt,
                     "Lorg/sqlite/jni/sqlite3_stmt;", jOut, &setter);
  (*env)->SetObjectField(env, jOut, setter, jStmt);
  EXCEPTION_IS_FATAL("Cannot set OutputPointer.sqlite3_stmt.value");
}

#ifdef SQLITE_ENABLE_FTS5








#if 0
/* Sets the value property of the OutputPointer.ByteArray jOut object
   to v. */
static void OutputPointer_set_ByteArray(JNIEnv * const env, jobject const jOut,
                               jbyteArray const v){
  jfieldID setter = 0;
  setupOutputPointer(env, S3JniClassNames.OutputPointer_ByteArray, "[B",
3108
3109
3110
3111
3112
3113
3114
























3115
3116
3117
3118
3119
3120
3121
}


JDECL(void,1set_1last_1insert_1rowid)(JENV_CSELF, jobject jpDb, jlong rowId){
  sqlite3_set_last_insert_rowid(PtrGet_sqlite3_context(jpDb),
                                (sqlite3_int64)rowId);
}

























static int s3jni_strlike_glob(int isLike, JNIEnv *const env,
                              jbyteArray baG, jbyteArray baT, jint escLike){
  int rc = 0;
  jbyte * const pG = JBA_TOC(baG);
  jbyte * const pT = pG ? JBA_TOC(baT) : 0;
  OOM_CHECK(pT);







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
}


JDECL(void,1set_1last_1insert_1rowid)(JENV_CSELF, jobject jpDb, jlong rowId){
  sqlite3_set_last_insert_rowid(PtrGet_sqlite3_context(jpDb),
                                (sqlite3_int64)rowId);
}

FIXME_THREADING(nphCache)
JDECL(jint,1status)(JENV_CSELF, jint op, jobject jOutCurrent, jobject jOutHigh,
                    jboolean reset ){
  int iCur = 0, iHigh = 0;
  int rc = sqlite3_status( op, &iCur, &iHigh, reset );
  if( 0==rc ){
    OutputPointer_set_Int32(env, jOutCurrent, iCur);
    OutputPointer_set_Int32(env, jOutHigh, iHigh);
  }
  return (jint)rc;
}

FIXME_THREADING(nphCache)
JDECL(jint,1status64)(JENV_CSELF, jint op, jobject jOutCurrent, jobject jOutHigh,
                      jboolean reset ){
  sqlite3_int64 iCur = 0, iHigh = 0;
  int rc = sqlite3_status64( op, &iCur, &iHigh, reset );
  if( 0==rc ){
    OutputPointer_set_Int64(env, jOutCurrent, iCur);
    OutputPointer_set_Int64(env, jOutHigh, iHigh);
  }
  return (jint)rc;
}

static int s3jni_strlike_glob(int isLike, JNIEnv *const env,
                              jbyteArray baG, jbyteArray baT, jint escLike){
  int rc = 0;
  jbyte * const pG = JBA_TOC(baG);
  jbyte * const pT = pG ? JBA_TOC(baT) : 0;
  OOM_CHECK(pT);
Changes to ext/jni/src/c/sqlite3-jni.h.
1415
1416
1417
1418
1419
1420
1421
















1422
1423
1424
1425
1426
1427
1428
 * Class:     org_sqlite_jni_SQLite3Jni
 * Method:    sqlite3_result_text64
 * Signature: (Lorg/sqlite/jni/sqlite3_context;[BJI)V
 */
JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1result_1text64
  (JNIEnv *, jclass, jobject, jbyteArray, jlong, jint);

















/*
 * Class:     org_sqlite_jni_SQLite3Jni
 * Method:    sqlite3_rollback_hook
 * Signature: (Lorg/sqlite/jni/sqlite3;Lorg/sqlite/jni/RollbackHook;)Lorg/sqlite/jni/RollbackHook;
 */
JNIEXPORT jobject JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1rollback_1hook
  (JNIEnv *, jclass, jobject, jobject);







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
 * Class:     org_sqlite_jni_SQLite3Jni
 * Method:    sqlite3_result_text64
 * Signature: (Lorg/sqlite/jni/sqlite3_context;[BJI)V
 */
JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1result_1text64
  (JNIEnv *, jclass, jobject, jbyteArray, jlong, jint);

/*
 * Class:     org_sqlite_jni_SQLite3Jni
 * Method:    sqlite3_status
 * Signature: (ILorg/sqlite/jni/OutputPointer/Int32;Lorg/sqlite/jni/OutputPointer/Int32;Z)I
 */
JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1status
  (JNIEnv *, jclass, jint, jobject, jobject, jboolean);

/*
 * Class:     org_sqlite_jni_SQLite3Jni
 * Method:    sqlite3_status64
 * Signature: (ILorg/sqlite/jni/OutputPointer/Int64;Lorg/sqlite/jni/OutputPointer/Int64;Z)I
 */
JNIEXPORT jint JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1status64
  (JNIEnv *, jclass, jint, jobject, jobject, jboolean);

/*
 * Class:     org_sqlite_jni_SQLite3Jni
 * Method:    sqlite3_rollback_hook
 * Signature: (Lorg/sqlite/jni/sqlite3;Lorg/sqlite/jni/RollbackHook;)Lorg/sqlite/jni/RollbackHook;
 */
JNIEXPORT jobject JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1rollback_1hook
  (JNIEnv *, jclass, jobject, jobject);
Changes to ext/jni/src/org/sqlite/jni/SQLite3Jni.java.
933
934
935
936
937
938
939
940
941
942
943

944
945
946
947
948
949
950
951
952
953
954
  */
  private static synchronized native void sqlite3_result_text64(
    @NotNull sqlite3_context cx, @Nullable byte[] text,
    long maxLength, int encoding
  );


  // public static synchronized native int sqlite3_status(
  //   int op, OutputPointer.Int32 pCurrent, OutputPointer.Int32 pHighwater,
  //   boolean reset
  // );

  // public static synchronized native int sqlite3_status64(
  //   int op, OutputPointer.Int64 pCurrent, OutputPointer.Int64 pHighwater,
  //   boolean reset
  // );

  /**
     Sets the current UDF result to the given bytes, which are assumed
     be encoded in UTF-16 using the platform's byte order.
  */
  public static void sqlite3_result_text16(
    @NotNull sqlite3_context cx, @Nullable byte[] text







|
|
|
|
>
|
|
|
|







933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
  */
  private static synchronized native void sqlite3_result_text64(
    @NotNull sqlite3_context cx, @Nullable byte[] text,
    long maxLength, int encoding
  );


  public static synchronized native int sqlite3_status(
    int op, @NotNull OutputPointer.Int32 pCurrent,
    @NotNull OutputPointer.Int32 pHighwater, boolean reset
  );

  public static synchronized native int sqlite3_status64(
    int op, @NotNull OutputPointer.Int64 pCurrent,
    @NotNull OutputPointer.Int64 pHighwater, boolean reset
  );

  /**
     Sets the current UDF result to the given bytes, which are assumed
     be encoded in UTF-16 using the platform's byte order.
  */
  public static void sqlite3_result_text16(
    @NotNull sqlite3_context cx, @Nullable byte[] text
Changes to ext/jni/src/org/sqlite/jni/Tester1.java.
135
136
137
138
139
140
141











142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
    int rc = sqlite3_prepare(db, sql, outStmt);
    affirm( 0 == rc );
    final sqlite3_stmt rv = outStmt.getValue();
    outStmt.clear();
    affirm( 0 != rv.getNativePointer() );
    return rv;
  }












  private static void testOpenDb1(){
    final OutputPointer.sqlite3 out = new OutputPointer.sqlite3();
    int rc = sqlite3_open(":memory:", out);
    ++metrics.dbOpen;
    sqlite3 db = out.getValue();
    affirm(0 == rc);
    affirm(0 < db.getNativePointer());
    sqlite3_db_config(db, SQLITE_DBCONFIG_DEFENSIVE, 1, null)
      /* This function has different mangled names in jdk8 vs jdk19,
         and this call is here to ensure that the build fails
         if it cannot find both names. */;
    sqlite3_close_v2(db);
    affirm(0 == db.getNativePointer());
  }

  private static void testCompileOption(){
    int i = 0;
    String optName;
    outln("compile options:");
    for( ; null != (optName = sqlite3_compileoption_get(i)); ++i){
      outln("\t"+optName+"\t (used="+
            sqlite3_compileoption_used(optName)+")");
    }

  }

  private static void testOpenDb2(){
    final OutputPointer.sqlite3 out = new OutputPointer.sqlite3();
    int rc = sqlite3_open_v2(":memory:", out,
                             SQLITE_OPEN_READWRITE
                             | SQLITE_OPEN_CREATE, null);







>
>
>
>
>
>
>
>
>
>
>














<
<
<
<
<
<
<
<
<
<
<







135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166











167
168
169
170
171
172
173
    int rc = sqlite3_prepare(db, sql, outStmt);
    affirm( 0 == rc );
    final sqlite3_stmt rv = outStmt.getValue();
    outStmt.clear();
    affirm( 0 != rv.getNativePointer() );
    return rv;
  }

  private static void testCompileOption(){
    int i = 0;
    String optName;
    outln("compile options:");
    for( ; null != (optName = sqlite3_compileoption_get(i)); ++i){
      outln("\t"+optName+"\t (used="+
            sqlite3_compileoption_used(optName)+")");
    }

  }

  private static void testOpenDb1(){
    final OutputPointer.sqlite3 out = new OutputPointer.sqlite3();
    int rc = sqlite3_open(":memory:", out);
    ++metrics.dbOpen;
    sqlite3 db = out.getValue();
    affirm(0 == rc);
    affirm(0 < db.getNativePointer());
    sqlite3_db_config(db, SQLITE_DBCONFIG_DEFENSIVE, 1, null)
      /* This function has different mangled names in jdk8 vs jdk19,
         and this call is here to ensure that the build fails
         if it cannot find both names. */;
    sqlite3_close_v2(db);
    affirm(0 == db.getNativePointer());











  }

  private static void testOpenDb2(){
    final OutputPointer.sqlite3 out = new OutputPointer.sqlite3();
    int rc = sqlite3_open_v2(":memory:", out,
                             SQLITE_OPEN_READWRITE
                             | SQLITE_OPEN_CREATE, null);
482
483
484
485
486
487
488





















489
490
491
492
493
494
495
       https://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html

       Let's ensure that we can convert to standard UTF-8 in Java code
       (noting that the JNI native API has no way to do this).
    */
    final byte[] ba = "a \0 b".getBytes(StandardCharsets.UTF_8);
    affirm( 5 == ba.length /* as opposed to 6 in modified utf-8 */);





















  }

  private static void testUdf1(){
    final sqlite3 db = createNewDb();
    // These ValueHolders are just to confirm that the func did what we want...
    final ValueHolder<Boolean> xDestroyCalled = new ValueHolder<>(false);
    final ValueHolder<Integer> xFuncAccum = new ValueHolder<>(0);







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
       https://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html

       Let's ensure that we can convert to standard UTF-8 in Java code
       (noting that the JNI native API has no way to do this).
    */
    final byte[] ba = "a \0 b".getBytes(StandardCharsets.UTF_8);
    affirm( 5 == ba.length /* as opposed to 6 in modified utf-8 */);
  }

  private static void testStatus(){
    final OutputPointer.Int64 cur64 = new OutputPointer.Int64();
    final OutputPointer.Int64 high64 = new OutputPointer.Int64();
    final OutputPointer.Int32 cur32 = new OutputPointer.Int32();
    final OutputPointer.Int32 high32 = new OutputPointer.Int32();
    final sqlite3 db = createNewDb();
    execSql(db, "create table t(a)");
    sqlite3_close_v2(db);

    int rc = sqlite3_status(SQLITE_STATUS_MEMORY_USED, cur32, high32, false);
    affirm( 0 == rc );
    affirm( cur32.getValue() > 0 );
    affirm( high32.getValue() >= cur32.getValue() );

    rc = sqlite3_status64(SQLITE_STATUS_MEMORY_USED, cur64, high64, false);
    affirm( 0 == rc );
    affirm( cur64.getValue() > 0 );
    affirm( high64.getValue() >= cur64.getValue() );

  }

  private static void testUdf1(){
    final sqlite3 db = createNewDb();
    // These ValueHolders are just to confirm that the func did what we want...
    final ValueHolder<Boolean> xDestroyCalled = new ValueHolder<>(false);
    final ValueHolder<Integer> xFuncAccum = new ValueHolder<>(0);
1079
1080
1081
1082
1083
1084
1085

1086
1087
1088
1089
1090
1091
1092
    testBindFetchInt64();
    testBindFetchDouble();
    testBindFetchText();
    testBindFetchBlob();
    testSql();
    testCollation();
    testToUtf8();

    testUdf1();
    testUdfJavaObject();
    testUdfAggregate();
    testUdfWindow();
    testTrace();
    testBusy();
    testProgress();







>







1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
    testBindFetchInt64();
    testBindFetchDouble();
    testBindFetchText();
    testBindFetchBlob();
    testSql();
    testCollation();
    testToUtf8();
    testStatus();
    testUdf1();
    testUdfJavaObject();
    testUdfAggregate();
    testUdfWindow();
    testTrace();
    testBusy();
    testProgress();