1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-01 06:27:03 +03:00

Wrap the sqlite3_backup API in the JNI wrapper1 API.

FossilOrigin-Name: 3ee6cc29d2111e7ad90860827c0ea808fdf07bc71defdade7e6794ec4a2a3ce2
This commit is contained in:
stephan
2023-11-04 22:47:40 +00:00
parent ffdb479e7c
commit dc8a684c11
4 changed files with 154 additions and 16 deletions

View File

@ -16,6 +16,7 @@ import java.nio.charset.StandardCharsets;
import org.sqlite.jni.capi.CApi;
import org.sqlite.jni.capi.sqlite3;
import org.sqlite.jni.capi.sqlite3_stmt;
import org.sqlite.jni.capi.sqlite3_backup;
import org.sqlite.jni.capi.OutputPointer;
/**
@ -767,14 +768,6 @@ public final class Sqlite implements AutoCloseable {
"This \"cannot happen\": all possible result codes were checked already."
);
}
/*
Potential signature change TODO:
boolean step()
Returning true for SQLITE_ROW and false for anything else.
Those semantics have proven useful in the WASM/JS bindings.
*/
}
/**
@ -1019,4 +1012,114 @@ public final class Sqlite implements AutoCloseable {
}
}
/**
Encapsulates state related to the sqlite3 backup API. Use
Sqlite.initBackup() to create new instances.
*/
public static final class Backup implements AutoCloseable {
private sqlite3_backup b = null;
private Sqlite dbTo = null;
private Sqlite dbFrom = null;
public static final int DONE = CApi.SQLITE_DONE;
public static final int BUSY = CApi.SQLITE_BUSY;
public static final int LOCKED = CApi.SQLITE_LOCKED;
Backup(Sqlite dbDest, String schemaDest,Sqlite dbSrc, String schemaSrc){
this.dbTo = dbDest;
this.dbFrom = dbSrc;
b = CApi.sqlite3_backup_init(dbDest.nativeHandle(), schemaDest,
dbSrc.nativeHandle(), schemaSrc);
if(null==b) toss();
}
private void toss(){
int rc = CApi.sqlite3_errcode(dbTo.nativeHandle());
if(0!=rc) throw new SqliteException(dbTo);
rc = CApi.sqlite3_errcode(dbFrom.nativeHandle());
if(0!=rc) throw new SqliteException(dbFrom);
throw new SqliteException(CApi.SQLITE_ERROR);
}
private sqlite3_backup getNative(){
if( null==b ) throw new IllegalStateException("This Backup is already closed.");
return b;
}
/**
If this backup is still active, this completes the backup and
frees its native resources, otherwise it this is a no-op.
*/
public void finish(){
if( null!=b ){
CApi.sqlite3_backup_finish(b);
b = null;
dbTo = null;
dbFrom = null;
}
}
/** Equivalent to finish(). */
@Override public void close(){
this.finish();
}
/**
Analog to sqlite3_backup_step(). Returns 0 if stepping succeeds
or, DONE if the end is reached, BUSY if one of the databases is
busy, LOCKED if one of the databases is locked, and throws for
any other result code or if this object has been closed. Note
that BUSY and LOCKED are not necessarily permanent errors, so
do not trigger an exception.
*/
public int step(int pageCount){
final int rc = CApi.sqlite3_backup_step(getNative(), pageCount);
switch(rc){
case 0:
case DONE:
case BUSY:
case LOCKED:
return rc;
default:
toss();
return CApi.SQLITE_ERROR/*not reached*/;
}
}
/**
Analog to sqlite3_backup_pagecount().
*/
public int pageCount(){
return CApi.sqlite3_backup_pagecount(getNative());
}
/**
Analog to sqlite3_backup_remaining().
*/
public int remaining(){
return CApi.sqlite3_backup_remaining(getNative());
}
}
/**
Analog to sqlite3_backup_init(). If schemaSrc is null, "main" is
assumed. Throws if either this db or dbSrc (the source db) are
not opened, if either of schemaDest or schemaSrc are null, or if
the underlying call to sqlite3_backup_init() fails.
The returned object must eventually be cleaned up by either
arranging for it to be auto-closed (e.g. using
try-with-resources) or by calling its finish() method.
*/
public Backup initBackup(String schemaDest, Sqlite dbSrc, String schemaSrc){
thisDb();
dbSrc.thisDb();
if( null==schemaSrc || null==schemaDest ){
throw new IllegalArgumentException(
"Neither the source nor destination schema name may be null."
);
}
return new Backup(this, schemaDest, dbSrc, schemaSrc);
}
}

