[Git][java-team/xerial-sqlite-jdbc][upstream] New upstream version 3.46.1.3+dfsg

Pierre Gruet (@pgt) gitlab at salsa.debian.org
Wed Oct 9 08:29:06 BST 2024



Pierre Gruet pushed to branch upstream at Debian Java Maintainers / xerial-sqlite-jdbc


Commits:
a19678a2 by Pierre Gruet at 2024-10-08T22:57:40+02:00
New upstream version 3.46.1.3+dfsg
- - - - -


29 changed files:

- Makefile
- Makefile.common
- README.adoc
- USAGE.md
- VERSION
- demo/Sample.java
- + docker/dockcross-riscv64
- pom.xml
- src/main/java/org/sqlite/JDBC.java
- src/main/java/org/sqlite/SQLiteConfig.java
- src/main/java/org/sqlite/SQLiteConnectionConfig.java
- src/main/java/org/sqlite/SQLiteDataSource.java
- src/main/java/org/sqlite/SQLiteJDBCLoader.java
- src/main/java/org/sqlite/core/CoreStatement.java
- src/main/java/org/sqlite/core/NativeDB.java
- src/main/java/org/sqlite/jdbc3/JDBC3DatabaseMetaData.java
- src/main/java/org/sqlite/jdbc3/JDBC3Statement.java
- + src/main/java/org/sqlite/util/Logger.java
- + src/main/java/org/sqlite/util/LoggerFactory.java
- src/main/java/org/sqlite/util/OSInfo.java
- src/main/java9/org/sqlite/nativeimage/SqliteJdbcFeature.java
- src/test/java/org/sqlite/DBMetaDataTest.java
- src/test/java/org/sqlite/MultipleClassLoaderTest.java
- src/test/java/org/sqlite/PrepStmtTest.java
- src/test/java/org/sqlite/SQLiteConfigTest.java
- src/test/java/org/sqlite/SQLiteDataSourceTest.java
- src/test/java/org/sqlite/StatementTest.java
- src/test/java/org/sqlite/architecture/CodingRulesTest.java
- src/test/java/org/sqlite/util/OSInfoTest.java


Changes:

=====================================
Makefile
=====================================
@@ -121,7 +121,7 @@ NATIVE_TARGET_DIR:=$(TARGET)/classes/org/sqlite/native/$(OS_NAME)/$(OS_ARCH)
 NATIVE_DLL:=$(NATIVE_DIR)/$(LIBNAME)
 
 # For cross-compilation, install docker. See also https://github.com/dockcross/dockcross
-native-all: native win32 win64 win-armv7 win-arm64 mac64-signed mac-arm64-signed linux32 linux64 freebsd32 freebsd64 freebsd-arm64 linux-arm linux-armv6 linux-armv7 linux-arm64 linux-android-arm linux-android-arm64 linux-android-x86 linux-android-x64 linux-ppc64 linux-musl32 linux-musl64 linux-musl-arm64
+native-all: native win32 win64 win-armv7 win-arm64 mac64-signed mac-arm64-signed linux32 linux64 freebsd32 freebsd64 freebsd-arm64 linux-arm linux-armv6 linux-armv7 linux-arm64 linux-android-arm linux-android-arm64 linux-android-x86 linux-android-x64 linux-ppc64 linux-musl32 linux-musl64 linux-musl-arm64 linux-riscv64
 
 native: $(NATIVE_DLL)
 
@@ -194,6 +194,9 @@ linux-android-x64: $(SQLITE_UNPACKED) jni-header
 linux-ppc64: $(SQLITE_UNPACKED) jni-header
 	./docker/dockcross-ppc64 -a $(DOCKER_RUN_OPTS) bash -c 'make clean-native native CROSS_PREFIX=powerpc64le-unknown-linux-gnu- OS_NAME=Linux OS_ARCH=ppc64'
 
+linux-riscv64: $(SQLITE_UNPACKED) jni-header
+	./docker/dockcross-riscv64 -a $(DOCKER_RUN_OPTS) bash -c 'make clean-native native CROSS_PREFIX=riscv64-unknown-linux-gnu- OS_NAME=Linux OS_ARCH=riscv64'
+
 mac64: $(SQLITE_UNPACKED) jni-header
 	docker run $(DOCKER_RUN_OPTS) -v $$PWD:/workdir -e CROSS_TRIPLE=x86_64-apple-darwin multiarch/crossbuild make clean-native native OS_NAME=Mac OS_ARCH=x86_64
 


=====================================
Makefile.common
=====================================
@@ -52,7 +52,7 @@ endif
 
 # os=Default is meant to be generic unix/linux
 
-known_targets := Linux-x86 Linux-x86_64 Linux-arm Linux-armv6 Linux-armv7 Linux-Android-arm Linux-Android-aarch64 Linux-Android-x86 Linux-Android-x86_64 Linux-ppc64 Mac-x86 Mac-x86_64 Mac-aarch64 DragonFly-x86_64 FreeBSD-x86 FreeBSD-x86_64 FreeBSD-aarch64 OpenBSD-x86_64 Windows-x86 Windows-x86_64 Windows-armv7 Windows-aarch64 SunOS-sparcv9 HPUX-ia64_32
+known_targets := Linux-x86 Linux-x86_64 Linux-arm Linux-armv6 Linux-armv7 Linux-Android-arm Linux-Android-aarch64 Linux-Android-x86 Linux-Android-x86_64 Linux-ppc64 Linux-riscv64 Mac-x86 Mac-x86_64 Mac-aarch64 DragonFly-x86_64 FreeBSD-x86 FreeBSD-x86_64 FreeBSD-aarch64 OpenBSD-x86_64 Windows-x86 Windows-x86_64 Windows-armv7 Windows-aarch64 SunOS-sparcv9 HPUX-ia64_32
 target := $(OS_NAME)-$(OS_ARCH)
 
 ifeq (,$(findstring $(strip $(target)),$(known_targets)))
@@ -141,6 +141,13 @@ Linux-ppc64_LINKFLAGS := $(Default_LINKFLAGS)
 Linux-ppc64_LIBNAME   := libsqlitejdbc.so
 Linux-ppc64_SQLITE_FLAGS  :=
 
+Linux-riscv64_CC        := $(CROSS_PREFIX)gcc
+Linux-riscv64_STRIP     := $(CROSS_PREFIX)strip
+Linux-riscv64_CCFLAGS   := -I$(JAVA_HOME)/include -Ilib/inc_linux -Os -fPIC -fvisibility=hidden
+Linux-riscv64_LINKFLAGS := $(Default_LINKFLAGS)
+Linux-riscv64_LIBNAME   := libsqlitejdbc.so
+Linux-riscv64_SQLITE_FLAGS  :=
+
 DragonFly-x86_64_CC        := $(CROSS_PREFIX)cc
 DragonFly-x86_64_STRIP     := $(CROSS_PREFIX)strip
 DragonFly-x86_64_CCFLAGS   := -I$(JAVA_HOME)/include -Ilib/inc_linux -O2 -fPIC -fvisibility=hidden


=====================================
README.adoc
=====================================
@@ -1,5 +1,5 @@
 = SQLite JDBC Driver
-:project-version: 3.45.2.0
+:project-version: 3.46.1.3
 
 image:https://img.shields.io/github/actions/workflow/status/xerial/sqlite-jdbc/ci.yml?branch=master[GitHub Workflow Status (branch),link=https://github.com/xerial/sqlite-jdbc/actions/workflows/ci.yml?query=branch%3Amaster]
 image:https://badges.gitter.im/xerial/sqlite-jdbc.svg[Join the chat,link=https://gitter.im/xerial/sqlite-jdbc?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge]
@@ -29,19 +29,18 @@ SQLite JDBC is a library for accessing SQLite databases through the JDBC API. Fo
 
 . <<Download,Download>> `sqlite-jdbc-{project-version}.jar`
 then append this jar file into your classpath.
-. https://search.maven.org/remotecontent?filepath=org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar[Download] `slf4j-api-1.7.36.jar` then append this jar file into your classpath.
 . Open a SQLite database connection from your code. (see the example below)
 
 === Example usage
 
