@@ -16,6 +16,7 @@ public class DuckDBDriver implements java.sql.Driver {
16
16
public static final String DUCKDB_USER_AGENT_PROPERTY = "custom_user_agent" ;
17
17
public static final String JDBC_STREAM_RESULTS = "jdbc_stream_results" ;
18
18
public static final String JDBC_PIN_DB = "jdbc_pin_db" ;
19
+ public static final String JDBC_IGNORE_UNSUPPORTED_OPTIONS = "jdbc_ignore_unsupported_options" ;
19
20
20
21
static final String DUCKDB_URL_PREFIX = "jdbc:duckdb:" ;
21
22
static final String MEMORY_DB = ":memory:" ;
@@ -27,6 +28,9 @@ public class DuckDBDriver implements java.sql.Driver {
27
28
private static boolean pinnedDbRefsShutdownHookRegistered = false ;
28
29
private static boolean pinnedDbRefsShutdownHookRun = false ;
29
30
31
+ private static final Set <String > supportedOptions = new LinkedHashSet <>();
32
+ private static final ReentrantLock supportedOptionsLock = new ReentrantLock ();
33
+
30
34
static {
31
35
try {
32
36
DriverManager .registerDriver (new DuckDBDriver ());
@@ -42,38 +46,51 @@ public Connection connect(String url, Properties info) throws SQLException {
42
46
if (!acceptsURL (url )) {
43
47
return null ;
44
48
}
45
- boolean read_only = false ;
49
+ final Properties props ;
46
50
if (info == null ) {
47
- info = new Properties ();
51
+ props = new Properties ();
48
52
} else { // make a copy because we're removing the read only property below
49
- info = (Properties ) info .clone ();
50
- }
51
- String prop_val = (String ) info .remove (DUCKDB_READONLY_PROPERTY );
52
- if (prop_val != null ) {
53
- String prop_clean = prop_val .trim ().toLowerCase ();
54
- read_only = prop_clean .equals ("1" ) || prop_clean .equals ("true" ) || prop_clean .equals ("yes" );
53
+ props = (Properties ) info .clone ();
55
54
}
56
55
56
+ // URL options
57
57
ParsedProps pp = parsePropsFromUrl (url );
58
+
59
+ // Options in URL take preference
58
60
for (Map .Entry <String , String > en : pp .props .entrySet ()) {
59
- info .put (en .getKey (), en .getValue ());
61
+ props .put (en .getKey (), en .getValue ());
60
62
}
61
- url = pp .shortUrl ;
62
63
63
- info .put ("duckdb_api" , "jdbc" );
64
+ // Ignore unsupported
65
+ removeUnsupportedOptions (props );
66
+
67
+ // Read-only option
68
+ String readOnlyStr = removeOption (props , DUCKDB_READONLY_PROPERTY );
69
+ boolean readOnly = isStringTruish (readOnlyStr , false );
70
+
71
+ // Client name option
72
+ props .put ("duckdb_api" , "jdbc" );
64
73
65
74
// Apache Spark passes this option when SELECT on a JDBC DataSource
66
75
// table is performed. It is the internal Spark option and is likely
67
76
// passed by mistake, so we need to ignore it to allow the connection
68
77
// to be established.
69
- info .remove ("path" );
78
+ props .remove ("path" );
70
79
71
- String pinDbOptStr = removeOption (info , JDBC_PIN_DB );
80
+ // Pin DB option
81
+ String pinDbOptStr = removeOption (props , JDBC_PIN_DB );
72
82
boolean pinDBOpt = isStringTruish (pinDbOptStr , false );
73
83
74
- DuckDBConnection conn = DuckDBConnection .newConnection (url , read_only , info );
84
+ // Create connection
85
+ DuckDBConnection conn = DuckDBConnection .newConnection (pp .shortUrl , readOnly , props );
75
86
76
- pinDB (pinDBOpt , url , conn );
87
+ // Run post-init
88
+ try {
89
+ pinDB (pinDBOpt , pp .shortUrl , conn );
90
+ } catch (SQLException e ) {
91
+ closeQuietly (conn );
92
+ throw e ;
93
+ }
77
94
78
95
return conn ;
79
96
}
@@ -98,6 +115,8 @@ public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws
98
115
list .add (createDriverPropInfo (JDBC_STREAM_RESULTS , "" , "Enable result set streaming" ));
99
116
list .add (createDriverPropInfo (JDBC_PIN_DB , "" ,
100
117
"Do not close the DB instance after all connections to it are closed" ));
118
+ list .add (createDriverPropInfo (JDBC_IGNORE_UNSUPPORTED_OPTIONS , "" ,
119
+ "Silently discard unsupported connection options" ));
101
120
list .sort ((o1 , o2 ) -> o1 .name .compareToIgnoreCase (o2 .name ));
102
121
return list .toArray (new DriverPropertyInfo [0 ]);
103
122
}
@@ -196,6 +215,38 @@ private static DriverPropertyInfo createDriverPropInfo(String name, String value
196
215
return dpi ;
197
216
}
198
217
218
+ private static void removeUnsupportedOptions (Properties props ) throws SQLException {
219
+ String ignoreStr = removeOption (props , JDBC_IGNORE_UNSUPPORTED_OPTIONS );
220
+ boolean ignore = isStringTruish (ignoreStr , false );
221
+ if (!ignore ) {
222
+ return ;
223
+ }
224
+ supportedOptionsLock .lock ();
225
+ try {
226
+ if (supportedOptions .isEmpty ()) {
227
+ Driver driver = DriverManager .getDriver (DUCKDB_URL_PREFIX );
228
+ Properties dpiProps = new Properties ();
229
+ dpiProps .put ("threads" , 1 );
230
+ DriverPropertyInfo [] dpis = driver .getPropertyInfo (DUCKDB_URL_PREFIX , dpiProps );
231
+ for (DriverPropertyInfo dpi : dpis ) {
232
+ supportedOptions .add (dpi .name );
233
+ }
234
+ }
235
+ List <String > unsupportedNames = new ArrayList <>();
236
+ for (Object nameObj : props .keySet ()) {
237
+ String name = String .valueOf (nameObj );
238
+ if (!supportedOptions .contains (name )) {
239
+ unsupportedNames .add (name );
240
+ }
241
+ }
242
+ for (String name : unsupportedNames ) {
243
+ props .remove (name );
244
+ }
245
+ } finally {
246
+ supportedOptionsLock .unlock ();
247
+ }
248
+ }
249
+
199
250
private static class ParsedProps {
200
251
final String shortUrl ;
201
252
final LinkedHashMap <String , String > props ;
0 commit comments