Mercurial > hg > monetdb-java
comparison src/main/java/org/monetdb/jdbc/MonetDriver.java @ 786:f7df78989ac5
Generate MonetVersion.java rather than MonetDriver.java
MonetDriver.java also contains code, MonetVersion only the generated values.
author | Joeri van Ruth <joeri.van.ruth@monetdbsolutions.com> |
---|---|
date | Fri, 30 Jun 2023 11:55:48 +0200 (22 months ago) |
parents | src/main/java/org/monetdb/jdbc/MonetDriver.java.in@e00866975421 |
children | 2f36ac68ac35 4c35009cd59c |
comparison
equal
deleted
inserted
replaced
785:e00866975421 | 786:f7df78989ac5 |
---|---|
1 /* | |
2 * This Source Code Form is subject to the terms of the Mozilla Public | |
3 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. | |
5 * | |
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2023 MonetDB B.V. | |
7 */ | |
8 | |
9 package org.monetdb.jdbc; | |
10 | |
11 import java.net.URI; | |
12 import java.sql.Connection; | |
13 import java.sql.Driver; | |
14 import java.sql.DriverManager; | |
15 import java.sql.DriverPropertyInfo; | |
16 import java.sql.SQLException; | |
17 import java.sql.SQLFeatureNotSupportedException; | |
18 import java.sql.Types; | |
19 import java.util.Map.Entry; | |
20 import java.util.Properties; | |
21 | |
22 /** | |
23 *<pre> | |
24 * A JDBC {@link Driver} suitable for the MonetDB RDBMS. | |
25 * | |
26 * This driver will be used by the DriverManager to determine if an URL | |
27 * is to be handled by this driver, and if it does, then this driver | |
28 * will supply a Connection suitable for MonetDB. | |
29 * | |
30 * This class has no explicit constructor, the default constructor | |
31 * generated by the Java compiler will be sufficient since nothing has | |
32 * to be set in order to use this driver. | |
33 * | |
34 * This Driver supports MonetDB database URLs. MonetDB URLs are defined as: | |
35 * <code>jdbc:monetdb://<host>[:<port>]/<database></code> | |
36 * where [:<port>] denotes that a port is optional. If not | |
37 * given, port 50000 will be used. | |
38 *</pre> | |
39 * | |
40 * @author Fabian Groffen | |
41 */ | |
42 public final class MonetDriver implements Driver { | |
43 // the url kind will be jdbc:monetdb://<host>[:<port>]/<database> | |
44 // Chapter 9.2.1 from Sun JDBC 3.0 specification | |
45 /** The prefix of a MonetDB url */ | |
46 static final String MONETURL = "jdbc:monetdb://"; | |
47 | |
48 // initialize this class: register it at the DriverManager | |
49 // Chapter 9.2 from Sun JDBC 3.0 specification | |
50 static { | |
51 try { | |
52 DriverManager.registerDriver(new MonetDriver()); | |
53 } catch (SQLException e) { | |
54 e.printStackTrace(); | |
55 } | |
56 } | |
57 | |
58 //== methods of interface Driver | |
59 | |
60 /** | |
61 * Retrieves whether the driver thinks that it can open a connection to the | |
62 * given URL. Typically drivers will return true if they understand the | |
63 * subprotocol specified in the URL and false if they do not. | |
64 * | |
65 * @param url the URL of the database | |
66 * @return true if this driver understands the given URL; false otherwise | |
67 */ | |
68 @Override | |
69 public boolean acceptsURL(final String url) { | |
70 return url != null && url.startsWith(MONETURL); | |
71 } | |
72 | |
73 /** | |
74 * Attempts to make a database connection to the given URL. The driver | |
75 * should return "null" if it realizes it is the wrong kind of driver to | |
76 * connect to the given URL. This will be common, as when the JDBC driver | |
77 * manager is asked to connect to a given URL it passes the URL to each | |
78 * loaded driver in turn. | |
79 * | |
80 * The driver should throw an SQLException if it is the right driver to | |
81 * connect to the given URL but has trouble connecting to the database. | |
82 * | |
83 * The java.util.Properties argument can be used to pass arbitrary string | |
84 * tag/value pairs as connection arguments. Normally at least "user" and | |
85 * "password" properties should be included in the Properties object. | |
86 * | |
87 * @param url the URL of the database to which to connect | |
88 * @param info a list of arbitrary string tag/value pairs as connection | |
89 * arguments. Normally at least a "user" and "password" property | |
90 * should be included | |
91 * @return a Connection object that represents a connection to the URL | |
92 * @throws SQLException if a database access error occurs | |
93 */ | |
94 @Override | |
95 public Connection connect(final String url, Properties info) | |
96 throws SQLException | |
97 { | |
98 // url should be of style jdbc:monetdb://<host>/<database> | |
99 if (!acceptsURL(url)) | |
100 return null; | |
101 | |
102 final Properties props = new Properties(); | |
103 // set the optional properties and their defaults here | |
104 props.put("port", "50000"); | |
105 props.put("debug", "false"); | |
106 props.put("language", "sql"); // mal, sql, <future> | |
107 props.put("so_timeout", "0"); | |
108 | |
109 if (info != null) | |
110 props.putAll(info); | |
111 info = props; | |
112 | |
113 // remove leading "jdbc:" so the rest is a valid hierarchical URI | |
114 final URI uri; | |
115 try { | |
116 uri = new URI(url.substring(5)); | |
117 } catch (java.net.URISyntaxException e) { | |
118 return null; | |
119 } | |
120 | |
121 final String uri_host = uri.getHost(); | |
122 if (uri_host == null) | |
123 return null; | |
124 info.put("host", uri_host); | |
125 | |
126 int uri_port = uri.getPort(); | |
127 if (uri_port > 0) | |
128 info.put("port", Integer.toString(uri_port)); | |
129 | |
130 // check the database | |
131 String uri_path = uri.getPath(); | |
132 if (uri_path != null && !uri_path.isEmpty()) { | |
133 uri_path = uri_path.substring(1).trim(); | |
134 if (!uri_path.isEmpty()) | |
135 info.put("database", uri_path); | |
136 } | |
137 | |
138 final String uri_query = uri.getQuery(); | |
139 if (uri_query != null) { | |
140 int pos; | |
141 // handle additional connection properties separated by the & character | |
142 final String args[] = uri_query.split("&"); | |
143 for (int i = 0; i < args.length; i++) { | |
144 pos = args[i].indexOf('='); | |
145 if (pos > 0) | |
146 info.put(args[i].substring(0, pos), args[i].substring(pos + 1)); | |
147 } | |
148 } | |
149 | |
150 // finally return the Connection object as requested | |
151 return new MonetConnection(info); | |
152 } | |
153 | |
154 /** | |
155 * Retrieves the driver's major version number. Initially this should be 1. | |
156 * | |
157 * @return this driver's major version number | |
158 */ | |
159 @Override | |
160 public int getMajorVersion() { | |
161 // defer to the static version of this method | |
162 return getDriverMajorVersion(); | |
163 } | |
164 | |
165 /** | |
166 * Gets the driver's minor version number. Initially this should be 0. | |
167 * | |
168 * @return this driver's minor version number | |
169 */ | |
170 @Override | |
171 public int getMinorVersion() { | |
172 // defer to the static version of this method | |
173 return getDriverMinorVersion(); | |
174 } | |
175 | |
176 /** | |
177 * Gets information about the possible properties for this driver. | |
178 * | |
179 * The getPropertyInfo method is intended to allow a generic GUI tool to | |
180 * discover what properties it should prompt a human for in order to get | |
181 * enough information to connect to a database. Note that depending on the | |
182 * values the human has supplied so far, additional values may become | |
183 * necessary, so it may be necessary to iterate though several calls to the | |
184 * getPropertyInfo method. | |
185 * | |
186 * @param url the URL of the database to which to connect | |
187 * @param info a proposed list of tag/value pairs that will be sent on | |
188 * connect open | |
189 * @return an array of DriverPropertyInfo objects describing possible | |
190 * properties. This array may be an empty array if no properties | |
191 * are required. | |
192 */ | |
193 @Override | |
194 public DriverPropertyInfo[] getPropertyInfo(final String url, final Properties info) { | |
195 if (!acceptsURL(url)) | |
196 return null; | |
197 | |
198 final String[] boolean_choices = new String[] { "true", "false" }; | |
199 final DriverPropertyInfo[] dpi = new DriverPropertyInfo[10]; // we currently support 10 connection properties | |
200 | |
201 DriverPropertyInfo prop = new DriverPropertyInfo("user", info != null ? info.getProperty("user") : null); | |
202 prop.required = true; | |
203 prop.description = "The user loginname to use when authenticating on the database server"; | |
204 dpi[0] = prop; | |
205 | |
206 prop = new DriverPropertyInfo("password", info != null ? info.getProperty("password") : null); | |
207 prop.required = true; | |
208 prop.description = "The password to use when authenticating on the database server"; | |
209 dpi[1] = prop; | |
210 | |
211 prop = new DriverPropertyInfo("debug", "false"); | |
212 prop.required = false; | |
213 prop.description = "Whether or not to create a log file for debugging purposes"; | |
214 prop.choices = boolean_choices; | |
215 dpi[2] = prop; | |
216 | |
217 prop = new DriverPropertyInfo("logfile", null); | |
218 prop.required = false; | |
219 prop.description = "The filename to write the debug log to. Only takes effect if debug is set to true. If the file exists, an incrementing number is added, till the filename is unique."; | |
220 dpi[3] = prop; | |
221 | |
222 prop = new DriverPropertyInfo("language", "sql"); | |
223 prop.required = false; | |
224 prop.description = "What language to use for MonetDB conversations (experts only)"; | |
225 prop.choices = new String[] { "sql", "mal" }; | |
226 dpi[4] = prop; | |
227 | |
228 prop = new DriverPropertyInfo("hash", null); | |
229 prop.required = false; | |
230 prop.description = "Force the use of the given hash algorithm (SHA512 or SHA384 or SHA256 or SHA1) during challenge response"; | |
231 prop.choices = new String[] { "SHA512", "SHA384", "SHA256", "SHA1" }; | |
232 dpi[5] = prop; | |
233 | |
234 prop = new DriverPropertyInfo("treat_blob_as_binary", "true"); | |
235 prop.required = false; | |
236 prop.description = "Should blob columns be mapped to Types.VARBINARY instead of Types.BLOB in ResultSets and PreparedStatements"; // recommend for increased performance due to less overhead | |
237 prop.choices = boolean_choices; | |
238 dpi[6] = prop; | |
239 | |
240 prop = new DriverPropertyInfo("treat_clob_as_varchar", "true"); | |
241 prop.required = false; | |
242 prop.description = "Should clob columns be mapped to Types.VARCHAR instead of Types.CLOB in ResultSets and PreparedStatements"; // recommend for increased performance due to less overhead | |
243 prop.choices = boolean_choices; | |
244 dpi[7] = prop; | |
245 | |
246 prop = new DriverPropertyInfo("so_timeout", "0"); | |
247 prop.required = false; | |
248 prop.description = "Defines the maximum time to wait in milliseconds on a blocking read socket call"; // this corresponds to the Connection.setNetworkTimeout() method introduced in JDBC 4.1 | |
249 dpi[8] = prop; | |
250 | |
251 prop = new DriverPropertyInfo("autocommit", "true"); | |
252 prop.required = false; | |
253 prop.description = "Whether the connection should start in auto-commit mode"; | |
254 prop.choices = boolean_choices; | |
255 dpi[9] = prop; | |
256 | |
257 return dpi; | |
258 } | |
259 | |
260 /** | |
261 * Reports whether this driver is a genuine JDBC Compliant™ driver. A | |
262 * driver may only report true here if it passes the JDBC compliance tests; | |
263 * otherwise it is required to return false. | |
264 * | |
265 * JDBC compliance requires full support for the JDBC API and full support | |
266 * for SQL 92 Entry Level. It is expected that JDBC compliant drivers will | |
267 * be available for all the major commercial databases. | |
268 * | |
269 * This method is not intended to encourage the development of non-JDBC | |
270 * compliant drivers, but is a recognition of the fact that some vendors are | |
271 * interested in using the JDBC API and framework for lightweight databases | |
272 * that do not support full database functionality, or for special databases | |
273 * such as document information retrieval where a SQL implementation may not | |
274 * be feasible. | |
275 * | |
276 * @return true if this driver is JDBC Compliant; false otherwise | |
277 */ | |
278 @Override | |
279 public boolean jdbcCompliant() { | |
280 // We're not fully JDBC compliant, but what we support is compliant | |
281 return false; | |
282 } | |
283 | |
284 /** | |
285 * Return the parent Logger of all the Loggers used by this data source. | |
286 * This should be the Logger farthest from the root Logger that is | |
287 * still an ancestor of all of the Loggers used by this data source. | |
288 * Configuring this Logger will affect all of the log messages | |
289 * generated by the data source. | |
290 * In the worst case, this may be the root Logger. | |
291 * | |
292 * @return the parent Logger for this data source | |
293 * @throws SQLFeatureNotSupportedException if the data source does | |
294 * not use java.util.logging | |
295 * @since 1.7 | |
296 */ | |
297 @Override | |
298 public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { | |
299 throw MonetWrapper.newSQLFeatureNotSupportedException("getParentLogger"); | |
300 } | |
301 | |
302 //== end methods of interface driver | |
303 | |
304 | |
305 /** | |
306 * Get MonetDB JDBC Driver major version number | |
307 * method called by MonetDatabaseMetaData methods | |
308 * @return MonetDB JDBC Driver major version number | |
309 */ | |
310 static final int getDriverMajorVersion() { | |
311 // defer to the generated MonetVersion class | |
312 return MonetVersion.majorVersion; | |
313 } | |
314 | |
315 /** | |
316 * Get MonetDB JDBC Driver minor version number | |
317 * method called by MonetDatabaseMetaData methods | |
318 * @return MonetDB JDBC Driver minor version number | |
319 */ | |
320 static final int getDriverMinorVersion() { | |
321 // defer to the generated MonetVersion class | |
322 return MonetVersion.minorVersion; | |
323 } | |
324 | |
325 /** | |
326 * Returns a touched up identifying version string of this driver. | |
327 * It is made public as it is called from org/monetdb/client/JdbcClient.java | |
328 * @return the version string | |
329 */ | |
330 public static final String getDriverVersion() { | |
331 return MonetVersion.driverVersion; | |
332 } | |
333 | |
334 /** A static Map containing the mapping between MonetDB types and Java SQL types */ | |
335 /* use SELECT sqlname, * FROM sys.types order by 1, id; to view all MonetDB types */ | |
336 /* see http://docs.oracle.com/javase/8/docs/api/java/sql/Types.html to view all supported java SQL types */ | |
337 private static final java.util.Map<String, Integer> typeMap = new java.util.HashMap<String, Integer>(); | |
338 static { | |
339 // fill the typeMap once | |
340 // typeMap.put("any", Integer.valueOf(Types.???)); | |
341 typeMap.put("bigint", Integer.valueOf(Types.BIGINT)); | |
342 typeMap.put("blob", Integer.valueOf(Types.BLOB)); | |
343 typeMap.put("boolean", Integer.valueOf(Types.BOOLEAN)); | |
344 typeMap.put("char", Integer.valueOf(Types.CHAR)); | |
345 typeMap.put("clob", Integer.valueOf(Types.CLOB)); | |
346 typeMap.put("date", Integer.valueOf(Types.DATE)); | |
347 typeMap.put("day_interval", Integer.valueOf(Types.NUMERIC)); // New as of Oct2020 release | |
348 typeMap.put("decimal", Integer.valueOf(Types.DECIMAL)); | |
349 typeMap.put("double", Integer.valueOf(Types.DOUBLE)); | |
350 // typeMap.put("geometry", Integer.valueOf(Types.???)); | |
351 // typeMap.put("geometrya", Integer.valueOf(Types.???)); | |
352 typeMap.put("hugeint", Integer.valueOf(Types.NUMERIC)); | |
353 typeMap.put("inet", Integer.valueOf(Types.VARCHAR)); | |
354 typeMap.put("int", Integer.valueOf(Types.INTEGER)); | |
355 typeMap.put("json", Integer.valueOf(Types.VARCHAR)); | |
356 // typeMap.put("mbr", Integer.valueOf(Types.???)); | |
357 typeMap.put("month_interval", Integer.valueOf(Types.INTEGER)); | |
358 typeMap.put("oid", Integer.valueOf(Types.BIGINT)); | |
359 // typeMap.put("ptr", Integer.valueOf(Types.???)); | |
360 typeMap.put("real", Integer.valueOf(Types.REAL)); | |
361 typeMap.put("sec_interval", Integer.valueOf(Types.DECIMAL)); | |
362 typeMap.put("smallint", Integer.valueOf(Types.SMALLINT)); | |
363 typeMap.put("str", Integer.valueOf(Types.VARCHAR)); // MonetDB prepare <stmt> uses type 'str' (instead of varchar) for the schema, table and column metadata output. DO NOT REMOVE this entry! | |
364 // typeMap.put("table", Integer.valueOf(Types.???)); | |
365 typeMap.put("time", Integer.valueOf(Types.TIME)); | |
366 typeMap.put("timestamp", Integer.valueOf(Types.TIMESTAMP)); | |
367 typeMap.put("timestamptz", Integer.valueOf(Types.TIMESTAMP_WITH_TIMEZONE)); // new in Java 8: Types.TIMESTAMP_WITH_TIMEZONE (value 2014) | |
368 typeMap.put("timetz", Integer.valueOf(Types.TIME_WITH_TIMEZONE)); // new in Java 8: Types.TIME_WITH_TIMEZONE (value 2013) | |
369 typeMap.put("tinyint", Integer.valueOf(Types.TINYINT)); | |
370 typeMap.put("url", Integer.valueOf(Types.VARCHAR)); | |
371 typeMap.put("uuid", Integer.valueOf(Types.VARCHAR)); | |
372 typeMap.put("varchar", Integer.valueOf(Types.VARCHAR)); | |
373 typeMap.put("wrd", Integer.valueOf(Types.BIGINT)); // keep it in for old (pre Dec2016) MonetDB servers | |
374 typeMap.put("xml", Integer.valueOf(Types.VARCHAR)); // used when "CREATE TYPE xml EXTERNAL NAME xml;" is executed | |
375 } | |
376 | |
377 /** | |
378 * Returns the java.sql.Types equivalent of the given MonetDB type name. | |
379 * | |
380 * @param type the SQL data type name as used by MonetDB | |
381 * @return the matching java.sql.Types constant or | |
382 * java.sql.Types.OTHER if nothing matched the given type name | |
383 */ | |
384 static final int getJdbcSQLType(final String type) { | |
385 // find the column type name in the typeMap | |
386 final Integer tp = typeMap.get(type); | |
387 if (tp != null) { | |
388 return tp.intValue(); | |
389 } | |
390 // When type name is not found in the map, for instance | |
391 // when it is a new type (not yet added in the above typeMap) or | |
392 // when type name is: any or geometry or geometrya or mbr or ptr or table. | |
393 return Types.OTHER; | |
394 } | |
395 | |
396 /** | |
397 * Returns the Class object for a given java.sql.Types value. | |
398 * | |
399 * @param type a value from java.sql.Types | |
400 * @return a Class object from which an instance would be returned | |
401 */ | |
402 static final Class<?> getClassForType(final int type) { | |
403 /** | |
404 * This switch returns the types as objects according to table B-3 from | |
405 * Oracle's JDBC specification 4.1 | |
406 */ | |
407 switch(type) { | |
408 case Types.CHAR: | |
409 case Types.VARCHAR: | |
410 /* case Types.LONGVARCHAR: // MonetDB doesn't use type LONGVARCHAR */ | |
411 return String.class; | |
412 case Types.NUMERIC: | |
413 case Types.DECIMAL: | |
414 return java.math.BigDecimal.class; | |
415 case Types.BOOLEAN: | |
416 return Boolean.class; | |
417 case Types.TINYINT: | |
418 case Types.SMALLINT: | |
419 return Short.class; | |
420 case Types.INTEGER: | |
421 return Integer.class; | |
422 case Types.BIGINT: | |
423 return Long.class; | |
424 case Types.REAL: | |
425 return Float.class; | |
426 case Types.FLOAT: | |
427 case Types.DOUBLE: | |
428 return Double.class; | |
429 case Types.BINARY: // MonetDB currently does not support these | |
430 case Types.VARBINARY: // see treat_blob_as_binary property | |
431 /* case Types.LONGVARBINARY: // MonetDB doesn't use type LONGVARBINARY */ | |
432 return byte[].class; | |
433 case Types.DATE: | |
434 return java.sql.Date.class; | |
435 case Types.TIME: | |
436 case Types.TIME_WITH_TIMEZONE: | |
437 return java.sql.Time.class; | |
438 case Types.TIMESTAMP: | |
439 case Types.TIMESTAMP_WITH_TIMEZONE: | |
440 return java.sql.Timestamp.class; | |
441 case Types.CLOB: | |
442 return java.sql.Clob.class; | |
443 case Types.BLOB: | |
444 return java.sql.Blob.class; | |
445 | |
446 // all the rest are currently not implemented and used | |
447 default: | |
448 return String.class; | |
449 } | |
450 } | |
451 | |
452 private static String TypeMapppingSQL; // cache to optimise getSQLTypeMap() | |
453 /** | |
454 * Returns a String usable in an SQL statement to map the server types | |
455 * to values of java.sql.Types using the global static type map. | |
456 * The returned string will be a SQL CASE x statement where the x is | |
457 * replaced with the given column name (or expression) string. | |
458 * | |
459 * @param column a String representing the value that should be evaluated | |
460 * in the SQL CASE statement | |
461 * @return a SQL CASE statement | |
462 */ | |
463 static final String getSQLTypeMap(final String column) { | |
464 if (TypeMapppingSQL == null) { | |
465 // first time, compose TypeMappping SQL string | |
466 final StringBuilder val = new StringBuilder((typeMap.size() * (7 + 7 + 7 + 4)) + 14); | |
467 for (Entry<String, Integer> entry : typeMap.entrySet()) { | |
468 val.append(" WHEN '").append(entry.getKey()).append("' THEN ").append(entry.getValue().toString()); | |
469 } | |
470 val.append(" ELSE " + Types.OTHER + " END"); | |
471 // as the typeMap is static, cache this SQL part for all next calls | |
472 TypeMapppingSQL = val.toString(); | |
473 } | |
474 return "CASE " + column + TypeMapppingSQL; | |
475 } | |
476 } |