Mercurial > hg > monetdb-java
view src/main/java/org/monetdb/jdbc/MonetDriver.java @ 970:f90d811e97eb default tip
Adjust getTableTypes() test for new table type: LOCAL TEMPORARY VIEW, added in 11.53.4 (Mar2025-SP1)
author | Martin van Dinther <martin.van.dinther@monetdbsolutions.com> |
---|---|
date | Thu, 03 Apr 2025 15:01:33 +0200 (4 days ago) |
parents | fd938d0a2b3a |
children |
line wrap: on
line source
/* * SPDX-License-Identifier: MPL-2.0 * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2024, 2025 MonetDB Foundation; * Copyright August 2008 - 2023 MonetDB B.V.; * Copyright 1997 - July 2008 CWI. */ package org.monetdb.jdbc; import org.monetdb.mcl.net.Parameter; import org.monetdb.mcl.net.Target; import org.monetdb.mcl.net.ValidationError; import java.net.URISyntaxException; import java.sql.Connection; import java.sql.Driver; import java.sql.DriverManager; import java.sql.DriverPropertyInfo; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.sql.Types; import java.util.Map.Entry; import java.util.Properties; /** *<pre> * A JDBC {@link Driver} suitable for the MonetDB RDBMS. * * This driver will be used by the DriverManager to determine if an URL * is to be handled by this driver, and if it does, then this driver * will supply a Connection suitable for MonetDB. * * This class has no explicit constructor, the default constructor * generated by the Java compiler will be sufficient since nothing has * to be set in order to use this driver. * * This Driver supports MonetDB database URLs. MonetDB URLs are defined as: * <code>jdbc:monetdb://<host>[:<port>]/<database></code> * where [:<port>] denotes that a port is optional. If not * given, port 50000 will be used. *</pre> * * @author Fabian Groffen */ public final class MonetDriver implements Driver { // the url kind will be jdbc:monetdb://<host>[:<port>]/<database> // Chapter 9.2.1 from Sun JDBC 3.0 specification // initialize this class: register it at the DriverManager // Chapter 9.2 from Sun JDBC 3.0 specification static { try { DriverManager.registerDriver(new MonetDriver()); } catch (SQLException e) { e.printStackTrace(); } } //== methods of interface Driver /** * Retrieves whether the driver thinks that it can open a connection to the * given URL. Typically drivers will return true if they understand the * subprotocol specified in the URL and false if they do not. * * @param url the URL of the database * @return true if this driver understands the given URL; false otherwise */ @Override public boolean acceptsURL(final String url) { if (url == null) return false; return url.startsWith("jdbc:monetdb:") || url.startsWith("jdbc:monetdbs:"); } /** * Attempts to make a database connection to the given URL. The driver * should return "null" if it realizes it is the wrong kind of driver to * connect to the given URL. This will be common, as when the JDBC driver * manager is asked to connect to a given URL it passes the URL to each * loaded driver in turn. * * The driver should throw an SQLException if it is the right driver to * connect to the given URL but has trouble connecting to the database. * * The java.util.Properties argument can be used to pass arbitrary string * tag/value pairs as connection arguments. Normally at least "user" and * "password" properties should be included in the Properties object. * * @param url the URL of the database to which to connect * @param info a list of arbitrary string tag/value pairs as connection * arguments. Normally at least a "user" and "password" property * should be included * @return a Connection object that represents a connection to the URL * @throws SQLException if a database access error occurs */ @Override public Connection connect(final String url, final Properties info) throws SQLException { // url should be of style jdbc:monetdb://<host>/<database> if (!acceptsURL(url)) return null; try { Target target = new Target(url, info); return new MonetConnection(target); } catch (ValidationError | URISyntaxException e) { throw new SQLException(e.getMessage()); } } /** * Retrieves the driver's major version number. Initially this should be 1. * * @return this driver's major version number */ @Override public int getMajorVersion() { return MonetVersion.majorVersion; } /** * Gets the driver's minor version number. Initially this should be 0. * * @return this driver's minor version number */ @Override public int getMinorVersion() { return MonetVersion.minorVersion; } /** * Gets information about the possible properties for this driver. * * The getPropertyInfo method is intended to allow a generic GUI tool to * discover what properties it should prompt a human for in order to get * enough information to connect to a database. Note that depending on the * values the human has supplied so far, additional values may become * necessary, so it may be necessary to iterate through several calls to the * getPropertyInfo method. * * @param url the URL of the database to which to connect * @param info a proposed list of tag/value pairs that will be sent on * connect open * @return an array of DriverPropertyInfo objects describing possible * properties. This array may be an empty array if no properties * are required. */ @Override public DriverPropertyInfo[] getPropertyInfo(final String url, final Properties info) { if (!acceptsURL(url)) return null; // Delegate to enum mcl.net.Parameters, which maintains all connection properties. // Note that if the URL starts with jdbc:monetdb://, TLS is always off. // If it starts with jdbc:monetdbs://, TLS is always on. // Only when the URL is exactly "jdbc:monetdb:", without slashes, TLS is determined // by the properties. boolean includeTls = (url.equals("jdbc:monetdb:") || url.startsWith("jdbc:monetdbs:")); return Parameter.getPropertyInfo(info, includeTls); } /** * Reports whether this driver is a genuine JDBC Compliant™ driver. A * driver may only report true here if it passes the JDBC compliance tests; * otherwise it is required to return false. * * JDBC compliance requires full support for the JDBC API and full support * for SQL 92 Entry Level. It is expected that JDBC compliant drivers will * be available for all the major commercial databases. * * This method is not intended to encourage the development of non-JDBC * compliant drivers, but is a recognition of the fact that some vendors are * interested in using the JDBC API and framework for lightweight databases * that do not support full database functionality, or for special databases * such as document information retrieval where a SQL implementation may not * be feasible. * * @return true if this driver is JDBC Compliant; false otherwise */ @Override public boolean jdbcCompliant() { // We're not fully JDBC compliant, but what we support is compliant return false; } /** * Return the parent Logger of all the Loggers used by this data source. * This should be the Logger farthest from the root Logger that is * still an ancestor of all of the Loggers used by this data source. * Configuring this Logger will affect all of the log messages * generated by the data source. * In the worst case, this may be the root Logger. * * @return the parent Logger for this data source * @throws SQLFeatureNotSupportedException if the data source does * not use java.util.logging * @since 1.7 */ @Override public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { throw MonetWrapper.newSQLFeatureNotSupportedException("getParentLogger"); } //== end methods of interface driver /** * Returns a touched up identifying version string of this driver. * It is made public as it is called from org/monetdb/client/JdbcClient.java * and org/monetdb/mcl/net/ClientInfo.java * @return the version string */ public static final String getDriverVersion() { return MonetVersion.driverVersion; } /** A static Map containing the mapping between MonetDB types and Java SQL types */ /* use SELECT sqlname, * FROM sys.types order by 1, id; to view all MonetDB types */ /* see http://docs.oracle.com/javase/8/docs/api/java/sql/Types.html to view all supported java SQL types */ private static final java.util.Map<String, Integer> typeMap = new java.util.HashMap<String, Integer>(); static { // fill the typeMap once // typeMap.put("any", Integer.valueOf(Types.???)); typeMap.put("bigint", Integer.valueOf(Types.BIGINT)); typeMap.put("blob", Integer.valueOf(Types.BLOB)); typeMap.put("boolean", Integer.valueOf(Types.BOOLEAN)); typeMap.put("char", Integer.valueOf(Types.CHAR)); typeMap.put("clob", Integer.valueOf(Types.CLOB)); typeMap.put("date", Integer.valueOf(Types.DATE)); typeMap.put("day_interval", Integer.valueOf(Types.NUMERIC)); // New as of Oct2020 release typeMap.put("decimal", Integer.valueOf(Types.DECIMAL)); typeMap.put("double", Integer.valueOf(Types.DOUBLE)); // typeMap.put("geometry", Integer.valueOf(Types.???)); // typeMap.put("geometrya", Integer.valueOf(Types.???)); typeMap.put("hugeint", Integer.valueOf(Types.NUMERIC)); typeMap.put("inet", Integer.valueOf(Types.VARCHAR)); typeMap.put("int", Integer.valueOf(Types.INTEGER)); typeMap.put("json", Integer.valueOf(Types.VARCHAR)); // typeMap.put("mbr", Integer.valueOf(Types.???)); typeMap.put("month_interval", Integer.valueOf(Types.INTEGER)); typeMap.put("oid", Integer.valueOf(Types.BIGINT)); // typeMap.put("ptr", Integer.valueOf(Types.???)); typeMap.put("real", Integer.valueOf(Types.REAL)); typeMap.put("sec_interval", Integer.valueOf(Types.DECIMAL)); typeMap.put("smallint", Integer.valueOf(Types.SMALLINT)); 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! // typeMap.put("table", Integer.valueOf(Types.???)); typeMap.put("time", Integer.valueOf(Types.TIME)); typeMap.put("timestamp", Integer.valueOf(Types.TIMESTAMP)); typeMap.put("timestamptz", Integer.valueOf(Types.TIMESTAMP_WITH_TIMEZONE)); // new in Java 8: Types.TIMESTAMP_WITH_TIMEZONE (value 2014) typeMap.put("timetz", Integer.valueOf(Types.TIME_WITH_TIMEZONE)); // new in Java 8: Types.TIME_WITH_TIMEZONE (value 2013) typeMap.put("tinyint", Integer.valueOf(Types.TINYINT)); typeMap.put("url", Integer.valueOf(Types.VARCHAR)); typeMap.put("uuid", Integer.valueOf(Types.VARCHAR)); typeMap.put("varchar", Integer.valueOf(Types.VARCHAR)); typeMap.put("wrd", Integer.valueOf(Types.BIGINT)); // keep it in for old (pre Dec2016) MonetDB servers typeMap.put("xml", Integer.valueOf(Types.VARCHAR)); // used when "CREATE TYPE xml EXTERNAL NAME xml;" is executed } /** * Returns the java.sql.Types equivalent of the given MonetDB type name. * * @param type the SQL data type name as used by MonetDB * @return the matching java.sql.Types constant or * java.sql.Types.OTHER if nothing matched the given type name */ static final int getJdbcSQLType(final String type) { // find the column type name in the typeMap final Integer tp = typeMap.get(type); if (tp != null) { return tp.intValue(); } // When type name is not found in the map, for instance // when it is a new type (not yet added in the above typeMap) or // when type name is: any or geometry or geometrya or mbr or ptr or table. return Types.OTHER; } /** * Returns the Class object for a given java.sql.Types value. * * @param type a value from java.sql.Types * @return a Class object from which an instance would be returned */ static final Class<?> getClassForType(final int type) { /** * This switch returns the types as objects according to table B-3 from * Oracle's JDBC specification 4.1 */ switch(type) { case Types.CHAR: case Types.VARCHAR: /* case Types.LONGVARCHAR: // MonetDB doesn't use type LONGVARCHAR */ return String.class; case Types.NUMERIC: case Types.DECIMAL: return java.math.BigDecimal.class; case Types.BOOLEAN: return Boolean.class; case Types.TINYINT: case Types.SMALLINT: return Short.class; case Types.INTEGER: return Integer.class; case Types.BIGINT: return Long.class; case Types.REAL: return Float.class; case Types.FLOAT: case Types.DOUBLE: return Double.class; case Types.BINARY: // MonetDB currently does not support these case Types.VARBINARY: // see treat_blob_as_binary property /* case Types.LONGVARBINARY: // MonetDB doesn't use type LONGVARBINARY */ return byte[].class; case Types.DATE: return java.sql.Date.class; case Types.TIME: return java.sql.Time.class; case Types.TIME_WITH_TIMEZONE: return java.time.OffsetTime.class; case Types.TIMESTAMP: return java.sql.Timestamp.class; case Types.TIMESTAMP_WITH_TIMEZONE: return java.time.OffsetDateTime.class; case Types.CLOB: return java.sql.Clob.class; case Types.BLOB: return java.sql.Blob.class; // all the rest are currently not implemented and used default: return String.class; } } private static String TypeMapppingSQL; // cache to optimise getSQLTypeMap() /** * Returns a String usable in an SQL statement to map the server types * to values of java.sql.Types using the global static type map. * The returned string will be a SQL CASE x statement where the x is * replaced with the given column name (or expression) string. * * @param column a String representing the value that should be evaluated * in the SQL CASE statement * @return a SQL CASE statement */ static final String getSQLTypeMap(final String column) { if (TypeMapppingSQL == null) { // first time, compose TypeMappping SQL string final StringBuilder val = new StringBuilder((typeMap.size() * (7 + 7 + 7 + 4)) + 14); for (Entry<String, Integer> entry : typeMap.entrySet()) { val.append(" WHEN '").append(entry.getKey()).append("' THEN ").append(entry.getValue().toString()); } val.append(" ELSE " + Types.OTHER + " END"); // as the typeMap is static, cache this SQL part for all next calls TypeMapppingSQL = val.toString(); } return "CASE " + column + TypeMapppingSQL; } }