diff --git a/Makefile b/Makefile
index df6d0c4bf..c834906d2 100644
--- a/Makefile
+++ b/Makefile
@@ -48,9 +48,14 @@ jni-header: $(TARGET)/common-lib/NativeDB.h
$(TARGET)/common-lib/NativeDB.h: $(TARGET)/common-lib/org/sqlite/core/NativeDB.class
$(JAVAH) -classpath $(TARGET)/common-lib -jni -o $@ org.sqlite.core.NativeDB
-test:
+test: test-natives
mvn test
+test-natives:
+ mkdir -p target/test-classes/
+ $(CC) -I$(SQLITE_SOURCE) -fPIC -shared -o target/test-classes/libtest.so src/test/c/test.c
+ $(CC) -I$(SQLITE_SOURCE) -fPIC -shared -o target/test-classes/libtest2.so src/test/c/test2.c
+
clean: clean-native clean-java clean-tests
@@ -110,44 +115,44 @@ $(NATIVE_DLL): $(SQLITE_OUT)/$(LIBNAME)
DOCKER_RUN_OPTS=--rm
-win32: $(SQLITE_UNPACKED) jni-header
+win32: $(SQLITE_UNPACKED) jni-header test-natives
./docker/dockcross-windows-x86 -a $(DOCKER_RUN_OPTS) bash -c 'make clean-native native CROSS_PREFIX=i686-w64-mingw32.static- OS_NAME=Windows OS_ARCH=x86'
-win64: $(SQLITE_UNPACKED) jni-header
+win64: $(SQLITE_UNPACKED) jni-header test-natives
./docker/dockcross-windows-x64 -a $(DOCKER_RUN_OPTS) bash -c 'make clean-native native CROSS_PREFIX=x86_64-w64-mingw32.static- OS_NAME=Windows OS_ARCH=x86_64'
-linux32: $(SQLITE_UNPACKED) jni-header
+linux32: $(SQLITE_UNPACKED) jni-header test-natives
docker run $(DOCKER_RUN_OPTS) -ti -v $$PWD:/work xerial/centos5-linux-x86 bash -c 'make clean-native native OS_NAME=Linux OS_ARCH=x86'
-linux64: $(SQLITE_UNPACKED) jni-header
+linux64: $(SQLITE_UNPACKED) jni-header test-natives
docker run $(DOCKER_RUN_OPTS) -ti -v $$PWD:/work xerial/centos5-linux-x86_64 bash -c 'make clean-native native OS_NAME=Linux OS_ARCH=x86_64'
-alpine-linux64: $(SQLITE_UNPACKED) jni-header
+alpine-linux64: $(SQLITE_UNPACKED) jni-header test-natives
docker run $(DOCKER_RUN_OPTS) -ti -v $$PWD:/work xerial/alpine-linux-x86_64 bash -c 'make clean-native native OS_NAME=Linux OS_ARCH=x86_64'
-linux-arm: $(SQLITE_UNPACKED) jni-header
+linux-arm: $(SQLITE_UNPACKED) jni-header test-natives
./docker/dockcross-armv5 -a $(DOCKER_RUN_OPTS) bash -c 'make clean-native native CROSS_PREFIX=arm-linux-gnueabi- OS_NAME=Linux OS_ARCH=arm'
-linux-armv6: $(SQLITE_UNPACKED) jni-header
+linux-armv6: $(SQLITE_UNPACKED) jni-header test-natives
./docker/dockcross-armv6 -a $(DOCKER_RUN_OPTS) bash -c 'make clean-native native CROSS_PREFIX=arm-linux-gnueabihf- OS_NAME=Linux OS_ARCH=armv6'
-linux-armv7: $(SQLITE_UNPACKED) jni-header
+linux-armv7: $(SQLITE_UNPACKED) jni-header test-natives
./docker/dockcross-armv7 -a $(DOCKER_RUN_OPTS) bash -c 'make clean-native native CROSS_PREFIX=arm-linux-gnueabihf- OS_NAME=Linux OS_ARCH=armv7'
-linux-arm64: $(SQLITE_UNPACKED) jni-header
+linux-arm64: $(SQLITE_UNPACKED) jni-header test-natives
./docker/dockcross-arm64 -a $(DOCKER_RUN_OPTS) bash -c 'make clean-native native CROSS_PREFIX=/usr/bin/aarch64-unknown-linux-gnueabi/bin/aarch64-unknown-linux-gnueabi- OS_NAME=Linux OS_ARCH=aarch64'
-linux-android-arm: $(SQLITE_UNPACKED) jni-header
+linux-android-arm: $(SQLITE_UNPACKED) jni-header test-natives
./docker/dockcross-android-arm -a $(DOCKER_RUN_OPTS) bash -c 'make clean-native native CROSS_PREFIX=/usr/arm-linux-androideabi/bin/arm-linux-androideabi- OS_NAME=Linux OS_ARCH=android-arm'
-linux-ppc64: $(SQLITE_UNPACKED) jni-header
+linux-ppc64: $(SQLITE_UNPACKED) jni-header test-natives
./docker/dockcross-ppc64 -a $(DOCKER_RUN_OPTS) bash -c 'make clean-native native CROSS_PREFIX=powerpc64le-linux-gnu- OS_NAME=Linux OS_ARCH=ppc64'
-mac64: $(SQLITE_UNPACKED) jni-header
+mac64: $(SQLITE_UNPACKED) jni-header test-natives
docker run -it $(DOCKER_RUN_OPTS) -v $$PWD:/workdir -e CROSS_TRIPLE=x86_64-apple-darwin multiarch/crossbuild make clean-native native OS_NAME=Mac OS_ARCH=x86_64
# deprecated
-mac32: $(SQLITE_UNPACKED) jni-header
+mac32: $(SQLITE_UNPACKED) jni-header test-natives
docker run -it $(DOCKER_RUN_OPTS) -v $$PWD:/workdir -e CROSS_TRIPLE=i386-apple-darwin multiarch/crossbuild make clean-native native OS_NAME=Mac OS_ARCH=x86
sparcv9:
@@ -166,6 +171,7 @@ clean-java:
clean-tests:
rm -rf $(TARGET)/{surefire*,testdb.jar*}
+ rm -rf target/test-classes
docker-linux64:
docker build -f docker/Dockerfile.linux_x86_64 -t xerial/centos5-linux-x86_64 .
diff --git a/src/main/java/org/sqlite/ExtensionInfo.java b/src/main/java/org/sqlite/ExtensionInfo.java
new file mode 100644
index 000000000..70b5bec13
--- /dev/null
+++ b/src/main/java/org/sqlite/ExtensionInfo.java
@@ -0,0 +1,178 @@
+package org.sqlite;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.sqlite.util.StringUtils;
+
+/**
+ * File and entry point needed to load a SQLite extension.
+ *
+ * Also provides static methods to serialize and deserialize a
+ * collection of
+ * Loading of extensions has to be enabled:
+ * ExtensionInfo
s into a String
.
+ *
+ * @see https://sqlite.org/loadext.html#loading_an_extension
+ * @see https://sqlite.org/lang_corefunc.html#load_extension
+ * @see https://sqlite.org/c3ref/load_extension.html
+ * @author Andy-2639
+ */
+public class ExtensionInfo {
+
+ private static final char SERIALIZE_ESCAPE_CHAR = '|';
+ private static final char SERIALIZE_EXTENSION_INFO_SEPARATOR = '*';
+ private static final char SERIALIZE_FILE_ENTRY_SEPARATOR = '"';
+
+ /** Must not be null
. */
+ private final String file;
+ /** May be null. */
+ private final String entry;
+
+ /*
+ *
null
.
+ * @return Serialized {@link ExtensionInfo}s. Never null
.
+ */
+ static String serialize(Collectionnull
.
+ */
+ static Setnull
, SQLite determines the entry point.
+ *
+ * @see https://sqlite.org/lang_corefunc.html#load_extension
+ * @see https://sqlite.org/c3ref/load_extension.html
+ */
+ ExtensionInfo(String file, String entry) {
+ if (file == null) {
+ throw new NullPointerException("file must not be null");
+ }
+ this.file = file;
+ this.entry = entry;
+ }
+
+ /**
+ * @return file native library containing the SQLite extension. Never null
.
+ */
+ public String getFile() {
+ return file;
+ }
+
+ /**
+ * Entry point of the extension.
+ *
+ * @return may be null
.
+ */
+ public String getEntry() {
+ return entry;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + file.hashCode();
+ result = prime * result + ((entry == null) ? 0 : entry.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if ((obj == null) || (getClass() != obj.getClass())) {
+ return false;
+ }
+ ExtensionInfo other = (ExtensionInfo)obj;
+ if (!file.equals(other.file)) {
+ return false;
+ }
+ if ((entry == null) != (other.entry == null)) {
+ return false;
+ }
+ if ((entry != null) && !(entry.equals(other.entry))) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/src/main/java/org/sqlite/SQLiteConfig.java b/src/main/java/org/sqlite/SQLiteConfig.java
index b783bb7b8..705ba1ce5 100755
--- a/src/main/java/org/sqlite/SQLiteConfig.java
+++ b/src/main/java/org/sqlite/SQLiteConfig.java
@@ -54,6 +54,9 @@ public class SQLiteConfig
private final int busyTimeout;
+ /** @author Andy-2639 */
+ private final Set
+ *
+ *
null
, SQLite determines the entry point.
+ * @throws SQLException
+ * @see https://sqlite.org/c3ref/load_extension.html
+ */
+ public abstract void load_extension(String file, String entry) throws SQLException;
+
+ /**
+ * Enables or disables loading of SQLite extensions (SQLite C-API and SQL function load_extension).
* @param enable True to enable; false otherwise.
* @return Result Codes
* @throws SQLException
* @see http://www.sqlite.org/c3ref/load_extension.html
+ * @see https://sqlite.org/c3ref/enable_load_extension.html
*/
public abstract int enable_load_extension(boolean enable) throws SQLException;
diff --git a/src/main/java/org/sqlite/core/NativeDB.c b/src/main/java/org/sqlite/core/NativeDB.c
index d05186da5..078746632 100644
--- a/src/main/java/org/sqlite/core/NativeDB.c
+++ b/src/main/java/org/sqlite/core/NativeDB.c
@@ -445,6 +445,51 @@ JNIEXPORT jint JNICALL Java_org_sqlite_core_NativeDB_shared_1cache(
}
+JNIEXPORT jint JNICALL Java_org_sqlite_core_NativeDB_dbconfig_1enable_1load_1extension
+ (JNIEnv *env, jobject this, jboolean enable)
+{
+ sqlite3 *db = gethandle(env, this);
+ if (!db)
+ {
+ throwex_db_closed(env);
+ return SQLITE_MISUSE;
+ }
+ return sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, enable ? 1 : 0, NULL);
+}
+
+
+JNIEXPORT void JNICALL Java_org_sqlite_core_NativeDB_load_1extension_1utf8
+ (JNIEnv *env, jobject this, jbyteArray file, jbyteArray entry)
+{
+ sqlite3 *db = gethandle(env, this);
+ if (!db)
+ {
+ throwex_db_closed(env);
+ }
+
+ char *file_bytes;
+ utf8JavaByteArrayToUtf8Bytes(env, file, &file_bytes, NULL);
+ if (!file_bytes)
+ {
+ return;
+ }
+
+ char *entry_bytes; // may be null to let SQLite determine entry name
+ utf8JavaByteArrayToUtf8Bytes(env, entry, &entry_bytes, NULL);
+
+ char *error_msg;
+ int result = sqlite3_load_extension(db, file_bytes, entry_bytes, &error_msg);
+ if (result != SQLITE_OK)
+ {
+ throwex_msg(env, error_msg);
+ }
+ sqlite3_free(error_msg);
+
+ freeUtf8Bytes(entry_bytes);
+ freeUtf8Bytes(file_bytes);
+}
+
+
JNIEXPORT jint JNICALL Java_org_sqlite_core_NativeDB_enable_1load_1extension(
JNIEnv *env, jobject this, jboolean enable)
{
diff --git a/src/main/java/org/sqlite/core/NativeDB.java b/src/main/java/org/sqlite/core/NativeDB.java
index d686ba9ff..66b14623e 100644
--- a/src/main/java/org/sqlite/core/NativeDB.java
+++ b/src/main/java/org/sqlite/core/NativeDB.java
@@ -102,6 +102,23 @@ public synchronized int _exec(String sql) throws SQLException {
@Override
public native synchronized int shared_cache(boolean enable);
+ /**
+ * @see org.sqlite.core.B#dbconfig_enable_load_extension(boolean)
+ */
+ @Override
+ public native synchronized int dbconfig_enable_load_extension(boolean enable) throws SQLException;
+
+ /**
+ * @see org.sqlite.core.DB#load_extension(String, String)
+ */
+ @Override
+ public void load_extension(String file, String entry) throws SQLException {
+ this.load_extension_utf8(NativeDB.stringToUtf8ByteArray(file),
+ NativeDB.stringToUtf8ByteArray(entry));
+ }
+
+ private native synchronized void load_extension_utf8(byte[] file, byte[] entry) throws SQLException;
+
/**
* @see org.sqlite.core.DB#enable_load_extension(boolean)
*/
diff --git a/src/main/java/org/sqlite/util/StringUtils.java b/src/main/java/org/sqlite/util/StringUtils.java
index ca6abde79..06466e20b 100644
--- a/src/main/java/org/sqlite/util/StringUtils.java
+++ b/src/main/java/org/sqlite/util/StringUtils.java
@@ -16,4 +16,42 @@ public static String join(Listnull
.
+ * @return
+ * @author Andy-2639
+ */
+ public static boolean inArray(char needle, char... haystack) {
+ for (int i = 0; i < haystack.length; i++) {
+ if (needle == haystack[i]) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @param s must NOT be null.
+ * @param esc
+ * @param specials must NOT be null
.
+ * @return never null
.
+ * @author Andy-2639
+ */
+ public static String escape(String s, char esc, char... specials) {
+ StringBuilder sb = new StringBuilder(2 * s.length());
+ for (int i = 0; i < s.length(); i++) {
+ char ch = s.charAt(i);
+ if ((ch == esc) || (StringUtils.inArray(ch, specials))) {
+ sb.append(esc);
+ }
+ sb.append(ch);
+ }
+ if (s.length() == sb.length()) {
+ return s;
+ } else {
+ return sb.toString();
+ }
+ }
}
diff --git a/src/main/resources/org/sqlite/native/Linux/aarch64/libsqlitejdbc.so b/src/main/resources/org/sqlite/native/Linux/aarch64/libsqlitejdbc.so
index d5be6dd14..caa25f31e 100755
Binary files a/src/main/resources/org/sqlite/native/Linux/aarch64/libsqlitejdbc.so and b/src/main/resources/org/sqlite/native/Linux/aarch64/libsqlitejdbc.so differ
diff --git a/src/main/resources/org/sqlite/native/Linux/android-arm/libsqlitejdbc.so b/src/main/resources/org/sqlite/native/Linux/android-arm/libsqlitejdbc.so
index a0a349467..c29884518 100755
Binary files a/src/main/resources/org/sqlite/native/Linux/android-arm/libsqlitejdbc.so and b/src/main/resources/org/sqlite/native/Linux/android-arm/libsqlitejdbc.so differ
diff --git a/src/main/resources/org/sqlite/native/Linux/arm/libsqlitejdbc.so b/src/main/resources/org/sqlite/native/Linux/arm/libsqlitejdbc.so
index 4c88289cd..d8084fd2e 100755
Binary files a/src/main/resources/org/sqlite/native/Linux/arm/libsqlitejdbc.so and b/src/main/resources/org/sqlite/native/Linux/arm/libsqlitejdbc.so differ
diff --git a/src/main/resources/org/sqlite/native/Linux/armv6/libsqlitejdbc.so b/src/main/resources/org/sqlite/native/Linux/armv6/libsqlitejdbc.so
index 115b86b6f..77d05c4de 100755
Binary files a/src/main/resources/org/sqlite/native/Linux/armv6/libsqlitejdbc.so and b/src/main/resources/org/sqlite/native/Linux/armv6/libsqlitejdbc.so differ
diff --git a/src/main/resources/org/sqlite/native/Linux/armv7/libsqlitejdbc.so b/src/main/resources/org/sqlite/native/Linux/armv7/libsqlitejdbc.so
index 70a842a63..c9b4ba3af 100755
Binary files a/src/main/resources/org/sqlite/native/Linux/armv7/libsqlitejdbc.so and b/src/main/resources/org/sqlite/native/Linux/armv7/libsqlitejdbc.so differ
diff --git a/src/main/resources/org/sqlite/native/Linux/ppc64/libsqlitejdbc.so b/src/main/resources/org/sqlite/native/Linux/ppc64/libsqlitejdbc.so
index 4ad134b3a..0c433b854 100755
Binary files a/src/main/resources/org/sqlite/native/Linux/ppc64/libsqlitejdbc.so and b/src/main/resources/org/sqlite/native/Linux/ppc64/libsqlitejdbc.so differ
diff --git a/src/main/resources/org/sqlite/native/Linux/x86/libsqlitejdbc.so b/src/main/resources/org/sqlite/native/Linux/x86/libsqlitejdbc.so
index 5798d8645..f08999a48 100644
Binary files a/src/main/resources/org/sqlite/native/Linux/x86/libsqlitejdbc.so and b/src/main/resources/org/sqlite/native/Linux/x86/libsqlitejdbc.so differ
diff --git a/src/main/resources/org/sqlite/native/Linux/x86_64/libsqlitejdbc.so b/src/main/resources/org/sqlite/native/Linux/x86_64/libsqlitejdbc.so
index 6a51dc15d..a496ba355 100644
Binary files a/src/main/resources/org/sqlite/native/Linux/x86_64/libsqlitejdbc.so and b/src/main/resources/org/sqlite/native/Linux/x86_64/libsqlitejdbc.so differ
diff --git a/src/main/resources/org/sqlite/native/Mac/x86_64/libsqlitejdbc.jnilib b/src/main/resources/org/sqlite/native/Mac/x86_64/libsqlitejdbc.jnilib
index 5eaa716e3..d323c6501 100755
Binary files a/src/main/resources/org/sqlite/native/Mac/x86_64/libsqlitejdbc.jnilib and b/src/main/resources/org/sqlite/native/Mac/x86_64/libsqlitejdbc.jnilib differ
diff --git a/src/main/resources/org/sqlite/native/Windows/x86/sqlitejdbc.dll b/src/main/resources/org/sqlite/native/Windows/x86/sqlitejdbc.dll
index 3939d2114..b3f368596 100755
Binary files a/src/main/resources/org/sqlite/native/Windows/x86/sqlitejdbc.dll and b/src/main/resources/org/sqlite/native/Windows/x86/sqlitejdbc.dll differ
diff --git a/src/main/resources/org/sqlite/native/Windows/x86_64/sqlitejdbc.dll b/src/main/resources/org/sqlite/native/Windows/x86_64/sqlitejdbc.dll
index 687d284af..5a82f84ec 100755
Binary files a/src/main/resources/org/sqlite/native/Windows/x86_64/sqlitejdbc.dll and b/src/main/resources/org/sqlite/native/Windows/x86_64/sqlitejdbc.dll differ
diff --git a/src/test/c/test.c b/src/test/c/test.c
new file mode 100644
index 000000000..50fdd7139
--- /dev/null
+++ b/src/test/c/test.c
@@ -0,0 +1,46 @@
+#ifndef SQLITE_CORE
+ #include "sqlite3ext.h"
+ SQLITE_EXTENSION_INIT1
+#else
+ #include "sqlite3.h"
+#endif
+
+static void test(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv)
+{
+ sqlite3_result_int(context, 1);
+}
+
+#if !SQLITE_CORE
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_test_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi)
+{
+ SQLITE_EXTENSION_INIT2(pApi)
+ return sqlite3_create_function(
+ db, "test", 0, SQLITE_ANY, (void*)0,
+ test, 0, 0);
+}
+#endif
+
+#if !SQLITE_CORE
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_testa_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi)
+{
+ SQLITE_EXTENSION_INIT2(pApi)
+ return sqlite3_create_function(
+ db, "testa", 0, SQLITE_ANY, (void*)0,
+ test, 0, 0);
+}
+#endif
diff --git a/src/test/c/test2.c b/src/test/c/test2.c
new file mode 100644
index 000000000..507472e14
--- /dev/null
+++ b/src/test/c/test2.c
@@ -0,0 +1,30 @@
+#ifndef SQLITE_CORE
+ #include "sqlite3ext.h"
+ SQLITE_EXTENSION_INIT1
+#else
+ #include "sqlite3.h"
+#endif
+
+static void test2(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv)
+{
+ sqlite3_result_int(context, 1);
+}
+
+#if !SQLITE_CORE
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int sqlite3_test_init(
+ sqlite3 *db,
+ char **pzErrMsg,
+ const sqlite3_api_routines *pApi)
+{
+ SQLITE_EXTENSION_INIT2(pApi)
+ return sqlite3_create_function(
+ db, "test2", 0, SQLITE_ANY, (void*)0,
+ test2, 0, 0);
+}
+#endif
diff --git a/src/test/java/org/sqlite/AllTests.java b/src/test/java/org/sqlite/AllTests.java
index 9e3ad4584..6ab88117b 100644
--- a/src/test/java/org/sqlite/AllTests.java
+++ b/src/test/java/org/sqlite/AllTests.java
@@ -29,7 +29,8 @@
UDFTest.class,
JSON1Test.class,
ProgressHandlerTest.class,
- BusyHandlerTest.class
+ BusyHandlerTest.class,
+ LoadExtensionTest.class,
})
public class AllTests {
diff --git a/src/test/java/org/sqlite/LoadExtensionTest.java b/src/test/java/org/sqlite/LoadExtensionTest.java
new file mode 100644
index 000000000..50d946527
--- /dev/null
+++ b/src/test/java/org/sqlite/LoadExtensionTest.java
@@ -0,0 +1,207 @@
+package org.sqlite;
+
+import static org.junit.Assert.*;
+import static org.junit.Assume.assumeTrue;
+
+import java.io.File;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * @author Andy-2639
+ */
+public class LoadExtensionTest {
+
+ public static final String LIBTEST = "target/test-classes/libtest.so";
+ public static final String LIBTEST2 = "target/test-classes/libtest2.so";
+
+ @BeforeClass
+ public static void beforeClass() {
+ assumeTrue((new File(LIBTEST)).exists());
+ assumeTrue((new File(LIBTEST2)).exists());
+ }
+
+ public SQLException execute(Connection conn, String sql) throws SQLException {
+ Statement stmt = null;
+ try {
+ stmt = conn.createStatement();
+ try {
+ stmt.execute(sql);
+ return null;
+ } catch (SQLException se) {
+ return se;
+ }
+ } finally {
+ if (stmt != null) {
+ stmt.close();
+ stmt = null;
+ }
+ }
+ }
+
+ @Test
+ public void testFunctionsNotDefined() throws SQLException {
+ Connection conn = null;
+ try {
+ SQLiteConfig config = new SQLiteConfig();
+ conn = config.createConnection("jdbc:sqlite:");
+ assertNotNull(this.execute(conn, "SELECT test()"));
+ assertNotNull(this.execute(conn, "SELECT testa()"));
+ assertNotNull(this.execute(conn, "SELECT test2()"));
+ assertNotNull(this.execute(conn, "SELECT test3()"));
+ } finally {
+ if (conn != null) {
+ conn.close();
+ conn = null;
+ }
+ }
+ }
+
+ @Test
+ public void testLoadSqlNotAllowed() throws SQLException {
+ Connection conn = null;
+ try {
+ SQLiteConfig config = new SQLiteConfig();
+ conn = config.createConnection("jdbc:sqlite:");
+ assertNotNull(this.execute(conn, "SELECT load_extension('" + LIBTEST + "');"));
+ } finally {
+ if (conn != null) {
+ conn.close();
+ conn = null;
+ }
+ }
+ }
+
+ @Test
+ public void testLoadSqlAllowed() throws SQLException {
+ Connection conn = null;
+ try {
+ SQLiteConfig config = new SQLiteConfig();
+ config.enableLoadExtension(true);
+ conn = config.createConnection("jdbc:sqlite:");
+ assertNull(this.execute(conn, "SELECT load_extension('" + LIBTEST + "');"));
+ assertNull(this.execute(conn, "SELECT test();"));
+ assertNotNull(this.execute(conn, "SELECT testa();"));
+ } finally {
+ if (conn != null) {
+ conn.close();
+ conn = null;
+ }
+ }
+ }
+
+ @Test
+ public void testLoadSqlAllowed2() throws SQLException {
+ Connection conn = null;
+ try {
+ SQLiteConfig config = new SQLiteConfig();
+ config.enableLoadExtension(true);
+ conn = config.createConnection("jdbc:sqlite:");
+ assertNull(this.execute(conn, "SELECT load_extension('" + LIBTEST + "', 'sqlite3_testa_init');"));
+ assertNull(this.execute(conn, "SELECT testa();"));
+ assertNotNull(this.execute(conn, "SELECT test();"));
+ } finally {
+ if (conn != null) {
+ conn.close();
+ conn = null;
+ }
+ }
+ }
+
+ @Test
+ public void testLoadCApi() throws SQLException {
+ Connection conn = null;
+ try {
+ SQLiteConfig config = new SQLiteConfig();
+ config.loadExtension(LIBTEST);
+ conn = config.createConnection("jdbc:sqlite:");
+ assertNull(this.execute(conn, "SELECT test();"));
+ assertNotNull(this.execute(conn, "SELECT testa();"));
+ } finally {
+ if (conn != null) {
+ conn.close();
+ conn = null;
+ }
+ }
+ }
+
+ @Test
+ public void testLoadCApi2() throws SQLException {
+ Connection conn = null;
+ try {
+ SQLiteConfig config = new SQLiteConfig();
+ config.loadExtension(LIBTEST, "sqlite3_testa_init");
+ conn = config.createConnection("jdbc:sqlite:");
+ assertNull(this.execute(conn, "SELECT testa();"));
+ assertNotNull(this.execute(conn, "SELECT test();"));
+ } finally {
+ if (conn != null) {
+ conn.close();
+ conn = null;
+ }
+ }
+ }
+
+ @Test
+ public void testLoadCApiForbiddenSql() throws SQLException {
+ Connection conn = null;
+ try {
+ SQLiteConfig config = new SQLiteConfig();
+ config.loadExtension(LIBTEST);
+ conn = config.createConnection("jdbc:sqlite:");
+ assertNull(this.execute(conn, "SELECT test();"));
+ assertNotNull(this.execute(conn, "SELECT load_extension('" + LIBTEST2 + "');"));
+ } finally {
+ if (conn != null) {
+ conn.close();
+ conn = null;
+ }
+ }
+ }
+
+ @Test
+ public void testLoadCApiSql() throws SQLException {
+ Connection conn = null;
+ try {
+ SQLiteConfig config = new SQLiteConfig();
+ config.enableLoadExtension(true);
+ config.loadExtension(LIBTEST);
+ conn = config.createConnection("jdbc:sqlite:");
+ assertNull(this.execute(conn, "SELECT test();"));
+ assertNull(this.execute(conn, "SELECT load_extension('" + LIBTEST2 + "');"));
+ assertNull(this.execute(conn, "SELECT test2();"));
+ assertNotNull(this.execute(conn, "SELECT test3();"));
+ } finally {
+ if (conn != null) {
+ conn.close();
+ conn = null;
+ }
+ }
+ }
+
+ @Test
+ public void testLoadCApiMultiple() throws SQLException {
+ Connection conn = null;
+ try {
+ SQLiteConfig config = new SQLiteConfig();
+ config.loadExtension(LIBTEST);
+ config.loadExtension(LIBTEST, "sqlite3_testa_init");
+ config.loadExtension(LIBTEST2);
+ conn = config.createConnection("jdbc:sqlite:");
+ assertNull(this.execute(conn, "SELECT test();"));
+ assertNull(this.execute(conn, "SELECT testa();"));
+ assertNull(this.execute(conn, "SELECT test2();"));
+ assertNotNull(this.execute(conn, "SELECT test3();"));
+ } finally {
+ if (conn != null) {
+ conn.close();
+ conn = null;
+ }
+ }
+ }
+
+}