View File

@ -603,6 +603,41 @@ public class Tester2 implements Runnable {
affirm( 8 == val.value );
}
private void testBackup(){
final Sqlite dbDest = openDb();
try (Sqlite dbSrc = openDb()) {
execSql(dbSrc, new String[]{
"pragma page_size=512; VACUUM;",
"create table t(a);",
"insert into t(a) values(1),(2),(3);"
});
Exception e = null;
try {
dbSrc.initBackup("main",dbSrc,"main");
}catch(Exception x){
e = x;
}
affirm( e instanceof SqliteException );
e = null;
try (Sqlite.Backup b = dbDest.initBackup("main",dbSrc,"main")) {
affirm( null!=b );
int rc;
while( Sqlite.Backup.DONE!=(rc = b.step(1)) ){
affirm( 0==rc );
}
affirm( b.pageCount() > 0 );
b.finish();
}
}
try (Sqlite.Stmt q = dbDest.prepare("SELECT sum(a) from t")) {
q.step();
affirm( q.columnInt(0) == 6 );
}
dbDest.close();
}
private void runTests(boolean fromThread) throws Exception {
List<java.lang.reflect.Method> mlist = testMethods;
affirm( null!=mlist );

View File

@ -1,5 +1,5 @@
C Reimplement\sauto-extensions\sin\sJava\sfor\suse\swith\sthe\sJNI\swrapper1\sAPI.
D 2023-11-04T21:51:34.589
C Wrap\sthe\ssqlite3_backup\sAPI\sin\sthe\sJNI\swrapper1\sAPI.
D 2023-11-04T22:47:40.514
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -296,9 +296,9 @@ F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe
F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java d5c108b02afd3c63c9e5e53f71f85273c1bfdc461ae526e0a0bb2b25e4df6483
F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03
F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 2833afdb9af5c1949bb35f4c926a5351fba9d1cdf0996864caa7b47827a346c7
F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 3da22cb18d8544fff1c7184aeaa2516c20d63e8a31db848eb7470ce285b284dc
F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java 8dd4cce0f0a42542af768a73c3c9e7bebd1c77207a35ba93de86c97d4c572847
F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 929a1e2ab4e135fbbae7f0d2d609f77cfbbc60bbec7ba789ce23d9c73bc6156e
F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 03638a1774a95bcc7b5de440a5f1398720460e30fc480032a2e8be24e997d30c
F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java 3c2eda2efe45a051e371ba98abee34f51ceec3bb7d28dfde866646b650fcb426
F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java 7b89a7391f771692c5b83b0a5b86266abe8d59f1c77d7a0eccc9b79f259d79af
F ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java c7d1452f9ff26175b3c19bbf273116cc2846610af68e01756d755f037fe7319f
F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43443408f3000139478c4dc745
@ -2142,8 +2142,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 b692eb8ccb2d0645599ad73a8bdacf5df499114244aadeb38aabc580fc4dc7c5
R 99817a8518af3f567a07823f0172a1fb
P 14ed4c64533622e5faf1aaa59c24885885aad43f1c0d4717773e79440e8e1468
R 631890601bc1abeba3be592d27b2aeb0
U stephan
Z 276f4a4bca9307a54b6144f3c8e4f323
Z 39a1f06f24f0b71c35deac1228d090c6
# Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
14ed4c64533622e5faf1aaa59c24885885aad43f1c0d4717773e79440e8e1468
3ee6cc29d2111e7ad90860827c0ea808fdf07bc71defdade7e6794ec4a2a3ce2