Skip to content

Commit 1245299

Browse files
committed
Use devtoolset-12 for Linux glibc builds
This PR brings in the build changes from mainline duckdb/duckdb#17776 fix. Additionally it enabled test runs on `ubuntu-latest` along with existing EL8 runs.
1 parent 5f877ad commit 1245299

File tree

6 files changed

+137
-90
lines changed

6 files changed

+137
-90
lines changed

.github/workflows/Java.yml

Lines changed: 66 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ jobs:
3131
needs: format-check
3232
env:
3333
MANYLINUX_IMAGE: quay.io/pypa/manylinux_2_28_x86_64
34-
MANYLINUX_PACKAGES: java-1.8.0-openjdk-devel ninja-build
3534
steps:
3635
- uses: actions/checkout@v4
3736
with:
@@ -45,18 +44,45 @@ jobs:
4544
-e GEN=ninja \
4645
-e JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk \
4746
${{ env.MANYLINUX_IMAGE }} \
48-
bash -c 'dnf install ${{ env.MANYLINUX_PACKAGES }} -y && make -C /duckdb release'
49-
50-
- name: JDBC Tests
47+
bash -c "
48+
set -e
49+
cat /etc/os-release
50+
dnf install -y \
51+
java-1.8.0-openjdk-devel \
52+
ninja-build \
53+
gcc-toolset-12-gcc-c++
54+
source /opt/rh/gcc-toolset-12/enable
55+
make -C /duckdb release
56+
"
57+
58+
- name: JDBC Tests EL8
5159
shell: bash
5260
if: ${{ inputs.skip_tests != 'true' }}
5361
run: |
5462
docker run \
5563
-v.:/duckdb \
56-
-e GEN=ninja \
57-
-e JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk \
5864
${{ env.MANYLINUX_IMAGE }} \
59-
bash -c 'dnf install ${{ env.MANYLINUX_PACKAGES }} -y && make -C /duckdb test'
65+
bash -c "
66+
set -e
67+
cat /etc/os-release
68+
dnf install -y \
69+
java-1.8.0-openjdk
70+
/usr/lib/jvm/jre-1.8.0-openjdk/bin/java -version
71+
cd /duckdb
72+
/usr/lib/jvm/jre-1.8.0-openjdk/bin/java \
73+
-cp ./build/release/duckdb_jdbc_tests.jar:./build/release/duckdb_jdbc.jar \
74+
org.duckdb.TestDuckDBJDBC
75+
rm ./test1.db
76+
"
77+
78+
- name: JDBC Tests
79+
shell: bash
80+
if: ${{ inputs.skip_tests != 'true' }}
81+
run: |
82+
cat /etc/os-release
83+
${JAVA_HOME_21_X64}/bin/java \
84+
-cp ./build/release/duckdb_jdbc_tests.jar:./build/release/duckdb_jdbc.jar \
85+
org.duckdb.TestDuckDBJDBC
6086
6187
- name: Deploy
6288
shell: bash
@@ -76,7 +102,6 @@ jobs:
76102
needs: java-linux-amd64
77103
env:
78104
MANYLINUX_IMAGE: quay.io/pypa/manylinux_2_28_aarch64
79-
MANYLINUX_PACKAGES: java-1.8.0-openjdk-devel ninja-build
80105
steps:
81106
- uses: actions/checkout@v4
82107
with:
@@ -90,18 +115,45 @@ jobs:
90115
-e GEN=ninja \
91116
-e JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk \
92117
${{ env.MANYLINUX_IMAGE }} \
93-
bash -c 'dnf install ${{ env.MANYLINUX_PACKAGES }} -y && make -C /duckdb release'
94-
95-
- name: JDBC Tests
118+
bash -c "
119+
set -e
120+
cat /etc/os-release
121+
dnf install -y \
122+
java-1.8.0-openjdk-devel \
123+
ninja-build \
124+
gcc-toolset-12-gcc-c++
125+
source /opt/rh/gcc-toolset-12/enable
126+
make -C /duckdb release
127+
"
128+
129+
- name: JDBC Tests EL8
96130
shell: bash
97131
if: ${{ inputs.skip_tests != 'true' }}
98132
run: |
99133
docker run \
100134
-v.:/duckdb \
101-
-e GEN=ninja \
102-
-e JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk \
103135
${{ env.MANYLINUX_IMAGE }} \
104-
bash -c 'dnf install ${{ env.MANYLINUX_PACKAGES }} -y && make -C /duckdb test'
136+
bash -c "
137+
set -e
138+
cat /etc/os-release
139+
dnf install -y \
140+
java-1.8.0-openjdk
141+
/usr/lib/jvm/jre-1.8.0-openjdk/bin/java -version
142+
cd /duckdb
143+
/usr/lib/jvm/jre-1.8.0-openjdk/bin/java \
144+
-cp ./build/release/duckdb_jdbc_tests.jar:./build/release/duckdb_jdbc.jar \
145+
org.duckdb.TestDuckDBJDBC
146+
rm ./test1.db
147+
"
148+
149+
- name: JDBC Tests
150+
shell: bash
151+
if: ${{ inputs.skip_tests != 'true' }}
152+
run: |
153+
cat /etc/os-release
154+
${JAVA_HOME_21_X64}/bin/java \
155+
-cp ./build/release/duckdb_jdbc_tests.jar:./build/release/duckdb_jdbc.jar \
156+
org.duckdb.TestDuckDBJDBC
105157
106158
- name: Deploy
107159
shell: bash