-Assuming `sqlite-jdbc-{project-version}.jar` and `slf4j-api-1.7.36.jar` are placed in the current directory.
+Assuming `sqlite-jdbc-{project-version}.jar` is placed in the current directory.
 
 [source,shell,subs="attributes+"]
 ----
 > javac Sample.java
-> java -classpath ".;sqlite-jdbc-{project-version}.jar;slf4j-api-1.7.36.jar" Sample   # in Windows
+> java -classpath ".;sqlite-jdbc-{project-version}.jar" Sample   # in Windows
 or
-> java -classpath ".:sqlite-jdbc-{project-version}.jar:slf4j-api-1.7.36.jar" Sample   # in macOS or Linux
+> java -classpath ".:sqlite-jdbc-{project-version}.jar" Sample   # in macOS or Linux
 name = leo
 id = 1
 name = yui
@@ -62,7 +61,7 @@ id = 2
     {
       public static void main(String[] args)
       {
-        // NOTE: Connection and Statement are AutoClosable.
+        // NOTE: Connection and Statement are AutoCloseable.
         //       Don't forget to close them both in order to avoid leaks.
         try
         (
@@ -110,14 +109,14 @@ Since sqlite-jdbc-3.6.19, the natively compiled SQLite engines will be used for
 the following operating systems:
 
 |===
-| |x86 |x86_64 |armv5 |armv6 |armv7 |arm64 |ppc64 
-
-|Windows |✔ |✔ | | |✔ |✔ | 
-|macOS | |✔ | | | |✔ | 
-|Linux (libc) |✔ |✔ |✔ |✔ |✔ |✔ |✔ 
-|Linux (musl) |✔ |✔ | | | |✔ | 
-|Android |✔ |✔ |✔ | | |✔ | 
-|FreeBSD |✔ |✔ | | | |✔ | 
+| |x86 |x86_64 |armv5 |armv6 |armv7 |arm64 |ppc64 | riscv64
+
+|Windows |✔ |✔ | | |✔ |✔ | |
+|macOS | |✔ | | | |✔ | |
+|Linux (libc) |✔ |✔ |✔ |✔ |✔ |✔ |✔ |✔ 
+|Linux (musl) |✔ |✔ | | | |✔ | |
+|Android |✔ |✔ |✔ | | |✔ | |
+|FreeBSD |✔ |✔ | | | |✔ | |
 |===
 
 In the other OSs not listed above, the pure-java SQLite is used. (Applies to versions before 3.7.15)


=====================================
USAGE.md
=====================================
@@ -11,14 +11,14 @@ Opening a UNIX (Linux, maxOS, etc.) file `/home/leo/work/mydatabase.db`
 try (Connection connection = DriverManager.getConnection("jdbc:sqlite:/home/leo/work/mydatabase.db")) { /*...*/ }
 ```
 
-## How to Use Memory Databases
-SQLite supports on-memory database management, which does not create any database files. To use a memory database in your Java code, get the database connection as follows:
+## How to Use Memory or Temporary Databases
+SQLite supports in-memory databases, which do not create any database files. To use a memory database in your Java code, get the database connection as follows:
 
 ```java
 try (Connection connection = DriverManager.getConnection("jdbc:sqlite::memory:")) { /*...*/ }
 ```
 
-And also, you can create memory database as follows:
+You can create temporary database as follows:
 ```java
 try (Connection connection = DriverManager.getConnection("jdbc:sqlite:")) { /*...*/ }
 ```
@@ -139,6 +139,22 @@ You set the mode at the connection string level:
 try (Connection connection = DriverManager.getConnection("jdbc:sqlite:db.sqlite?hexkey_mode=sse", "", "AE...")) { /*...*/ }
 ```
 
+## Generated keys
+
+SQLite has limited support to retrieve generated keys, using [last_insert_rowid](https://www.sqlite.org/c3ref/last_insert_rowid.html), with the following limitations:
+- a single ID can be retrieved, even if multiple rows were added or updated
+- it needs to be called right after the statement
+
+By default the driver will eagerly retrieve the generated keys after each statement, which may impact performances.
+
+You can disable the retrieval of generated keys in 3 ways:
+- via `SQLiteDataSource#setGetGeneratedKeys(false)`
+- via `SQLiteConnectionConfig#setGetGeneratedKeys(false)`:
+- using the pragma `jdbc.get_generated_keys`:
+```java
+try (Connection connection = DriverManager.getConnection("jdbc:sqlite::memory:?jdbc.get_generated_keys=false")) { /*...*/ }
+```
+
 ## Explicit read only transactions (use with Hibernate)
 
 In order for the driver to be compliant with Hibernate, it needs to allow setting the read only flag after a connection has been created.


=====================================
VERSION
=====================================
@@ -1 +1 @@
-version=3.45.2
+version=3.46.1


=====================================
demo/Sample.java
=====================================
@@ -8,7 +8,7 @@
     {
       public static void main(String[] args) 
       {
-        // NOTE: Connection and Statement are AutoClosable.
+        // NOTE: Connection and Statement are AutoCloseable.
         //       Don't forget to close them both in order to avoid leaks.
         try
         (


=====================================
docker/dockcross-riscv64
=====================================
@@ -0,0 +1,278 @@
+#!/usr/bin/env bash
+
+DEFAULT_DOCKCROSS_IMAGE=dockcross/linux-riscv64:latest
+
+#------------------------------------------------------------------------------
+# Helpers
+#
+err() {
+    echo -e >&2 "ERROR: $*\n"
+}
+
+die() {
+    err "$*"
+    exit 1
+}
+
+has() {
+    # eg. has command update
+    local kind=$1
+    local name=$2
+
+    type -t $kind:$name | grep -q function
+}
+
+# If OCI_EXE is not already set, search for a container executor (OCI stands for "Open Container Initiative")
+if [ -z "$OCI_EXE" ]; then
+    if which podman >/dev/null 2>/dev/null; then
+        OCI_EXE=podman
+    elif which docker >/dev/null 2>/dev/null; then
+        OCI_EXE=docker
+    else
+        die "Cannot find a container executor. Search for docker and podman."
+    fi
+fi
+
+#------------------------------------------------------------------------------
+# Command handlers
+#
+command:update-image() {
+    $OCI_EXE pull $FINAL_IMAGE
+}
+
+help:update-image() {
+    echo "Pull the latest $FINAL_IMAGE ."
+}
+
+command:update-script() {
+    if cmp -s <( $OCI_EXE run --rm $FINAL_IMAGE ) $0; then
+        echo "$0 is up to date"
+    else
+        echo -n "Updating $0 ... "
+        $OCI_EXE run --rm $FINAL_IMAGE > $0 && echo ok
+    fi
+}
+
+help:update-script() {
+    echo "Update $0 from $FINAL_IMAGE ."
+}
+
+command:update() {
+    command:update-image
+    command:update-script
+}
+
+help:update() {
+    echo "Pull the latest $FINAL_IMAGE, and then update $0 from that."
+}
+
+command:help() {
+    if [[ $# != 0 ]]; then
+        if ! has command $1; then
+            err \"$1\" is not an dockcross command
+            command:help
+        elif ! has help $1; then
+            err No help found for \"$1\"
+        else
+            help:$1
+        fi
+    else
+        cat >&2 <<ENDHELP
+Usage: dockcross [options] [--] command [args]
+
+By default, run the given *command* in an dockcross Docker container.
+
+The *options* can be one of:
+
+    --args|-a           Extra args to the *docker run* command
+    --image|-i          Docker cross-compiler image to use
+    --config|-c         Bash script to source before running this script
+
+
+Additionally, there are special update commands:
+
+    update-image
+    update-script
+    update
+
+For update command help use: $0 help <command>
+ENDHELP
+        exit 1
+    fi
+}
+
+#------------------------------------------------------------------------------
+# Option processing
+#
+special_update_command=''
+while [[ $# != 0 ]]; do
+    case $1 in
+
+        --)
+            shift
+            break
+            ;;
+
+        --args|-a)
+            ARG_ARGS="$2"
+            shift 2
+            ;;
+
+        --config|-c)
+            ARG_CONFIG="$2"
+            shift 2
+            ;;
+
+        --image|-i)
+            ARG_IMAGE="$2"
+            shift 2
+            ;;
+        update|update-image|update-script)
+            special_update_command=$1
+            break
+            ;;
+        -*)
+            err Unknown option \"$1\"
+            command:help
+            exit
+            ;;
+
+        *)
+            break
+            ;;
+
+    esac
+done
+
+# The precedence for options is:
+# 1. command-line arguments
+# 2. environment variables
+# 3. defaults
+
+# Source the config file if it exists
+DEFAULT_DOCKCROSS_CONFIG=~/.dockcross
+FINAL_CONFIG=${ARG_CONFIG-${DOCKCROSS_CONFIG-$DEFAULT_DOCKCROSS_CONFIG}}
+
+[[ -f "$FINAL_CONFIG" ]] && source "$FINAL_CONFIG"
+
+# Set the docker image
+FINAL_IMAGE=${ARG_IMAGE-${DOCKCROSS_IMAGE-$DEFAULT_DOCKCROSS_IMAGE}}
+
+# Handle special update command
+if [ "$special_update_command" != "" ]; then
+    case $special_update_command in
+
+        update)
+            command:update
+            exit $?
+            ;;
+
+        update-image)
+            command:update-image
+            exit $?
+            ;;
+
+        update-script)
+            command:update-script
+            exit $?
+            ;;
+
+    esac
+fi
+
+# Set the docker run extra args (if any)
+FINAL_ARGS=${ARG_ARGS-${DOCKCROSS_ARGS}}
+
+# Bash on Ubuntu on Windows
+UBUNTU_ON_WINDOWS=$([ -e /proc/version ] && grep -l Microsoft /proc/version || echo "")
+# MSYS, Git Bash, etc.
+MSYS=$([ -e /proc/version ] && grep -l MINGW /proc/version || echo "")
+# CYGWIN
+CYGWIN=$([ -e /proc/version ] && grep -l CYGWIN /proc/version || echo "")
+
+if [ -z "$UBUNTU_ON_WINDOWS" -a -z "$MSYS" -a "$OCI_EXE" != "podman" ]; then
+    USER_IDS=(-e BUILDER_UID="$( id -u )" -e BUILDER_GID="$( id -g )" -e BUILDER_USER="$( id -un )" -e BUILDER_GROUP="$( id -gn )")
+fi
+
+# Change the PWD when working in Docker on Windows
+if [ -n "$UBUNTU_ON_WINDOWS" ]; then
+    WSL_ROOT="/mnt/"
+    CFG_FILE=/etc/wsl.conf
+	if [ -f "$CFG_FILE" ]; then
+		CFG_CONTENT=$(cat $CFG_FILE | sed -r '/[^=]+=[^=]+/!d' | sed -r 's/\s+=\s/=/g')
+		eval "$CFG_CONTENT"
+		if [ -n "$root" ]; then
+			WSL_ROOT=$root
+		fi
+	fi
+    HOST_PWD=`pwd -P`
+    HOST_PWD=${HOST_PWD/$WSL_ROOT//}
+elif [ -n "$MSYS" ]; then
+    HOST_PWD=$PWD
+    HOST_PWD=${HOST_PWD/\//}
+    HOST_PWD=${HOST_PWD/\//:\/}
+elif [ -n "$CYGWIN" ]; then
+    for f in pwd readlink cygpath ; do
+        test -n "$(type "${f}" )" || { echo >&2 "Missing functionality (${f}) (in cygwin)." ; exit 1 ; } ;
+    done ;
+    HOST_PWD="$( cygpath -w "$( readlink -f "$( pwd ;)" ; )" ; )" ;
+else
+    HOST_PWD=$PWD
+    [ -L $HOST_PWD ] && HOST_PWD=$(readlink $HOST_PWD)
+fi
+
+# Mount Additional Volumes
+if [ -z "$SSH_DIR" ]; then
+    SSH_DIR="$HOME/.ssh"
+fi
+
+HOST_VOLUMES=
+if [ -e "$SSH_DIR" -a -z "$MSYS" ]; then
+    if test -n "${CYGWIN}" ; then
+      HOST_VOLUMES+="-v $(cygpath -w ${SSH_DIR} ; ):/home/$(id -un)/.ssh" ;
+    else
+      HOST_VOLUMES+="-v $SSH_DIR:/home/$(id -un)/.ssh" ;
+    fi ;
+fi
+
+#------------------------------------------------------------------------------
+# Now, finally, run the command in a container
+#
+TTY_ARGS=
+tty -s && [ -z "$MSYS" ] && TTY_ARGS=-ti
+CONTAINER_NAME=dockcross_$RANDOM
+$OCI_EXE run $TTY_ARGS --name $CONTAINER_NAME \
+    -v "$HOST_PWD":/work \
+    $HOST_VOLUMES \
+    "${USER_IDS[@]}" \
+    $FINAL_ARGS \
+    $FINAL_IMAGE "$@"
+run_exit_code=$?
+
+# Attempt to delete container
+rm_output=$($OCI_EXE rm -f $CONTAINER_NAME 2>&1)
+rm_exit_code=$?
+if [[ $rm_exit_code != 0 ]]; then
+  if [[ "$CIRCLECI" == "true" ]] && [[ $rm_output == *"Driver btrfs failed to remove"* ]]; then
+    : # Ignore error because of https://circleci.com/docs/docker-btrfs-error/
+  else
+    echo "$rm_output"
+    exit $rm_exit_code
+  fi
+fi
+
+exit $run_exit_code
+
+################################################################################
+#
+# This image is not intended to be run manually.
+#
+# To create a dockcross helper script for the
+# dockcross/linux-riscv64:latest image, run:
+#
+# docker run --rm dockcross/linux-riscv64:latest > dockcross-linux-riscv64-latest
+# chmod +x dockcross-linux-riscv64-latest
+#
+# You may then wish to move the dockcross script to your PATH.
+#
+################################################################################


=====================================
pom.xml
=====================================
@@ -4,16 +4,17 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.xerial</groupId>
     <artifactId>sqlite-jdbc</artifactId>
-    <version>3.45.2.0</version>
+    <version>3.46.1.3</version>
     <name>SQLite JDBC</name>
     <description>SQLite JDBC library</description>
     <url>https://github.com/xerial/sqlite-jdbc</url>
 
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-        <junit.version>5.10.2</junit.version>
-        <surefire.version>3.2.5</surefire.version>
-        <graalvm.version>23.1.2</graalvm.version>
+        <junit.version>5.11.0</junit.version>
+        <surefire.version>3.5.0</surefire.version>
+        <archunit.version>1.3.0</archunit.version>
+        <graalvm.version>24.1.0</graalvm.version>
         <java9.sourceDirectory>${project.basedir}/src/main/java9</java9.sourceDirectory>
     </properties>
 
@@ -94,13 +95,13 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-help-plugin</artifactId>
-                <version>3.4.0</version>
+                <version>3.5.0</version>
             </plugin>
 
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
-                <version>3.12.1</version>
+                <version>3.13.0</version>
                 <configuration>
                     <release>8</release>
                 </configuration>
@@ -136,7 +137,7 @@
 
             <plugin>
                 <artifactId>maven-jar-plugin</artifactId>
-                <version>3.3.0</version>
+                <version>3.4.2</version>
                 <configuration>
                     <!-- Pick the MANIFEST generated by the bundle plugin -->
                     <archive>
@@ -186,7 +187,7 @@
             <plugin>
                 <groupId>org.sonatype.plugins</groupId>
                 <artifactId>nexus-staging-maven-plugin</artifactId>
-                <version>1.6.13</version>
+                <version>1.7.0</version>
                 <extensions>true</extensions>
                 <configuration>
                     <serverId>ossrh</serverId>
@@ -198,7 +199,7 @@
             <plugin>
                 <groupId>org.jreleaser</groupId>
                 <artifactId>jreleaser-maven-plugin</artifactId>
-                <version>1.11.0</version>
+                <version>1.14.0</version>
                 <configuration>
                     <configFile>jreleaser.yml</configFile>
                 </configuration>
@@ -207,13 +208,13 @@
             <plugin>
                 <groupId>org.codehaus.mojo</groupId>
                 <artifactId>versions-maven-plugin</artifactId>
-                <version>2.16.2</version>
+                <version>2.17.1</version>
             </plugin>
 
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-enforcer-plugin</artifactId>
-                <version>3.4.1</version>
+                <version>3.5.0</version>
                 <executions>
                     <execution>
                         <id>enforce-maven</id>
@@ -284,7 +285,7 @@
                     <plugin>
                         <groupId>org.apache.maven.plugins</groupId>
                         <artifactId>maven-gpg-plugin</artifactId>
-                        <version>3.2.0</version>
+                        <version>3.2.6</version>
                         <executions>
                             <execution>
                                 <id>sign-artifacts</id>
@@ -298,7 +299,7 @@
                     <plugin>
                         <groupId>org.apache.maven.plugins</groupId>
                         <artifactId>maven-javadoc-plugin</artifactId>
-                        <version>3.6.3</version>
+                        <version>3.10.0</version>
                         <configuration>
                             <sourcepath>src/main/java</sourcepath>
                             <additionalOptions>-Xdoclint:none</additionalOptions>
@@ -316,7 +317,7 @@
                     <plugin>
                         <groupId>org.apache.maven.plugins</groupId>
                         <artifactId>maven-source-plugin</artifactId>
-                        <version>3.3.0</version>
+                        <version>3.3.1</version>
                         <executions>
                             <execution>
                                 <id>attach-sources</id>
@@ -337,7 +338,7 @@
                     <plugin>
                         <groupId>org.graalvm.buildtools</groupId>
                         <artifactId>native-maven-plugin</artifactId>
-                        <version>0.10.1</version>
+                        <version>0.10.3</version>
                         <extensions>true</extensions>
                         <executions>
                             <execution>
@@ -352,13 +353,8 @@
                             <fallback>false</fallback>
                             <verbose>true</verbose>
                             <buildArgs>
-                                <!--
-                                ArchUnit tests don't run in native-image tests.
-                                Remove the ArchUnit JUnit Engine from the ServiceLoader.
-                                -->
-                                <buildArg>
-                                    -H:ServiceLoaderFeatureExcludeServiceProviders=com.tngtech.archunit.junit.internal.ArchUnitTestEngine
-                                </buildArg>
+                                <!-- required to allow junit-pioneer to compile with strict image heap enabled -->
+                                <arg>--initialize-at-build-time=org.junitpioneer.jupiter.issue.IssueExtensionExecutionListener</arg>
                             </buildArgs>
                         </configuration>
                     </plugin>
@@ -371,13 +367,30 @@
                             <excludes>
                                 <!--  Cannot run in native mode, classes under test cannot be found, class path is empty  -->
                                 <exclude>**/MultipleClassLoaderTest.java</exclude>
-                                <!--  Not needed  -->
-                                <exclude>**/architecture/*.java</exclude>
                             </excludes>
                         </configuration>
                     </plugin>
                 </plugins>
             </build>
+
+            <dependencies>
+                <dependency>
+                    <groupId>com.tngtech.archunit</groupId>
+                    <artifactId>archunit-junit5</artifactId>
+                    <version>${archunit.version}</version>
+                    <scope>test</scope>
+                    <exclusions>
+                        <!--
+                        ArchUnit tests don't run in native-image tests.
+                        Remove the ArchUnit JUnit Engine entirely from the dependency graph thus from the ServiceLoader.
+                        -->
+                        <exclusion>
+                            <groupId>com.tngtech.archunit</groupId>
+                            <artifactId>archunit-junit5-engine</artifactId>
+                        </exclusion>
+                    </exclusions>
+                </dependency>
+            </dependencies>
         </profile>
         <profile>
             <id>native-exported</id>
@@ -402,6 +415,7 @@
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
             <version>1.7.36</version>
+            <optional>true</optional>
         </dependency>
         <!--
         This dependency makes compilation on non-GraalVM versions possible.
@@ -423,7 +437,7 @@
         <dependency>
             <groupId>org.assertj</groupId>
             <artifactId>assertj-core</artifactId>
-            <version>3.25.3</version>
+            <version>3.26.3</version>
             <scope>test</scope>
             <exclusions>
                 <exclusion>
@@ -445,13 +459,13 @@
         <dependency>
             <groupId>org.mockito</groupId>
             <artifactId>mockito-core</artifactId>
-            <version>5.11.0</version>
+            <version>5.13.0</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>com.tngtech.archunit</groupId>
             <artifactId>archunit-junit5</artifactId>
-            <version>1.2.1</version>
+            <version>${archunit.version}</version>
             <scope>test</scope>
         </dependency>
         <!--   Required by archunit     -->


=====================================
src/main/java/org/sqlite/JDBC.java
=====================================
@@ -18,12 +18,12 @@ package org.sqlite;
 
 import java.sql.*;
 import java.util.Properties;
-import java.util.logging.Logger;
-import org.slf4j.LoggerFactory;
 import org.sqlite.jdbc4.JDBC4Connection;
+import org.sqlite.util.Logger;
+import org.sqlite.util.LoggerFactory;
 
 public class JDBC implements Driver {
-    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(JDBC.class);
+    private static final Logger logger = LoggerFactory.getLogger(JDBC.class);
     public static final String PREFIX = "jdbc:sqlite:";
 
     static {
@@ -49,7 +49,7 @@ public class JDBC implements Driver {
         return false;
     }
 
-    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
+    public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException {
         // TODO
         return null;
     }


=====================================
src/main/java/org/sqlite/SQLiteConfig.java
=====================================
@@ -188,6 +188,7 @@ public class SQLiteConfig {
 
         // exclude this "fake" pragma from execution
         pragmaParams.remove(Pragma.JDBC_EXPLICIT_READONLY.pragmaName);
+        pragmaParams.remove(Pragma.JDBC_GET_GENERATED_KEYS.pragmaName);
 
         Statement stat = conn.createStatement();
         try {
@@ -330,6 +331,9 @@ public class SQLiteConfig {
                 defaultConnectionConfig.getDateStringFormat());
         pragmaTable.setProperty(
                 Pragma.JDBC_EXPLICIT_READONLY.pragmaName, this.explicitReadOnly ? "true" : "false");
+        pragmaTable.setProperty(
+                Pragma.JDBC_GET_GENERATED_KEYS.pragmaName,
+                defaultConnectionConfig.isGetGeneratedKeys() ? "true" : "false");
         return pragmaTable;
     }
 
@@ -349,7 +353,9 @@ public class SQLiteConfig {
         return result;
     }
 
-    private static final String[] OnOff = new String[] {"true", "false"};
+    static class OnOff {
+        private static final String[] Values = new String[] {"true", "false"};
+    }
 
     static final Set<String> pragmaSet = new TreeSet<String>();
 
@@ -377,11 +383,14 @@ public class SQLiteConfig {
 
         // Parameters requiring SQLite3 API invocation
         OPEN_MODE("open_mode", "Database open-mode flag", null),
-        SHARED_CACHE("shared_cache", "Enable SQLite Shared-Cache mode, native driver only", OnOff),
+        SHARED_CACHE(
+                "shared_cache",
+                "Enable SQLite Shared-Cache mode, native driver only",
+                OnOff.Values),
         LOAD_EXTENSION(
                 "enable_load_extension",
                 "Enable SQLite load_extension() function, native driver only",
-                OnOff),
+                OnOff.Values),
 
         // Pragmas that can be set after opening the database
         CACHE_SIZE(
@@ -395,24 +404,25 @@ public class SQLiteConfig {
         CASE_SENSITIVE_LIKE(
                 "case_sensitive_like",
                 "Installs a new application-defined LIKE function that is either case sensitive or insensitive depending on the value",
-                OnOff),
-        COUNT_CHANGES("count_changes", "Deprecated", OnOff),
+                OnOff.Values),
+        COUNT_CHANGES("count_changes", "Deprecated", OnOff.Values),
         DEFAULT_CACHE_SIZE("default_cache_size", "Deprecated", null),
         DEFER_FOREIGN_KEYS(
                 "defer_foreign_keys",
                 "When the defer_foreign_keys PRAGMA is on, enforcement of all foreign key constraints is delayed until the outermost transaction is committed. The defer_foreign_keys pragma defaults to OFF so that foreign key constraints are only deferred if they are created as \"DEFERRABLE INITIALLY DEFERRED\". The defer_foreign_keys pragma is automatically switched off at each COMMIT or ROLLBACK. Hence, the defer_foreign_keys pragma must be separately enabled for each transaction. This pragma is only meaningful if foreign key constraints are enabled, of course.",
-                OnOff),
-        EMPTY_RESULT_CALLBACKS("empty_result_callback", "Deprecated", OnOff),
+                OnOff.Values),
+        EMPTY_RESULT_CALLBACKS("empty_result_callback", "Deprecated", OnOff.Values),
         ENCODING(
                 "encoding",
                 "Set the encoding that the main database will be created with if it is created by this session",
                 toStringArray(Encoding.values())),
-        FOREIGN_KEYS("foreign_keys", "Set the enforcement of foreign key constraints", OnOff),
-        FULL_COLUMN_NAMES("full_column_names", "Deprecated", OnOff),
+        FOREIGN_KEYS(
+                "foreign_keys", "Set the enforcement of foreign key constraints", OnOff.Values),
+        FULL_COLUMN_NAMES("full_column_names", "Deprecated", OnOff.Values),
         FULL_SYNC(
                 "fullsync",
                 "Whether or not the F_FULLFSYNC syncing method is used on systems that support it. Only Mac OS X supports F_FULLFSYNC.",
-                OnOff),
+                OnOff.Values),
         INCREMENTAL_VACUUM(
                 "incremental_vacuum",
                 "Causes up to N pages to be removed from the freelist. The database file is truncated by the same amount. The incremental_vacuum pragma has no effect if the database is not in auto_vacuum=incremental mode or if there are no pages on the freelist. If there are fewer than N pages on the freelist, or if N is less than 1, or if the \"(N)\" argument is omitted, then the entire freelist is cleared.",
@@ -425,8 +435,8 @@ public class SQLiteConfig {
                 "journal_size_limit",
                 "Limit the size of rollback-journal and WAL files left in the file-system after transactions or checkpoints",
                 null),
-        LEGACY_ALTER_TABLE("legacy_alter_table", "Use legacy alter table behavior", OnOff),
-        LEGACY_FILE_FORMAT("legacy_file_format", "No-op", OnOff),
+        LEGACY_ALTER_TABLE("legacy_alter_table", "Use legacy alter table behavior", OnOff.Values),
+        LEGACY_FILE_FORMAT("legacy_file_format", "No-op", OnOff.Values),
         LOCKING_MODE(
                 "locking_mode",
                 "Set the database connection locking-mode",
@@ -437,17 +447,18 @@ public class SQLiteConfig {
                 null),
         MAX_PAGE_COUNT(
                 "max_page_count", "Set the maximum number of pages in the database file", null),
-        READ_UNCOMMITTED("read_uncommitted", "Set READ UNCOMMITTED isolation", OnOff),
-        RECURSIVE_TRIGGERS("recursive_triggers", "Set the recursive trigger capability", OnOff),
+        READ_UNCOMMITTED("read_uncommitted", "Set READ UNCOMMITTED isolation", OnOff.Values),
+        RECURSIVE_TRIGGERS(
+                "recursive_triggers", "Set the recursive trigger capability", OnOff.Values),
         REVERSE_UNORDERED_SELECTS(
                 "reverse_unordered_selects",
                 "When enabled, this PRAGMA causes many SELECT statements without an ORDER BY clause to emit their results in the reverse order from what they normally would",
-                OnOff),
+                OnOff.Values),
         SECURE_DELETE(
                 "secure_delete",
                 "When secure_delete is on, SQLite overwrites deleted content with zeros",
                 new String[] {"true", "false", "fast"}),
-        SHORT_COLUMN_NAMES("short_column_names", "Deprecated", OnOff),
+        SHORT_COLUMN_NAMES("short_column_names", "Deprecated", OnOff.Values),
         SYNCHRONOUS(
                 "synchronous",
                 "Set the \"synchronous\" flag",
@@ -535,7 +546,9 @@ public class SQLiteConfig {
 
         // extensions: "fake" pragmas to allow conformance with JDBC
         JDBC_EXPLICIT_READONLY(
-                "jdbc.explicit_readonly", "Set explicit read only transactions", null);
+                "jdbc.explicit_readonly", "Set explicit read only transactions", null),
+        JDBC_GET_GENERATED_KEYS(
+                "jdbc.get_generated_keys", "Enable retrieval of generated keys", OnOff.Values);
 
         public final String pragmaName;
         public final String[] choices;
@@ -555,6 +568,20 @@ public class SQLiteConfig {
             this.choices = choices;
         }
 
+        /**
+         * Convert the given enum values to a string array
+         *
+         * @param list Array if PragmaValue.
+         * @return String array of Enum values
+         */
+        private static String[] toStringArray(PragmaValue[] list) {
+            String[] result = new String[list.length];
+            for (int i = 0; i < list.length; i++) {
+                result[i] = list[i].getValue();
+            }
+            return result;
+        }
+
         public final String getPragmaName() {
             return pragmaName;
         }
@@ -700,20 +727,6 @@ public class SQLiteConfig {
         public String getValue();
     }
 
-    /**
-     * Convert the given enum values to a string array
-     *
-     * @param list Array if PragmaValue.
-     * @return String array of Enum values
-     */
-    private static String[] toStringArray(PragmaValue[] list) {
-        String[] result = new String[list.length];
-        for (int i = 0; i < list.length; i++) {
-            result[i] = list[i].getValue();
-        }
-        return result;
-    }
-
     public enum Encoding implements PragmaValue {
         UTF8("'UTF-8'"),
         UTF16("'UTF-16'"),
@@ -1176,4 +1189,12 @@ public class SQLiteConfig {
     public int getBusyTimeout() {
         return busyTimeout;
     }
+
+    public boolean isGetGeneratedKeys() {
+        return this.defaultConnectionConfig.isGetGeneratedKeys();
+    }
+
+    public void setGetGeneratedKeys(boolean generatedKeys) {
+        this.defaultConnectionConfig.setGetGeneratedKeys(generatedKeys);
+    }
 }


=====================================
src/main/java/org/sqlite/SQLiteConnectionConfig.java
=====================================
@@ -19,6 +19,7 @@ public class SQLiteConnectionConfig implements Cloneable {
     private int transactionIsolation = Connection.TRANSACTION_SERIALIZABLE;
     private SQLiteConfig.TransactionMode transactionMode = SQLiteConfig.TransactionMode.DEFERRED;
     private boolean autoCommit = true;
+    private boolean getGeneratedKeys = true;
 
     public static SQLiteConnectionConfig fromPragmaTable(Properties pragmaTable) {
         return new SQLiteConnectionConfig(
@@ -38,7 +39,10 @@ public class SQLiteConnectionConfig implements Cloneable {
                         pragmaTable.getProperty(
                                 SQLiteConfig.Pragma.TRANSACTION_MODE.pragmaName,
                                 SQLiteConfig.TransactionMode.DEFERRED.name())),
-                true);
+                true,
+                Boolean.parseBoolean(
+                        pragmaTable.getProperty(
+                                SQLiteConfig.Pragma.JDBC_GET_GENERATED_KEYS.pragmaName, "true")));
     }
 
     public SQLiteConnectionConfig(
@@ -47,13 +51,15 @@ public class SQLiteConnectionConfig implements Cloneable {
             String dateStringFormat,
             int transactionIsolation,
             SQLiteConfig.TransactionMode transactionMode,
-            boolean autoCommit) {
+            boolean autoCommit,
+            boolean getGeneratedKeys) {
         setDateClass(dateClass);
         setDatePrecision(datePrecision);
         setDateStringFormat(dateStringFormat);
         setTransactionIsolation(transactionIsolation);
         setTransactionMode(transactionMode);
         setAutoCommit(autoCommit);
+        setGetGeneratedKeys(getGeneratedKeys);
     }
 
     public SQLiteConnectionConfig copyConfig() {
@@ -63,7 +69,8 @@ public class SQLiteConnectionConfig implements Cloneable {
                 dateStringFormat,
                 transactionIsolation,
                 transactionMode,
-                autoCommit);
+                autoCommit,
+                getGeneratedKeys);
     }
 
     public long getDateMultiplier() {
@@ -124,8 +131,16 @@ public class SQLiteConnectionConfig implements Cloneable {
         this.transactionMode = transactionMode;
     }
 
+    public boolean isGetGeneratedKeys() {
+        return getGeneratedKeys;
+    }
+
+    public void setGetGeneratedKeys(boolean getGeneratedKeys) {
+        this.getGeneratedKeys = getGeneratedKeys;
+    }
+
     private static final Map<SQLiteConfig.TransactionMode, String> beginCommandMap =
-            new EnumMap<SQLiteConfig.TransactionMode, String>(SQLiteConfig.TransactionMode.class);
+            new EnumMap<>(SQLiteConfig.TransactionMode.class);
 
     static {
         beginCommandMap.put(SQLiteConfig.TransactionMode.DEFERRED, "begin;");


=====================================
src/main/java/org/sqlite/SQLiteDataSource.java
=====================================
@@ -437,6 +437,15 @@ public class SQLiteDataSource implements DataSource {
         config.setTransactionMode(transactionMode);
     }
 
+    /**
+     * Configure where generated keys will be retrieved for this database.
+     *
+     * @param generatedKeys true to retrieve generated keys
+     */
+    public void setGetGeneratedKeys(boolean generatedKeys) {
+        config.setGetGeneratedKeys(generatedKeys);
+    }
+
     /**
      * Sets the value of the user-version. It is a big-endian 32-bit signed integer stored in the
      * database header at offset 60.


=====================================
src/main/java/org/sqlite/SQLiteJDBCLoader.java
=====================================
@@ -39,9 +39,9 @@ import java.util.List;
 import java.util.Properties;
 import java.util.UUID;
 import java.util.stream.Stream;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.sqlite.util.LibraryLoaderUtil;
+import org.sqlite.util.Logger;
+import org.sqlite.util.LoggerFactory;
 import org.sqlite.util.OSInfo;
 import org.sqlite.util.StringUtils;
 


=====================================
src/main/java/org/sqlite/core/CoreStatement.java
=====================================
@@ -181,10 +181,12 @@ public abstract class CoreStatement implements Codes {
      * block.
      */
     public void updateGeneratedKeys() throws SQLException {
-        clearGeneratedKeys();
-        if (sql != null && INSERT_PATTERN.matcher(sql).find()) {
-            generatedKeysStat = conn.createStatement();
-            generatedKeysRs = generatedKeysStat.executeQuery("SELECT last_insert_rowid();");
+        if (conn.getConnectionConfig().isGetGeneratedKeys()) {
+            clearGeneratedKeys();
+            if (sql != null && INSERT_PATTERN.matcher(sql).find()) {
+                generatedKeysStat = conn.createStatement();
+                generatedKeysRs = generatedKeysStat.executeQuery("SELECT last_insert_rowid();");
+            }
         }
     }
 


=====================================
src/main/java/org/sqlite/core/NativeDB.java
=====================================
@@ -19,14 +19,14 @@ package org.sqlite.core;
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
 import java.sql.SQLException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.sqlite.BusyHandler;
 import org.sqlite.Collation;
 import org.sqlite.Function;
 import org.sqlite.ProgressHandler;
 import org.sqlite.SQLiteConfig;
 import org.sqlite.SQLiteJDBCLoader;
+import org.sqlite.util.Logger;
+import org.sqlite.util.LoggerFactory;
 
 /** This class provides a thin JNI layer over the SQLite3 C API. */
 public final class NativeDB extends DB {


=====================================
src/main/java/org/sqlite/jdbc3/JDBC3DatabaseMetaData.java
=====================================
@@ -21,12 +21,12 @@ import java.util.Properties;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.sqlite.SQLiteConnection;
 import org.sqlite.core.CoreDatabaseMetaData;
 import org.sqlite.core.CoreStatement;
 import org.sqlite.jdbc3.JDBC3DatabaseMetaData.ImportedKeyFinder.ForeignKey;
+import org.sqlite.util.Logger;
+import org.sqlite.util.LoggerFactory;
 import org.sqlite.util.QueryUtils;
 import org.sqlite.util.StringUtils;
 
@@ -1078,7 +1078,10 @@ public abstract class JDBC3DatabaseMetaData extends CoreDatabaseMetaData {
                             colType = colType.substring(0, iStartOfDimension).trim();
                         }
 
-                        int colGenerated = "2".equals(colHidden) ? 1 : 0;
+                        int colGenerated = 0;
+                        if ("2".equals(colHidden) || "3".equals(colHidden)) {
+                            colGenerated = 1;
+                        }
 
                         sql.append("select ")
                                 .append(i + 1)


=====================================
src/main/java/org/sqlite/jdbc3/JDBC3Statement.java
=====================================
@@ -8,14 +8,14 @@ import java.sql.SQLFeatureNotSupportedException;
 import java.sql.SQLWarning;
 import java.sql.Statement;
 import java.util.Arrays;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.sqlite.ExtendedCommand;
 import org.sqlite.ExtendedCommand.SQLExtension;
 import org.sqlite.SQLiteConnection;
 import org.sqlite.core.CoreStatement;
 import org.sqlite.core.DB;
 import org.sqlite.core.DB.ProgressObserver;
+import org.sqlite.util.Logger;
+import org.sqlite.util.LoggerFactory;
 
 public abstract class JDBC3Statement extends CoreStatement {
 


=====================================
src/main/java/org/sqlite/util/Logger.java
=====================================
@@ -0,0 +1,18 @@
+package org.sqlite.util;
+
+/** A simple internal Logger interface. */
+public interface Logger {
+    boolean isTraceEnabled();
+
+    void trace(String format, Object o1, Object o2);
+
+    void info(String format, Object o1, Object o2);
+
+    void warn(String msg);
+
+    void error(String message, Throwable t);
+
+    void error(String format, Object o1, Throwable t);
+
+    void error(String format, Object o1, Object o2, Throwable t);
+}


=====================================
src/main/java/org/sqlite/util/LoggerFactory.java
=====================================
@@ -0,0 +1,130 @@
+package org.sqlite.util;
+
+import java.text.MessageFormat;
+
+/**
+ * A factory for {@link Logger} instances that uses SLF4J if present, falling back on a
+ * java.util.logging implementation otherwise.
+ */
+public class LoggerFactory {
+    static final boolean USE_SLF4J;
+
+    static {
+        boolean useSLF4J;
+        try {
+            Class.forName("org.slf4j.Logger");
+            useSLF4J = true;
+        } catch (Exception e) {
+            useSLF4J = false;
+        }
+        USE_SLF4J = useSLF4J;
+    }
+
+    /**
+     * Get a {@link Logger} instance for the given host class.
+     *
+     * @param hostClass the host class from which log messages will be issued
+     * @return a Logger
+     */
+    public static Logger getLogger(Class<?> hostClass) {
+        if (USE_SLF4J) {
+            return new SLF4JLogger(hostClass);
+        }
+
+        return new JDKLogger(hostClass);
+    }
+
+    private static class JDKLogger implements Logger {
+        final java.util.logging.Logger logger;
+
+        public JDKLogger(Class<?> hostClass) {
+            logger = java.util.logging.Logger.getLogger(hostClass.getCanonicalName());
+        }
+
+        @Override
+        public boolean isTraceEnabled() {
+            return logger.isLoggable(java.util.logging.Level.FINEST);
+        }
+
+        @Override
+        public void trace(String format, Object o1, Object o2) {
+            if (logger.isLoggable(java.util.logging.Level.FINEST)) {
+                logger.log(java.util.logging.Level.FINEST, MessageFormat.format(format, o1, o2));
+            }
+        }
+
+        @Override
+        public void info(String format, Object o1, Object o2) {
+            if (logger.isLoggable(java.util.logging.Level.INFO)) {
+                logger.log(java.util.logging.Level.INFO, MessageFormat.format(format, o1, o2));
+            }
+        }
+
+        @Override
+        public void warn(String msg) {
+            logger.log(java.util.logging.Level.WARNING, msg);
+        }
+
+        @Override
+        public void error(String message, Throwable t) {
+            logger.log(java.util.logging.Level.SEVERE, message, t);
+        }
+
+        @Override
+        public void error(String format, Object o1, Throwable t) {
+            if (logger.isLoggable(java.util.logging.Level.SEVERE)) {
+                logger.log(java.util.logging.Level.SEVERE, MessageFormat.format(format, o1), t);
+            }
+        }
+
+        @Override
+        public void error(String format, Object o1, Object o2, Throwable t) {
+            if (logger.isLoggable(java.util.logging.Level.SEVERE)) {
+                logger.log(java.util.logging.Level.SEVERE, MessageFormat.format(format, o1, o2), t);
+            }
+        }
+    }
+
+    private static class SLF4JLogger implements Logger {
+        final org.slf4j.Logger logger;
+
+        SLF4JLogger(Class<?> hostClass) {
+            logger = org.slf4j.LoggerFactory.getLogger(hostClass);
+        }
+
+        @Override
+        public boolean isTraceEnabled() {
+            return logger.isTraceEnabled();
+        }
+
+        @Override
+        public void trace(String format, Object o1, Object o2) {
+            logger.trace(format, o1, o2);
+        }
+
+        @Override
+        public void info(String format, Object o1, Object o2) {
+            logger.info(format, o1, o2);
+        }
+
+        @Override
+        public void warn(String msg) {
+            logger.warn(msg);
+        }
+
+        @Override
+        public void error(String message, Throwable t) {
+            logger.error(message, t);
+        }
+
+        @Override
+        public void error(String format, Object o1, Throwable t) {
+            logger.error(format, o1, t);
+        }
+
+        @Override
+        public void error(String format, Object o1, Object o2, Throwable t) {
+            logger.error(format, o1, o2, t);
+        }
+    }
+}


=====================================
src/main/java/org/sqlite/util/OSInfo.java
=====================================
@@ -31,8 +31,6 @@ import java.nio.file.Paths;
 import java.util.HashMap;
 import java.util.Locale;
 import java.util.stream.Stream;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * Provides OS name and architecture name.
@@ -49,6 +47,7 @@ public class OSInfo {
     public static final String IA64 = "ia64";
     public static final String PPC = "ppc";
     public static final String PPC64 = "ppc64";
+    public static final String RISCV64 = "riscv64";
 
     static {
         // x86 mappings
@@ -88,6 +87,8 @@ public class OSInfo {
         archMapping.put("power_rs64", PPC64);
         archMapping.put("ppc64el", PPC64);
         archMapping.put("ppc64le", PPC64);
+
+        archMapping.put(RISCV64, RISCV64);
     }
 
     public static void main(String[] args) {
@@ -191,8 +192,14 @@ public class OSInfo {
                 // Use armv5, soft-float ABI
                 return "arm";
             } else if (armType.startsWith("aarch64")) {
-                // Use arm64
-                return "aarch64";
+                boolean is32bitJVM = "32".equals(System.getProperty("sun.arch.data.model"));
+                if (is32bitJVM) {
+                    // An aarch64 architecture should support armv7
+                    return "armv7";
+                } else {
+                    // Use arm64
+                    return "aarch64";
+                }
             }
 
             // Java 1.8 introduces a system property to determine armel or armhf


=====================================
src/main/java9/org/sqlite/nativeimage/SqliteJdbcFeature.java
=====================================
@@ -10,6 +10,7 @@ import org.sqlite.core.NativeDB;
 import org.sqlite.jdbc3.JDBC3DatabaseMetaData;
 import org.sqlite.util.LibraryLoaderUtil;
 import org.sqlite.util.OSInfo;
+import org.sqlite.util.ProcessRunner;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -27,6 +28,7 @@ public class SqliteJdbcFeature implements Feature {
         RuntimeClassInitialization.initializeAtBuildTime(SQLiteJDBCLoader.VersionHolder.class);
         RuntimeClassInitialization.initializeAtBuildTime(JDBC3DatabaseMetaData.class);
         RuntimeClassInitialization.initializeAtBuildTime(OSInfo.class);
+        RuntimeClassInitialization.initializeAtBuildTime(ProcessRunner.class);
         RuntimeClassInitialization.initializeAtBuildTime(LibraryLoaderUtil.class);
         a.registerReachabilityHandler(
                 this::nativeDbReachable, method(SQLiteJDBCLoader.class, "initialize"));


=====================================
src/test/java/org/sqlite/DBMetaDataTest.java
=====================================
@@ -18,6 +18,7 @@ import java.util.Map;
 import java.util.Properties;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.condition.DisabledInNativeImage;
@@ -490,6 +491,29 @@ public class DBMetaDataTest {
         assertThat(rs.next()).isFalse();
     }
 
+    @Test
+    @DisplayName(
+            "Issue #1132 - Generated columns with stored in SQLite are not marked as generated")
+    public void getColumnsIncludingGeneratedStored() throws SQLException {
+        stat.executeUpdate(
+                "create table foo("
+                        + "\n"
+                        + "  id integer primary key,"
+                        + "\n"
+                        + "  bar int not null generated always as (id + 1) stored"
+                        + "\n"
+                        + ");");
+
+        ResultSet rs = meta.getColumns(null, null, "foo", "%");
+        assertThat(rs.next()).isTrue();
+        assertThat(rs.getString(4)).as("first column is named 'id'").isEqualTo("id");
+        assertThat(rs.getString(24)).as("first column is generated").isEqualTo("NO");
+        assertThat(rs.next()).isTrue();
+        assertThat(rs.getString(4)).as("second column is named 'bar'").isEqualTo("bar");
+        assertThat(rs.getString(24)).as("second column is generated").isEqualTo("YES");
+        assertThat(rs.next()).isFalse();
+    }
+
     @Test
     public void getColumnsWithEscape() throws SQLException {
         stat.executeUpdate("create table wildcard(col1 integer, co_1 integer, 'co%1' integer)");


=====================================
src/test/java/org/sqlite/MultipleClassLoaderTest.java
=====================================
@@ -48,7 +48,12 @@ import java.util.jar.JarOutputStream;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable;
 
+ at DisabledIfEnvironmentVariable(
+        named = "SKIP_TEST_MULTIARCH",
+        matches = "true",
+        disabledReason = "Those tests would fail when ran on a multi-arch image")
 public class MultipleClassLoaderTest {
 
     private Connection connection = null;


=====================================
src/test/java/org/sqlite/PrepStmtTest.java
=====================================
@@ -81,6 +81,36 @@ public class PrepStmtTest {
         rs.close();
     }
 
+    @Test
+    public void pragmaGetGeneratedKeys() throws SQLException {
+        SQLiteConnection connection =
+                (SQLiteConnection)
+                        DriverManager.getConnection(
+                                "jdbc:sqlite::memory:?jdbc.get_generated_keys=false");
+        assertThat(connection.getConnectionConfig().isGetGeneratedKeys()).isFalse();
+    }
+
+    @Test
+    public void updateWithoutGeneratedKeys() throws SQLException {
+        Connection conn =
+                DriverManager.getConnection("jdbc:sqlite::memory:?jdbc.get_generated_keys=false");
+
+        assertThat(conn.prepareStatement("create table s1 (c1);").executeUpdate()).isEqualTo(0);
+        PreparedStatement prep = conn.prepareStatement("insert into s1 values (?);");
+        prep.setInt(1, 3);
+        assertThat(prep.executeUpdate()).isEqualTo(1);
+        assertThat(prep.getResultSet()).isNull();
+        prep.setInt(1, 5);
+        assertThat(prep.executeUpdate()).isEqualTo(1);
+        prep.setInt(1, 7);
+        assertThat(prep.executeUpdate()).isEqualTo(1);
+
+        ResultSet rsgk = prep.getGeneratedKeys();
+        assertThat(rsgk.next()).isFalse();
+        rsgk.close();
+        prep.close();
+    }
+
     @Test
     public void multiUpdate() throws SQLException {
         stat.executeUpdate("create table test (c1);");


=====================================
src/test/java/org/sqlite/SQLiteConfigTest.java
=====================================
@@ -1,9 +1,12 @@
 package org.sqlite;
 
-import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.*;
 
+import java.util.HashSet;
 import java.util.Properties;
+import java.util.Set;
 import org.junit.jupiter.api.Test;
+import org.sqlite.SQLiteConfig.Pragma;
 
 public class SQLiteConfigTest {
 
@@ -15,6 +18,7 @@ public class SQLiteConfigTest {
         config.setDateStringFormat("yyyy/mm/dd");
         config.setDatePrecision("seconds");
         config.setDateClass("real");
+        config.setGetGeneratedKeys(false);
 
         Properties properties = config.toProperties();
 
@@ -24,6 +28,8 @@ public class SQLiteConfigTest {
                 .isEqualTo(SQLiteConfig.DatePrecision.SECONDS.name());
         assertThat(properties.getProperty(SQLiteConfig.Pragma.DATE_CLASS.getPragmaName()))
                 .isEqualTo(SQLiteConfig.DateClass.REAL.name());
+        assertThat(properties.getProperty(Pragma.JDBC_GET_GENERATED_KEYS.getPragmaName()))
+                .isEqualTo("false");
     }
 
     @Test
@@ -50,4 +56,14 @@ public class SQLiteConfigTest {
                 .isEqualTo("100");
         assertThat(config.getBusyTimeout()).isEqualTo(100);
     }
+
+    @Test
+    public void pragmaSet() {
+        Set<String> expectedPragmaSet = new HashSet<>();
+        for (Pragma v : SQLiteConfig.Pragma.values()) {
+            expectedPragmaSet.add(v.pragmaName);
+        }
+
+        assertThat(SQLiteConfig.pragmaSet).isEqualTo(expectedPragmaSet);
+    }
 }


=====================================
src/test/java/org/sqlite/SQLiteDataSourceTest.java
=====================================
@@ -14,6 +14,7 @@ import static org.assertj.core.api.Assertions.assertThat;
 import java.nio.ByteOrder;
 import java.sql.Connection;
 import java.sql.ResultSet;
+import java.sql.SQLException;
 import java.sql.Statement;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
@@ -92,4 +93,36 @@ public class SQLiteDataSourceTest {
                 .isEqualTo("1234");
         assertThat(ds.getConfig().getBusyTimeout()).isEqualTo(1234);
     }
+
+    @Test
+    public void setGetGeneratedKeys() throws SQLException {
+        final SQLiteDataSource ds = new SQLiteDataSource();
+        ds.setGetGeneratedKeys(false);
+        assertThat(
+                        ds.getConfig()
+                                .toProperties()
+                                .getProperty(
+                                        SQLiteConfig.Pragma.JDBC_GET_GENERATED_KEYS.pragmaName))
+                .isEqualTo("false");
+        assertThat(ds.getConfig().isGetGeneratedKeys()).isEqualTo(false);
+        assertThat(
+                        ((SQLiteConnection) ds.getConnection())
+                                .getConnectionConfig()
+                                .isGetGeneratedKeys())
+                .isFalse();
+
+        ds.setGetGeneratedKeys(true);
+        assertThat(
+                        ds.getConfig()
+                                .toProperties()
+                                .getProperty(
+                                        SQLiteConfig.Pragma.JDBC_GET_GENERATED_KEYS.pragmaName))
+                .isEqualTo("true");
+        assertThat(ds.getConfig().isGetGeneratedKeys()).isEqualTo(true);
+        assertThat(
+                        ((SQLiteConnection) ds.getConnection())
+                                .getConnectionConfig()
+                                .isGetGeneratedKeys())
+                .isTrue();
+    }
 }


=====================================
src/test/java/org/sqlite/StatementTest.java
=====================================
@@ -1,8 +1,6 @@
 package org.sqlite;
 
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
-import static org.assertj.core.api.Assertions.assertThatNoException;
+import static org.assertj.core.api.Assertions.*;
 import static org.assertj.core.data.Offset.offset;
 
 import java.lang.reflect.Method;
@@ -351,6 +349,23 @@ public class StatementTest {
         assertThat(rs).isNotNull();
         assertThat(rs.next()).isFalse();
         stat2.close();
+
+        // disable then re-enable generated keys retrieval
+        try {
+            ((SQLiteConnection) conn).getConnectionConfig().setGetGeneratedKeys(false);
+            stat.executeUpdate("insert into t1 (v) values ('red');");
+            rs = stat.getGeneratedKeys();
+            assertThat(rs.next()).isFalse();
+
+            ((SQLiteConnection) conn).getConnectionConfig().setGetGeneratedKeys(true);
+
+            stat.executeUpdate("insert into t1 (v) values ('red');");
+            rs = stat.getGeneratedKeys();
+            assertThat(rs.next()).isTrue();
+            rs.close();
+        } finally {
+            ((SQLiteConnection) conn).getConnectionConfig().setGetGeneratedKeys(true);
+        }
     }
 
     @Test


=====================================
src/test/java/org/sqlite/architecture/CodingRulesTest.java
=====================================
@@ -1,6 +1,7 @@
 package org.sqlite.architecture;
 
 import static com.tngtech.archunit.base.DescribedPredicate.not;
+import static com.tngtech.archunit.core.domain.JavaClass.Predicates.belongToAnyOf;
 import static com.tngtech.archunit.core.domain.JavaClass.Predicates.equivalentTo;
 import static com.tngtech.archunit.lang.conditions.ArchPredicates.are;
 import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
@@ -14,15 +15,26 @@ import com.tngtech.archunit.core.domain.properties.HasOwner;
 import com.tngtech.archunit.core.importer.ImportOption;
 import com.tngtech.archunit.junit.AnalyzeClasses;
 import com.tngtech.archunit.junit.ArchTest;
+import com.tngtech.archunit.lang.ArchCondition;
 import com.tngtech.archunit.lang.ArchRule;
 import com.tngtech.archunit.lang.conditions.ArchConditions;
 import java.sql.DriverManager;
+import org.sqlite.util.LoggerFactory;
 import org.sqlite.util.OSInfo;
 
 @AnalyzeClasses(
         packages = "org.sqlite",
         importOptions = {ImportOption.DoNotIncludeTests.class})
 class CodingRulesTest {
+    public static final ArchCondition<JavaClass> USE_SLF4J_LOGGING;
+
+    static {
+        USE_SLF4J_LOGGING =
+                ArchConditions.dependOnClassesThat(
+                                com.tngtech.archunit.core.domain.JavaClass.Predicates
+                                        .resideInAPackage("org.slf4j"))
+                        .as("use SLF4J");
+    }
 
     @ArchTest
     void no_access_to_standard_streams(JavaClasses importedClasses) {
@@ -35,7 +47,12 @@ class CodingRulesTest {
 
     @ArchTest private final ArchRule no_jodatime = NO_CLASSES_SHOULD_USE_JODATIME;
 
-    @ArchTest private final ArchRule no_java_util_logging = NO_CLASSES_SHOULD_USE_JAVA_UTIL_LOGGING;
+    @ArchTest
+    private final ArchRule no_loggers_except_ours =
+            noClasses()
+                    .that(not(belongToAnyOf(LoggerFactory.class)))
+                    .should(USE_JAVA_UTIL_LOGGING)
+                    .orShould(USE_SLF4J_LOGGING);
 
     @ArchTest
     private final ArchRule no_driver_manager_println =


=====================================
src/test/java/org/sqlite/util/OSInfoTest.java
=====================================
@@ -24,7 +24,7 @@ import org.junit.jupiter.api.condition.DisabledInNativeImage;
 import org.junitpioneer.jupiter.SetSystemProperty;
 
 @DisabledIfEnvironmentVariable(
-        named = "SKIP_TEST_OSINFO",
+        named = "SKIP_TEST_MULTIARCH",
         matches = "true",
         disabledReason = "Those tests would fail when ran on a musl based Linux")
 @DisabledInNativeImage



View it on GitLab: https://salsa.debian.org/java-team/xerial-sqlite-jdbc/-/commit/a19678a2379751cb8f674c590744fb26c94407a6

-- 
View it on GitLab: https://salsa.debian.org/java-team/xerial-sqlite-jdbc/-/commit/a19678a2379751cb8f674c590744fb26c94407a6
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20241009/565422c5/attachment.htm>


More information about the pkg-java-commits mailing list