vcs log sqlite backend - rename native lib to avoid conflicts

GitOrigin-RevId: 242c92aef577c49598355a87d5597ee85642d2ea
This commit is contained in:
Vladimir Krivosheev
2023-01-17 14:42:31 +01:00
committed by intellij-monorepo-bot
parent 6ba8d7ec6b
commit 2b6c42bbb1
46 changed files with 260763 additions and 2042 deletions

View File

@@ -1,8 +1,8 @@
<component name="libraryTable">
<library name="sqlite-native" type="repository">
<properties include-transitive-deps="false" maven-id="org.sqlite:native:3.40.0-2" />
<properties include-transitive-deps="false" maven-id="org.sqlite:native:3.40.0-11" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/sqlite/native/3.40.0-2/native-3.40.0-2.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/sqlite/native/3.40.0-11/native-3.40.0-11.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />

View File

@@ -509,18 +509,27 @@ private suspend fun unpackNativeLibraries(sourceFile: Path, paths: List<String>,
val libVersion = sourceFile.getName(sourceFile.nameCount - 2).toString()
val signTool = context.proprietaryBuildTools.signTool
val unsignedFiles = TreeMap<OsFamily, MutableList<Path>>()
val packagePrefix = getCommonPath(paths)
val packagePrefix = if (paths.size == 1) {
// if a native lib is built with the only arch for testing purposes
val first = paths.first()
first.substring(0, first.indexOf('/') + 1)
}
else {
getCommonPath(paths)
}
val libName = sourceFile.name.substringBefore('-')
HashMapZipFile.load(sourceFile).use { zipFile ->
val jnaOutDir = Files.createDirectories(context.paths.tempDir.resolve(libName))
Files.createDirectories(jnaOutDir)
val outDir = Files.createDirectories(context.paths.tempDir.resolve(libName))
Files.createDirectories(outDir)
for (pathWithPackage in paths) {
val path = pathWithPackage.substring(packagePrefix.length)
val fileName = path.substring(path.lastIndexOf('/') + 1)
val os = when {
path.startsWith("darwin-") || path.startsWith("darwin/") || path.startsWith("mac/") || path.startsWith("Mac/") -> OsFamily.MACOS
path.startsWith("win32-") || path.startsWith("win/") || path.startsWith("Windows/") -> OsFamily.WINDOWS
path.startsWith("darwin-") || path.startsWith("mac-") || path.startsWith("darwin/") || path.startsWith("mac/") || path.startsWith("Mac/") -> OsFamily.MACOS
path.startsWith("win32-") || path.startsWith("win/") || path.startsWith("win-") || path.startsWith("Windows/") -> OsFamily.WINDOWS
path.startsWith("Linux-Android/") || path.startsWith("Linux-Musl/") -> continue
path.startsWith("linux-") || path.startsWith("linux/") || path.startsWith("Linux/") -> OsFamily.LINUX
else -> continue
@@ -529,7 +538,7 @@ private suspend fun unpackNativeLibraries(sourceFile: Path, paths: List<String>,
val osAndArch = path.substring(0, path.indexOf('/'))
val arch: JvmArchitecture? = when {
osAndArch.endsWith("-aarch64") || path.contains("/aarch64/") -> JvmArchitecture.aarch64
osAndArch.endsWith("-x86-64") || path.contains("/x86-64/") || path.contains("/x86_64/") -> JvmArchitecture.x64
osAndArch.contains("x86-64") || path.contains("x86_64") -> JvmArchitecture.x64
// universal library
os == OsFamily.MACOS && path.count { it == '/' } == 1 -> null
else -> continue
@@ -544,7 +553,7 @@ private suspend fun unpackNativeLibraries(sourceFile: Path, paths: List<String>,
if (file == null) {
@Suppress("UNNECESSARY_NOT_NULL_ASSERTION")
file = jnaOutDir.resolve(path)!!
file = outDir.resolve(path)!!
Files.createDirectories(file.parent)
FileChannel.open(file, W_CREATE_NEW).use { channel ->
val byteBuffer = zipFile.getByteBuffer(pathWithPackage)!!

View File

@@ -1,10 +1,10 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@file:Suppress("ReplaceGetOrSet")
package org.jetbrains.intellij.build.impl
// https://rosettacode.org/wiki/Find_common_directory_path#Java
fun getCommonPath(paths: List<String>): String {
internal fun getCommonPath(paths: List<String>): String {
var commonPath = ""
val folders = Array(paths.size) { paths[it].split('/') }
for (j in folders[0].indices) {

1
platform/sqlite/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
target/

22
platform/sqlite/Makefile Normal file
View File

@@ -0,0 +1,22 @@
.phony: archive-native install-native
archive-native:
rm -f target/sqlite-native.jar
cd target && zip -r sqlite-native.jar sqlite -i '*.jnilib' '*.so' '*.dll' '*.sha256'
install-native: archive-native
mvn install:install-file -DgroupId=org.sqlite \
-DartifactId=native \
-Dversion=3.40.0-11 \
-Dpackaging=jar \
-Dfile=target/sqlite-native.jar
deploy-native: archive-native
mvn deploy:deploy-file -DgroupId=org.sqlite \
-DartifactId=native \
-Dversion=3.40.0-11 \
-Dpackaging=jar \
-Dfile=target/sqlite-native.jar \
-DrepositoryId=space-intellij-dependencies \
-Durl=https://packages.jetbrains.team/maven/p/ij/intellij-dependencies

49
platform/sqlite/build.sh Executable file
View File

@@ -0,0 +1,49 @@
#!/usr/bin/env bash
# Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
set -ex
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)
cd "$SCRIPT_DIR"
createSysRoot() {
outDir="target/linux-$1"
if [ -d "$outDir" ]; then
echo "Sysroot $outDir exists, skip creating"
return
fi
imageArch=""
if [ "$1" == "x86_64" ]; then
imageArch=amd64
elif [ "$1" == "aarch64" ]; then
imageArch=arm64v8
fi
mkdir -p "$outDir"
# use old glibc (2.24)
nerdctl save --platform linux/$imageArch -o "$outDir.tar" buildpack-deps:bionic
python3 docker-image-extract.py "$outDir.tar" "$outDir"
unlink "$outDir.tar"
}
createSysRoot x86_64
#createSysRoot aarch64
# echo "deb http://archive.ubuntu.com/ubuntu/ jammy-proposed universe" | tee /etc/apt/sources.list.d/docker.list
# apt-get update && apt install -y install clang lldb lld
#nerdctl run -ti -v "$SCRIPT_DIR":/work silkeh/clang@sha256:693fdfa16424b2f41408204933b63a796e2700f1865a19c7eec7f6606040d7fd
#OS=mac ARCH=aarch64 ./make.sh
#OS=mac ARCH=x86_64 ./make.sh
#OS=linux ARCH=aarch64 ./make.sh
#OS=linux ARCH=x86_64 ./make.sh
#
#nerdctl run --rm --platform linux/amd64 -v "$SCRIPT_DIR":/work --workdir=/work \
# dockcross/windows-static-x64 bash -c 'OS=win ARCH=x86_64 CC=gcc CROSS_PREFIX=x86_64-w64-mingw32.static- ./make.sh'
#
#nerdctl run --rm --platform linux/amd64 -v "$SCRIPT_DIR":/work --workdir=/work \
# dockcross/windows-arm64 bash -c 'OS=win ARCH=aarch64 CC=clang CROSS_PREFIX=aarch64-w64-mingw32- ./make.sh'
nerdctl run --rm --platform linux/amd64 -v "$SCRIPT_DIR":/work --workdir=/work \
dockcross/linux-arm64 bash -c 'OS=linux ARCH=aarch64 CC=gcc CROSS_PREFIX=aarch64-unknown-linux-gnu- ./make.sh'

View File

@@ -0,0 +1,32 @@
# https://www.madebymikal.com/quick-hack-extracting-the-contents-of-a-docker-image-to-disk/
# Call me like this:
# docker-image-extract tarfile.tar extracted
import tarfile
import json
import os
import sys
image_path = sys.argv[1]
extracted_path = sys.argv[2]
image = tarfile.open(image_path)
manifest = json.loads(image.extractfile('manifest.json').read())
for layer in manifest[0]['Layers']:
print('Found layer: %s' % layer)
layer_tar = tarfile.open(fileobj=image.extractfile(layer))
for tarinfo in layer_tar:
print(' ... %s' % tarinfo.name)
if tarinfo.isdev():
print(' --> skip device files')
continue
dest = os.path.join(extracted_path, tarinfo.name)
if not tarinfo.isdir() and os.path.exists(dest):
print(' --> remove old version of file')
os.unlink(dest)
layer_tar.extract(tarinfo, path=extracted_path)

View File

@@ -5,6 +5,8 @@
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/sqlite" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />

76
platform/sqlite/make.sh Executable file
View File

@@ -0,0 +1,76 @@
#!/usr/bin/env bash
# Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
set -ex
outDir="target/sqlite/$OS-$ARCH"
rm -rf "${outDir:?}/*"
mkdir -p "$outDir"
# brew install llvm
# use latest CLang 15 instead of 14 for a smaller binaries
export PATH="/opt/homebrew/opt/llvm/bin:$PATH"
export LDFLAGS="-L/opt/homebrew/opt/llvm/lib"
export CPPFLAGS="-I/opt/homebrew/opt/llvm/include"
cFlags="-O3 -fPIC -Isqlite -fvisibility=hidden -Wno-implicit-function-declaration"
linkFlags="-Wl,-S,-x"
libFilename="so"
if [ "$OS" == "mac" ]; then
cFlags+=" -mmacosx-version-min=10.14"
linkFlags="-dynamiclib -fuse-ld=lld "
libFilename="libsqliteij.jnilib"
if [ "$ARCH" == "x86_64" ]; then
cFlags+=" --target=x86_64-apple-darwin18.7.0"
fi
elif [ "$OS" == "linux" ]; then
libFilename="libsqliteij.so"
# cannot compile arm - unable to find library -lgcc, so, use dock cross
if [ "$ARCH" == "aarch64" ]; then
linkFlags+=" -shared"
else
cFlags+=" --target=$ARCH-unknown-linux-gnu --sysroot=target/linux-$ARCH"
linkFlags+=" -shared -fuse-ld=lld"
fi
elif [ "$OS" == "win" ]; then
linkFlags="-Wl,--kill-at -shared -static-libgcc"
libFilename="sqliteij.dll"
fi
CC="${CC:-clang}"
#linkFlags+=" -fuse-ld=lld"
"${CROSS_PREFIX}${CC}" -o "$outDir/sqlite3.o" -c $cFlags \
-DSQLITE_DQS=1 \
-DSQLITE_THREADSAFE=1 \
-DSQLITE_DEFAULT_MEMSTATUS=0 \
-DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 \
-DSQLITE_LIKE_DOESNT_MATCH_BLOBS \
-DSQLITE_MAX_EXPR_DEPTH=0 \
-DSQLITE_OMIT_DECLTYPE \
-DSQLITE_OMIT_DEPRECATED \
-DSQLITE_OMIT_PROGRESS_CALLBACK \
-DSQLITE_OMIT_SHARED_CACHE \
-DSQLITE_USE_ALLOCA \
-DSQLITE_OMIT_AUTOINIT \
-DSQLITE_HAVE_ISNAN \
-DHAVE_USLEEP=1 \
-DSQLITE_TEMP_STORE=2 \
-DSQLITE_DEFAULT_CACHE_SIZE=2000 \
-DSQLITE_CORE \
-DSQLITE_ENABLE_FTS5 \
-DSQLITE_ENABLE_RTREE \
-DSQLITE_ENABLE_STAT4 \
-DSQLITE_MAX_MMAP_SIZE=1099511627776 \
\
sqlite/sqlite3.c
"${CROSS_PREFIX}${CC}" -o "$outDir/NativeDB.o" -c $cFlags -I"sqlite/$OS" sqlite/NativeDB.c
libFile="$outDir/$libFilename"
"${CROSS_PREFIX}${CC}" $cFlags -o "$libFile" "$outDir/NativeDB.o" "$outDir/sqlite3.o" $linkFlags
shasum -a 256 "$libFile" | head -c 64 >"$libFile.sha256"
unlink "$outDir/sqlite3.o"
unlink "$outDir/NativeDB.o"

View File

@@ -53,7 +53,7 @@ static jmethodID w_mth_inverse = 0;
static jmethodID w_mth_xvalue = 0;
static jclass pclass = 0;
static jclass phandleclass = 0;
//static jclass phandleclass = 0;
static jmethodID pmethod = 0;
static jmethodID exp_msg = 0;
@@ -427,11 +427,15 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
{
JNIEnv* env = 0;
if (JNI_OK != (*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_2))
return JNI_ERR;
if (JNI_OK != (*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_2)) {
return JNI_ERR;
}
dbclass = (*env)->FindClass(env, "org/jetbrains/sqlite/NativeDB");
if (!dbclass) {
return JNI_ERR;
}
dbclass = (*env)->FindClass(env, "org/jetbrains/sqlite/core/NativeDB");
if (!dbclass) return JNI_ERR;
dbclass = (*env)->NewWeakGlobalRef(env, dbclass);
dbpointer = (*env)->GetFieldID(env, dbclass, "pointer", "J");
mth_stringToUtf8ByteArray = (*env)->GetStaticMethodID(
@@ -466,20 +470,20 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
w_mth_inverse = (*env)->GetMethodID(env, wclass, "xInverse", "()V");
w_mth_xvalue = (*env)->GetMethodID(env, wclass, "xValue", "()V");
pclass = (*env)->FindClass(env, "org/jetbrains/sqlite/core/DB$ProgressObserver");
pclass = (*env)->FindClass(env, "org/jetbrains/sqlite/SqliteDb$ProgressObserver");
if(!pclass) return JNI_ERR;
pclass = (*env)->NewWeakGlobalRef(env, pclass);
pmethod = (*env)->GetMethodID(env, pclass, "progress", "(II)V");
phandleclass = (*env)->FindClass(env, "org/jetbrains/sqlite/ProgressHandler");
if(!phandleclass) return JNI_ERR;
phandleclass = (*env)->NewWeakGlobalRef(env, phandleclass);
// phandleclass = (*env)->FindClass(env, "org/jetbrains/sqlite/ProgressHandler");
// if(!phandleclass) return JNI_ERR;
// phandleclass = (*env)->NewWeakGlobalRef(env, phandleclass);
jclass exclass = (*env)->FindClass(env, "java/lang/Throwable");
exp_msg = (*env)->GetMethodID(
env, exclass, "toString", "()Ljava/lang/String;");
return JNI_VERSION_1_2;
return JNI_VERSION_10;
}
// FINALIZATION
@@ -502,20 +506,20 @@ JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) {
if (pclass) (*env)->DeleteWeakGlobalRef(env, pclass);
if (phandleclass) (*env)->DeleteWeakGlobalRef(env, phandleclass);
// if (phandleclass) (*env)->DeleteWeakGlobalRef(env, phandleclass);
}
// WRAPPERS for sqlite_* functions //////////////////////////////////
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_shared_1cache(
JNIEnv *env, jobject this, jboolean enable)
{
return sqlite3_enable_shared_cache(enable ? 1 : 0);
}
//JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_shared_1cache(
// JNIEnv *env, jobject this, jboolean enable)
//{
// return sqlite3_enable_shared_cache(enable ? 1 : 0);
//}
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_enable_1load_1extension(
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_enable_1load_1extension(
JNIEnv *env, jobject this, jboolean enable)
{
sqlite3 *db = gethandle(env, this);
@@ -529,40 +533,39 @@ JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_enable_1load_1ext
}
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_core_NativeDB__1open_1utf8(
JNIEnv *env, jobject this, jbyteArray file, jint flags)
{
sqlite3 *db;
int ret;
char *file_bytes;
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_open(JNIEnv *env, jobject this, jbyteArray file, jint flags) {
int ret;
sqlite3 *db;
char *file_bytes;
db = gethandle(env, this);
if (db) {
throwex_msg(env, "DB already open");
sqlite3_close(db);
return;
}
// compiled with SQLITE_OMIT_AUTOINIT
ret = sqlite3_initialize();
if (ret != SQLITE_OK) {
return ret;
}
utf8JavaByteArrayToUtf8Bytes(env, file, &file_bytes, NULL);
if (!file_bytes) return;
utf8JavaByteArrayToUtf8Bytes(env, file, &file_bytes, NULL);
if (!file_bytes) {
return SQLITE_ERROR;
}
ret = sqlite3_open_v2(file_bytes, &db, flags, NULL);
freeUtf8Bytes(file_bytes);
ret = sqlite3_open_v2(file_bytes, &db, flags, NULL);
freeUtf8Bytes(file_bytes);
sethandle(env, this, db);
if (ret != SQLITE_OK) {
ret = sqlite3_extended_errcode(db);
throwex_errorcode(env, this, ret);
sethandle(env, this, 0); // The handle is needed for throwex_errorcode
sqlite3_close(db);
return;
}
if (ret != SQLITE_OK) {
ret = sqlite3_extended_errcode(db);
sqlite3_close(db);
return ret;
}
// Ignore failures, as we can tolerate regular result codes.
(void) sqlite3_extended_result_codes(db, 1);
sethandle(env, this, db);
// ignore failures, as we can tolerate regular result codes
(void) sqlite3_extended_result_codes(db, 1);
return SQLITE_OK;
}
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_core_NativeDB_interrupt(JNIEnv *env, jobject this)
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB_interrupt(JNIEnv *env, jobject this)
{
sqlite3 *db = gethandle(env, this);
if (!db)
@@ -574,7 +577,7 @@ JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_core_NativeDB_interrupt(JNIEnv
sqlite3_interrupt(db);
}
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_core_NativeDB_busy_1timeout(
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB_busy_1timeout(
JNIEnv *env, jobject this, jint ms)
{
sqlite3 *db = gethandle(env, this);
@@ -593,7 +596,7 @@ int busyHandlerCallBack(void* callback, int nbPrevInvok) {
struct BusyHandlerContext *busyHandlerContext = (struct BusyHandlerContext*) callback;
(*(busyHandlerContext->vm))->AttachCurrentThread(busyHandlerContext->vm, (void **)&env, 0);
return (*env)->CallIntMethod( env,
return (*env)->CallIntMethod( env,
busyHandlerContext->obj,
busyHandlerContext->methodId,
nbPrevInvok);
@@ -631,12 +634,12 @@ void change_busy_handler(JNIEnv *env, jobject nativeDB, jobject busyHandler)
set_new_handler(env, nativeDB, "busyHandler", busyHandlerContext, &free_busy_handler);
}
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_core_NativeDB_busy_1handler(
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB_busy_1handler(
JNIEnv *env, jobject nativeDB, jobject busyHandler) {
change_busy_handler(env, nativeDB, busyHandler);
}
JNIEXPORT jlong JNICALL Java_org_jetbrains_sqlite_core_NativeDB_prepare_1utf8(
JNIEXPORT jlong JNICALL Java_org_jetbrains_sqlite_NativeDB_prepare_1utf8(
JNIEnv *env, jobject this, jbyteArray sql)
{
sqlite3* db;
@@ -666,7 +669,7 @@ JNIEXPORT jlong JNICALL Java_org_jetbrains_sqlite_core_NativeDB_prepare_1utf8(
}
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB__1exec_1utf8(
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB__1exec_1utf8(
JNIEnv *env, jobject this, jbyteArray sql)
{
sqlite3* db;
@@ -697,7 +700,7 @@ JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB__1exec_1utf8(
}
JNIEXPORT jobject JNICALL Java_org_jetbrains_sqlite_core_NativeDB_errmsg_1utf8(JNIEnv *env, jobject this)
JNIEXPORT jobject JNICALL Java_org_jetbrains_sqlite_NativeDB_errmsg_1utf8(JNIEnv *env, jobject this)
{
sqlite3 *db;
const char *str;
@@ -708,20 +711,20 @@ JNIEXPORT jobject JNICALL Java_org_jetbrains_sqlite_core_NativeDB_errmsg_1utf8(J
throwex_db_closed(env);
return NULL;
}
str = (const char*) sqlite3_errmsg(db);
if (!str) return NULL;
return utf8BytesToDirectByteBuffer(env, str, strlen(str));
}
JNIEXPORT jobject JNICALL Java_org_jetbrains_sqlite_core_NativeDB_libversion_1utf8(
JNIEXPORT jobject JNICALL Java_org_jetbrains_sqlite_NativeDB_libversion_1utf8(
JNIEnv *env, jobject this)
{
const char* version = sqlite3_libversion();
return utf8BytesToDirectByteBuffer(env, version, strlen(version));
}
JNIEXPORT jlong JNICALL Java_org_jetbrains_sqlite_core_NativeDB_changes(
JNIEXPORT jlong JNICALL Java_org_jetbrains_sqlite_NativeDB_changes(
JNIEnv *env, jobject this)
{
sqlite3 *db = gethandle(env, this);
@@ -734,7 +737,7 @@ JNIEXPORT jlong JNICALL Java_org_jetbrains_sqlite_core_NativeDB_changes(
return sqlite3_changes64(db);
}
JNIEXPORT jlong JNICALL Java_org_jetbrains_sqlite_core_NativeDB_total_1changes(
JNIEXPORT jlong JNICALL Java_org_jetbrains_sqlite_NativeDB_total_1changes(
JNIEnv *env, jobject this)
{
sqlite3 *db = gethandle(env, this);
@@ -747,7 +750,7 @@ JNIEXPORT jlong JNICALL Java_org_jetbrains_sqlite_core_NativeDB_total_1changes(
return sqlite3_total_changes64(db);
}
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_finalize(
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_finalize(
JNIEnv *env, jobject this, jlong stmt)
{
if (!stmt)
@@ -759,7 +762,7 @@ JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_finalize(
return sqlite3_finalize(toref(stmt));
}
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_step(
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_step(
JNIEnv *env, jobject this, jlong stmt)
{
if (!stmt)
@@ -771,7 +774,7 @@ JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_step(
return sqlite3_step(toref(stmt));
}
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_reset(
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_reset(
JNIEnv *env, jobject this, jlong stmt)
{
if (!stmt)
@@ -783,7 +786,7 @@ JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_reset(
return sqlite3_reset(toref(stmt));
}
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_clear_1bindings(
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_clear_1bindings(
JNIEnv *env, jobject this, jlong stmt)
{
if (!stmt)
@@ -795,7 +798,7 @@ JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_clear_1bindings(
return sqlite3_clear_bindings(toref(stmt));
}
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_bind_1parameter_1count(
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_bind_1parameter_1count(
JNIEnv *env, jobject this, jlong stmt)
{
if (!stmt)
@@ -807,7 +810,7 @@ JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_bind_1parameter_1
return sqlite3_bind_parameter_count(toref(stmt));
}
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_column_1count(
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_column_1count(
JNIEnv *env, jobject this, jlong stmt)
{
if (!stmt)
@@ -819,7 +822,7 @@ JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_column_1count(
return sqlite3_column_count(toref(stmt));
}
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_column_1type(
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_column_1type(
JNIEnv *env, jobject this, jlong stmt, jint col)
{
if (!stmt)
@@ -831,56 +834,40 @@ JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_column_1type(
return sqlite3_column_type(toref(stmt), col);
}
JNIEXPORT jobject JNICALL Java_org_jetbrains_sqlite_core_NativeDB_column_1decltype_1utf8(
JNIEnv *env, jobject this, jlong stmt, jint col)
{
const char *str;
//JNIEXPORT jobject JNICALL Java_org_jetbrains_sqlite_NativeDB_column_1table_1name_1utf8(
// JNIEnv *env, jobject this, jlong stmt, jint col)
//{
// const char *str;
//
// if (!stmt)
// {
// throwex_stmt_finalized(env);
// return NULL;
// }
//
// str = sqlite3_column_table_name(toref(stmt), col);
// if (!str) return NULL;
// return utf8BytesToDirectByteBuffer(env, str, strlen(str));
//}
if (!stmt)
{
throwex_stmt_finalized(env);
return NULL;
}
//JNIEXPORT jobject JNICALL Java_org_jetbrains_sqlite_NativeDB_column_1name_1utf8(
// JNIEnv *env, jobject this, jlong stmt, jint col)
//{
// const char *str;
//
// if (!stmt)
// {
// throwex_stmt_finalized(env);
// return NULL;
// }
//
// str = sqlite3_column_name(toref(stmt), col);
// if (!str) return NULL;
//
// return utf8BytesToDirectByteBuffer(env, str, strlen(str));
//}
str = (const char*) sqlite3_column_decltype(toref(stmt), col);
if (!str) return NULL;
return utf8BytesToDirectByteBuffer(env, str, strlen(str));
}
JNIEXPORT jobject JNICALL Java_org_jetbrains_sqlite_core_NativeDB_column_1table_1name_1utf8(
JNIEnv *env, jobject this, jlong stmt, jint col)
{
const char *str;
if (!stmt)
{
throwex_stmt_finalized(env);
return NULL;
}
str = sqlite3_column_table_name(toref(stmt), col);
if (!str) return NULL;
return utf8BytesToDirectByteBuffer(env, str, strlen(str));
}
JNIEXPORT jobject JNICALL Java_org_jetbrains_sqlite_core_NativeDB_column_1name_1utf8(
JNIEnv *env, jobject this, jlong stmt, jint col)
{
const char *str;
if (!stmt)
{
throwex_stmt_finalized(env);
return NULL;
}
str = sqlite3_column_name(toref(stmt), col);
if (!str) return NULL;
return utf8BytesToDirectByteBuffer(env, str, strlen(str));
}
JNIEXPORT jobject JNICALL Java_org_jetbrains_sqlite_core_NativeDB_column_1text_1utf8(
JNIEXPORT jobject JNICALL Java_org_jetbrains_sqlite_NativeDB_column_1text_1utf8(
JNIEnv *env, jobject this, jlong stmt, jint col)
{
sqlite3 *db;
@@ -912,7 +899,7 @@ JNIEXPORT jobject JNICALL Java_org_jetbrains_sqlite_core_NativeDB_column_1text_1
return utf8BytesToDirectByteBuffer(env, bytes, nbytes);
}
JNIEXPORT jbyteArray JNICALL Java_org_jetbrains_sqlite_core_NativeDB_column_1blob(
JNIEXPORT jbyteArray JNICALL Java_org_jetbrains_sqlite_NativeDB_column_1blob(
JNIEnv *env, jobject this, jlong stmt, jint col)
{
sqlite3 *db;
@@ -963,7 +950,7 @@ JNIEXPORT jbyteArray JNICALL Java_org_jetbrains_sqlite_core_NativeDB_column_1blo
return jBlob;
}
JNIEXPORT jdouble JNICALL Java_org_jetbrains_sqlite_core_NativeDB_column_1double(
JNIEXPORT jdouble JNICALL Java_org_jetbrains_sqlite_NativeDB_column_1double(
JNIEnv *env, jobject this, jlong stmt, jint col)
{
if (!stmt)
@@ -975,7 +962,7 @@ JNIEXPORT jdouble JNICALL Java_org_jetbrains_sqlite_core_NativeDB_column_1double
return sqlite3_column_double(toref(stmt), col);
}
JNIEXPORT jlong JNICALL Java_org_jetbrains_sqlite_core_NativeDB_column_1long(
JNIEXPORT jlong JNICALL Java_org_jetbrains_sqlite_NativeDB_column_1long(
JNIEnv *env, jobject this, jlong stmt, jint col)
{
if (!stmt)
@@ -987,7 +974,7 @@ JNIEXPORT jlong JNICALL Java_org_jetbrains_sqlite_core_NativeDB_column_1long(
return sqlite3_column_int64(toref(stmt), col);
}
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_column_1int(
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_column_1int(
JNIEnv *env, jobject this, jlong stmt, jint col)
{
if (!stmt)
@@ -999,7 +986,7 @@ JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_column_1int(
return sqlite3_column_int(toref(stmt), col);
}
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_bind_1null(
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_bind_1null(
JNIEnv *env, jobject this, jlong stmt, jint pos)
{
if (!stmt)
@@ -1011,7 +998,7 @@ JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_bind_1null(
return sqlite3_bind_null(toref(stmt), pos);
}
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_bind_1int(
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_bind_1int(
JNIEnv *env, jobject this, jlong stmt, jint pos, jint v)
{
if (!stmt)
@@ -1023,7 +1010,7 @@ JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_bind_1int(
return sqlite3_bind_int(toref(stmt), pos, v);
}
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_bind_1long(
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_bind_1long(
JNIEnv *env, jobject this, jlong stmt, jint pos, jlong v)
{
if (!stmt)
@@ -1035,7 +1022,7 @@ JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_bind_1long(
return sqlite3_bind_int64(toref(stmt), pos, v);
}
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_bind_1double(
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_bind_1double(
JNIEnv *env, jobject this, jlong stmt, jint pos, jdouble v)
{
if (!stmt)
@@ -1047,7 +1034,7 @@ JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_bind_1double(
return sqlite3_bind_double(toref(stmt), pos, v);
}
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_bind_1text_1utf8(
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_bind_1text_1utf8(
JNIEnv *env, jobject this, jlong stmt, jint pos, jbyteArray v)
{
int rc;
@@ -1069,7 +1056,7 @@ JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_bind_1text_1utf8(
return rc;
}
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_bind_1blob(
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_bind_1blob(
JNIEnv *env, jobject this, jlong stmt, jint pos, jbyteArray v)
{
jint rc;
@@ -1090,14 +1077,14 @@ JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_bind_1blob(
return rc;
}
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_core_NativeDB_result_1null(
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB_result_1null(
JNIEnv *env, jobject this, jlong context)
{
if (!context) return;
sqlite3_result_null(toref(context));
}
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_core_NativeDB_result_1text_1utf8(
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB_result_1text_1utf8(
JNIEnv *env, jobject this, jlong context, jbyteArray value)
{
char* value_bytes;
@@ -1117,7 +1104,7 @@ JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_core_NativeDB_result_1text_1utf
freeUtf8Bytes(value_bytes);
}
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_core_NativeDB_result_1blob(
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB_result_1blob(
JNIEnv *env, jobject this, jlong context, jobject value)
{
jbyte *bytes;
@@ -1133,28 +1120,28 @@ JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_core_NativeDB_result_1blob(
(*env)->ReleasePrimitiveArrayCritical(env, value, bytes, JNI_ABORT);
}
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_core_NativeDB_result_1double(
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB_result_1double(
JNIEnv *env, jobject this, jlong context, jdouble value)
{
if (!context) return;
sqlite3_result_double(toref(context), value);
}
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_core_NativeDB_result_1long(
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB_result_1long(
JNIEnv *env, jobject this, jlong context, jlong value)
{
if (!context) return;
sqlite3_result_int64(toref(context), value);
}
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_core_NativeDB_result_1int(
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB_result_1int(
JNIEnv *env, jobject this, jlong context, jint value)
{
if (!context) return;
sqlite3_result_int(toref(context), value);
}
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_core_NativeDB_result_1error_1utf8(
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB_result_1error_1utf8(
JNIEnv *env, jobject this, jlong context, jbyteArray err)
{
char* err_bytes;
@@ -1173,7 +1160,7 @@ JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_core_NativeDB_result_1error_1ut
freeUtf8Bytes(err_bytes);
}
JNIEXPORT jobject JNICALL Java_org_jetbrains_sqlite_core_NativeDB_value_1text_1utf8(
JNIEXPORT jobject JNICALL Java_org_jetbrains_sqlite_NativeDB_value_1text_1utf8(
JNIEnv *env, jobject this, jobject f, jint arg)
{
const char* bytes;
@@ -1188,7 +1175,7 @@ JNIEXPORT jobject JNICALL Java_org_jetbrains_sqlite_core_NativeDB_value_1text_1u
return utf8BytesToDirectByteBuffer(env, bytes, nbytes);
}
JNIEXPORT jbyteArray JNICALL Java_org_jetbrains_sqlite_core_NativeDB_value_1blob(
JNIEXPORT jbyteArray JNICALL Java_org_jetbrains_sqlite_NativeDB_value_1blob(
JNIEnv *env, jobject this, jobject f, jint arg)
{
int length;
@@ -1209,28 +1196,28 @@ JNIEXPORT jbyteArray JNICALL Java_org_jetbrains_sqlite_core_NativeDB_value_1blob
return jBlob;
}
JNIEXPORT jdouble JNICALL Java_org_jetbrains_sqlite_core_NativeDB_value_1double(
JNIEXPORT jdouble JNICALL Java_org_jetbrains_sqlite_NativeDB_value_1double(
JNIEnv *env, jobject this, jobject f, jint arg)
{
sqlite3_value *value = tovalue(env, f, arg);
return value ? sqlite3_value_double(value) : 0;
}
JNIEXPORT jlong JNICALL Java_org_jetbrains_sqlite_core_NativeDB_value_1long(
JNIEXPORT jlong JNICALL Java_org_jetbrains_sqlite_NativeDB_value_1long(
JNIEnv *env, jobject this, jobject f, jint arg)
{
sqlite3_value *value = tovalue(env, f, arg);
return value ? sqlite3_value_int64(value) : 0;
}
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_value_1int(
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_value_1int(
JNIEnv *env, jobject this, jobject f, jint arg)
{
sqlite3_value *value = tovalue(env, f, arg);
return value ? sqlite3_value_int(value) : 0;
}
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_value_1type(
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_value_1type(
JNIEnv *env, jobject this, jobject func, jint arg)
{
return sqlite3_value_type(tovalue(env, func, arg));
@@ -1254,7 +1241,7 @@ void free_udf_func(void *udfToFree) {
free(udf);
}
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_create_1function_1utf8(
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_create_1function_1utf8(
JNIEnv *env, jobject nativeDB, jbyteArray name, jobject func, jint nArgs, jint flags)
{
jint ret = 0;
@@ -1305,7 +1292,7 @@ JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_create_1function_
return ret;
}
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_destroy_1function_1utf8(
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_destroy_1function_1utf8(
JNIEnv *env, jobject nativeDB, jbyteArray name)
{
jint ret = 0;
@@ -1313,7 +1300,7 @@ JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_destroy_1function
utf8JavaByteArrayToUtf8Bytes(env, name, &name_bytes, NULL);
if (!name_bytes) { throwex_outofmemory(env); return 0; }
ret = sqlite3_create_function(
gethandle(env, nativeDB), name_bytes, -1, SQLITE_UTF16, NULL, NULL, NULL, NULL
);
@@ -1322,7 +1309,7 @@ JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_destroy_1function
return ret;
}
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_create_1collation_1utf8(
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_create_1collation_1utf8(
JNIEnv *env, jobject this, jbyteArray name, jobject func)
{
jint ret = 0;
@@ -1352,7 +1339,7 @@ JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_create_1collation
return ret;
}
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_destroy_1collation_1utf8(
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_destroy_1collation_1utf8(
JNIEnv *env, jobject this, jbyteArray name)
{
jint ret = 0;
@@ -1369,7 +1356,7 @@ JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_destroy_1collatio
return ret;
}
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_limit(JNIEnv *env, jobject this, jint id, jint value)
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_limit(JNIEnv *env, jobject this, jint id, jint value)
{
sqlite3* db;
@@ -1386,73 +1373,73 @@ JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_limit(JNIEnv *env
// COMPOUND FUNCTIONS ///////////////////////////////////////////////
JNIEXPORT jobjectArray JNICALL Java_org_jetbrains_sqlite_core_NativeDB_column_1metadata(
JNIEnv *env, jobject this, jlong stmt)
{
const char *zTableName, *zColumnName;
int pNotNull, pPrimaryKey, pAutoinc, i, colCount;
jobjectArray array;
jbooleanArray colData;
jboolean* colDataRaw;
sqlite3 *db;
sqlite3_stmt *dbstmt;
db = gethandle(env, this);
if (!db)
{
throwex_db_closed(env);
return NULL;
}
if (!stmt)
{
throwex_stmt_finalized(env);
return NULL;
}
dbstmt = toref(stmt);
colCount = sqlite3_column_count(dbstmt);
array = (*env)->NewObjectArray(
env, colCount, (*env)->FindClass(env, "[Z"), NULL) ;
if (!array) { throwex_outofmemory(env); return 0; }
colDataRaw = (jboolean*)malloc(3 * sizeof(jboolean));
if (!colDataRaw) { throwex_outofmemory(env); return 0; }
for (i = 0; i < colCount; i++) {
// load passed column name and table name
zColumnName = sqlite3_column_name(dbstmt, i);
zTableName = sqlite3_column_table_name(dbstmt, i);
pNotNull = 0;
pPrimaryKey = 0;
pAutoinc = 0;
// request metadata for column and load into output variables
if (zTableName && zColumnName) {
sqlite3_table_column_metadata(
db, 0, zTableName, zColumnName,
0, 0, &pNotNull, &pPrimaryKey, &pAutoinc
);
}
// load relevant metadata into 2nd dimension of return results
colDataRaw[0] = pNotNull;
colDataRaw[1] = pPrimaryKey;
colDataRaw[2] = pAutoinc;
colData = (*env)->NewBooleanArray(env, 3);
if (!colData) { throwex_outofmemory(env); return 0; }
(*env)->SetBooleanArrayRegion(env, colData, 0, 3, colDataRaw);
(*env)->SetObjectArrayElement(env, array, i, colData);
}
free(colDataRaw);
return array;
}
//JNIEXPORT jobjectArray JNICALL Java_org_jetbrains_sqlite_NativeDB_column_1metadata(
// JNIEnv *env, jobject this, jlong stmt)
//{
// const char *zTableName, *zColumnName;
// int pNotNull, pPrimaryKey, pAutoinc, i, colCount;
// jobjectArray array;
// jbooleanArray colData;
// jboolean* colDataRaw;
// sqlite3 *db;
// sqlite3_stmt *dbstmt;
//
// db = gethandle(env, this);
// if (!db)
// {
// throwex_db_closed(env);
// return NULL;
// }
//
// if (!stmt)
// {
// throwex_stmt_finalized(env);
// return NULL;
// }
//
// dbstmt = toref(stmt);
//
// colCount = sqlite3_column_count(dbstmt);
// array = (*env)->NewObjectArray(
// env, colCount, (*env)->FindClass(env, "[Z"), NULL) ;
// if (!array) { throwex_outofmemory(env); return 0; }
//
// colDataRaw = (jboolean*)malloc(3 * sizeof(jboolean));
// if (!colDataRaw) { throwex_outofmemory(env); return 0; }
//
// for (i = 0; i < colCount; i++) {
// // load passed column name and table name
// zColumnName = sqlite3_column_name(dbstmt, i);
// zTableName = sqlite3_column_table_name(dbstmt, i);
//
// pNotNull = 0;
// pPrimaryKey = 0;
// pAutoinc = 0;
//
// // request metadata for column and load into output variables
// if (zTableName && zColumnName) {
// sqlite3_table_column_metadata(
// db, 0, zTableName, zColumnName,
// 0, 0, &pNotNull, &pPrimaryKey, &pAutoinc
// );
// }
//
// // load relevant metadata into 2nd dimension of return results
// colDataRaw[0] = pNotNull;
// colDataRaw[1] = pPrimaryKey;
// colDataRaw[2] = pAutoinc;
//
// colData = (*env)->NewBooleanArray(env, 3);
// if (!colData) { throwex_outofmemory(env); return 0; }
//
// (*env)->SetBooleanArrayRegion(env, colData, 0, 3, colDataRaw);
// (*env)->SetObjectArrayElement(env, array, i, colData);
// }
//
// free(colDataRaw);
//
// return array;
//}
// backup function
@@ -1529,8 +1516,8 @@ void copyLoop(JNIEnv *env, sqlite3_backup *pBackup, jobject progress,
** If the backup process is successfully completed, SQLITE_OK is returned.
** Otherwise, if an error occurs, an SQLite error code is returned.
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_backup(
JNIEnv *env, jobject this,
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_backup(
JNIEnv *env, jobject this,
jbyteArray zDBName,
jbyteArray zFilename, /* Name of file to back up to */
jobject observer, /* Progress function to invoke */
@@ -1598,10 +1585,10 @@ JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_backup(
#else
return SQLITE_INTERNAL;
#endif
}
}
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_restore(
JNIEnv *env, jobject this,
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_restore(
JNIEnv *env, jobject this,
jbyteArray zDBName,
jbyteArray zFilename, /* Name of file to restore from */
jobject observer, /* Progress function to invoke */
@@ -1674,75 +1661,75 @@ JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_core_NativeDB_restore(
// Progress handler
struct ProgressHandlerContext {
JavaVM *vm;
jmethodID mth;
jobject phandler;
};
//struct ProgressHandlerContext {
// JavaVM *vm;
// jmethodID mth;
// jobject phandler;
//};
static void free_progress_handler(JNIEnv *env, void *toFree) {
struct ProgressHandlerContext* progressHandlerContext = (struct ProgressHandlerContext*) toFree;
(*env)->DeleteGlobalRef(env, progressHandlerContext->phandler);
free(toFree);
}
//static void free_progress_handler(JNIEnv *env, void *toFree) {
// struct ProgressHandlerContext* progressHandlerContext = (struct ProgressHandlerContext*) toFree;
// (*env)->DeleteGlobalRef(env, progressHandlerContext->phandler);
// free(toFree);
//}
//
//static int progress_handler_function(void *ctx) {
// JNIEnv *env = 0;
// struct ProgressHandlerContext* progressHandlerContext = (struct ProgressHandlerContext*) ctx;
// (*progressHandlerContext->vm)->AttachCurrentThread(progressHandlerContext->vm, (void **)&env, 0);
// jint rv = (*env)->CallIntMethod(env, progressHandlerContext->phandler, progressHandlerContext->mth);
// return rv;
//}
static int progress_handler_function(void *ctx) {
JNIEnv *env = 0;
struct ProgressHandlerContext* progressHandlerContext = (struct ProgressHandlerContext*) ctx;
(*progressHandlerContext->vm)->AttachCurrentThread(progressHandlerContext->vm, (void **)&env, 0);
jint rv = (*env)->CallIntMethod(env, progressHandlerContext->phandler, progressHandlerContext->mth);
return rv;
}
//static void change_progress_handler(JNIEnv *env, jobject nativeDB, jobject progressHandler, jint vmCalls)
//{
// sqlite3 *db;
//
// db = gethandle(env, nativeDB);
// if (!db){
// throwex_db_closed(env);
// return;
// }
//
// struct ProgressHandlerContext* progressHandlerContext = NULL;
//
// if (progressHandler) {
// progressHandlerContext = (struct ProgressHandlerContext*) malloc(sizeof(struct ProgressHandlerContext));
// (*env)->GetJavaVM(env, &progressHandlerContext->vm);
//
// progressHandlerContext->phandler = (*env)->NewGlobalRef(env, progressHandler);
// progressHandlerContext->mth = (*env)->GetMethodID( env,
// (*env)->GetObjectClass(env, progressHandlerContext->phandler),
// "progress",
// "()I");
// }
//
// if (progressHandlerContext) {
// sqlite3_progress_handler(gethandle(env, nativeDB), vmCalls, &progress_handler_function, progressHandlerContext);
// } else {
// sqlite3_progress_handler(gethandle(env, nativeDB), 0, NULL, NULL);
// }
//
// set_new_handler(env, nativeDB, "progressHandler", progressHandlerContext, &free_progress_handler);
//}
static void change_progress_handler(JNIEnv *env, jobject nativeDB, jobject progressHandler, jint vmCalls)
{
sqlite3 *db;
db = gethandle(env, nativeDB);
if (!db){
throwex_db_closed(env);
return;
}
struct ProgressHandlerContext* progressHandlerContext = NULL;
if (progressHandler) {
progressHandlerContext = (struct ProgressHandlerContext*) malloc(sizeof(struct ProgressHandlerContext));
(*env)->GetJavaVM(env, &progressHandlerContext->vm);
progressHandlerContext->phandler = (*env)->NewGlobalRef(env, progressHandler);
progressHandlerContext->mth = (*env)->GetMethodID( env,
(*env)->GetObjectClass(env, progressHandlerContext->phandler),
"progress",
"()I");
}
if (progressHandlerContext) {
sqlite3_progress_handler(gethandle(env, nativeDB), vmCalls, &progress_handler_function, progressHandlerContext);
} else {
sqlite3_progress_handler(gethandle(env, nativeDB), 0, NULL, NULL);
}
set_new_handler(env, nativeDB, "progressHandler", progressHandlerContext, &free_progress_handler);
}
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_core_NativeDB_register_1progress_1handler(
JNIEnv *env,
jobject nativeDB,
jint vmCalls,
jobject progressHandler
)
{
change_progress_handler(env, nativeDB, progressHandler, vmCalls);
}
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_core_NativeDB_clear_1progress_1handler(
JNIEnv *env,
jobject nativeDB
)
{
change_progress_handler(env, nativeDB, NULL, 0);
}
//JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB_register_1progress_1handler(
// JNIEnv *env,
// jobject nativeDB,
// jint vmCalls,
// jobject progressHandler
//)
//{
// change_progress_handler(env, nativeDB, progressHandler, vmCalls);
//}
//
//JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB_clear_1progress_1handler(
// JNIEnv *env,
// jobject nativeDB
//)
//{
// change_progress_handler(env, nativeDB, NULL, 0);
//}
// Update hook
@@ -1778,7 +1765,7 @@ static void clear_update_listener(JNIEnv *env, jobject nativeDB){
set_new_handler(env, nativeDB, "updateListener", NULL, &free_update_handler);
}
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_core_NativeDB_set_1update_1listener(JNIEnv *env, jobject nativeDB, jboolean enabled) {
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB_set_1update_1listener(JNIEnv *env, jobject nativeDB, jboolean enabled) {
if (enabled) {
struct UpdateHandlerContext* update_handler_context = (struct UpdateHandlerContext*) malloc(sizeof(struct UpdateHandlerContext));
update_handler_context->method = (*env)->GetMethodID(env, dbclass, "onUpdate", "(ILjava/lang/String;Ljava/lang/String;J)V");
@@ -1826,7 +1813,7 @@ void clear_commit_listener(JNIEnv *env, jobject nativeDB, sqlite3 *db) {
set_new_handler(env, nativeDB, "commitListener", NULL, freeCommitHandlerCtx);
}
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_core_NativeDB_set_1commit_1listener(JNIEnv *env, jobject nativeDB, jboolean enabled) {
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB_set_1commit_1listener(JNIEnv *env, jobject nativeDB, jboolean enabled) {
sqlite3 *db = gethandle(env, nativeDB);
if (enabled) {
struct CommitHandlerContext *commit_handler_context = (struct CommitHandlerContext*) malloc(sizeof(struct CommitHandlerContext));
@@ -1841,13 +1828,13 @@ JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_core_NativeDB_set_1commit_1list
}
}
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_core_NativeDB__1close(
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB__1close(
JNIEnv *env, jobject nativeDB)
{
sqlite3 *db = gethandle(env, nativeDB);
if (db)
{
change_progress_handler(env, nativeDB, NULL, 0);
// change_progress_handler(env, nativeDB, NULL, 0);
change_busy_handler(env, nativeDB, NULL);
clear_commit_listener(env, nativeDB, db);
clear_update_listener(env, nativeDB);

View File

@@ -0,0 +1,442 @@
#include <jni.h>
/* Header for class org_sqlite__NativeDB */
#ifndef _Included_org_jetbrains_sqlite_NativeDB
#define _Included_org_jetbrains_sqlite_NativeDB
#ifdef __cplusplus
extern "C" {
#endif
#undef org_jetbrains_sqlite_NativeDB_DEFAULT_BACKUP_BUSY_SLEEP_TIME_MILLIS
#define org_jetbrains_sqlite_NativeDB_DEFAULT_BACKUP_BUSY_SLEEP_TIME_MILLIS 100L
#undef org_jetbrains_sqlite_NativeDB_DEFAULT_BACKUP_NUM_BUSY_BEFORE_FAIL
#define org_jetbrains_sqlite_NativeDB_DEFAULT_BACKUP_NUM_BUSY_BEFORE_FAIL 3L
#undef org_jetbrains_sqlite_NativeDB_DEFAULT_PAGES_PER_BACKUP_STEP
#define org_jetbrains_sqlite_NativeDB_DEFAULT_PAGES_PER_BACKUP_STEP 100L
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: open
* Signature: ([BI)I
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_open
(JNIEnv *, jobject, jbyteArray, jint);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: _close
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB__1close
(JNIEnv *, jobject);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: _exec_utf8
* Signature: ([B)I
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB__1exec_1utf8
(JNIEnv *, jobject, jbyteArray);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: shared_cache
* Signature: (Z)I
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_shared_1cache
(JNIEnv *, jobject, jboolean);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: enable_load_extension
* Signature: (Z)I
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_enable_1load_1extension
(JNIEnv *, jobject, jboolean);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: interrupt
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB_interrupt
(JNIEnv *, jobject);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: busy_timeout
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB_busy_1timeout
(JNIEnv *, jobject, jint);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: busy_handler
* Signature: (Lorg/sqlite/BusyHandler;)V
*/
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB_busy_1handler
(JNIEnv *, jobject, jobject);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: prepare_utf8
* Signature: ([B)J
*/
JNIEXPORT jlong JNICALL Java_org_jetbrains_sqlite_NativeDB_prepare_1utf8
(JNIEnv *, jobject, jbyteArray);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: errmsg_utf8
* Signature: ()Ljava/nio/ByteBuffer;
*/
JNIEXPORT jobject JNICALL Java_org_jetbrains_sqlite_NativeDB_errmsg_1utf8
(JNIEnv *, jobject);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: libversion_utf8
* Signature: ()Ljava/nio/ByteBuffer;
*/
JNIEXPORT jobject JNICALL Java_org_jetbrains_sqlite_NativeDB_libversion_1utf8
(JNIEnv *, jobject);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: changes
* Signature: ()J
*/
JNIEXPORT jlong JNICALL Java_org_jetbrains_sqlite_NativeDB_changes
(JNIEnv *, jobject);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: total_changes
* Signature: ()J
*/
JNIEXPORT jlong JNICALL Java_org_jetbrains_sqlite_NativeDB_total_1changes
(JNIEnv *, jobject);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: finalize
* Signature: (J)I
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_finalize
(JNIEnv *, jobject, jlong);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: step
* Signature: (J)I
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_step
(JNIEnv *, jobject, jlong);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: reset
* Signature: (J)I
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_reset
(JNIEnv *, jobject, jlong);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: clear_bindings
* Signature: (J)I
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_clear_1bindings
(JNIEnv *, jobject, jlong);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: bind_parameter_count
* Signature: (J)I
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_bind_1parameter_1count
(JNIEnv *, jobject, jlong);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: column_count
* Signature: (J)I
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_column_1count
(JNIEnv *, jobject, jlong);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: column_type
* Signature: (JI)I
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_column_1type
(JNIEnv *, jobject, jlong, jint);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: column_text_utf8
* Signature: (JI)Ljava/nio/ByteBuffer;
*/
JNIEXPORT jobject JNICALL Java_org_jetbrains_sqlite_NativeDB_column_1text_1utf8
(JNIEnv *, jobject, jlong, jint);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: column_blob
* Signature: (JI)Ljava/nio/ByteBuffer;
*/
JNIEXPORT jobject JNICALL Java_org_jetbrains_sqlite_NativeDB_column_1blob
(JNIEnv *, jobject, jlong, jint);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: column_double
* Signature: (JI)D
*/
JNIEXPORT jdouble JNICALL Java_org_jetbrains_sqlite_NativeDB_column_1double
(JNIEnv *, jobject, jlong, jint);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: column_long
* Signature: (JI)J
*/
JNIEXPORT jlong JNICALL Java_org_jetbrains_sqlite_NativeDB_column_1long
(JNIEnv *, jobject, jlong, jint);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: column_int
* Signature: (JI)I
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_column_1int
(JNIEnv *, jobject, jlong, jint);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: bind_null
* Signature: (JI)I
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_bind_1null
(JNIEnv *, jobject, jlong, jint);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: bind_int
* Signature: (JII)I
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_bind_1int
(JNIEnv *, jobject, jlong, jint, jint);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: bind_long
* Signature: (JIJ)I
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_bind_1long
(JNIEnv *, jobject, jlong, jint, jlong);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: bind_double
* Signature: (JID)I
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_bind_1double
(JNIEnv *, jobject, jlong, jint, jdouble);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: bind_text_utf8
* Signature: (JI[B)I
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_bind_1text_1utf8
(JNIEnv *, jobject, jlong, jint, jbyteArray);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: bind_blob
* Signature: (JI[B)I
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_bind_1blob
(JNIEnv *, jobject, jlong, jint, jbyteArray);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: result_null
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB_result_1null
(JNIEnv *, jobject, jlong);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: result_text_utf8
* Signature: (J[B)V
*/
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB_result_1text_1utf8
(JNIEnv *, jobject, jlong, jbyteArray);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: result_blob
* Signature: (J[B)V
*/
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB_result_1blob
(JNIEnv *, jobject, jlong, jbyteArray);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: result_double
* Signature: (JD)V
*/
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB_result_1double
(JNIEnv *, jobject, jlong, jdouble);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: result_long
* Signature: (JJ)V
*/
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB_result_1long
(JNIEnv *, jobject, jlong, jlong);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: result_int
* Signature: (JI)V
*/
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB_result_1int
(JNIEnv *, jobject, jlong, jint);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: result_error_utf8
* Signature: (J[B)V
*/
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB_result_1error_1utf8
(JNIEnv *, jobject, jlong, jbyteArray);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: value_text_utf8
* Signature: (Lorg/sqlite/Function;I)Ljava/nio/ByteBuffer;
*/
JNIEXPORT jobject JNICALL Java_org_jetbrains_sqlite_NativeDB_value_1text_1utf8
(JNIEnv *, jobject, jobject, jint);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: value_blob
* Signature: (Lorg/sqlite/Function;I)[B
*/
JNIEXPORT jbyteArray JNICALL Java_org_jetbrains_sqlite_NativeDB_value_1blob
(JNIEnv *, jobject, jobject, jint);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: value_double
* Signature: (Lorg/sqlite/Function;I)D
*/
JNIEXPORT jdouble JNICALL Java_org_jetbrains_sqlite_NativeDB_value_1double
(JNIEnv *, jobject, jobject, jint);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: value_long
* Signature: (Lorg/sqlite/Function;I)J
*/
JNIEXPORT jlong JNICALL Java_org_jetbrains_sqlite_NativeDB_value_1long
(JNIEnv *, jobject, jobject, jint);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: value_int
* Signature: (Lorg/sqlite/Function;I)I
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_value_1int
(JNIEnv *, jobject, jobject, jint);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: value_type
* Signature: (Lorg/sqlite/Function;I)I
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_value_1type
(JNIEnv *, jobject, jobject, jint);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: create_function_utf8
* Signature: ([BLorg/sqlite/Function;II)I
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_create_1function_1utf8
(JNIEnv *, jobject, jbyteArray, jobject, jint, jint);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: destroy_function_utf8
* Signature: ([B)I
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_destroy_1function_1utf8
(JNIEnv *, jobject, jbyteArray);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: create_collation_utf8
* Signature: ([BLorg/sqlite/Collation;)I
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_create_1collation_1utf8
(JNIEnv *, jobject, jbyteArray, jobject);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: destroy_collation_utf8
* Signature: ([B)I
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_destroy_1collation_1utf8
(JNIEnv *, jobject, jbyteArray);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: limit
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_limit
(JNIEnv *, jobject, jint, jint);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: backup
* Signature: ([B[BLorg/sqlite/core/DB/ProgressObserver;III)I
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_backup
(JNIEnv *, jobject, jbyteArray, jbyteArray, jobject, jint, jint, jint);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: restore
* Signature: ([B[BLorg/sqlite/core/DB/ProgressObserver;III)I
*/
JNIEXPORT jint JNICALL Java_org_jetbrains_sqlite_NativeDB_restore
(JNIEnv *, jobject, jbyteArray, jbyteArray, jobject, jint, jint, jint);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: set_commit_listener
* Signature: (Z)V
*/
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB_set_1commit_1listener
(JNIEnv *, jobject, jboolean);
/*
* Class: org_jetbrains_sqlite_NativeDB
* Method: set_update_listener
* Signature: (Z)V
*/
JNIEXPORT void JNICALL Java_org_jetbrains_sqlite_NativeDB_set_1update_1listener
(JNIEnv *, jobject, jboolean);
#ifdef __cplusplus
}
#endif
#endif

1987
platform/sqlite/sqlite/jni.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,66 @@
/*
* Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#ifndef _JAVASOFT_JNI_MD_H_
#define _JAVASOFT_JNI_MD_H_
#ifndef __has_attribute
#define __has_attribute(x) 0
#endif
#ifndef JNIEXPORT
#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility)
#ifdef ARM
#define JNIEXPORT __attribute__((externally_visible,visibility("default")))
#else
#define JNIEXPORT __attribute__((visibility("default")))
#endif
#else
#define JNIEXPORT
#endif
#endif
#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility)
#ifdef ARM
#define JNIIMPORT __attribute__((externally_visible,visibility("default")))
#else
#define JNIIMPORT __attribute__((visibility("default")))
#endif
#else
#define JNIIMPORT
#endif
#define JNICALL
typedef int jint;
#ifdef _LP64
typedef long jlong;
#else
typedef long long jlong;
#endif
typedef signed char jbyte;
#endif /* !_JAVASOFT_JNI_MD_H_ */

View File

@@ -0,0 +1,66 @@
/*
* Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#ifndef _JAVASOFT_JNI_MD_H_
#define _JAVASOFT_JNI_MD_H_
#ifndef __has_attribute
#define __has_attribute(x) 0
#endif
#ifndef JNIEXPORT
#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility)
#ifdef ARM
#define JNIEXPORT __attribute__((externally_visible,visibility("default")))
#else
#define JNIEXPORT __attribute__((visibility("default")))
#endif
#else
#define JNIEXPORT
#endif
#endif
#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility)
#ifdef ARM
#define JNIIMPORT __attribute__((externally_visible,visibility("default")))
#else
#define JNIIMPORT __attribute__((visibility("default")))
#endif
#else
#define JNIIMPORT
#endif
#define JNICALL
typedef int jint;
#ifdef _LP64
typedef long jlong;
#else
typedef long long jlong;
#endif
typedef signed char jbyte;
#endif /* !_JAVASOFT_JNI_MD_H_ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#ifndef _JAVASOFT_JNI_MD_H_
#define _JAVASOFT_JNI_MD_H_
#ifndef JNIEXPORT
#define JNIEXPORT __declspec(dllexport)
#endif
#define JNIIMPORT __declspec(dllimport)
#define JNICALL __stdcall
// 'long' is always 32 bit on windows so this matches what jdk expects
typedef long jint;
typedef __int64 jlong;
typedef signed char jbyte;
#endif /* !_JAVASOFT_JNI_MD_H_ */

View File

@@ -1,13 +1,10 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.sqlite;
import org.jetbrains.sqlite.core.SqliteConnection;
import java.sql.SQLException;
import java.io.IOException;
/** <a href="https://www.sqlite.org/c3ref/busy_handler.html">...</a> */
public abstract class BusyHandler {
/**
* <a href="https://www.sqlite.org/c3ref/busy_handler.html">...</a>
*
@@ -25,11 +22,9 @@ public abstract class BusyHandler {
* @param conn the SQLite connection
* @param busyHandler the busyHandler
*/
private static void commitHandler(SqliteConnection conn, BusyHandler busyHandler)
throws SQLException {
private static void commitHandler(SqliteConnection conn, BusyHandler busyHandler) throws IOException {
if (conn.isClosed()) {
throw new SQLException("connection closed");
throw new IOException("connection closed");
}
conn.db.busy_handler(busyHandler);
@@ -42,7 +37,7 @@ public abstract class BusyHandler {
* @param busyHandler the busyHandler
*/
public static void setHandler(SqliteConnection conn, BusyHandler busyHandler)
throws SQLException {
throws IOException {
commitHandler(conn, busyHandler);
}
@@ -51,7 +46,7 @@ public abstract class BusyHandler {
*
* @param conn the SQLite connection
*/
public static void clearHandler(SqliteConnection conn) throws SQLException {
public static void clearHandler(SqliteConnection conn) throws IOException {
commitHandler(conn, null);
}
}

View File

@@ -15,11 +15,7 @@
*/
package org.jetbrains.sqlite;
import org.jetbrains.sqlite.core.Codes;
import org.jetbrains.sqlite.core.DB;
import org.jetbrains.sqlite.core.SqliteConnection;
import java.sql.SQLException;
import java.io.IOException;
/**
* Provides an interface for creating SQLite user-defined collations.
@@ -43,7 +39,7 @@ import java.sql.SQLException;
*/
public abstract class Collation {
private SqliteConnection conn;
private DB db;
private SqliteDb db;
/**
* Called by SQLite as a custom collation to compare two strings.
@@ -62,16 +58,16 @@ public abstract class Collation {
* @param name The name of the collation.
* @param f The collation to register.
*/
public static void create(SqliteConnection conn, String name, Collation f) throws SQLException {
public static void create(SqliteConnection conn, String name, Collation f) throws IOException {
if (conn.isClosed()) {
throw new SQLException("connection closed");
throw new IOException("connection closed");
}
f.conn = conn;
f.db = f.conn.db;
if (f.db.create_collation(name, f) != Codes.SQLITE_OK) {
throw new SQLException("error creating collation");
if (f.db.create_collation(name, f) != SqliteCodes.SQLITE_OK) {
throw new IOException("error creating collation");
}
}
@@ -81,7 +77,7 @@ public abstract class Collation {
* @param conn The connection to remove the collation from.
* @param name The name of the collation.
*/
public static void destroy(SqliteConnection conn, String name) throws SQLException {
public static void destroy(SqliteConnection conn, String name) {
conn.db.destroy_collation(name);
}
}

View File

@@ -15,12 +15,8 @@
*/
package org.jetbrains.sqlite;
import org.jetbrains.sqlite.core.Codes;
import org.jetbrains.sqlite.core.DB;
import org.jetbrains.sqlite.core.SqliteConnection;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
/**
* Provides an interface for creating SQLite user-defined functions.
@@ -57,7 +53,7 @@ public abstract class Function {
long value = 0; // pointer sqlite3_value**
int args = 0;
private SqliteConnection conn;
private DB db;
private SqliteDb db;
/**
* Called by SQLite as a custom function. Should access arguments through <tt>value_*(int)</tt>,
@@ -69,7 +65,7 @@ public abstract class Function {
* Returns the number of arguments passed to the function. Can only be called from
* <tt>xFunc()</tt>.
*/
protected final synchronized int args() throws SQLException {
protected final synchronized int args() throws IOException {
checkContext();
return args;
}
@@ -78,7 +74,7 @@ public abstract class Function {
* Called by <tt>xFunc</tt> to return a value.
*
*/
protected final synchronized void result(byte[] value) throws SQLException {
protected final synchronized void result(byte[] value) throws IOException {
checkContext();
db.result_blob(context, value);
}
@@ -87,7 +83,7 @@ public abstract class Function {
* Called by <tt>xFunc</tt> to return a value.
*
*/
protected final synchronized void result(double value) throws SQLException {
protected final synchronized void result(double value) throws IOException {
checkContext();
db.result_double(context, value);
}
@@ -96,7 +92,7 @@ public abstract class Function {
* Called by <tt>xFunc</tt> to return a value.
*
*/
protected final synchronized void result(int value) throws SQLException {
protected final synchronized void result(int value) throws IOException {
checkContext();
db.result_int(context, value);
}
@@ -105,13 +101,13 @@ public abstract class Function {
* Called by <tt>xFunc</tt> to return a value.
*
*/
protected final synchronized void result(long value) throws SQLException {
protected final synchronized void result(long value) throws IOException {
checkContext();
db.result_long(context, value);
}
/** Called by <tt>xFunc</tt> to return a value. */
protected final synchronized void result() throws SQLException {
protected final synchronized void result() throws IOException {
checkContext();
db.result_null(context);
}
@@ -120,7 +116,7 @@ public abstract class Function {
* Called by <tt>xFunc</tt> to return a value.
*
*/
protected final synchronized void result(String value) throws SQLException {
protected final synchronized void result(String value) throws IOException {
checkContext();
db.result_text(context, value);
}
@@ -129,7 +125,7 @@ public abstract class Function {
* Called by <tt>xFunc</tt> to throw an error.
*
*/
protected final synchronized void error(String err) throws SQLException {
protected final synchronized void error(String err) throws IOException {
checkContext();
db.result_error(context, err);
}
@@ -138,7 +134,7 @@ public abstract class Function {
* Called by <tt>xFunc</tt> to access the value of an argument.
*
*/
protected final synchronized String value_text(int arg) throws SQLException {
protected final synchronized String value_text(int arg) throws IOException {
checkValue(arg);
return db.value_text(this, arg);
}
@@ -147,7 +143,7 @@ public abstract class Function {
* Called by <tt>xFunc</tt> to access the value of an argument.
*
*/
protected final synchronized byte[] value_blob(int arg) throws SQLException {
protected final synchronized byte[] value_blob(int arg) throws IOException {
checkValue(arg);
return db.value_blob(this, arg);
}
@@ -156,7 +152,7 @@ public abstract class Function {
* Called by <tt>xFunc</tt> to access the value of an argument.
*
*/
protected final synchronized double value_double(int arg) throws SQLException {
protected final synchronized double value_double(int arg) throws IOException {
checkValue(arg);
return db.value_double(this, arg);
}
@@ -165,7 +161,7 @@ public abstract class Function {
* Called by <tt>xFunc</tt> to access the value of an argument.
*
*/
protected final synchronized int value_int(int arg) throws SQLException {
protected final synchronized int value_int(int arg) throws IOException {
checkValue(arg);
return db.value_int(this, arg);
}
@@ -174,7 +170,7 @@ public abstract class Function {
* Called by <tt>xFunc</tt> to access the value of an argument.
*
*/
protected final synchronized long value_long(int arg) throws SQLException {
protected final synchronized long value_long(int arg) throws IOException {
checkValue(arg);
return db.value_long(this, arg);
}
@@ -183,26 +179,26 @@ public abstract class Function {
* Called by <tt>xFunc</tt> to access the value of an argument.
*
*/
protected final synchronized int value_type(int arg) throws SQLException {
protected final synchronized int value_type(int arg) throws IOException {
checkValue(arg);
return db.value_type(this, arg);
}
/** */
private void checkContext() throws SQLException {
private void checkContext() throws IOException {
if (conn == null || conn.db == null || context == 0) {
throw new SQLException("no context, not allowed to read value");
throw new IOException("no context, not allowed to read value");
}
}
/**
*/
private void checkValue(int arg) throws SQLException {
private void checkValue(int arg) throws IOException {
if (conn == null || conn.db == null || value == 0) {
throw new SQLException("not in value access state");
throw new IOException("not in value access state");
}
if (arg >= args) {
throw new SQLException("arg " + arg + " out bounds [0," + args + ")");
throw new IOException("arg " + arg + " out bounds [0," + args + ")");
}
}
@@ -213,7 +209,7 @@ public abstract class Function {
* @param name The name of the function.
* @param f The function to register.
*/
public static void create(SqliteConnection conn, String name, Function f) throws SQLException {
public static void create(SqliteConnection conn, String name, Function f) throws IOException {
create(conn, name, f, 0);
}
@@ -226,7 +222,7 @@ public abstract class Function {
* @param flags Extra flags to pass, such as {@link #FLAG_DETERMINISTIC}
*/
public static void create(SqliteConnection conn, String name, Function f, int flags)
throws SQLException {
throws IOException {
create(conn, name, f, -1, flags);
}
@@ -240,20 +236,20 @@ public abstract class Function {
* @param flags Extra flags to pass, such as {@link #FLAG_DETERMINISTIC}
*/
public static void create(SqliteConnection conn, String name, Function f, int nArgs, int flags)
throws SQLException {
throws IOException {
if (conn.isClosed()) {
throw new SQLException("connection closed");
throw new IOException("connection closed");
}
f.conn = conn;
f.db = f.conn.db;
if (nArgs < -1 || nArgs > 127) {
throw new SQLException("invalid args provided: " + nArgs);
throw new IOException("invalid args provided: " + nArgs);
}
if (f.db.create_function(name, f, nArgs, flags) != Codes.SQLITE_OK) {
throw new SQLException("error creating function");
if (f.db.create_function(name, f, nArgs, flags) != SqliteCodes.SQLITE_OK) {
throw new IOException("error creating function");
}
}
@@ -264,7 +260,7 @@ public abstract class Function {
* @param name The name of the function.
* @param nArgs Ignored.
*/
public static void destroy(SqliteConnection conn, String name, int nArgs) throws SQLException {
public static void destroy(SqliteConnection conn, String name, int nArgs) {
conn.db.destroy_function(name);
}
@@ -274,7 +270,7 @@ public abstract class Function {
* @param conn The connection to remove the function from.
* @param name The name of the function.
*/
public static void destroy(SqliteConnection conn, String name) throws SQLException {
public static void destroy(SqliteConnection conn, String name) {
destroy(conn, name, -1);
}

View File

@@ -3,10 +3,6 @@
package org.jetbrains.sqlite
import org.jetbrains.sqlite.core.Codes
import org.jetbrains.sqlite.core.DB
import org.jetbrains.sqlite.core.stepInBatch
class IntBinder(paramCount: Int, batchCountHint: Int = 1) : BaseBinder(paramCount) {
private var batch: IntArray = IntArray(paramCount * batchCountHint)
@@ -28,12 +24,12 @@ class IntBinder(paramCount: Int, batchCountHint: Int = 1) : BaseBinder(paramCoun
batch[batchPosition + 2] = v3
}
override fun bindParams(pointer: Long, db: DB) {
override fun bindParams(pointer: Long, db: SqliteDb) {
assert(batchQueryCount == 0)
for ((index, value) in batch.withIndex()) {
val status = db.bind_int(pointer, index + 1, value) and 0xFF
if (status != Codes.SQLITE_OK) {
throw db.newSQLException(status)
if (status != SqliteCodes.SQLITE_OK) {
throw db.newException(status)
}
}
}
@@ -50,13 +46,13 @@ class IntBinder(paramCount: Int, batchCountHint: Int = 1) : BaseBinder(paramCoun
}
}
override fun executeBatch(pointer: Long, db: DB) {
override fun executeBatch(pointer: Long, db: SqliteDb) {
for (batchIndex in 0 until batchQueryCount) {
db.reset(pointer)
for (index in 0 until paramCount) {
val status = db.bind_int(pointer, index + 1, batch[batchIndex * paramCount + index]) and 0xFF
if (status != Codes.SQLITE_OK) {
throw db.newSQLException(status)
if (status != SqliteCodes.SQLITE_OK) {
throw db.newException(status)
}
}
@@ -86,12 +82,12 @@ class LongBinder(paramCount: Int, batchCountHint: Int = 1) : BaseBinder(paramCou
batch[batchPosition + 2] = v3
}
override fun bindParams(pointer: Long, db: DB) {
override fun bindParams(pointer: Long, db: SqliteDb) {
assert(batchQueryCount == 0)
for ((index, value) in batch.withIndex()) {
val status = db.bind_long(pointer, index + 1, value) and 0xFF
if (status != Codes.SQLITE_OK) {
throw db.newSQLException(status)
if (status != SqliteCodes.SQLITE_OK) {
throw db.newException(status)
}
}
}
@@ -108,13 +104,13 @@ class LongBinder(paramCount: Int, batchCountHint: Int = 1) : BaseBinder(paramCou
}
}
override fun executeBatch(pointer: Long, db: DB) {
override fun executeBatch(pointer: Long, db: SqliteDb) {
for (batchIndex in 0 until batchQueryCount) {
db.reset(pointer)
for (index in 0 until paramCount) {
val status = db.bind_long(pointer, index + 1, batch[batchIndex * paramCount + index]) and 0xFF
if (status != Codes.SQLITE_OK) {
throw db.newSQLException(status)
if (status != SqliteCodes.SQLITE_OK) {
throw db.newException(status)
}
}

View File

@@ -0,0 +1,362 @@
/*
* Copyright (c) 2007 David Crawshaw <david@zentus.com >
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
@file:Suppress("FunctionName")
package org.jetbrains.sqlite
import java.io.IOException
import java.nio.ByteBuffer
import java.nio.charset.StandardCharsets
/** This class provides a thin JNI layer over the SQLite3 C API. */
internal class NativeDB : SqliteDb() {
// SQLite connection handle.
private var pointer: Long = 0
@Suppress("unused")
private val busyHandler: Long = 0
@Suppress("unused")
private val updateListener: Long = 0
@Suppress("unused")
private val commitListener: Long = 0
@Synchronized
override fun open(file: String, openFlags: Int): Int {
check(pointer == 0L) { "Database $file is already opened" }
return open(stringToUtf8ByteArray(file), openFlags)
}
@Synchronized
external override fun open(filename: ByteArray, openFlags: Int): Int
@Synchronized
external override fun _close()
@Synchronized
override fun _exec(sql: String): Int {
return _exec_utf8(stringToUtf8ByteArray(sql))
}
@Synchronized
external fun _exec_utf8(sqlUtf8: ByteArray?): Int
@Synchronized
external override fun enable_load_extension(enable: Boolean): Int
external override fun interrupt()
@Synchronized
external override fun busy_timeout(ms: Int)
@Synchronized
external override fun busy_handler(busyHandler: BusyHandler?)
@Synchronized
override fun prepare(sql: String): SafeStatementPointer {
return SafeStatementPointer(db = this, pointer = prepare_utf8(stringToUtf8ByteArray(sql)))
}
// byte[] instead of string is actually more performant
@Synchronized
external fun prepare_utf8(sqlUtf8: ByteArray?): Long
@Synchronized
override fun errmsg(): String? {
return utf8ByteBufferToString(errmsg_utf8() ?: return null)
}
@Suppress("SpellCheckingInspection")
@Synchronized
external fun errmsg_utf8(): ByteBuffer?
@Synchronized
override fun libversion(): String {
return utf8ByteBufferToString(libversion_utf8())
}
@Suppress("SpellCheckingInspection")
private external fun libversion_utf8(): ByteBuffer
@Synchronized
external override fun changes(): Long
@Synchronized
external override fun total_changes(): Long
@Synchronized
external override fun finalize(stmt: Long): Int
@Synchronized
external override fun step(stmt: Long): Int
@Synchronized
external override fun reset(stmt: Long): Int
@Synchronized
external override fun clear_bindings(stmt: Long): Int
@Synchronized
external override fun bind_parameter_count(stmt: Long): Int
@Synchronized
external override fun column_count(stmt: Long): Int
@Synchronized
external override fun column_type(stmt: Long, col: Int): Int
@Synchronized
override fun column_text(statementPointer: Long, zeroBasedColumnIndex: Int): String? {
return utf8ByteBufferToString(column_text_utf8(statementPointer, zeroBasedColumnIndex) ?: return null)
}
@Synchronized
external fun column_text_utf8(stmt: Long, col: Int): ByteBuffer?
@Synchronized
external override fun column_blob(statementPointer: Long, zeroBasedColumnIndex: Int): ByteArray?
@Synchronized
external override fun column_double(statementPointer: Long, zeroBasedColumnIndex: Int): Double
@Synchronized
external override fun column_long(statementPointer: Long, zeroBasedColumnIndex: Int): Long
@Synchronized
external override fun column_int(statementPointer: Long, zeroBasedColumnIndex: Int): Int
@Synchronized
external override fun bind_null(stmt: Long, oneBasedColumnIndex: Int): Int
@Synchronized
external override fun bind_int(stmt: Long, oneBasedColumnIndex: Int, v: Int): Int
@Synchronized
external override fun bind_long(stmt: Long, oneBasedColumnIndex: Int, v: Long): Int
@Synchronized
external override fun bind_double(stmt: Long, oneBasedColumnIndex: Int, v: Double): Int
@Synchronized
override fun bind_text(stmt: Long, oneBasedColumnIndex: Int, v: String?): Int {
return bind_text_utf8(stmt, oneBasedColumnIndex, stringToUtf8ByteArray(v))
}
@Synchronized
external fun bind_text_utf8(stmt: Long, pos: Int, vUtf8: ByteArray?): Int
@Synchronized
external override fun bind_blob(stmt: Long, oneBasedColumnIndex: Int, v: ByteArray?): Int
@Synchronized
external override fun result_null(context: Long)
@Synchronized
override fun result_text(context: Long, `val`: String?) {
result_text_utf8(context, stringToUtf8ByteArray(`val`))
}
@Synchronized
external fun result_text_utf8(context: Long, valUtf8: ByteArray?)
@Synchronized
external override fun result_blob(context: Long, `val`: ByteArray?)
@Synchronized
external override fun result_double(context: Long, `val`: Double)
@Synchronized
external override fun result_long(context: Long, `val`: Long)
@Synchronized
external override fun result_int(context: Long, `val`: Int)
@Synchronized
override fun result_error(context: Long, err: String?) {
result_error_utf8(context, stringToUtf8ByteArray(err))
}
@Synchronized
external fun result_error_utf8(context: Long, errUtf8: ByteArray?)
@Synchronized
override fun value_text(f: Function, arg: Int): String {
return utf8ByteBufferToString(value_text_utf8(f, arg))
}
@Synchronized
external fun value_text_utf8(f: Function?, argUtf8: Int): ByteBuffer
/** @see SqliteDb.value_blob
*/
@Synchronized
external override fun value_blob(f: Function?, arg: Int): ByteArray?
@Synchronized
external override fun value_double(f: Function?, arg: Int): Double
@Synchronized
external override fun value_long(f: Function?, arg: Int): Long
@Synchronized
external override fun value_int(f: Function?, arg: Int): Int
@Synchronized
external override fun value_type(f: Function, arg: Int): Int
/** @see SqliteDb.create_function
*/
@Synchronized
override fun create_function(name: String, function: Function, nArgs: Int, flags: Int): Int {
return create_function_utf8(nameUtf8 = nameToUtf8ByteArray(nameType = "function", name = name),
func = function,
nArgs = nArgs,
flags = flags)
}
@Synchronized
external fun create_function_utf8(nameUtf8: ByteArray, func: Function, nArgs: Int, flags: Int): Int
@Synchronized
override fun destroy_function(name: String): Int {
return destroy_function_utf8(nameToUtf8ByteArray("function", name))
}
@Synchronized
external fun destroy_function_utf8(nameUtf8: ByteArray?): Int
@Synchronized
override fun create_collation(name: String, collation: Collation): Int {
return create_collation_utf8(nameToUtf8ByteArray("collation", name), collation)
}
@Synchronized
external fun create_collation_utf8(nameUtf8: ByteArray, coll: Collation): Int
@Synchronized
override fun destroy_collation(name: String): Int {
return destroy_collation_utf8(nameToUtf8ByteArray(nameType = "collation", name = name))
}
@Synchronized
external fun destroy_collation_utf8(nameUtf8: ByteArray?): Int
@Synchronized
external override fun limit(id: Int, value: Int): Int
override fun backup(dbName: String, destFileName: String, observer: ProgressObserver?): Int {
return backup(dbNameUtf8 = stringToUtf8ByteArray(dbName),
destFileNameUtf8 = stringToUtf8ByteArray(destFileName),
observer = observer,
sleepTimeMillis = DEFAULT_BACKUP_BUSY_SLEEP_TIME_MILLIS,
nTimeouts = DEFAULT_BACKUP_NUM_BUSY_BEFORE_FAIL,
pagesPerStep = DEFAULT_PAGES_PER_BACKUP_STEP)
}
override fun backup(dbName: String,
destFileName: String,
observer: ProgressObserver?,
sleepTimeMillis: Int,
nTimeouts: Int,
pagesPerStep: Int): Int {
return backup(dbNameUtf8 = stringToUtf8ByteArray(dbName),
destFileNameUtf8 = stringToUtf8ByteArray(destFileName),
observer = observer,
sleepTimeMillis = sleepTimeMillis,
nTimeouts = nTimeouts,
pagesPerStep = pagesPerStep)
}
@Synchronized
external fun backup(dbNameUtf8: ByteArray,
destFileNameUtf8: ByteArray,
observer: ProgressObserver?,
sleepTimeMillis: Int,
nTimeouts: Int,
pagesPerStep: Int): Int
@Synchronized
override fun restore(dbName: String, sourceFileName: String, observer: ProgressObserver?): Int {
return restore(dbName = dbName,
sourceFileName = sourceFileName,
observer = observer,
sleepTimeMillis = DEFAULT_BACKUP_BUSY_SLEEP_TIME_MILLIS,
nTimeouts = DEFAULT_BACKUP_NUM_BUSY_BEFORE_FAIL,
pagesPerStep = DEFAULT_PAGES_PER_BACKUP_STEP)
}
@Synchronized
override fun restore(dbName: String?,
sourceFileName: String?,
observer: ProgressObserver?,
sleepTimeMillis: Int,
nTimeouts: Int,
pagesPerStep: Int): Int {
return restore(
dbNameUtf8 = stringToUtf8ByteArray(dbName),
sourceFileName = stringToUtf8ByteArray(sourceFileName),
observer = observer,
sleepTimeMillis = sleepTimeMillis,
nTimeouts = nTimeouts,
pagesPerStep = pagesPerStep)
}
@Synchronized
external fun restore(dbNameUtf8: ByteArray?,
sourceFileName: ByteArray?,
observer: ProgressObserver?,
sleepTimeMillis: Int,
nTimeouts: Int,
pagesPerStep: Int): Int
@Synchronized
external override fun set_commit_listener(enabled: Boolean)
@Synchronized
external override fun set_update_listener(enabled: Boolean)
companion object {
private const val DEFAULT_BACKUP_BUSY_SLEEP_TIME_MILLIS = 100
private const val DEFAULT_BACKUP_NUM_BUSY_BEFORE_FAIL = 3
private const val DEFAULT_PAGES_PER_BACKUP_STEP = 100
private fun nameToUtf8ByteArray(nameType: String, name: String): ByteArray {
val nameUtf8 = stringToUtf8ByteArray(name)
check(!(name.isEmpty() || nameUtf8.size > 255)) { "invalid $nameType name: '$name'" }
return nameUtf8
}
/**
* Throws an IOException. Called from native code
*/
@Suppress("unused", "SpellCheckingInspection")
@JvmStatic
fun throwex(msg: String?) {
throw IOException(msg)
}
// called from native code (only to convert exception text on calling function)
@JvmStatic
fun stringToUtf8ByteArray(str: String?): ByteArray {
return str!!.toByteArray(StandardCharsets.UTF_8)
}
fun utf8ByteBufferToString(buffer: ByteBuffer): String {
val bytes = ByteArray(buffer.remaining())
buffer.get(bytes)
return bytes.decodeToString()
}
}
}

View File

@@ -3,20 +3,16 @@
package org.jetbrains.sqlite
import org.jetbrains.sqlite.core.DB
import org.jetbrains.sqlite.core.sqlBind
import org.jetbrains.sqlite.core.stepInBatch
sealed class Binder {
internal abstract val paramCount: Int
abstract val batchQueryCount: Int
internal abstract fun bindParams(pointer: Long, db: DB)
abstract fun addBatch()
abstract fun executeBatch(pointer: Long, db: DB)
internal abstract fun bindParams(pointer: Long, db: SqliteDb)
internal abstract fun executeBatch(pointer: Long, db: SqliteDb)
internal abstract fun clearBatch()
}
@@ -28,12 +24,12 @@ object EmptyBinder : Binder() {
override val batchQueryCount: Int
get() = 0
override fun bindParams(pointer: Long, db: DB) {
override fun bindParams(pointer: Long, db: SqliteDb) {
}
override fun addBatch() = throw IllegalStateException()
override fun executeBatch(pointer: Long, db: DB) = throw IllegalStateException()
override fun executeBatch(pointer: Long, db: SqliteDb) = throw IllegalStateException()
override fun clearBatch() {
}
@@ -55,7 +51,7 @@ sealed class BaseBinder(override val paramCount: Int) : Binder() {
class ObjectBinder(paramCount: Int, batchCountHint: Int = 1) : BaseBinder(paramCount) {
private var batch: Array<Any?> = arrayOfNulls(paramCount * batchCountHint)
override fun bindParams(pointer: Long, db: DB) {
override fun bindParams(pointer: Long, db: SqliteDb) {
assert(batchQueryCount == 0)
for ((position, value) in batch.withIndex()) {
sqlBind(pointer, position, value, db)
@@ -74,7 +70,7 @@ class ObjectBinder(paramCount: Int, batchCountHint: Int = 1) : BaseBinder(paramC
}
}
override fun executeBatch(pointer: Long, db: DB) {
override fun executeBatch(pointer: Long, db: SqliteDb) {
for (batchIndex in 0 until batchQueryCount) {
db.reset(pointer)
for (position in 0 until paramCount) {

View File

@@ -1,36 +0,0 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.sqlite;
import org.jetbrains.sqlite.core.SqliteConnection;
import java.sql.SQLException;
/** <a href="https://sqlite.org/c3ref/progress_handler.html">...</a> */
public abstract class ProgressHandler {
protected abstract int progress();
/**
* Sets a progress handler for the connection.
*
* @param conn the SQLite connection
* @param vmCalls the approximate number of virtual machine instructions that are evaluated
* between successive invocations of the progressHandler
* @param progressHandler the progressHandler
*/
public static void setHandler(
SqliteConnection conn, int vmCalls, ProgressHandler progressHandler) throws SQLException {
if (conn.isClosed()) {
throw new SQLException("connection closed");
}
conn.db.register_progress_handler(vmCalls, progressHandler);
}
/**
* Clears any progress handler registered with the connection.
*
* @param conn the SQLite connection
*/
public static void clearHandler(SqliteConnection conn) throws SQLException {
conn.db.clear_progress_handler();
}
}

View File

@@ -1,10 +0,0 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.sqlite;
/** <a href="https://www.sqlite.org/c3ref/commit_hook.html">...</a> */
public interface SQLiteCommitListener {
void onCommit();
void onRollback();
}

View File

@@ -3,8 +3,6 @@
package org.jetbrains.sqlite
import org.jetbrains.sqlite.core.SqliteConnection
class SQLiteConfig {
// SQLite defaults to 0, but as https://github.com/xerial/sqlite-jdbc we use 3000
var busyTimeout: Int = 3000
@@ -16,7 +14,9 @@ class SQLiteConfig {
// SQLite defaults to FULL (https://www.sqlite.org/pragma.html#pragma_synchronous),
// but "FULL synchronous is very safe, but it is also slower", so
// as we use WAL (see above) and WAL "is safe from corruption with synchronous=NORMAL", we use NORMAL as default.
private var synchronous: SynchronousMode = SynchronousMode.NORMAL
//private var synchronous: SynchronousMode = SynchronousMode.NORMAL
// SQLite is compiled with SQLITE_DEFAULT_WAL_SYNCHRONOUS=1
// set the default open mode of SQLite3
var openModeFlag: Int = 0x00 or SQLiteOpenMode.READWRITE.flag or SQLiteOpenMode.CREATE.flag
@@ -28,12 +28,13 @@ class SQLiteConfig {
if (journalMode != JournalMode.DELETE) {
yield("PRAGMA journal_mode = $journalMode")
}
if (synchronous != SynchronousMode.FULL) {
yield("PRAGMA synchronous = $synchronous")
}
//if (synchronous != SynchronousMode.FULL && journalMode != synchronous) {
// yield("PRAGMA synchronous = $synchronous")
//}
// https://www.sqlite.org/pragma.html#pragma_temp_store
yield("PRAGMA temp_store = MEMORY")
yield("pragma cache_size = 2000")
}.joinToString(";")
connection.db.exec(sql)
}

View File

@@ -1,40 +0,0 @@
/*--------------------------------------------------------------------------
* Copyright 2016 Magnus Reftel
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*--------------------------------------------------------------------------*/
// --------------------------------------
// sqlite-jdbc Project
//
// SQLiteException.java
// Since: Jun 28, 2016
//
// $URL$
// $Author$
// --------------------------------------
package org.jetbrains.sqlite;
import java.sql.SQLException;
public final class SQLiteException extends SQLException {
private final SQLiteErrorCode resultCode;
public SQLiteException(String message, SQLiteErrorCode resultCode) {
super(message, null, resultCode.code & 0xff);
this.resultCode = resultCode;
}
public SQLiteErrorCode getResultCode() {
return resultCode;
}
}

View File

@@ -1,27 +0,0 @@
package org.jetbrains.sqlite;
public enum SQLiteLimits {
SQLITE_LIMIT_LENGTH(0),
SQLITE_LIMIT_SQL_LENGTH(1),
SQLITE_LIMIT_COLUMN(2),
SQLITE_LIMIT_EXPR_DEPTH(3),
SQLITE_LIMIT_COMPOUND_SELECT(4),
SQLITE_LIMIT_VDBE_OP(5),
SQLITE_LIMIT_FUNCTION_ARG(6),
SQLITE_LIMIT_ATTACHED(7),
SQLITE_LIMIT_LIKE_PATTERN_LENGTH(8),
SQLITE_LIMIT_VARIABLE_NUMBER(9),
SQLITE_LIMIT_TRIGGER_DEPTH(10),
SQLITE_LIMIT_WORKER_THREADS(11),
SQLITE_LIMIT_PAGE_COUNT(12);
private final int id;
SQLiteLimits(int id) {
this.id = id;
}
public int getId() {
return id;
}
}

View File

@@ -1,13 +0,0 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.sqlite;
/** <a href="https://www.sqlite.org/c3ref/update_hook.html">...</a> */
public interface SQLiteUpdateListener {
void onUpdate(Type type, String database, String table, long rowId);
enum Type {
INSERT,
DELETE,
UPDATE
}
}

View File

@@ -1,5 +1,5 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.sqlite.core
package org.jetbrains.sqlite
/**
* A class for safely wrapping calls to a native pointer to a statement, ensuring no other thread
@@ -9,11 +9,8 @@ internal class SafeStatementPointer(
// store a reference to the DB, to lock it before any safe function is called. This avoids
// deadlocking by locking the DB. All calls with the raw pointer are synchronized with the DB
// anyway, so making a separate lock would be pointless
private val db: SqliteDb,
@JvmField
@PublishedApi
internal val db: DB,
@JvmField
@PublishedApi
internal val pointer: Long,
) {
/**
@@ -64,7 +61,7 @@ internal class SafeStatementPointer(
* @param task the function to run
* @return the return of the passed in function
*/
inline fun safeRunInt(task: (db: DB, statementPointer: Long) -> Int): Int {
inline fun safeRunInt(task: (db: SqliteDb, statementPointer: Long) -> Int): Int {
synchronized(db) {
ensureOpen()
return task(db, pointer)
@@ -77,7 +74,7 @@ internal class SafeStatementPointer(
* @param task the function to run
* @return the return code of the function
*/
inline fun <T> safeRun(task: (db: DB, statementPointer: Long) -> T): T {
inline fun <T> safeRun(task: (db: SqliteDb, statementPointer: Long) -> T): T {
synchronized(db) {
ensureOpen()
return task(db, pointer)

View File

@@ -1,18 +1,23 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@file:Suppress("RemoveExplicitTypeArguments")
package org.jetbrains.sqlite.core
package org.jetbrains.sqlite
import org.intellij.lang.annotations.Language
import org.jetbrains.sqlite.*
import java.nio.file.Files
import java.nio.file.Path
import java.util.concurrent.atomic.AtomicBoolean
class SqliteConnection(file: Path?, config: SQLiteConfig = SQLiteConfig()) : AutoCloseable {
//private final AtomicInteger savePoint = new AtomicInteger(0);
@JvmField
internal val db: NativeDB
private val closed = AtomicBoolean(true)
val isClosed: Boolean
get() = closed.get()
private var currentBusyTimeout: Int
/**
* @return The busy timeout value for the connection.
@@ -25,45 +30,17 @@ class SqliteConnection(file: Path?, config: SQLiteConfig = SQLiteConfig()) : Aut
db.busy_timeout(timeoutMillis)
}
//
///** @see Connection#setSavepoint() */
//public SqliteSavepoint setSavepoint() throws SQLException {
// checkOpen();
// var sp = new SqliteSavepoint(savePoint.incrementAndGet());
// getDatabase().exec(String.format("SAVEPOINT %s", sp.getSavepointName()));
// return sp;
//}
//
///** @see Connection#setSavepoint(String) */
//public SqliteSavepoint setSavepoint(String name) throws SQLException {
// checkOpen();
// var sp = new SqliteSavepoint(savePoint.incrementAndGet(), name);
// getDatabase().exec(String.format("SAVEPOINT %s", sp.getSavepointName()));
// return sp;
//}
//
///** @see Connection#releaseSavepoint(Savepoint) */
//public void releaseSavepoint(Savepoint savepoint) throws SQLException {
// checkOpen();
// getDatabase()
// .exec(String.format("RELEASE SAVEPOINT %s", savepoint.getSavepointName()));
//}
//
///** @see Connection#rollback(Savepoint) */
//public void rollback(Savepoint savepoint) throws SQLException {
// checkOpen();
// getDatabase()
// .exec(
// String.format("ROLLBACK TO SAVEPOINT %s", savepoint.getSavepointName())
// );
//}
init {
file?.parent?.let { Files.createDirectories(it) }
loadNativeDb()
db = NativeDB()
@Suppress("IfThenToElvis")
db.open(if (file == null) ":memory:" else file.toAbsolutePath().normalize().toString(), config.openModeFlag)
val status = db.open(if (file == null) ":memory:" else file.toAbsolutePath().normalize().toString(), config.openModeFlag) and 0xff
if (status != SqliteCodes.SQLITE_OK) {
throw SqliteDb.newException(status, "", null)
}
closed.set(false)
try {
config.apply(this)
currentBusyTimeout = config.busyTimeout
@@ -101,9 +78,6 @@ class SqliteConnection(file: Path?, config: SQLiteConfig = SQLiteConfig()) : Aut
return SqlitePreparedStatement(connection = this, sql = sql, binder = binder)
}
val isClosed: Boolean
get() = db.isClosed
//
///** @see Connection#setSavepoint() */
//public SqliteSavepoint setSavepoint() throws SQLException {
@@ -181,9 +155,9 @@ class SqliteConnection(file: Path?, config: SQLiteConfig = SQLiteConfig()) : Aut
internal fun step(statementPointer: Long, sql: String): Boolean {
return when (val status = db.step(statementPointer) and 0xFF) {
Codes.SQLITE_DONE -> true
Codes.SQLITE_ROW -> false
else -> throw DB.newSQLException(status, db.errmsg(), sql)
SqliteCodes.SQLITE_DONE -> true
SqliteCodes.SQLITE_ROW -> false
else -> throw SqliteDb.newException(status, db.errmsg()!!, sql)
}
}
@@ -194,8 +168,8 @@ class SqliteConnection(file: Path?, config: SQLiteConfig = SQLiteConfig()) : Aut
if (values is Int) {
val status = db.bind_int(statementPointer, 1, values)
if (status != Codes.SQLITE_OK) {
throw db.newSQLException(status)
if (status != SqliteCodes.SQLITE_OK) {
throw db.newException(status)
}
}
else {
@@ -218,13 +192,13 @@ class SqliteConnection(file: Path?, config: SQLiteConfig = SQLiteConfig()) : Aut
}
override fun close() {
if (!isClosed) {
if (closed.compareAndSet(false, true)) {
db.close()
}
}
private fun checkOpen() {
check(!isClosed) { "database connection closed" }
check(!closed.get()) { "database connection closed" }
}
fun beginTransaction() {
@@ -279,7 +253,7 @@ class SqliteConnection(file: Path?, config: SQLiteConfig = SQLiteConfig()) : Aut
//}
}
internal fun sqlBind(pointer: Long, index: Int, v: Any?, db: DB) {
internal fun sqlBind(pointer: Long, index: Int, v: Any?, db: SqliteDb) {
val position = index + 1
val status = when (v) {
null -> db.bind_null(pointer, position)
@@ -293,20 +267,20 @@ internal fun sqlBind(pointer: Long, index: Int, v: Any?, db: DB) {
else -> throw UnsupportedOperationException("Unexpected param type: ${v.javaClass}")
} and 0xFF
if (status != Codes.SQLITE_OK) {
throw db.newSQLException(status)
if (status != SqliteCodes.SQLITE_OK) {
throw db.newException(status)
}
}
internal fun stepInBatch(statementPointer: Long, db: DB, batchIndex: Int) {
internal fun stepInBatch(statementPointer: Long, db: SqliteDb, batchIndex: Int) {
val status = db.step(statementPointer)
if (status != DB.SQLITE_DONE) {
if (status != SqliteCodes.SQLITE_DONE) {
db.reset(statementPointer)
if (status == DB.SQLITE_ROW) {
if (status == SqliteCodes.SQLITE_ROW) {
throw IllegalStateException("batch entry $batchIndex: query returns results")
}
else {
throw db.newSQLException(status)
throw db.newException(status)
}
}
}

View File

@@ -0,0 +1,611 @@
/*
* Copyright (c) 2007 David Crawshaw <david@zentus.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
@file:Suppress("FunctionName")
package org.jetbrains.sqlite
import com.intellij.openapi.diagnostic.Logger
import java.io.IOException
import java.util.concurrent.ConcurrentHashMap
internal abstract class SqliteDb {
// tracer for statements to avoid unfinalized statements on db close
private val statements = ConcurrentHashMap.newKeySet<SafeStatementPointer>()
private val updateListeners = HashSet<SQLiteUpdateListener>()
private val commitListeners = HashSet<SQLiteCommitListener>()
companion object {
/**
* Throws formatted SqliteException with error code and message.
*/
fun newException(errorCode: Int, errorMessage: String, sql: String? = null): SqliteException {
val code = SqliteErrorCode.getErrorCode(errorCode)
var text = if (code == SqliteErrorCode.UNKNOWN_ERROR) {
"$code:$errorCode ($errorMessage)"
}
else {
"$code ($errorMessage)"
}
if (sql != null) {
text += " (sql=$sql)"
}
return SqliteException(message = text, resultCode = code)
}
}
/**
* Aborts any pending operation and returns at its earliest opportunity.
* See [http://www.sqlite.org/c3ref/interrupt.html](http://www.sqlite.org/c3ref/interrupt.html)
*/
abstract fun interrupt()
/**
* Sets a [busy handler](http://www.sqlite.org/c3ref/busy_handler.html) that sleeps
* for a specified amount of time when a table is locked.
*
* @param ms Time to sleep in milliseconds.
* @see [http://www.sqlite.org/c3ref/busy_timeout.html](http://www.sqlite.org/c3ref/busy_timeout.html)
*/
abstract fun busy_timeout(ms: Int)
/**
* Sets a [busy handler](http://www.sqlite.org/c3ref/busy_handler.html) that sleeps
* for a specified amount of time when a table is locked.
*
* @see [http://www.sqlite.org/c3ref/busy_timeout.html](http://www.sqlite.org/c3ref/busy_handler.html)
*/
abstract fun busy_handler(busyHandler: BusyHandler?)
/**
* Return English-language text that describes the error as either UTF-8 or UTF-16.
*
* @return Error description in English.
* @see [http://www.sqlite.org/c3ref/errcode.html](http://www.sqlite.org/c3ref/errcode.html)
*/
@Suppress("SpellCheckingInspection")
abstract fun errmsg(): String?
/**
* Returns the value for SQLITE_VERSION, SQLITE_VERSION_NUMBER, and SQLITE_SOURCE_ID C
* preprocessor macros that are associated with the library.
*
* @see [http://www.sqlite.org/c3ref/c_source_id.html](http://www.sqlite.org/c3ref/c_source_id.html)
*/
@Suppress("SpellCheckingInspection")
abstract fun libversion(): String
/**
* @return Number of rows that were changed, inserted or deleted by the last SQL statement
* @see [http://www.sqlite.org/c3ref/changes.html](http://www.sqlite.org/c3ref/changes.html)
*/
abstract fun changes(): Long
/**
* @return Number of row changes caused by INSERT, UPDATE or DELETE statements since the
* database connection was opened.
* @see [http://www.sqlite.org/c3ref/total_changes.html](http://www.sqlite.org/c3ref/total_changes.html)
*/
abstract fun total_changes(): Long
/**
* Enables or disables loading of SQLite extensions.
*
* @param enable True to enable; false otherwise.
* @return [Result Codes](http://www.sqlite.org/c3ref/c_abort.html)
* @see [http://www.sqlite.org/c3ref/load_extension.html](http://www.sqlite.org/c3ref/load_extension.html)
*/
abstract fun enable_load_extension(enable: Boolean): Int
/**
* Execute an SQL statement using the process of compiling, evaluating, and destroying the prepared statement object.
*
* @param sql SQL statement to be executed.
* @see [http://www.sqlite.org/c3ref/exec.html](http://www.sqlite.org/c3ref/exec.html)
*/
@Synchronized
fun exec(sql: String) {
val status = _exec(sql)
if (status != SqliteCodes.SQLITE_OK) {
throw newException(errorCode = status, errorMessage = errmsg()!!, sql = sql)
}
}
abstract fun open(file: String, openFlags: Int): Int
/**
* Closes a database connection and finalizes any remaining statements before the closing
* operation.
*
* @see [http://www.sqlite.org/c3ref/close.html](http://www.sqlite.org/c3ref/close.html)
*/
@Synchronized
fun close() {
// finalize any remaining statements before closing db
for (element in statements) {
try {
element.internalClose()
}
catch (e: Throwable) {
Logger.getInstance(SqliteDb::class.java).error(e)
}
}
_close()
}
/**
* Complies an SQL statement.
* @see [http://www.sqlite.org/c3ref/prepare.html](http://www.sqlite.org/c3ref/prepare.html)
*/
@Synchronized
fun prepareForStatement(sql: String): SafeStatementPointer {
val pointer = prepare(sql)
check(statements.add(pointer)) { "Already added pointer to statements set" }
return pointer
}
/**
* Destroys a statement.
*
* @param safePtr the pointer wrapper to remove from internal structures
* @param ptr the raw pointer to free
* @return [Result Codes](http://www.sqlite.org/c3ref/c_abort.html)
* @see [http://www.sqlite.org/c3ref/finalize.html](http://www.sqlite.org/c3ref/finalize.html)
*/
@Synchronized
fun finalize(safePtr: SafeStatementPointer, ptr: Long): Int {
try {
return finalize(ptr)
}
finally {
statements.remove(safePtr)
}
}
/**
* Creates an SQLite interface to a database with the provided open flags.
*
* @param filename The database to open.
* @param openFlags File opening configurations ([http://www.sqlite.org/c3ref/c_open_autoproxy.html](http://www.sqlite.org/c3ref/c_open_autoproxy.html))
* @see [http://www.sqlite.org/c3ref/open.html](http://www.sqlite.org/c3ref/open.html)
*/
protected abstract fun open(filename: ByteArray, openFlags: Int): Int
/**
* Closes the SQLite interface to a database.
*
* @see [http://www.sqlite.org/c3ref/close.html](http://www.sqlite.org/c3ref/close.html)
*/
protected abstract fun _close()
/**
* Complies, evaluates, executes and commits an SQL statement.
*
* @param sql An SQL statement.
* @return [Result Codes](http://www.sqlite.org/c3ref/c_abort.html)
* @see [http://www.sqlite.org/c3ref/exec.html](http://www.sqlite.org/c3ref/exec.html)
*/
abstract fun _exec(sql: String): Int
/**
* Complies an SQL statement.
*
* @param sql An SQL statement.
* @return [Result Codes](http://www.sqlite.org/c3ref/c_abort.html)
* @see [http://www.sqlite.org/c3ref/prepare.html](http://www.sqlite.org/c3ref/prepare.html)
*/
protected abstract fun prepare(sql: String): SafeStatementPointer
/**
* Destroys a prepared statement.
*
* @param stmt Pointer to the statement pointer.
* @return [Result Codes](http://www.sqlite.org/c3ref/c_abort.html)
* @see [http://www.sqlite.org/c3ref/finalize.html](http://www.sqlite.org/c3ref/finalize.html)
*/
abstract fun finalize(stmt: Long): Int
/**
* Evaluates a statement.
*
* @param stmt Pointer to the statement.
* @return [Result Codes](http://www.sqlite.org/c3ref/c_abort.html)
* @see [http://www.sqlite.org/c3ref/step.html](http://www.sqlite.org/c3ref/step.html)
*/
abstract fun step(stmt: Long): Int
/**
* Sets a prepared statement object back to its initial state, ready to be re-executed.
*
* @param stmt Pointer to the statement.
* @return [Result Codes](http://www.sqlite.org/c3ref/c_abort.html)
* @see [http://www.sqlite.org/c3ref/reset.html](http://www.sqlite.org/c3ref/reset.html)
*/
abstract fun reset(stmt: Long): Int
/**
* Reset all bindings on a prepared statement (reset all host parameters to NULL).
*
* @param stmt Pointer to the statement.
* @return [Result Codes](http://www.sqlite.org/c3ref/c_abort.html)
* @see [http://www.sqlite.org/c3ref/clear_bindings.html](http://www.sqlite.org/c3ref/clear_bindings.html)
*/
abstract fun clear_bindings(stmt: Long): Int
/**
* @param stmt Pointer to the statement.
* @return Number of parameters in a prepared SQL.
* @see [http://www.sqlite.org/c3ref/bind_parameter_count.html](http://www.sqlite.org/c3ref/bind_parameter_count.html)
*/
abstract fun bind_parameter_count(stmt: Long): Int
/**
* @param stmt Pointer to the statement.
* @return Number of columns in the result set returned by the prepared statement.
* @see [http://www.sqlite.org/c3ref/column_count.html](http://www.sqlite.org/c3ref/column_count.html)
*/
abstract fun column_count(stmt: Long): Int
/**
* @param stmt Pointer to the statement.
* @param col Number of column.
* @return Datatype code for the initial data type of the result column.
* @see [http://www.sqlite.org/c3ref/column_blob.html](http://www.sqlite.org/c3ref/column_blob.html)
*/
abstract fun column_type(stmt: Long, col: Int): Int
abstract fun column_text(statementPointer: Long, zeroBasedColumnIndex: Int): String?
abstract fun column_blob(statementPointer: Long, zeroBasedColumnIndex: Int): ByteArray?
abstract fun column_double(statementPointer: Long, zeroBasedColumnIndex: Int): Double
abstract fun column_long(statementPointer: Long, zeroBasedColumnIndex: Int): Long
abstract fun column_int(statementPointer: Long, zeroBasedColumnIndex: Int): Int
abstract fun bind_null(stmt: Long, oneBasedColumnIndex: Int): Int
abstract fun bind_int(stmt: Long, oneBasedColumnIndex: Int, v: Int): Int
abstract fun bind_long(stmt: Long, oneBasedColumnIndex: Int, v: Long): Int
abstract fun bind_double(stmt: Long, oneBasedColumnIndex: Int, v: Double): Int
abstract fun bind_text(stmt: Long, oneBasedColumnIndex: Int, v: String?): Int
abstract fun bind_blob(stmt: Long, oneBasedColumnIndex: Int, v: ByteArray?): Int
/**
* Sets the result of an SQL function as NULL with the pointer to the SQLite database context.
*
* @param context Pointer to the SQLite database context.
* @see [http://www.sqlite.org/c3ref/result_blob.html](http://www.sqlite.org/c3ref/result_blob.html)
*/
abstract fun result_null(context: Long)
/**
* Sets the result of an SQL function as text data type with the pointer to the SQLite database
* context and the the result value of String.
*
* @param context Pointer to the SQLite database context.
* @param val Result value of an SQL function.
* @see [http://www.sqlite.org/c3ref/result_blob.html](http://www.sqlite.org/c3ref/result_blob.html)
*/
abstract fun result_text(context: Long, `val`: String?)
/**
* Sets the result of an SQL function as blob data type with the pointer to the SQLite database
* context and the the result value of byte array.
*
* @param context Pointer to the SQLite database context.
* @param val Result value of an SQL function.
* @see [http://www.sqlite.org/c3ref/result_blob.html](http://www.sqlite.org/c3ref/result_blob.html)
*/
abstract fun result_blob(context: Long, `val`: ByteArray?)
/**
* Sets the result of an SQL function as double data type with the pointer to the SQLite
* database context and the the result value of double.
*
* @param context Pointer to the SQLite database context.
* @param val Result value of an SQL function.
* @see [http://www.sqlite.org/c3ref/result_blob.html](http://www.sqlite.org/c3ref/result_blob.html)
*/
abstract fun result_double(context: Long, `val`: Double)
/**
* Sets the result of an SQL function as long data type with the pointer to the SQLite database
* context and the the result value of long.
*
* @param context Pointer to the SQLite database context.
* @param val Result value of an SQL function.
* @see [http://www.sqlite.org/c3ref/result_blob.html](http://www.sqlite.org/c3ref/result_blob.html)
*/
abstract fun result_long(context: Long, `val`: Long)
/**
* Sets the result of an SQL function as int data type with the pointer to the SQLite database
* context and the the result value of int.
*
* @param context Pointer to the SQLite database context.
* @param val Result value of an SQL function.
* @see [http://www.sqlite.org/c3ref/result_blob.html](http://www.sqlite.org/c3ref/result_blob.html)
*/
abstract fun result_int(context: Long, `val`: Int)
/**
* Sets the result of an SQL function as an error with the pointer to the SQLite database
* context and the error of String.
*
* @param context Pointer to the SQLite database context.
* @param err Error result of an SQL function.
* @see [http://www.sqlite.org/c3ref/result_blob.html](http://www.sqlite.org/c3ref/result_blob.html)
*/
abstract fun result_error(context: Long, err: String?)
/**
* @param f SQLite function object.
* @param arg Pointer to the parameter of the SQLite function or aggregate.
* @return Parameter value of the given SQLite function or aggregate in text data type.
* @see [http://www.sqlite.org/c3ref/value_blob.html](http://www.sqlite.org/c3ref/value_blob.html)
*/
abstract fun value_text(f: Function, arg: Int): String
/**
* @param f SQLite function object.
* @param arg Pointer to the parameter of the SQLite function or aggregate.
* @return Parameter value of the given SQLite function or aggregate in blob data type.
* @see [http://www.sqlite.org/c3ref/value_blob.html](http://www.sqlite.org/c3ref/value_blob.html)
*/
abstract fun value_blob(f: Function?, arg: Int): ByteArray?
/**
* @param f SQLite function object.
* @param arg Pointer to the parameter of the SQLite function or aggregate.
* @return Parameter value of the given SQLite function or aggregate in double data type
* @see [http://www.sqlite.org/c3ref/value_blob.html](http://www.sqlite.org/c3ref/value_blob.html)
*/
abstract fun value_double(f: Function?, arg: Int): Double
/**
* @param f SQLite function object.
* @param arg Pointer to the parameter of the SQLite function or aggregate.
* @return Parameter value of the given SQLite function or aggregate in long data type.
* @see [http://www.sqlite.org/c3ref/value_blob.html](http://www.sqlite.org/c3ref/value_blob.html)
*/
abstract fun value_long(f: Function?, arg: Int): Long
/**
* Accesses the parameter values on the function or aggregate in int data type with the function
* object and the parameter value.
*
* @param f SQLite function object.
* @param arg Pointer to the parameter of the SQLite function or aggregate.
* @return Parameter value of the given SQLite function or aggregate.
* @see [http://www.sqlite.org/c3ref/value_blob.html](http://www.sqlite.org/c3ref/value_blob.html)
*/
abstract fun value_int(f: Function?, arg: Int): Int
/**
* @param f SQLite function object.
* @param arg Pointer to the parameter of the SQLite function or aggregate.
* @return Parameter datatype of the function or aggregate in int data type.
* @see [http://www.sqlite.org/c3ref/value_blob.html](http://www.sqlite.org/c3ref/value_blob.html)
*/
abstract fun value_type(f: Function, arg: Int): Int
/**
* Create a user defined function with given function name and the function object.
*
* @param name The function name to be created.
* @param function SQLite function object.
* @param flags Extra flags to use when creating the function, such as [ ][Function.FLAG_DETERMINISTIC]
* @return [Result Codes](http://www.sqlite.org/c3ref/c_abort.html)
* @see [http://www.sqlite.org/c3ref/create_function.html](http://www.sqlite.org/c3ref/create_function.html)
*/
abstract fun create_function(name: String, function: Function, nArgs: Int, flags: Int): Int
/**
* De-registers a user defined function
*
* @param name Name of the function to de-register.
* @return [Result Codes](http://www.sqlite.org/c3ref/c_abort.html)
*/
abstract fun destroy_function(name: String): Int
/**
* Create a user defined collation with given collation name and the collation object.
*
* @param name The collation name to be created.
* @param collation SQLite collation object.
* @return [Result Codes](https://www.sqlite.org/c3ref/c_abort.html)
* @see [https://www.sqlite.org/c3ref/create_collation.html](https://www.sqlite.org/c3ref/create_collation.html)
*/
abstract fun create_collation(name: String, collation: Collation): Int
/**
* Create a user defined collation with given collation name and the collation object.
*
* @param name The collation name to be created.
* @return [Result Codes](https://www.sqlite.org/c3ref/c_abort.html)
*/
abstract fun destroy_collation(name: String): Int
/**
* @param dbName Database name to be backed up.
* @param destFileName Target backup file name.
* @param observer ProgressObserver object.
* @return [Result Codes](http://www.sqlite.org/c3ref/c_abort.html)
*/
abstract fun backup(dbName: String, destFileName: String, observer: ProgressObserver?): Int
/**
* @param dbName Database name to be backed up.
* @param destFileName Target backup file name.
* @param observer ProgressObserver object.
* @param sleepTimeMillis time to wait during a backup/restore operation if sqlite3_backup_step
* returns SQLITE_BUSY before continuing
* @param nTimeouts the number of times sqlite3_backup_step can return SQLITE_BUSY before
* failing
* @param pagesPerStep the number of pages to copy in each sqlite3_backup_step. If this is
* negative, the entire DB is copied at once.
* @return [Result Codes](http://www.sqlite.org/c3ref/c_abort.html)
*/
abstract fun backup(dbName: String,
destFileName: String,
observer: ProgressObserver?,
sleepTimeMillis: Int,
nTimeouts: Int,
pagesPerStep: Int): Int
/**
* @param dbName Database name for restoring data.
* @param sourceFileName Source file name.
* @param observer ProgressObserver object.
* @return [Result Codes](http://www.sqlite.org/c3ref/c_abort.html)
*/
abstract fun restore(dbName: String, sourceFileName: String, observer: ProgressObserver?): Int
/**
* @param dbName the name of the db to restore
* @param sourceFileName the filename of the source db to restore
* @param observer ProgressObserver object.
* @param sleepTimeMillis time to wait during a backup/restore operation if sqlite3_backup_step
* returns SQLITE_BUSY before continuing
* @param nTimeouts the number of times sqlite3_backup_step can return SQLITE_BUSY before
* failing
* @param pagesPerStep the number of pages to copy in each sqlite3_backup_step. If this is
* negative, the entire DB is copied at once.
* @return [Result Codes](http://www.sqlite.org/c3ref/c_abort.html)
*/
abstract fun restore(dbName: String?,
sourceFileName: String?,
observer: ProgressObserver?,
sleepTimeMillis: Int,
nTimeouts: Int,
pagesPerStep: Int): Int
/**
* @param id The id of the limit.
* @param value The new value of the limit.
* @return The prior value of the limit
* @see [https://www.sqlite.org/c3ref/limit.html](https://www.sqlite.org/c3ref/limit.html)
*/
abstract fun limit(id: Int, value: Int): Int
// COMPOUND FUNCTIONS ////////////////////////////////////////////
abstract fun set_commit_listener(enabled: Boolean)
abstract fun set_update_listener(enabled: Boolean)
@Synchronized
fun addUpdateListener(listener: SQLiteUpdateListener) {
if (updateListeners.add(listener) && updateListeners.size == 1) {
set_update_listener(true)
}
}
@Synchronized
fun addCommitListener(listener: SQLiteCommitListener) {
if (commitListeners.add(listener) && commitListeners.size == 1) {
set_commit_listener(true)
}
}
@Synchronized
fun removeUpdateListener(listener: SQLiteUpdateListener) {
if (updateListeners.remove(listener) && updateListeners.isEmpty()) {
set_update_listener(false)
}
}
@Synchronized
fun removeCommitListener(listener: SQLiteCommitListener) {
if (commitListeners.remove(listener) && commitListeners.isEmpty()) {
set_commit_listener(false)
}
}
fun onUpdate(type: Int, database: String?, table: String?, rowId: Long) {
var listeners: Set<SQLiteUpdateListener>
synchronized(this) { listeners = HashSet(updateListeners) }
for (listener in listeners) {
val operationType = when (type) {
18 -> SQLiteUpdateListener.Type.INSERT
9 -> SQLiteUpdateListener.Type.DELETE
23 -> SQLiteUpdateListener.Type.UPDATE
else -> throw AssertionError("Unknown type: $type")
}
listener.onUpdate(operationType, database, table, rowId)
}
}
fun onCommit(commit: Boolean) {
var listeners: Set<SQLiteCommitListener>
synchronized(this) { listeners = HashSet(commitListeners) }
for (listener in listeners) {
if (commit) {
listener.onCommit()
}
else {
listener.onRollback()
}
}
}
/**
* Throws IOException with an error message.
*/
@Suppress("unused", "SpellCheckingInspection")
@Throws(IOException::class)
fun throwex() {
throw IOException(errmsg())
}
@Suppress("SpellCheckingInspection", "unused")
fun throwex(errorCode: Int) {
throw newException(errorCode = errorCode, errorMessage = errmsg()!!)
}
fun newException(errorCode: Int, sql: String? = null): SqliteException {
return newException(errorCode = errorCode, errorMessage = errmsg()!!, sql = sql)
}
interface ProgressObserver {
fun progress(remaining: Int, pageCount: Int)
}
}
class SqliteException internal constructor(message: String, @Suppress("unused") val resultCode: SqliteErrorCode) : IOException(message)
// https://www.sqlite.org/c3ref/commit_hook.html)
interface SQLiteCommitListener {
fun onCommit()
fun onRollback()
}
/** [...](https://www.sqlite.org/c3ref/update_hook.html) */
interface SQLiteUpdateListener {
fun onUpdate(type: Type?, database: String?, table: String?, rowId: Long)
enum class Type {
INSERT,
DELETE,
UPDATE
}
}
internal object SqliteCodes {
/** Successful result */
const val SQLITE_OK = 0
/** Library used incorrectly */
const val SQLITE_MISUSE = 21
/** sqlite_step() has another row ready */
const val SQLITE_ROW = 100
/** sqlite_step() has finished executing */
const val SQLITE_DONE = 101
}

View File

@@ -22,18 +22,18 @@
// $URL$
// $Author$
// --------------------------------------
package org.jetbrains.sqlite;
package org.jetbrains.sqlite
/**
* SQLite3 error code
*
* @author leo
* @see <a
* href="http://www.sqlite.org/c3ref/c_abort.html">http://www.sqlite.org/c3ref/c_abort.html</a>
* @see [http://www.sqlite.org/c3ref/c_abort.html](http://www.sqlite.org/c3ref/c_abort.html)
*/
public enum SQLiteErrorCode {
enum class SqliteErrorCode(@JvmField val code: Int, @JvmField val message: String) {
UNKNOWN_ERROR(-1, "unknown error"),
SQLITE_OK(0, "Successful result"),
/* beginning-of-error-codes */
SQLITE_ERROR(1, "SQL error or missing database"),
SQLITE_INTERNAL(2, "Internal logic error in SQLite"),
@@ -65,6 +65,7 @@ public enum SQLiteErrorCode {
SQLITE_WARNING(28, "Warnings from sqlite3_log()"),
SQLITE_ROW(100, "sqlite3_step() has another row ready"),
SQLITE_DONE(101, "sqlite3_step() has finished executing"),
/* Beginning of extended error codes */
SQLITE_ABORT_ROLLBACK(
516,
@@ -184,34 +185,17 @@ public enum SQLiteErrorCode {
SQLITE_READONLY_ROLLBACK(776, "Hot journal needs to be rolled back"),
SQLITE_WARNING_AUTOINDEX(284, "automatic indexing is used");
public final int code;
public final String message;
/**
* Constructor that applies error code and message.
*
* @param code Error code.
* @param message Message for the error.
/** @see Enum.toString
*/
SQLiteErrorCode(int code, String message) {
this.code = code;
this.message = message;
}
override fun toString(): String = "[$name] $message"
/** @see Enum#toString() */
@Override
public String toString() {
return String.format("[%s] %s", name(), message);
}
/**
* @param errorCode Error code.
* @return Error message.
*/
public static SQLiteErrorCode getErrorCode(int errorCode) {
for (SQLiteErrorCode each : values()) {
if (errorCode == each.code) return each;
companion object {
/**
* @param errorCode Error code.
* @return Error message.
*/
internal fun getErrorCode(errorCode: Int): SqliteErrorCode {
return values().firstOrNull { errorCode == it.code } ?: UNKNOWN_ERROR
}
return UNKNOWN_ERROR;
}
}
}

View File

@@ -1,9 +1,8 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.sqlite.core
package org.jetbrains.sqlite
class SqliteIntPreparedStatement internal constructor(private val connection: SqliteConnection, private val sql: String) : SqliteStatement {
@JvmField
internal val pointer: SafeStatementPointer
private val pointer: SafeStatementPointer
private var batchPosition = 0
private var batch: IntArray
@@ -36,17 +35,14 @@ class SqliteIntPreparedStatement internal constructor(private val connection: Sq
isClosed = true
}
internal val db: DB
get() = connection.db
private fun internalClose() {
val pointer = pointer.takeIf { !it.isClosed } ?: return
check(!connection.isClosed) { "Connection is closed" }
batchPosition = 0
val status = pointer.close()
if (status != Codes.SQLITE_OK && status != Codes.SQLITE_MISUSE) {
throw db.newSQLException(status)
if (status != SqliteCodes.SQLITE_OK && status != SqliteCodes.SQLITE_MISUSE) {
throw connection.db.newException(status)
}
}
@@ -69,14 +65,15 @@ class SqliteIntPreparedStatement internal constructor(private val connection: Sq
}
try {
synchronized(pointer.db) {
val db = connection.db
synchronized(db) {
pointer.ensureOpen()
for (batchIndex in 0 until batchQueryCount) {
db.reset(pointer.pointer)
for (position in 0 until paramCount) {
val status = db.bind_int(pointer.pointer, position + 1, batch[batchIndex * paramCount + position]) and 0xFF
if (status != Codes.SQLITE_OK) {
throw db.newSQLException(status)
if (status != SqliteCodes.SQLITE_OK) {
throw db.newException(status)
}
}

View File

@@ -1,7 +1,6 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.sqlite.core
package org.jetbrains.sqlite
import org.jetbrains.sqlite.Binder
import kotlin.time.Duration
class SqlitePreparedStatement<T : Binder> internal constructor(private val connection: SqliteConnection,
@@ -37,7 +36,7 @@ class SqlitePreparedStatement<T : Binder> internal constructor(private val conne
isClosed = true
}
internal val db: DB
internal val db: SqliteDb
get() = connection.db
private fun internalClose() {
@@ -47,8 +46,8 @@ class SqlitePreparedStatement<T : Binder> internal constructor(private val conne
resultSet.close()
binder.clearBatch()
val status = pointer.close()
if (status != Codes.SQLITE_OK && status != Codes.SQLITE_MISUSE) {
throw db.newSQLException(status)
if (status != SqliteCodes.SQLITE_OK && status != SqliteCodes.SQLITE_MISUSE) {
throw db.newException(status)
}
}

View File

@@ -1,5 +1,7 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.sqlite.core
package org.jetbrains.sqlite
private const val SQLITE_NULL = 5
class SqliteResultSet(private val statement: SqlitePreparedStatement<*>) {
/**
@@ -58,16 +60,16 @@ class SqliteResultSet(private val statement: SqlitePreparedStatement<*>) {
}
// do the real work
return when (val statusCode = statement.pointer.safeRunInt(DB::step)) {
Codes.SQLITE_DONE -> {
return when (val statusCode = statement.pointer.safeRunInt(SqliteDb::step)) {
SqliteCodes.SQLITE_DONE -> {
pastLastRow = true
false
}
Codes.SQLITE_ROW -> {
SqliteCodes.SQLITE_ROW -> {
row++
true
}
else -> throw statement.db.newSQLException(statusCode)
else -> throw statement.db.newException(statusCode)
}
}
@@ -86,7 +88,7 @@ class SqliteResultSet(private val statement: SqlitePreparedStatement<*>) {
//val isFirst: Boolean
// get() = row == 1
fun wasNull(): Boolean = safeGetColumnType(lastColumn) == Codes.SQLITE_NULL
fun wasNull(): Boolean = safeGetColumnType(lastColumn) == SQLITE_NULL
///** @see ResultSet.getBigDecimal
// */
@@ -122,11 +124,11 @@ class SqliteResultSet(private val statement: SqlitePreparedStatement<*>) {
}
fun getDouble(col: Int): Double {
return if (safeGetColumnType(markColumn(col)) == Codes.SQLITE_NULL) 0.0 else safeGetDoubleCol(col)
return if (safeGetColumnType(markColumn(col)) == SQLITE_NULL) 0.0 else safeGetDoubleCol(col)
}
fun getFloat(col: Int): Float {
return if (safeGetColumnType(markColumn(col)) == Codes.SQLITE_NULL) 0f else safeGetDoubleCol(col).toFloat()
return if (safeGetColumnType(markColumn(col)) == SQLITE_NULL) 0f else safeGetDoubleCol(col).toFloat()
}
fun getInt(zeroBasedColumnIndex: Int): Int {
@@ -137,9 +139,9 @@ class SqliteResultSet(private val statement: SqlitePreparedStatement<*>) {
fun getLong(zeroBasedColumnIndex: Int): Long {
val pointer = statement.pointer
synchronized(pointer.db) {
synchronized(statement.db) {
pointer.ensureOpen()
return pointer.db.column_long(pointer.pointer, markColumn(zeroBasedColumnIndex))
return statement.db.column_long(pointer.pointer, markColumn(zeroBasedColumnIndex))
}
}
@@ -151,9 +153,9 @@ class SqliteResultSet(private val statement: SqlitePreparedStatement<*>) {
private fun safeGetDoubleCol(zeroBasedColumnIndex: Int): Double {
val pointer = statement.pointer
synchronized(pointer.db) {
synchronized(statement.db) {
pointer.ensureOpen()
return pointer.db.column_double(pointer.pointer, markColumn(zeroBasedColumnIndex))
return statement.db.column_double(pointer.pointer, markColumn(zeroBasedColumnIndex))
}
}

View File

@@ -1,5 +1,5 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.sqlite.core;
package org.jetbrains.sqlite;
public final class SqliteSavepoint {
final int id;

View File

@@ -1,5 +1,5 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.sqlite.core
package org.jetbrains.sqlite
sealed interface SqliteStatement : AutoCloseable {
fun executeBatch()

View File

@@ -3,10 +3,6 @@ package org.jetbrains.sqlite
import com.intellij.openapi.diagnostic.logger
import org.intellij.lang.annotations.Language
import org.jetbrains.sqlite.core.SqliteConnection
import org.jetbrains.sqlite.core.SqliteIntPreparedStatement
import org.jetbrains.sqlite.core.SqlitePreparedStatement
import org.jetbrains.sqlite.core.SqliteStatement
/**
* Simplifies calling [SqliteStatement.executeBatch] or [SqliteStatement.close] for multiple statements.

View File

@@ -1,104 +0,0 @@
/*
* Copyright (c) 2007 David Crawshaw <david@zentus.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package org.jetbrains.sqlite.core;
public interface Codes {
/** Successful result */
int SQLITE_OK = 0;
/** SQL error or missing database */
int SQLITE_ERROR = 1;
/** An internal logic error in SQLite */
int SQLITE_INTERNAL = 2;
/** Access permission denied */
int SQLITE_PERM = 3;
/** Callback routine requested an abort */
int SQLITE_ABORT = 4;
/** The database file is locked */
int SQLITE_BUSY = 5;
/** A table in the database is locked */
int SQLITE_LOCKED = 6;
/** A malloc() failed */
int SQLITE_NOMEM = 7;
/** Attempt to write a readonly database */
int SQLITE_READONLY = 8;
/** Operation terminated by sqlite_interrupt() */
int SQLITE_INTERRUPT = 9;
/** Some kind of disk I/O error occurred */
int SQLITE_IOERR = 10;
/** The database disk image is malformed */
int SQLITE_CORRUPT = 11;
/** (Internal Only) Table or record not found */
int SQLITE_NOTFOUND = 12;
/** Insertion failed because database is full */
int SQLITE_FULL = 13;
/** Unable to open the database file */
int SQLITE_CANTOPEN = 14;
/** Database lock protocol error */
int SQLITE_PROTOCOL = 15;
/** (Internal Only) Database table is empty */
int SQLITE_EMPTY = 16;
/** The database schema changed */
int SQLITE_SCHEMA = 17;
/** Too much data for one row of a table */
int SQLITE_TOOBIG = 18;
/** Abort due to constraint violation */
int SQLITE_CONSTRAINT = 19;
/** Data type mismatch */
int SQLITE_MISMATCH = 20;
/** Library used incorrectly */
int SQLITE_MISUSE = 21;
/** Uses OS features not supported on host */
int SQLITE_NOLFS = 22;
/** Authorization denied */
int SQLITE_AUTH = 23;
/** sqlite_step() has another row ready */
int SQLITE_ROW = 100;
/** sqlite_step() has finished executing */
int SQLITE_DONE = 101;
// types returned by sqlite3_column_type()
int SQLITE_INTEGER = 1;
int SQLITE_FLOAT = 2;
int SQLITE_TEXT = 3;
int SQLITE_BLOB = 4;
int SQLITE_NULL = 5;
}

View File

@@ -1,730 +0,0 @@
/*
* Copyright (c) 2007 David Crawshaw <david@zentus.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package org.jetbrains.sqlite.core;
import com.intellij.openapi.diagnostic.Logger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.sqlite.*;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
/*
* This class is the interface to SQLite. It provides some helper functions
* used by other parts of the driver. The goal of the helper functions here
* are not only to provide functionality, but to handle contractual
* differences between the JDBC specification and the SQLite C API.
*
* The process of moving SQLite weirdness into this class is incomplete.
* You'll still find lots of code in Stmt and PrepStmt that are doing
* implicit contract conversions. Sorry.
*
* The subclass, NativeDB, provides the actual access to SQLite functions.
*/
public abstract class DB implements Codes {
private final AtomicBoolean closed = new AtomicBoolean(true);
// tracer for statements to avoid unfinalized statements on db close
private final Set<SafeStatementPointer> statements = ConcurrentHashMap.newKeySet();
private final Set<SQLiteUpdateListener> updateListeners = new HashSet<>();
private final Set<SQLiteCommitListener> commitListeners = new HashSet<>();
public DB() {
}
public boolean isClosed() {
return closed.get();
}
// WRAPPER FUNCTIONS ////////////////////////////////////////////
/**
* Aborts any pending operation and returns at its earliest opportunity.
*
* @see <a
* href="http://www.sqlite.org/c3ref/interrupt.html">http://www.sqlite.org/c3ref/interrupt.html</a>
*/
public abstract void interrupt();
/**
* Sets a <a href="http://www.sqlite.org/c3ref/busy_handler.html">busy handler</a> that sleeps
* for a specified amount of time when a table is locked.
*
* @param ms Time to sleep in milliseconds.
* @see <a
* href="http://www.sqlite.org/c3ref/busy_timeout.html">http://www.sqlite.org/c3ref/busy_timeout.html</a>
*/
public abstract void busy_timeout(int ms);
/**
* Sets a <a href="http://www.sqlite.org/c3ref/busy_handler.html">busy handler</a> that sleeps
* for a specified amount of time when a table is locked.
*
* @see <a
* href="http://www.sqlite.org/c3ref/busy_handler.html">http://www.sqlite.org/c3ref/busy_timeout.html</a>
*/
public abstract void busy_handler(BusyHandler busyHandler);
/**
* Return English-language text that describes the error as either UTF-8 or UTF-16.
*
* @return Error description in English.
* @see <a
* href="http://www.sqlite.org/c3ref/errcode.html">http://www.sqlite.org/c3ref/errcode.html</a>
*/
abstract String errmsg();
/**
* Returns the value for SQLITE_VERSION, SQLITE_VERSION_NUMBER, and SQLITE_SOURCE_ID C
* preprocessor macros that are associated with the library.
*
* @return Compile-time SQLite version information.
* @see <a
* href="http://www.sqlite.org/c3ref/libversion.html">http://www.sqlite.org/c3ref/libversion.html</a>
* @see <a
* href="http://www.sqlite.org/c3ref/c_source_id.html">http://www.sqlite.org/c3ref/c_source_id.html</a>
*/
public abstract String libversion();
/**
* @return Number of rows that were changed, inserted or deleted by the last SQL statement
* @see <a
* href="http://www.sqlite.org/c3ref/changes.html">http://www.sqlite.org/c3ref/changes.html</a>
*/
public abstract long changes();
/**
* @return Number of row changes caused by INSERT, UPDATE or DELETE statements since the
* database connection was opened.
* @see <a
* href="http://www.sqlite.org/c3ref/total_changes.html">http://www.sqlite.org/c3ref/total_changes.html</a>
*/
public abstract long total_changes();
public abstract int shared_cache(boolean enable);
/**
* Enables or disables loading of SQLite extensions.
*
* @param enable True to enable; false otherwise.
* @return <a href="http://www.sqlite.org/c3ref/c_abort.html">Result Codes</a>
* @see <a
* href="http://www.sqlite.org/c3ref/load_extension.html">http://www.sqlite.org/c3ref/load_extension.html</a>
*/
public abstract int enable_load_extension(boolean enable);
/**
* Execute an SQL statement using the process of compiling, evaluating, and destroying the prepared statement object.
*
* @param sql SQL statement to be executed.
* @see <a href="http://www.sqlite.org/c3ref/exec.html">http://www.sqlite.org/c3ref/exec.html</a>
*/
public final synchronized void exec(@NotNull String sql) throws SQLException {
int status = _exec(sql);
if (status != SQLITE_OK) {
throw newSQLException(status, errmsg(), sql);
}
}
/**
* Creates an SQLite interface to a database for the given connection.
*
* @param file The database.
* @param openFlags File opening configurations (<a
* href="http://www.sqlite.org/c3ref/c_open_autoproxy.html">http://www.sqlite.org/c3ref/c_open_autoproxy.html</a>)
* @see <a
* href="http://www.sqlite.org/c3ref/open.html">http://www.sqlite.org/c3ref/open.html</a>
*/
final synchronized void open(String file, int openFlags) throws SQLException {
_open(file, openFlags);
closed.set(false);
}
/**
* Closes a database connection and finalizes any remaining statements before the closing
* operation.
*
* @see <a
* href="http://www.sqlite.org/c3ref/close.html">http://www.sqlite.org/c3ref/close.html</a>
*/
public final synchronized void close() throws SQLException {
// finalize any remaining statements before closing db
for (SafeStatementPointer element : statements) {
try {
element.internalClose$intellij_platform_sqlite();
}
catch (Throwable e) {
Logger.getInstance(DB.class).error(e);
}
}
closed.set(true);
_close();
}
/**
* Complies an SQL statement.
* @see <a href="http://www.sqlite.org/c3ref/prepare.html">http://www.sqlite.org/c3ref/prepare.html</a>
*/
final synchronized @NotNull SafeStatementPointer prepareForStatement(@NotNull String sql) throws SQLException {
SafeStatementPointer pointer = prepare(sql);
if (!statements.add(pointer)) {
throw new IllegalStateException("Already added pointer to statements set");
}
return pointer;
}
/**
* Destroys a statement.
*
* @param safePtr the pointer wrapper to remove from internal structures
* @param ptr the raw pointer to free
* @return <a href="http://www.sqlite.org/c3ref/c_abort.html">Result Codes</a>
* @see <a
* href="http://www.sqlite.org/c3ref/finalize.html">http://www.sqlite.org/c3ref/finalize.html</a>
*/
public synchronized int finalize(SafeStatementPointer safePtr, long ptr) {
try {
return finalize(ptr);
}
finally {
statements.remove(safePtr);
}
}
/**
* Creates an SQLite interface to a database with the provided open flags.
*
* @param filename The database to open.
* @param openFlags File opening configurations (<a
* href="http://www.sqlite.org/c3ref/c_open_autoproxy.html">http://www.sqlite.org/c3ref/c_open_autoproxy.html</a>)
* @see <a
* href="http://www.sqlite.org/c3ref/open.html">http://www.sqlite.org/c3ref/open.html</a>
*/
protected abstract void _open(String filename, int openFlags) throws SQLException;
/**
* Closes the SQLite interface to a database.
*
* @see <a
* href="http://www.sqlite.org/c3ref/close.html">http://www.sqlite.org/c3ref/close.html</a>
*/
protected abstract void _close() throws SQLException;
/**
* Complies, evaluates, executes and commits an SQL statement.
*
* @param sql An SQL statement.
* @return <a href="http://www.sqlite.org/c3ref/c_abort.html">Result Codes</a>
* @see <a
* href="http://www.sqlite.org/c3ref/exec.html">http://www.sqlite.org/c3ref/exec.html</a>
*/
public abstract int _exec(String sql) throws SQLException;
/**
* Complies an SQL statement.
*
* @param sql An SQL statement.
* @return <a href="http://www.sqlite.org/c3ref/c_abort.html">Result Codes</a>
* @see <a
* href="http://www.sqlite.org/c3ref/prepare.html">http://www.sqlite.org/c3ref/prepare.html</a>
*/
protected abstract SafeStatementPointer prepare(String sql) throws SQLException;
/**
* Destroys a prepared statement.
*
* @param stmt Pointer to the statement pointer.
* @return <a href="http://www.sqlite.org/c3ref/c_abort.html">Result Codes</a>
* @see <a
* href="http://www.sqlite.org/c3ref/finalize.html">http://www.sqlite.org/c3ref/finalize.html</a>
*/
public abstract int finalize(long stmt);
/**
* Evaluates a statement.
*
* @param stmt Pointer to the statement.
* @return <a href="http://www.sqlite.org/c3ref/c_abort.html">Result Codes</a>
* @see <a
* href="http://www.sqlite.org/c3ref/step.html">http://www.sqlite.org/c3ref/step.html</a>
*/
public abstract int step(long stmt);
/**
* Sets a prepared statement object back to its initial state, ready to be re-executed.
*
* @param stmt Pointer to the statement.
* @return <a href="http://www.sqlite.org/c3ref/c_abort.html">Result Codes</a>
* @see <a
* href="http://www.sqlite.org/c3ref/reset.html">http://www.sqlite.org/c3ref/reset.html</a>
*/
public abstract int reset(long stmt);
/**
* Reset all bindings on a prepared statement (reset all host parameters to NULL).
*
* @param stmt Pointer to the statement.
* @return <a href="http://www.sqlite.org/c3ref/c_abort.html">Result Codes</a>
* @see <a
* href="http://www.sqlite.org/c3ref/clear_bindings.html">http://www.sqlite.org/c3ref/clear_bindings.html</a>
*/
public abstract int clear_bindings(long stmt); // TODO remove?
/**
* @param stmt Pointer to the statement.
* @return Number of parameters in a prepared SQL.
* @see <a
* href="http://www.sqlite.org/c3ref/bind_parameter_count.html">http://www.sqlite.org/c3ref/bind_parameter_count.html</a>
*/
public abstract int bind_parameter_count(long stmt);
/**
* @param stmt Pointer to the statement.
* @return Number of columns in the result set returned by the prepared statement.
* @see <a
* href="http://www.sqlite.org/c3ref/column_count.html">http://www.sqlite.org/c3ref/column_count.html</a>
*/
public abstract int column_count(long stmt);
/**
* @param stmt Pointer to the statement.
* @param col Number of column.
* @return Datatype code for the initial data type of the result column.
* @see <a
* href="http://www.sqlite.org/c3ref/column_blob.html">http://www.sqlite.org/c3ref/column_blob.html</a>
*/
public abstract int column_type(long stmt, int col);
/**
* @param stmt Pointer to the statement.
* @param col Number of column.
* @return Declared type of the table column for prepared statement.
* @see <a
* href="http://www.sqlite.org/c3ref/column_decltype.html">http://www.sqlite.org/c3ref/column_decltype.html</a>
*/
public abstract String column_decltype(long stmt, int col);
/**
* @param stmt Pointer to the statement.
* @param col Number of column.
* @return Original text of column name which is the declared in the CREATE TABLE statement.
* @see <a
* href="http://www.sqlite.org/c3ref/column_database_name.html">http://www.sqlite.org/c3ref/column_database_name.html</a>
*/
public abstract String column_table_name(long stmt, int col);
/**
* @param stmt Pointer to the statement.
* @param col The number of column.
* @return Name assigned to a particular column in the result set of a SELECT statement.
* @see <a
* href="http://www.sqlite.org/c3ref/column_name.html">http://www.sqlite.org/c3ref/column_name.html</a>
*/
public abstract String column_name(long stmt, int col);
public abstract String column_text(long statementPointer, int zeroBasedColumnIndex);
public abstract byte[] column_blob(long statementPointer, int zeroBasedColumnIndex);
public abstract double column_double(long statementPointer, int zeroBasedColumnIndex);
public abstract long column_long(long statementPointer, int zeroBasedColumnIndex);
public abstract int column_int(long statementPointer, int zeroBasedColumnIndex);
abstract int bind_null(long stmt, int oneBasedColumnIndex);
public abstract int bind_int(long stmt, int oneBasedColumnIndex, int v);
public abstract int bind_long(long stmt, int oneBasedColumnIndex, long v);
abstract int bind_double(long stmt, int oneBasedColumnIndex, double v);
abstract int bind_text(long stmt, int oneBasedColumnIndex, String v);
abstract int bind_blob(long stmt, int oneBasedColumnIndex, byte[] v);
/**
* Sets the result of an SQL function as NULL with the pointer to the SQLite database context.
*
* @param context Pointer to the SQLite database context.
* @see <a
* href="http://www.sqlite.org/c3ref/result_blob.html">http://www.sqlite.org/c3ref/result_blob.html</a>
*/
public abstract void result_null(long context);
/**
* Sets the result of an SQL function as text data type with the pointer to the SQLite database
* context and the the result value of String.
*
* @param context Pointer to the SQLite database context.
* @param val Result value of an SQL function.
* @see <a
* href="http://www.sqlite.org/c3ref/result_blob.html">http://www.sqlite.org/c3ref/result_blob.html</a>
*/
public abstract void result_text(long context, String val);
/**
* Sets the result of an SQL function as blob data type with the pointer to the SQLite database
* context and the the result value of byte array.
*
* @param context Pointer to the SQLite database context.
* @param val Result value of an SQL function.
* @see <a
* href="http://www.sqlite.org/c3ref/result_blob.html">http://www.sqlite.org/c3ref/result_blob.html</a>
*/
public abstract void result_blob(long context, byte[] val);
/**
* Sets the result of an SQL function as double data type with the pointer to the SQLite
* database context and the the result value of double.
*
* @param context Pointer to the SQLite database context.
* @param val Result value of an SQL function.
* @see <a
* href="http://www.sqlite.org/c3ref/result_blob.html">http://www.sqlite.org/c3ref/result_blob.html</a>
*/
public abstract void result_double(long context, double val);
/**
* Sets the result of an SQL function as long data type with the pointer to the SQLite database
* context and the the result value of long.
*
* @param context Pointer to the SQLite database context.
* @param val Result value of an SQL function.
* @see <a
* href="http://www.sqlite.org/c3ref/result_blob.html">http://www.sqlite.org/c3ref/result_blob.html</a>
*/
public abstract void result_long(long context, long val);
/**
* Sets the result of an SQL function as int data type with the pointer to the SQLite database
* context and the the result value of int.
*
* @param context Pointer to the SQLite database context.
* @param val Result value of an SQL function.
* @see <a
* href="http://www.sqlite.org/c3ref/result_blob.html">http://www.sqlite.org/c3ref/result_blob.html</a>
*/
public abstract void result_int(long context, int val);
/**
* Sets the result of an SQL function as an error with the pointer to the SQLite database
* context and the the error of String.
*
* @param context Pointer to the SQLite database context.
* @param err Error result of an SQL function.
* @see <a
* href="http://www.sqlite.org/c3ref/result_blob.html">http://www.sqlite.org/c3ref/result_blob.html</a>
*/
public abstract void result_error(long context, String err);
/**
* @param f SQLite function object.
* @param arg Pointer to the parameter of the SQLite function or aggregate.
* @return Parameter value of the given SQLite function or aggregate in text data type.
* @see <a
* href="http://www.sqlite.org/c3ref/value_blob.html">http://www.sqlite.org/c3ref/value_blob.html</a>
*/
public abstract String value_text(Function f, int arg);
/**
* @param f SQLite function object.
* @param arg Pointer to the parameter of the SQLite function or aggregate.
* @return Parameter value of the given SQLite function or aggregate in blob data type.
* @see <a
* href="http://www.sqlite.org/c3ref/value_blob.html">http://www.sqlite.org/c3ref/value_blob.html</a>
*/
public abstract byte[] value_blob(Function f, int arg);
/**
* @param f SQLite function object.
* @param arg Pointer to the parameter of the SQLite function or aggregate.
* @return Parameter value of the given SQLite function or aggregate in double data type
* @see <a
* href="http://www.sqlite.org/c3ref/value_blob.html">http://www.sqlite.org/c3ref/value_blob.html</a>
*/
public abstract double value_double(Function f, int arg);
/**
* @param f SQLite function object.
* @param arg Pointer to the parameter of the SQLite function or aggregate.
* @return Parameter value of the given SQLite function or aggregate in long data type.
* @see <a
* href="http://www.sqlite.org/c3ref/value_blob.html">http://www.sqlite.org/c3ref/value_blob.html</a>
*/
public abstract long value_long(Function f, int arg);
/**
* Accesses the parameter values on the function or aggregate in int data type with the function
* object and the parameter value.
*
* @param f SQLite function object.
* @param arg Pointer to the parameter of the SQLite function or aggregate.
* @return Parameter value of the given SQLite function or aggregate.
* @see <a
* href="http://www.sqlite.org/c3ref/value_blob.html">http://www.sqlite.org/c3ref/value_blob.html</a>
*/
public abstract int value_int(Function f, int arg);
/**
* @param f SQLite function object.
* @param arg Pointer to the parameter of the SQLite function or aggregate.
* @return Parameter datatype of the function or aggregate in int data type.
* @see <a
* href="http://www.sqlite.org/c3ref/value_blob.html">http://www.sqlite.org/c3ref/value_blob.html</a>
*/
public abstract int value_type(Function f, int arg);
/**
* Create a user defined function with given function name and the function object.
*
* @param name The function name to be created.
* @param f SQLite function object.
* @param flags Extra flags to use when creating the function, such as {@link
* Function#FLAG_DETERMINISTIC}
* @return <a href="http://www.sqlite.org/c3ref/c_abort.html">Result Codes</a>
* @see <a
* href="http://www.sqlite.org/c3ref/create_function.html">http://www.sqlite.org/c3ref/create_function.html</a>
*/
public abstract int create_function(String name, Function f, int nArgs, int flags)
throws SQLException;
/**
* De-registers a user defined function
*
* @param name Name of the function to de-registered.
* @return <a href="http://www.sqlite.org/c3ref/c_abort.html">Result Codes</a>
*/
public abstract int destroy_function(String name) throws SQLException;
/**
* Create a user defined collation with given collation name and the collation object.
*
* @param name The collation name to be created.
* @param c SQLite collation object.
* @return <a href="https://www.sqlite.org/c3ref/c_abort.html">Result Codes</a>
* @see <a
* href="https://www.sqlite.org/c3ref/create_collation.html">https://www.sqlite.org/c3ref/create_collation.html</a>
*/
public abstract int create_collation(String name, Collation c) throws SQLException;
/**
* Create a user defined collation with given collation name and the collation object.
*
* @param name The collation name to be created.
* @return <a href="https://www.sqlite.org/c3ref/c_abort.html">Result Codes</a>
*/
public abstract int destroy_collation(String name) throws SQLException;
/**
* @param dbName Database name to be backed up.
* @param destFileName Target backup file name.
* @param observer ProgressObserver object.
* @return <a href="http://www.sqlite.org/c3ref/c_abort.html">Result Codes</a>
*/
public abstract int backup(String dbName, String destFileName, ProgressObserver observer)
throws SQLException;
/**
* @param dbName Database name to be backed up.
* @param destFileName Target backup file name.
* @param observer ProgressObserver object.
* @param sleepTimeMillis time to wait during a backup/restore operation if sqlite3_backup_step
* returns SQLITE_BUSY before continuing
* @param nTimeouts the number of times sqlite3_backup_step can return SQLITE_BUSY before
* failing
* @param pagesPerStep the number of pages to copy in each sqlite3_backup_step. If this is
* negative, the entire DB is copied at once.
* @return <a href="http://www.sqlite.org/c3ref/c_abort.html">Result Codes</a>
*/
public abstract int backup(
String dbName,
String destFileName,
ProgressObserver observer,
int sleepTimeMillis,
int nTimeouts,
int pagesPerStep)
throws SQLException;
/**
* @param dbName Database name for restoring data.
* @param sourceFileName Source file name.
* @param observer ProgressObserver object.
* @return <a href="http://www.sqlite.org/c3ref/c_abort.html">Result Codes</a>
*/
public abstract int restore(String dbName, String sourceFileName, ProgressObserver observer)
throws SQLException;
/**
* @param dbName the name of the db to restore
* @param sourceFileName the filename of the source db to restore
* @param observer ProgressObserver object.
* @param sleepTimeMillis time to wait during a backup/restore operation if sqlite3_backup_step
* returns SQLITE_BUSY before continuing
* @param nTimeouts the number of times sqlite3_backup_step can return SQLITE_BUSY before
* failing
* @param pagesPerStep the number of pages to copy in each sqlite3_backup_step. If this is
* negative, the entire DB is copied at once.
* @return <a href="http://www.sqlite.org/c3ref/c_abort.html">Result Codes</a>
*/
public abstract int restore(
String dbName,
String sourceFileName,
ProgressObserver observer,
int sleepTimeMillis,
int nTimeouts,
int pagesPerStep)
throws SQLException;
/**
* @param id The id of the limit.
* @param value The new value of the limit.
* @return The prior value of the limit
* @see <a
* href="https://www.sqlite.org/c3ref/limit.html">https://www.sqlite.org/c3ref/limit.html</a>
*/
public abstract int limit(int id, int value) throws SQLException;
/** Progress handler */
public abstract void register_progress_handler(int vmCalls, ProgressHandler progressHandler) throws SQLException
;
public abstract void clear_progress_handler() throws SQLException;
/**
* Returns an array describing the attributes (not null, primary key and auto increment) of
* columns.
*
* @param stmt Pointer to the statement.
* @return Column attribute array.<br>
* index[col][0] = true if column constrained NOT NULL;<br>
* index[col][1] = true if column is part of the primary key; <br>
* index[col][2] = true if column is auto-increment.
*/
public abstract boolean[][] column_metadata(long stmt);
// COMPOUND FUNCTIONS ////////////////////////////////////////////
abstract void set_commit_listener(boolean enabled);
abstract void set_update_listener(boolean enabled);
public synchronized void addUpdateListener(SQLiteUpdateListener listener) {
if (updateListeners.add(listener) && updateListeners.size() == 1) {
set_update_listener(true);
}
}
public synchronized void addCommitListener(SQLiteCommitListener listener) {
if (commitListeners.add(listener) && commitListeners.size() == 1) {
set_commit_listener(true);
}
}
public synchronized void removeUpdateListener(SQLiteUpdateListener listener) {
if (updateListeners.remove(listener) && updateListeners.isEmpty()) {
set_update_listener(false);
}
}
public synchronized void removeCommitListener(SQLiteCommitListener listener) {
if (commitListeners.remove(listener) && commitListeners.isEmpty()) {
set_commit_listener(false);
}
}
void onUpdate(int type, String database, String table, long rowId) {
Set<SQLiteUpdateListener> listeners;
synchronized (this) {
listeners = new HashSet<>(updateListeners);
}
for (SQLiteUpdateListener listener : listeners) {
SQLiteUpdateListener.Type operationType = switch (type) {
case 18 -> SQLiteUpdateListener.Type.INSERT;
case 9 -> SQLiteUpdateListener.Type.DELETE;
case 23 -> SQLiteUpdateListener.Type.UPDATE;
default -> throw new AssertionError("Unknown type: " + type);
};
listener.onUpdate(operationType, database, table, rowId);
}
}
void onCommit(boolean commit) {
Set<SQLiteCommitListener> listeners;
synchronized (this) {
listeners = new HashSet<>(commitListeners);
}
for (SQLiteCommitListener listener : listeners) {
if (commit) {
listener.onCommit();
}
else {
listener.onRollback();
}
}
}
/**
* Throws SQLException with error message.
*/
@SuppressWarnings({"unused", "SpellCheckingInspection"})
final void throwex() throws SQLException {
throw new SQLException(errmsg());
}
@SuppressWarnings({"SpellCheckingInspection", "unused"})
public final void throwex(int errorCode) throws SQLException {
throw newSQLException(errorCode);
}
/**
* Throws SQL Exception with error code.
*
* @param errorCode Error code to be passed.
* @return SQLException with error code and message.
*/
public final SQLiteException newSQLException(int errorCode) {
return newSQLException(errorCode, errmsg(), null);
}
/**
* Throws formatted SQLException with error code and message.
*
* @param errorCode Error code to be passed.
* @param errorMessage Error message to be passed.
* @return Formatted SQLException with error code and message.
*/
public static SQLiteException newSQLException(int errorCode, String errorMessage, @Nullable String sql) {
SQLiteErrorCode code = SQLiteErrorCode.getErrorCode(errorCode);
String msg;
if (code == SQLiteErrorCode.UNKNOWN_ERROR) {
msg = code + ":" + errorCode + " (" + errorMessage + ")";
}
else {
msg = code + " (" + errorMessage + ")";
}
if (sql != null) {
msg += " (sql=" + sql + ")";
}
return new SQLiteException(msg, code);
}
public interface ProgressObserver {
void progress(int remaining, int pageCount);
}
}

View File

@@ -1,516 +0,0 @@
/*
* Copyright (c) 2007 David Crawshaw <david@zentus.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package org.jetbrains.sqlite.core;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.sqlite.BusyHandler;
import org.jetbrains.sqlite.Collation;
import org.jetbrains.sqlite.Function;
import org.jetbrains.sqlite.ProgressHandler;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.sql.SQLException;
/** This class provides a thin JNI layer over the SQLite3 C API. */
public final class NativeDB extends DB {
private static final int DEFAULT_BACKUP_BUSY_SLEEP_TIME_MILLIS = 100;
private static final int DEFAULT_BACKUP_NUM_BUSY_BEFORE_FAIL = 3;
private static final int DEFAULT_PAGES_PER_BACKUP_STEP = 100;
/** SQLite connection handle. */
private final long pointer = 0;
/** busy handler pointer to JNI global busyhandler reference. */
private final long busyHandler = 0;
// pointer to commit listener structure, if enabled.
private final long commitListener = 0;
// WRAPPER FUNCTIONS ////////////////////////////////////////////
// pointer to update listener structure, if enabled.
private final long updateListener = 0;
/** handler pointer to JNI global progressHandler reference. */
private long progressHandler;
public NativeDB() {
super();
}
/** @see DB#_open(String, int) */
@Override
protected synchronized void _open(String file, int openFlags) throws SQLException {
_open_utf8(stringToUtf8ByteArray(file), openFlags);
}
synchronized native void _open_utf8(byte[] fileUtf8, int openFlags) throws SQLException;
/** @see DB#_close() */
@Override
protected synchronized native void _close() throws SQLException;
/** @see DB#_exec(String) */
@Override
public synchronized int _exec(String sql) throws SQLException {
return _exec_utf8(stringToUtf8ByteArray(sql));
}
synchronized native int _exec_utf8(byte[] sqlUtf8) throws SQLException;
/** @see DB#shared_cache(boolean) */
@Override
public synchronized native int shared_cache(boolean enable);
/** @see DB#enable_load_extension(boolean) */
@Override
public synchronized native int enable_load_extension(boolean enable);
/** @see DB#interrupt() */
@Override
public native void interrupt();
/** @see DB#busy_timeout(int) */
@Override
public synchronized native void busy_timeout(int ms);
/** @see DB#busy_handler(BusyHandler) */
@Override
public synchronized native void busy_handler(BusyHandler busyHandler);
/** @see DB#prepare(String) */
@Override
protected synchronized SafeStatementPointer prepare(@NotNull String sql) throws SQLException {
return new SafeStatementPointer(this, prepare_utf8(stringToUtf8ByteArray(sql)));
}
// byte[] instead of string is actually more performant
public synchronized native long prepare_utf8(byte[] sqlUtf8) throws SQLException;
/** @see DB#errmsg() */
@Override
synchronized String errmsg() {
return utf8ByteBufferToString(errmsg_utf8());
}
synchronized native ByteBuffer errmsg_utf8();
/** @see DB#libversion() */
@Override
public synchronized String libversion() {
return utf8ByteBufferToString(libversion_utf8());
}
native ByteBuffer libversion_utf8();
/** @see DB#changes() */
@Override
public synchronized native long changes();
/** @see DB#total_changes() */
@Override
public synchronized native long total_changes();
/** @see DB#finalize(long) */
@Override
public synchronized native int finalize(long stmt);
/** @see DB#step(long) */
@Override
public synchronized native int step(long stmt);
@Override
public synchronized native int reset(long stmt);
/** @see DB#clear_bindings(long) */
@Override
public synchronized native int clear_bindings(long stmt);
/** @see DB#bind_parameter_count(long) */
@Override
public synchronized native int bind_parameter_count(long stmt);
/** @see DB#column_count(long) */
@Override
public synchronized native int column_count(long stmt);
/** @see DB#column_type(long, int) */
@Override
public synchronized native int column_type(long stmt, int col);
/** @see DB#column_decltype(long, int) */
@Override
public synchronized String column_decltype(long stmt, int col) {
return utf8ByteBufferToString(column_decltype_utf8(stmt, col));
}
synchronized native ByteBuffer column_decltype_utf8(long stmt, int col);
/** @see DB#column_table_name(long, int) */
@Override
public synchronized String column_table_name(long stmt, int col) {
return utf8ByteBufferToString(column_table_name_utf8(stmt, col));
}
synchronized native ByteBuffer column_table_name_utf8(long stmt, int col);
/** @see DB#column_name(long, int) */
@Override
public synchronized String column_name(long stmt, int col) {
return utf8ByteBufferToString(column_name_utf8(stmt, col));
}
synchronized native ByteBuffer column_name_utf8(long stmt, int col);
/** @see DB#column_text(long, int) */
@Override
public synchronized String column_text(long statementPointer, int zeroBasedColumnIndex) {
return utf8ByteBufferToString(column_text_utf8(statementPointer, zeroBasedColumnIndex));
}
synchronized native ByteBuffer column_text_utf8(long stmt, int col);
/** @see DB#column_blob(long, int) */
@Override
public synchronized native byte[] column_blob(long statementPointer, int zeroBasedColumnIndex);
/** @see DB#column_double(long, int) */
@Override
public synchronized native double column_double(long statementPointer, int zeroBasedColumnIndex);
/** @see DB#column_long(long, int) */
@Override
public synchronized native long column_long(long statementPointer, int zeroBasedColumnIndex);
/** @see DB#column_int(long, int) */
@Override
public synchronized native int column_int(long statementPointer, int zeroBasedColumnIndex);
/** @see DB#bind_null(long, int) */
@Override
synchronized native int bind_null(long stmt, int oneBasedColumnIndex);
/** @see DB#bind_int(long, int, int) */
@Override
public synchronized native int bind_int(long stmt, int oneBasedColumnIndex, int v);
/** @see DB#bind_long(long, int, long) */
@Override
public synchronized native int bind_long(long stmt, int oneBasedColumnIndex, long v);
/** @see DB#bind_double(long, int, double) */
@Override
synchronized native int bind_double(long stmt, int oneBasedColumnIndex, double v);
/** @see DB#bind_text(long, int, String) */
@Override
synchronized int bind_text(long stmt, int oneBasedColumnIndex, String v) {
return bind_text_utf8(stmt, oneBasedColumnIndex, stringToUtf8ByteArray(v));
}
synchronized native int bind_text_utf8(long stmt, int pos, byte[] vUtf8);
/** @see DB#bind_blob(long, int, byte[]) */
@Override
synchronized native int bind_blob(long stmt, int oneBasedColumnIndex, byte[] v);
/** @see DB#result_null(long) */
@Override
public synchronized native void result_null(long context);
/** @see DB#result_text(long, String) */
@Override
public synchronized void result_text(long context, String val) {
result_text_utf8(context, stringToUtf8ByteArray(val));
}
synchronized native void result_text_utf8(long context, byte[] valUtf8);
/** @see DB#result_blob(long, byte[]) */
@Override
public synchronized native void result_blob(long context, byte[] val);
/** @see DB#result_double(long, double) */
@Override
public synchronized native void result_double(long context, double val);
/** @see DB#result_long(long, long) */
@Override
public synchronized native void result_long(long context, long val);
/** @see DB#result_int(long, int) */
@Override
public synchronized native void result_int(long context, int val);
/** @see DB#result_error(long, String) */
@Override
public synchronized void result_error(long context, String err) {
result_error_utf8(context, stringToUtf8ByteArray(err));
}
synchronized native void result_error_utf8(long context, byte[] errUtf8);
/** @see DB#value_text(Function, int) */
@Override
public synchronized String value_text(Function f, int arg) {
return utf8ByteBufferToString(value_text_utf8(f, arg));
}
synchronized native ByteBuffer value_text_utf8(Function f, int argUtf8);
/** @see DB#value_blob(Function, int) */
@Override
public synchronized native byte[] value_blob(Function f, int arg);
/** @see DB#value_double(Function, int) */
@Override
public synchronized native double value_double(Function f, int arg);
/** @see DB#value_long(Function, int) */
@Override
public synchronized native long value_long(Function f, int arg);
/** @see DB#value_int(Function, int) */
@Override
public synchronized native int value_int(Function f, int arg);
/** @see DB#value_type(Function, int) */
@Override
public synchronized native int value_type(Function f, int arg);
/** @see DB#create_function(String, Function, int, int) */
@Override
public synchronized int create_function(String name, Function func, int nArgs, int flags)
throws SQLException {
return create_function_utf8(nameToUtf8ByteArray("function", name), func, nArgs, flags);
}
synchronized native int create_function_utf8(
byte[] nameUtf8, Function func, int nArgs, int flags);
/** @see DB#destroy_function(String) */
@Override
public synchronized int destroy_function(String name) throws SQLException {
return destroy_function_utf8(nameToUtf8ByteArray("function", name));
}
synchronized native int destroy_function_utf8(byte[] nameUtf8);
/** @see DB#create_collation(String, Collation) */
@Override
public synchronized int create_collation(String name, Collation coll) throws SQLException {
return create_collation_utf8(nameToUtf8ByteArray("collation", name), coll);
}
synchronized native int create_collation_utf8(byte[] nameUtf8, Collation coll);
/** @see DB#destroy_collation(String) */
@Override
public synchronized int destroy_collation(String name) throws SQLException {
return destroy_collation_utf8(nameToUtf8ByteArray("collation", name));
}
synchronized native int destroy_collation_utf8(byte[] nameUtf8);
@Override
public synchronized native int limit(int id, int value) throws SQLException;
private static byte[] nameToUtf8ByteArray(String nameType, String name) throws SQLException {
final byte[] nameUtf8 = stringToUtf8ByteArray(name);
if (name == null || name.isEmpty() || nameUtf8.length > 255) {
throw new SQLException("invalid " + nameType + " name: '" + name + "'");
}
return nameUtf8;
}
/**
* @see DB#backup(String, String,
* ProgressObserver)
*/
@Override
public int backup(String dbName, String destFileName, ProgressObserver observer)
throws SQLException {
return backup(
stringToUtf8ByteArray(dbName),
stringToUtf8ByteArray(destFileName),
observer,
DEFAULT_BACKUP_BUSY_SLEEP_TIME_MILLIS,
DEFAULT_BACKUP_NUM_BUSY_BEFORE_FAIL,
DEFAULT_PAGES_PER_BACKUP_STEP);
}
/**
* @see DB#backup(String, String, ProgressObserver, int, int,
* int)
*/
@Override
public int backup(
String dbName,
String destFileName,
ProgressObserver observer,
int sleepTimeMillis,
int nTimeouts,
int pagesPerStep)
throws SQLException {
return backup(
stringToUtf8ByteArray(dbName),
stringToUtf8ByteArray(destFileName),
observer,
sleepTimeMillis,
nTimeouts,
pagesPerStep);
}
synchronized native int backup(
byte[] dbNameUtf8,
byte[] destFileNameUtf8,
ProgressObserver observer,
int sleepTimeMillis,
int nTimeouts,
int pagesPerStep)
throws SQLException;
/**
* @see DB#restore(String, String,
* ProgressObserver)
*/
@Override
public synchronized int restore(String dbName, String sourceFileName, ProgressObserver observer)
throws SQLException {
return restore(
dbName,
sourceFileName,
observer,
DEFAULT_BACKUP_BUSY_SLEEP_TIME_MILLIS,
DEFAULT_BACKUP_NUM_BUSY_BEFORE_FAIL,
DEFAULT_PAGES_PER_BACKUP_STEP);
}
// COMPOUND FUNCTIONS (for optimisation) /////////////////////////
/** @see DB#restore(String, String, ProgressObserver, int, int, int) */
@Override
public synchronized int restore(
String dbName,
String sourceFileName,
ProgressObserver observer,
int sleepTimeMillis,
int nTimeouts,
int pagesPerStep)
throws SQLException {
return restore(
stringToUtf8ByteArray(dbName),
stringToUtf8ByteArray(sourceFileName),
observer,
sleepTimeMillis,
nTimeouts,
pagesPerStep);
}
synchronized native int restore(
byte[] dbNameUtf8,
byte[] sourceFileName,
ProgressObserver observer,
int sleepTimeMillis,
int nTimeouts,
int pagesPerStep)
throws SQLException;
/**
* Provides metadata for table columns.
*
* @return For each column returns: <br>
* res[col][0] = true if column constrained NOT NULL<br>
* res[col][1] = true if column is part of the primary key<br>
* res[col][2] = true if column is auto-increment.
* @see DB#column_metadata(long)
*/
@Override
public synchronized native boolean[][] column_metadata(long stmt);
@Override
synchronized native void set_commit_listener(boolean enabled);
@Override
synchronized native void set_update_listener(boolean enabled);
@Override
public synchronized native void register_progress_handler(
int vmCalls, ProgressHandler progressHandler) throws SQLException;
@Override
public synchronized native void clear_progress_handler() throws SQLException;
/**
* Getter for native pointer to validate memory is properly cleaned up in unit tests
*
* @return a native pointer to validate memory is properly cleaned up in unit tests
*/
long getBusyHandler() {
return busyHandler;
}
/**
* Getter for native pointer to validate memory is properly cleaned up in unit tests
*
* @return a native pointer to validate memory is properly cleaned up in unit tests
*/
long getCommitListener() {
return commitListener;
}
/**
* Getter for native pointer to validate memory is properly cleaned up in unit tests
*
* @return a native pointer to validate memory is properly cleaned up in unit tests
*/
long getUpdateListener() {
return updateListener;
}
/**
* Getter for native pointer to validate memory is properly cleaned up in unit tests
*
* @return a native pointer to validate memory is properly cleaned up in unit tests
*/
long getProgressHandler() {
return progressHandler;
}
/**
* Throws an SQLException. Called from native code
*
* @param msg Message for the SQLException.
* @throws SQLException the generated SQLException
*/
@SuppressWarnings("unused")
static void throwex(String msg) throws SQLException {
throw new SQLException(msg);
}
static byte[] stringToUtf8ByteArray(String str) {
return str.getBytes(StandardCharsets.UTF_8);
}
static String utf8ByteBufferToString(ByteBuffer buffer) {
if (buffer == null) {
return null;
}
byte[] buff = new byte[buffer.remaining()];
buffer.get(buff);
return new String(buff, StandardCharsets.UTF_8);
}
}

View File

@@ -7,7 +7,6 @@ import com.intellij.openapi.util.io.NioFiles
import com.intellij.util.ResourceUtil
import com.intellij.util.io.DigestUtil
import com.intellij.util.system.CpuArch
import org.jetbrains.sqlite.core.Codes
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardCopyOption
@@ -15,7 +14,7 @@ import java.nio.file.StandardCopyOption
private var extracted = false
// The version of the SQLite JDBC driver.
private const val VERSION: String = "3.40.0.0"
private const val VERSION: String = "3.40.0.1-2"
/**
* Loads the SQLite interface backend.
@@ -32,20 +31,11 @@ internal fun loadNativeDb() {
extracted = true
}
/**
* Loads SQLite native library using given a path and name of the library.
*/
private fun loadSqliteNativeLibrary() {
@Suppress("SpellCheckingInspection")
var nativeLibraryName = System.mapLibraryName("sqlitejdbc")?.replace(".dylib", ".jnilib")!!
val relativeDirName = "${osNameToDirName()}/${if (CpuArch.isArm64()) "aarch64" else "x86_64"}"
val libPath = try {
PathManager.getLibPath()
}
catch (ignore: RuntimeException) {
// unit test or benchmark - no home path
null
}
val nativeLibraryName = System.mapLibraryName("sqliteij")?.replace(".dylib", ".jnilib")!!
val relativeDirName = "${osNameToDirName()}-${if (CpuArch.isArm64()) "aarch64" else "x86_64"}"
val libPath = getLibPath()
if (libPath != null) {
val nativeLibFile = Path.of(libPath, "native", relativeDirName, nativeLibraryName).toAbsolutePath().normalize()
if (Files.exists(nativeLibFile)) {
@@ -55,19 +45,9 @@ private fun loadSqliteNativeLibrary() {
}
// load the os-dependent library from the jar file
val nativeLibraryPath = "sqlite-native/$relativeDirName"
val classLoader = Codes::class.java.classLoader
var hasNativeLib = classLoader.getResource("$nativeLibraryPath/$nativeLibraryName") != null
if (!hasNativeLib && SystemInfoRt.isMac) {
// fix for openjdk7 for Mac
@Suppress("SpellCheckingInspection")
val altName = "libsqlitejdbc.jnilib"
if (classLoader.getResource("$nativeLibraryPath/$altName") != null) {
nativeLibraryName = altName
hasNativeLib = true
}
}
val nativeLibraryPath = "sqlite/$relativeDirName"
val classLoader = SqliteCodes::class.java.classLoader
val hasNativeLib = classLoader.getResource("$nativeLibraryPath/$nativeLibraryName") != null
if (hasNativeLib) {
// try extracting the library from jar
val tempDir = if (libPath == null) {
@@ -85,12 +65,27 @@ private fun loadSqliteNativeLibrary() {
}
}
private fun getLibPath(): String? {
if (System.getProperty("sqlite.use.path.manager") == "false") {
return null
}
val libPath = try {
PathManager.getLibPath()
}
catch (ignore: RuntimeException) {
// unit test or benchmark - no home path
null
}
return libPath
}
/**
* Extracts and loads the specified library file to the target folder
*/
private fun extractAndLoadLibraryFile(libFolderForCurrentOS: String, libraryFileName: String, tempDir: Path) {
val nativeLibraryFilePath = "$libFolderForCurrentOS/$libraryFileName"
val classLoader = Codes::class.java.classLoader
val classLoader = SqliteCodes::class.java.classLoader
val expectedHash = ResourceUtil.getResourceAsBytes("$nativeLibraryFilePath.sha256", classLoader)!!.decodeToString()

View File

@@ -0,0 +1,13 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.sqlite
object SqlTestMain {
@JvmStatic
fun main(args: Array<String>) {
System.setProperty("sqlite.use.path.manager", "false")
SqliteConnection(file = null).use {
testInsert(SqliteConnection(file = null))
println("succeed")
}
}
}

View File

@@ -4,7 +4,6 @@
package org.jetbrains.sqlite
import org.assertj.core.api.Assertions.assertThat
import org.jetbrains.sqlite.core.SqliteConnection
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
@@ -24,32 +23,7 @@ class SqliteTest {
@Test
fun insert() {
connection.execute("""
create table log (
commitId integer primary key,
message text not null,
authorTime integer not null,
commitTime integer not null,
committerId integer null
) strict
""")
connection.prepareStatement("""
insert into log(commitId, message, authorTime, commitTime, committerId)
values(?, ?, ?, ?, ?)
on conflict(commitId) do update set message=excluded.message
""", ObjectBinder(5)).use { statement ->
statement.binder.bind(12, "test", 2, 2, 1)
statement.binder.addBatch()
statement.executeBatch()
}
connection.prepareStatement("select message from log where commitId = ?", IntBinder(paramCount = 1)).use { statement ->
statement.binder.bind(12)
val resultSet = statement.executeQuery()
assertThat(resultSet.next()).isTrue()
assertThat(resultSet.getString(0)).isEqualTo("test")
}
testInsert(connection)
}
@Test
@@ -126,4 +100,33 @@ class SqliteTest {
}
}
}
}
}
internal fun testInsert(connection: SqliteConnection) {
connection.execute("""
create table log (
commitId integer primary key,
message text not null,
authorTime integer not null,
commitTime integer not null,
committerId integer null
) strict
""")
connection.prepareStatement("""
insert into log(commitId, message, authorTime, commitTime, committerId)
values(?, ?, ?, ?, ?)
on conflict(commitId) do update set message=excluded.message
""", ObjectBinder(5)).use { statement ->
statement.binder.bind(12, "test", 2, 2, 1)
statement.binder.addBatch()
statement.executeBatch()
}
connection.prepareStatement("select message from log where commitId = ?", IntBinder(paramCount = 1)).use { statement ->
statement.binder.bind(12)
val resultSet = statement.executeQuery()
assertThat(resultSet.next()).isTrue()
assertThat(resultSet.getString(0)).isEqualTo("test")
}
}

View File

@@ -21,12 +21,7 @@ import it.unimi.dsi.fastutil.ints.IntArrayList
import it.unimi.dsi.fastutil.ints.IntSet
import kotlinx.coroutines.*
import org.intellij.lang.annotations.Language
import org.jetbrains.sqlite.EmptyBinder
import org.jetbrains.sqlite.IntBinder
import org.jetbrains.sqlite.ObjectBinder
import org.jetbrains.sqlite.StatementCollection
import org.jetbrains.sqlite.core.SqliteConnection
import org.jetbrains.sqlite.core.SqlitePreparedStatement
import org.jetbrains.sqlite.*
import java.nio.file.Files
import java.util.*
import java.util.function.IntConsumer