src/main/java/org/duckdb/DuckDBConnection.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public final class DuckDBConnection implements java.sql.Connection {
3737
public static final String DEFAULT_SCHEMA = "main";
3838

3939
ByteBuffer connRef;
40-
final ReentrantLock connRefLock = new ReentrantLock();
40+
final Lock connRefLock = new ReentrantLock();
4141
final LinkedHashSet<DuckDBPreparedStatement> preparedStatements = new LinkedHashSet<>();
4242
volatile boolean closing;
4343

@@ -488,11 +488,14 @@ void checkOpen() throws SQLException {
488488
* This function calls the underlying C++ interrupt function which aborts the query running on this connection.
489489
*/
490490
void interrupt() throws SQLException {
491-
if (!connRefLock.isHeldByCurrentThread()) {
492-
throw new SQLException("Connection lock state error");
493-
}
494491
checkOpen();
495-
DuckDBNative.duckdb_jdbc_interrupt(connRef);
492+
connRefLock.lock();
493+
try {
494+
checkOpen();
495+
DuckDBNative.duckdb_jdbc_interrupt(connRef);
496+
} finally {
497+
connRefLock.unlock();
498+
}
496499
}
497500

498501
QueryProgress queryProgress() throws SQLException {

src/main/java/org/duckdb/DuckDBDriver.java

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public class DuckDBDriver implements java.sql.Driver {
1616
public static final String JDBC_STREAM_RESULTS = "jdbc_stream_results";
1717
public static final String JDBC_AUTO_COMMIT = "jdbc_auto_commit";
1818
public static final String JDBC_PIN_DB = "jdbc_pin_db";
19+
public static final String JDBC_IGNORE_UNSUPPORTED_OPTIONS = "jdbc_ignore_unsupported_options";
1920

2021
static final String DUCKDB_URL_PREFIX = "jdbc:duckdb:";
2122
static final String MEMORY_DB = ":memory:";
@@ -33,6 +34,9 @@ public class DuckDBDriver implements java.sql.Driver {
3334
private static boolean pinnedDbRefsShutdownHookRegistered = false;
3435
private static boolean pinnedDbRefsShutdownHookRun = false;
3536

37+
private static final Set<String> supportedOptions = new LinkedHashSet<>();
38+
private static final ReentrantLock supportedOptionsLock = new ReentrantLock();
39+
3640
static {
3741
try {
3842
DriverManager.registerDriver(new DuckDBDriver());
@@ -52,13 +56,20 @@ public Connection connect(String url, Properties info) throws SQLException {
5256
props = (Properties) info.clone();
5357
}
5458

59+
// URL options
5560
ParsedProps pp = parsePropsFromUrl(url);
5661
for (Map.Entry<String, String> en : pp.props.entrySet()) {
5762
props.put(en.getKey(), en.getValue());
5863
}
5964

65+
// Ignore unsupported
66+
removeUnsupportedOptions(props);
67+
68+
// Read-only option
6069
String readOnlyStr = removeOption(props, DUCKDB_READONLY_PROPERTY);
6170
boolean readOnly = isStringTruish(readOnlyStr, false);
71+
72+
// Client name option
6273
props.put("duckdb_api", "jdbc");
6374

6475
// Apache Spark passes this option when SELECT on a JDBC DataSource
@@ -67,6 +78,7 @@ public Connection connect(String url, Properties info) throws SQLException {
6778
// to be established.
6879
props.remove("path");
6980

81+
// DuckLake options
7082
String ducklake = removeOption(props, DUCKLAKE_OPTION);
7183
String ducklakeAlias = removeOption(props, DUCKLAKE_ALIAS_OPTION, DUCKLAKE_OPTION);
7284
final String shortUrl;
@@ -83,13 +95,13 @@ public Connection connect(String url, Properties info) throws SQLException {
8395
shortUrl = pp.shortUrl;
8496
}
8597

98+
// Pin DB option
8699
String pinDbOptStr = removeOption(props, JDBC_PIN_DB);
87100
boolean pinDBOpt = isStringTruish(pinDbOptStr, false);
88101

102+
// Create connection
89103
DuckDBConnection conn = DuckDBConnection.newConnection(shortUrl, readOnly, props);
90-
91104
pinDB(pinDBOpt, shortUrl, conn);
92-
93105
initDucklake(conn, shortUrl, ducklake, ducklakeAlias);
94106

95107
return conn;
@@ -116,6 +128,8 @@ public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws
116128
list.add(createDriverPropInfo(JDBC_AUTO_COMMIT, "", "Set default auto-commit mode"));
117129
list.add(createDriverPropInfo(JDBC_PIN_DB, "",
118130
"Do not close the DB instance after all connections to it are closed"));
131+
list.add(createDriverPropInfo(JDBC_IGNORE_UNSUPPORTED_OPTIONS, "",
132+
"Silently discard unsupported connection options"));
119133
list.sort((o1, o2) -> o1.name.compareToIgnoreCase(o2.name));
120134
return list.toArray(new DriverPropertyInfo[0]);
121135
}
@@ -251,6 +265,38 @@ private static DriverPropertyInfo createDriverPropInfo(String name, String value
251265
return dpi;
252266
}
253267

268+
private static void removeUnsupportedOptions(Properties props) throws SQLException {
269+
String ignoreStr = removeOption(props, JDBC_IGNORE_UNSUPPORTED_OPTIONS);
270+
boolean ignore = isStringTruish(ignoreStr, false);
271+
if (!ignore) {
272+
return;
273+
}
274+
supportedOptionsLock.lock();
275+
try {
276+
if (supportedOptions.isEmpty()) {
277+
Driver driver = DriverManager.getDriver(DUCKDB_URL_PREFIX);
278+
Properties dpiProps = new Properties();
279+
dpiProps.put("threads", 1);
280+
DriverPropertyInfo[] dpis = driver.getPropertyInfo(DUCKDB_URL_PREFIX, dpiProps);
281+
for (DriverPropertyInfo dpi : dpis) {
282+
supportedOptions.add(dpi.name);
283+
}
284+
}
285+
List<String> unsupportedNames = new ArrayList<>();
286+
for (Object nameObj : props.keySet()) {
287+
String name = String.valueOf(nameObj);
288+
if (!supportedOptions.contains(name)) {
289+
unsupportedNames.add(name);
290+
}
291+
}
292+
for (String name : unsupportedNames) {
293+
props.remove(name);
294+
}
295+
} finally {
296+
supportedOptionsLock.unlock();
297+
}
298+
}
299+
254300
private static class ParsedProps {
255301
final String shortUrl;
256302
final LinkedHashMap<String, String> props;

src/main/java/org/duckdb/DuckDBPreparedStatement.java

Lines changed: 6 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public class DuckDBPreparedStatement implements PreparedStatement {
4444
private DuckDBConnection conn;
4545

4646
private ByteBuffer stmtRef = null;
47-
final ReentrantLock stmtRefLock = new ReentrantLock();
47+
final Lock stmtRefLock = new ReentrantLock();
4848
volatile boolean closeOnCompletion = false;
4949

5050
private DuckDBResultSet selectResult = null;
@@ -159,11 +159,6 @@ private boolean execute(boolean startTransaction) throws SQLException {
159159
checkOpen();
160160
checkPrepared();
161161

162-
// Wait with dispatching a new query if connection is locked by cancel() call
163-
Lock connLock = getConnRefLock();
164-
connLock.lock();
165-
connLock.unlock();
166-
167162
ByteBuffer resultRef = null;
168163

169164
stmtRefLock.lock();
@@ -447,27 +442,12 @@ public void setQueryTimeout(int seconds) throws SQLException {
447442
@Override
448443
public void cancel() throws SQLException {
449444
checkOpen();
450-
// Only proceed to interrupt call after ensuring that the query on
451-
// this statement is still running.
452-
if (!stmtRefLock.isLocked()) {
453-
return;
454-
}
455-
// Cancel is intended to be called concurrently with execute,
456-
// thus we cannot take the statement lock that is held while
457-
// query is running. NPE may be thrown if connection is closed
458-
// concurrently.
459445
try {
460-
// Taking connection lock will prevent new queries to be executed
461-
Lock connLock = getConnRefLock();
462-
connLock.lock();
463-
try {
464-
if (!stmtRefLock.isLocked()) {
465-
return;
466-
}
467-
conn.interrupt();
468-
} finally {
469-
connLock.unlock();
470-
}
446+
// Cancel is intended to be called concurrently with execute,
447+
// thus we cannot take the statement lock that is held while
448+
// query is running. NPE may be thrown if connection is closed
449+
// concurrently.
450+
conn.interrupt();
471451
} catch (NullPointerException e) {
472452
throw new SQLException(e);
473453
}
@@ -1235,13 +1215,4 @@ private int[] intArrayFromLong(long[] arr) {
12351215
}
12361216
return res;
12371217
}
1238-
1239-
private Lock getConnRefLock() throws SQLException {
1240-
// NPE can be thrown if statement is closed concurrently.
1241-
try {
1242-
return conn.connRefLock;
1243-
} catch (NullPointerException e) {
1244-
throw new SQLException(e);
1245-
}
1246-
}
12471218
}

src/test/java/org/duckdb/TestClosure.java

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -251,38 +251,4 @@ public static void test_results_fetch_no_hang() throws Exception {
251251
}
252252
}
253253
}
254-
255-
public static void test_stmt_can_only_cancel_self() throws Exception {
256-
try (Connection conn = DriverManager.getConnection(JDBC_URL); Statement stmt1 = conn.createStatement();
257-
Statement stmt2 = conn.createStatement()) {
258-
stmt1.execute("DROP TABLE IF EXISTS test_fib1");
259-
stmt1.execute("CREATE TABLE test_fib1(i bigint, p double, f double)");
260-
stmt1.execute("INSERT INTO test_fib1 values(1, 0, 1)");
261-
long start = System.currentTimeMillis();
262-
Thread th = new Thread(() -> {
263-
try {
264-
Thread.sleep(200);
265-
stmt1.cancel();
266-
} catch (Exception e) {
267-
e.printStackTrace();
268-
}
269-
});
270-
th.start();
271-
try (
272-
ResultSet rs = stmt2.executeQuery(
273-
"WITH RECURSIVE cte AS ("
274-
+
275-
"SELECT * from test_fib1 UNION ALL SELECT cte.i + 1, cte.f, cte.p + cte.f from cte WHERE cte.i < 40000) "
276-
+ "SELECT avg(f) FROM cte")) {
277-
rs.next();
278-
assertTrue(rs.getDouble(1) > 0);
279-
}
280-
th.join();
281-
long elapsed = System.currentTimeMillis() - start;
282-
assertTrue(elapsed > 1000);
283-
assertFalse(conn.isClosed());
284-
assertFalse(stmt1.isClosed());
285-
assertFalse(stmt2.isClosed());
286-
}
287-
}
288254
}

src/test/java/org/duckdb/TestDuckDBJDBC.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import static java.util.Collections.emptyList;
1111
import static java.util.Collections.singletonList;
1212
import static org.duckdb.DuckDBDriver.DUCKDB_USER_AGENT_PROPERTY;
13+
import static org.duckdb.DuckDBDriver.JDBC_STREAM_RESULTS;
1314
import static org.duckdb.DuckDBTimestamp.localDateTimeFromTimestamp;
1415
import static org.duckdb.test.Assertions.*;
1516
import static org.duckdb.test.Runner.runTests;
@@ -3656,6 +3657,14 @@ public static void test_driver_property_info() throws Exception {
36563657
assertTrue(dpis.length > 0);
36573658
}
36583659

3660+
public static void test_ignore_unsupported_options() throws Exception {
3661+
assertThrows(() -> { DriverManager.getConnection("jdbc:duckdb:;foo=bar;"); }, SQLException.class);
3662+
Properties config = new Properties();
3663+
config.put("boo", "bar");
3664+
config.put(JDBC_STREAM_RESULTS, true);
3665+
DriverManager.getConnection("jdbc:duckdb:;foo=bar;jdbc_ignore_unsupported_options=yes;", config).close();
3666+
}
3667+
36593668
public static void main(String[] args) throws Exception {
36603669
String arg1 = args.length > 0 ? args[0] : "";
36613670
final int statusCode;

0 commit comments

Comments
 (0)