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://&lt;host&gt;[:&lt;port&gt;]/&lt;database&gt;</code>
36 * where [:&lt;port&gt;] 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&trade; 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 }