Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,24 @@ jobs:
- name: spotless:check
run: mvn --batch-mode --no-transfer-progress spotless:check

android-signatures:
name: Check Android signatures
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: 11
java-package: jdk
cache: 'maven'
- name: Download and install signatures jar
run: |
wget -O coreLib2.signature https://repo1.maven.org/maven2/com/toasttab/android/gummy-bears-api-24/0.12.0/gummy-bears-api-24-0.12.0-coreLib2.signature
mvn --batch-mode --no-transfer-progress org.apache.maven.plugins:maven-install-plugin:3.1.1:install-file -Dfile=./coreLib2.signature -DgroupId=org.sqlite.signatures -DartifactId=gummy-bears-api-24 -Dversion=0.1 -Dpackaging=signature
- name: animal-sniffer:check
run: mvn --batch-mode --no-transfer-progress compile animal-sniffer:check

test:
name: test ${{ matrix.os }} jdk${{ matrix.java }}
strategy:
Expand Down Expand Up @@ -190,7 +208,7 @@ jobs:

release:
name: Deploy
needs: [ lint, test, test_multiarch, test_external_amalgamation, test_graalvm ]
needs: [ lint, android-signatures, test, test_multiarch, test_external_amalgamation, test_graalvm ]
if: github.repository_owner == 'xerial' && github.ref == 'refs/heads/master' # only perform on latest master
runs-on: ubuntu-latest
steps:
Expand Down
5 changes: 5 additions & 0 deletions USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,11 @@ The name of directories in our jar and in Android Studio differ, here is a mappi
| x86 | x86 |
| x86_64 | x86_64 |

