Skip to content

Commit

Permalink
feat(sqlite): support serialize/deserialize sqlite APis
Browse files Browse the repository at this point in the history
  • Loading branch information
yuvalp-k2view authored Nov 8, 2023
1 parent 4232352 commit 6823954
Show file tree
Hide file tree
Showing 28 changed files with 387 additions and 0 deletions.
23 changes: 23 additions & 0 deletions src/main/java/org/sqlite/SQLiteConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -569,4 +569,27 @@ protected static String extractPragmasFromFilename(String url, String filename,
protected String transactionPrefix() {
return this.connectionConfig.transactionPrefix();
}

/**
* Returns a byte array representing the schema content. This method is intended for in-memory
* schemas. Serialized databases are limited to 2gb.
*
* @param schema The schema to serialize
* @return A byte[] holding the database content
*/
public byte[] serialize(String schema) throws SQLException {
return db.serialize(schema);
}

/**
* Deserialize the schema using the given byte array. This method is intended for in-memory
* database. The call will replace the content of an existing schema. To make sure there is an
* existing schema, first execute ATTACH ':memory:' AS schema_name
*
* @param schema The schema to serialize
* @param buff The buffer to deserialize
*/
public void deserialize(String schema, byte[] buff) throws SQLException {
db.deserialize(schema, buff);
}
}
4 changes: 4 additions & 0 deletions src/main/java/org/sqlite/core/DB.java
Original file line number Diff line number Diff line change
Expand Up @@ -1260,4 +1260,8 @@ private void ensureAutocommit(long beginPtr, long commitPtr) throws SQLException
reset(commitPtr);
}
}

public abstract byte[] serialize(String schema) throws SQLException;

public abstract void deserialize(String schema, byte[] buff) throws SQLException;
}
99 changes: 99 additions & 0 deletions src/main/java/org/sqlite/core/NativeDB.c
Original file line number Diff line number Diff line change
Expand Up @@ -1865,3 +1865,102 @@ JNIEXPORT void JNICALL Java_org_sqlite_core_NativeDB__1close(
sethandle(env, nativeDB, 0);
}
}

JNIEXPORT jbyteArray JNICALL Java_org_sqlite_core_NativeDB_serialize(JNIEnv *env, jobject this, jstring jschema)
{

sqlite3 *db = gethandle(env, this);
if (!db)
{
throwex_db_closed(env);
return NULL;
}

const char* schema = (*env)->GetStringUTFChars(env, jschema, 0);

sqlite3_int64 size;
int need_free=0;
unsigned char *buff = sqlite3_serialize(db, schema, &size, SQLITE_SERIALIZE_NOCOPY);
if (buff==NULL)
{
// This happens if we start without a deserialized database
buff = sqlite3_serialize(db, schema, &size, 0);
if (buff==NULL)
{
(*env)->ReleaseStringUTFChars(env, jschema, schema);
throwex_msg(env, "Serialization failed, allocation failed");
return NULL;
}
need_free = 1;
}
(*env)->ReleaseStringUTFChars(env, jschema, schema);

jbyteArray jbuff = (*env)->NewByteArray(env, size);
if (jbuff!=NULL)
{
void *jbuff_pointer = (*env)->GetPrimitiveArrayCritical(env, jbuff, NULL);
if (jbuff_pointer!=NULL)
{
memcpy(jbuff_pointer, buff, size);
(*env)->ReleasePrimitiveArrayCritical(env, jbuff, buff, 0);
}
else
{
throwex_msg(env, "Failed to get byte[] address");
(*env)->DeleteLocalRef(env, jbuff);
jbuff = NULL;
}
}
else
{
throwex_msg(env, "Failed to allocate java byte[]");
}


if (need_free)
{
sqlite3_free(buff);
}
return jbuff;
}

JNIEXPORT void JNICALL Java_org_sqlite_core_NativeDB_deserialize(JNIEnv *env, jobject this, jstring jschema, jbyteArray jbuff)
{
sqlite3 *db = gethandle(env, this);
if (!db)
{
throwex_db_closed(env);
return;
}

jlong size = (*env)->GetArrayLength(env, jbuff);
unsigned char *sqlite_buff = sqlite3_malloc64(size);
if (sqlite_buff==NULL)
{
throwex_msg(env, "Failed to allocate native memory for database");
return;
}

void *buff = (*env)->GetPrimitiveArrayCritical(env, jbuff, NULL);
if (buff==NULL)
{
throwex_msg(env, "Failed to get byte[] address");
sqlite3_free(sqlite_buff);
return;
}
memcpy(sqlite_buff, buff, size);
(*env)->ReleasePrimitiveArrayCritical(env, jbuff, buff, JNI_ABORT);

const char* schema = (*env)->GetStringUTFChars(env, jschema, 0);
int ret = sqlite3_deserialize(db, schema, sqlite_buff, size, size, SQLITE_DESERIALIZE_FREEONCLOSE | SQLITE_DESERIALIZE_RESIZEABLE);
if (ret!=SQLITE_OK)
{
throwex_errorcode(env, this, ret);
}
else
{
sqlite3_int64 max_size = 1024L * 1024L * 1000L * 2L; //~2gb, bigger values will result in sqlite malloc error
sqlite3_file_control(db, schema, SQLITE_FCNTL_SIZE_LIMIT, &max_size);
}
(*env)->ReleaseStringUTFChars(env, jschema, schema);
}
6 changes: 6 additions & 0 deletions src/main/java/org/sqlite/core/NativeDB.java
Original file line number Diff line number Diff line change
Expand Up @@ -559,4 +559,10 @@ long getUpdateListener() {
long getProgressHandler() {
return progressHandler;
}

@Override
public synchronized native byte[] serialize(String schema) throws SQLException;

@Override
public synchronized native void deserialize(String schema, byte[] buff) throws SQLException;
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified src/main/resources/org/sqlite/native/Linux/x86/libsqlitejdbc.so
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading

0 comments on commit 6823954

Please sign in to comment.