Skip to content

Commit 2ea59fe

Browse files
committed
Allow to ignore unsupported connection options
Currently driver performs strict checks on the user-specified connection options. If stray options are passed - exception is thrown on connect. This is considered to be a good feature, to prevent accidental typos in option names. But in some cases user does not have full control over the options passed to driver by other tools. This change adds new boolean connection property `jdbc_ignore_unsupported_options`, when it is enabled - all unsupported connection options are ignored. When used with external tools, it is intended to be set in connection string like this: ``` jdbc:duckdb:;jdbc_ignore_unsupported_options=true; ``` Testing: new test added. Fixes: #232
1 parent 258ee50 commit 2ea59fe

File tree

2 files changed

+57
-2
lines changed

2 files changed

+57
-2
lines changed

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/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)