Your project will need to integrate the [desugared core library](https://developer.android.com/studio/write/java11-default-support-table) (default).

The following methods will not work in Android:
- `JDBC3PreparedStatement#getParameterTypeName`

## How to load Run-Time Loadable Extensions

### Enable loadable extensions
Expand Down
25 changes: 25 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,31 @@
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>animal-sniffer-maven-plugin</artifactId>
<version>1.27</version>
<configuration>
<!-- <signature>-->
<!-- <groupId>com.toasttab.android</groupId>-->
<!-- <artifactId>gummy-bears-api-24</artifactId>-->
<!-- <version>0.12.0</version>-->
<!-- </signature>-->
<!-- The animal-sniffer plugin forces the classifier to 'signature', preventing the use of the coreLib signatures: https://github.com/open-toast/gummy-bears#core-library-desugaring -->
<!-- Workaround is to install the jar locally using the maven-install-plugin -->
<!-- Download the file: https://repo1.maven.org/maven2/com/toasttab/android/gummy-bears-api-24/0.12.0/gummy-bears-api-24-0.12.0-coreLib2.signature -->
<!-- Install: mvn org.apache.maven.plugins:maven-install-plugin:3.1.1:install-file -Dfile=./gummy-bears-api-24-0.12.0-coreLib2.signature -DgroupId=org.sqlite.signatures -DartifactId=gummy-bears-api-24 -Dversion=0.1 -Dpackaging=signature -->
<signature>
<groupId>org.sqlite.signatures</groupId>
<artifactId>gummy-bears-api-24</artifactId>
<version>0.1</version>
</signature>
<annotations>
<annotation>org.sqlite.util.AndroidSignatureIgnore</annotation>
</annotations>
</configuration>
</plugin>
</plugins>

<pluginManagement>
Expand Down
16 changes: 12 additions & 4 deletions src/main/java/org/sqlite/SQLiteConnection.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package org.sqlite;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
Expand Down Expand Up @@ -316,8 +316,16 @@ private static File extractResource(URL resourceAddr) throws IOException {
URLConnection conn = resourceAddr.openConnection();
// Disable caches to avoid keeping unnecessary file references after the single-use copy
conn.setUseCaches(false);
try (InputStream reader = conn.getInputStream()) {
Files.copy(reader, dbFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
try (InputStream reader = conn.getInputStream();
OutputStream writer = new FileOutputStream(dbFile)) {
// Replace this code with buffer copy so we don't rely on java.nio package for Android
// compatibility
// Files.copy(reader, dbFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = reader.read(buffer)) != -1) {
writer.write(buffer, 0, bytesRead);
}
return dbFile;
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/org/sqlite/SQLiteJDBCLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import java.util.Properties;
import java.util.UUID;
import java.util.stream.Stream;
import org.sqlite.util.AndroidSignatureIgnore;
import org.sqlite.util.LibraryLoaderUtil;
import org.sqlite.util.Logger;
import org.sqlite.util.LoggerFactory;
Expand All @@ -57,6 +58,7 @@
*
* @author leo
*/
@AndroidSignatureIgnore(explanation = "The loader is not used on Android")
public class SQLiteJDBCLoader {
private static final Logger logger = LoggerFactory.getLogger(SQLiteJDBCLoader.class);

Expand Down
5 changes: 4 additions & 1 deletion src/main/java/org/sqlite/core/DB.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import java.sql.BatchUpdateException;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
Expand Down Expand Up @@ -941,11 +942,13 @@ private synchronized long[] executeBatch(
if (rc != SQLITE_DONE) {
reset(stmt);
if (rc == SQLITE_ROW) {
// don't use the constructor with long because of
// https://github.com/xerial/sqlite-jdbc/issues/1378
throw new BatchUpdateException(
"batch entry " + i + ": query returns results",
null,
0,
changes,
Arrays.stream(changes).mapToInt(l -> (int) l).toArray(),
null);
}
throwex(rc);
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/org/sqlite/jdbc3/JDBC3PreparedStatement.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.sqlite.SQLiteConnection;
import org.sqlite.core.CorePreparedStatement;
import org.sqlite.core.DB;
import org.sqlite.util.AndroidSignatureIgnore;

public abstract class JDBC3PreparedStatement extends CorePreparedStatement {

Expand Down Expand Up @@ -169,6 +170,7 @@ public String getParameterClassName(int param) throws SQLException {
}

/** @see java.sql.ParameterMetaData#getParameterTypeName(int) */
@AndroidSignatureIgnore(explanation = "Android does not support java.sql.JDBCType")
public String getParameterTypeName(int pos) throws SQLException {
checkIndex(pos);
return JDBCType.valueOf(getParameterType(pos)).getName();
Expand Down
8 changes: 7 additions & 1 deletion src/main/java/org/sqlite/jdbc3/JDBC3Statement.java
Original file line number Diff line number Diff line change
Expand Up @@ -245,8 +245,14 @@ public long[] executeLargeBatch() throws SQLException {
db.prepare(this);
changes[i] = db.executeUpdate(this, null);
} catch (SQLException e) {
// don't use the constructor with long because of
// https://github.com/xerial/sqlite-jdbc/issues/1378
throw new BatchUpdateException(
"batch entry " + i + ": " + e.getMessage(), null, 0, changes, e);
"batch entry " + i + ": " + e.getMessage(),
null,
0,
Arrays.stream(changes).mapToInt(l -> (int) l).toArray(),
e);
} finally {
if (pointer != null) pointer.close();
}
Expand Down
23 changes: 20 additions & 3 deletions src/main/java/org/sqlite/jdbc4/JDBC4ResultSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,11 @@ public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
if (type == LocalDate.class) {
try {
Date date = getDate(columnIndex);
if (date != null) return type.cast(date.toLocalDate());
if (date != null)
// inlining of java.sql.Date.toLocateDate() for Android
return type.cast(
LocalDate.of(
date.getYear() + 1900, date.getMonth() + 1, date.getDate()));
else return null;
} catch (SQLException sqlException) {
// If the FastDateParser failed, try parse it with LocalDate.
Expand All @@ -336,7 +340,10 @@ public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
if (type == LocalTime.class) {
try {
Time time = getTime(columnIndex);
if (time != null) return type.cast(time.toLocalTime());
if (time != null)
// inlining of java.sql.Date.toLocateTime() for Android
return type.cast(
LocalTime.of(time.getHours(), time.getMinutes(), time.getSeconds()));
else return null;
} catch (SQLException sqlException) {
// If the FastDateParser failed, try parse it with LocalTime.
Expand All @@ -347,7 +354,17 @@ public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
if (type == LocalDateTime.class) {
try {
Timestamp timestamp = getTimestamp(columnIndex);
if (timestamp != null) return type.cast(timestamp.toLocalDateTime());
if (timestamp != null)
// inlining of java.sql.Date.toLocateDateTime() for Android
return type.cast(
LocalDateTime.of(
timestamp.getYear() + 1900,
timestamp.getMonth() + 1,
timestamp.getDate(),
timestamp.getHours(),
timestamp.getMinutes(),
timestamp.getSeconds(),
timestamp.getNanos()));
else return null;
} catch (SQLException e) {
// If the FastDateParser failed, try parse it with LocalDateTime.
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/org/sqlite/util/AndroidSignatureIgnore.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.sqlite.util;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.TYPE, ElementType.FIELD})
public @interface AndroidSignatureIgnore {
String explanation();
}
9 changes: 0 additions & 9 deletions src/main/java/org/sqlite/util/ProcessRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;

public class ProcessRunner {
String runAndWaitFor(String command) throws IOException, InterruptedException {
Expand All @@ -13,14 +12,6 @@ String runAndWaitFor(String command) throws IOException, InterruptedException {
return getProcessOutput(p);
}

String runAndWaitFor(String command, long timeout, TimeUnit unit)
throws IOException, InterruptedException {
Process p = Runtime.getRuntime().exec(command);
p.waitFor(timeout, unit);

return getProcessOutput(p);
}

static String getProcessOutput(Process process) throws IOException {
try (InputStream in = process.getInputStream()) {
int readLen;
Expand Down
8 changes: 7 additions & 1 deletion src/main/java9/org/sqlite/nativeimage/SqliteJdbcFeature.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,15 @@
import org.graalvm.nativeimage.hosted.RuntimeClassInitialization;
import org.graalvm.nativeimage.hosted.RuntimeJNIAccess;
import org.graalvm.nativeimage.hosted.RuntimeResourceAccess;
import org.sqlite.*;
import org.sqlite.BusyHandler;
import org.sqlite.Collation;
import org.sqlite.Function;
import org.sqlite.ProgressHandler;
import org.sqlite.SQLiteJDBCLoader;
import org.sqlite.core.DB;
import org.sqlite.core.NativeDB;
import org.sqlite.jdbc3.JDBC3DatabaseMetaData;
import org.sqlite.util.AndroidSignatureIgnore;
import org.sqlite.util.LibraryLoaderUtil;
import org.sqlite.util.OSInfo;
import org.sqlite.util.ProcessRunner;
Expand All @@ -21,6 +26,7 @@
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

@AndroidSignatureIgnore(explanation = "Used by GraalVM only")
public class SqliteJdbcFeature implements Feature {

@Override
Expand Down
Loading