Mercurial > hg > monetdb-java
view src/main/java/org/monetdb/jdbc/MonetParameterMetaData.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 | d416e9b6b3d0 |
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 java.sql.ParameterMetaData; import java.sql.SQLDataException; import java.sql.SQLException; import java.sql.Types; /** *<pre> * A {@link ParameterMetaData} suitable for the MonetDB database. * * An object that can be used to get information about the types and properties * for each parameter marker in a PreparedStatement or CallableStatement object. *</pre> * * @author Martin van Dinther * @version 1.0 */ final class MonetParameterMetaData extends MonetWrapper implements ParameterMetaData { /** The parental Connection object */ private final MonetConnection conn; /** The number of parameters, it can be zero !! */ private final int paramCount; /** The MonetDB type names of the parameters in the PreparedStatement */ private final String[] monetdbTypes; /** The JDBC SQL type codes of the parameters in the PreparedStatement */ private final int[] JdbcSQLTypes; /** The precisions of the parameters in the PreparedStatement */ private final int[] precisions; /** The scales of the parameters in the PreparedStatement */ private final int[] scales; /** * Constructor backed by the given connection and metadata arrays. * It is used by MonetPreparedStatement. * * @param connection the parent connection * @param paramcount the number of parameters, it can be zero !! * @param types the MonetDB type names * @param jdbcTypes the JDBC SQL type codes * @param precisions the precision for each parameter * @param scales the scale for each parameter * @throws IllegalArgumentException if called with null for one of the arguments */ MonetParameterMetaData( final MonetConnection connection, final int paramcount, final String[] types, final int[] jdbcTypes, final int[] precisions, final int[] scales) throws IllegalArgumentException { if (connection == null) { throw new IllegalArgumentException("Connection may not be null!"); } if (types == null) { throw new IllegalArgumentException("MonetDB Types may not be null!"); } if (jdbcTypes == null) { throw new IllegalArgumentException("JDBC Types may not be null!"); } if (precisions == null) { throw new IllegalArgumentException("Precisions may not be null!"); } if (scales == null) { throw new IllegalArgumentException("Scales may not be null!"); } if (types.length != precisions.length || types.length != (paramcount +1)) { throw new IllegalArgumentException("Inconsistent Parameters metadata"); } this.conn = connection; this.paramCount = paramcount; this.monetdbTypes = types; this.JdbcSQLTypes = jdbcTypes; this.precisions = precisions; this.scales = scales; } /** * Retrieves the number of parameters in the PreparedStatement object * for which this ParameterMetaData object contains information. * * @return the number of parameters */ @Override public int getParameterCount() { return paramCount; } /** * Retrieves whether null values are allowed in the * designated parameter. * * This is currently always unknown for MonetDB/SQL. * * @param param - the first parameter is 1, the second is 2, ... * @return the nullability status of the given parameter; * one of ParameterMetaData.parameterNoNulls, * ParameterMetaData.parameterNullable, or * ParameterMetaData.parameterNullableUnknown */ @Override public int isNullable(final int param) throws SQLException { checkParameterIndexValidity(param); return ParameterMetaData.parameterNullableUnknown; } /** * Retrieves whether values for the designated parameter can * be signed numbers. * * @param param - the first parameter is 1, the second is 2, ... * @return true if so; false otherwise * @throws SQLException if a database access error occurs */ @Override public boolean isSigned(final int param) throws SQLException { // we can hardcode this, based on the parameter type switch (getParameterType(param)) { case Types.TINYINT: case Types.SMALLINT: case Types.INTEGER: case Types.REAL: case Types.FLOAT: case Types.DOUBLE: case Types.DECIMAL: case Types.NUMERIC: case Types.DATE: // year can be negative case Types.TIMESTAMP: // year can be negative case Types.TIMESTAMP_WITH_TIMEZONE: return true; case Types.BIGINT: { final String monettype = getParameterTypeName(param); // data of type oid or ptr is not signed if ("oid".equals(monettype) || "ptr".equals(monettype)) return false; return true; } default: return false; } } /** * Retrieves the designated parameter's specified column size. * The returned value represents the maximum column size for * the given parameter. * For numeric data, this is the maximum precision. * For character data, this is the length in characters. * For datetime datatypes, this is the length in characters * of the String representation (assuming the maximum allowed * precision of the fractional seconds component). * For binary data, this is the length in bytes. * For the ROWID datatype, this is the length in bytes. * 0 is returned for data types where the column size is not applicable. * * @param param - the first parameter is 1, the second is 2, ... * @return precision * @throws SQLException if a database access error occurs */ @Override public int getPrecision(final int param) throws SQLException { switch (getParameterType(param)) { case Types.BIGINT: return 19; case Types.INTEGER: return 10; case Types.SMALLINT: return 5; case Types.TINYINT: return 3; case Types.REAL: return 7; case Types.FLOAT: case Types.DOUBLE: return 15; case Types.DECIMAL: case Types.NUMERIC: // these data types have a variable precision (max precision is 38) try { // Special handling for: day_interval and sec_interval as they are // mapped to Types.NUMERIC and Types.DECIMAL types (see MonetDriver typeMap) final String monettype = monetdbTypes[param]; if (monettype != null && monettype.endsWith("_interval")) { /* for interval types, precisions[] contains the interval subtype code */ switch (precisions[param]) { case 1: return 4; // interval year case 2: return 6; // interval year to month case 3: return 6; // interval month case 4: return 9; // interval day case 5: return 11; // interval day to hour case 6: return 13; // interval day to minute case 7: return 15; // interval day to second case 8: return 11; // interval hour case 9: return 13; // interval hour to minute case 10: return 15; // interval hour to second case 11: return 13; // interval minute case 12: return 15; // interval minute to second case 13: return 15; // interval second default: { // fall back to the 3 available monettype names if ("sec_interval".equals(monettype)) return 15; if ("day_interval".equals(monettype)) return 9; if ("month_interval".equals(monettype)) return 6; } } } return precisions[param]; } catch (IndexOutOfBoundsException e) { throw newSQLInvalidParameterIndexException(param); } case Types.CHAR: case Types.VARCHAR: /* case Types.LONGVARCHAR: // MonetDB doesn't use type LONGVARCHAR */ case Types.CLOB: // these data types have a variable length try { return precisions[param]; } catch (IndexOutOfBoundsException e) { throw newSQLInvalidParameterIndexException(param); } case Types.BINARY: case Types.VARBINARY: /* case Types.LONGVARBINARY: // MonetDB doesn't use type LONGVARBINARY */ case Types.BLOB: // these data types have a variable length // It expects number of bytes, not number of hex chars try { return precisions[param]; } catch (IndexOutOfBoundsException e) { throw newSQLInvalidParameterIndexException(param); } case Types.DATE: return 10; // 2020-10-08 case Types.TIME: return 15; // 21:51:34.399753 case Types.TIME_WITH_TIMEZONE: return 21; // 21:51:34.399753+02:00 case Types.TIMESTAMP: return 26; // 2020-10-08 21:51:34.399753 case Types.TIMESTAMP_WITH_TIMEZONE: return 32; // 2020-10-08 21:51:34.399753+02:00 case Types.BOOLEAN: return 1; default: // All other types should return 0 return 0; } } /** * Retrieves the designated parameter's number of digits to * right of the decimal point. * 0 is returned for data types where the scale is not applicable. * * @param param - the first parameter is 1, the second is 2, ... * @return scale * @throws SQLException if a database access error occurs */ @Override public int getScale(final int param) throws SQLException { checkParameterIndexValidity(param); try { return scales[param]; } catch (IndexOutOfBoundsException e) { throw newSQLInvalidParameterIndexException(param); } } /** * Retrieves the designated parameter's SQL type. * * @param param - the first parameter is 1, the second is 2, ... * @return SQL type from java.sql.Types * @throws SQLException if a database access error occurs */ @Override public int getParameterType(final int param) throws SQLException { checkParameterIndexValidity(param); try { return JdbcSQLTypes[param]; } catch (IndexOutOfBoundsException e) { throw newSQLInvalidParameterIndexException(param); } } /** * Retrieves the designated parameter's database-specific type name. * * @param param - the first parameter is 1, the second is 2, ... * @return type the name used by the database. If the * parameter type is a user-defined type, then a * fully-qualified type name is returned. * @throws SQLException if a database access error occurs */ @Override public String getParameterTypeName(final int param) throws SQLException { checkParameterIndexValidity(param); try { final String monettype = monetdbTypes[param]; if (monettype != null && monettype.endsWith("_interval")) { /* convert the interval type names to valid SQL data type names */ /* for interval types, precisions[] contains the interval subtype code */ switch (precisions[param]) { case 1: return "interval year"; case 2: return "interval year to month"; case 3: return "interval month"; case 4: return "interval day"; case 5: return "interval day to hour"; case 6: return "interval day to minute"; case 7: return "interval day to second"; case 8: return "interval hour"; case 9: return "interval hour to minute"; case 10: return "interval hour to second"; case 11: return "interval minute"; case 12: return "interval minute to second"; case 13: return "interval second"; default: { // fall back to the 3 available monettype names if ("day_interval".equals(monettype)) return "interval day"; if ("month_interval".equals(monettype)) return "interval month"; if ("sec_interval".equals(monettype)) return "interval second"; } } } return monettype; } catch (IndexOutOfBoundsException e) { throw newSQLInvalidParameterIndexException(param); } } /** * Retrieves the fully-qualified name of the Java class whose instances * should be passed to the method PreparedStatement.setObject. * * @param param - the first parameter is 1, the second is 2, ... * @return the fully-qualified name of the class in the Java * programming language that would be used by the * method PreparedStatement.setObject to set the * value in the specified parameter. This is the * class name used for custom mapping. * @throws SQLException if a database access error occurs */ @Override public String getParameterClassName(final int param) throws SQLException { final String MonetDBType = getParameterTypeName(param); final java.util.Map<String,Class<?>> map = conn.getTypeMap(); final Class<?> type; if (map != null && map.containsKey(MonetDBType)) { type = (Class)map.get(MonetDBType); } else { type = MonetDriver.getClassForType(getParameterType(param)); } if (type != null) { return type.getCanonicalName(); } throw new SQLException("parameter type mapping null: " + MonetDBType, "M0M03"); } /** * Retrieves the designated parameter's mode. * For MonetDB/SQL we currently only support INput parameters. * * @param param - the first parameter is 1, the second is 2, ... * @return mode of the parameter; one of * ParameterMetaData.parameterModeIn, * ParameterMetaData.parameterModeOut, * ParameterMetaData.parameterModeInOut or * ParameterMetaData.parameterModeUnknown. */ @Override public int getParameterMode(final int param) throws SQLException { checkParameterIndexValidity(param); return ParameterMetaData.parameterModeIn; } /** * A private utility method to check validity of parameter index number * * @param param - the first parameter is 1, the second is 2, ... * @throws SQLDataException when invalid parameter index number */ private final void checkParameterIndexValidity(final int param) throws SQLDataException { if (param < 1 || param > paramCount) throw newSQLInvalidParameterIndexException(param); } /** * Small helper method that formats the "Invalid Parameter Index number ..." * message and creates a new SQLDataException object whose SQLState is set * to "22010": invalid indicator parameter value. * * @param paramIdx the parameter index number * @return a new created SQLDataException object with SQLState 22010 */ private final SQLDataException newSQLInvalidParameterIndexException(final int paramIdx) { return new SQLDataException("Invalid Parameter Index number: " + paramIdx, "22010"); } }